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

Subversion Repositories rtf68ksys

[/] [rtf68ksys/] [trunk/] [Software/] [TinyBasic.x68] - Blame information for rev 7

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 7 robfinch
;*****************************************************************
2
;                                                                *
3
;               Tiny BASIC for the Motorola MC68000                          *
4
;                                                                *
5
; Derived from Palo Alto Tiny BASIC as published in the May 1976 *
6
; issue of Dr. Dobb's Journal.  Adapted to the 68000 by:         *
7
;       Gordon Brandly                                               *
8
;       12147 - 51 Street                                            *
9
;       Edmonton AB  T5W 3G8                                         *
10
;       Canada                                                       *
11
;       (updated mailing address for 1996)                           *
12
;                                                                *
13
; This version is for MEX68KECB Educational Computer Board I/O.  *
14
;                                                                *
15
;*****************************************************************
16
;    Copyright (C) 1984 by Gordon Brandly. This program may be   *
17
;    freely distributed for personal use only. All commercial    *
18
;                      rights are reserved.                              *
19
;*****************************************************************
20
;                                                                *
21
; Some Modifications by: Robert Finch                            *
22
; This version running on a Diligent Nexys2 board XC3S1200e      *
23
; Running TG68 for a processor                                   *
24
; - two character variable names                                 *
25
; - TICK variable                                                *
26
; -                                                *
27
;                                                                *
28
;*****************************************************************
29
; Vers. 1.0  1984/7/17  - Original version by Gordon Brandly
30
;       1.1  1984/12/9  - Addition of '$' print term by Marvin Lipford
31
;       1.2  1985/4/9   - Bug fix in multiply routine by Rick Murray
32
 
33
;       OPT     FRS,BRS         forward ref.'s & branches default to short
34
RANDOM          EQU             0xFFDC0C00      ; Hardware random# gen. address
35
GRAPHICS        EQU             0xFFDAE000      ; graphics (line draw) acceelerator address
36
SPRCTRL         EQU             0xFFDAD000      ; sprite controller address
37
 
38
BUFLEN  EQU     80      ;       length of keyboard input buffer
39
 
40
;*
41
;* Internal variables follow:
42
;*
43
        BSS
44
        ORG             0x600
45
RANPNT:
46
        DC.L    START   ;       random number pointer
47
CURRNT:
48
        DC.L    1               ;Current line pointer
49
STKGOS:
50
        DC.L    1               ;Saves stack pointer in 'GOSUB'
51
STKINP:
52
        DC.L    1               ;Saves stack pointer during 'INPUT'
53
LOPVAR:
54
        DC.L    1               ;'FOR' loop save area
55
LOPINC:
56
        DC.L    1               ;increment
57
LOPLMT:
58
        DC.L    1               ;limit
59
LOPLN:
60
        DC.L    1               ;line number
61
LOPPT:
62
        DC.L    1               ;text pointer
63
TXTUNF:
64
        DC.L    1               ;points to unfilled text area
65
VARBGN:
66
        DC.L    1               ;points to variable area
67
STKLMT:
68
        DC.L    1               ;holds lower limit for stack growth
69
BUFFER:
70
        FILL.B  BUFLEN,0x00     ;       Keyboard input buffer
71
 
72
TXT     EQU     $               ;Beginning of program area
73
 
74
        CODE
75
        even
76
        ORG     0xFFFF2400
77
 
78
; Tell the outside world about these symbols
79
; only needed for the assembler, since this file is included from another file
80
public START
81
public ENDMEM
82
public PRTNUM
83
public AUXIN
84
 
85
;*
86
;* Standard jump table. You can change these addresses if you are
87
;* customizing this interpreter for a different environment.
88
;*
89
START:
90
                BRA.L   CSTART          ;Cold Start entry point
91
GOWARM: BRA.L   WSTART          ;Warm Start entry point
92
GOOUT:  BRA.L   OUTC            ;Jump to character-out routine
93
GOIN:   BRA.L   INC             ;Jump to character-in routine
94
GOAUXO: BRA.L   AUXOUT          ;Jump to auxiliary-out routine
95
GOAUXI: BRA.L   AUXIN           ;Jump to auxiliary-in routine
96
GOBYE:  BRA.L   BYEBYE          ;Jump to monitor, DOS, etc.
97
;*
98
;* Modifiable system constants:
99
;*
100
; Give Tiny Basic 3MB
101
TXTBGN  DC.L    0xC00000        ;beginning of program memory
102
ENDMEM  DC.L    0xF00000        ;       end of available memory
103
;*
104
;* The main interpreter starts here:
105
;*
106
CSTART:
107
        LEA             START,A0
108
        MOVE.L  A0,RANPNT
109
        MOVE.L  ENDMEM,SP       ;initialize stack pointer
110
        LEA             INITMSG,A6      ;tell who we are
111
        BSR.L   PRMESG
112
        MOVE.L  TXTBGN,TXTUNF   ;init. end-of-program pointer
113
        MOVE.L  ENDMEM,D0       ;get address of end of memory
114
        SUB.L   #2048,D0        ;reserve 2K for the stack
115
        MOVE.L  D0,STKLMT
116
        SUB.L   #4104,D0        ;reserve variable area (27 long words)
117
        MOVE.L  D0,VARBGN
118
WSTART:
119
        CLR.L   D0              ;initialize internal variables
120
        MOVE.L  D0,LOPVAR
121
        MOVE.L  D0,STKGOS
122
        MOVE.L  D0,CURRNT       ;current line number pointer = 0
123
        MOVE.L  ENDMEM,SP       ;init S.P. again, just in case
124
        LEA     OKMSG,A6        ;display "OK"
125
        BSR.L   PRMESG
126
ST3:
127
        MOVE.B  #'>',D0  ;       Monitor with a '>' and
128
        BSR.L   GETLN   ;       read a line.
129
        BSR.L   TOUPBUF ;       convert to upper case
130
        MOVE.L  A0,A4   ;       save pointer to end of line
131
        LEA     BUFFER,A0       ;point to the beginning of line
132
        BSR.L   TSTNUM  ;       is there a number there?
133
        BSR.L   IGNBLK  ;       skip trailing blanks
134
        TST     D1              ;does line no. exist? (or nonzero?)
135
        BEQ.L   DIRECT  ;       if not, it's a direct statement
136
        CMP.L   #0xFFFF,D1      ;see if line no. is <= 16 bits
137
        BCC.L   QHOW            ;if not, we've overflowed
138
        MOVE.B  D1,-(A0)        ;store the binary line no.
139
        ROR     #8,D1           ;(Kludge to store a word on a
140
        MOVE.B  D1,-(A0)        ;possible byte boundary)
141
        ROL     #8,D1
142
        BSR.L   FNDLN   ;       find this line in save area
143
        MOVE.L  A1,A5   ;       save possible line pointer
144
        BNE     ST4                             ;       if not found, insert
145
        BSR.L   FNDNXT          ;find the next line (into A1)
146
        MOVE.L  A5,A2           ;pointer to line to be deleted
147
        MOVE.L  TXTUNF,A3       ;points to top of save area
148
        BSR.L   MVUP            ;move up to delete
149
        MOVE.L  A2,TXTUNF       ;update the end pointer
150
ST4:
151
        MOVE.L  A4,D0           ;calculate the length of new line
152
        SUB.L   A0,D0
153
        CMP.L   #3,D0           ;is it just a line no. & CR?
154
        BEQ     ST3                             ;if so, it was just a delete
155
        MOVE.L  TXTUNF,A3       ;compute new end
156
        MOVE.L  A3,A6
157
        ADD.L   D0,A3
158
        MOVE.L  VARBGN,D0       ;see if there's enough room
159
        CMP.L   A3,D0
160
        BLS.L   QSORRY          ;if not, say so
161
        MOVE.L  A3,TXTUNF       ;if so, store new end position
162
        MOVE.L  A6,A1           ;points to old unfilled area
163
        MOVE.L  A5,A2           ;points to beginning of move area
164
        BSR.L   MVDOWN          ;move things out of the way
165
        MOVE.L  A0,A1           ;set up to do the insertion
166
        MOVE.L  A5,A2
167
        MOVE.L  A4,A3
168
        BSR.L   MVUP            ;do it
169
        BRA     ST3             ;go back and get another line
170
 
171
;*
172
;*******************************************************************
173
;*
174
;* *** Tables *** DIRECT *** EXEC ***
175
;*
176
;* This section of the code tests a string against a table. When
177
;* a match is found, control is transferred to the section of
178
;* code according to the table.
179
;*
180
;* At 'EXEC', A0 should point to the string, A1 should point to
181
;* the character table, and A2 should point to the execution
182
;* table. At 'DIRECT', A0 should point to the string, A1 and
183
;* A2 will be set up to point to TAB1 and TAB1.1, which are
184
;* the tables of all direct and statement commands.
185
;*
186
;* A '.' in the string will terminate the test and the partial
187
;* match will be considered as a match, e.g. 'P.', 'PR.','PRI.',
188
;* 'PRIN.', or 'PRINT' will all match 'PRINT'.
189
;*
190
;* There are two tables: the character table and the execution
191
;* table. The character table consists of any number of text items.
192
;* Each item is a string of characters with the last character's
193
;* high bit set to one. The execution table holds a 16-bit
194
;* execution addresses that correspond to each entry in the
195
;* character table.
196
;*
197
;* The end of the character table is a 0 byte which corresponds
198
;* to the default routine in the execution table, which is
199
;* executed if none of the other table items are matched.
200
;*
201
;* Character-matching tables:
202
TAB1:
203
        DC.B    'LIS',('T'+0x80) ;        Direct commands
204
        DC.B    'LOA',('D'+0x80)
205
        DC.B    'NE',('W'+0x80)
206
        DC.B    'RU',('N'+0x80)
207
        DC.B    'SAV',('E'+0x80)
208
        DC.B    'CL',('S'+0x80)
209
TAB2:
210
        DC.B    'NEX',('T'+0x80)  ;       Direct / statement
211
        DC.B    'LE',('T'+0x80)
212
        DC.B    'I',('F'+0x80)
213
        DC.B    'GOT',('O'+0x80)
214
        DC.B    'GOSU',('B'+0x80)
215
        DC.B    'RETUR',('N'+0x80)
216
        DC.B    'RE',('M'+0x80)
217
        DC.B    'FO',('R'+0x80)
218
        DC.B    'INPU',('T'+0x80)
219
        DC.B    'PRIN',('T'+0x80)
220
        DC.B    'POK',('E'+0x80)
221
        DC.B    'STO',('P'+0x80)
222
        DC.B    'BY',('E'+0x80)
223
        DC.B    'CAL',('L'+0x80)
224
        DC.B    'LIN',('E'+0x80)
225
        DC.B    'POIN',('T'+0x80)
226
        DC.B    'PENCOLO',('R'+0x80)
227
        DC.B    'FILLCOLO',('R'+0x80)
228
        DC.B    'SPRPO',('S'+0x80)
229
        DC.B    0
230
TAB4:
231
        DC.B    'PEE',('K'+0x80)   ;      Functions
232
        DC.B    'RN',('D'+0x80)
233
        DC.B    'AB',('S'+0x80)
234
        DC.B    'SIZ',('E'+0x80)
235
        DC.B    'TIC',('K'+0x80)
236
        DC.B    'TEM',('P'+0x80)
237
        DC.B    'SG',('N'+0x80)
238
        DC.B    0
239
TAB5:
240
        DC.B    'T',('O'+0x80)      ;     "TO" in "FOR"
241
        DC.B    0
242
TAB6:
243
        DC.B    'STE',('P'+0x80)     ;    "STEP" in "FOR"
244
        DC.B    0
245
TAB8:
246
        DC.B    '>',('='+0x80)        ;   Relational operators
247
        DC.B    '<',('>'+0x80)
248
        DC.B    ('>'+0x80)
249
        DC.B    ('='+0x80)
250
        DC.B    '<',('='+0x80)
251
        DC.B    ('<'+0x80)
252
        DC.B    0
253
;       DC.B    0        ;<- for aligning on a word boundary
254
 
255
        even
256
 
257
;* Execution address tables:
258
TAB1_1:
259
        DC.W    LIST_                   ;Direct commands
260
        DC.W    LOAD
261
        DC.W    NEW
262
        DC.W    RUN
263
        DC.W    SAVE
264
        DC.W    CLS
265
TAB2_1:
266
        DC.W    NEXT                    ;Direct / statement
267
        DC.W    LET
268
        DC.W    IF
269
        DC.W    GOTO
270
        DC.W    GOSUB
271
        DC.W    RETURN
272
        DC.W    REM
273
        DC.W    FOR
274
        DC.W    INPUT
275
        DC.W    PRINT
276
        DC.W    POKE
277
        DC.W    STOP_
278
        DC.W    GOBYE
279
        DC.W    CALL
280
        DC.W    LINE
281
        DC.W    POINT
282
        DC.W    PENCOLOR
283
        DC.W    FILLCOLOR
284
        DC.W    SPRPOS
285
        DC.W    DEFLT
286
TAB4_1:
287
        DC.W    PEEK                    ;Functions
288
        DC.W    RND
289
        DC.W    ABS
290
        DC.W    SIZE_
291
        DC.W    TICK
292
        DC.W    TEMP
293
        DC.W    SGN
294
        DC.W    XP40
295
TAB5_1:
296
        DC.W    FR1             ;       "TO" in "FOR"
297
        DC.W    QWHAT
298
TAB6_1:
299
        DC.W    FR2             ;       "STEP" in "FOR"
300
        DC.W    FR3
301
TAB8_1:
302
        DC.W    XP11;   >=              Relational operators
303
        DC.W    XP12    ;<>
304
        DC.W    XP13    ;>
305
        DC.W    XP15    ;=
306
        DC.W    XP14    ;<=
307
        DC.W    XP16    ;<
308
        DC.W    XP17
309
;*
310
DIRECT:
311
        LEA     TAB1,A1
312
        LEA     TAB1_1,A2
313
EXEC:
314
        BSR.L   IGNBLK;         ignore leading blanks
315
        MOVE.L  A0,A3           ;save the pointer
316
        CLR.B   D2              ;clear match flag
317
EXLP:
318
        MOVE.B  (A0)+,D0;       get the program character
319
        MOVE.B  (A1),D1         ;get the table character
320
        BNE     EXNGO           ;If end of table,
321
        MOVE.L  A3,A0   ;;      restore the text pointer and...
322
        BRA     EXGO            ;execute the default.
323
EXNGO:
324
        MOVE.B  D0,D3   ;       Else check for period...
325
        AND.B   D2,D3           ;and a match.
326
        CMP.B   #'.',D3
327
        BEQ     EXGO            ;if so, execute
328
        AND.B   #0x7F,D1 ;      ignore the table's high bit
329
        CMP.B   D0,D1   ;       is there a match?
330
        BEQ     EXMAT
331
        ADDQ.L  #2,A2   ;       if not, try the next entry
332
        MOVE.L  A3,A0   ;       reset the program pointer
333
        CLR.B   D2              ;sorry, no match
334
EX1:
335
        TST.B   (A1)+   ;       get to the end of the entry
336
        BPL     EX1
337
        BRA     EXLP            ;back for more matching
338
EXMAT:
339
        MOVEQ   #-1,D2;         we've got a match so far
340
        TST.B   (A1)+   ;       end of table entry?
341
        BPL     EXLP            ;if not, go back for more
342
EXGO:
343
        LEA             0xFFFF0000,A3   ;       execute the appropriate routine
344
        move.w  (a2),a2
345
        JMP     (A3,A2.W)
346
 
347
CLS:
348
        jsr             ClearScreen
349
        clr.w   CursorRow
350
        clr.w   CursorCol
351
        bra             WSTART
352
;*
353
;*******************************************************************
354
;*
355
;* What follows is the code to execute direct and statement
356
;* commands. Control is transferred to these points via the command
357
;* table lookup code of 'DIRECT' and 'EXEC' in the last section.
358
;* After the command is executed, control is transferred to other
359
;* sections as follows:
360
;*
361
;* For 'LIST', 'NEW', and 'STOP': go back to the warm start point.
362
;* For 'RUN': go execute the first stored line if any; else go
363
;* back to the warm start point.
364
;* For 'GOTO' and 'GOSUB': go execute the target line.
365
;* For 'RETURN' and 'NEXT'; go back to saved return line.
366
;* For all others: if 'CURRNT' is 0, go to warm start; else go;
367
;* execute next command. (This is done in 'FINISH'.)
368
;*
369
;*******************************************************************
370
;*
371
;* *** NEW *** STOP *** RUN (& friends) *** GOTO ***
372
;*
373
;* 'NEW' sets TXTUNF to point to TXTBGN
374
;*
375
;* 'STOP' goes back to WSTART
376
;*
377
;* 'RUN' finds the first stored line, stores its address
378
;* in CURRNT, and starts executing it. Note that only those
379
;* commands in TAB2 are legal for a stored program.
380
;*
381
;* There are 3 more entries in 'RUN':
382
;* 'RUNNXL' finds next line, stores it's address and executes it.
383
;* 'RUNTSL' stores the address of this line and executes it.
384
;* 'RUNSML' continues the execution on same line.
385
;*
386
;* 'GOTO expr' evaluates the expression, finds the target
387
;* line, and jumps to 'RUNTSL' to do it.
388
;*
389
NEW:
390
        BSR.L   ENDCHK
391
        MOVE.L  TXTBGN,TXTUNF   ;set the end pointer
392
 
393
STOP_:
394
        BSR.L   ENDCHK
395
        BRA     WSTART
396
 
397
RUN:
398
        BSR.L   ENDCHK
399
        MOVE.L  TXTBGN,A0       ;set pointer to beginning
400
        MOVE.L  A0,CURRNT
401
 
402
RUNNXL:
403
        TST.L   CURRNT  ;       executing a program?
404
        BEQ.L   WSTART          ;if not, we've finished a direct stat.
405
        CLR.L   D1              ;else find the next line number
406
        MOVE.L  A0,A1
407
        BSR.L   FNDLNP
408
        BCS     WSTART          ;if we've fallen off the end, stop
409
 
410
RUNTSL:
411
        MOVE.L  A1,CURRNT       ;set CURRNT to point to the line no.
412
        MOVE.L  A1,A0           ;set the text pointer to
413
        ADDQ.L  #2,A0           ;the start of the line text
414
 
415
RUNSML:
416
        BSR.L   CHKIO   ;       see if a control-C was pressed
417
        LEA     TAB2,A1         ;find command in TAB2
418
        LEA     TAB2_1,A2
419
        BRA     EXEC            ;and execute it
420
 
421
GOTO:
422
        BSR.L   EXPR    ;       evaluate the following expression
423
        BSR.L   ENDCHK          ;must find end of line
424
        MOVE.L  D0,D1
425
        BSR.L   FNDLN           ;find the target line
426
        BNE.L   QHOW            ;no such line no.
427
        BRA     RUNTSL          ;go do it
428
 
429
;*
430
;*******************************************************************
431
;*
432
;* *** LIST *** PRINT ***
433
;*
434
;* LIST has two forms:
435
;* 'LIST' lists all saved lines
436
;* 'LIST #' starts listing at the line #
437
;* Control-S pauses the listing, control-C stops it.
438
;*
439
;* PRINT command is 'PRINT ....:' or 'PRINT ....'
440
;* where '....' is a list of expressions, formats, back-arrows,
441
;* and strings. These items a separated by commas.
442
;*
443
;* A format is a pound sign followed by a number.  It controls
444
;* the number of spaces the value of an expression is going to
445
;* be printed in.  It stays effective for the rest of the print
446
;* command unless changed by another format.  If no format is
447
;* specified, 11 positions will be used.
448
;*
449
;* A string is quoted in a pair of single- or double-quotes.
450
;*
451
;* An underline (back-arrow) means generate a  without a 
452
;*
453
;* A  is generated after the entire list has been printed
454
;* or if the list is empty.  If the list ends with a semicolon,
455
;* however, no  is generated.
456
;*
457
 
458
LIST_:
459
        BSR.L   TSTNUM  ;       see if there's a line no.
460
        BSR.L   ENDCHK          ;if not, we get a zero
461
        BSR.L   FNDLN           ;find this or next line
462
LS1:
463
        BCS     WSTART          ;warm start if we passed the end
464
        BSR.L   PRTLN   ;       print the line
465
        BSR.L   CHKIO   ;       check for listing halt request
466
        BEQ     LS3
467
        CMP.B   #CTRLS,D0       ;pause the listing?
468
        BNE     LS3
469
LS2:
470
        BSR.L   CHKIO           ;if so, wait for another keypress
471
        BEQ     LS2
472
LS3:
473
        BSR.L   FNDLNP          ;find the next line
474
        BRA     LS1
475
 
476
PRINT:
477
        MOVE    #11,D4  ;       D4 = number of print spaces
478
        BSR.L   TSTC            ;if null list and ":"
479
        DC.B    ':',PR2-$
480
        BSR.L   CRLF1           ;give CR-LF and continue
481
        BRA     RUNSML          ;execution on the same line
482
PR2:
483
        BSR.L   TSTC            ;if null list and 
484
        DC.B    CR,PR0-$
485
        BSR.L   CRLF1           ;also give CR-LF and
486
        BRA     RUNNXL          ;execute the next line
487
PR0:
488
        BSR.L   TSTC            ;else is it a format?
489
        DC.B    '#',PR1-$
490
        BSR.L   EXPR            ;yes, evaluate expression
491
        MOVE    D0,D4           ;and save it as print width
492
        BRA     PR3             ;look for more to print
493
PR1:
494
        BSR.L   TSTC            ;is character expression? (MRL)
495
        DC.B    '$',PR4-$
496
        BSR.L   EXPR            ;yep. Evaluate expression (MRL)
497
        BSR     GOOUT           ;print low byte (MRL)
498
        BRA     PR3             ;look for more. (MRL)
499
PR4:
500
        BSR.L   QTSTG   ;       is it a string?
501
        BRA.S   PR8             ;if not, must be an expression
502
PR3:
503
        BSR.L   TSTC    ;       if ",", go find next
504
        DC.B    ',',PR6-$
505
        BSR.L   FIN             ;in the list.
506
        BRA     PR0
507
PR6:
508
        BSR.L   CRLF1   ;       list ends here
509
        BRA     FINISH
510
PR8:
511
        MOVE    D4,-(SP)        ;save the width value
512
        BSR.L   EXPR            ;evaluate the expression
513
        MOVE    (SP)+,D4        ;restore the width
514
        MOVE.L  D0,D1
515
        BSR.L   PRTNUM          ;print its value
516
        BRA     PR3             ;more to print?
517
 
518
FINISH:
519
        BSR.L   FIN     ;       Check end of command
520
        BRA.L   QWHAT   ;       print "What?" if wrong
521
 
522
;*
523
;*******************************************************************
524
;*
525
;* *** GOSUB *** & RETURN ***
526
;*
527
;* 'GOSUB expr:' or 'GOSUB expr' is like the 'GOTO' command,
528
;* except that the current text pointer, stack pointer, etc. are
529
;* saved so that execution can be continued after the subroutine
530
;* 'RETURN's.  In order that 'GOSUB' can be nested (and even
531
;* recursive), the save area must be stacked.  The stack pointer
532
;* is saved in 'STKGOS'.  The old 'STKGOS' is saved on the stack.
533
;* If we are in the main routine, 'STKGOS' is zero (this was done
534
;* in the initialization section of the interpreter), but we still
535
;* save it as a flag for no further 'RETURN's.
536
;*
537
;* 'RETURN' undoes everything that 'GOSUB' did, and thus
538
;* returns the execution to the command after the most recent
539
;* 'GOSUB'.  If 'STKGOS' is zero, it indicates that we never had
540
;* a 'GOSUB' and is thus an error.
541
;*
542
GOSUB:
543
        BSR.L   PUSHA   ;       save the current 'FOR' parameters
544
        BSR.L   EXPR            ;get line number
545
        MOVE.L  A0,-(SP)        ;save text pointer
546
        MOVE.L  D0,D1
547
        BSR.L   FNDLN           ;find the target line
548
        BNE.L   AHOW            ;if not there, say "How?"
549
        MOVE.L  CURRNT,-(SP)    ;found it, save old 'CURRNT'...
550
        MOVE.L  STKGOS,-(SP)    ;and 'STKGOS'
551
        CLR.L   LOPVAR          ;load new values
552
        MOVE.L  SP,STKGOS
553
        BRA     RUNTSL
554
 
555
RETURN:
556
        BSR.L   ENDCHK  ;       there should be just a 
557
        MOVE.L  STKGOS,D1       ;get old stack pointer
558
        BEQ.L   QWHAT           ;if zero, it doesn't exist
559
        MOVE.L  D1,SP           ;else restore it
560
        MOVE.L  (SP)+,STKGOS    ;and the old 'STKGOS'
561
        MOVE.L  (SP)+,CURRNT    ;and the old 'CURRNT'
562
        MOVE.L  (SP)+,A0        ;and the old text pointer
563
        BSR.L   POPA            ;and the old 'FOR' parameters
564
        BRA     FINISH          ;and we are back home
565
 
566
;*
567
;*******************************************************************
568
;*
569
;* *** FOR *** & NEXT ***
570
;*
571
;* 'FOR' has two forms:
572
;* 'FOR var=exp1 TO exp2 STEP exp1' and 'FOR var=exp1 TO exp2'
573
;* The second form means the same thing as the first form with a
574
;* STEP of positive 1.  The interpreter will find the variable 'var'
575
;* and set its value to the current value of 'exp1'.  It also
576
;* evaluates 'exp2' and 'exp1' and saves all these together with
577
;* the text pointer, etc. in the 'FOR' save area, which consisits of
578
;* 'LOPVAR', 'LOPINC', 'LOPLMT', 'LOPLN', and 'LOPPT'.  If there is
579
;* already something in the save area (indicated by a non-zero
580
;* 'LOPVAR'), then the old save area is saved on the stack before
581
;* the new values are stored.  The interpreter will then dig in the
582
;* stack and find out if this same variable was used in another
583
;* currently active 'FOR' loop.  If that is the case, then the old
584
;* 'FOR' loop is deactivated. (i.e. purged from the stack)
585
;*
586
;* 'NEXT var' serves as the logical (not necessarily physical) end
587
;* of the 'FOR' loop.  The control variable 'var' is checked with
588
;* the 'LOPVAR'.  If they are not the same, the interpreter digs in
589
;* the stack to find the right one and purges all those that didn't
590
;* match.  Either way, it then adds the 'STEP' to that variable and
591
;* checks the result with against the limit value.  If it is within
592
;* the limit, control loops back to the command following the
593
;* 'FOR'.  If it's outside the limit, the save area is purged and
594
;* execution continues.
595
;*
596
FOR:
597
        BSR.L   PUSHA           ;save the old 'FOR' save area
598
        BSR.L   SETVAL          ;set the control variable
599
        MOVE.L  A6,LOPVAR       ;save its address
600
        LEA     TAB5,A1         ;use 'EXEC' to test for 'TO'
601
        LEA     TAB5_1,A2
602
        BRA     EXEC
603
FR1:
604
        BSR.L   EXPR            ;evaluate the limit
605
        MOVE.L  D0,LOPLMT       ;save that
606
        LEA     TAB6,A1         ;use 'EXEC' to look for the
607
        LEA     TAB6_1,A2       ;word 'STEP'
608
        BRA     EXEC
609
FR2:
610
        BSR.L   EXPR    ;       found it, get the step value
611
        BRA     FR4
612
FR3:
613
        MOVEQ   #1,D0   ;       not found, step defaults to 1
614
FR4:
615
        MOVE.L  D0,LOPINC       ;save that too
616
FR5:
617
        MOVE.L  CURRNT,LOPLN    ;save address of current line number
618
        MOVE.L  A0,LOPPT        ;and text pointer
619
        MOVE.L  SP,A6           ;dig into the stack to find 'LOPVAR'
620
        BRA     FR7
621
FR6:
622
        ADD.L   #20,A6          ;look at next stack frame
623
FR7:
624
        MOVE.L  (A6),D0         ;is it zero?
625
        BEQ     FR8             ;if so, we're done
626
        CMP.L   LOPVAR,D0       ;same as current LOPVAR?
627
        BNE     FR6             ;nope, look some more
628
        MOVE.L  SP,A2   ;       Else remove 5 long words from...
629
        MOVE.L  A6,A1   ;       inside the stack.
630
        LEA     20,A3
631
        ADD.L   A1,A3
632
        BSR.L   MVDOWN
633
        MOVE.L  A3,SP   ;       set the SP 5 long words up
634
FR8:
635
        BRA     FINISH          ;and continue execution
636
 
637
NEXT:
638
        BSR.L   TSTV;           get address of variable
639
        BCS.L   QWHAT   ;       if no variable, say "What?"
640
        MOVE.L  D0,A1   ;       save variable's address
641
NX0:
642
        MOVE.L  LOPVAR,D0;      If 'LOPVAR' is zero, we never...
643
        BEQ.L   QWHAT   ;       had a FOR loop, so say "What?"
644
        CMP.L   D0,A1   ;;      else we check them
645
        BEQ     NX3     ;       OK, they agree
646
        BSR.L   POPA    ;       nope, let's see the next frame
647
        BRA     NX0
648
NX3:
649
        MOVE.L  (A1),D0 ;       get control variable's value
650
        ADD.L   LOPINC,D0;      add in loop increment
651
        BVS.L   QHOW    ;       say "How?" for 32-bit overflow
652
        MOVE.L  D0,(A1) ;       save control variable's new value
653
        MOVE.L  LOPLMT,D1;      get loop's limit value
654
        TST.L   LOPINC
655
        BPL     NX1     ;       branch if loop increment is positive
656
        EXG     D0,D1
657
NX1:
658
        CMP.L   D0,D1;          test against limit
659
        BLT     NX2;            branch if outside limit
660
        MOVE.L  LOPLN,CURRNT    ;Within limit, go back to the...
661
        MOVE.L  LOPPT,A0        ;saved 'CURRNT' and text pointer.
662
        BRA     FINISH
663
NX2:
664
        BSR.L   POPA            ;purge this loop
665
        BRA     FINISH
666
 
667
;*
668
;*******************************************************************
669
;*
670
;* *** REM *** IF *** INPUT *** LET (& DEFLT) ***
671
;*
672
;* 'REM' can be followed by anything and is ignored by the
673
;* interpreter.
674
;*
675
;* 'IF' is followed by an expression, as a condition and one or
676
;* more commands (including other 'IF's) separated by colons.
677
;* Note that the word 'THEN' is not used.  The interpreter evaluates
678
;* the expression.  If it is non-zero, execution continues.  If it
679
;* is zero, the commands that follow are ignored and execution
680
;* continues on the next line.
681
;*
682
;* 'INPUT' is like the 'PRINT' command, and is followed by a list
683
;* of items.  If the item is a string in single or double quotes,
684
;* or is an underline (back arrow), it has the same effect as in
685
;* 'PRINT'.  If an item is a variable, this variable name is
686
;* printed out followed by a colon, then the interpreter waits for
687
;* an expression to be typed in.  The variable is then set to the
688
;* value of this expression.  If the variable is preceeded by a
689
;* string (again in single or double quotes), the string will be
690
;* displayed followed by a colon.  The interpreter the waits for an
691
;* expression to be entered and sets the variable equal to the
692
;* expression's value.  If the input expression is invalid, the
693
;* interpreter will print "What?", "How?", or "Sorry" and reprint
694
;* the prompt and redo the input.  The execution will not terminate
695
;* unless you press control-C.  This is handled in 'INPERR'.
696
;*
697
;* 'LET' is followed by a list of items separated by commas.
698
;* Each item consists of a variable, an equals sign, and an
699
;* expression.  The interpreter evaluates the expression and sets
700
;* the variable to that value.  The interpreter will also handle
701
;* 'LET' commands without the word 'LET'.  This is done by 'DEFLT'.
702
;*
703
REM:
704
        BRA     IF2             ;skip the rest of the line
705
 
706
IF:
707
        BSR.L   EXPR    ;       evaluate the expression
708
IF1:
709
        TST.L   D0              ;is it zero?
710
        BNE     RUNSML          ;if not, continue
711
IF2:
712
        MOVE.L  A0,A1
713
        CLR.L   D1
714
        BSR.L   FNDSKP  ;       if so, skip the rest of the line
715
        BCC     RUNTSL          ;and run the next line
716
        BRA.L   WSTART  ;       if no next line, do a warm start
717
 
718
INPERR:
719
        MOVE.L  STKINP,SP;      restore the old stack pointer
720
        MOVE.L  (SP)+,CURRNT;   and old 'CURRNT'
721
        ADDQ.L  #4,SP
722
        MOVE.L  (SP)+,A0        ;and old text pointer
723
 
724
INPUT:
725
        MOVE.L  A0,-(SP);       save in case of error
726
        BSR.L   QTSTG           ;is next item a string?
727
        BRA.S   IP2             ;nope
728
        BSR.L   TSTV    ;       yes, but is it followed by a variable?
729
        BCS     IP4             ;if not, branch
730
        MOVE.L  D0,A2   ;       put away the variable's address
731
        BRA     IP3             ;if so, input to variable
732
IP2:
733
        MOVE.L  A0,-(SP);       save for 'PRTSTG'
734
        BSR.L   TSTV    ;       must be a variable now
735
        BCS.L   QWHAT   ;       "What?" it isn't?
736
        MOVE.L  D0,A2   ;       put away the variable's address
737
        MOVE.B  (A0),D2 ;       get ready for 'PRTSTG'
738
        CLR.B   D0
739
        MOVE.B  D0,(A0)
740
        MOVE.L  (SP)+,A1
741
        BSR.L   PRTSTG  ;       print string as prompt
742
        MOVE.B  D2,(A0) ;       restore text
743
IP3:
744
        MOVE.L  A0,-(SP);       save in case of error
745
        MOVE.L  CURRNT,-(SP)    ;also save 'CURRNT'
746
        MOVE.L  #-1,CURRNT      ;flag that we are in INPUT
747
        MOVE.L  SP,STKINP       ;save the stack pointer too
748
        MOVE.L  A2,-(SP)        ;save the variable address
749
        MOVE.B  #':',D0     ;    print a colon first
750
        BSR.L   GETLN           ;then get an input line
751
        LEA     BUFFER,A0       ;point to the buffer
752
        BSR.L   EXPR    ;       evaluate the input
753
        MOVE.L  (SP)+,A2        ;restore the variable address
754
        MOVE.L  D0,(A2)         ;save value in variable
755
        MOVE.L  (SP)+,CURRNT    ;restore old 'CURRNT'
756
        MOVE.L  (SP)+,A0;       and the old text pointer
757
IP4:
758
        ADDQ.L  #4,SP   ;       clean up the stack
759
        BSR.L   TSTC    ;       is the next thing a comma?
760
        DC.B    ',',IP5-$
761
        BRA     INPUT   ;       yes, more items
762
IP5:
763
        BRA     FINISH
764
 
765
DEFLT:
766
        CMP.B   #CR,(A0);       empty line is OK
767
        BEQ     LT1             ;else it is 'LET'
768
 
769
LET:
770
        BSR.L   SETVAL          ;do the assignment
771
        BSR.L   TSTC            ;check for more 'LET' items
772
        DC.B    ',',LT1-$
773
        BRA     LET
774
LT1:
775
        BRA     FINISH          ;until we are finished.
776
 
777
;*
778
;*******************************************************************
779
;*
780
;* *** LOAD *** & SAVE ***
781
;*
782
;* These two commands transfer a program to/from an auxiliary
783
;* device such as a cassette, another computer, etc.  The program
784
;* is converted to an easily-stored format: each line starts with
785
;* a colon, the line no. as 4 hex digits, and the rest of the line.
786
;* At the end, a line starting with an '@' sign is sent.  This
787
;* format can be read back with a minimum of processing time by
788
;* the 68000.
789
;*
790
LOAD:
791
        MOVE.L  TXTBGN,A0       ;set pointer to start of prog. area
792
        MOVE.B  #CR,D0          ;For a CP/M host, tell it we're ready...
793
        BSR     GOAUXO          ;by sending a CR to finish PIP command.
794
LOD1:
795
        BSR     GOAUXI  ;       look for start of line
796
        BEQ     LOD1
797
        CMP.B   #'@',D0  ;       end of program?
798
        BEQ     LODEND
799
        CMP.B   #':',D0   ;      if not, is it start of line?
800
        BNE     LOD1                    ;if not, wait for it
801
        BSR     GBYTE                   ;get first byte of line no.
802
        MOVE.B  D1,(A0)+        ;store it
803
        BSR     GBYTE                   ;get 2nd bye of line no.
804
        MOVE.B  D1,(A0)+        ;       store that, too
805
LOD2:
806
        BSR     GOAUXI  ;       get another text char.
807
        BEQ     LOD2
808
        MOVE.B  D0,(A0)+        ;store it
809
        CMP.B   #CR,D0          ;is it the end of the line?
810
        BNE     LOD2            ;if not, go back for more
811
        BRA     LOD1            ;if so, start a new line
812
LODEND:
813
        MOVE.L  A0,TXTUNF       ;set end-of program pointer
814
        BRA     WSTART          ;back to direct mode
815
 
816
GBYTE:
817
        MOVEQ   #1,D2   ;               get two hex characters from auxiliary
818
        CLR     D1                      ;and store them as a byte in D1
819
GBYTE1:
820
        BSR     GOAUXI          ;       get a char.
821
        BEQ     GBYTE1
822
        CMP.B   #'A',D0
823
        BCS     GBYTE2
824
        SUBQ.B  #7,D0   ;       if greater than 9, adjust
825
GBYTE2:
826
        AND.B   #0xF,D0         ;strip ASCII
827
        LSL.B   #4,D1           ;put nybble into the result
828
        OR.B    D0,D1
829
        DBRA    D2,GBYTE1       ;get another char.
830
        RTS
831
 
832
SAVE:
833
        MOVE.L  TXTBGN,A0;      set pointer to start of prog. area
834
        MOVE.L  TXTUNF,A1       ;set pointer to end of prog. area
835
SAVE1:
836
        MOVE.B  #CR,D0  ;       send out a CR & LF (CP/M likes this)
837
        BSR     GOAUXO
838
        MOVE.B  #LF,D0
839
        BSR     GOAUXO
840
        CMP.L   A0,A1           ;are we finished?
841
        BLS     SAVEND
842
        MOVE.B  #':',D0      ;   if not, start a line
843
        BSR     GOAUXO
844
        MOVE.B  (A0)+,D1        ;send first half of line no.
845
        BSR     PBYTE
846
        MOVE.B  (A0)+,D1        ;and send 2nd half
847
        BSR     PBYTE
848
SAVE2:
849
        MOVE.B  (A0)+,D0;       get a text char.
850
        CMP.B   #CR,D0          ;is it the end of the line?
851
        BEQ     SAVE1           ;if so, send CR & LF and start new line
852
        BSR     GOAUXO          ;send it out
853
        BRA     SAVE2           ;go back for more text
854
SAVEND:
855
        MOVE.B  #'@',D0 ;        send end-of-program indicator
856
        BSR     GOAUXO
857
        MOVE.B  #CR,D0  ;       followed by a CR & LF
858
        BSR     GOAUXO
859
        MOVE.B  #LF,D0
860
        BSR     GOAUXO
861
        MOVE.B  #0x1A,D0        ;and a control-Z to end the CP/M file
862
        BSR     GOAUXO
863
        BRA     WSTART          ;then go do a warm start
864
 
865
PBYTE:
866
        MOVEQ   #1,D2   ;       send two hex characters from D1's low byte
867
PBYTE1:
868
        ROL.B   #4,D1   ;       get the next nybble
869
        MOVE.B  D1,D0
870
        AND.B   #0xF,D0 ;       strip off garbage
871
        ADD.B   #'0',D0   ;      make it into ASCII
872
        CMP.B   #'9',D0
873
        BLS     PBYTE2
874
        ADDQ.B  #7,D0           ;adjust if greater than 9
875
PBYTE2:
876
        BSR     GOAUXO          ;send it out
877
        DBRA    D2,PBYTE1       ;then send the next nybble
878
        RTS
879
 
880
;*
881
;*******************************************************************
882
;*
883
;* *** POKE *** & CALL ***
884
;*
885
;* 'POKE expr1,expr2' stores the byte from 'expr2' into the memory
886
;* address specified by 'expr1'.
887
;*
888
;* 'CALL expr' jumps to the machine language subroutine whose
889
;* starting address is specified by 'expr'.  The subroutine can use
890
;* all registers but must leave the stack the way it found it.
891
;* The subroutine returns to the interpreter by executing an RTS.
892
;*
893
POKE:
894
        BSR     EXPR            ;get the memory address
895
        BSR.L   TSTC            ;it must be followed by a comma
896
        DC.B    ',',PKER-$
897
        MOVE.L  D0,-(SP)        ;save the address
898
        BSR     EXPR            ;get the byte to be POKE'd
899
        MOVE.L  (SP)+,A1        ;get the address back
900
        MOVE.B  D0,(A1)         ;store the byte in memory
901
        BRA     FINISH
902
PKER:
903
        BRA.L   QWHAT   ;       if no comma, say "What?"
904
 
905
;*
906
;*******************************************************************
907
;* Graphics Commands added R. Finch
908
 
909
POINT:
910
        BSR EXPR
911
        BSR     TSTC
912
        DC.B    ',',PKER-$
913
        MOVE.L  D0,-(SP)
914
        BSR     EXPR
915
        MOVE.L  (SP)+,D1
916
        MOVE.L  D0,D2
917
        BSR DrawPixel
918
        BRA FINISH
919
 
920
PENCOLOR:
921
        BSR     EXPR
922
        MOVE.L  d0,GRAPHICS
923
        BRA FINISH
924
FILLCOLOR:
925
        BSR     EXPR
926
        MOVE.L  d0,GRAPHICS+4
927
        BRA FINISH
928
 
929
SPRPOS:
930
        BSR EXPR
931
        BSR     TSTC
932
        DC.B    ',',LINEERR1-$
933
        MOVE.L  D0,-(SP)
934
        BSR     EXPR
935
        BSR     TSTC
936
        DC.B    ',',LINEERR2-$
937
        MOVE.L  D0,-(SP)
938
        BSR     EXPR
939
        MOVE.L  D1,-(SP)
940
        MOVE.L  8(SP),D1        ; D1 = sprite number
941
        ANDI.L  #7,D1
942
        ASL.L   #4,D1           ; D1 * 16
943
        ADD.L   #SPRCTRL,D1     ; D1 = register base
944
        MOVE.L  A1,-(SP)        ; save off A1
945
        MOVE.L  D1,A1           ; A1 = register base
946
        MOVE.W  D0,2(A1)        ; set Y position
947
        MOVE.L  8(SP),D0
948
        MOVE.W  D0,0(A1)        ; set X position
949
        MOVE.L  (SP)+,A1        ; get back A1
950
        MOVE.L  (SP)+,D1        ; get D1 back
951
        ADD.L   #8,SP           ; pop stack
952
        BRA     FINISH
953
 
954
LINE:
955
        BSR     EXPR
956
        BSR     TSTC
957
        DC.B    ',',LINEERR1-$
958
        MOVE.L  D0,-(SP)
959
        BSR     EXPR
960
        BSR     TSTC
961
        DC.B    ',',LINEERR2-$
962
        MOVE.L  D0,-(SP)
963
        BSR     EXPR
964
        BSR     TSTC
965
        DC.B    ',',LINEERR3-$
966
        MOVE.L  D0,-(SP)
967
        BSR     EXPR
968
        MOVE.W  d0,GRAPHICS+14
969
        MOVE.L  (SP)+,d0
970
        MOVE.W  d0,GRAPHICS+12
971
        MOVE.L  (SP)+,d0
972
        MOVE.W  d0,GRAPHICS+10
973
        MOVE.L  (SP)+,d0
974
        MOVE.W  d0,GRAPHICS+8
975
        MOVE.W  #G_DRAWLINE,GRAPHICS+30
976
        BRA             FINISH
977
 
978
LINEERR1:
979
        BRA.L   QWHAT
980
LINEERR2:
981
        ADDQ    #4,SP
982
        BRA.L   QWHAT
983
LINEERR3:
984
        ADD.L   #8,SP
985
        BRA.L   QWHAT
986
 
987
;*
988
;*******************************************************************
989
;*
990
CALL:
991
        BSR     EXPR            ;get the subroutine's address
992
        TST.L   D0              ;make sure we got a valid address
993
        BEQ.L   QHOW    ;       if not, say "How?"
994
        MOVE.L  A0,-(SP);       save the text pointer
995
        MOVE.L  D0,A1
996
        JSR     (A1)            ;jump to the subroutine
997
        MOVE.L  (SP)+,A0        ;restore the text pointer
998
        BRA     FINISH
999
;*
1000
;*******************************************************************
1001
;*
1002
;* *** EXPR ***
1003
;*
1004
;* 'EXPR' evaluates arithmetical or logical expressions.
1005
;* ::=
1006
;*         
1007
;* where  is one of the operators in TAB8 and the result
1008
;* of these operations is 1 if true and 0 if false.
1009
;* ::=(+,-,&,|)(+,-,&,|)(...
1010
;* where () are optional and (... are optional repeats.
1011
;* ::=( <* or /> )(...
1012
;* ::=
1013
;*          
1014
;*          ()
1015
;*  is recursive so that the variable '@' can have an 
1016
;* as an index, functions can have an  as arguments, and
1017
;*  can be an  in parenthesis.
1018
;*
1019
EXPR:
1020
        BSR     EXPR2
1021
        MOVE.L  D0,-(SP);       save  value
1022
        LEA     TAB8,A1         ;look up a relational operator
1023
        LEA     TAB8_1,A2
1024
        BRA     EXEC            ;go do it
1025
 
1026
XP11:
1027
        BSR     XP18    ;       is it ">="?
1028
        BLT     XPRT0           ;no, return D0=0
1029
        BRA     XPRT1           ;else return D0=1
1030
 
1031
XP12:
1032
        BSR     XP18    ;       is it "<>"?
1033
        BEQ     XPRT0           ;no, return D0=0
1034
        BRA     XPRT1           ;else return D0=1
1035
 
1036
XP13:
1037
        BSR     XP18    ;       is it ">"?
1038
        BLE     XPRT0           ;no, return D0=0
1039
        BRA     XPRT1           ;else return D0=1
1040
 
1041
XP14:
1042
        BSR     XP18    ;       is it "<="?
1043
        BGT     XPRT0           ;no, return D0=0
1044
        BRA     XPRT1           ;else return D0=1
1045
 
1046
XP15:
1047
        BSR     XP18    ;       is it "="?
1048
        BNE     XPRT0           ;if not, return D0=0
1049
        BRA     XPRT1           ;else return D0=1
1050
XP15RT:
1051
        RTS
1052
 
1053
XP16:
1054
        BSR     XP18    ;       is it "<"?
1055
        BGE     XPRT0           ;if not, return D0=0
1056
        BRA     XPRT1           ;else return D0=1
1057
XP16RT:
1058
        RTS
1059
 
1060
XPRT0:
1061
        CLR.L   D0      ;       return D0=0 (false)
1062
        RTS
1063
 
1064
XPRT1:
1065
        MOVEQ   #1,D0;          return D0=1 (true)
1066
        RTS
1067
 
1068
XP17:
1069
        MOVE.L  (SP)+,D0        ;it's not a rel. operator
1070
        RTS                     ;return D0=
1071
 
1072
XP18:
1073
        MOVE.L  (SP)+,D0        ;reverse the top two stack items
1074
        MOVE.L  (SP)+,D1
1075
        MOVE.L  D0,-(SP)
1076
        MOVE.L  D1,-(SP)
1077
        BSR     EXPR2           ;do second 
1078
        MOVE.L  (SP)+,D1
1079
        CMP.L   D0,D1   ;       compare with the first result
1080
        RTS                     ;return the result
1081
 
1082
EXPR2:
1083
        BSR.L   TSTC            ;negative sign?
1084
        DC.B    '-',XP20-$
1085
        CLR.L   D0      ;       yes, fake '0-'
1086
        BRA     XP26
1087
XP20:
1088
        BSR.L   TSTC
1089
        DC.B    '!',XP21-$
1090
        CLR.L   D0
1091
        MOVE.L  D0,-(SP)
1092
        BSR             EXPR3
1093
        NOT.L   D0
1094
        JMP             XP24
1095
XP21:
1096
        BSR.L   TSTC    ;       positive sign? ignore it
1097
        DC.B    '+',XP22-$
1098
XP22:
1099
        BSR     EXPR3           ;first 
1100
XP23:
1101
        BSR.L   TSTC    ;       add?
1102
        DC.B    '+',XP25-$
1103
        MOVE.L  D0,-(SP)        ;yes, save the value
1104
        BSR     EXPR3           ;get the second 
1105
XP24:
1106
        MOVE.L  (SP)+,D1
1107
        ADD.L   D1,D0   ;       add it to the first 
1108
        BVS.L   QHOW    ;       branch if there's an overflow
1109
        BRA     XP23    ;       else go back for more operations
1110
XP25:
1111
        BSR.L   TSTC            ;subtract?
1112
        DC.B    '-',XP27-$      ; was XP42-$
1113
XP26:
1114
        MOVE.L  D0,-(SP)        ;yes, save the result of 1st 
1115
        BSR     EXPR3           ;get second 
1116
        NEG.L   D0              ;change its sign
1117
        JMP     XP24            ;and do an addition
1118
XP27:
1119
        BSR.L   TSTC
1120
        DC.B    '&',XP28-$
1121
        MOVE.L  D0,-(SP)
1122
        BSR     EXPR3
1123
        MOVE.L  (SP)+,D1
1124
        AND.L   D1,D0
1125
        BRA             XP23
1126
XP28:
1127
        BSR.L   TSTC
1128
        DC.B    '|',XP42-$
1129
        MOVE.L  D0,-(SP)
1130
        BSR     EXPR3
1131
        MOVE.L  (SP)+,D1
1132
        OR.L    D1,D0
1133
        BRA             XP23
1134
 
1135
EXPR3:
1136
        BSR     EXPR4           ;get first 
1137
XP31:
1138
        BSR.L   TSTC    ;       multiply?
1139
        DC.B    '*',XP34-$
1140
        MOVE.L  D0,-(SP);       yes, save that first result
1141
        BSR     EXPR4           ;get second 
1142
        MOVE.L  (SP)+,D1
1143
        BSR.L   MULT32  ;       multiply the two
1144
        BRA     XP31            ;then look for more terms
1145
XP34:
1146
        BSR.L   TSTC;           divide?
1147
        DC.B    '/',XP42-$
1148
        MOVE.L  D0,-(SP);       save result of 1st 
1149
        BSR     EXPR4           ;get second 
1150
        MOVE.L  (SP)+,D1
1151
        EXG     D0,D1
1152
        BSR.L   DIV32   ;       do the division
1153
        BRA     XP31            ;go back for any more terms
1154
 
1155
EXPR4:
1156
        LEA     TAB4,A1 ;       find possible function
1157
        LEA     TAB4_1,A2
1158
        BRA     EXEC
1159
XP40:
1160
        BSR     TSTV    ;       nope, not a function
1161
        BCS     XP41            ;nor a variable
1162
        MOVE.L  D0,A1
1163
        CLR.L   D0
1164
        MOVE.L  (A1),D0 ;       if a variable, return its value in D0
1165
EXP4RT:
1166
        RTS
1167
XP41:
1168
        BSR.L   TSTNUM  ;       or is it a number?
1169
        MOVE.L  D1,D0
1170
        TST     D2              ;(if not, # of digits will be zero)
1171
        BNE     EXP4RT  ;       if so, return it in D0
1172
PARN:
1173
        BSR.L   TSTC    ;       else look for ( EXPR )
1174
        DC.B    '(',XP43-$
1175
        BSR     EXPR
1176
        BSR.L   TSTC
1177
        DC.B    ')',XP43-$
1178
XP42:
1179
        RTS
1180
XP43:
1181
        BRA.L   QWHAT   ;       else say "What?"
1182
 
1183
;*
1184
;* ===== Test for a valid variable name.  Returns Carry=1 if not
1185
;*      found, else returns Carry=0 and the address of the
1186
;*      variable in D0.
1187
 
1188
TSTV:
1189
        BSR.L   IGNBLK
1190
        CLR.L   D0
1191
        MOVE.B  (A0),D0 ;       look at the program text
1192
        SUB.B   #'@',D0
1193
        BCS     TSTVRT  ;       C=1: not a variable
1194
        BNE     TV1             ;branch if not "@" array
1195
        ADDQ    #1,A0   ;       If it is, it should be
1196
        BSR     PARN            ;followed by (EXPR) as its index.
1197
        ADD.L   D0,D0
1198
        BCS.L   QHOW    ;       say "How?" if index is too big
1199
        ADD.L   D0,D0
1200
        BCS.L   QHOW
1201
        MOVE.L  D0,-(SP)        ;save the index
1202
        BSR.L   SIZE_           ;get amount of free memory
1203
        MOVE.L  (SP)+,D1        ;get back the index
1204
        CMP.L   D1,D0           ;see if there's enough memory
1205
        BLS.L   QSORRY          ;if not, say "Sorry"
1206
        MOVE.L  VARBGN,D0       ;put address of array element...
1207
        SUB.L   D1,D0           ;into D0
1208
        RTS
1209
TV1:
1210
        CMP.B   #27,D0          ;if not @, is it A through Z?
1211
        EOR     #1,CCR
1212
        BCS     TSTVRT          ;if not, set Carry and return
1213
        ADDQ    #1,A0   ;       else bump the text pointer
1214
;
1215
        CLR.L   D1
1216
        MOVE.B  (a0),D1
1217
        BSR             CVT26
1218
        cmpi.b  #0xff,d1
1219
        beq             tv2
1220
        ADDQ    #1,A0   ; bump text pointer
1221
        asl.l   #5,D1
1222
        ADD.L   D1,D0
1223
tv2:
1224
        ADD     D0,D0           ;compute the variable's address
1225
        ADD     D0,D0
1226
        MOVE.L  VARBGN,D1
1227
        ADD     D1,D0           ;and return it in D0 with Carry=0
1228
TSTVRT:
1229
        RTS
1230
 
1231
CVT26:
1232
        cmpi.b  #'A',d1
1233
        blo             CVT26a
1234
        cmpi.b  #'Z',d1
1235
        bhi             CVT26a
1236
        subi.b  #'A',d1
1237
        rts
1238
CVT26a:
1239
        moveq   #-1,d1
1240
        rts
1241
;*
1242
;* ===== Multiplies the 32 bit values in D0 and D1, returning
1243
;*      the 32 bit result in D0.
1244
;*
1245
MULT32:
1246
        MOVE.L  D1,D4
1247
        EOR.L   D0,D4   ;       see if the signs are the same
1248
        TST.L   D0              ;take absolute value of D0
1249
        BPL     MLT1
1250
        NEG.L   D0
1251
MLT1:
1252
        TST.L   D1      ;       take absolute value of D1
1253
        BPL     MLT2
1254
        NEG.L   D1
1255
MLT2:
1256
        CMP.L   #0xFFFF,D1      ;is second argument <= 16 bits?
1257
        BLS     MLT3    ;       OK, let it through
1258
        EXG     D0,D1   ;       else swap the two arguments
1259
        CMP.L   #0xFFFF,D1      ;and check 2nd argument again
1260
        BHI.L   QHOW            ;one of them MUST be 16 bits
1261
MLT3:
1262
        MOVE    D0,D2   ;       prepare for 32 bit X 16 bit multiply
1263
        MULU    D1,D2           ;multiply low word
1264
        SWAP    D0
1265
        MULU    D1,D0           ;multiply high word
1266
        SWAP    D0
1267
;*** Rick Murray's bug correction follows:
1268
        TST     D0              ;if lower word not 0, then overflow
1269
        BNE.L   QHOW    ;       if overflow, say "How?"
1270
        ADD.L   D2,D0   ;       D0 now holds the product
1271
        BMI.L   QHOW    ;       if sign bit set, it's an overflow
1272
        TST.L   D4              ;were the signs the same?
1273
        BPL     MLTRET
1274
        NEG.L   D0              ;if not, make the result negative
1275
MLTRET:
1276
        RTS
1277
 
1278
;*
1279
;* ===== Divide the 32 bit value in D0 by the 32 bit value in D1.
1280
;*      Returns the 32 bit quotient in D0, remainder in D1.
1281
;*
1282
DIV32:
1283
        TST.L   D1              ;check for divide-by-zero
1284
        BEQ.L   QHOW            ;if so, say "How?"
1285
        MOVE.L  D1,D2
1286
        MOVE.L  D1,D4
1287
        EOR.L   D0,D4           ;see if the signs are the same
1288
        TST.L   D0              ;take absolute value of D0
1289
        BPL     DIV1
1290
        NEG.L   D0
1291
DIV1:
1292
        TST.L   D1      ;       take absolute value of D1
1293
        BPL     DIV2
1294
        NEG.L   D1
1295
DIV2:
1296
        MOVEQ   #31,D3  ;       iteration count for 32 bits
1297
        MOVE.L  D0,D1
1298
        CLR.L   D0
1299
DIV3:
1300
        ADD.L   D1,D1   ;       (This algorithm was translated from
1301
        ADDX.L  D0,D0           ;the divide routine in Ron Cain's
1302
        BEQ     DIV4            ;Small-C run time library.)
1303
        CMP.L   D2,D0
1304
        BMI     DIV4
1305
        ADDQ.L  #1,D1
1306
        SUB.L   D2,D0
1307
DIV4:
1308
        DBRA    D3,DIV3
1309
        EXG     D0,D1   ;       put rem. & quot. in proper registers
1310
        TST.L   D4      ;       were the signs the same?
1311
        BPL     DIVRT
1312
        NEG.L   D0      ;       if not, results are negative
1313
        NEG.L   D1
1314
DIVRT:
1315
        RTS
1316
 
1317
;*
1318
;* ===== The PEEK function returns the byte stored at the address
1319
;*      contained in the following expression.
1320
;*
1321
PEEK:
1322
        BSR     PARN    ;       get the memory address
1323
        MOVE.L  D0,A1
1324
        CLR.L   D0              ;upper 3 bytes will be zero
1325
        MOVE.B  (A1),D0 ;       get the addressed byte
1326
        RTS                     ;and return it
1327
 
1328
;*
1329
;* ===== The RND function returns a random number from 1 to
1330
;*      the value of the following expression in D0.
1331
;*  Uses hardware rand# generator R. Finch
1332
RND:
1333
        BSR     PARN    ;       get the upper limit
1334
        TST.L   D0      ;       it must be positive and non-zero
1335
        BEQ.L   QHOW
1336
        BMI.L   QHOW
1337
        MOVE.L  D0,D1
1338
        MOVE.W  RANDOM+2,D0
1339
        SWAP    D0
1340
        MOVE.W  RANDOM,D0
1341
        BCLR    #31,D0  ;       make sure it's positive
1342
        BSR     DIV32           ;RND(n)=MOD(number,n)+1
1343
        MOVE.L  D1,D0   ;       MOD is the remainder of the div.
1344
        ADDQ.L  #1,D0
1345
        RTS
1346
 
1347
;*
1348
;* ===== The ABS function returns an absolute value in D0.
1349
;*
1350
ABS:
1351
        BSR     PARN            ;get the following expr.'s value
1352
        TST.L   D0
1353
        BPL     ABSRT
1354
        NEG.L   D0              ;if negative, complement it
1355
        BMI.L   QHOW    ;       if still negative, it was too big
1356
ABSRT:
1357
        RTS
1358
 
1359
;* RTF
1360
;* ===== The SGN function returns the sign value in D0.
1361
;*
1362
SGN:
1363
        BSR             PARN    ;get the following expr.'s value
1364
        TST.L   D0
1365
        BEQ             SGNRT
1366
        BMI             SGNMI
1367
        MOVEQ   #1,d0
1368
SGNRT:
1369
        RTS
1370
SGNMI:
1371
        MOVEQ   #-1,d0
1372
        RTS
1373
 
1374
;*
1375
;* ===== The SIZE function returns the size of free memory in D0.
1376
;*
1377
SIZE_:
1378
        MOVE.L  VARBGN,D0       ;get the number of free bytes...
1379
        SUB.L   TXTUNF,D0       ;between 'TXTUNF' and 'VARBGN'
1380
        RTS                     ;return the number in D0
1381
 
1382
;* RTF
1383
;* ===== return the millisecond time value
1384
;*
1385
TICK:
1386
        move.l  Milliseconds,d0
1387
        rts
1388
 
1389
TEMP:
1390
        bsr             ReadTemp
1391
        andi.l  #0xffff,d0
1392
        rts
1393
 
1394
;*
1395
;*******************************************************************
1396
;*
1397
;* *** SETVAL *** FIN *** ENDCHK *** ERROR (& friends) ***
1398
;*
1399
;* 'SETVAL' expects a variable, followed by an equal sign and then
1400
;* an expression.  It evaluates the expression and sets the variable
1401
;* to that value.
1402
;*
1403
;* 'FIN' checks the end of a command.  If it ended with ":",
1404
;* execution continues. If it ended with a CR, it finds the
1405
;* the next line and continues from there.
1406
;*
1407
;* 'ENDCHK' checks if a command is ended with a CR. This is
1408
;* required in certain commands, such as GOTO, RETURN, STOP, etc.
1409
;*
1410
;* 'ERROR' prints the string pointed to by A0. It then prints the
1411
;* line pointed to by CURRNT with a "?" inserted at where the
1412
;* old text pointer (should be on top of the stack) points to.
1413
;* Execution of Tiny BASIC is stopped and a warm start is done.
1414
;* If CURRNT is zero (indicating a direct command), the direct
1415
;* command is not printed. If CURRNT is -1 (indicating
1416
;* 'INPUT' command in progress), the input line is not printed
1417
;* and execution is not terminated but continues at 'INPERR'.
1418
;*
1419
;* Related to 'ERROR' are the following:
1420
;* 'QWHAT' saves text pointer on stack and gets "What?" message.
1421
;* 'AWHAT' just gets the "What?" message and jumps to 'ERROR'.
1422
;* 'QSORRY' and 'ASORRY' do the same kind of thing.
1423
;* 'QHOW' and 'AHOW' also do this for "How?".
1424
;*
1425
SETVAL:
1426
        BSR     TSTV    ;       variable name?
1427
        BCS     QWHAT           ;if not, say "What?"
1428
        MOVE.L  D0,-(SP);       save the variable's address
1429
        BSR.L   TSTC    ;       get past the "=" sign
1430
        DC.B    '=',SV1-$
1431
        BSR     EXPR    ;       evaluate the expression
1432
        MOVE.L  (SP)+,A6
1433
        MOVE.L  D0,(A6) ;       and save its value in the variable
1434
        RTS
1435
SV1:
1436
        BRA     QWHAT   ;       if no "=" sign
1437
 
1438
FIN:
1439
        BSR.L   TSTC    ;       *** FIN ***
1440
        DC.B    ':',FI1-$
1441
        ADDQ.L  #4,SP   ;       if ":", discard return address
1442
        BRA     RUNSML  ;       continue on the same line
1443
FI1:
1444
        BSR.L   TSTC    ;       not ":", is it a CR?
1445
        DC.B    CR,FI2-$
1446
        ADDQ.L  #4,SP   ;       yes, purge return address
1447
        BRA     RUNNXL          ;execute the next line
1448
FI2:
1449
        RTS                     ;else return to the caller
1450
 
1451
ENDCHK:
1452
        BSR.L   IGNBLK
1453
        CMP.B   #CR,(A0);       does it end with a CR?
1454
        BNE     QWHAT   ;       if not, say "WHAT?"
1455
        RTS
1456
 
1457
QWHAT:
1458
        MOVE.L  A0,-(SP)
1459
AWHAT:
1460
        LEA     WHTMSG,A6
1461
ERROR:
1462
        BSR.L   PRMESG  ;       display the error message
1463
        MOVE.L  (SP)+,A0        ;restore the text pointer
1464
        MOVE.L  CURRNT,D0       ;get the current line number
1465
        BEQ     WSTART          ;if zero, do a warm start
1466
        CMP.L   #-1,D0          ;is the line no. pointer = -1?
1467
        BEQ     INPERR          ;if so, redo input
1468
        MOVE.B  (A0),-(SP)      ;save the char. pointed to
1469
        CLR.B   (A0)            ;put a zero where the error is
1470
        MOVE.L  CURRNT,A1       ;point to start of current line
1471
        BSR.L   PRTLN           ;display the line in error up to the 0
1472
        MOVE.B  (SP)+,(A0)      ;restore the character
1473
        MOVE.B  #'?',D0     ;    display a "?"
1474
        BSR     GOOUT
1475
        CLR     D0
1476
        SUBQ.L  #1,A1           ;point back to the error char.
1477
        BSR.L   PRTSTG          ;display the rest of the line
1478
        BRA     WSTART          ;and do a warm start
1479
QSORRY:
1480
        MOVE.L  A0,-(SP)
1481
ASORRY:
1482
        LEA     SRYMSG,A6
1483
        BRA     ERROR
1484
QHOW:
1485
        MOVE.L  A0,-(SP)        ;Error: "How?"
1486
AHOW:
1487
        LEA     HOWMSG,A6
1488
        BRA     ERROR
1489
;*
1490
;*******************************************************************
1491
;*
1492
;* *** GETLN *** FNDLN (& friends) ***
1493
;*
1494
;* 'GETLN' reads in input line into 'BUFFER'. It first prompts with
1495
;* the character in D0 (given by the caller), then it fills the
1496
;* buffer and echos. It ignores LF's but still echos
1497
;* them back. Control-H is used to delete the last character
1498
;* entered (if there is one), and control-X is used to delete the
1499
;* whole line and start over again. CR signals the end of a line,
1500
;* and causes 'GETLN' to return.
1501
;*
1502
GETLN:
1503
        BSR     GOOUT           ;display the prompt
1504
        MOVE.B  #' ',D0      ;   and a space
1505
        BSR     GOOUT
1506
        LEA     BUFFER,A0;      A0 is the buffer pointer
1507
GL1:
1508
        BSR.L   CHKIO;          check keyboard
1509
        BEQ     GL1     ;       wait for a char. to come in
1510
        CMP.B   #CTRLH,D0       ;delete last character?
1511
        BEQ     GL3     ;       if so
1512
        CMP.B   #CTRLX,D0;      delete the whole line?
1513
        BEQ     GL4     ;       if so
1514
        CMP.B   #CR,D0  ;       accept a CR
1515
        BEQ     GL2
1516
        CMP.B   #' ',D0  ;       if other control char., discard it
1517
        BCS     GL1
1518
GL2:
1519
        MOVE.B  D0,(A0)+;       save the char.
1520
        BSR     GOOUT           ;echo the char back out
1521
        CMP.B   #CR,D0  ;       if it's a CR, end the line
1522
        BEQ     GL7
1523
        CMP.L   #(BUFFER+BUFLEN-1),A0   ;any more room?
1524
        BCS     GL1     ;       yes: get some more, else delete last char.
1525
GL3:
1526
        MOVE.B  #CTRLH,D0       ;delete a char. if possible
1527
        BSR     GOOUT
1528
        MOVE.B  #' ',D0
1529
        BSR     GOOUT
1530
        CMP.L   #BUFFER,A0      ;any char.'s left?
1531
        BLS     GL1             ;if not
1532
        MOVE.B  #CTRLH,D0;      if so, finish the BS-space-BS sequence
1533
        BSR     GOOUT
1534
        SUBQ.L  #1,A0   ;       decrement the text pointer
1535
        BRA     GL1             ;back for more
1536
GL4:
1537
        MOVE.L  A0,D1   ;       delete the whole line
1538
        SUB.L   #BUFFER,D1;     figure out how many backspaces we need
1539
        BEQ     GL6             ;if none needed, branch
1540
        SUBQ    #1,D1   ;       adjust for DBRA
1541
GL5:
1542
        MOVE.B  #CTRLH,D0       ;and display BS-space-BS sequences
1543
        BSR     GOOUT
1544
        MOVE.B  #' ',D0
1545
        BSR     GOOUT
1546
        MOVE.B  #CTRLH,D0
1547
        BSR     GOOUT
1548
        DBRA    D1,GL5
1549
GL6:
1550
        LEA     BUFFER,A0       ;reinitialize the text pointer
1551
        BRA     GL1             ;and go back for more
1552
GL7:
1553
        MOVE.B  #LF,D0  ;       echo a LF for the CR
1554
        BSR     GOOUT
1555
        RTS
1556
 
1557
;*
1558
;*******************************************************************
1559
;*
1560
;* *** FNDLN (& friends) ***
1561
;*
1562
;* 'FNDLN' finds a line with a given line no. (in D1) in the
1563
;* text save area.  A1 is used as the text pointer. If the line
1564
;* is found, A1 will point to the beginning of that line
1565
;* (i.e. the high byte of the line no.), and flags are NC & Z.
1566
;* If that line is not there and a line with a higher line no.
1567
;* is found, A1 points there and flags are NC & NZ. If we reached
1568
;* the end of the text save area and cannot find the line, flags
1569
;* are C & NZ.
1570
;* 'FNDLN' will initialize A1 to the beginning of the text save
1571
;* area to start the search. Some other entries of this routine
1572
;* will not initialize A1 and do the search.
1573
;* 'FNDLNP' will start with A1 and search for the line no.
1574
;* 'FNDNXT' will bump A1 by 2, find a CR and then start search.
1575
;* 'FNDSKP' uses A1 to find a CR, and then starts the search.
1576
;*
1577
FNDLN:
1578
        CMP.L   #0xFFFF,D1      ;line no. must be < 65535
1579
        BCC     QHOW
1580
        MOVE.L  TXTBGN,A1       ;init. the text save pointer
1581
 
1582
FNDLNP:
1583
        MOVE.L  TXTUNF,A2       ;check if we passed the end
1584
        SUBQ.L  #1,A2
1585
        CMPA.L  A1,A2
1586
        BCS     FNDRET  ;       if so, return with Z=0 & C=1
1587
        MOVE.B  (A1),D2 ;if not, get a line no.
1588
        LSL.W   #8,D2
1589
        MOVE.B  1(A1),D2
1590
        CMP.W   D1,D2           ;is this the line we want?
1591
        BCS     FNDNXT          ;no, not there yet
1592
FNDRET:
1593
        RTS                     ;return the cond. codes
1594
 
1595
FNDNXT:
1596
        ADDQ.L  #2,A1;          find the next line
1597
 
1598
FNDSKP:
1599
        CMP.B   #CR,(A1)+       ;try to find a CR
1600
        BNE     FNDSKP          ;keep looking
1601
        BRA     FNDLNP          ;check if end of text
1602
 
1603
;*
1604
;*******************************************************************
1605
;*
1606
;* *** MVUP *** MVDOWN *** POPA *** PUSHA ***
1607
;*
1608
;* 'MVUP' moves a block up from where A1 points to where A2 points
1609
;* until A1=A3
1610
;*
1611
;* 'MVDOWN' moves a block down from where A1 points to where A3
1612
;* points until A1=A2
1613
;*
1614
;* 'POPA' restores the 'FOR' loop variable save area from the stack
1615
;*
1616
;* 'PUSHA' stacks for 'FOR' loop variable save area onto the stack
1617
;*
1618
MVUP:
1619
        CMP.L   A1,A3   ;       see the above description
1620
        BEQ     MVRET
1621
        MOVE.B  (A1)+,(A2)+
1622
        BRA     MVUP
1623
MVRET:
1624
        RTS
1625
 
1626
MVDOWN:
1627
        CMP.L   A1,A2   ;       see the above description
1628
        BEQ     MVRET
1629
        MOVE.B  -(A1),-(A3)
1630
        BRA     MVDOWN
1631
 
1632
POPA:
1633
        MOVE.L  (SP)+,A6        ;A6 = return address
1634
        MOVE.L  (SP)+,LOPVAR    ;restore LOPVAR, but zero means no more
1635
        BEQ     PP1
1636
        MOVE.L  (SP)+,LOPINC    ;if not zero, restore the rest
1637
        MOVE.L  (SP)+,LOPLMT
1638
        MOVE.L  (SP)+,LOPLN
1639
        MOVE.L  (SP)+,LOPPT
1640
PP1:
1641
        JMP     (A6)    ;       return
1642
 
1643
PUSHA:
1644
        MOVE.L  STKLMT,D1       ;Are we running out of stack room?
1645
        SUB.L   SP,D1
1646
        BCC             QSORRY          ;if so, say we're sorry
1647
        MOVE.L  (SP)+,A6        ;else get the return address
1648
        MOVE.L  LOPVAR,D1       ;save loop variables
1649
        BEQ             PU1             ;if LOPVAR is zero, that's all
1650
        MOVE.L  LOPPT,-(SP)     ;else save all the others
1651
        MOVE.L  LOPLN,-(SP)
1652
        MOVE.L  LOPLMT,-(SP)
1653
        MOVE.L  LOPINC,-(SP)
1654
PU1:
1655
        MOVE.L  D1,-(SP)
1656
        JMP     (A6)            ;return
1657
 
1658
;*
1659
;*******************************************************************
1660
;*
1661
;* *** PRTSTG *** QTSTG *** PRTNUM *** PRTLN ***
1662
;*
1663
;* 'PRTSTG' prints a string pointed to by A1. It stops printing
1664
;* and returns to the caller when either a CR is printed or when
1665
;* the next byte is the same as what was passed in D0 by the
1666
;* caller.
1667
;*
1668
;* 'QTSTG' looks for an underline (back-arrow on some systems),
1669
;* single-quote, or double-quote.  If none of these are found, returns
1670
;* to the caller.  If underline, outputs a CR without a LF.  If single
1671
;* or double quote, prints the quoted string and demands a matching
1672
;* end quote.  After the printing, the next 2 bytes of the caller are
1673
;* skipped over (usually a short branch instruction).
1674
;*
1675
;* 'PRTNUM' prints the 32 bit number in D1, leading blanks are added if
1676
;* needed to pad the number of spaces to the number in D4.
1677
;* However, if the number of digits is larger than the no. in
1678
;* D4, all digits are printed anyway. Negative sign is also
1679
;* printed and counted in, positive sign is not.
1680
;*
1681
;* 'PRTLN' prints the saved text line pointed to by A1
1682
;* with line no. and all.
1683
;*
1684
PRTSTG:
1685
        MOVE.B  D0,D1   ;       save the stop character
1686
PS1:
1687
        MOVE.B  (A1)+,D0        ;get a text character
1688
        CMP.B   D0,D1           ;same as stop character?
1689
        BEQ             PRTRET          ;if so, return
1690
        BSR             GOOUT           ;display the char.
1691
        CMP.B   #CR,D0          ;;is it a C.R.?
1692
        BNE             PS1             ;no, go back for more
1693
        MOVE.B  #LF,D0  ;       yes, add a L.F.
1694
        BSR             GOOUT
1695
PRTRET:
1696
        RTS                     ;then return
1697
 
1698
QTSTG:
1699
        BSR.L   TSTC;           *** QTSTG ***
1700
        DC.B    '"',QT3-$
1701
        MOVE.B  #'"',D0  ;       it is a "
1702
QT1:
1703
        MOVE.L  A0,A1
1704
        BSR     PRTSTG          ;print until another
1705
        MOVE.L  A1,A0
1706
        MOVE.L  (SP)+,A1;       pop return address
1707
        CMP.B   #LF,D0  ;       was last one a CR?
1708
        BEQ     RUNNXL          ;if so, run next line
1709
QT2:
1710
        ADDQ.L  #2,A1   ;       skip 2 bytes on return
1711
        JMP     (A1)            ;return
1712
QT3:
1713
        BSR.L   TSTC    ;       is it a single quote?
1714
        DC.B    '\'',QT4-$
1715
        MOVE.B  #'''',D0  ;      if so, do same as above
1716
        BRA     QT1
1717
QT4:
1718
        BSR.L   TSTC            ;is it an underline?
1719
        DC.B    '_',QT5-$
1720
        MOVE.B  #CR,D0          ;if so, output a CR without LF
1721
        BSR.L   GOOUT
1722
        MOVE.L  (SP)+,A1        ;pop return address
1723
        BRA     QT2
1724
QT5:
1725
        RTS                     ;none of the above
1726
 
1727
PRTNUM:
1728
        movem.l d0/d1/d4/a1/a5,-(a7)
1729
        lea             scratch1,a5
1730
        move.l  d1,d0
1731
        jsr             HEX2DEC
1732
        lea             scratch1,a5
1733
PN8:
1734
        move.b  (a5)+,d0
1735
        beq             PN7
1736
        dbra    d4,PN8
1737
PN7:
1738
        tst.w   d4
1739
        bmi             PN9
1740
        MOVE.B  #' ',D0  ;       display the required leading spaces
1741
        BSR             GOOUT
1742
        DBRA    D4,PN7
1743
PN9:
1744
        lea             scratch1,a1
1745
        jsr             DisplayString
1746
        movem.l (a7)+,d0/d1/d4/a1/a5
1747
        rts
1748
 
1749
;PRTNUM
1750
;       MOVE.L  D1,D3   ;       save the number for later
1751
;       MOVE.L  D4,-(SP)        ;save the width value
1752
;       MOVE.W  #0xFFFF,-(SP)   ;flag for end of digit string
1753
;       TST.L   D1              ;is it negative?
1754
;       BPL     PN1             ;if not
1755
;       NEG.L   D1      ;       else make it positive
1756
;       SUBQ    #1,D4   ;       one less for width count
1757
;PN1:
1758
;       DIVU    #10,D1  ;       get the next digit
1759
;       BVS     PNOV    ;       overflow flag set?
1760
;       MOVE.L  D1,D0   ;       if not, save remainder
1761
;       AND.L   #0xFFFF,D1      ;strip the remainder
1762
;       BRA     TOASCII         ;skip the overflow stuff
1763
;PNOV:
1764
;       MOVE    D1,D0   ;       prepare for long word division
1765
;       CLR.W   D1              ;zero out low word
1766
;       SWAP    D1              ;high word into low
1767
;       DIVU    #10,D1  ;       divide high word
1768
;       MOVE    D1,D2   ;       save quotient
1769
;       MOVE    D0,D1   ;       low word into low
1770
;       DIVU    #10,D1  ;       divide low word
1771
;       MOVE.L  D1,D0   ;       D0 = remainder
1772
;       SWAP    D1              ;       R/Q becomes Q/R
1773
;       MOVE    D2,D1   ;       D1 is low/high
1774
;       SWAP    D1              ;       D1 is finally high/low
1775
;TOASCII:
1776
;       SWAP    D0              ;       get remainder
1777
;       MOVE.W  D0,-(SP);       stack it as a digit
1778
;       SWAP    D0
1779
;       SUBQ    #1,D4   ;       decrement width count
1780
;       TST.L   D1              ;if quotient is zero, we're done
1781
;       BNE     PN1
1782
;       SUBQ    #1,D4   ;       adjust padding count for DBRA
1783
;       BMI     PN4             ;skip padding if not needed
1784
;PN3:
1785
;       MOVE.B  #' ',D0  ;       display the required leading spaces
1786
;       BSR     GOOUT
1787
;       DBRA    D4,PN3
1788
;PN4:
1789
;       TST.L   D3              ;is number negative?
1790
;       BPL     PN5
1791
;       MOVE.B  #'-',D0  ;       if so, display the sign
1792
;       BSR     GOOUT
1793
;PN5:
1794
;       MOVE.W  (SP)+,D0        ;now unstack the digits and display
1795
;       BMI     PNRET           ;until the flag code is reached
1796
;       ADD.B   #'0',D0   ;      make into ASCII
1797
;       BSR     GOOUT
1798
;       BRA     PN5
1799
;PNRET:
1800
;       MOVE.L  (SP)+,D4        ;restore width value
1801
;       RTS
1802
 
1803
PRTLN:
1804
        CLR.L   D1
1805
        MOVE.B  (A1)+,D1        ;get the binary line number
1806
        LSL     #8,D1
1807
        MOVE.B  (A1)+,D1
1808
        MOVEQ   #5,D4           ;display a 5 digit line no.
1809
        BSR     PRTNUM
1810
        MOVE.B  #' ',D0      ;   followed by a blank
1811
        BSR     GOOUT
1812
        CLR     D0              ;stop char. is a zero
1813
        BRA     PRTSTG  ;       display the rest of the line
1814
 
1815
;*
1816
;* ===== Test text byte following the call to this subroutine. If it
1817
;*      equals the byte pointed to by A0, return to the code following
1818
;*      the call. If they are not equal, branch to the point
1819
;*      indicated by the offset byte following the text byte.
1820
;*
1821
TSTC:
1822
        BSR     IGNBLK          ;ignore leading blanks
1823
        MOVE.L  (SP)+,A1        ;get the return address
1824
        MOVE.B  (A1)+,D1        ;get the byte to compare
1825
        CMP.B   (A0),D1         ;is it = to what A0 points to?
1826
        BEQ     TC1             ;if so
1827
        CLR.L   D1              ;If not, add the second
1828
        MOVE.B  (A1),D1 ;       byte following the call to
1829
        ADD.L   D1,A1   ;       the return address.
1830
        JMP     (A1)            ;jump to the routine
1831
TC1:
1832
        ADDQ.L  #1,A0   ;       if equal, bump text pointer
1833
        ADDQ.L  #1,A1   ;       Skip the 2 bytes following
1834
        JMP     (A1)            ;the call and continue.
1835
 
1836
;*
1837
;* ===== See if the text pointed to by A0 is a number. If so,
1838
;*      return the number in D1 and the number of digits in D2,
1839
;*      else return zero in D1 and D2.
1840
;*
1841
TSTNUM:
1842
        CLR.L   D1              ;initialize return parameters
1843
        CLR     D2
1844
        BSR     IGNBLK          ;skip over blanks
1845
TN1:
1846
        CMP.B   #'0',(A0) ;      is it less than zero?
1847
        BCS     TSNMRET         ;if so, that's all
1848
        CMP.B   #'9',(A0) ;      is it greater than nine?
1849
        BHI     TSNMRET         ;if so, return
1850
        CMP.L   #214748364,D1   ;see if there's room for new digit
1851
        BCC     QHOW            ;if not, we've overflowd
1852
        MOVE.L  D1,D0   ;       quickly multiply result by 10
1853
        ADD.L   D1,D1
1854
        ADD.L   D1,D1
1855
        ADD.L   D0,D1
1856
        ADD.L   D1,D1
1857
        MOVE.B  (A0)+,D0        ;add in the new digit
1858
        AND.L   #0xF,D0
1859
        ADD.L   D0,D1
1860
        ADDQ    #1,D2           ;increment the no. of digits
1861
        BRA     TN1
1862
TSNMRET:
1863
        RTS
1864
 
1865
;*
1866
;* ===== Skip over blanks in the text pointed to by A0.
1867
;*
1868
IGNBLK:
1869
        CMP.B   #' ',(A0)   ;    see if it's a space
1870
        BNE     IGBRET          ;if so, swallow it
1871
IGB1:
1872
        ADDQ.L  #1,A0   ;       increment the text pointer
1873
        BRA     IGNBLK
1874
IGBRET:
1875
        RTS
1876
 
1877
;*
1878
;* ===== Convert the line of text in the input buffer to upper
1879
;*      case (except for stuff between quotes).
1880
;*
1881
TOUPBUF:
1882
        LEA     BUFFER,A0       ;set up text pointer
1883
        CLR.B   D1              ;clear quote flag
1884
TOUPB1:
1885
        MOVE.B  (A0)+,D0        ;get the next text char.
1886
        CMP.B   #CR,D0          ;is it end of line?
1887
        BEQ     TOUPBRT         ;if so, return
1888
        CMP.B   #'"',D0  ;       a double quote?
1889
        BEQ     DOQUO
1890
        CMP.B   #'''',D0  ;      or a single quote?
1891
        BEQ     DOQUO
1892
        TST.B   D1              ;inside quotes?
1893
        BNE     TOUPB1          ;if so, do the next one
1894
        BSR     TOUPPER         ;convert to upper case
1895
        MOVE.B  D0,-(A0);       store it
1896
        ADDQ.L  #1,A0
1897
        BRA     TOUPB1          ;and go back for more
1898
TOUPBRT:
1899
        RTS
1900
 
1901
DOQUO:
1902
        TST.B   D1      ;       are we inside quotes?
1903
        BNE     DOQUO1
1904
        MOVE.B  D0,D1   ;       if not, toggle inside-quotes flag
1905
        BRA     TOUPB1
1906
DOQUO1:
1907
        CMP.B   D0,D1   ;       make sure we're ending proper quote
1908
        BNE     TOUPB1          ;if not, ignore it
1909
        CLR.B   D1              ;else clear quote flag
1910
        BRA     TOUPB1
1911
 
1912
;*
1913
;* ===== Convert the character in D0 to upper case
1914
;*
1915
TOUPPER:
1916
        CMP.B   #'a',D0   ;      is it < 'a'?
1917
        BCS     TOUPRET
1918
        CMP.B   #'z',D0        ; or > 'z'?
1919
        BHI     TOUPRET
1920
        SUB.B   #32,D0          ;if not, make it upper case
1921
TOUPRET:
1922
        RTS
1923
 
1924
;*
1925
;* 'CHKIO' checks the input. If there's no input, it will return
1926
;* to the caller with the Z flag set. If there is input, the Z
1927
;* flag is cleared and the input byte is in D0. However, if a
1928
;* control-C is read, 'CHKIO' will warm-start BASIC and will not
1929
;* return to the caller.
1930
;*
1931
CHKIO:
1932
        BSR.L   GOIN    ;       get input if possible
1933
        BEQ     CHKRET          ;if Zero, no input
1934
        CMP.B   #CTRLC,D0       ;is it control-C?
1935
        BNE     CHKRET          ;if not
1936
        BRA.L   WSTART          ;if so, do a warm start
1937
CHKRET:
1938
        RTS
1939
 
1940
;*
1941
;* ===== Display a CR-LF sequence
1942
;*
1943
CRLF1:
1944
        LEA     CLMSG,A6
1945
 
1946
;*
1947
;* ===== Display a zero-ended string pointed to by register A6
1948
;*
1949
PRMESG:
1950
        MOVE.B  (A6)+,D0        ;get the char.
1951
        BEQ     PRMRET          ;if it's zero, we're done
1952
        BSR     GOOUT           ;else display it
1953
        BRA     PRMESG
1954
PRMRET:
1955
        RTS
1956
 
1957
;******************************************************
1958
;* The following routines are the only ones that need *
1959
;* to be changed for a different I/O environment.     *
1960
;******************************************************
1961
 
1962
;UART           EQU             0xFFDC0A00
1963
;UART_LS                EQU             UART+1
1964
;UART_CTRL      EQU             UART+7
1965
;KEYBD          EQU             0xFFDC0000
1966
 
1967
 
1968
;*
1969
;* ===== Output character to the console (Port 1) from register D0
1970
;*      (Preserves all registers.)
1971
;*
1972
OUTC:
1973
        MOVEM.L D0/D1,-(SP)
1974
        MOVE.L  D0,D1
1975
        JSR             DisplayChar
1976
        MOVEM.L (SP)+,D0/D1
1977
        RTS
1978
 
1979
;*
1980
;* ===== Input a character from the console into register D0 (or
1981
;*      return Zero status if there's no character available).
1982
;*
1983
INC:
1984
        MOVE.W  KEYBD,D0        ;is character ready?
1985
        BPL             INCRET0         ;if not, return Zero status
1986
        CLR.W   KEYBD+2         ; clear keyboard strobe line
1987
        AND.W   #0xFF,D0        ;zero out the high bit
1988
        RTS
1989
INCRET0
1990
        MOVEQ   #0,D0
1991
        RTS
1992
 
1993
;*
1994
;* ===== Output character to the host (Port 2) from register D0
1995
;*      (Preserves all registers.)
1996
;*
1997
AUXOUT:
1998
        BTST    #5,UART_LS      ;is port ready for a character?
1999
        BEQ             AUXOUT          ;if not, wait for it
2000
        MOVE.B  D0,UART         ;out it goes.
2001
        RTS
2002
 
2003
;*
2004
;* ===== Input a character from the host into register D0 (or
2005
;*      return Zero status if there's no character available).
2006
;*
2007
AUXIN:
2008
        BTST    #0,UART_LS      ;is character ready?
2009
        BEQ             AXIRET          ;if not, return Zero status
2010
        MOVE.B  UART,D0         ;else get the character
2011
        AND.B   #0x7F,D0        ;zero out the high bit
2012
AXIRET:
2013
        RTS
2014
 
2015
;*
2016
;* ===== Return to the resident monitor, operating system, etc.
2017
;*
2018
BYEBYE:
2019
        JMP             Monitor
2020
;    MOVE.B     #228,D7         ;return to Tutor
2021
;       TRAP    #14
2022
 
2023
INITMSG:
2024
        DC.B    CR,LF,'Gordo\'s MC68000 Tiny BASIC, v1.3',CR,LF,LF,0
2025
OKMSG:
2026
        DC.B    CR,LF,'OK',CR,LF,0
2027
HOWMSG:
2028
        DC.B    'How?',CR,LF,0
2029
WHTMSG:
2030
        DC.B    'What?',CR,LF,0
2031
SRYMSG:
2032
        DC.B    'Sorry.'
2033
CLMSG:
2034
        DC.B    CR,LF,0
2035
;       DC.B    0        ;<- for aligning on a word boundary
2036
        even
2037
 
2038
LSTROM  EQU             $
2039
        ;       end of possible ROM area
2040
 

powered by: WebSVN 2.1.0

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