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

Subversion Repositories raptor64

[/] [raptor64/] [trunk/] [software/] [sample code/] [bootrom.s] - Blame information for rev 46

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 robfinch
; ============================================================================
2 46 robfinch
;        __
3
;   \\__/ o\    (C) 2012-2013  Robert Finch, Stratford
4
;    \  __ /    All rights reserved.
5
;     \/_//     robfinch<remove>@opencores.org
6
;       ||
7
;  
8 27 robfinch
;
9
; This source file is free software: you can redistribute it and/or modify 
10
; it under the terms of the GNU Lesser General Public License as published 
11
; by the Free Software Foundation, either version 3 of the License, or     
12
; (at your option) any later version.                                      
13
;                                                                          
14
; This source file is distributed in the hope that it will be useful,      
15
; but WITHOUT ANY WARRANTY; without even the implied warranty of           
16
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            
17
; GNU General Public License for more details.                             
18
;                                                                          
19
; You should have received a copy of the GNU General Public License        
20
; along with this program.  If not, see <http://www.gnu.org/licenses/>.    
21
;                                                                          
22
; ============================================================================
23
;
24
CR      EQU     0x0D            ;ASCII equates
25
LF      EQU     0x0A
26
TAB     EQU     0x09
27
CTRLC   EQU     0x03
28
CTRLH   EQU     0x08
29 46 robfinch
CTRLI   EQU     0x09
30
CTRLJ   EQU     0x0A
31
CTRLK   EQU     0x0B
32
CTRLM   EQU 0x0D
33 27 robfinch
CTRLS   EQU     0x13
34
CTRLX   EQU     0x18
35 43 robfinch
XON             EQU     0x11
36
XOFF    EQU     0x13
37 10 robfinch
 
38 46 robfinch
EX_IRQ  EQU     449
39
 
40 43 robfinch
DATA_PRESENT    EQU     0x01            ; there is data preset at the serial port bc_uart3
41
XMIT_NOT_FULL   EQU     0x20
42
 
43
BUFLEN  EQU     80      ;       length of keyboard input buffer
44
 
45
; Initial stack tops for contexts
46
; Each context gets 1k from the special 16k startup stack memory
47
;
48
STACKTOP0       EQU             0xFFFF_FFFF_FFFE_FFF8
49
STACKTOP1       EQU             0xFFFF_FFFF_FFFE_FBF8
50
STACKTOP2       EQU             0xFFFF_FFFF_FFFE_F7F8
51
STACKTOP3       EQU             0xFFFF_FFFF_FFFE_F3F8
52
STACKTOP4       EQU             0xFFFF_FFFF_FFFE_EFF8
53
STACKTOP5       EQU             0xFFFF_FFFF_FFFE_EBF8
54
STACKTOP6       EQU             0xFFFF_FFFF_FFFE_E7F8
55
STACKTOP7       EQU             0xFFFF_FFFF_FFFE_E3F8
56
STACKTOP8       EQU             0xFFFF_FFFF_FFFE_DFF8
57
STACKTOP9       EQU             0xFFFF_FFFF_FFFE_DBF8
58
STACKTOP10      EQU             0xFFFF_FFFF_FFFE_D7F8
59
STACKTOP11      EQU             0xFFFF_FFFF_FFFE_D3F8
60
STACKTOP12      EQU             0xFFFF_FFFF_FFFE_CFF8
61
STACKTOP13      EQU             0xFFFF_FFFF_FFFE_CBF8
62
STACKTOP14      EQU             0xFFFF_FFFF_FFFE_C7F8
63
STACKTOP15      EQU             0xFFFF_FFFF_FFFE_C3F8
64
 
65
 
66
; BOOT ROM routines
67
 
68
TCBSize         EQU             0x200                   ; 512 bytes per TCB
69
TCBBase         EQU             0x00000001_00000000                     ; TCB pages
70
TCBr1           EQU             0x00
71
TCBr2           EQU             0x08
72
TCBr3           EQU             0x10
73
TCBr4           EQU             0x18
74
TCBr5           EQU             0x20
75
TCBr6           EQU             0x28
76
TCBr7           EQU             0x30
77
TCBr8           EQU             0x38
78
TCBr9           EQU             0x40
79
TCBr10          EQU             0x48
80
TCBr11          EQU             0x50
81
TCBr12          EQU             0x58
82
TCBr13          EQU             0x60
83
TCBr14          EQU             0x68
84
TCBr15          EQU             0x70
85
TCBr16          EQU             0x78
86
TCBr17          EQU             0x80
87
TCBr18          EQU             0x88
88
TCBr19          EQU             0x90
89
TCBr20          EQU             0x98
90
TCBr21          EQU             0xA0
91
TCBr22          EQU             0xA8
92
TCBr23          EQU             0xB0
93
TCBr24          EQU             0xB8
94
TCBr25          EQU             0xC0
95
TCBr26          EQU             0xC8
96
TCBr27          EQU             0xD0
97
TCBr28          EQU             0xD8
98
TCBr29          EQU             0xE0
99
TCBr30          EQU             0xE8
100
TCBr31          EQU             0xF0
101
 
102 46 robfinch
SCREENGATE      EQU             0x00
103
KEYBDGATE       EQU             0x01
104
VIDEOGATE       EQU             0x02
105
CARDGATE        EQU             0x03
106 43 robfinch
warmStart   EQU     0x1020
107
usrJmp      EQU     0x1028
108
TickIRQAddr             EQU             0x1030
109
TaskBlock               EQU             0x1038
110
Milliseconds    EQU             0x1400
111
Lastloc                 EQU             0x1408
112 46 robfinch
CharColor       EQU             0x1410
113 43 robfinch
ScreenColor     EQU             0x1414
114 46 robfinch
CursorRow       EQU             0x1417
115 43 robfinch
CursorCol       EQU             0x1418
116
CursorFlash     EQU             0x141A
117
KeybdEcho       EQU             0x141C
118
KeybdBuffer     EQU             0x1440
119
KeybdHead       EQU             0x1450
120
KeybdTail       EQU             0x1451
121 46 robfinch
sp_save         EQU             0x1460
122
lr_save         EQU             0x1468
123
r1_save         EQU             0x1470
124
r2_save         EQU             0x1478
125
r26_save        EQU             0x1480
126 43 robfinch
Score           EQU             0x1500
127
Manpos          EQU             0x1508
128
MissileActive   EQU             0x1510
129
MissileX        EQU             0x1512
130
MissileY        EQU             0x1514
131
InvadersRow1    EQU             0x1520
132
InvadersRow2    EQU             0x1530
133
InvadersRow3    EQU             0x1540
134
InvadersRow4    EQU             0x1550
135
InvadersRow5    EQU             0x1560
136
InvadersColpos  EQU             0x1570
137
InvadersRowpos  EQU             0x1571
138
Uart_rxfifo             EQU             0x1600
139
Uart_rxhead             EQU             0x1800
140
Uart_rxtail             EQU             0x1802
141
Uart_ms                 EQU             0x1808
142
Uart_rxrts              EQU             0x1809
143
Uart_rxdtr              EQU             0x180A
144
Uart_rxxon              EQU             0x180B
145
Uart_rxflow             EQU             0x180C
146
Uart_fon                EQU             0x180E
147
Uart_foff               EQU             0x1810
148
Uart_txrts              EQU             0x1812
149
Uart_txdtr              EQU             0x1813
150
Uart_txxon              EQU             0x1814
151
Uart_txxonoff   EQU             0x1815
152
TaskList                EQU             0x2000
153
ReadyList1              EQU             0x2000
154
ReadyList2              EQU             0x2020
155
ReadyList3              EQU             0x2040
156
ReadyList4              EQU             0x2060
157
ReadyList5              EQU             0x2080
158
ReadyNdx1               EQU             0x20A0
159
ReadyNdx2               EQU             0x20A1
160
ReadyNdx3               EQU             0x20A2
161
ReadyNdx4               EQU             0x20A3
162
ReadyNdx5               EQU             0x20A4
163
RunningTCB              EQU             0x20A6
164
NextToRunTCB    EQU             0x20A8
165
r1save                  EQU             0x20B0
166
r2save                  EQU             0x20B8
167
AXCstart                EQU             0x20C0
168
 
169 46 robfinch
; Context startup address table
170
;
171
ctx0start               EQU             0x20D0
172
ctx1start               EQU             0x20D8
173
ctx2start               EQU             0x20E0
174
ctx3start               EQU             0x20E8
175
ctx4start               EQU             0x20F0
176
ctx5start               EQU             0x20F8
177
ctx6start               EQU             0x2100
178
ctx7start               EQU             0x2108
179
ctx8start               EQU             0x2110
180
ctx9start               EQU             0x2118
181
ctx10start              EQU             0x2120
182
ctx11start              EQU             0x2128
183
ctx12start              EQU             0x2130
184
ctx13start              EQU             0x2138
185
ctx14start              EQU             0x2140
186
ctx15start              EQU             0x2148
187
sp_saves                EQU             0x2200
188
sp_saves_end    EQU             0x2280
189 43 robfinch
p100IRQvec              EQU             0x3000
190
keybdIRQvec             EQU             0x3008
191
serialIRQvec    EQU             0x3010
192
rasterIRQvec    EQU             0x3018
193
 
194 46 robfinch
startSector     EQU             0x30F8
195
BPB                     EQU             0x3100
196
 
197 43 robfinch
TEXTSCR         EQU             0xD0_0000
198
COLORSCR        EQU             0xD1_0000
199
TEXTREG         EQU             0xDA_0000
200 27 robfinch
TEXT_COLS       EQU             0x0
201
TEXT_ROWS       EQU             0x2
202
TEXT_CURPOS     EQU             0x16
203 43 robfinch
KEYBD           EQU             0xDC_0000
204
KEYBDCLR        EQU             0xDC_0002
205
 
206
UART            EQU             0xDC_0A00
207
UART_LS         EQU             0xDC_0A01
208
UART_MS         EQU             0xDC_0A02
209
UART_IS         EQU             0xDC_0A03
210
UART_IE         EQU             0xDC_0A04
211
UART_MC         EQU             0xDC_0A06
212
DATETIME        EQU             0xDC_0400
213 46 robfinch
 
214
SPIMASTER       EQU             0xDC_0500
215
SPI_MASTER_VERSION_REG  EQU     0x00
216
SPI_MASTER_CONTROL_REG  EQU     0x01
217
SPI_TRANS_TYPE_REG      EQU             0x02
218
SPI_TRANS_CTRL_REG      EQU             0x03
219
SPI_TRANS_STATUS_REG    EQU     0x04
220
SPI_TRANS_ERROR_REG             EQU     0x05
221
SPI_DIRECT_ACCESS_DATA_REG              EQU     0x06
222
SPI_SD_ADDR_7_0_REG             EQU     0x07
223
SPI_SD_ADDR_15_8_REG    EQU     0x08
224
SPI_SD_ADDR_23_16_REG   EQU     0x09
225
SPI_SD_ADDR_31_24_REG   EQU     0x0a
226
SPI_RX_FIFO_DATA_REG    EQU     0x10
227
SPI_RX_FIFO_DATA_COUNT_MSB      EQU     0x12
228
SPI_RX_FIFO_DATA_COUNT_LSB  EQU 0x13
229
SPI_RX_FIFO_CTRL_REG            EQU     0x14
230
SPI_TX_FIFO_DATA_REG    EQU     0x20
231
SPI_TX_FIFO_CTRL_REG    EQU     0x24
232
SPI_INIT_SD                     EQU             0x01
233
SPI_TRANS_START         EQU             0x01
234
SPI_TRANS_BUSY          EQU             0x01
235
SPI_INIT_NO_ERROR       EQU             0x00
236
SPI_READ_NO_ERROR       EQU             0x00
237
RW_READ_SD_BLOCK        EQU             0x02
238
RW_WRITE_SD_BLOCK       EQU             0x03
239
 
240
 
241 43 robfinch
PIC                     EQU             0xDC_0FF0
242
PIC_IE          EQU             0xDC_0FF2
243
 
244
PSG                     EQU             0xD5_0000
245
PSGFREQ0        EQU             0xD5_0000
246
PSGPW0          EQU             0xD5_0002
247
PSGCTRL0        EQU             0xD5_0004
248
PSGADSR0        EQU             0xD5_0006
249
 
250
SPRRAM          EQU             0xD8_0000
251
AC97            EQU             0xDC_1000
252 46 robfinch
TMP                     EQU             0xDC_0300
253 43 robfinch
LED                     EQU             0xDC_0600
254 46 robfinch
ETHMAC          EQU             0xDC_2000
255
CONFIGREC       EQU             0xDC_FFFF
256
MIIMODER        EQU             0x28
257
MIIADDRESS      EQU             0x30
258 43 robfinch
GACCEL          EQU             0xDA_E000
259
RASTERIRQ       EQU             0xDA_0100
260 27 robfinch
BOOT_STACK      EQU             0xFFFF_FFFF_FFFE_FFF8
261 43 robfinch
SPRITEREGS      EQU             0xDA_D000
262 27 robfinch
BITMAPSCR       EQU             0x00000001_00200000
263
 
264 46 robfinch
BOOTJMP         EQU             0x100800204
265
 
266 27 robfinch
txempty EQU             0x40
267
rxfull  EQU             0x01
268
 
269 43 robfinch
;
270
; Internal variables follow:
271
;
272
                bss
273 46 robfinch
                org             0x1048
274 43 robfinch
txtWidth        db      0                ; BIOS var =56
275
txtHeight       db      0                ; BIOS var =31
276
cursx   db              0                ; cursor x position
277
cursy   db              0                ; cursor y position
278
pos             dh              0                ; text screen position
279
charToPrint             dc              0
280
fgColor                 db              0
281
bkColor                 db              0
282
cursFlash               db              0        ; flash the cursor ?
283
 
284 46 robfinch
lineLinkTbl             fill.b  47,0     ; screen line link table
285 43 robfinch
typef   db      0   ; variable / expression type
286
        align   8
287
OSSP    dw      1       ; OS value of sp
288
CURRNT  dw      1       ;       Current line pointer
289
STKGOS  dw      1       ;       Saves stack pointer in 'GOSUB'
290
STKINP  dw      1       ;       Saves stack pointer during 'INPUT'
291
LOPVAR  dw      1       ;       'FOR' loop save area
292
LOPINC  dw      1       ;       increment
293
LOPLMT  dw      1       ;       limit
294
LOPLN   dw      1       ;       line number
295
LOPPT   dw      1       ;       text pointer
296
TXTUNF  dw      1       ;       points to unfilled text area
297
VARBGN  dw      1       ;       points to variable area
298
IVARBGN dw  1   ;   points to integer variable area
299
SVARBGN dw  1   ;   points to string variable area
300
FVARBGN dw  1   ;   points to float variable area
301
STKBOT  dw      1       ;       holds lower limit for stack growth
302
NUMWKA  fill.b  24,0                     ; numeric work area
303
BUFFER  fill.b  BUFLEN,0x00             ;               Keyboard input buffer
304
 
305
        bss
306
        org     0x1_00600000
307
TXT             equ             0x1_00600000    ; Beginning of program area
308
 
309 27 robfinch
;       org 0x070
310
;       iret
311
;       nop
312
;       nop
313
;       nop
314
;       nop
315
;       nop
316
;       nop
317
;       nop
318
;
319
        code
320 43 robfinch
        org 0xFFFF_FFFF_FFFF_B000
321 27 robfinch
 
322
; jump table
323
;
324
        jmp             SerialGetChar
325
        jmp             SerialPutChar
326
        jmp             SetKeyboardEcho
327
        jmp             KeybdCheckForKey
328
        jmp             KeybdGetChar
329
        jmp             DisplayChar
330
        jmp             DisplayString
331 46 robfinch
        jmp             DisplayNum
332
        jmp             CalcScreenLoc
333
        jmp             ClearScreen
334
        jmp             DisplayWord
335 27 robfinch
 
336 10 robfinch
start:
337 27 robfinch
;       lea             MSGRAM,a1
338
;       jsr             DisplayString
339
 
340
ColdStart:
341 46 robfinch
        icache_off                              ; turn on the ICache
342 43 robfinch
        dcache_off                              ; turn on the DCache
343
 
344 46 robfinch
; Make sure semaphores are available by closing the gates.
345
; We don't know what power up state is.
346
 
347
        cmgi    #KEYBDGATE
348
        cmgi    #VIDEOGATE
349
 
350
; Initialize the context startup address table with NULL
351
 
352
        xor             r1,r1,r1
353
        sw              r1,ctx0start
354
        sw              r1,ctx1start
355
        sw              r1,ctx2start
356
        sw              r1,ctx3start
357
        sw              r1,ctx4start
358
        sw              r1,ctx5start
359
        sw              r1,ctx6start
360
        sw              r1,ctx7start
361
        sw              r1,ctx8start
362
        sw              r1,ctx9start
363
        sw              r1,ctx10start
364
        sw              r1,ctx11start
365
        sw              r1,ctx12start
366
        sw              r1,ctx13start
367
        sw              r1,ctx14start
368
        sw              r1,ctx15start
369
 
370 43 robfinch
; Initialize the context schedule with all contexts treated equally
371
; There are only 16 contexts, but 256 schedule slots. Each context is
372
; given 16 slots distributed evenly throughout the execution pattern
373
; table.
374
;
375
        xor             r1,r1,r1        ; r1 = 0
376
ict1:
377
        mtep    r1,r1           ; only the low order four bits of r1 will move to the pattern table
378
        addui   r1,r1,#1
379
        cmpi    r2,r1,#255
380
        bne             r2,r0,ict1
381
 
382
; Point the interrupt return address register of the context to the 
383
; context startup code. The context will start up when an interrupt return
384
; occurs.
385
;
386
; We cannot use a loop for this. Fortunately there's only 16 contexts.
387
;
388
        lea             r25,ctxstart
389 46 robfinch
        mtspr   IPC,r25
390 43 robfinch
        lea             r30,STACKTOP0
391
        iepp
392
        lea             r25,ctxstart
393 46 robfinch
        mtspr   IPC,r25
394 43 robfinch
        lea             r30,STACKTOP1
395
        iepp
396
        lea             r25,ctxstart
397 46 robfinch
        mtspr   IPC,r25
398 43 robfinch
        lea             r30,STACKTOP2
399
        iepp
400
        lea             r25,ctxstart
401 46 robfinch
        mtspr   IPC,r25
402 43 robfinch
        lea             r30,STACKTOP3
403
        iepp
404
 
405
        lea             r25,ctxstart
406 46 robfinch
        mtspr   IPC,r25
407 43 robfinch
        lea             r30,STACKTOP4
408
        iepp
409
        lea             r25,ctxstart
410 46 robfinch
        mtspr   IPC,r25
411 43 robfinch
        lea             r30,STACKTOP5
412
        iepp
413
        lea             r25,ctxstart
414 46 robfinch
        mtspr   IPC,r25
415 43 robfinch
        lea             r30,STACKTOP6
416
        iepp
417
        lea             r25,ctxstart
418 46 robfinch
        mtspr   IPC,r25
419 43 robfinch
        lea             r30,STACKTOP7
420
        iepp
421
 
422
        lea             r25,ctxstart
423 46 robfinch
        mtspr   IPC,r25
424 43 robfinch
        lea             r30,STACKTOP8
425
        iepp
426
        lea             r25,ctxstart
427 46 robfinch
        mtspr   IPC,r25
428 43 robfinch
        lea             r30,STACKTOP9
429
        iepp
430
        lea             r25,ctxstart
431 46 robfinch
        mtspr   IPC,r25
432 43 robfinch
        lea             r30,STACKTOP10
433
        iepp
434
        lea             r25,ctxstart
435 46 robfinch
        mtspr   IPC,r25
436 43 robfinch
        lea             r30,STACKTOP11
437
        iepp
438
 
439
        lea             r25,ctxstart
440 46 robfinch
        mtspr   IPC,r25
441 43 robfinch
        lea             r30,STACKTOP12
442
        iepp
443
        lea             r25,ctxstart
444 46 robfinch
        mtspr   IPC,r25
445 43 robfinch
        lea             r30,STACKTOP13
446
        iepp
447
        lea             r25,ctxstart
448 46 robfinch
        mtspr   IPC,r25
449 43 robfinch
        lea             r30,STACKTOP14
450
        iepp
451
        lea             r25,ctxstart
452 46 robfinch
        mtspr   IPC,r25
453 43 robfinch
        lea             r30,STACKTOP15
454
        iepp
455
 
456
; Ensure that context zero is the active context
457
;
458
ctxstart3:
459
        mfspr   r1,AXC
460
        beq             r1,r0,ctxstart2
461
        iepp
462
        bra             ctxstart3
463
ctxstart2:
464
        sb              r1,AXCstart             ; save off the startup context which should be context zero
465
 
466
; Entry point for context startup
467
;
468
; Avoid repeating all the system initialization when a context starts up by testing whether
469
; or not the context is the starting context.
470
;
471
ctxstart:
472
        mfspr   r1,AXC
473
        lbu             r2,AXCstart
474
        bne             r1,r2,ctxstart1
475
 
476
;
477
; set system vectors
478
; TBA defaults to zero on reset
479
;
480
        setlo   r3,#0
481
        setlo   r2,#511
482
        lea             r1,nmirout
483
csj5:
484
        sw              r1,[r3]
485
        addui   r3,r3,#8
486
        loop    r2,csj5
487 46 robfinch
        lea             r1,VideoSC              ; Video BIOS vector
488
        sw              r1,0xCD0
489
        lea             r1,SCCARDSC             ; SD Card BIOS vector
490
        sw              r1,0xCE8
491
        lea             r1,RTCSC                ; Real time clock vector
492
        sw              r1,0xD00
493 43 robfinch
        lea             r1,KeybdSC              ; keyboard BIOS vector
494
        sw              r1,0xD08
495
        lea             r1,irqrout
496
        sw              r1,0xE08                ; set IRQ vector
497 46 robfinch
        lea             r1,ui_irout
498
        sw              r1,0xF78                ; set unimplemented instruction vector
499 43 robfinch
        lea             r1,dberr_rout
500
        sw              r1,0xFE0                ; set Bus error vector
501
        lea             r1,iberr_rout
502
        sw              r1,0xFE8                ; set Bus error vector
503
        lea             r1,nmirout
504
        sw              r1,0xFF0                ; set NMI vector
505 46 robfinch
 
506
; set system interrupt hook vectors
507
 
508 43 robfinch
        lea             r1,KeybdIRQ
509
        sw              r1,keybdIRQvec
510
        lea             r1,Pulse100
511
        sw              r1,p100IRQvec
512
        lea             r1,SerialIRQ
513
        sw              r1,serialIRQvec
514
        lea             r1,RasterIRQfn
515
        sw              r1,rasterIRQvec
516
 
517
        ;-------------------------------
518
        ; Initialize I/O devices
519
        ;-------------------------------
520 46 robfinch
        inbu    r1,CONFIGREC
521
        bfext   r1,r1,#4,#4
522
        beq             r1,r0,skip5
523
        call    tmp_init
524
skip5:
525
        inbu    r1,CONFIGREC
526
        bfext   r1,r1,#5,#5
527
        beq             r1,r0,skip4
528 43 robfinch
        call    SerialInit
529 46 robfinch
skip4:
530 27 robfinch
        call    KeybdInit
531
        call    PICInit
532 43 robfinch
        call    SetupRasterIRQ
533 27 robfinch
        cli                                             ; enable interrupts
534 43 robfinch
;       call    HelloWorld
535 27 robfinch
        setlo   r3,#0xCE                ; blue on blue
536
        sc              r3,ScreenColor
537 46 robfinch
        sc              r3,CharColor
538 43 robfinch
        lc              r3,0x1414
539 27 robfinch
        setlo   r3,#32
540 43 robfinch
        sc              r3,0x1416               ; we do a store, then a load through the dcache
541
        lc              r2,0x1416               ;
542 27 robfinch
        beq             r2,r3,dcokay
543
        dcache_off                              ; data cache failed
544
dcokay:
545 43 robfinch
        sc              r0,NextToRunTCB
546
        sc              r0,RunningTCB
547 46 robfinch
        lw              r1,#2                   ; get rid of startup keyboard glitchs by trying to get a character
548
        syscall #417
549
        lw              r1,#2                   ; get rid of startup keyboard glitchs by trying to get a character
550
        syscall #417
551
 
552
        ; wait for screen to be available
553 27 robfinch
        call    ClearScreen
554
        call    ClearBmpScreen
555 46 robfinch
 
556
; Test whether or not the sprite controller is present. Skip
557
; Initialization if it isn't.
558
 
559
        inb             r1,CONFIGREC
560
        bfext   r1,r1,#0,#0
561
        beq             r1,r0,skip1
562 43 robfinch
        call    RandomizeSprram
563 46 robfinch
skip1:
564
 
565
        sb              r0,CursorRow
566
        sb              r0,CursorCol
567
        lw              r1,#1
568 43 robfinch
        sb              r1,CursorFlash
569
        lea             r1,MSGSTART
570
        call    DisplayStringCRLF
571 46 robfinch
 
572
; Test whether or not sound generator is present
573
; skip initialization and beep if not present
574
 
575
        inb             r1,CONFIGREC
576
        bfext   r1,r1,#2,#2
577
        beq             r1,r0,skip2
578 43 robfinch
        call    SetupAC97               ; and Beep
579 46 robfinch
        lw              r1,#4
580
        outb    r1,LED
581 43 robfinch
        call    Beep
582 46 robfinch
skip2:
583 27 robfinch
 
584 46 robfinch
        lea             r1,context1disp ; start a display
585
        sw              r1,ctx1start
586
 
587
; Startup Ethernet access ?
588
;
589
        inb             r1,CONFIGREC
590
        bfext   r1,r1,#1,#1
591
        beq             r1,r0,skip3
592
        lea             r1,eth_main
593
        sw              r1,ctx2start
594
skip3:
595
 
596
        lea             r1,RandomLines
597
        sw              r1,ctx3start
598
        call    spi_init
599
        bne             r1,r0,skip_spi_read
600
        call    spi_read_boot
601
        call    loadBootFile
602
skip_spi_read:
603
        jmp             Monitor
604
 
605 27 robfinch
j4:
606
        jmp             Monitor
607
        bra             j4
608
 
609 46 robfinch
; The contexts wait for a context startup address to be placed in the
610
; startup table. Once an address is in the table, a call to the context
611
; code will be made. The default is a NULL pointer, which
612
; causes the context to loop around back to here while waiting for a
613
; code to run.
614 43 robfinch
;
615
ctxstart1:
616 46 robfinch
        lea             r1,ctx0start    ; r1 = context start table base
617
        mfspr   r2,AXC                  ; r2 = index into start table
618
        lw              r1,[r1+r2*8]    ; r1 = context start address
619
        beq             r1,r0,ctx12
620
        jal             lr,[r1]                 ; perform a call to the context code
621
 
622
; We might as well move to the next context, since there's nothing
623
; to do. This can be accomplished by tirggering a IRQ interrupt.
624
; We can't just increment the excution pattern pointer, because that
625
; would only switch the register set and not the program counter.
626
; An interrupt saves the program counter, and restores it from the
627
; IPC context register.
628
;
629
ctx12:
630
        sei                                     ; causes a priv violation. don't allow interrupts during syscall
631
        nop                                     ; wait for sei to take effect
632
        nop
633
        nop
634
        syscall #EX_IRQ
635 43 robfinch
        bra             ctxstart1
636
 
637 27 robfinch
;       call    ramtest
638
 
639 46 robfinch
context1disp:
640
 
641
; once we've started, clear the start vector so that the context
642
; isn't continuously restarted.
643
;
644
        sw              r0,ctx1start
645
        lea             r3,TEXTSCR
646
        lw              r1,#'V'
647
        lw              r2,#330
648
        lw              r4,#47
649
        call    AsciiToScreen
650
ctx11:
651
        inch    r1,[r3+r2]
652
        addui   r1,r1,#1
653
        outc    r1,[r3+r2]
654
        addui   r2,r2,#168
655
        loop    r4,ctx11
656
        bra             context1disp
657
 
658 27 robfinch
;-----------------------------------------
659
; Hello World!
660
;-----------------------------------------
661
HelloWorld:
662
        subui   r30,r30,#24
663 43 robfinch
        sw              r1,[sp]
664
        sw              r2,8[sp]
665
        sw              lr,16[sp]
666
        lea             r2,MSG
667 27 robfinch
j3:
668
        lb              r1,[r2]
669
        beq             r1,r0,j2
670
        call    SerialPutChar
671
        addui   r2,r2,#1
672
        bra             j3
673
j2:
674 43 robfinch
        sw              lr,16[sp]
675
        sw              r2,8[sp]
676
        sw              r1,[sp]
677 27 robfinch
        ret             #24
678
 
679
 
680
        align   16
681
MSG:
682 43 robfinch
        db      "Hello World!",0
683 27 robfinch
MSGSTART:
684 43 robfinch
        db      "Raptor64 system starting....",0
685 27 robfinch
 
686
        align 16
687
 
688
;----------------------------------------------------------
689
; Initialize programmable interrupt controller (PIC)
690 46 robfinch
;  0 = nmi (parity error)
691 27 robfinch
;  1 = keyboard reset
692 43 robfinch
;  2 = 1000Hz pulse (context switcher)
693
;  3 = 100Hz pulse (cursor flash)
694 46 robfinch
;  4 = ethmac
695 43 robfinch
;  8 = uart
696
; 13 = raster interrupt
697 27 robfinch
; 15 = keyboard char
698
;----------------------------------------------------------
699
PICInit:
700 43 robfinch
        lea             r1,PICret
701
        sw              r1,TickIRQAddr
702
        ; enable: raster irq,
703 46 robfinch
        setlo   r1,#0x800F      ; enable nmi,kbd_rst,and kbd_irq
704 43 robfinch
        ; A10F enable serial IRQ
705
        outc    r1,PIC_IE
706
PICret:
707 27 robfinch
        ret
708
 
709 43 robfinch
;==============================================================================
710
; Serial port
711
;==============================================================================
712 27 robfinch
;-----------------------------------------
713 43 robfinch
; Initialize the serial port
714 27 robfinch
;-----------------------------------------
715 43 robfinch
;
716
SerialInit:
717
        sc              r0,Uart_rxhead          ; reset buffer indexes
718
        sc              r0,Uart_rxtail
719
        setlo   r1,#0x1f0
720
        sc              r1,Uart_foff            ; set threshold for XOFF
721
        setlo   r1,#0x010
722
        sc              r1,Uart_fon                     ; set threshold for XON
723
        setlo   r1,#1
724
        outb    r1,UART_IE                      ; enable receive interrupt only
725
        sb              r0,Uart_rxrts           ; no RTS/CTS signals available
726
        sb              r0,Uart_txrts           ; no RTS/CTS signals available
727
        sb              r0,Uart_txdtr           ; no DTR signals available
728
        sb              r0,Uart_rxdtr           ; no DTR signals available
729
        setlo   r1,#1
730
        sb              r1,Uart_txxon           ; for now
731
        ret
732
 
733
;---------------------------------------------------------------------------------
734
; Get character directly from serial port. Blocks until a character is available.
735
;---------------------------------------------------------------------------------
736
;
737
SerialGetCharDirect:
738 27 robfinch
sgc1:
739 43 robfinch
        inb             r1,UART_LS              ; uart status
740
        andi    r1,r1,#rxfull   ; is there a char available ?
741
        beq             r1,r0,sgc1
742
        inb             r1,UART
743
        ret
744 27 robfinch
 
745 43 robfinch
;------------------------------------------------
746
; Check for a character at the serial port
747
; returns r1 = 1 if char available, 0 otherwise
748
;------------------------------------------------
749
;
750
SerialCheckForCharDirect:
751
        inb             r1,UART_LS              ; uart status
752
        andi    r1,r1,#rxfull   ; is there a char available ?
753
        sne             r1,r1,r0
754
        ret
755
 
756 27 robfinch
;-----------------------------------------
757
; Put character to serial port
758 43 robfinch
; r1 = char to put
759 27 robfinch
;-----------------------------------------
760 43 robfinch
;
761 27 robfinch
SerialPutChar:
762 43 robfinch
        subui   sp,sp,#32
763
        sw              r2,[sp]
764
        sw              r3,8[sp]
765
        sw              r4,16[sp]
766
        sw              r5,24[sp]
767
        inb             r2,UART_MC
768
        ori             r2,r2,#3                ; assert DTR / RTS
769
        outb    r2,UART_MC
770
        lb              r2,Uart_txrts
771
        beq             r2,r0,spcb1
772
        lw              r4,Milliseconds
773
        setlo   r3,#100                 ; delay count (1 s)
774
spcb3:
775
        inb             r2,UART_MS
776
        andi    r2,r2,#10               ; is CTS asserted ?
777
        bne             r2,r0,spcb1
778
        lw              r5,Milliseconds
779
        beq             r4,r5,spcb3
780
        mov             r4,r5
781
        loop    r3,spcb3
782
        bra             spcabort
783
spcb1:
784
        lb              r2,Uart_txdtr
785
        beq             r2,r0,spcb2
786
        lw              r4,Milliseconds
787
        setlo   r3,#100                 ; delay count
788
spcb4:
789
        inb             r2,UART_MS
790
        andi    r2,r2,#20               ; is DSR asserted ?
791
        bne             r2,r0,spcb2
792
        lw              r5,Milliseconds
793
        beq             r4,r5,spcb4
794
        mov             r4,r5
795
        loop    r3,spcb4
796
        bra             spcabort
797
spcb2:
798
        lb              r2,Uart_txxon
799
        beq             r2,r0,spcb5
800
spcb6:
801
        lb              r2,Uart_txxonoff
802
        beq             r2,r0,spcb5
803
        inb             r4,UART_MS
804
        andi    r4,r4,#0x80                     ; DCD ?
805
        bne             r4,r0,spcb6
806
spcb5:
807
        lw              r4,Milliseconds
808
        setlo   r3,#100                         ; wait up to 1s
809
spcb8:
810
        inb             r2,UART_LS
811
        andi    r2,r2,#0x20                     ; tx not full ?
812
        bne             r2,r0,spcb7
813
        lw              r5,Milliseconds
814
        beq             r4,r5,spcb8
815
        mov             r4,r5
816
        loop    r3,spcb8
817
        bra             spcabort
818
spcb7:
819
        outb    r1,UART
820
spcabort:
821
        lw              r2,[sp]
822
        lw              r3,8[sp]
823
        lw              r4,16[sp]
824
        lw              r5,24[sp]
825
        ret             #32
826 27 robfinch
 
827 43 robfinch
;-------------------------------------------------
828
; Compute number of characters in recieve buffer.
829
; r4 = number of chars
830
;-------------------------------------------------
831
CharsInRxBuf:
832
        lc              r4,Uart_rxhead
833
        lc              r2,Uart_rxtail
834
        subu    r4,r4,r2
835
        bgt             r4,r0,cirxb1
836
        setlo   r4,#0x200
837
        addu    r4,r4,r2
838
        lc              r2,Uart_rxhead
839
        subu    r4,r4,r2
840
cirxb1:
841
        ret
842
 
843
;----------------------------------------------
844
; Get character from rx fifo
845
; If the fifo is empty enough then send an XON
846
;----------------------------------------------
847
;
848
SerialGetChar:
849
        subui   sp,sp,#32
850
        sw              r2,[sp]
851
        sw              r3,8[sp]
852
        sw              r4,16[sp]
853
        sw              lr,24[sp]
854
        lc              r3,Uart_rxhead
855
        lc              r2,Uart_rxtail
856
        beq             r2,r3,sgcfifo1  ; is there a char available ?
857
        lea             r3,Uart_rxfifo
858
        lb              r1,[r2+r3]              ; get the char from the fifo into r1
859
        addui   r2,r2,#1                ; increment the fifo pointer
860
        andi    r2,r2,#0x1ff
861
        sc              r2,Uart_rxtail
862
        lb              r2,Uart_rxflow  ; using flow control ?
863
        beq             r2,r0,sgcfifo2
864
        lc              r3,Uart_fon             ; enough space in Rx buffer ?
865
        call    CharsInRxBuf
866
        bgt             r4,r3,sgcfifo2
867
        sb              r0,Uart_rxflow  ; flow off
868
        lb              r4,Uart_rxrts
869
        beq             r4,r0,sgcfifo3
870
        inb             r4,UART_MC              ; set rts bit in MC
871
        ori             r4,r4,#2
872
        outb    r4,UART_MC
873
sgcfifo3:
874
        lb              r4,Uart_rxdtr
875
        beq             r4,r0,sgcfifo4
876
        inb             r4,UART_MC              ; set DTR
877
        ori             r4,r4,#1
878
        outb    r4,UART_MC
879
sgcfifo4:
880
        lb              r4,Uart_rxxon
881
        beq             r4,r0,sgcfifo5
882
        setlo   r4,#XON
883
        outb    r4,UART
884
sgcfifo5:
885
sgcfifo2:                                       ; return with char in r1
886
        lw              r2,[sp]
887
        lw              r3,8[sp]
888
        lw              r4,16[sp]
889
        lw              lr,24[sp]
890
        ret             #32
891
sgcfifo1:
892
        setlo   r1,#-1                  ; no char available
893
        lw              r2,[sp]
894
        lw              r3,8[sp]
895
        lw              r4,16[sp]
896
        lw              lr,24[sp]
897
        ret             #32
898
 
899
;-----------------------------------------
900
; Serial port IRQ
901
;-----------------------------------------
902
;
903
SerialIRQ:
904
        subui   sp,sp,#40
905
        sw              r1,[sp]
906
        sw              r2,8[sp]
907
        sw              r3,16[sp]
908
        sw              r4,24[sp]
909
        sw              lr,32[sp]
910
        inb             r1,UART_IS              ; get interrupt status
911
        bge             r1,r0,sirq1
912
        andi    r1,r1,#0x7f             ; switch on interrupt type
913
        beqi    r1,#4,srxirq
914
        beqi    r1,#0xC,stxirq
915
        beqi    r1,#0x10,smsirq
916
sirq1:
917
        lw              r1,[sp]
918
        lw              r2,8[sp]
919
        lw              r3,16[sp]
920
        lw              r4,24[sp]
921
        lw              lr,32[sp]
922
        ret             #40
923
 
924
; Get the modem status and record it
925
smsirq:
926
        inb             r1,UART_MS
927
        sb              r1,Uart_ms
928
        bra             sirq1
929
 
930
stxirq:
931
        bra             sirq1
932
 
933
; Get a character from the uart and store it in the rx fifo
934
srxirq:
935
srxirq1:
936
        inb             r1,UART                         ; get the char (clears interrupt)
937
        lb              r2,Uart_txxon
938
        beq             r2,r0,srxirq3
939
        bnei    r1,#XOFF,srxirq2
940
        setlo   r1,#1
941
        sb              r1,Uart_txxonoff
942
        bra             srxirq5
943
srxirq2:
944
        bnei    r1,#XON,srxirq3
945
        sb              r0,Uart_txxonoff
946
        bra             srxirq5
947
srxirq3:
948
        sb              r0,Uart_txxonoff
949
        lc              r2,Uart_rxhead
950
        lea             r3,Uart_rxfifo
951
        sb              r1,[r3+r2]                      ; store in buffer
952
        addui   r2,r2,#1
953
        andi    r2,r2,#0x1ff
954
        sc              r2,Uart_rxhead
955
srxirq5:
956
        inb             r1,UART_LS                      ; check for another ready character
957
        andi    r1,r1,#rxfull
958
        bne             r1,r0,srxirq1
959
        lb              r1,Uart_rxflow          ; are we using flow controls?
960
        bne             r1,r0,srxirq8
961
        call    CharsInRxBuf
962
        lc              r1,Uart_foff
963
        blt             r4,r1,srxirq8
964
        setlo   r1,#1
965
        sb              r1,Uart_rxflow
966
        lb              r1,Uart_rxrts
967
        beq             r1,r0,srxirq6
968
        inb             r1,UART_MC
969
        andi    r1,r1,#0xFD             ; turn off RTS
970
        outb    r1,UART_MC
971
srxirq6:
972
        lb              r1,Uart_rxdtr
973
        beq             r1,r0,srxirq7
974
        inb             r1,UART_MC
975
        andi    r1,r1,#0xFE             ; turn off DTR
976
        outb    r1,UART_MC
977
srxirq7:
978
        lb              r1,Uart_rxxon
979
        beq             r1,r0,srxirq8
980
        setlo   r1,#XOFF
981
        outb    r1,UART
982
srxirq8:
983
        bra             sirq1
984
 
985 27 robfinch
;==============================================================================
986 46 robfinch
; Video BIOS
987
; Video interrupt #410
988
;
989
; Function in R1
990
; 0x02 = Set Cursor Position    r2 = row, r3 = col 
991
; 0x03 = Get Cursor position    returns r1 = row, r2 = col
992
; 0x06 = Scroll screen up
993
; 0x09 = Display character+attribute, r2=char, r3=attrib, r4=#times
994
; 0x0A = Display character, r2 = char, r3 = # times
995
; 0x0C = Display Pixel r2 = x, r3 = y, r4 = color
996
; 0x0D = Get pixel  r2 = x, r3 = y
997
; 0x14 = Display String r2 = pointer to string
998
; 0x15 = Display number r2 = number, r3 = # digits
999
; 0x16 = Display String + CRLF   r2 = pointer to string
1000
; 0x17 = Display Word r2 as hex = word
1001
; 0x18 = Display Half word as hex r2 = half word
1002
; 0x19 = Display Charr char in hex r2 = char
1003
; 0x1A = Display Byte in hex r2 = byte
1004
;==============================================================================
1005
;
1006
VideoSC:
1007
        mfspr   r26,AXC                         ; get context
1008
        shlui   r26,r26,#3                      ; *8
1009
        sw              sp,sp_saves[r26]        ; save sp in save area
1010
        shlui   r26,r26,#8                      ; 2k for stack
1011
        mov             sp,r26
1012
        addui   sp,sp,#0x100008000      ; base stacks address
1013
        subui   sp,sp,#8
1014
        sw              lr,[sp]
1015
Video1:
1016
        omgi    lr,#VIDEOGATE
1017
        bne             lr,r0,Video1
1018
        beqi    r1,#0x02,Video_x02
1019
        beqi    r1,#0x03,Video_x03
1020
        beqi    r1,#0x06,Video_x06
1021
        beqi    r1,#0x09,Video_x09
1022
        beqi    r1,#0x0A,Video_x0A
1023
        beqi    r1,#0x0C,Video_x0C
1024
        beqi    r1,#0x0C,Video_x0D
1025
        beqi    r1,#0x14,Video_x14
1026
        beqi    r1,#0x15,Video_x15
1027
        beqi    r1,#0x16,Video_x16
1028
        beqi    r1,#0x17,Video_x17
1029
        beqi    r1,#0x1A,Video_x1A
1030
        bra             VideoRet
1031
 
1032
Video_x02:
1033
        sb              r2,CursorRow
1034
        sb              r3,CursorCol
1035
        call    CalcScreenLoc
1036
        bra             VideoRet
1037
 
1038
Video_x03:
1039
        lbu             r1,CursorRow
1040
        lbu             r2,CursorCol
1041
        bra             VideoRet
1042
 
1043
Video_x06:
1044
        call    ScrollUp
1045
        bra             VideoRet
1046
 
1047
Video_x09:
1048
        sc              r3,CharColor
1049
        mov             r1,r2
1050
Video_x09a:
1051
        call    DisplayChar
1052
        loop    r4,Video_x09a
1053
        bra             VideoRet
1054
 
1055
Video_x0A:
1056
        mov             r1,r2
1057
Video_x0Aa:
1058
        call    DisplayChar
1059
        loop    r3,Video_x0Aa
1060
        bra             VideoRet
1061
 
1062
Video_x0C:
1063
        sh              r2,GACCEL+8             ; x0
1064
        sh              r3,GACCEL+12    ; y0
1065
        sh              r4,GACCEL+0              ; color
1066
        lw              r1,#1
1067
        sh              r1,GACCEL+60    ; DRAW PIXEL command
1068
        bra             VideoRet
1069
 
1070
Video_x0D:
1071
        sh              r2,GACCEL+8             ; x0
1072
        sh              r3,GACCEL+12    ; y0
1073
        lw              r1,#8
1074
        sh              r1,GACCEL+60    ; GET PIXEL command
1075
        nop                                             ; let command start
1076
        nop
1077
        nop
1078
vxd1:
1079
        lhu             r1,GACCEL+56    ; wait for state = IDLE
1080
        bne             r1,r0,vxd1
1081
        lhu             r1,GACCEL+52
1082
        bra             VideoRet
1083
 
1084
Video_x14:
1085
        mov             r1,r2
1086
        call    DisplayString
1087
        bra             VideoRet
1088
 
1089
Video_x15:
1090
        mov             r1,r2
1091
        mov             r2,r3
1092
        call    DisplayNum
1093
        bra             VideoRet
1094
 
1095
Video_x16:
1096
        mov             r1,r2
1097
        call    DisplayStringCRLF
1098
        bra             VideoRet
1099
 
1100
Video_x17:
1101
        mov             r1,r2
1102
        call    DisplayWord
1103
        bra             VideoRet
1104
 
1105
Video_x1A:
1106
        mov             r1,r2
1107
        call    DisplayByte
1108
        bra             VideoRet
1109
 
1110
VideoRet:
1111
        cmgi    #VIDEOGATE
1112
        lw              lr,[sp]
1113
        mfspr   r26,AXC                         ; get context
1114
        shlui   r26,r26,#3                      ; *8
1115
        lw              sp,sp_saves[r26]        ; get back the stack
1116
        eret
1117
 
1118
;==============================================================================
1119
; BIOS interrupt #413
1120
; 0x00  initialize
1121
; 0x01  read sector             r2 = sector #, r3 = pointer to buffer
1122
; 0x02  write sector
1123
;==============================================================================
1124
;
1125
SDCARDSC:
1126
        mfspr   r26,AXC                         ; get context
1127
        shlui   r26,r26,#3                      ; *8
1128
        sw              sp,sp_saves[r26]        ; save sp in save area
1129
        shlui   r26,r26,#8                      ; 2k for stack
1130
        mov             sp,r26
1131
        addui   sp,sp,#0x100008000      ; base stacks address
1132
        subui   sp,sp,#8
1133
        sw              lr,[sp]
1134
SDC_1:
1135
        omgi    lr,#CARDGATE
1136
        bne             lr,r0,SDC_1
1137
        beqi    r1,#0,SDC_x00
1138
        beqi    r1,#1,SDC_x01
1139
        beqi    r1,#2,SDC_x02
1140
        bra             SDCRet
1141
SDC_x00:
1142
        call    spi_init
1143
        bra             SDCRet
1144
SDC_x01:
1145
        mov             r1,r2
1146
        mov             r2,r3
1147
        call    spi_read_sector
1148
        bra             SDCRet
1149
SDC_x02:
1150
SDCRet:
1151
        cmgi    #CARDGATE
1152
        lw              lr,[sp]
1153
        mfspr   r26,AXC                         ; get context
1154
        shlui   r26,r26,#3                      ; *8
1155
        lw              sp,sp_saves[r26]        ; get back the stack
1156
        eret
1157
 
1158
;==============================================================================
1159
; Real time clock BIOS
1160
; BIOS interrupt #416
1161
;
1162
; Function
1163
; 0x00 = get system tick
1164
; 0x01 = get date/time
1165
; 0x02 = set date/time
1166
;==============================================================================
1167
;
1168
RTCSC:
1169
        mfspr   r26,AXC                         ; get context
1170
        shlui   r26,r26,#3                      ; *8
1171
        sw              sp,sp_saves[r26]        ; save sp in save area
1172
        shlui   r26,r26,#8                      ; 2k for stack
1173
        mov             sp,r26
1174
        addui   sp,sp,#0x100008000      ; base stacks address
1175
        subui   sp,sp,#8
1176
        sw              lr,[sp]
1177
        ;
1178
        beqi    r1,#0x00,RTC_x00
1179
        beqi    r1,#0x01,RTC_x01
1180
RTC_x00:
1181
        mfspr   r1,TICK
1182
        bra             RTCRet
1183
RTC_x01:
1184
        outw    r0,DATETIME+24          ; trigger a snapshot
1185
        nop
1186
        inw             r1,DATETIME                     ; get the snapshotted date and time
1187
        bra             RTCRet
1188
RTCRet:
1189
        lw              lr,[sp]
1190
        mfspr   r26,AXC                         ; get context
1191
        shlui   r26,r26,#3                      ; *8
1192
        lw              sp,sp_saves[r26]        ; get back the stack
1193
        eret
1194
 
1195
;==============================================================================
1196 43 robfinch
; Keyboard BIOS
1197
; BIOS interrupt #417
1198
;
1199
; Function in R1
1200 46 robfinch
; 0x00 = initialize keyboard
1201
; 0x01 = set keyboard echo
1202
; 0x02 = get keyboard character from buffer
1203
; 0x03 = check for key available in buffer
1204
; 0x04 = check for key directly at keyboard port
1205
; 0x05 = get keyboard character directly from keyboard port (blocks)
1206 27 robfinch
;==============================================================================
1207 43 robfinch
;
1208
KeybdSC:
1209 46 robfinch
        mfspr   r26,AXC                         ; get context
1210
        shlui   r26,r26,#3                      ; *8
1211
        sw              sp,sp_saves[r26]        ; save sp in save area
1212
        shlui   r26,r26,#8                      ; 2k for stack
1213
        mov             sp,r26
1214
        addui   sp,sp,#0x100008000      ; base stacks address
1215 43 robfinch
        subui   sp,sp,#8
1216
        sw              lr,[sp]
1217 46 robfinch
kbdsc5:
1218
        omgi    lr,#KEYBDGATE
1219
        bne             lr,r0,kbdsc5
1220
        beqi    r1,#0,kbd_x00
1221
        beqi    r1,#1,kbd_x01
1222
        beqi    r1,#2,kbd_x02
1223
        beqi    r1,#3,kbd_x03
1224
        beqi    r1,#4,kbd_x04
1225
        beqi    r1,#5,kbd_x05
1226
        bra             kbdscRet
1227
kbd_x00:
1228 43 robfinch
        call    KeybdInit
1229
        bra             kbdscRet
1230 46 robfinch
kbd_x01:
1231 43 robfinch
        mov             r1,r2
1232
        call    SetKeyboardEcho
1233
        bra             kbdscRet
1234 46 robfinch
kbd_x02:
1235 43 robfinch
        call    KeybdGetChar
1236
        bra             kbdscRet
1237 46 robfinch
kbd_x03:
1238 43 robfinch
        call    KeybdCheckForKey
1239
        bra             kbdscRet
1240 46 robfinch
kbd_x04:
1241
        call    KeybdCheckForKeyDirect
1242
        bra             kbdscRet
1243
kbd_x05:
1244
        call    KeybdGetCharDirect
1245
        bra             kbdscRet
1246 43 robfinch
kbdscRet:
1247 46 robfinch
        cmgi    #KEYBDGATE
1248 43 robfinch
        lw              lr,[sp]
1249 46 robfinch
        mfspr   r26,AXC                         ; get context
1250
        shlui   r26,r26,#3                      ; *8
1251
        lw              sp,sp_saves[r26]        ; get back the stack
1252 43 robfinch
        eret
1253
 
1254 27 robfinch
;------------------------------------------------------------------------------
1255
; Initialize keyboard
1256
;------------------------------------------------------------------------------
1257
KeybdInit:
1258
        sb              r0,KeybdHead
1259
        sb              r0,KeybdTail
1260
        setlo   r1,#1                   ; turn on keyboard echo
1261
        sb              r1,KeybdEcho
1262
        ret
1263
 
1264
;------------------------------------------------------------------------------
1265
; Normal keyboard interrupt, the lowest priority interrupt in the system.
1266
; Grab the character from the keyboard device and store it in a buffer.
1267
;------------------------------------------------------------------------------
1268
;
1269
KeybdIRQ:
1270 43 robfinch
        subui   sp,sp,#8
1271
        sw              r2,[sp]
1272 27 robfinch
        lbu             r1,KeybdHead
1273
        andi    r1,r1,#0x0f                             ; r1 = index into buffer
1274
KeybdIRQa:
1275
        inch    r2,KEYBD                                ; get keyboard character
1276
        outc    r0,KEYBD+2                              ; clear keyboard strobe (turns off the IRQ)
1277 43 robfinch
        sb              r2,KeybdBuffer[r1]              ; store character in buffer
1278 27 robfinch
        addui   r1,r1,#1                                ; increment head index
1279
        andi    r1,r1,#0x0f
1280
        sb              r1,KeybdHead
1281
KeybdIRQb:
1282
        lbu             r2,KeybdTail                    ; check to see if we've collided
1283
        bne             r1,r2,KeybdIRQc                 ; with the tail
1284
        addui   r2,r2,#1                                ; if so, increment the tail index
1285
        andi    r2,r2,#0x0f                             ; the oldest character will be lost
1286
        sb              r2,KeybdTail
1287
KeybdIRQc:
1288 43 robfinch
        lw              r2,[sp]
1289
        ret             #8
1290 27 robfinch
 
1291
;------------------------------------------------------------------------------
1292
; r1 0=echo off, non-zero = echo on
1293
;------------------------------------------------------------------------------
1294
SetKeyboardEcho:
1295
        sb              r1,KeybdEcho
1296
        ret
1297
 
1298
;-----------------------------------------
1299
; Get character from keyboard buffer
1300
;-----------------------------------------
1301
KeybdGetChar:
1302
        subui   sp,sp,#16
1303 43 robfinch
        sw              r2,[sp]
1304
        sw              lr,8[sp]
1305 27 robfinch
        lbu             r2,KeybdTail
1306
        lbu             r1,KeybdHead
1307
        beq             r1,r2,nochar
1308 43 robfinch
        lbu             r1,KeybdBuffer[r2]
1309 27 robfinch
        addui   r2,r2,#1
1310
        andi    r2,r2,#0x0f
1311
        sb              r2,KeybdTail
1312 43 robfinch
        lb              r2,KeybdEcho
1313
        beq             r2,r0,kgc3
1314
        bnei    r1,#CR,kgc2
1315
        call    CRLF                    ; convert CR keystroke into CRLF
1316
        bra             kgc3
1317
kgc2:
1318
        call    DisplayChar
1319
        bra             kgc3
1320 27 robfinch
nochar:
1321
        setlo   r1,#-1
1322 43 robfinch
kgc3:
1323
        lw              lr,8[sp]
1324
        lw              r2,[sp]
1325 27 robfinch
        ret             #16
1326
 
1327
;------------------------------------------------------------------------------
1328
; Check if there is a keyboard character available in the keyboard buffer.
1329
;------------------------------------------------------------------------------
1330
;
1331
KeybdCheckForKey:
1332
        lbu             r1,KeybdTail
1333
        lbu             r2,KeybdHead
1334 43 robfinch
        sne             r1,r1,r2
1335 27 robfinch
        ret
1336
 
1337
;------------------------------------------------------------------------------
1338
; Check if there is a keyboard character available. If so return true (1)
1339
; otherwise return false (0) in r1.
1340
;------------------------------------------------------------------------------
1341
;
1342
KeybdCheckForKeyDirect:
1343
        inch    r1,KEYBD
1344 43 robfinch
        slt             r1,r1,r0
1345 27 robfinch
        ret
1346
 
1347
;------------------------------------------------------------------------------
1348
; Get character directly from keyboard. This routine blocks until a key is
1349
; available.
1350
;------------------------------------------------------------------------------
1351
;
1352
KeybdGetCharDirect:
1353
        subui   sp,sp,#16
1354 43 robfinch
        sw              r2,[sp]
1355
        sw              lr,8[sp]
1356 27 robfinch
        setlo   r2,KEYBD
1357
kgc1:
1358
        inch    r1,KEYBD
1359
        bge             r1,r0,kgc1
1360
        outc    r0,KEYBD+2              ; clear keyboard strobe
1361
        andi    r1,r1,#0xff             ; remove strobe bit
1362
        lb              r2,KeybdEcho    ; is keyboard echo on ?
1363
        beq             r2,r0,gk1
1364
        bnei    r1,#'\r',gk2    ; convert CR keystroke into CRLF
1365
        call    CRLF
1366
        bra             gk1
1367
gk2:
1368
        call    DisplayChar
1369
gk1:
1370 43 robfinch
        lw              r2,[sp]
1371
        lw              lr,8[sp]
1372 27 robfinch
        ret             #16
1373
 
1374
;==============================================================================
1375
;==============================================================================
1376 46 robfinch
tmp_init:
1377
        ; wait for the rst1626 to go low
1378
        lw              r2,#10000000    ; retry for up to several seconds
1379
tmp_init4:
1380
        beq             r2,r0,tmp_init5
1381
        subui   r2,r2,#1
1382
        inch    r1,TMP+2        ; read the status reg
1383
        blt             r1,r0,tmp_init4
1384
tmp_init5:
1385
 
1386
        lw              r1,#0x51        ; Start temperature conversion
1387
        outc    r1,TMP
1388
 
1389
        ; wait a bit for the trigger to take effect
1390
        lw              r1,#2500
1391
tmp_init1:
1392
        loop    r1,tmp_init1
1393
 
1394
        ; wait for the rst1626 to go low
1395
        lw              r2,#10000000    ; retry for up to several seconds
1396
tmp_init2:
1397
        beq             r2,r0,tmp_init3
1398
        subui   r2,r2,#1
1399
        inch    r1,TMP+2        ; read the status reg
1400
        blt             r1,r0,tmp_init2
1401
tmp_init3:
1402
        ret
1403
 
1404
tmp_read:
1405
        subui   sp,sp,#24
1406
        sw              lr,[sp]
1407
        sw              r1,8[sp]
1408
        sw              r2,16[sp]
1409
 
1410
        lw              r1,#25000000    ; wait about 1 second or so
1411
tmp_read1:
1412
        loop    r1,tmp_read1
1413
        lw              r1,#0xAC        ; issue read temperature conversion
1414
        outc    r1,TMP
1415
 
1416
        ; wait a bit for the trigger to take effect
1417
        lw              r1,#2500
1418
tmp_read3:
1419
        loop    r1,tmp_read3
1420
 
1421
        ; wait for the rst1626 to go low
1422
        lw              r2,#10000000
1423
tmp_read2:
1424
        inch    r1,TMP+2        ; read the status reg
1425
        beq             r2,r0,tmp_read4
1426
        subui   r2,r2,#1
1427
        blt             r1,r0,tmp_read2
1428
tmp_read4:
1429
        inch    r1,TMP+2                ; read the temperature
1430
        lw              r2,#5                   ; five digits
1431
        call    DisplayNum
1432
        lw              lr,[sp]
1433
        lw              r1,8[sp]
1434
        lw              r2,16[sp]
1435
        ret             #24
1436
 
1437
;==============================================================================
1438
;==============================================================================
1439 27 robfinch
;------------------------------------------------------------------------------
1440 43 robfinch
; 100 Hz interrupt
1441 27 robfinch
; - takes care of "flashing" the cursor
1442
;------------------------------------------------------------------------------
1443
;
1444 43 robfinch
Pulse100:
1445
        subui   sp,sp,#8
1446
        sw              lr,[sp]
1447
        lea             r2,TEXTSCR
1448
        inch    r1,334[r2]
1449 27 robfinch
        addui   r1,r1,#1
1450 43 robfinch
        outc    r1,334[r2]
1451 46 robfinch
;       call    DisplayDatetime
1452 43 robfinch
        call    SelectNextToRunTCB
1453
        call    SwitchTask
1454 46 robfinch
        outb    r0,0xDCFFFC             ; clear interrupt
1455 43 robfinch
;       lw              r1,TickIRQAddr
1456
;       jal             r31,[r1]
1457
;       lw              r1,Milliseconds
1458
;       andi    r1,r1,#0x0f
1459
;       bnei    r1,#5,p1001
1460
;       call    FlashCursor
1461
p1001:
1462
        lw              lr,[sp]
1463
        ret             #8
1464 27 robfinch
 
1465
;------------------------------------------------------------------------------
1466 43 robfinch
;------------------------------------------------------------------------------
1467
SelectNextToRunTCB:
1468
        sc              r0,NextToRunTCB
1469
        ret
1470
 
1471
;------------------------------------------------------------------------------
1472
; Switch from the RunningTCB to the NextToRunTCB
1473
;------------------------------------------------------------------------------
1474
SwitchTask:
1475
        sw              r1,r1save
1476
        sw              r2,r2save
1477
        lcu             r1,NextToRunTCB
1478
        lcu             r2,RunningTCB
1479
        bne             r1,r2,swtsk1            ; are we already running this TCB ?
1480
        lw              r1,r1save
1481
        lw              r2,r2save
1482
        ret
1483
swtsk1:
1484
        andi    r2,r2,#0x1ff            ; max 512 TCB's
1485
        mului   r2,r2,#TCBSize
1486
        addui   r2,r2,#TCBBase
1487
        lw              r1,r1save                       ; get back r1
1488
        sw              r1,TCBr1[r2]
1489
        lw              r1,r2save                       ; get back r2
1490
        sw              r1,TCBr2[r2]
1491
        sw              r3,TCBr3[r2]
1492
        sw              r4,TCBr4[r2]
1493
        sw              r5,TCBr5[r2]
1494
        sw              r6,TCBr6[r2]
1495
        sw              r7,TCBr7[r2]
1496
        sw              r8,TCBr8[r2]
1497
        sw              r9,TCBr9[r2]
1498
        sw              r10,TCBr10[r2]
1499
        sw              r11,TCBr11[r2]
1500
        sw              r12,TCBr12[r2]
1501
        sw              r13,TCBr13[r2]
1502
        sw              r14,TCBr14[r2]
1503
        sw              r15,TCBr15[r2]
1504
        sw              r16,TCBr16[r2]
1505
        sw              r17,TCBr17[r2]
1506
        sw              r18,TCBr18[r2]
1507
        sw              r19,TCBr19[r2]
1508
        sw              r20,TCBr20[r2]
1509
        sw              r21,TCBr21[r2]
1510
        sw              r22,TCBr22[r2]
1511
        sw              r23,TCBr23[r2]
1512
        sw              r24,TCBr24[r2]
1513
        sw              r25,TCBr25[r2]
1514
        sw              r26,TCBr26[r2]
1515
        sw              r27,TCBr27[r2]
1516
        sw              r28,TCBr28[r2]
1517
        sw              r29,TCBr29[r2]
1518
        sw              r30,TCBr30[r2]
1519
        sw              r31,TCBr31[r2]
1520
 
1521
        lcu             r2,NextToRunTCB
1522
        sc              r2,RunningTCB
1523
        mului   r2,r2,#TCBSize
1524
        addui   r2,r2,#TCBBase
1525
 
1526
        lw              r1,TCBr1[r2]
1527
        lw              r3,TCBr3[r2]
1528
        lw              r4,TCBr4[r2]
1529
        lw              r5,TCBr5[r2]
1530
        lw              r6,TCBr6[r2]
1531
        lw              r7,TCBr7[r2]
1532
        lw              r8,TCBr8[r2]
1533
        lw              r9,TCBr9[r2]
1534
        lw              r10,TCBr10[r2]
1535
        lw              r11,TCBr11[r2]
1536
        lw              r12,TCBr12[r2]
1537
        lw              r13,TCBr13[r2]
1538
        lw              r14,TCBr14[r2]
1539
        lw              r15,TCBr15[r2]
1540
        lw              r16,TCBr16[r2]
1541
        lw              r17,TCBr17[r2]
1542
        lw              r18,TCBr18[r2]
1543
        lw              r19,TCBr19[r2]
1544
        lw              r20,TCBr20[r2]
1545
        lw              r21,TCBr21[r2]
1546
        lw              r22,TCBr22[r2]
1547
        lw              r23,TCBr23[r2]
1548
        lw              r24,TCBr24[r2]
1549
        lw              r25,TCBr25[r2]
1550
        lw              r26,TCBr26[r2]
1551
        lw              r27,TCBr27[r2]
1552
        lw              r28,TCBr28[r2]
1553
        lw              r29,TCBr29[r2]
1554
        lw              r30,TCBr30[r2]
1555
        lw              r31,TCBr31[r2]
1556
        lw              r2,TCBr2[r2]
1557
        ret
1558
 
1559
;------------------------------------------------------------------------------
1560 27 robfinch
; Flash Cursor
1561
;------------------------------------------------------------------------------
1562
;
1563
FlashCursor:
1564
        subui   sp,sp,#32
1565 43 robfinch
        sw              r1,[sp]
1566
        sw              r2,8[sp]
1567
        sw              r3,16[sp]
1568
        sw              lr,24[sp]
1569 27 robfinch
        call    CalcScreenLoc
1570
        addui   r1,r1,#0x10000
1571 43 robfinch
        lb              r2,CursorFlash
1572
        beq             r2,r0,flshcrsr2
1573 27 robfinch
        ; causes screen colors to flip around
1574 43 robfinch
        inch    r2,[r1]
1575 27 robfinch
        addui   r2,r2,#1
1576 43 robfinch
        outc    r2,[r1]
1577
flshcrsr3:
1578 27 robfinch
        lw              r2,Lastloc
1579
        beq             r1,r2,flshcrsr1
1580
        ; restore the screen colors of the previous cursor location
1581
        lc              r3,ScreenColor
1582 43 robfinch
        outc    r3,[r2]
1583 27 robfinch
        sw              r1,Lastloc
1584
flshcrsr1:
1585 43 robfinch
        lw              r1,[sp]
1586
        lw              r2,8[sp]
1587
        lw              r3,16[sp]
1588
        lw              lr,24[sp]
1589 27 robfinch
        ret             #32
1590 43 robfinch
flshcrsr2:
1591
        lc              r3,ScreenColor
1592
        outc    r3,[r1]
1593
        bra             flshcrsr3
1594 27 robfinch
 
1595 43 robfinch
CursorOff:
1596
        lw              r1,#0xA0
1597
        outc    r1,TEXTREG+16           ; turn off cursor
1598
        ret
1599
CursorOn:
1600
        lw              r1,#0xE0
1601
        outc    r1,TEXTREG+16           ; turn on cursor
1602
        ret
1603
 
1604 27 robfinch
;------------------------------------------------------------------------------
1605
;------------------------------------------------------------------------------
1606
ClearBmpScreen:
1607 43 robfinch
        subui   sp,sp,#24
1608
        sw              r1,[sp]
1609
        sw              r2,8[sp]
1610
        sw              r3,16[sp]
1611
        lw              r2,#1364*768
1612
        shrui   r2,r2,#3                        ; r2 = # words to clear
1613
        lea             r1,0x2929292929292929   ; r1 = color for eight pixels
1614
        lea             r3,BITMAPSCR            ; r3 = screen address
1615 27 robfinch
csj4:
1616 43 robfinch
        sw              r1,[r3]                         ; store pixel data
1617
        addui   r3,r3,#8                        ; advance screen address by eight
1618
        loop    r2,csj4                         ; decrement pixel count and loop back
1619
        lw              r1,[sp]
1620
        lw              r2,8[sp]
1621
        lw              r3,16[sp]
1622
        ret             #24
1623 27 robfinch
 
1624
;------------------------------------------------------------------------------
1625
; Clear the screen and the screen color memory
1626
; We clear the screen to give a visual indication that the system
1627
; is working at all.
1628
;------------------------------------------------------------------------------
1629
;
1630
ClearScreen:
1631
        subui   sp,sp,#40
1632 43 robfinch
        sw              r1,[sp]
1633
        sw              r2,8[sp]
1634
        sw              r3,16[sp]
1635
        sw              r4,24[sp]
1636
        sw              lr,32[sp]
1637
        lea             r3,TEXTREG
1638
        inch    r1,TEXT_COLS[r3]        ; calc number to clear
1639
        inch    r2,TEXT_ROWS[r3]
1640 27 robfinch
        mulu    r2,r1,r2                        ; r2 = # chars to clear
1641
        setlo   r1,#32                  ; space char
1642
        lc              r4,ScreenColor
1643
        call    AsciiToScreen
1644 43 robfinch
        lea             r3,TEXTSCR              ; text screen address
1645 27 robfinch
csj4:
1646 43 robfinch
        outc    r1,[r3]
1647
        outc    r4,0x10000[r3]  ; color screen is 0x10000 higher
1648
        addui   r3,r3,#2
1649 27 robfinch
        loop    r2,csj4
1650 43 robfinch
        lw              lr,32[sp]
1651
        lw              r4,24[sp]
1652
        lw              r3,16[sp]
1653
        lw              r2,8[sp]
1654
        lw              r1,[sp]
1655 27 robfinch
        ret             #40
1656
 
1657
;------------------------------------------------------------------------------
1658
; Scroll text on the screen upwards
1659
;------------------------------------------------------------------------------
1660
;
1661
ScrollUp:
1662
        subui   sp,sp,#40
1663 43 robfinch
        sw              r1,[sp]
1664
        sw              r2,8[sp]
1665
        sw              r3,16[sp]
1666
        sw              r4,24[sp]
1667
        sw              lr,32[sp]
1668
        lea             r3,TEXTREG
1669
        inch    r1,TEXT_COLS[r3]        ; r1 = # text columns
1670
        inch    r2,TEXT_ROWS[r3]
1671 27 robfinch
        mulu    r2,r1,r2                        ; calc number of chars to scroll
1672
        subu    r2,r2,r1                        ; one less row
1673 43 robfinch
        lea             r3,TEXTSCR
1674 27 robfinch
scrup1:
1675 46 robfinch
        inch    r4,[r3+r1*2]            ; indexed addressing example
1676 43 robfinch
        outc    r4,[r3]
1677 27 robfinch
        addui   r3,r3,#2
1678
        loop    r2,scrup1
1679
 
1680 43 robfinch
        lea             r3,TEXTREG
1681
        inch    r1,TEXT_ROWS[r3]
1682 27 robfinch
        subui   r1,r1,#1
1683
        call    BlankLine
1684 43 robfinch
        lw              r1,[sp]
1685
        lw              r2,8[sp]
1686
        lw              r3,16[sp]
1687
        lw              r4,24[sp]
1688
        lw              lr,32[sp]
1689 27 robfinch
        ret             #40
1690
 
1691
;------------------------------------------------------------------------------
1692
; Blank out a line on the display
1693
; line number to blank is in r1
1694
;------------------------------------------------------------------------------
1695
;
1696
BlankLine:
1697
        subui   sp,sp,#24
1698 43 robfinch
        sw              r1,[sp]
1699
        sw              r2,8[sp]
1700
        sw              r3,16[sp]
1701
        lea             r3,TEXTREG                      ; r3 = text register address
1702
        inch    r2,TEXT_COLS[r3]        ; r2 = # chars to blank out
1703 27 robfinch
        mulu    r3,r2,r1
1704
        shli    r3,r3,#1
1705
        addui   r3,r3,#TEXTSCR          ; r3 = screen address
1706
        setlo   r1,#' '
1707
blnkln1:
1708 43 robfinch
        outc    r1,[r3]
1709 27 robfinch
        addui   r3,r3,#2
1710
        loop    r2,blnkln1
1711 43 robfinch
        lw              r1,[sp]
1712
        lw              r2,8[sp]
1713
        lw              r3,16[sp]
1714 27 robfinch
        ret             #24
1715
 
1716
;------------------------------------------------------------------------------
1717
; Convert ASCII character to screen display character.
1718
;------------------------------------------------------------------------------
1719
;
1720
AsciiToScreen:
1721
        andi    r1,r1,#0x00ff
1722
        bltui   r1,#'A',atoscr1
1723
        bleui   r1,#'Z',atoscr1
1724
        bgtui   r1,#'z',atoscr1
1725
        bltui   r1,#'a',atoscr1
1726 46 robfinch
        subui   r1,r1,#0x60
1727 27 robfinch
atoscr1:
1728
        ori             r1,r1,#0x100
1729
        ret
1730
 
1731
;------------------------------------------------------------------------------
1732
; Convert screen character to ascii character
1733
;------------------------------------------------------------------------------
1734
;
1735
ScreenToAscii:
1736
        andi    r1,r1,#0xff
1737
        bgtui   r1,#26,stasc1
1738
        addui   r1,r1,#60
1739
stasc1:
1740
        ret
1741
 
1742
;------------------------------------------------------------------------------
1743
; Calculate screen memory location from CursorRow,CursorCol.
1744
; Also refreshes the cursor location.
1745
; Destroys r1,r2,r3
1746
; r1 = screen location
1747
;------------------------------------------------------------------------------
1748
;
1749
CalcScreenLoc:
1750 46 robfinch
        lbu             r1,CursorRow
1751 27 robfinch
        andi    r1,r1,#0x7f
1752 43 robfinch
        lea             r3,TEXTREG
1753 27 robfinch
        inch    r2,TEXT_COLS[r3]
1754
        mulu    r2,r2,r1
1755 46 robfinch
        lbu             r1,CursorCol
1756 27 robfinch
        andi    r1,r1,#0x7f
1757
        addu    r2,r2,r1
1758
        outc    r2,TEXT_CURPOS[r3]
1759 46 robfinch
        shlui   r2,r2,#1
1760 27 robfinch
        addui   r1,r2,#TEXTSCR                  ; r1 = screen location
1761
        ret
1762
 
1763
;------------------------------------------------------------------------------
1764
; Display a character on the screen
1765
; d1.b = char to display
1766
;------------------------------------------------------------------------------
1767
;
1768
DisplayChar:
1769
        bnei    r1,#'\r',dccr           ; carriage return ?
1770
        subui   sp,sp,#32
1771 43 robfinch
        sw              r1,[sp]
1772
        sw              r2,8[sp]
1773
        sw              r3,16[sp]
1774
        sw              lr,24[sp]
1775 46 robfinch
        sb              r0,CursorCol            ; just set cursor column to zero on a CR
1776 27 robfinch
        bra             dcx7
1777
dccr:
1778 46 robfinch
;       beqi    r1,#CTRLK,dccr1
1779 27 robfinch
        bnei    r1,#0x91,dcx6           ; cursor right ?
1780 46 robfinch
dccr1:
1781 27 robfinch
        subui   sp,sp,#32
1782 43 robfinch
        sw              r1,[sp]
1783
        sw              r2,8[sp]
1784
        sw              r3,16[sp]
1785
        sw              lr,24[sp]
1786 46 robfinch
        lbu             r2,CursorCol
1787 27 robfinch
        beqi    r2,#56,dcx7
1788
        addui   r2,r2,#1
1789 46 robfinch
        sb              r2,CursorCol
1790 27 robfinch
dcx7:
1791
        call    CalcScreenLoc
1792 43 robfinch
        lw              lr,24[sp]
1793
        lw              r3,16[sp]
1794
        lw              r2,8[sp]
1795
        lw              r1,[sp]
1796 27 robfinch
        ret             #32
1797
dcx6:
1798 46 robfinch
;       beqi    r1,#CTRLI,dccu1
1799 27 robfinch
        bnei    r1,#0x90,dcx8           ; cursor up ?
1800 46 robfinch
dccu1:
1801 27 robfinch
        subui   sp,sp,#32
1802 43 robfinch
        sw              r1,[sp]
1803
        sw              r2,8[sp]
1804
        sw              r3,16[sp]
1805
        sw              lr,24[sp]
1806 46 robfinch
        lbu             r2,CursorRow
1807 27 robfinch
        beqi    r2,#0,dcx7
1808
        subui   r2,r2,#1
1809 46 robfinch
        sb              r2,CursorRow
1810 27 robfinch
        bra             dcx7
1811
dcx8:
1812 46 robfinch
;       beqi    r1,#CTRLJ,dccl1
1813 27 robfinch
        bnei    r1,#0x93,dcx9           ; cursor left ?
1814 46 robfinch
dccl1:
1815 27 robfinch
        subui   sp,sp,#32
1816 43 robfinch
        sw              r1,[sp]
1817
        sw              r2,8[sp]
1818
        sw              r3,16[sp]
1819
        sw              lr,24[sp]
1820 46 robfinch
        lbu             r2,CursorCol
1821 27 robfinch
        beqi    r2,#0,dcx7
1822
        subui   r2,r2,#1
1823 46 robfinch
        sb              r2,CursorCol
1824 27 robfinch
        bra             dcx7
1825
dcx9:
1826 46 robfinch
;       beqi    r1,#CTRLM,dccd1
1827 27 robfinch
        bnei    r1,#0x92,dcx10          ; cursor down ?
1828 46 robfinch
dccd1:
1829 27 robfinch
        subui   sp,sp,#32
1830 43 robfinch
        sw              r1,[sp]
1831
        sw              r2,8[sp]
1832
        sw              r3,16[sp]
1833
        sw              lr,24[sp]
1834 46 robfinch
        lbu             r2,CursorRow
1835 27 robfinch
        beqi    r2,#30,dcx7
1836
        addui   r2,r2,#1
1837 46 robfinch
        sb              r2,CursorRow
1838 27 robfinch
        bra             dcx7
1839
dcx10:
1840
        bnei    r1,#0x94,dcx11                  ; cursor home ?
1841
        subui   sp,sp,#32
1842 43 robfinch
        sw              r1,[sp]
1843
        sw              r2,8[sp]
1844
        sw              r3,16[sp]
1845
        sw              lr,24[sp]
1846 46 robfinch
        lbu             r2,CursorCol
1847 27 robfinch
        beq             r2,r0,dcx12
1848 46 robfinch
        sb              r0,CursorCol
1849 27 robfinch
        bra             dcx7
1850
dcx12:
1851 46 robfinch
        sb              r0,CursorRow
1852 27 robfinch
        bra             dcx7
1853
dcx11:
1854
        subui   sp,sp,#48
1855 43 robfinch
        sw              r1,[sp]
1856
        sw              r2,8[sp]
1857
        sw              r3,16[sp]
1858
        sw              r4,24[sp]
1859
        sw              r5,32[sp]
1860
        sw              lr,40[sp]
1861 27 robfinch
        bnei    r1,#0x99,dcx13          ; delete ?
1862
        call    CalcScreenLoc
1863 46 robfinch
        mov             r3,r1                           ; r3 = screen location
1864
        lbu             r1,CursorCol            ; r1 = cursor column
1865 27 robfinch
        bra             dcx5
1866
dcx13:
1867
        bnei    r1,#CTRLH,dcx3          ; backspace ?
1868 46 robfinch
        lbu             r2,CursorCol
1869 27 robfinch
        beq             r2,r0,dcx4
1870
        subui   r2,r2,#1
1871 46 robfinch
        sb              r2,CursorCol
1872 27 robfinch
        call    CalcScreenLoc           ; a0 = screen location
1873 46 robfinch
        mov             r3,r1                           ; r3 = screen location
1874
        lbu             r1,CursorCol
1875 27 robfinch
dcx5:
1876 43 robfinch
        inch    r2,2[r3]
1877
        outc    r2,[r3]
1878 27 robfinch
        addui   r3,r3,#2
1879
        addui   r1,r1,#1
1880 43 robfinch
        lea             r4,TEXTREG
1881 27 robfinch
        inch    r5,TEXT_COLS[r4]
1882
        bltu    r1,r5,dcx5
1883 43 robfinch
        setlo   r1,#' '
1884
        call    AsciiToScreen
1885
        outc    r1,-2[r3]
1886 27 robfinch
        bra             dcx4
1887
dcx3:
1888
        beqi    r1,#'\n',dclf   ; linefeed ?
1889 46 robfinch
        mov             r4,r1                   ; save r1 in r4
1890 27 robfinch
        call    CalcScreenLoc   ; r1 = screen location
1891 46 robfinch
        mov             r3,r1                   ; r3 = screen location
1892
        mov             r1,r4                   ; restore r1
1893 27 robfinch
        call    AsciiToScreen   ; convert ascii char to screen char
1894 43 robfinch
        outc    r1,[r3]
1895 46 robfinch
        lc              r1,CharColor
1896
        outc    r1,0x10000[r3]
1897 27 robfinch
        call    IncCursorPos
1898 43 robfinch
        bra             dcx4
1899 27 robfinch
dclf:
1900
        call    IncCursorRow
1901
dcx4:
1902 43 robfinch
        lw              lr,40[sp]
1903
        lw              r5,32[sp]
1904
        lw              r4,24[sp]
1905
        lw              r3,16[sp]
1906
        lw              r2,8[sp]
1907
        lw              r1,[sp]
1908 27 robfinch
        ret             #48
1909
 
1910
 
1911
;------------------------------------------------------------------------------
1912
; Increment the cursor position, scroll the screen if needed.
1913
;------------------------------------------------------------------------------
1914
;
1915
IncCursorPos:
1916
        subui   sp,sp,#32
1917 43 robfinch
        sw              r1,[sp]
1918
        sw              r2,8[sp]
1919
        sw              r3,16[sp]
1920
        sw              lr,24[sp]
1921 46 robfinch
        lbu             r1,CursorCol
1922 27 robfinch
        addui   r1,r1,#1
1923 46 robfinch
        sb              r1,CursorCol
1924 27 robfinch
        inch    r2,TEXTREG+TEXT_COLS
1925
        bleu    r1,r2,icc1
1926 46 robfinch
        sb              r0,CursorCol            ; column = 0
1927 27 robfinch
        bra             icr1
1928
IncCursorRow:
1929
        subui   sp,sp,#32
1930 43 robfinch
        sw              r1,[sp]
1931
        sw              r2,8[sp]
1932
        sw              r3,16[sp]
1933
        sw              lr,24[sp]
1934 27 robfinch
icr1:
1935 46 robfinch
        lbu             r1,CursorRow
1936 27 robfinch
        addui   r1,r1,#1
1937 46 robfinch
        sb              r1,CursorRow
1938 27 robfinch
        inch    r2,TEXTREG+TEXT_ROWS
1939
        bleu    r1,r2,icc1
1940
        subui   r2,r2,#1                        ; backup the cursor row, we are scrolling up
1941 46 robfinch
        sb              r2,CursorRow
1942 27 robfinch
        call    ScrollUp
1943
icc1:
1944
        call    CalcScreenLoc
1945 43 robfinch
        lw              lr,24[sp]
1946
        lw              r3,16[sp]
1947
        lw              r2,8[sp]
1948
        lw              r1,[sp]
1949 27 robfinch
        ret             #32
1950
 
1951
;------------------------------------------------------------------------------
1952
; Display a string on the screen.
1953
;------------------------------------------------------------------------------
1954
;
1955
DisplayString:
1956 46 robfinch
        subui   sp,sp,#24
1957 43 robfinch
        sw              r1,[sp]
1958
        sw              r2,8[sp]
1959
        sw              lr,16[sp]
1960
        mov             r2,r1                   ; r2 = pointer to string
1961 27 robfinch
dspj1:
1962
        lbu             r1,[r2]                 ; move string char into r1
1963
        addui   r2,r2,#1                ; increment pointer
1964
        beq             r1,r0,dsret             ; is it end of string ?
1965
        call    DisplayChar             ; display character
1966
        bra             dspj1                   ; go back for next character
1967
dsret:
1968 43 robfinch
        lw              lr,16[sp]
1969
        lw              r2,8[sp]
1970
        lw              r1,[sp]
1971 27 robfinch
        ret             #24
1972
 
1973
DisplayStringCRLF:
1974
        subui   r30,r30,#8
1975
        sw              r31,[r30]
1976
        call    DisplayString
1977
        lw              r31,[r30]
1978
        addui   r30,r30,#8
1979
 
1980
CRLF:
1981 46 robfinch
        subui   sp,sp,#16
1982 43 robfinch
        sw              r1,[sp]
1983
        sw              lr,8[sp]
1984 27 robfinch
        setlo   r1,#'\r'
1985
        call    DisplayChar
1986
        setlo   r1,#'\n'
1987
        call    DisplayChar
1988 43 robfinch
        lw              lr,8[sp]
1989
        lw              r1,[sp]
1990 27 robfinch
        ret             #16
1991
 
1992 46 robfinch
; Call the Tiny BASIC routine to display a number
1993
;
1994
DisplayNum:
1995
        jmp             PRTNUM
1996
 
1997 27 robfinch
;------------------------------------------------------------------------------
1998
; Display nybble in r1
1999
;------------------------------------------------------------------------------
2000
;
2001
DisplayNybble:
2002 43 robfinch
        subui   sp,sp,#16
2003
        sw              r1,[sp]
2004
        sw              lr,8[sp]
2005 27 robfinch
        andi    r1,r1,#0x0F
2006
        addui   r1,r1,#'0'
2007
        bleui   r1,#'9',dispnyb1
2008
        addui   r1,r1,#7
2009
dispnyb1:
2010
        call    DisplayChar
2011 43 robfinch
        lw              lr,8[sp]
2012
        lw              r1,[sp]
2013 27 robfinch
        ret             #16
2014
 
2015
;------------------------------------------------------------------------------
2016
; Display the byte in r1
2017
;------------------------------------------------------------------------------
2018
;
2019
DisplayByte:
2020
        subui   sp,sp,#16
2021 43 robfinch
        sw              r1,[sp]
2022
        sw              lr,8[sp]
2023 27 robfinch
        rori    r1,r1,#4
2024
        call    DisplayNybble
2025
        roli    r1,r1,#4
2026
        call    DisplayNybble
2027 43 robfinch
        lw              lr,8[sp]
2028
        lw              r1,[sp]
2029 27 robfinch
        ret             #16
2030
 
2031
;------------------------------------------------------------------------------
2032 46 robfinch
; Display the char in r1
2033
;------------------------------------------------------------------------------
2034
;
2035
DisplayCharr:
2036
        subui   sp,sp,#16
2037
        sw              r1,[sp]
2038
        sw              lr,8[sp]
2039
        rori    r1,r1,#8
2040
        call    DisplayByte
2041
        roli    r1,r1,#8
2042
        call    DisplayByte
2043
        lw              lr,8[sp]
2044
        lw              r1,[sp]
2045
        ret             #16
2046
 
2047
;------------------------------------------------------------------------------
2048
; Display the half-word in r1
2049
;------------------------------------------------------------------------------
2050
;
2051
DisplayHalf:
2052
        subui   sp,sp,#16
2053
        sw              r1,[sp]
2054
        sw              lr,8[sp]
2055
        rori    r1,r1,#16
2056
        call    DisplayCharr
2057
        roli    r1,r1,#16
2058
        call    DisplayCharr
2059
        lw              lr,8[sp]
2060
        lw              r1,[sp]
2061
        ret             #16
2062
 
2063
;------------------------------------------------------------------------------
2064 27 robfinch
; Display the 64 bit word in r1
2065
;------------------------------------------------------------------------------
2066
;
2067
DisplayWord:
2068
        subui   sp,sp,#24
2069 43 robfinch
        sw              r1,[sp]
2070
        sw              r3,8[sp]
2071
        sw              lr,16[sp]
2072 27 robfinch
        setlo   r3,#7
2073
dspwd1:
2074
        roli    r1,r1,#8
2075
        call    DisplayByte
2076
        loop    r3,dspwd1
2077 43 robfinch
        lw              lr,16[sp]
2078
        lw              r3,8[sp]
2079
        lw              r1,[sp]
2080 27 robfinch
        ret             #24
2081
 
2082
;------------------------------------------------------------------------------
2083
; Display memory pointed to by r2.
2084
; destroys r1,r3
2085
;------------------------------------------------------------------------------
2086
;
2087 46 robfinch
DisplayMemB:
2088 43 robfinch
        subui   sp,sp,#24
2089
        sw              r1,[sp]
2090
        sw              r3,8[sp]
2091
        sw              lr,16[sp]
2092 27 robfinch
        setlo   r1,#':'
2093
        call    DisplayChar
2094 43 robfinch
        mov             r1,r2
2095 27 robfinch
        call    DisplayWord
2096
        setlo   r3,#7
2097
dspmem1:
2098
        setlo   r1,#' '
2099
        call    DisplayChar
2100 46 robfinch
        lbu             r1,[r2]
2101 27 robfinch
        call    DisplayByte
2102
        addui   r2,r2,#1
2103
        loop    r3,dspmem1
2104
        call    CRLF
2105 43 robfinch
        lw              lr,16[sp]
2106
        lw              r3,8[sp]
2107
        lw              r1,[sp]
2108
        ret             #24
2109 27 robfinch
 
2110 46 robfinch
DisplayMemC:
2111
        subui   sp,sp,#24
2112
        sw              r1,[sp]
2113
        sw              r3,8[sp]
2114
        sw              lr,16[sp]
2115
        setlo   r1,#':'
2116
        call    DisplayChar
2117
        mov             r1,r2
2118
        call    DisplayWord
2119
        setlo   r3,#3
2120
dspmemc1:
2121
        setlo   r1,#' '
2122
        call    DisplayChar
2123
        lcu             r1,[r2]
2124
        call    DisplayCharr
2125
        addui   r2,r2,#2
2126
        loop    r3,dspmemc1
2127
        call    CRLF
2128
        lw              lr,16[sp]
2129
        lw              r3,8[sp]
2130
        lw              r1,[sp]
2131
        ret             #24
2132
 
2133
DisplayMemW:
2134
        subui   sp,sp,#24
2135
        sw              r1,[sp]
2136
        sw              lr,16[sp]
2137
        setlo   r1,#':'
2138
        call    DisplayChar
2139
        mov             r1,r2
2140
        call    DisplayWord
2141
        setlo   r1,#' '
2142
        call    DisplayChar
2143
        lw              r1,[r2]
2144
        call    DisplayWord
2145
        addui   r2,r2,#8
2146
        call    CRLF
2147
        lw              lr,16[sp]
2148
        lw              r1,[sp]
2149
        ret             #24
2150
 
2151 27 robfinch
;------------------------------------------------------------------------------
2152
; Converts binary number in r1 into BCD number in r2 and r1.
2153
;------------------------------------------------------------------------------
2154
;
2155
BinToBCD:
2156
        subui   sp,sp,#48
2157 43 robfinch
        sw              r3,[sp]
2158
        sw              r4,8[sp]
2159
        sw              r5,16[sp]
2160
        sw              r6,24[sp]
2161
        sw              r7,32[sp]
2162
        sw              r8,40[sp]
2163 27 robfinch
        setlo   r2,#10
2164
        setlo   r8,#19          ; number of digits to produce - 1
2165
bta1:
2166 46 robfinch
        modu    r3,r1,r2
2167 27 robfinch
        shli    r3,r3,#60       ; shift result to uppermost bits
2168
        shli    r7,r5,#60       ; copy low order nybble of r5 to r4 topmost nybble
2169
        shrui   r4,r4,#4
2170
        or              r4,r4,r7
2171
        shrui   r5,r5,#4
2172
        or              r5,r5,r3        ; copy new bcd digit into uppermost bits of r5
2173
        divui   r1,r1,r2        ; r1=r1/10
2174
        loop    r8,bta1
2175
        shrui   r4,r4,#48       ; right align number in register
2176
        shli    r6,r5,#16
2177
        or              r4,r4,r6        ; copy bits into r4
2178
        shrui   r5,r5,#48
2179 43 robfinch
        mov             r1,r4
2180
        mov             r2,r5
2181
        lw              r3,[sp]
2182
        lw              r4,8[sp]
2183
        lw              r5,16[sp]
2184
        lw              r6,24[sp]
2185
        lw              r7,32[sp]
2186
        lw              r8,40[sp]
2187 27 robfinch
        ret             #48
2188
 
2189
;------------------------------------------------------------------------------
2190
; Converts BCD number in r1 into Ascii number in r2 and r1.
2191
;------------------------------------------------------------------------------
2192
;
2193
BCDToAscii:
2194
        subui   sp,sp,#32
2195 43 robfinch
        sw              r3,[sp]
2196
        sw              r4,8[sp]
2197
        sw              r5,16[sp]
2198
        sw              r8,24[sp]
2199 27 robfinch
        setlo   r8,#15
2200
bta2:
2201
        andi    r2,r1,#0x0F
2202
        ori             r2,r2,#0x30
2203
        shli    r2,r2,#56
2204
        shrui   r4,r4,#8
2205
        shli    r5,r3,#56
2206
        or              r4,r4,r5
2207
        shrui   r3,r3,#8
2208
        or              r3,r3,r2
2209
        shrui   r1,r1,#4
2210
        loop    r8,bta2
2211 43 robfinch
        mov             r1,r4
2212
        mov             r2,r3
2213
        lw              r3,[sp]
2214
        lw              r4,8[sp]
2215
        lw              r5,16[sp]
2216
        lw              r8,24[sp]
2217 27 robfinch
        ret             #32
2218
 
2219
;------------------------------------------------------------------------------
2220
; Convert a binary number into a 20 character ascii string.
2221
; r1 = number to convert
2222
; r2 = address of string buffer
2223
;------------------------------------------------------------------------------
2224
;
2225
BinToStr:
2226
        subui   sp,sp,#56
2227 43 robfinch
        sw              r3,[sp]
2228
        sw              r7,8[sp]
2229
        sw              r8,16[sp]
2230
        sw              r9,24[sp]
2231
        sw              r10,32[sp]
2232
        sw              r11,40[sp]
2233
        sw              lr,48[sp]
2234
        mov             r11,r2
2235 27 robfinch
        call    BinToBCD
2236 43 robfinch
        mov             r10,r2  ; save off r2
2237 27 robfinch
        call    BCDToAscii
2238
        setlo   r9,#1
2239
btos3:
2240
        setlo   r8,#7
2241
btos1:
2242
        shli    r7,r9,#3
2243
        addui   r7,r7,r8
2244
        addui   r7,r7,#4
2245
        andi    r3,r1,#0xff
2246
        sb              r3,[r7+r11]
2247
        shrui   r1,r1,#8
2248
        loop    r8,btos1
2249 43 robfinch
        mov             r1,r2
2250 27 robfinch
        loop    r9,btos3
2251
; the last four digits
2252 43 robfinch
        mov             r1,r10  ; get back r2
2253 27 robfinch
        call    BCDToAscii
2254
        setlo   r8,#3
2255
btos2:
2256
        andi    r3,r1,#0xff
2257
        sb              r3,[r8+r11]
2258
        shrui   r1,r1,#8
2259
        loop    r8,btos2
2260
        sb              r0,20[r11]      ; null terminate
2261 43 robfinch
        lw              r3,[sp]
2262
        lw              r7,8[sp]
2263
        lw              r8,16[sp]
2264
        lw              r9,24[sp]
2265
        lw              r10,32[sp]
2266
        lw              r11,40[sp]
2267
        lw              lr,48[sp]
2268 27 robfinch
        ret             #56
2269
 
2270
 
2271
;==============================================================================
2272 46 robfinch
; System Monitor Program
2273 27 robfinch
;==============================================================================
2274 46 robfinch
;
2275 27 robfinch
Monitor:
2276 43 robfinch
        lea             sp,STACKTOP0    ; top of stack; reset the stack pointer
2277 27 robfinch
        sb              r0,KeybdEcho    ; turn off keyboard echo
2278
PromptLn:
2279
        call    CRLF
2280
        setlo   r1,#'$'
2281
        call    DisplayChar
2282
 
2283
; Get characters until a CR is keyed
2284
;
2285
Prompt3:
2286 46 robfinch
;       lw              r1,#2                   ; get keyboard character
2287
;       syscall #417
2288 27 robfinch
        call    KeybdGetChar
2289
        beqi    r1,#-1,Prompt3  ; wait for a character
2290
        beqi    r1,#CR,Prompt1
2291
        call    DisplayChar
2292
        bra             Prompt3
2293
 
2294
; Process the screen line that the CR was keyed on
2295
;
2296
Prompt1:
2297 46 robfinch
        sb              r0,CursorCol    ; go back to the start of the line
2298 27 robfinch
        call    CalcScreenLoc   ; r1 = screen memory location
2299 46 robfinch
        mov             r3,r1
2300 43 robfinch
        inch    r1,[r3]
2301 27 robfinch
        addui   r3,r3,#2
2302
        call    ScreenToAscii
2303
        bnei    r1,#'$',Prompt2 ; skip over '$' prompt character
2304 43 robfinch
        inch    r1,[r3]
2305 27 robfinch
        addui   r3,r3,#2
2306
        call    ScreenToAscii
2307
 
2308
; Dispatch based on command character
2309
;
2310
Prompt2:
2311
        beqi    r1,#':',Editmem         ; $: - edit memory
2312
        beqi    r1,#'D',Dumpmem         ; $D - dump memory
2313 46 robfinch
        beqi    r1,#'F',Fillmem         ; $F - fill memory
2314
Prompt7:
2315
        bnei    r1,#'B',Prompt4         ; $B - start tiny basic
2316
        jmp             CSTART
2317
Prompt4:
2318 27 robfinch
        beqi    r1,#'J',ExecuteCode     ; $J - execute code
2319 46 robfinch
        bnei    r1,#'L',Prompt9 ; $L - load S19 file
2320
        jmp             LoadSector
2321
Prompt9:
2322
        bnei    r1,#'?',Prompt10        ; $? - display help
2323
        lea             r1,HelpMsg
2324
        call    DisplayString
2325
        jmp             Monitor
2326
Prompt10:
2327 27 robfinch
        beqi    r1,#'C',TestCLS         ; $C - clear screen
2328 46 robfinch
        bnei    r1,#'R',Prompt12
2329
        jmp             RandomLinesCall
2330
Prompt12:
2331
        bnei    r1,#'I',Prompt13
2332
        jmp             Invaders
2333
Prompt13:
2334
        bnei    r1,#'P',Prompt14
2335
        jmp             Piano
2336
Prompt14:
2337
        bnei    r1,#'T',Prompt15
2338
        call    tmp_read
2339
Prompt15:
2340
        jmp             Monitor
2341 27 robfinch
 
2342 43 robfinch
RandomLinesCall:
2343
        call    RandomLines
2344 46 robfinch
        jmp             Monitor
2345 43 robfinch
 
2346 27 robfinch
TestCLS:
2347 43 robfinch
        inch    r1,[r3]
2348 27 robfinch
        addui   r3,r3,#2
2349
        call    ScreenToAscii
2350
        bnei    r1,#'L',Monitor
2351 43 robfinch
        inch    r1,[r3]
2352 27 robfinch
        addui   r3,r3,#2
2353
        call    ScreenToAscii
2354
        bnei    r1,#'S',Monitor
2355
        call    ClearScreen
2356
        sb              r0,CursorCol
2357
        sb              r0,CursorRow
2358
        call    CalcScreenLoc
2359 46 robfinch
        jmp             Monitor
2360 10 robfinch
 
2361 27 robfinch
HelpMsg:
2362
        db      "? = Display help",CR,LF
2363
        db      "CLS = clear screen",CR,LF
2364
        db      ": = Edit memory bytes",CR,LF
2365
        db      "L = Load S19 file",CR,LF
2366 46 robfinch
        db      "D[B|C|H|W] = Dump memory",CR,LF
2367
        db      "F[B|C|H|W] = Fill memory",CR,LF
2368 27 robfinch
        db      "B = start tiny basic",CR,LF
2369 43 robfinch
        db      "J = Jump to code",CR,LF
2370
        db      "I = Invaders",CR,LF
2371
        db      "R = Random lines",CR,LF
2372 46 robfinch
        db      "T = get temperature",CR,LF
2373 43 robfinch
        db      "P = Piano",CR,LF,0
2374 46 robfinch
        align   4
2375 27 robfinch
 
2376
;------------------------------------------------------------------------------
2377
; Ignore blanks in the input
2378
; r3 = text pointer
2379
; r1 destroyed
2380
;------------------------------------------------------------------------------
2381
;
2382
ignBlanks:
2383
        subui   sp,sp,#8
2384
        sw              r31,[sp]
2385
ignBlanks1:
2386 43 robfinch
        inch    r1,[r3]
2387 27 robfinch
        addui   r3,r3,#2
2388
        call    ScreenToAscii
2389
        beqi    r1,#' ',ignBlanks1
2390
        subui   r3,r3,#2
2391
        lw              r31,[sp]
2392
        ret             #8
2393
 
2394
;------------------------------------------------------------------------------
2395
; Edit memory byte(s).
2396
;------------------------------------------------------------------------------
2397
;
2398
EditMem:
2399
        call    ignBlanks
2400
        call    GetHexNumber
2401
        or              r5,r1,r0
2402
        setlo   r4,#7
2403
edtmem1:
2404
        call    ignBlanks
2405
        call    GetHexNumber
2406
        sb              r1,[r5]
2407
        addui   r5,r5,#1
2408
        loop    r4,edtmem1
2409 46 robfinch
        jmp             Monitor
2410 27 robfinch
 
2411
;------------------------------------------------------------------------------
2412
; Execute code at the specified address.
2413
;------------------------------------------------------------------------------
2414
;
2415
ExecuteCode:
2416
        call    ignBlanks
2417
        call    GetHexNumber
2418 43 robfinch
        jal             r31,[r1]
2419 46 robfinch
        jmp     Monitor
2420 27 robfinch
 
2421 46 robfinch
LoadSector:
2422
        call    ignBlanks
2423
        call    GetHexNumber
2424
        lw              r2,#0x3800
2425
        call    spi_read_sector
2426
        jmp             Monitor
2427
 
2428 27 robfinch
;------------------------------------------------------------------------------
2429
; Do a memory dump of the requested location.
2430
;------------------------------------------------------------------------------
2431
;
2432
DumpMem:
2433 46 robfinch
        inch    r1,[r3]
2434
        addui   r3,r3,#2
2435
        call    ScreenToAscii
2436
        mov             r6,r1                   ; r6 = fill type character
2437 27 robfinch
        call    ignBlanks
2438 46 robfinch
        call    GetHexNumber    ; get start address of dump
2439 43 robfinch
        mov             r2,r1
2440 46 robfinch
        call    ignBlanks
2441
        call    GetHexNumber    ; get number of bytes to dump
2442
        shrui   r1,r1,#3                ; 1/8 as many dump rows
2443
        bnei    r1,#0,Dumpmem2
2444
        lw              r1,#1                   ; dump at least one row
2445
Dumpmem2:
2446 27 robfinch
        call    CRLF
2447 46 robfinch
        beqi    r6,#'W',DumpmemW
2448
;       beqi    r6,#'H',DumpmemH
2449
        beqi    r6,#'C',DumpmemC
2450
DumpmemB:
2451
        call    DisplayMemB
2452
        loop    r1,DumpmemB
2453
        jmp             Monitor
2454
DumpmemC:
2455
        call    DisplayMemC
2456
        loop    r1,DumpmemC
2457
        jmp             Monitor
2458
DumpmemW:
2459
        call    DisplayMemW
2460
        loop    r1,DumpmemW
2461
        jmp             Monitor
2462
 
2463
;       call    DisplayMem
2464
;       call    DisplayMem
2465
;       call    DisplayMem
2466
;       call    DisplayMem
2467
;       call    DisplayMem
2468
;       call    DisplayMem
2469
;       call    DisplayMem
2470 27 robfinch
        bra             Monitor
2471
 
2472 46 robfinch
Fillmem:
2473
        inch    r1,[r3]
2474
        addui   r3,r3,#2
2475
        call    ScreenToAscii
2476
        mov             r6,r1                   ; r6 = fill type character
2477
        call    ignBlanks
2478
        call    GetHexNumber    ; get start address of dump
2479
        mov             r2,r1
2480
        call    ignBlanks
2481
        call    GetHexNumber    ; get number of bytes to fill
2482
        mov             r5,r1
2483
        call    ignBlanks
2484
        call    GetHexNumber    ; get the fill byte
2485
        beqi    r6,#'C',FillmemC
2486
        beqi    r6,#'H',FillmemH
2487
        beqi    r6,#'W',FillmemW
2488
FillmemB:
2489
        sb              r1,[r2]
2490
        addui   r2,r2,#1
2491
        loop    r5,FillmemB
2492
        jmp             Monitor
2493
FillmemC:
2494
        sc              r1,[r2]
2495
        addui   r2,r2,#2
2496
        loop    r5,FillmemC
2497
        jmp             Monitor
2498
FillmemH:
2499
        sh              r1,[r2]
2500
        addui   r2,r2,#4
2501
        loop    r5,FillmemH
2502
        jmp             Monitor
2503
FillmemW:
2504
        sw              r1,[r2]
2505
        addui   r2,r2,#8
2506
        loop    r5,FillmemW
2507
        jmp             Monitor
2508
 
2509 27 robfinch
;------------------------------------------------------------------------------
2510
; Get a hexidecimal number. Maximum of sixteen digits.
2511
; R3 = text pointer (updated)
2512 43 robfinch
; R1 = hex number
2513 27 robfinch
;------------------------------------------------------------------------------
2514
;
2515
GetHexNumber:
2516
        subui   sp,sp,#24
2517 43 robfinch
        sw              r2,[sp]
2518
        sw              r4,8[sp]
2519
        sw              lr,16[sp]
2520 27 robfinch
        setlo   r2,#0
2521
        setlo   r4,#15
2522
gthxn2:
2523 43 robfinch
        inch    r1,[r3]
2524 27 robfinch
        addui   r3,r3,#2
2525
        call    ScreenToAscii
2526
        call    AsciiToHexNybble
2527
        beqi    r1,#-1,gthxn1
2528
        shli    r2,r2,#4
2529
        andi    r1,r1,#0x0f
2530
        or              r2,r2,r1
2531
        loop    r4,gthxn2
2532
gthxn1:
2533 43 robfinch
        mov             r1,r2
2534
        lw              lr,16[sp]
2535
        lw              r4,8[sp]
2536
        lw              r2,[sp]
2537 27 robfinch
        ret             #24
2538
 
2539
;------------------------------------------------------------------------------
2540
; Convert ASCII character in the range '0' to '9', 'a' to 'f' or 'A' to 'F'
2541
; to a hex nybble.
2542
;------------------------------------------------------------------------------
2543
;
2544
AsciiToHexNybble:
2545
        bltui   r1,#'0',gthx3
2546
        bgtui   r1,#'9',gthx5
2547
        subui   r1,r1,#'0'
2548 10 robfinch
        ret
2549 27 robfinch
gthx5:
2550
        bltui   r1,#'A',gthx3
2551
        bgtui   r1,#'F',gthx6
2552
        subui   r1,r1,#'A'
2553
        addui   r1,r1,#10
2554
        ret
2555
gthx6:
2556
        bltui   r1,#'a',gthx3
2557
        bgtui   r1,#'f',gthx3
2558
        subui   r1,r1,#'a'
2559
        addui   r1,r1,#10
2560
        ret
2561
gthx3:
2562
        setlo   r1,#-1          ; not a hex number
2563
        ret
2564 10 robfinch
 
2565
;==============================================================================
2566 27 robfinch
; Load an S19 format file
2567
;==============================================================================
2568
;
2569
LoadS19:
2570
        bra             ProcessRec
2571
NextRec:
2572
        call    sGetChar
2573
        bne             r1,#LF,NextRec
2574
ProcessRec:
2575
        call    sGetChar
2576
        beqi    r1,#26,Monitor  ; CTRL-Z ?
2577
        bnei    r1,#'S',NextRec
2578
        call    sGetChar
2579
        blt             r1,#'0',NextRec
2580
        bgt             r1,#'9',NextRec
2581
        or              r4,r1,r0                ; r4 = record type
2582
        call    sGetChar
2583
        call    AsciiToHexNybble
2584
        or              r2,r1,r0
2585
        call    sGetChar
2586
        call    AsciiToHexNybble
2587
        shli    r2,r2,#4
2588
        or              r2,r2,r1                ; r2 = byte count
2589
        or              r3,r2,r1                ; r3 = byte count
2590
        beqi    r4,#'0',NextRec ; manufacturer ID record, ignore
2591
        beqi    r4,#'1',ProcessS1
2592
        beqi    r4,#'2',ProcessS2
2593
        beqi    r4,#'3',ProcessS3
2594
        beqi    r4,#'5',NextRec ; record count record, ignore
2595
        beqi    r4,#'7',ProcessS7
2596
        beqi    r4,#'8',ProcessS8
2597
        beqi    r4,#'9',ProcessS9
2598
        bra             NextRec
2599
 
2600
pcssxa:
2601
        andi    r3,r3,#0xff
2602
        subui   r3,r3,#1                ; one less for loop
2603
pcss1a:
2604
        call    sGetChar
2605
        call    AsciiToHexNybble
2606
        shli    r2,r2,#4
2607
        or              r2,r2,r1
2608
        call    sGetChar
2609
        call    AsciiToHexNybble
2610
        shli    r2,r2,#4
2611
        or              r2,r2,r1
2612
        sb              r2,[r5]
2613
        addui   r5,r5,#1
2614
        loop    r3,pcss1a
2615
; Get the checksum byte
2616
        call    sGetChar
2617
        call    AsciiToHexNybble
2618
        shli    r2,r2,#4
2619
        or              r2,r2,r1
2620
        call    sGetChar
2621
        call    AsciiToHexNybble
2622
        shli    r2,r2,#4
2623
        or              r2,r2,r1
2624
        bra             NextRec
2625
 
2626
ProcessS1:
2627
        call    S19Get16BitAddress
2628
        bra             pcssxa
2629
ProcessS2:
2630
        call    S19Get24BitAddress
2631
        bra             pcssxa
2632
ProcessS3:
2633
        call    S19Get32BitAddress
2634
        bra             pcssxa
2635
ProcessS7:
2636
        call    S19Get32BitAddress
2637
        sw              r5,S19StartAddress
2638
        bra             Monitor
2639
ProcessS8:
2640
        call    S19Get24BitAddress
2641
        sw              r5,S19StartAddress
2642
        bra             Monitor
2643
ProcessS9:
2644
        call    S19Get16BitAddress
2645
        sw              r5,S19StartAddress
2646 46 robfinch
        jmp             Monitor
2647 27 robfinch
 
2648
S19Get16BitAddress:
2649
        subui   sp,sp,#8
2650
        sw              r31,[sp]
2651
        call    sGetChar
2652
        call    AsciiToHexNybble
2653
        or              r2,r1,r0
2654
        bra             S1932b
2655
 
2656
S19Get24BitAddress:
2657
        subui   sp,sp,#8
2658
        sw              r31,[sp]
2659
        call    sGetChar
2660
        call    AsciiToHexNybble
2661
        or              r2,r1,r0
2662
        bra             S1932a
2663
 
2664
S19Get32BitAddress:
2665
        subui   sp,sp,#8
2666
        sw              r31,[sp]
2667
        call    sGetChar
2668
        call    AsciiToHexNybble
2669
        or              r2,r1,r0
2670
        call    sGetChar
2671
        call    AsciiToHexNybble
2672
        shli    r2,r2,#4
2673
        or              r2,r1,r2
2674
        call    sGetChar
2675
        call    AsciiToHexNybble
2676
        shli    r2,r2,#4
2677
        or              r2,r2,r1
2678
S1932a:
2679
        call    sGetChar
2680
        call    AsciiToHexNybble
2681
        shli    r2,r2,#4
2682
        or              r2,r2,r1
2683
        call    sGetChar
2684
        call    AsciiToHexNybble
2685
        shli    r2,r2,#4
2686
        or              r2,r2,r1
2687
S1932b:
2688
        call    sGetChar
2689
        call    AsciiToHexNybble
2690
        shli    r2,r2,#4
2691
        or              r2,r2,r1
2692
        call    sGetChar
2693
        call    AsciiToHexNybble
2694
        shli    r2,r2,#4
2695
        or              r2,r2,r1
2696
        call    sGetChar
2697
        call    AsciiToHexNybble
2698
        shli    r2,r2,#4
2699
        or              r2,r2,r1
2700
        xor             r4,r4,r4
2701
        or              r5,r2,r0
2702
        lw              r31,[sp]
2703
        addui   sp,sp,#8
2704
        ret
2705
 
2706
;------------------------------------------------------------------------------
2707
; Get a character from auxillary input, checking the keyboard status for a
2708
; CTRL-C
2709
;------------------------------------------------------------------------------
2710
;
2711
sGetChar:
2712
        subui   sp,sp,#8
2713
        sw              r31,[sp]
2714
sgc2:
2715
        call    KeybdCheckForKey
2716
        beq             r1,r0,sgc1
2717
        call    KeybdGetchar
2718
        beqi    r1,#CRTLC,Monitor
2719
sgc1:
2720
        call    AUXIN
2721 43 robfinch
        ble             r1,r0,sgc2
2722 27 robfinch
        lw              r31,[sp]
2723 43 robfinch
        ret             #8
2724 27 robfinch
 
2725
;--------------------------------------------------------------------------
2726 43 robfinch
; Draw random lines on the bitmap screen.
2727 27 robfinch
;--------------------------------------------------------------------------
2728 46 robfinch
;
2729 43 robfinch
RandomLines:
2730
        subui   sp,sp,#24
2731
        sw              r1,[sp]
2732
        sw              r3,8[sp]
2733
        sw              lr,16[sp]
2734 46 robfinch
        sw              r0,ctx3start    ; prevent restarting context over and over again
2735 43 robfinch
rl5:
2736
        gran
2737
        mfspr   r1,rand                 ; select a random color
2738
        outh    r1,GACCEL
2739
rl1:                                            ; random X0
2740
        gran
2741
        mfspr   r1,rand
2742
        lw              r3,#1364
2743 46 robfinch
        modu    r1,r1,r3
2744 43 robfinch
        outh    r1,GACCEL+8
2745
rl2:                                            ; random X1
2746
        gran
2747
        mfspr   r1,rand
2748
        lw              r3,#1364
2749 46 robfinch
        modu    r1,r1,r3
2750 43 robfinch
        outh    r1,GACCEL+16
2751
rl3:                                            ; random Y0
2752
        gran
2753
        mfspr   r1,rand
2754
        lw              r3,#768
2755 46 robfinch
        modu    r1,r1,r3
2756 43 robfinch
        outh    r1,GACCEL+12
2757
rl4:                                            ; random Y1
2758
        gran
2759
        mfspr   r1,rand
2760
        lw              r3,#768
2761 46 robfinch
        modu    r1,r1,r3
2762 43 robfinch
        outh    r1,GACCEL+20
2763
        setlo   r1,#2                   ; draw line command
2764
        outh    r1,GACCEL+60
2765
rl8:
2766 46 robfinch
;       call    KeybdGetChar
2767
;       beqi    r1,#CTRLC,rl7
2768
        inch    r1,GACCEL+56    ; ensure controller is in IDLE state
2769
        bne             r1,r0,rl8
2770
        bra             rl5
2771 43 robfinch
rl7:
2772
        lw              lr,16[sp]
2773
        lw              r3,8[sp]
2774
        lw              r1,[sp]
2775
        ret             #24
2776
 
2777
;--------------------------------------------------------------------------
2778
; Initialize sprite image caches with random data.
2779
;--------------------------------------------------------------------------
2780
RandomizeSprram:
2781
        lea             r2,SPRRAM
2782
        setlo   r4,#14335               ; number of chars to initialize
2783
rsr1:
2784
        gran
2785
        mfspr   r1,rand
2786
        outc    r1,[r2]
2787
        addui   r2,r2,#2
2788
        loop    r4,rsr1
2789
        ret
2790
 
2791
;--------------------------------------------------------------------------
2792
; Setup the AC97/LM4550 audio controller. Check keyboard for a CTRL-C
2793
; interrupt which may be necessary if the audio controller isn't 
2794
; responding.
2795
;--------------------------------------------------------------------------
2796 27 robfinch
;
2797
SetupAC97:
2798 43 robfinch
        subui   sp,sp,#16
2799
        sw              r1,[sp]
2800
        sw              lr,8[sp]
2801
sac974:
2802
        outc    r0,AC97+0x26    ; trigger a read of register 26 (status reg)
2803 27 robfinch
sac971:                                         ; wait for status to register 0xF (all ready)
2804 43 robfinch
        call    KeybdGetChar    ; see if we needed to CTRL-C
2805
        beqi    r1,#CTRLC,sac973
2806 46 robfinch
        inch    r1,AC97+0x68    ; wait for dirty bit to clear
2807 43 robfinch
        bne             r1,r0,sac971
2808 46 robfinch
        inch    r1,AC97+0x26    ; check status at reg h26, wait for
2809 43 robfinch
        andi    r1,r1,#0x0F             ; analogue to be ready
2810
        bnei    r1,#0x0F,sac974
2811
sac973:
2812
        outc    r0,AC97+2               ; master volume, 0db attenuation, mute off
2813
        outc    r0,AC97+4               ; headphone volume, 0db attenuation, mute off
2814
        outc    r0,AC97+0x18    ; PCM gain (mixer) mute off, no attenuation
2815
        outc    r0,AC97+0x0A    ; mute PC beep
2816
        setlo   r1,#0x8000              ; bypass 3D sound
2817
        outc    r1,AC97+0x20
2818
sac972:
2819
        call    KeybdGetChar
2820
        beqi    r1,#CTRLC,sac975
2821 46 robfinch
        inch    r1,AC97+0x68    ; wait for dirty bits to clear
2822 43 robfinch
        bne             r1,r0,sac972    ; wait a while for the settings to take effect
2823
sac975:
2824
        lw              lr,8[sp]
2825
        lw              r1,[sp]
2826
        ret             #16
2827 27 robfinch
 
2828 43 robfinch
;--------------------------------------------------------------------------
2829
; Sound a 800 Hz beep
2830
;--------------------------------------------------------------------------
2831
;
2832 27 robfinch
Beep:
2833 43 robfinch
        subui   sp,sp,#16
2834
        sw              r1,[sp]
2835
        sw              lr,8[sp]
2836
        setlo   r1,#8
2837
        outb    r1,LED
2838 27 robfinch
        ori             r1,r0,#15               ; master volume to max
2839 43 robfinch
        outc    r1,PSG+128
2840 27 robfinch
        ori             r1,r0,#13422    ; 800Hz
2841 43 robfinch
        outc    r1,PSGFREQ0
2842
        setlo   r1,#9
2843
        outb    r1,LED
2844
        ; decay  (16.384 ms)2
2845
        ; attack (8.192 ms)1
2846
        ; release (1.024 s)A
2847
        ; sustain level C
2848
        setlo   r1,#0xCA12
2849
        outc    r1,PSGADSR0
2850 27 robfinch
        ori             r1,r0,#0x1104   ; gate, output enable, triangle waveform
2851 43 robfinch
        outc    r1,PSGCTRL0
2852 46 robfinch
        ori             r1,r0,#2500000  ; delay about 1s
2853 27 robfinch
beep1:
2854
        loop    r1,beep1
2855 43 robfinch
        setlo   r1,#13
2856
        outb    r1,LED
2857
        ori             r1,r0,#0x0104   ; gate off, output enable, triangle waveform
2858
        outc    r1,PSGCTRL0
2859 46 robfinch
        ori             r1,r0,#2500000  ; delay about 1s
2860 43 robfinch
beep2:
2861
        loop    r1,beep2
2862
        setlo   r1,#16
2863
        outb    r1,LED
2864 27 robfinch
        ori             r1,r0,#0x0000   ; gate off, output enable off, no waveform
2865 43 robfinch
        outc    r1,PSGCTRL0
2866
        lw              lr,8[sp]
2867
        lw              r1,[sp]
2868
        ret             #16
2869
 
2870
;--------------------------------------------------------------------------
2871
;--------------------------------------------------------------------------
2872
; 
2873
Piano:
2874
        ori             r1,r0,#15               ; master volume to max
2875
        outc    r1,PSG+128
2876
playnt:
2877
        call    KeybdGetChar
2878
        beqi    r1,#CTRLC,Monitor
2879
        beqi    r1,#'a',playnt1a
2880
        beqi    r1,#'b',playnt1b
2881
        beqi    r1,#'c',playnt1c
2882
        beqi    r1,#'d',playnt1d
2883
        beqi    r1,#'e',playnt1e
2884
        beqi    r1,#'f',playnt1f
2885
        beqi    r1,#'g',playnt1g
2886
        bra             playnt
2887
 
2888
playnt1a:
2889
        setlo   r1,#7217
2890
        call    Tone
2891
        bra             playnt
2892
playnt1b:
2893
        setlo   r1,#8101
2894
        call    Tone
2895
        bra             playnt
2896
playnt1c:
2897
        setlo   r1,#4291
2898
        call    Tone
2899
        bra             playnt
2900
playnt1d:
2901
        setlo   r1,#4817
2902
        call    Tone
2903
        bra             playnt
2904
playnt1e:
2905
        setlo   r1,#5407
2906
        call    Tone
2907
        bra             playnt
2908
playnt1f:
2909
        setlo   r1,#5728
2910
        call    Tone
2911
        bra             playnt
2912
playnt1g:
2913
        setlo   r1,#6430
2914
        call    Tone
2915
        bra             playnt
2916
 
2917
Tone:
2918
        subui   sp,sp,#16
2919
        sw              r1,[sp]
2920
        sw              lr,8[sp]
2921
        outc    r1,PSGFREQ0
2922
        ; decay  (16.384 ms)2
2923
        ; attack (8.192 ms)1
2924
        ; release (1.024 s)A
2925
        ; sustain level C
2926
        setlo   r1,#0xCA12
2927
        outc    r1,PSGADSR0
2928
        ori             r1,r0,#0x1104   ; gate, output enable, triangle waveform
2929
        outc    r1,PSGCTRL0
2930
        ori             r1,r0,#250000   ; delay about 10ms
2931
tone1:
2932
        loop    r1,tone1
2933
        ori             r1,r0,#0x0104   ; gate off, output enable, triangle waveform
2934
        outc    r1,PSGCTRL0
2935
        ori             r1,r0,#250000   ; delay about 10ms
2936
tone2:
2937
        loop    r1,tone2
2938
        ori             r1,r0,#0x0000   ; gate off, output enable off, no waveform
2939
        outc    r1,PSGCTRL0
2940
        lw              lr,8[sp]
2941
        lw              r1,[sp]
2942
        ret             #16
2943
 
2944
;==============================================================================
2945
;==============================================================================
2946
SetupRasterIRQ:
2947
        subui   sp,sp,#8
2948
        sw              r1,[sp]
2949
        setlo   r1,#200
2950
        outc    r1,RASTERIRQ
2951
        setlo   r1,#240
2952
        outc    r1,RASTERIRQ+2
2953
        setlo   r1,#280
2954
        outc    r1,RASTERIRQ+4
2955
        setlo   r1,#320
2956
        outc    r1,RASTERIRQ+6
2957
        setlo   r1,#360
2958
        outc    r1,RASTERIRQ+8
2959
        lw              r1,[sp]
2960
        ret             #8
2961
 
2962
RasterIRQfn:
2963
        inch    r1,RASTERIRQ+30         ; get the raster compare register # (clears IRQ)
2964
        beqi    r1,#1,rirq1
2965
        beqi    r1,#2,rirq2
2966
        beqi    r1,#3,rirq3
2967
        beqi    r1,#4,rirq4
2968
        beqi    r1,#5,rirq5
2969
        beqi    r1,#6,rirq6
2970
        beqi    r1,#7,rirq7
2971
        beqi    r1,#8,rirq8
2972 27 robfinch
        ret
2973 43 robfinch
rirq1:
2974
rirq2:
2975
rirq3:
2976
rirq4:
2977
rirq5:
2978
rirq6:
2979
rirq7:
2980
rirq8:
2981
        mului   r1,r1,#40
2982
        addui   r1,r1,#204
2983
        outc    r1,SPRITEREGS+2
2984
        outc    r1,SPRITEREGS+18
2985
        outc    r1,SPRITEREGS+34
2986
        outc    r1,SPRITEREGS+50
2987
        outc    r1,SPRITEREGS+66
2988
        outc    r1,SPRITEREGS+82
2989
        outc    r1,SPRITEREGS+98
2990
        outc    r1,SPRITEREGS+114
2991
        ret
2992 27 robfinch
 
2993 43 robfinch
;------------------------------------------------------------------------------
2994
;------------------------------------------------------------------------------
2995
DisplayDatetime:
2996 46 robfinch
        subui   sp,sp,#48
2997 43 robfinch
        sw              r1,[sp]
2998
        sw              r2,8[sp]
2999
        sw              r3,16[sp]
3000 46 robfinch
        sw              r4,24[sp]
3001
        sw              r5,32[sp]
3002 43 robfinch
        sw              lr,24[sp]
3003
        call    CursorOff
3004 46 robfinch
        lw              r1,#3                           ; get cursor position
3005
        syscall #410
3006
        mov             r4,r1                           ; r4 = row
3007
        mov             r5,r2                           ; r5 = col
3008
        lw              r1,#2                           ; set cursor position
3009
        lw              r2,#46                          ; move cursor down to last display line
3010
        lw              r3,#64
3011
        syscall #410
3012
        lw              r1,#1                           ; get the snapshotted date and time
3013
        syscall #416
3014 43 robfinch
        call    DisplayWord                     ; display on screen
3015 46 robfinch
        lw              r1,#2                           ; restore cursor position
3016
        mov             r2,r4                           ; r2 = row
3017
        mov             r3,r5                           ; r3 = col
3018
        syscall #410
3019 43 robfinch
        call    CursorOn
3020
        lw              lr,24[sp]
3021
        lw              r3,16[sp]
3022
        lw              r2,8[sp]
3023
        lw              r1,[sp]
3024 46 robfinch
        lw              r4,24[sp]
3025
        lw              r5,32[sp]
3026
        ret             #48
3027 43 robfinch
 
3028
;==============================================================================
3029
;==============================================================================
3030
InitializeGame:
3031
        subui   sp,sp,#16
3032
        sm              [sp],r3/lr
3033
        setlo   r3,#320
3034
        sc              r3,Manpos
3035
        sc              r0,Score
3036
        sb              r0,MissileActive
3037
        sc              r0,MissileX
3038
        sc              r0,MissileY
3039
        lm              [sp],r3/lr
3040
        ret             #16
3041
 
3042
DrawScore:
3043
        subui   sp,sp,#24
3044
        sm              [sp],r1/r3/lr
3045
        setlo   r3,#1
3046
        sb              r3,CursorRow
3047
        setlo   r3,#40
3048
        sb              r3,CursorCol
3049
        lb              r1,Score
3050
        call    DisplayByte
3051
        lb              r1,Score+1
3052
        call    DisplayByte
3053
        lm              [sp],r1/r3/lr
3054
        ret             #24
3055
 
3056
DrawMissile:
3057
        subui   sp,sp,#16
3058
        sm              [sp],r1/lr
3059
        lc              r1,MissileY
3060
        bleu    r1,#2,MissileOff
3061
        lc              r1,MissileX
3062
        shrui   r1,r1,#3
3063
        sb              r1,CursorCol
3064
        lc              r1,MissileY
3065
        sb              r1,CursorRow
3066
        subui   r1,r1,#1
3067
        sc              r1,MissileY
3068
        setlo   r1,#'^'
3069
        call    DisplayChar
3070
        lb              r1,CursorCol
3071
        subui   r1,r1,#1
3072
        sb              r1,CursorCol
3073
        lb              r1,CursorRow
3074
        subui   r1,r1,#1
3075
        sb              r1,CursorRow
3076
        setlo   r1,#' '
3077
        call    DisplayChar
3078
        lm              [sp],r1/lr
3079
        ret             #16
3080
MissileOff:
3081
        sb              r0,MissileActive
3082
        lc              r1,MissileX
3083
        shrui   r1,r1,#3
3084
        sb              r1,CursorCol
3085
        lc              r1,MissileY
3086
        sb              r1,CursorRow
3087
        setlo   r1,#' '
3088
        call    DisplayChar
3089
        lm              [sp],r1/lr
3090
        ret             #16
3091
 
3092
DrawMan:
3093
        subui   sp,sp,#24
3094
        sm              [sp],r1/r3/lr
3095
        setlo   r3,#46
3096
        sb              r3,CursorRow
3097
        lc              r3,Manpos
3098
        shrui   r3,r3,#3
3099
        sb              r3,CursorCol
3100
        setlo   r1,#' '
3101
        call    DisplayChar
3102
        setlo   r1,#'#'
3103
        call    DisplayChar
3104
        setlo   r1,#'A'
3105
        call    DisplayChar
3106
        setlo   r1,#'#'
3107
        call    DisplayChar
3108
        setlo   r1,#' '
3109
        call    DisplayChar
3110
        lm              [sp],r1/r3/lr
3111
        ret             #24
3112
 
3113
DrawInvader:
3114
        lw              r3,InvaderPos
3115
        lw              r1,#233
3116
        sc              r1,[r3]
3117
        lw              r1,#242
3118
        sc              r1,1[r3]
3119
        lw              r1,#223
3120
        sc              r1,2[r3]
3121
        ret
3122
 
3123
DrawInvaders:
3124
        subui   sp,sp,#40
3125
        sm              [sp],r1/r2/r3/r4/lr
3126
        lc              r1,InvadersRow1
3127
        lc              r4,InvadersColpos
3128
        andi    r2,r1,#1
3129
        beq             r2,r0,dinv1
3130
        lb              r3,InvadersRowpos
3131
        sb              r3,CursorRow
3132
        sb              r4,CursorCol
3133
        setlo   r1,#' '
3134
        call    DisplayByte
3135
        setlo   r1,#'#'
3136
        call    DisplayByte
3137
        setlo   r1,#'#'
3138
        call    DisplayByte
3139
        setlo   r1,#'#'
3140
        call    DisplayByte
3141
        setlo   r1,#' '
3142
        call    DisplayByte
3143
        lb              r1,CursorRow
3144
        addui   r1,r1,#1
3145
        sb              r1,CursorRow
3146
        lb              r1,CursorCol
3147
        subui   r1,r1,#5
3148
        setlo   r1,#' '
3149
        call    DisplayByte
3150
        setlo   r1,#'X'
3151
        call    DisplayByte
3152
        setlo   r1,#' '
3153
        call    DisplayByte
3154
        setlo   r1,#'X'
3155
        call    DisplayByte
3156
        setlo   r1,#' '
3157
        call    DisplayByte
3158
dinv1:
3159
        lm              [sp],r1/r2/r3/r4/lr
3160
        ret             #40
3161
DrawBombs:
3162
        ret
3163
 
3164
Invaders:
3165
        subui   sp,#240
3166
        sm              [sp],r1/r2/r3/r4/lr
3167
        call    InitializeGame
3168
InvadersLoop:
3169
        call    DrawScore
3170
        call    DrawInvaders
3171
        call    DrawBombs
3172
        call    DrawMissile
3173
        call    DrawMan
3174
TestMoveMan:
3175
        call    KeybdGetChar
3176
        beqi    r1,#'k',MoveManRight
3177
        beqi    r1,#'j',MoveManLeft
3178
        beqi    r1,#' ',FireMissile
3179
        bra             Invaders1
3180
MoveManRight:
3181
        lc              r2,Manpos
3182
        bgtu    r2,#640,Invaders1
3183
        addui   r2,r2,#8
3184
        sc              r2,Manpos
3185
        bra             Invaders1
3186
MoveManLeft:
3187
        lc              r2,Manpos
3188
        ble             r2,r0,Invaders1
3189
        subui   r2,r2,#8
3190
        sc              r2,Manpos
3191
        bra             Invaders1
3192
FireMissile:
3193
        lb              r2,MissileActive
3194
        bne             r2,r0,Invaders1
3195
        setlo   r2,#1
3196
        sb              r2,MissileActive
3197
        lc              r2,Manpos
3198
        sc              r2,MissileX
3199
        setlo   r2,#46
3200
        sc              r2,MissileY
3201
        bra             Invaders1
3202
Invaders1:
3203
        beqi    r1,#CTRLC,InvadersEnd
3204
        bra             InvadersLoop
3205
InvadersEnd:
3206
        lm              [sp],r1/r2/r3/r4/lr
3207
        addui   sp,sp,#240
3208
        bra             Monitor
3209
 
3210
;==============================================================================
3211
;==============================================================================
3212 46 robfinch
;
3213
; Initialize the SD card
3214
; Returns
3215
; r = 0 if successful, 1 otherwise
3216
;
3217
spi_init:
3218
        subui   sp,sp,#24
3219
        sw              lr,[sp]
3220
        sw              r2,8[sp]
3221
        sw              r3,16[sp]
3222
        lea             r3,SPIMASTER
3223
        lw              r1,#SPI_INIT_SD
3224
        outb    r1,SPI_TRANS_TYPE_REG[r3]
3225
        lw              r1,#SPI_TRANS_START
3226
        outb    r1,SPI_TRANS_CTRL_REG[r3]
3227
        nop
3228
spi_init1:
3229
        inb             r1,SPI_TRANS_STATUS_REG[r3]
3230
        mov             r2,r1                                                   ; note: some time needs to be wasted
3231
        mov             r1,r2                                                   ; between status reads.
3232
        beqi    r1,#SPI_TRANS_BUSY,spi_init1
3233
        inb             r1,SPI_TRANS_ERROR_REG[r3]
3234
        bfext   r1,r1,#1,#0
3235
        bne             r1,#SPI_INIT_NO_ERROR,spi_error
3236
        lea             r1,spi_init_ok_msg
3237
        call    DisplayString
3238
        xor             r1,r1,r1
3239
        bra             spi_init_exit
3240
spi_error:
3241
        call    DisplayByte
3242
        lea             r1,spi_init_error_msg
3243
        call    DisplayString
3244
        lw              r1,#1
3245
spi_init_exit:
3246
        lw              lr,[sp]
3247
        lw              r2,8[sp]
3248
        lw              r3,16[sp]
3249
        ret             #24
3250
 
3251
 
3252
; SPI read sector
3253
;
3254
; r1= sector number to read
3255
; r2= address to place read data
3256
; Returns:
3257
; r1 = 0 if successful
3258
;
3259
spi_read_sector:
3260
        subui   sp,sp,#40
3261
        sw              lr,[sp]
3262
        sw              r5,8[sp]
3263
        sw              r2,16[sp]
3264
        sw              r3,24[sp]
3265
        sw              r4,32[sp]
3266
        lea             r3,SPIMASTER
3267
 
3268
        ; spi master wants a byte address, so we multiply the sector number
3269
        ; by 512.
3270
        shlui   r1,r1,#9
3271
        outb    r1,SPI_SD_ADDR_7_0_REG[r3]
3272
        shrui   r1,r1,#8
3273
        outb    r1,SPI_SD_ADDR_15_8_REG[r3]
3274
        shrui   r1,r1,#8
3275
        outb    r1,SPI_SD_ADDR_23_16_REG[r3]
3276
        shrui   r1,r1,#8
3277
        outb    r1,SPI_SD_ADDR_31_24_REG[r3]
3278
 
3279
        ; Force the reciever fifo to be empty, in case a prior error leaves it
3280
        ; in an unknown state.
3281
        lw              r1,#1
3282
        outb    r1,SPI_RX_FIFO_CTRL_REG[r3]
3283
 
3284
        lw              r1,#RW_READ_SD_BLOCK
3285
        outb    r1,SPI_TRANS_TYPE_REG[r3]
3286
        lw              r1,#SPI_TRANS_START
3287
        outb    r1,SPI_TRANS_CTRL_REG[r3]
3288
        nop
3289
spi_read_sect1:
3290
        inb             r1,SPI_TRANS_STATUS_REG[r3]
3291
        mov             r4,r1                                                   ; just a delay between consecutive status reg reads
3292
        mov             r1,r4
3293
        beqi    r1,#SPI_TRANS_BUSY,spi_read_sect1
3294
        inb             r1,SPI_TRANS_ERROR_REG[r3]
3295
        bfext   r1,r1,#3,#2
3296
        bnei    r1,#SPI_READ_NO_ERROR,spi_read_error
3297
        lw              r4,#512         ; read 512 bytes from fifo
3298
spi_read_sect2:
3299
        inb             r1,SPI_RX_FIFO_DATA_REG[r3]
3300
        sb              r1,[r2]
3301
        addui   r2,r2,#1
3302
        loop    r4,spi_read_sect2
3303
        xor             r1,r1,r1
3304
        bra             spi_read_ret
3305
spi_read_error:
3306
        call    DisplayByte
3307
        lea             r1,spi_read_error_msg
3308
        call    DisplayString
3309
        lw              r1,#1
3310
spi_read_ret:
3311
        lw              lr,[sp]
3312
        lw              r5,8[sp]
3313
        lw              r2,16[sp]
3314
        lw              r3,24[sp]
3315
        lw              r4,32[sp]
3316
        ret             #40
3317
 
3318
; Read the boot sector from the disk.
3319
; Must find it first by looking for the signature bytes 'EB' and '55AA'.
3320
;
3321
spi_read_boot:
3322
        subui   sp,sp,#32
3323
        sw              lr,[sp]
3324
        sw              r2,8[sp]
3325
        sw              r3,16[sp]
3326
        sw              r5,24[sp]
3327
        sw              r0,startSector                                  ; default starting sector
3328
        lw              r3,#500 ;1934720                                                ; number of sectors to read (up to 1GB)
3329
        lw              r5,#0                                                    ; r5 = starting address
3330
spi_read_boot1:
3331
        mov             r1,r5                                                   ; r1 = sector number
3332
        lw              r2,#8                                                   ; eight digits
3333
        sb              r0,CursorCol
3334
        call    DisplayNum                                              ; Display the sector number being checked
3335
        mov             r1,r5                                                   ; r1 = sector number
3336
        lw              r2,#0x100800000                                 ; r2 = target address
3337
        call    spi_read_sector
3338
 
3339
; The following displays the contents of the sector
3340
;       lw              r1,#0x10
3341
;       lw              r2,#0x3800
3342
;spi_read_boot5:
3343
;       call    DisplayMemB
3344
;       loop    r1,spi_read_boot5
3345
 
3346
        addui   r5,r5,#1                                                ; move to next sector
3347
        lbu             r1,0x100800000
3348
        cmpui   r2,r1,#0xEB
3349
        beq             r2,r0,spi_read_boot2
3350
spi_read_boot3:
3351
        loop    r3,spi_read_boot1
3352
        lw              r1,#1                                                   ; r1 = 1 for error
3353
        bra             spi_read_boot4
3354
spi_read_boot2:
3355
        lea             r1,msgFoundEB
3356
        call    DisplayString
3357
        lbu             r1,0x1008001FE                                  ; check for 0x55AA signature
3358
        bnei    r1,#0x55,spi_read_boot3
3359
        lbu             r1,0x1008001FF
3360
        bnei    r1,#0xAA,spi_read_boot3
3361
        subui   r1,r5,#1
3362
        sw              r1,startSector
3363
        xor             r1,r1,r1                                                ; r1 = 0, for okay status
3364
spi_read_boot4:
3365
        lw              lr,[sp]
3366
        lw              r2,8[sp]
3367
        lw              r3,16[sp]
3368
        lw              r5,24[sp]
3369
        ret             #32
3370
 
3371
msgFoundEB:
3372
        db      "Found EB code.",CR,LF,0
3373
        .align 4
3374
 
3375
; Load the FAT tables into memory
3376
;
3377
loadFAT:
3378
        subui   sp,sp,#8
3379
        sw              lr,[sp]
3380
        lcu             r3,0x100800016                                  ; sectors per FAT
3381
        lbu             r2,0x100800010                                  ; number of FATs
3382
        mulu    r3,r3,r2                                                ; offset
3383
        lea             r2,0x100800200                                  ; where to place FAT
3384
        lcu             r5,0x10080000E                                  ; r5 = # reserved sectors before FAT
3385
        lw              r6,startSector
3386
        addu    r5,r5,r6
3387
loadFAT1:
3388
        mov             r1,r5                                                   ; r1 = sector #
3389
        call    spi_read_sector
3390
        addui   r5,r5,#1
3391
        addui   r2,r2,#512                                              ; advance 512 bytes
3392
        loop    r3,loadFAT1
3393
        lw              lr,[sp]
3394
        ret             #8
3395
 
3396
; Load the root directory from disk
3397
; r2 = where to place root directory in memory
3398
;
3399
loadRootDirectory:
3400
        lcu             r3,0x100800016                                  ; sectors per FAT
3401
        lbu             r4,0x100800010                                  ; number of FATs
3402
        mulu    r3,r3,r4                                                ; offset
3403
        lcu             r4,0x10080000E                                  ; r2 = # reserved sectors before FAT
3404
        addu    r3,r3,r4                                                ; r3 = root directory sector number
3405
        lw              r6,startSector
3406
        addu    r5,r3,r6                                                ; r5 = root directory sector number
3407
        ; we have to use two byte loads here because the number is at an unaligned data address
3408
        lbu             r7,0x100800011                                  ; r7 <= number of root directory entries
3409
        lbu             r8,0x100800012
3410
        shlui   r8,r8,#8
3411
        or              r7,r7,r8
3412
        mov             r8,r7                                                   ; r8 = number of root directory entries
3413
        shlui   r7,r7,#5                                                ; r7 *=32 = size of root directory table (bytes)
3414
        shrui   r7,r7,#9                                                ; r7 /= 512 = number of sectors in root directory
3415
        mov             r3,r7
3416
loadRootDir1:
3417
        mov             r1,r5
3418
        call    spi_read_sector
3419
        addui   r5,r5,#1
3420
        addui   r2,r2,#512
3421
        loop    r3,loadRootDir1
3422
 
3423
loadBootFile:
3424
        ; For now we cheat and just go directly to sector 512.
3425
        bra             loadBootFileTmp
3426
 
3427
        lcu             r3,0x100800016                                  ; sectors per FAT
3428
        lbu             r2,0x100800010                                  ; number of FATs
3429
        mulu    r3,r3,r2                                                ; offset
3430
        lcu             r2,0x10080000E                                  ; r2 = # reserved sectors before FAT
3431
        addu    r3,r3,r2                                                ; r3 = root directory sector number
3432
        ; we have to use two byte loads here because the number is at an unaligned data address
3433
        lbu             r7,0x100800011                                  ; r7 <= number of root directory entries
3434
        lbu             r8,0x100800012
3435
        shlui   r8,r8,#8
3436
        or              r7,r7,r8
3437
        mov             r8,r7                                                   ; r8 = number of root directory entries
3438
        shlui   r7,r7,#5                                                ; r7 *=32 = size of root directory table (bytes)
3439
        shrui   r7,r7,#9                                                ; r7 /= 512 = number of sectors in root directory
3440
 
3441
; now we need to fetch the sectors of the root directory and put them somewhere in
3442
; memory
3443
;
3444
loadBootFile4:
3445
        lw              r1,[r3]                                                 ; get filename
3446
        cmpui   r1,r1,#0x454C4946544F4F42               ; "BOOTFILE"
3447
        beq             r1,r0,loadBootFile5
3448
loadBootFile3:
3449
        addui   r3,r3,#32                                               ; move to next directory entry
3450
        loop    r7,loadBootFile4
3451
; boot file not found
3452
 
3453
; here we found the file in the directory
3454
;
3455
loadBootFile5:
3456
        lcu             r2,0x1a[r3]                                             ; get starting cluster
3457
        lcu             r7,0x100800011                                  ; r7 = number of root directory entries
3458
        shlui   r7,r7,#5                                                ; r7 *=32 = size of root directory table (bytes)
3459
        shrui   r7,r7,#9                                                ; r7 /= 512 = number of sectors in root directory
3460
 
3461
loadBootFileTmp:
3462
        ; We load the number of sectors per cluster, then load a single cluster of the file.
3463
        ; This is 16kib
3464
        lbu             r3,0x10080000D                                  ; sectors per cluster
3465
        lea             r2,0x100800200                                  ; where to place FAT in memory
3466
        lw              r5,startSector                                  ; r5=start sector of disk
3467
        addui   r5,r5,#512                                              ; r5= sector 512
3468
loadBootFile1:
3469
        mov             r1,r5                                                   ; r1=sector to read
3470
        call    spi_read_sector
3471
        addui   r5,r5,#1                                                ; r5 = next sector
3472
        addui   r2,r2,#512
3473
        loop    r3,loadBootFile1
3474
        lhu             r1,0x100800200                                  ; make sure it's bootable
3475
        bnei    r1,#0x544F4F42,loadBootFile2
3476
        lw              r1,#0x16
3477
        lea             r1,msgJumpingToBoot
3478
        call    DisplayString
3479
        lw              r1,#0x100800204
3480
        jal             lr,[r1]
3481
        jmp             Monitor
3482
loadBootFile2:
3483
        lea             r1,msgNotBootable
3484
        call    DisplayString
3485
        jmp             Monitor
3486
 
3487
msgJumpingToBoot:
3488
        db      "Jumping to boot",0
3489
msgNotBootable:
3490
        db      "SD card not bootable.",0
3491
spi_init_ok_msg:
3492
        db "SD card initialized okay.",0
3493
spi_init_error_msg:
3494
        db      ": error occurred initializing the SD card.",0
3495
spi_boot_error_msg:
3496
        db      "SD card boot error",0
3497
spi_read_error_msg:
3498
        db      "SD card read error",0
3499
 
3500
        .align  4
3501
 
3502
;==============================================================================
3503
; Ethernet
3504
;==============================================================================
3505
my_MAC1 EQU     0x00
3506
my_MAC2 EQU     0xFF
3507
my_MAC3 EQU     0xEE
3508
my_MAC4 EQU     0xF0
3509
my_MAC5 EQU     0xDA
3510
my_MAC6 EQU     0x42
3511
 
3512
        .bss
3513
eth_unique_id   dw              0
3514
 
3515
        .code
3516
 
3517
; Initialize the ethmac controller.
3518
; Supply a MAC address, set MD clock
3519
;
3520
eth_init:
3521
        lea             r3,ETHMAC
3522
        lw              r1,#0x64                        ; 100
3523
        sh              r1,MIIMODER[r3]
3524
        lw              r1,#7                           ; PHY address
3525
        sh              r1,MIIADDRESS[r3]
3526
        lw              r1,#0xEEF0DA42
3527
        sh              r1,0x40[r3]                     ; MAC0
3528
        lw              r1,#0x00FF
3529
        sh              r1,0x44[r3]                     ; MAC1
3530
        ret
3531
 
3532
; Request a packet and display on screen
3533
; r1 = address where to put packet
3534
;
3535
eth_request_packet:
3536
        subui   sp,sp,#24
3537
        sw              r3,[sp]
3538
        sw              r2,8[sp]
3539
        sw              r4,16[sp]
3540
        lea             r3,ETHMAC
3541
        lw              r2,#4                           ; clear rx interrupt
3542
        sh              r2,4[r3]
3543
        sh              r1,0x604[r3]            ; storage address
3544
        lw              r2,#0xe000                      ; enable interrupt
3545
        sh              r2,0x600[r3]
3546
eth1:
3547
        nop
3548
        inh             r2,4[r3]
3549
        bfext   r2,r2,#2,#2                     ; get bit #2
3550
        beq             r2,r0,eth1
3551
        inh             r2,0x600[r3]            ; get from descriptor
3552
        shrui   r2,r2,#16
3553
        lw              r3,#0
3554
        lea             r4,TEXTSCR+7560         ; second last line of screen
3555
eth20:
3556
        lbu             r2,[r1+r3]                      ; get byte
3557
        sc              r2,[r4+r3*2]            ; store to screen
3558
        addui   r3,r3,#1
3559
        cmpui   r2,r3,#83
3560
        bne             r2,r0,eth20
3561
        lw              r3,[sp]
3562
        lw              r2,8[sp]
3563
        lw              r4,16[sp]
3564
        ret             #24
3565
 
3566
; r1 = packet address
3567
;
3568
eth_interpret_packet:
3569
        subui   sp,sp,#16
3570
        sw              r3,[sp]
3571
        sw              r2,8[sp]
3572
        lbu             r2,12[r1]
3573
        lbu             r3,13[r1]
3574
        bnei    r2,#8,eth2                      ; 0x806 ?
3575
        bnei    r3,#6,eth2
3576
        lw              r1,#2                           ; return r1 = 2 for ARP
3577
eth5:
3578
        lw              r3,[sp]
3579
        lw              r2,8[sp]
3580
        ret             #16
3581
eth2:
3582
        bnei    r2,#8,eth3                      ; 0x800 ?
3583
        bnei    r3,#0,eth3
3584
        lbu             r2,23[r1]
3585
        bnei    r2,#1,eth4
3586
        lw              r1,#1
3587
        bra             eth5                            ; return 1 ICMP
3588
eth4:
3589
        bnei    r2,#0x11,eth6
3590
        lw              r1,#3                           ; return 3 for UDP
3591
        bra             eth5
3592
eth6:
3593
        bnei    r2,#6,eth7
3594
        lw              r1,#4                           ; return 4 for TCP
3595
        bra             eth5
3596
eth7:
3597
eth3:
3598
        xor             r1,r1,r1                        ; return zero for unknown
3599
        lw              r3,[sp]
3600
        lw              r2,8[sp]
3601
        ret             #16
3602
 
3603
; r1 = address of packet to send
3604
; r2 = packet length
3605
;
3606
eth_send_packet:
3607
        subui   sp,sp,#16
3608
        sw              r3,[sp]
3609
        sw              r4,8[sp]
3610
        lea             r3,ETHMAC
3611
        ; wait for tx buffer to be clear
3612
eth8:
3613
        inh             r4,0x400[r3]
3614
        bfext   r4,r4,#15,#15
3615
        beqi    r4,#1,eth8
3616
        lw              r4,#1                   ; clear tx interrupt
3617
        sh              r4,4[r3]
3618
        ; set address
3619
        sh              r1,0x404[r3]
3620
        ; set the packet length field and enable interrupts
3621
        shlui   r2,r2,#16
3622
        ori             r2,r2,#0xF000
3623
        sh              r2,0x400[r3]
3624
        lw              r4,8[sp]
3625
        lw              r3,[sp]
3626
        ret             #16
3627
 
3628
; Only for IP type packets (not ARP)
3629
; r1 = rx buffer address
3630
; r2 = swap flag
3631
; Returns:
3632
; r1 = data start index
3633
;
3634
eth_build_packet:
3635
        subui   sp,sp,#64
3636
        sw              r3,[sp]
3637
        sw              r4,8[sp]
3638
        sw              r5,16[sp]
3639
        sw              r6,24[sp]
3640
        sw              r7,32[sp]
3641
        sw              r8,40[sp]
3642
        sw              r9,48[sp]
3643
        sw              r10,56[sp]
3644
        lbu             r3,6[r1]
3645
        lbu             r4,7[r1]
3646
        lbu             r5,8[r1]
3647
        lbu             r6,9[r1]
3648
        lbu             r7,10[r1]
3649
        lbu             r8,11[r1]
3650
        ; write to destination header
3651
        sb              r3,[r1]
3652
        sb              r4,1[r1]
3653
        sb              r5,2[r1]
3654
        sb              r6,3[r1]
3655
        sb              r7,4[r1]
3656
        sb              r8,5[r1]
3657
        ; write to source header
3658
        lw              r3,#my_MAC1
3659
        sb              r3,6[r1]
3660
        lw              r3,#my_MAC2
3661
        sb              r3,7[r1]
3662
        lw              r3,#my_MAC3
3663
        sb              r3,8[r1]
3664
        lw              r3,#my_MAC4
3665
        sb              r3,9[r1]
3666
        lw              r3,#my_MAC5
3667
        sb              r3,10[r1]
3668
        lw              r3,#my_MAC6
3669
        sb              r3,11[r1]
3670
        bnei    r2,#1,eth16                     // if (swap)
3671
        lbu             r3,26[r1]
3672
        lbu             r4,27[r1]
3673
        lbu             r5,28[r1]
3674
        lbu             r6,29[r1]
3675
        ; read destination
3676
        lbu             r7,30[r1]
3677
        lbu             r8,31[r1]
3678
        lbu             r9,32[r1]
3679
        lbu             r10,33[r1]
3680
        ; write to sender
3681
        sb              r7,26[r1]
3682
        sb              r8,27[r1]
3683
        sb              r9,28[r1]
3684
        sb              r10,29[r1]
3685
        ; write destination
3686
        sb              r3,30[r1]
3687
        sb              r4,31[r1]
3688
        sb              r5,32[r1]
3689
        sb              r6,33[r1]
3690
eth16:
3691
        lw              r3,eth_unique_id
3692
        addui   r3,r3,#1
3693
        sw              r3,eth_unique_id
3694
        sb              r3,19[r1]
3695
        shrui   r3,r3,#8
3696
        sb              r3,18[r1]
3697
        lbu             r3,14[r1]
3698
        andi    r3,r3,#0xF
3699
        shlui   r3,r3,#2                ; *4
3700
        addui   r1,r3,#14               ; return datastart in r1
3701
        lw              r3,[sp]
3702
        lw              r4,8[sp]
3703
        lw              r5,16[sp]
3704
        lw              r6,24[sp]
3705
        lw              r7,32[sp]
3706
        lw              r8,40[sp]
3707
        lw              r9,48[sp]
3708
        lw              r10,56[sp]
3709
        ret             #64
3710
 
3711
; Compute IPv4 checksum of header
3712
; r1 = packet address
3713
; r2 = data start
3714
;
3715
eth_checksum:
3716
        subui   sp,sp,#24
3717
        sw              r3,[sp]
3718
        sw              r4,8[sp]
3719
        sw              r5,16[sp]
3720
        ; set checksum to zero
3721
        sb              r0,24[r1]
3722
        sb              r0,25[r1]
3723
        xor             r3,r3,r3                ; r3 = sum = zero
3724
        lw              r4,#14
3725
eth15:
3726
        mov             r5,r2
3727
        subui   r5,r5,#1                ; r5 = datastart - 1
3728
        bge             r4,r5,eth14
3729
        lbu             r5,[r1+r4]              ; shi = [rx_addr+i]
3730
        lbu             r6,1[r1+r4]             ; slo = [rx_addr+i+1]
3731
        shlui   r5,r5,#8
3732
        or              r5,r5,r6                ; shilo
3733
        addu    r3,r3,r5                ; sum = sum + shilo
3734
        addui   r4,r4,#2                ; i = i + 2
3735
        bra             eth15
3736
eth14:
3737
        mov             r5,r3                   ; r5 = sum
3738
        andi    r3,r3,#0xffff
3739
        shrui   r5,r5,#16
3740
        addu    r3,r3,r5
3741
        com             r3,r3
3742
        sb              r3,25[r1]               ; low byte
3743
        shrui   r3,r3,#8
3744
        sb              r3,24[r1]               ; high byte
3745
        sw              r3,[sp]
3746
        sw              r4,8[sp]
3747
        sw              r5,16[sp]
3748
        ret             #24
3749
 
3750
; r1 = packet address
3751
; returns r1 = 1 if this IP
3752
;       
3753
eth_verifyIP:
3754
        subui   sp,sp,#32
3755
        sw              r2,[sp]
3756
        sw              r3,8[sp]
3757
        sw              r4,16[sp]
3758
        sw              r5,24[sp]
3759
        lbu             r2,30[r1]
3760
        lbu             r3,31[r1]
3761
        lbu             r4,32[r1]
3762
        lbu             r5,33[r1]
3763
        ; Check for general broadcast
3764
        bnei    r2,#0xFF,eth11
3765
        bnei    r3,#0xFF,eth11
3766
        bnei    r4,#0xFF,eth11
3767
        bnei    r5,#0xFF,eth11
3768
eth12:
3769
        lw              r1,#1
3770
eth13:
3771
        lw              r2,[sp]
3772
        lw              r3,8[sp]
3773
        lw              r4,16[sp]
3774
        lw              r5,24[sp]
3775
        ret             #32
3776
eth11:
3777
        mov             r1,r2
3778
        shlui   r1,r1,#8
3779
        or              r1,r1,r3
3780
        shlui   r1,r1,#8
3781
        or              r1,r1,r4
3782
        shlui   r1,r1,#8
3783
        or              r1,r1,r5
3784
        beqi    r1,#0xC0A8012A,eth12
3785
        xor             r1,r1,r1
3786
        bra             eth13
3787
 
3788
 
3789
eth_main:
3790
        call    eth_init
3791
eth_loop:
3792
        xor             r1,r1,r1
3793
        lw              r1,#0x1_00000000                ; memory address zero
3794
        call    eth_request_packet
3795
        call    eth_interpret_packet    ; r1 = packet type
3796
 
3797
        bnei    r1,#1,eth10
3798
        mov             r2,r1                                   ; save off r1, r2 = packet type
3799
        lw              r1,#0x1_00000000                ; memory address zero
3800
        call    eth_verifyIP
3801
        mov     r3,r1
3802
        mov     r1,r2                                   ; r1 = packet type again
3803
        bnei    r3,#1,eth10
3804
 
3805
        lw              r1,#0x1_00000000                ; memory address zero
3806
        lw              r2,#1
3807
        call    eth_build_packet
3808
        mov             r3,r1                                   ; r3 = icmpstart
3809
        lw              r1,#0x1_00000000                ; memory address zero
3810
        sb              r0,[r1+r3]                              ; [rx_addr+icmpstart] = 0
3811
        lbu             r2,17[r1]
3812
        addui   r2,r2,#14                               ; r2 = len
3813
        mov             r6,r2                                   ; r6 = len
3814
        lbu             r4,2[r1+r3]                             ; shi
3815
        lbu             r5,3[r1+r3]                             ; slo
3816
        shlui   r4,r4,#8
3817
        or              r4,r4,r5                                ; sum = {shi,slo};
3818
        com             r4,r4                                   ; sum = ~sum
3819
        subui   r4,r4,#0x800                    ; sum = sum - 0x800
3820
        com             r4,r4                                   ; sum = ~sum
3821
        sb              r4,3[r1+r3]
3822
        shrui   r4,r4,#8
3823
        sb              r4,2[r1+r3]
3824
        mov             r2,r3
3825
        call    eth_checksum
3826
        lw              r1,#0x1_00000000                ; memory address zero
3827
        mov             r2,r6
3828
        call    eth_send_packet
3829
        jmp             eth_loop
3830
eth10:
3831
        ; r2 = rx_addr
3832
        bnei    r1,#2,eth_loop          ; Do we have ARP ?
3833
;       xor             r2,r2,r2                        ; memory address zero
3834
        lw              r2,#1_00000000
3835
        ; get the opcode
3836
        lbu             r13,21[r2]
3837
        bnei    r13,#1,eth_loop         ; ARP request
3838
        ; get destination IP address
3839
        lbu             r9,38[r2]
3840
        lbu             r10,39[r2]
3841
        lbu             r11,40[r2]
3842
        lbu             r12,41[r2]
3843
        ; set r15 = destination IP
3844
        mov             r15,r9
3845
        shlui   r15,r15,#8
3846
        or              r15,r15,r10
3847
        shlui   r15,r15,#8
3848
        or              r15,r15,r11
3849
        shlui   r15,r15,#8
3850
        or              r15,r15,r12
3851
        ; Is it our IP ?
3852
        bnei    r15,#0xC0A8012A,eth_loop; //192.168.1.42
3853
        ; get source IP address
3854
        lbu             r5,28[r2]
3855
        lbu             r6,29[r2]
3856
        lbu             r7,30[r2]
3857
        lbu             r8,31[r2]
3858
        ; set r14 = source IP
3859
        mov             r14,r5
3860
        shlui   r14,r14,#8
3861
        or              r14,r14,r6
3862
        shlui   r14,r14,#8
3863
        or              r14,r14,r7
3864
        shlui   r14,r14,#8
3865
        or              r14,r14,r8
3866
        ; Get the source MAC address
3867
        lbu             r16,22[r2]
3868
        lbu             r17,23[r2]
3869
        lbu             r18,24[r2]
3870
        lbu             r19,25[r2]
3871
        lbu             r20,26[r2]
3872
        lbu             r21,27[r2]
3873
        ; write to destination header
3874
        sb              r16,[r2]
3875
        sb              r17,1[r2]
3876
        sb              r18,2[r2]
3877
        sb              r19,3[r2]
3878
        sb              r20,4[r2]
3879
        sb              r21,5[r2]
3880
        ; and write to ARP destination
3881
        sb              r16,32[r2]
3882
        sb              r17,33[r2]
3883
        sb              r18,34[r2]
3884
        sb              r19,35[r2]
3885
        sb              r20,36[r2]
3886
        sb              r21,37[r2]
3887
        ; write to source header
3888
;       stbc    #0x00,6[r2]
3889
;       stbc    #0xFF,7[r2]
3890
;       stbc    #0xEE,8[r2]
3891
;       stbc    #0xF0,9[r2]
3892
;       stbc    #0xDA,10[r2]
3893
;       stbc    #0x42,11[r2]
3894
        sb              r0,6[r2]
3895
        lw              r1,#0xFF
3896
        sb              r1,7[r2]
3897
        lw              r1,#0xEE
3898
        sb              r1,8[r2]
3899
        lw              r1,#0xF0
3900
        sb              r1,9[r2]
3901
        lw              r1,#0xDA
3902
        sb              r1,10[r2]
3903
        lw              r1,#0x42
3904
        sb              r1,11[r2]
3905
        ; write to ARP source
3906
;       stbc    #0x00,22[r2]
3907
;       stbc    #0xFF,23[r2]
3908
;       stbc    #0xEE,24[r2]
3909
;       stbc    #0xF0,25[r2]
3910
;       stbc    #0xDA,26[r2]
3911
;       stbc    #0x42,27[r2]
3912
        sb              r0,22[r2]
3913
        lw              r1,#0xFF
3914
        sb              r1,23[r2]
3915
        lw              r1,#0xEE
3916
        sb              r1,24[r2]
3917
        lw              r1,#0xF0
3918
        sb              r1,25[r2]
3919
        lw              r1,#0xDA
3920
        sb              r1,26[r2]
3921
        lw              r1,#0x42
3922
        sb              r1,27[r2]
3923
        ; swap sender / destination IP
3924
        ; write sender
3925
        sb              r9,28[r2]
3926
        sb              r10,29[r2]
3927
        sb              r11,30[r2]
3928
        sb              r12,31[r2]
3929
        ; write destination
3930
        sb              r5,38[r2]
3931
        sb              r6,39[r2]
3932
        sb              r7,40[r2]
3933
        sb              r8,41[r2]
3934
        ; change request to reply
3935
;       stbc    #2,21[r2]
3936
        lw              r1,#2
3937
        sb              r1,21[r2]
3938
        mov             r1,r2                   ; r1 = packet address
3939
        lw              r2,#0x2A                ; r2 = packet length
3940
        call    eth_send_packet
3941
        jmp             eth_loop
3942
 
3943
 
3944
;==============================================================================
3945
;==============================================================================
3946 43 robfinch
;****************************************************************;
3947
;                                                                ;
3948
;               Tiny BASIC for the Raptor64                              ;
3949
;                                                                ;
3950
; Derived from a 68000 derivative of Palo Alto Tiny BASIC as     ;
3951
; published in the May 1976 issue of Dr. Dobb's Journal.         ;
3952
; Adapted to the 68000 by:                                       ;
3953
;       Gordon brndly                                                                    ;
3954
;       12147 - 51 Street                                                                ;
3955
;       Edmonton AB  T5W 3G8                                                         ;
3956
;       Canada                                                                               ;
3957
;       (updated mailing address for 1996)                                       ;
3958
;                                                                ;
3959
; Adapted to the Raptor64 by:                                    ;
3960
;    Robert Finch                                                ;
3961
;    Ontario, Canada                                             ;
3962
;        robfinch<remove>@opencores.org                              ;  
3963
;****************************************************************;
3964
;    Copyright (C) 2012 by Robert Finch. This program may be     ;
3965
;    freely distributed for personal use only. All commercial    ;
3966
;                      rights are reserved.                                          ;
3967
;****************************************************************;
3968
;
3969
; Register Usage
3970
; r8 = text pointer (global usage)
3971
; r3,r4 = inputs parameters to subroutines
3972
; r2 = return value
3973
;
3974
;* Vers. 1.0  1984/7/17 - Original version by Gordon brndly
3975
;*      1.1  1984/12/9  - Addition of '0x' print term by Marvin Lipford
3976
;*      1.2  1985/4/9   - Bug fix in multiply routine by Rick Murray
3977
 
3978
;
3979
; Standard jump table. You can change these addresses if you are
3980
; customizing this interpreter for a different environment.
3981
;
3982
GOSTART:
3983
                jmp     CSTART  ;       Cold Start entry point
3984
GOWARM:
3985
                jmp     WSTART  ;       Warm Start entry point
3986
GOOUT:
3987
                jmp     OUTC    ;       Jump to character-out routine
3988
GOIN:
3989
                jmp     INC             ;Jump to character-in routine
3990
GOAUXO:
3991
                jmp     AUXOUT  ;       Jump to auxiliary-out routine
3992
GOAUXI:
3993
                jmp     AUXIN   ;       Jump to auxiliary-in routine
3994
GOBYE:
3995
                jmp     BYEBYE  ;       Jump to monitor, DOS, etc.
3996
;
3997
; Modifiable system constants:
3998
;
3999
                align   8
4000
TXTBGN  dw      0x000000001_00600000    ;TXT            ;beginning of program memory
4001
ENDMEM  dw      0x000000001_07FFFFF8    ;       end of available memory
4002
;
4003
; The main interpreter starts here:
4004
;
4005
; Usage
4006
; r1 = temp
4007
; r8 = text buffer pointer
4008
; r12 = end of text in text buffer
4009
;
4010
        align   16
4011
CSTART:
4012
        ; First save off the link register and OS sp value
4013
        subui   sp,sp,#8
4014
        sw              lr,[sp]
4015
        sw              sp,OSSP
4016
        lw              sp,ENDMEM       ; initialize stack pointer
4017
        subui   sp,sp,#8
4018
        sw      lr,[sp]    ; save off return address
4019 46 robfinch
        sb              r0,CursorRow    ; set screen output
4020
        sb              r0,CursorCol
4021 43 robfinch
        sb              r0,CursorFlash
4022 46 robfinch
        sh              r0,pos
4023 43 robfinch
        lw              r2,#0x10000020  ; black chars, yellow background
4024 46 robfinch
;       sh              r2,charToPrint
4025 43 robfinch
        call    ClearScreen
4026
        lea             r1,msgInit      ;       tell who we are
4027 46 robfinch
;       call    PRMESGAUX
4028 43 robfinch
        lea             r1,msgInit      ;       tell who we are
4029
        call    PRMESG
4030
        lw              r1,TXTBGN       ;       init. end-of-program pointer
4031
        sw              r1,TXTUNF
4032
        lw              r1,ENDMEM       ;       get address of end of memory
4033 46 robfinch
        subui   r1,r1,#4096     ;       reserve 4K for the stack
4034 43 robfinch
        sw              r1,STKBOT
4035 46 robfinch
        subui   r1,r1,#16384 ;   1000 vars
4036 43 robfinch
        sw      r1,VARBGN
4037
        call    clearVars   ; clear the variable area
4038
        lw      r1,VARBGN   ; calculate number of bytes free
4039
        lw              r3,TXTUNF
4040 46 robfinch
        subu    r1,r1,r3
4041 43 robfinch
        setlo   r2,#0
4042
        call    PRTNUM
4043
        lea             r1,msgBytesFree
4044
        call    PRMESG
4045
WSTART:
4046
        sw              r0,LOPVAR   ; initialize internal variables
4047
        sw              r0,STKGOS
4048
        sw              r0,CURRNT       ;       current line number pointer = 0
4049
        lw              sp,ENDMEM       ;       init S.P. again, just in case
4050
        lea             r1,msgReady     ;       display "Ready"
4051
        call    PRMESG
4052
ST3:
4053
        setlo   r1,#'>'         ; Prompt with a '>' and
4054
        call    GETLN           ; read a line.
4055
        call    TOUPBUF         ; convert to upper case
4056
        mov             r12,r8          ; save pointer to end of line
4057
        lea             r8,BUFFER       ; point to the beginning of line
4058
        call    TSTNUM          ; is there a number there?
4059
        call    IGNBLK          ; skip trailing blanks
4060
; does line no. exist? (or nonzero?)
4061
        beq             r1,r0,DIRECT            ; if not, it's a direct statement
4062
        bleu    r1,#0xFFFF,ST2  ; see if line no. is <= 16 bits
4063
        lea             r1,msgLineRange ; if not, we've overflowed
4064
        bra             ERROR
4065
ST2:
4066
    ; ugliness - store a character at potentially an
4067
    ; odd address (unaligned).
4068
        mov             r2,r1       ; r2 = line number
4069
        sb              r2,-2[r8]
4070
        shrui   r2,r2,#8
4071
        sb              r2,-1[r8]       ; store the binary line no.
4072
        subui   r8,r8,#2
4073
        call    FNDLN           ; find this line in save area
4074
        mov             r13,r9          ; save possible line pointer
4075
        beq             r1,r0,ST4       ; if not found, insert
4076
        ; here we found the line, so we're replacing the line
4077
        ; in the text area
4078
        ; first step - delete the line
4079
        setlo   r1,#0
4080
        call    FNDNXT          ; find the next line (into r9)
4081
        bne             r1,r0,ST7
4082
        beq             r9,r0,ST6       ; no more lines
4083
ST7:
4084
        mov             r1,r9           ; r1 = pointer to next line
4085
        mov             r2,r13          ; pointer to line to be deleted
4086
        lw              r3,TXTUNF       ; points to top of save area
4087
        call    MVUP            ; move up to delete
4088
        sw              r2,TXTUNF       ; update the end pointer
4089
        ; we moved the lines of text after the line being
4090
        ; deleted down, so the pointer to the next line
4091
        ; needs to be reset
4092
        mov             r9,r13
4093
        bra             ST4
4094
        ; here there were no more lines, so just move the
4095
        ; end of text pointer down
4096
ST6:
4097
        sw              r13,TXTUNF
4098
        mov             r9,r13
4099
ST4:
4100
        ; here we're inserting because the line wasn't found
4101
        ; or it was deleted     from the text area
4102
        mov             r1,r12          ; calculate the length of new line
4103
        sub             r1,r1,r8
4104
        blei    r1,#3,ST3       ; is it just a line no. & CR? if so, it was just a delete
4105
 
4106
        lw              r11,TXTUNF      ; compute new end of text
4107
        mov             r10,r11         ; r10 = old TXTUNF
4108
        add             r11,r11,r1              ; r11 = new top of TXTUNF (r1=line length)
4109
 
4110
        lw              r1,VARBGN       ; see if there's enough room
4111
        bltu    r11,r1,ST5
4112
        lea             r1,msgTooBig    ; if not, say so
4113
        jmp             ERROR
4114
 
4115
        ; open a space in the text area
4116
ST5:
4117
        sw              r11,TXTUNF      ; if so, store new end position
4118
        mov             r1,r10          ; points to old end of text
4119
        mov             r2,r11          ; points to new end of text
4120
        mov             r3,r9       ; points to start of line after insert line
4121
        call    MVDOWN          ; move things out of the way
4122
 
4123
        ; copy line into text space
4124
        mov             r1,r8           ; set up to do the insertion; move from buffer
4125
        mov             r2,r13          ; to vacated space
4126
        mov             r3,r12          ; until end of buffer
4127
        call    MVUP            ; do it
4128
        bra             ST3                     ; go back and get another line
4129
 
4130
;******************************************************************
4131
;
4132
; *** Tables *** DIRECT *** EXEC ***
4133
;
4134
; This section of the code tests a string against a table. When
4135
; a match is found, control is transferred to the section of
4136
; code according to the table.
4137
;
4138
; At 'EXEC', r8 should point to the string, r9 should point to
4139
; the character table, and r10 should point to the execution
4140
; table. At 'DIRECT', r8 should point to the string, r9 and
4141
; r10 will be set up to point to TAB1 and TAB1_1, which are
4142
; the tables of all direct and statement commands.
4143
;
4144
; A '.' in the string will terminate the test and the partial
4145
; match will be considered as a match, e.g. 'P.', 'PR.','PRI.',
4146
; 'PRIN.', or 'PRINT' will all match 'PRINT'.
4147
;
4148
; There are two tables: the character table and the execution
4149
; table. The character table consists of any number of text items.
4150
; Each item is a string of characters with the last character's
4151
; high bit set to one. The execution table holds a 32-bit
4152
; execution addresses that correspond to each entry in the
4153
; character table.
4154
;
4155
; The end of the character table is a 0 byte which corresponds
4156
; to the default routine in the execution table, which is
4157
; executed if none of the other table items are matched.
4158
;
4159
; Character-matching tables:
4160 46 robfinch
 
4161 43 robfinch
TAB1:
4162
        db      "LIS",'T'+0x80        ; Direct commands
4163
        db      "LOA",'D'+0x80
4164
        db      "NE",'W'+0x80
4165
        db      "RU",'N'+0x80
4166
        db      "SAV",'E'+0x80
4167
TAB2:
4168
        db      "NEX",'T'+0x80         ; Direct / statement
4169
        db      "LE",'T'+0x80
4170
        db      "I",'F'+0x80
4171
        db      "GOT",'O'+0x80
4172
        db      "GOSU",'B'+0x80
4173
        db      "RETUR",'N'+0x80
4174
        db      "RE",'M'+0x80
4175
        db      "FO",'R'+0x80
4176
        db      "INPU",'T'+0x80
4177
        db      "PRIN",'T'+0x80
4178
        db      "POKE",'C'+0x80
4179
        db      "POKE",'H'+0x80
4180
        db      "POKE",'W'+0x80
4181
        db      "POK",'E'+0x80
4182
        db      "STO",'P'+0x80
4183
        db      "BY",'E'+0x80
4184
        db      "SY",'S'+0x80
4185
        db      "CL",'S'+0x80
4186
    db  "CL",'R'+0x80
4187
    db  "RDC",'F'+0x80
4188
        db      0
4189
TAB4:
4190
        db      "PEEK",'C'+0x80        ;Functions
4191
        db      "PEEK",'H'+0x80        ;Functions
4192
        db      "PEEK",'W'+0x80        ;Functions
4193
        db      "PEE",'K'+0x80         ;Functions
4194
        db      "RN",'D'+0x80
4195
        db      "AB",'S'+0x80
4196
        db      "SIZ",'E'+0x80
4197
        db  "US",'R'+0x80
4198
        db      0
4199
TAB5:
4200
        db      "T",'O'+0x80           ;"TO" in "FOR"
4201
        db      0
4202
TAB6:
4203
        db      "STE",'P'+0x80         ;"STEP" in "FOR"
4204
        db      0
4205
TAB8:
4206
        db      '>','='+0x80           ;Relational operators
4207
        db      '<','>'+0x80
4208
        db      '>'+0x80
4209
        db      '='+0x80
4210
        db      '<','='+0x80
4211
        db      '<'+0x80
4212
        db      0
4213
TAB9:
4214
    db  "AN",'D'+0x80
4215
    db  0
4216
TAB10:
4217
    db  "O",'R'+0x80
4218
    db  0
4219
 
4220
        .align  8
4221
 
4222
;* Execution address tables:
4223
TAB1_1:
4224
        dw      LISTX                   ;Direct commands
4225
        dw      LOAD
4226
        dw      NEW
4227
        dw      RUN
4228
        dw      SAVE
4229
TAB2_1:
4230
        dw      NEXT            ;       Direct / statement
4231
        dw      LET
4232
        dw      IF
4233
        dw      GOTO
4234
        dw      GOSUB
4235
        dw      RETURN
4236
        dw      IF2                     ; REM
4237
        dw      FOR
4238
        dw      INPUT
4239
        dw      PRINT
4240
        dw      POKEC
4241
        dw      POKEH
4242
        dw      POKEW
4243
        dw      POKE
4244
        dw      STOP
4245
        dw      GOBYE
4246
        dw      SYSX
4247
        dw      _cls
4248
        dw  _clr
4249
        dw      _rdcf
4250
        dw      DEFLT
4251
TAB4_1:
4252
        dw  PEEKC
4253
        dw  PEEKH
4254
        dw  PEEKW
4255
        dw      PEEK                    ;Functions
4256
        dw      RND
4257
        dw      ABS
4258
        dw      SIZEX
4259
        dw  USRX
4260
        dw      XP40
4261
TAB5_1
4262
        dw      FR1                     ;"TO" in "FOR"
4263
        dw      QWHAT
4264
TAB6_1
4265
        dw      FR2                     ;"STEP" in "FOR"
4266
        dw      FR3
4267
TAB8_1
4268
        dw      XP11    ;>=             Relational operators
4269
        dw      XP12    ;<>
4270
        dw      XP13    ;>
4271
        dw      XP15    ;=
4272
        dw      XP14    ;<=
4273
        dw      XP16    ;<
4274
        dw      XP17
4275
TAB9_1
4276
    dw  XP_AND
4277
    dw  XP_ANDX
4278
TAB10_1
4279
    dw  XP_OR
4280
    dw  XP_ORX
4281
 
4282 46 robfinch
        .align  4
4283 43 robfinch
 
4284 27 robfinch
;*
4285 43 robfinch
; r3 = match flag (trashed)
4286
; r9 = text table
4287
; r10 = exec table
4288
; r11 = trashed
4289
DIRECT:
4290
        lea             r9,TAB1
4291
        lea             r10,TAB1_1
4292
EXEC:
4293
        mov             r11,lr          ; save link reg
4294
        call    IGNBLK          ; ignore leading blanks
4295
        mov             lr,r11          ; restore link reg
4296
        mov             r11,r8          ; save the pointer
4297
        setlo   r3,#0            ; clear match flag
4298
EXLP:
4299
        lbu             r1,[r8]         ; get the program character
4300
        addui   r8,r8,#1
4301
        lbu             r2,[r9]         ; get the table character
4302
        bne             r2,r0,EXNGO             ; If end of table,
4303
        mov             r8,r11          ;       restore the text pointer and...
4304
        bra             EXGO            ;   execute the default.
4305
EXNGO:
4306
        beq             r1,r3,EXGO      ; Else check for period... if so, execute
4307
        andi    r2,r2,#0x7f     ; ignore the table's high bit
4308
        beq             r2,r1,EXMAT;            is there a match?
4309
        addui   r10,r10,#8      ;if not, try the next entry
4310
        mov             r8,r11          ; reset the program pointer
4311
        setlo   r3,#0            ; sorry, no match
4312
EX1:
4313
        addui   r9,r9,#1
4314
        lb              r1,-1[r9]       ; get to the end of the entry
4315
        bgt             r1,r0,EX1
4316
        bra             EXLP            ; back for more matching
4317
EXMAT:
4318
        setlo   r3,#'.'         ; we've got a match so far
4319
        addui   r9,r9,#1
4320
        lb              r1,-1[r9]       ; end of table entry?
4321
        bgt             r1,r0,EXLP              ; if not, go back for more
4322
EXGO:
4323
        lw              r11,[r10]       ; execute the appropriate routine
4324
        jal             r0,[r11]
4325
 
4326
;    lb      r1,[r8]     ; get token from text space
4327
;    bpl
4328
;    and     r1,#0x7f
4329
;    shl     r1,#2       ; * 4 - word offset
4330
;    add     r1,r1,#TAB1_1
4331
;    lw      r1,[r1]
4332
;    jmp     [r1]
4333
 
4334
 
4335
;******************************************************************
4336
;
4337
; What follows is the code to execute direct and statement
4338
; commands. Control is transferred to these points via the command
4339
; table lookup code of 'DIRECT' and 'EXEC' in the last section.
4340
; After the command is executed, control is transferred to other
4341
; sections as follows:
4342
;
4343
; For 'LISTX', 'NEW', and 'STOP': go back to the warm start point.
4344
; For 'RUN': go execute the first stored line if any; else go
4345
; back to the warm start point.
4346
; For 'GOTO' and 'GOSUB': go execute the target line.
4347
; For 'RETURN' and 'NEXT'; go back to saved return line.
4348
; For all others: if 'CURRNT' is 0, go to warm start; else go
4349
; execute next command. (This is done in 'FINISH'.)
4350
;
4351
;******************************************************************
4352
;
4353
; *** NEW *** STOP *** RUN (& friends) *** GOTO ***
4354
;
4355
; 'NEW<CR>' sets TXTUNF to point to TXTBGN
4356
;
4357
; 'STOP<CR>' goes back to WSTART
4358
;
4359
; 'RUN<CR>' finds the first stored line, stores its address
4360
; in CURRNT, and starts executing it. Note that only those
4361
; commands in TAB2 are legal for a stored program.
4362
;
4363
; There are 3 more entries in 'RUN':
4364
; 'RUNNXL' finds next line, stores it's address and executes it.
4365
; 'RUNTSL' stores the address of this line and executes it.
4366
; 'RUNSML' continues the execution on same line.
4367
;
4368
; 'GOTO expr<CR>' evaluates the expression, finds the target
4369
; line, and jumps to 'RUNTSL' to do it.
4370
;
4371
NEW:
4372
        call    ENDCHK
4373
        lw              r1,TXTBGN
4374
        sw              r1,TXTUNF       ;       set the end pointer
4375
        call    clearVars
4376
 
4377
STOP:
4378
        call    ENDCHK
4379
        bra             WSTART          ; WSTART will reset the stack
4380
 
4381
RUN:
4382
        call    ENDCHK
4383
        lw              r8,TXTBGN       ;       set pointer to beginning
4384
        sw              r8,CURRNT
4385
        call    clearVars
4386
 
4387
RUNNXL:                                 ; RUN <next line>
4388
        lw              r1,CURRNT       ; executing a program?
4389
        beq             r1,r0,WSTART    ; if not, we've finished a direct stat.
4390
        setlo   r1,#0        ; else find the next line number
4391
        mov             r9,r8
4392
        call    FNDLNP          ; search for the next line
4393
        bne             r1,r0,RUNTSL
4394
        bne             r9,r0,RUNTSL
4395
        bra             WSTART          ; if we've fallen off the end, stop
4396
 
4397
RUNTSL:                                 ; RUN <this line>
4398
        sw              r9,CURRNT       ; set CURRNT to point to the line no.
4399
        lea             r8,2[r9]        ; set the text pointer to
4400
 
4401
RUNSML:                 ; RUN <same line>
4402
        call    CHKIO           ; see if a control-C was pressed
4403
        lea             r9,TAB2         ; find command in TAB2
4404
        lea             r10,TAB2_1
4405
        bra             EXEC            ; and execute it
4406
 
4407
GOTO:
4408
        call    OREXPR          ;evaluate the following expression
4409
        mov     r5,r1
4410
        call    ENDCHK          ;must find end of line
4411
        mov     r1,r5
4412
        call    FNDLN           ; find the target line
4413
        bne             r1,r0,RUNTSL            ; go do it
4414
        lea             r1,msgBadGotoGosub
4415
        bra             ERROR           ; no such line no.
4416
 
4417
_clr:
4418
    call    clearVars
4419
    bra     FINISH
4420
 
4421
; Clear the variable area of memory
4422
clearVars:
4423
    subui   sp,sp,#16
4424
    sw          r6,[sp]
4425
    sw          lr,8[sp]
4426
    setlo   r6,#2048    ; number of words to clear
4427
    lw      r1,VARBGN
4428
cv1:
4429
    sw      r0,[r1]
4430
    add     r1,r1,#8
4431
    loop        r6,cv1
4432
    lw          lr,8[sp]
4433
    lw          r6,[sp]
4434
    ret         #16
4435
 
4436
 
4437
;******************************************************************
4438
; LIST
4439
;
4440
; LISTX has two forms:
4441
; 'LIST<CR>' lists all saved lines
4442
; 'LIST #<CR>' starts listing at the line #
4443
; Control-S pauses the listing, control-C stops it.
4444
;******************************************************************
4445
;
4446
LISTX:
4447
        call    TSTNUM          ; see if there's a line no.
4448
        mov     r5,r1
4449
        call    ENDCHK          ; if not, we get a zero
4450
        mov     r1,r5
4451
        call    FNDLN           ; find this or next line
4452
LS1:
4453
        bne             r1,r0,LS4
4454
        beq             r9,r0,WSTART    ; warm start if we passed the end
4455
LS4:
4456
        mov             r1,r9
4457
        call    PRTLN           ; print the line
4458
        mov             r9,r1           ; set pointer for next
4459
        call    CHKIO           ; check for listing halt request
4460
        beq             r1,r0,LS3
4461
        bnei    r1,#CTRLS,LS3   ; pause the listing?
4462
LS2:
4463
        call    CHKIO           ; if so, wait for another keypress
4464
        beq             r1,r0,LS2
4465
LS3:
4466
        setlo   r1,#0
4467
        call    FNDLNP          ; find the next line
4468
        bra             LS1
4469
 
4470
 
4471
;******************************************************************
4472
; PRINT command is 'PRINT ....:' or 'PRINT ....<CR>'
4473
; where '....' is a list of expressions, formats, back-arrows,
4474
; and strings.  These items a separated by commas.
4475
;
4476
; A format is a pound sign followed by a number.  It controls
4477
; the number of spaces the value of an expression is going to
4478
; be printed in.  It stays effective for the rest of the print
4479
; command unless changed by another format.  If no format is
4480
; specified, 11 positions will be used.
4481
;
4482
; A string is quoted in a pair of single- or double-quotes.
4483
;
4484
; An underline (back-arrow) means generate a <CR> without a <LF>
4485
;
4486
; A <CR LF> is generated after the entire list has been printed
4487
; or if the list is empty.  If the list ends with a semicolon,
4488
; however, no <CR LF> is generated.
4489
;******************************************************************
4490
;
4491
PRINT:
4492
        lw              r5,#11          ; D4 = number of print spaces
4493
        setlo   r3,#':'
4494
        lea             r4,PR2
4495
        call    TSTC            ; if null list and ":"
4496
        call    CRLF            ; give CR-LF and continue
4497
        bra             RUNSML          ;               execution on the same line
4498
PR2:
4499
        setlo   r3,#CR
4500
        lea             r4,PR0
4501
        call    TSTC            ;if null list and <CR>
4502
        call    CRLF            ;also give CR-LF and
4503
        bra             RUNNXL          ;execute the next line
4504
PR0:
4505
        setlo   r3,#'#'
4506
        lea             r4,PR1
4507
        call    TSTC            ;else is it a format?
4508
        call    OREXPR          ; yes, evaluate expression
4509
        lw              r5,r1           ; and save it as print width
4510
        bra             PR3             ; look for more to print
4511
PR1:
4512
        setlo   r3,#'$'
4513
        lea             r4,PR4
4514
        call    TSTC    ;       is character expression? (MRL)
4515
        call    OREXPR  ;       yep. Evaluate expression (MRL)
4516
        call    GOOUT   ;       print low byte (MRL)
4517
        bra             PR3             ;look for more. (MRL)
4518
PR4:
4519
        call    QTSTG   ;       is it a string?
4520
        ; the following branch must occupy only two bytes!
4521
        bra             PR8             ;       if not, must be an expression
4522
PR3:
4523
        setlo   r3,#','
4524
        lea             r4,PR6
4525
        call    TSTC    ;       if ",", go find next
4526
        call    FIN             ;in the list.
4527
        bra             PR0
4528
PR6:
4529
        call    CRLF            ;list ends here
4530
        bra             FINISH
4531
PR8:
4532
        call    OREXPR          ; evaluate the expression
4533
        lw              r2,r5           ; set the width
4534
        call    PRTNUM          ; print its value
4535
        bra             PR3                     ; more to print?
4536
 
4537
FINISH:
4538
        call    FIN             ; Check end of command
4539
        jmp             QWHAT   ; print "What?" if wrong
4540
 
4541
 
4542
;*******************************************************************
4543
;
4544
; *** GOSUB *** & RETURN ***
4545
;
4546
; 'GOSUB expr:' or 'GOSUB expr<CR>' is like the 'GOTO' command,
4547
; except that the current text pointer, stack pointer, etc. are
4548
; saved so that execution can be continued after the subroutine
4549
; 'RETURN's.  In order that 'GOSUB' can be nested (and even
4550
; recursive), the save area must be stacked.  The stack pointer
4551
; is saved in 'STKGOS'.  The old 'STKGOS' is saved on the stack.
4552
; If we are in the main routine, 'STKGOS' is zero (this was done
4553
; in the initialization section of the interpreter), but we still
4554
; save it as a flag for no further 'RETURN's.
4555
;******************************************************************
4556
;
4557
GOSUB:
4558
        call    PUSHA           ; save the current 'FOR' parameters
4559
        call    OREXPR          ; get line number
4560
        call    FNDLN           ; find the target line
4561
        bne             r1,r0,gosub1
4562
        lea             r1,msgBadGotoGosub
4563
        bra             ERROR           ; if not there, say "How?"
4564
gosub1:
4565
        sub             sp,sp,#24
4566
        sw              r8,[sp]         ; save text pointer
4567
        lw              r1,CURRNT
4568
        sw              r1,8[sp]        ; found it, save old 'CURRNT'...
4569
        lw              r1,STKGOS
4570
        sw              r1,16[sp]       ; and 'STKGOS'
4571
        sw              r0,LOPVAR       ; load new values
4572
        sw              sp,STKGOS
4573
        bra             RUNTSL
4574
 
4575
 
4576
;******************************************************************
4577
; 'RETURN<CR>' undoes everything that 'GOSUB' did, and thus
4578
; returns the execution to the command after the most recent
4579
; 'GOSUB'.  If 'STKGOS' is zero, it indicates that we never had
4580
; a 'GOSUB' and is thus an error.
4581
;******************************************************************
4582
;
4583
RETURN:
4584
        call    ENDCHK          ; there should be just a <CR>
4585
        lw              r1,STKGOS       ; get old stack pointer
4586
        bne             r1,r0,return1
4587
        lea             r1,msgRetWoGosub
4588
        bra             ERROR           ; if zero, it doesn't exist
4589
return1:
4590
        mov             sp,r1           ; else restore it
4591
        lw              r1,16[sp]
4592
        sw              r1,STKGOS       ; and the old 'STKGOS'
4593
        lw              r1,8[sp]
4594
        sw              r1,CURRNT       ; and the old 'CURRNT'
4595
        lw              r8,[sp]         ; and the old text pointer
4596
        add             sp,sp,#24
4597
        call    POPA            ;and the old 'FOR' parameters
4598
        bra             FINISH          ;and we are back home
4599
 
4600
;******************************************************************
4601
; *** FOR *** & NEXT ***
4602
;
4603
; 'FOR' has two forms:
4604
; 'FOR var=exp1 TO exp2 STEP exp1' and 'FOR var=exp1 TO exp2'
4605
; The second form means the same thing as the first form with a
4606
; STEP of positive 1.  The interpreter will find the variable 'var'
4607
; and set its value to the current value of 'exp1'.  It also
4608
; evaluates 'exp2' and 'exp1' and saves all these together with
4609
; the text pointer, etc. in the 'FOR' save area, which consists of
4610
; 'LOPVAR', 'LOPINC', 'LOPLMT', 'LOPLN', and 'LOPPT'.  If there is
4611
; already something in the save area (indicated by a non-zero
4612
; 'LOPVAR'), then the old save area is saved on the stack before
4613
; the new values are stored.  The interpreter will then dig in the
4614
; stack and find out if this same variable was used in another
4615
; currently active 'FOR' loop.  If that is the case, then the old
4616
; 'FOR' loop is deactivated. (i.e. purged from the stack)
4617
;******************************************************************
4618
;
4619
FOR:
4620
        call    PUSHA           ; save the old 'FOR' save area
4621
        call    SETVAL          ; set the control variable
4622
        sw              r1,LOPVAR       ; save its address
4623
        lea             r9,TAB5
4624
        lea             r10,TAB5_1; use 'EXEC' to test for 'TO'
4625
        jmp             EXEC
4626
FR1:
4627
        call    OREXPR          ; evaluate the limit
4628
        sw              r1,LOPLMT       ; save that
4629
        lea             r9,TAB6
4630
        lea             r10,TAB6_1      ; use 'EXEC' to test for the word 'STEP
4631
        jmp             EXEC
4632
FR2:
4633
        call    OREXPR          ; found it, get the step value
4634
        bra             FR4
4635
FR3:
4636
        setlo   r1,#1           ; not found, step defaults to 1
4637
FR4:
4638
        sw              r1,LOPINC       ; save that too
4639
FR5:
4640
        lw              r2,CURRNT
4641
        sw              r2,LOPLN        ; save address of current line number
4642
        sw              r8,LOPPT        ; and text pointer
4643
        lw              r3,sp           ; dig into the stack to find 'LOPVAR'
4644
        lw              r6,LOPVAR
4645
        bra             FR7
4646
FR6:
4647
        addui   r3,r3,#40       ; look at next stack frame
4648
FR7:
4649
        lw              r2,[r3]         ; is it zero?
4650
        beq             r2,r0,FR8       ; if so, we're done
4651
        bne             r2,r6,FR6       ; same as current LOPVAR? nope, look some more
4652
 
4653
    lw      r1,r3       ; Else remove 5 long words from...
4654
        addui   r2,r3,#40   ; inside the stack.
4655
        lw              r3,sp
4656
        call    MVDOWN
4657
        add             sp,sp,#40       ; set the SP 5 long words up
4658
FR8:
4659
    bra     FINISH              ; and continue execution
4660
 
4661
 
4662
;******************************************************************
4663
; 'NEXT var' serves as the logical (not necessarily physical) end
4664
; of the 'FOR' loop.  The control variable 'var' is checked with
4665
; the 'LOPVAR'.  If they are not the same, the interpreter digs in
4666
; the stack to find the right one and purges all those that didn't
4667
; match.  Either way, it then adds the 'STEP' to that variable and
4668
; checks the result with against the limit value.  If it is within
4669
; the limit, control loops back to the command following the
4670
; 'FOR'.  If it's outside the limit, the save area is purged and
4671
; execution continues.
4672
;******************************************************************
4673
;
4674
NEXT:
4675
        setlo   r1,#0            ; don't allocate it
4676
        call    TSTV            ; get address of variable
4677
        bne             r1,r0,NX4
4678
        lea             r1,msgNextVar
4679
        bra             ERROR           ; if no variable, say "What?"
4680
NX4:
4681
        mov             r9,r1           ; save variable's address
4682
NX0:
4683
        lw              r1,LOPVAR       ; If 'LOPVAR' is zero, we never...
4684
        bne             r1,r0,NX5   ; had a FOR loop
4685
        lea             r1,msgNextFor
4686
        bra             ERROR
4687
NX5:
4688
        beq             r1,r9,NX2       ; else we check them OK, they agree
4689
        call    POPA            ; nope, let's see the next frame
4690
        bra             NX0
4691
NX2:
4692
        lw              r1,[r9]         ; get control variable's value
4693
        lw              r2,LOPINC
4694
        addu    r1,r1,r2        ; add in loop increment
4695
;       BVS.L   QHOW            say "How?" for 32-bit overflow
4696
        sw              r1,[r9]         ; save control variable's new value
4697
        lw              r3,LOPLMT       ; get loop's limit value
4698
        bgt             r2,r0,NX1       ; check loop increment, branch if loop increment is positive
4699
        blt             r1,r3,NXPurge   ; test against limit
4700
        bra     NX3
4701
NX1:
4702
        bgt             r1,r3,NXPurge
4703
NX3:
4704
        lw              r8,LOPLN        ; Within limit, go back to the...
4705
        sw              r8,CURRNT
4706
        lw              r8,LOPPT        ; saved 'CURRNT' and text pointer.
4707
        bra             FINISH
4708
NXPurge:
4709
    call    POPA        ; purge this loop
4710
    bra     FINISH
4711
 
4712
 
4713
;******************************************************************
4714
; *** REM *** IF *** INPUT *** LET (& DEFLT) ***
4715
;
4716
; 'REM' can be followed by anything and is ignored by the
4717
; interpreter.
4718
;
4719
;REM
4720
;    br     IF2             ; skip the rest of the line
4721
; 'IF' is followed by an expression, as a condition and one or
4722
; more commands (including other 'IF's) separated by colons.
4723
; Note that the word 'THEN' is not used.  The interpreter evaluates
4724
; the expression.  If it is non-zero, execution continues.  If it
4725
; is zero, the commands that follow are ignored and execution
4726
; continues on the next line.
4727
;******************************************************************
4728
;
4729
IF:
4730
    call        OREXPR          ; evaluate the expression
4731
IF1:
4732
    bne     r1,r0,RUNSML                ; is it zero? if not, continue
4733
IF2:
4734
    mov         r9,r8           ; set lookup pointer
4735
        setlo   r1,#0            ; find line #0 (impossible)
4736
        call    FNDSKP          ; if so, skip the rest of the line
4737
        bgt             r1,r0,WSTART    ; if no next line, do a warm start
4738
IF3:
4739
        bra             RUNTSL          ; run the next line
4740
 
4741
 
4742
;******************************************************************
4743
; INPUT is called first and establishes a stack frame
4744
INPERR:
4745
        lw              sp,STKINP       ; restore the old stack pointer
4746
        lw              r8,16[sp]
4747
        sw              r8,CURRNT       ; and old 'CURRNT'
4748
        lw              r8,8[sp]        ; and old text pointer
4749
        addui   sp,sp,#40       ; fall through will subtract 40
4750
 
4751
; 'INPUT' is like the 'PRINT' command, and is followed by a list
4752
; of items.  If the item is a string in single or double quotes,
4753
; or is an underline (back arrow), it has the same effect as in
4754
; 'PRINT'.  If an item is a variable, this variable name is
4755
; printed out followed by a colon, then the interpreter waits for
4756
; an expression to be typed in.  The variable is then set to the
4757
; value of this expression.  If the variable is preceeded by a
4758
; string (again in single or double quotes), the string will be
4759
; displayed followed by a colon.  The interpreter the waits for an
4760
; expression to be entered and sets the variable equal to the
4761
; expression's value.  If the input expression is invalid, the
4762
; interpreter will print "What?", "How?", or "Sorry" and reprint
4763
; the prompt and redo the input.  The execution will not terminate
4764
; unless you press control-C.  This is handled in 'INPERR'.
4765
;
4766
INPUT:
4767
        subui   sp,sp,#40       ; allocate stack frame
4768
        sw      r5,32[sp]
4769
IP6:
4770
        sw              r8,[sp]         ; save in case of error
4771
        call    QTSTG           ; is next item a string?
4772
        bra             IP2                     ; nope - this branch must take only two bytes
4773
        setlo   r1,#1           ; allocate var
4774
        call    TSTV            ; yes, but is it followed by a variable?
4775
        beq     r1,r0,IP4   ; if not, brnch
4776
        mov             r10,r1          ; put away the variable's address
4777
        bra             IP3                     ; if so, input to variable
4778
IP2:
4779
        sw              r8,8[sp]        ; save for 'PRTSTG'
4780
        setlo   r1,#1
4781
        call    TSTV            ; must be a variable now
4782
        bne             r1,r0,IP7
4783
        lea             r1,msgInputVar
4784
        bra             ERROR           ; "What?" it isn't?
4785
IP7:
4786
        mov             r10,r1          ; put away the variable's address
4787
        lb              r5,[r8]         ; get ready for 'PRTSTG' by null terminating
4788
        sb              r0,[r8]
4789
        lw              r1,8[sp]        ; get back text pointer
4790
        call    PRTSTG          ; print string as prompt
4791
        sb              r5,[r8]         ; un-null terminate
4792
IP3
4793
        sw              r8,8[sp]        ; save in case of error
4794
        lw              r1,CURRNT
4795
        sw              r1,16[sp]       ; also save 'CURRNT'
4796
        setlo   r1,#-1
4797
        sw              r1,CURRNT       ; flag that we are in INPUT
4798
        sw              sp,STKINP       ; save the stack pointer too
4799
        sw              r10,24[sp]      ; save the variable address
4800
        setlo   r1,#':'         ; print a colon first
4801
        call    GETLN           ; then get an input line
4802
        lea             r8,BUFFER       ; point to the buffer
4803
        call    OREXPR          ; evaluate the input
4804
        lw              r10,24[sp]      ; restore the variable address
4805
        sw              r1,[r10]        ; save value in variable
4806
        lw              r1,16[sp]       ; restore old 'CURRNT'
4807
        sw              r1,CURRNT
4808
        lw              r8,8[sp]        ; and the old text pointer
4809
IP4:
4810
        setlo   r3,#','
4811
        lea             r4,IP5          ; is the next thing a comma?
4812
        call    TSTC
4813
        bra             IP6                     ; yes, more items
4814
IP5:
4815
    lw      r5,32[sp]
4816
        add             sp,sp,#40       ; clean up the stack
4817
        jmp             FINISH
4818
 
4819
 
4820
DEFLT:
4821
    lb      r1,[r8]
4822
        beq         r1,#CR,FINISH           ; empty line is OK else it is 'LET'
4823
 
4824
 
4825
;******************************************************************
4826
; 'LET' is followed by a list of items separated by commas.
4827
; Each item consists of a variable, an equals sign, and an
4828
; expression.  The interpreter evaluates the expression and sets
4829
; the variable to that value.  The interpreter will also handle
4830
; 'LET' commands without the word 'LET'.  This is done by 'DEFLT'.
4831
;******************************************************************
4832
;
4833
LET:
4834
    call        SETVAL          ; do the assignment
4835
    setlo       r3,#','
4836
    lea         r4,FINISH
4837
        call    TSTC            ; check for more 'LET' items
4838
        bra         LET
4839
LT1:
4840
    bra     FINISH              ; until we are finished.
4841
 
4842
 
4843
;******************************************************************
4844
; *** LOAD *** & SAVE ***
4845
;
4846
; These two commands transfer a program to/from an auxiliary
4847
; device such as a cassette, another computer, etc.  The program
4848
; is converted to an easily-stored format: each line starts with
4849
; a colon, the line no. as 4 hex digits, and the rest of the line.
4850
; At the end, a line starting with an '@' sign is sent.  This
4851
; format can be read back with a minimum of processing time by
4852
; the Butterfly.
4853
;******************************************************************
4854
;
4855
LOAD
4856
        lw              r8,TXTBGN       ; set pointer to start of prog. area
4857
        setlo   r1,#CR          ; For a CP/M host, tell it we're ready...
4858
        call    GOAUXO          ; by sending a CR to finish PIP command.
4859
LOD1:
4860
        call    GOAUXI          ; look for start of line
4861
        ble             r1,r0,LOD1
4862
        beq             r1,#'@',LODEND  ; end of program?
4863
        beq     r1,#0x1A,LODEND ; or EOF marker
4864
        bne             r1,#':',LOD1    ; if not, is it start of line? if not, wait for it
4865
        call    GCHAR           ; get line number
4866
        sb              r1,[r8]         ; store it
4867
        shrui   r1,r1,#8
4868
        sb              r1,1[r8]
4869
        addui   r8,r8,#2
4870
LOD2:
4871
        call    GOAUXI          ; get another text char.
4872
        ble             r1,r0,LOD2
4873
        sb              r1,[r8]
4874
        addui   r8,r8,#1        ; store it
4875
        bne             r1,#CR,LOD2             ; is it the end of the line? if not, go back for more
4876
        bra             LOD1            ; if so, start a new line
4877
LODEND:
4878
        sw              r8,TXTUNF       ; set end-of program pointer
4879
        bra             WSTART          ; back to direct mode
4880
 
4881
 
4882
; get character from input (16 bit value)
4883
GCHAR:
4884
        subui   sp,sp,#24
4885
        sw              r5,[sp]
4886
        sw              r6,8[sp]
4887
        sw              lr,16[sp]
4888
        setlo   r6,#3       ; repeat four times
4889
        setlo   r5,#0
4890
GCHAR1:
4891
        call    GOAUXI          ; get a char
4892
        ble             r1,r0,GCHAR1
4893
        call    asciiToHex
4894
        shli    r5,r5,#4
4895
        or              r5,r5,r1
4896
        loop    r6,GCHAR1
4897
        mov             r1,r5
4898
        lw              lr,16[sp]
4899
        lw              r6,8[sp]
4900
        lw              r5,[sp]
4901
        ret             #24
4902
 
4903
 
4904
; convert an ascii char to hex code
4905
; input
4906
;       r1 = char to convert
4907
 
4908
asciiToHex:
4909
        blei    r1,#'9',a2h1    ; less than '9'
4910
        subui   r1,r1,#7        ; shift 'A' to '9'+1
4911
a2h1:
4912
        subui   r1,r1,#'0'      ;
4913
        andi    r1,r1,#15       ; make sure a nybble
4914
        ret
4915
 
4916
 
4917
 
4918
SAVE:
4919
        lw              r8,TXTBGN       ;set pointer to start of prog. area
4920
        lw              r9,TXTUNF       ;set pointer to end of prog. area
4921
SAVE1:
4922
        call    AUXOCRLF    ; send out a CR & LF (CP/M likes this)
4923
        bgeu    r8,r9,SAVEND    ; are we finished?
4924
        setlo   r1,#':'         ; if not, start a line
4925
        call    GOAUXO
4926
        lbu             r1,[r8]         ; get line number
4927
        lbu             r2,1[r8]
4928
        shli    r2,r2,#8
4929
        or              r1,r1,r2
4930
        addui   r8,r8,#2
4931
        call    PWORD       ; output line number as 4-digit hex
4932
SAVE2:
4933
        lb              r1,[r8]         ; get a text char.
4934
        addui   r8,r8,#1
4935
        beqi    r1,#CR,SAVE1            ; is it the end of the line? if so, send CR & LF and start new line
4936
        call    GOAUXO          ; send it out
4937
        bra             SAVE2           ; go back for more text
4938
SAVEND:
4939
        setlo   r1,#'@'         ; send end-of-program indicator
4940
        call    GOAUXO
4941
        call    AUXOCRLF    ; followed by a CR & LF
4942
        setlo   r1,#0x1A        ; and a control-Z to end the CP/M file
4943
        call    GOAUXO
4944
        bra             WSTART          ; then go do a warm start
4945
 
4946
 
4947
; output a CR LF sequence to auxillary output
4948
; Registers Affected
4949
;   r3 = LF
4950
AUXOCRLF:
4951
    subui   sp,sp,#8
4952
    sw      lr,[sp]
4953
    setlo   r1,#CR
4954
    call    GOAUXO
4955
    setlo   r1,#LF
4956
    call    GOAUXO
4957
    lw      lr,[sp]
4958
    ret         #8
4959
 
4960
 
4961
; output a word in hex format
4962
; tricky because of the need to reverse the order of the chars
4963
PWORD:
4964
        sub             sp,sp,#16
4965
        sw              lr,[sp]
4966
        sw              r5,8[sp]
4967
        lea             r5,NUMWKA+15
4968
        mov             r4,r1           ; r4 = value
4969
pword1:
4970
    mov     r1,r4           ; r1 = value
4971
    shrui       r4,r4,#4        ; shift over to next nybble
4972
    call    toAsciiHex  ; convert LS nybble to ascii hex
4973
    sb      r1,[r5]     ; save in work area
4974
    subui   r5,r5,#1
4975
    cmpui   r1,r5,#NUMWKA
4976
    bge     r1,r0,pword1
4977
pword2:
4978
    addui   r5,r5,#1
4979
    lb      r1,[r5]     ; get char to output
4980
        call    GOAUXO          ; send it
4981
        cmpui   r1,r5,#NUMWKA+15
4982
        blt     r1,r0,pword2
4983
        lw              r5,8[sp]
4984
        lw              lr,[sp]
4985
        ret             #16
4986
 
4987
 
4988
; convert nybble in r2 to ascii hex char2
4989
; r2 = character to convert
4990
 
4991
toAsciiHex:
4992
        andi    r1,r1,#15       ; make sure it's a nybble
4993
        blti    r1,#10,tah1     ; > 10 ?
4994
        addi    r1,r1,#7        ; bump it up to the letter 'A'
4995
tah1:
4996
        addui   r1,r1,#'0'      ; bump up to ascii '0'
4997
        ret
4998
 
4999
 
5000
 
5001
;******************************************************************
5002
; *** POKE *** & SYSX ***
5003
;
5004
; 'POKE expr1,expr2' stores the byte from 'expr2' into the memory
5005
; address specified by 'expr1'.
5006
;
5007
; 'SYSX expr' jumps to the machine language subroutine whose
5008
; starting address is specified by 'expr'.  The subroutine can use
5009
; all registers but must leave the stack the way it found it.
5010
; The subroutine returns to the interpreter by executing an RET.
5011
;******************************************************************
5012
;
5013
POKE:
5014
        subui   sp,sp,#8
5015
        call    OREXPR          ; get the memory address
5016
        setlo   r3,#','
5017
        lea             r4,PKER         ; it must be followed by a comma
5018
        call    TSTC            ; it must be followed by a comma
5019
        sw              r1,[sp]     ; save the address
5020
        call    OREXPR          ; get the byte to be POKE'd
5021
        lw              r2,[sp]     ; get the address back
5022
        sb              r1,[r2]         ; store the byte in memory
5023
        addui   sp,sp,#8
5024
        bra             FINISH
5025
PKER:
5026
        lea             r1,msgComma
5027
        bra             ERROR           ; if no comma, say "What?"
5028
 
5029
POKEC:
5030
        subui   sp,sp,#8
5031
        call    OREXPR          ; get the memory address
5032
        setlo   r3,#','
5033
        lea             r4,PKER         ; it must be followed by a comma
5034
        call    TSTC            ; it must be followed by a comma
5035
        sw              r1,[sp]     ; save the address
5036
        call    OREXPR          ; get the byte to be POKE'd
5037
        lw              r2,[sp]     ; get the address back
5038
        sc              r1,[r2]         ; store the char in memory
5039
        addui   sp,sp,#8
5040
        jmp             FINISH
5041
 
5042
POKEH:
5043
        subui   sp,sp,#8
5044
        call    OREXPR          ; get the memory address
5045
        setlo   r3,#','
5046
        lea             r4,PKER         ; it must be followed by a comma
5047
        call    TSTC
5048
        sw              r1,[sp]     ; save the address
5049
        call    OREXPR          ; get the byte to be POKE'd
5050
        lw              r2,[sp]     ; get the address back
5051
        sh              r1,[r2]         ; store the word in memory
5052
        addui   sp,sp,#8
5053
        jmp             FINISH
5054
 
5055
POKEW:
5056
        subui   sp,sp,#8
5057
        call    OREXPR          ; get the memory address
5058
        setlo   r3,#','
5059
        lea             r4,PKER         ; it must be followed by a comma
5060
        call    TSTC
5061
        sw              r1,[sp]     ; save the address
5062
        call    OREXPR          ; get the word to be POKE'd
5063
        lw              r2,[sp]     ; get the address back
5064
        sw              r1,[r2]         ; store the word in memory
5065
        addui   sp,sp,#8
5066
        jmp             FINISH
5067
 
5068
SYSX:
5069
        subui   sp,sp,#8
5070
        call    OREXPR          ; get the subroutine's address
5071
        bne             r1,r0,sysx1     ; make sure we got a valid address
5072
        lea             r1,msgSYSBad
5073
        bra             ERROR
5074
sysx1:
5075
        sw              r8,[sp]     ; save the text pointer
5076
        jal             r31,[r1]        ; jump to the subroutine
5077
        lw              r8,[sp]     ; restore the text pointer
5078
        addui   sp,sp,#8
5079
        bra             FINISH
5080
 
5081
;******************************************************************
5082
; *** EXPR ***
5083
;
5084
; 'EXPR' evaluates arithmetical or logical expressions.
5085
; <OREXPR>::= <ANDEXPR> OR <ANDEXPR> ...
5086
; <ANDEXPR>::=<EXPR> AND <EXPR> ...
5087
; <EXPR>::=<EXPR2>
5088
;          <EXPR2><rel.op.><EXPR2>
5089
; where <rel.op.> is one of the operators in TAB8 and the result
5090
; of these operations is 1 if true and 0 if false.
5091
; <EXPR2>::=(+ or -)<EXPR3>(+ or -)<EXPR3>(...
5092
; where () are optional and (... are optional repeats.
5093
; <EXPR3>::=<EXPR4>( <* or /><EXPR4> )(...
5094
; <EXPR4>::=<variable>
5095
;           <function>
5096
;           (<EXPR>)
5097
; <EXPR> is recursive so that the variable '@' can have an <EXPR>
5098
; as an index, functions can have an <EXPR> as arguments, and
5099
; <EXPR4> can be an <EXPR> in parenthesis.
5100
;
5101
 
5102
; <OREXPR>::=<ANDEXPR> OR <ANDEXPR> ...
5103
;
5104
OREXPR:
5105
        subui   sp,sp,#16
5106
        sw              lr,[sp]
5107
        call    ANDEXPR         ; get first <ANDEXPR>
5108
XP_OR1:
5109
        sw              r1,4[sp]        ; save <ANDEXPR> value
5110
        lea             r9,TAB10        ; look up a logical operator
5111
        lea             r10,TAB10_1
5112
        jmp             EXEC            ; go do it
5113
XP_OR:
5114
    call    ANDEXPR
5115
    lw      r2,8[sp]
5116
    or      r1,r1,r2
5117
    bra     XP_OR1
5118
XP_ORX:
5119
        lw              r1,8[sp]
5120
    lw      lr,[sp]
5121
    ret         #16
5122
 
5123
 
5124
; <ANDEXPR>::=<EXPR> AND <EXPR> ...
5125
;
5126
ANDEXPR:
5127
        subui   sp,sp,#16
5128
        sw              lr,[sp]
5129
        call    EXPR            ; get first <EXPR>
5130
XP_AND1:
5131
        sw              r1,8[sp]        ; save <EXPR> value
5132
        lea             r9,TAB9         ; look up a logical operator
5133
        lea             r10,TAB9_1
5134
        jmp             EXEC            ; go do it
5135
XP_AND:
5136
    call    EXPR
5137
    lw      r2,8[sp]
5138
    and     r1,r1,r2
5139
    bra     XP_AND1
5140
XP_ANDX:
5141
        lw              r1,8[sp]
5142
    lw      lr,[sp]
5143
    ret         #16
5144
 
5145
 
5146
; Determine if the character is a digit
5147
;   Parameters
5148
;       r1 = char to test
5149
;   Returns
5150
;       r1 = 1 if digit, otherwise 0
5151
;
5152
isDigit:
5153
    blt     r1,#'0',isDigitFalse
5154
    bgt     r1,#'9',isDigitFalse
5155
    setlo   r1,#1
5156
    ret
5157
isDigitFalse:
5158
    setlo   r1,#0
5159
    ret
5160
 
5161
 
5162
; Determine if the character is a alphabetic
5163
;   Parameters
5164
;       r1 = char to test
5165
;   Returns
5166
;       r1 = 1 if alpha, otherwise 0
5167
;
5168
isAlpha:
5169
    blt     r1,#'A',isAlphaFalse
5170
    ble     r1,#'Z',isAlphaTrue
5171
    blt     r1,#'a',isAlphaFalse
5172
    bgt     r1,#'z',isAlphaFalse
5173
isAlphaTrue:
5174
    setlo   r1,#1
5175
    ret
5176
isAlphaFalse:
5177
    setlo   r1,#0
5178
    ret
5179
 
5180
 
5181
; Determine if the character is a alphanumeric
5182
;   Parameters
5183
;       r1 = char to test
5184
;   Returns
5185
;       r1 = 1 if alpha, otherwise 0
5186
;
5187
isAlnum:
5188
    subui   sp,sp,#8
5189
    sw      lr,[sp]
5190
    or      r2,r1,r0            ; save test char
5191
    call    isDigit
5192
    bne         r1,r0,isDigitx  ; if it is a digit
5193
    or      r1,r2,r0            ; get back test char
5194
    call    isAlpha
5195
isDigitx:
5196
    lw      lr,[sp]
5197
    ret         #8
5198
 
5199
 
5200
EXPR:
5201
        subui   sp,sp,#16
5202
        sw              lr,[sp]
5203
        call    EXPR2
5204
        sw              r1,8[sp]        ; save <EXPR2> value
5205
        lea             r9,TAB8         ; look up a relational operator
5206
        lea             r10,TAB8_1
5207
        jmp             EXEC            ; go do it
5208
XP11:
5209
        lw              r1,8[sp]
5210
        call    XP18    ; is it ">="?
5211
        bge             r2,r1,XPRT1     ; no, return r2=1
5212
        bra             XPRT0   ; else return r2=0
5213
XP12:
5214
        lw              r1,8[sp]
5215
        call    XP18    ; is it "<>"?
5216
        bne             r2,r1,XPRT1     ; no, return r2=1
5217
        bra             XPRT0   ; else return r2=0
5218
XP13:
5219
        lw              r1,8[sp]
5220
        call    XP18    ; is it ">"?
5221
        bgt             r2,r1,XPRT1     ; no, return r2=1
5222
        bra             XPRT0   ; else return r2=0
5223
XP14:
5224
        lw              r1,8[sp]
5225
        call    XP18    ; is it "<="?
5226
        ble             r2,r1,XPRT1     ; no, return r2=1
5227
        bra             XPRT0   ; else return r2=0
5228
XP15:
5229
        lw              r1,8[sp]
5230
        call    XP18    ; is it "="?
5231
        beq             r2,r1,XPRT1     ; if not, return r2=1
5232
        bra             XPRT0   ; else return r2=0
5233
XP16:
5234
        lw              r1,8[sp]
5235
        call    XP18    ; is it "<"?
5236
        blt             r2,r1,XPRT1     ; if not, return r2=1
5237
        bra             XPRT0   ; else return r2=0
5238
XPRT0:
5239
        lw              lr,[sp]
5240
        setlo   r1,#0   ; return r1=0 (false)
5241
        ret             #16
5242
XPRT1:
5243
        lw              lr,[sp]
5244
        setlo   r1,#1   ; return r1=1 (true)
5245
        ret             #16
5246
 
5247
XP17:                           ; it's not a rel. operator
5248
        lw              r1,8[sp]        ; return r2=<EXPR2>
5249
        lw              lr,[sp]
5250
        ret             #16
5251
 
5252
XP18:
5253
        subui   sp,sp,#16
5254
        sw              lr,[sp]
5255
        sw              r1,8[sp]
5256
        call    EXPR2           ; do a second <EXPR2>
5257
        lw              r2,8[sp]
5258
        lw              lr,[sp]
5259
        ret             #16
5260
 
5261
; <EXPR2>::=(+ or -)<EXPR3>(+ or -)<EXPR3>(...
5262
 
5263
EXPR2:
5264
        subui   sp,sp,#16
5265
        sw              lr,[sp]
5266
        setlo   r3,#'-'
5267
        lea             r4,XP21
5268
        call    TSTC            ; negative sign?
5269
        setlo   r1,#0            ; yes, fake '0-'
5270
        sw              r0,8[sp]
5271
        bra             XP26
5272
XP21:
5273
        setlo   r3,#'+'
5274
        lea             r4,XP22
5275
        call    TSTC            ; positive sign? ignore it
5276
XP22:
5277
        call    EXPR3           ; first <EXPR3>
5278
XP23:
5279
        sw              r1,8[sp]        ; yes, save the value
5280
        setlo   r3,#'+'
5281
        lea             r4,XP25
5282
        call    TSTC            ; add?
5283
        call    EXPR3           ; get the second <EXPR3>
5284
XP24:
5285
        lw              r2,8[sp]
5286
        add             r1,r1,r2        ; add it to the first <EXPR3>
5287
;       BVS.L   QHOW            brnch if there's an overflow
5288
        bra             XP23            ; else go back for more operations
5289
XP25:
5290
        setlo   r3,#'-'
5291
        lea             r4,XP45
5292
        call    TSTC            ; subtract?
5293
XP26:
5294
        call    EXPR3           ; get second <EXPR3>
5295
        neg             r1,r1           ; change its sign
5296
        bra             XP24            ; and do an addition
5297
XP45:
5298
        lw              r1,8[sp]
5299
        lw              lr,[sp]
5300
        ret             #16
5301
 
5302
 
5303
; <EXPR3>::=<EXPR4>( <* or /><EXPR4> )(...
5304
 
5305
EXPR3:
5306
        subui   sp,sp,#16
5307
        sw              lr,[sp]
5308
        call    EXPR4           ; get first <EXPR4>
5309
XP31:
5310
        sw              r1,8[sp]        ; yes, save that first result
5311
        setlo   r3,#'*'
5312
        lea             r4,XP34
5313
        call    TSTC            ; multiply?
5314
        call    EXPR4           ; get second <EXPR4>
5315
        lw              r2,8[sp]
5316
        muls    r1,r1,r2        ; multiply the two
5317
        bra             XP31        ; then look for more terms
5318
XP34:
5319
        setlo   r3,#'/'
5320
        lea             r4,XP47
5321
        call    TSTC            ; divide?
5322
        call    EXPR4           ; get second <EXPR4>
5323
        or      r2,r1,r0
5324
        lw              r1,8[sp]
5325
        divs    r1,r1,r2        ; do the division
5326
        bra             XP31            ; go back for any more terms
5327
XP47:
5328
        lw              r1,8[sp]
5329
        lw              lr,[sp]
5330
        ret             #16
5331
 
5332
 
5333
; Functions are called through EXPR4
5334
; <EXPR4>::=<variable>
5335
;           <function>
5336
;           (<EXPR>)
5337
 
5338
EXPR4:
5339
    subui   sp,sp,#24
5340
    sw      lr,[sp]
5341
    lea         r9,TAB4         ; find possible function
5342
    lea         r10,TAB4_1
5343
        jmp             EXEC        ; branch to function which does subsequent ret for EXPR4
5344
XP40:                   ; we get here if it wasn't a function
5345
        setlo   r1,#0
5346
        call    TSTV
5347
        beq     r1,r0,XP41  ; nor a variable
5348
        lw              r1,[r1]         ; if a variable, return its value in r1
5349
        lw      lr,[sp]
5350
        ret             #24
5351
XP41:
5352
        call    TSTNUM          ; or is it a number?
5353
        bne             r2,r0,XP46      ; (if not, # of digits will be zero) if so, return it in r1
5354
        call    PARN        ; check for (EXPR)
5355
XP46:
5356
        lw      lr,[sp]
5357
        ret             #24
5358
 
5359
 
5360
; Check for a parenthesized expression
5361
PARN:
5362
        subui   sp,sp,#8
5363
        sw              lr,[sp]
5364
        setlo   r3,#'('
5365
        lea             r4,XP43
5366
        call    TSTC            ; else look for ( OREXPR )
5367
        call    OREXPR
5368
        setlo   r3,#')'
5369
        lea             r4,XP43
5370
        call    TSTC
5371
XP42:
5372
        lw              lr,[sp]
5373
        ret             #8
5374
XP43:
5375
        lea             r1,msgWhat
5376
        bra             ERROR
5377
 
5378
 
5379
; ===== Test for a valid variable name.  Returns Z=1 if not
5380
;       found, else returns Z=0 and the address of the
5381
;       variable in r1.
5382
; Parameters
5383
;       r1 = 1 = allocate if not found
5384
; Returns
5385
;       r1 = address of variable, zero if not found
5386
 
5387
TSTV:
5388
        subui   sp,sp,#24
5389
        sw              lr,[sp]
5390
        sw              r5,8[sp]
5391
        or              r5,r1,r0        ; allocate flag
5392
        call    IGNBLK
5393
        lbu             r1,[r8]         ; look at the program text
5394
        blt     r1,#'@',tstv_notfound   ; C=1: not a variable
5395
        bne             r1,#'@',TV1     ; brnch if not "@" array
5396
        addui   r8,r8,#1        ; If it is, it should be
5397
        call    PARN            ; followed by (EXPR) as its index.
5398
        shli    r1,r1,#3
5399
;       BCS.L   QHOW            say "How?" if index is too big
5400
        subui   sp,sp,#24
5401
    sw      r1,8[sp]    ; save the index
5402
    sw          lr,[sp]
5403
        call    SIZEX           ; get amount of free memory
5404
        lw              lr,[sp]
5405
        lw      r2,8[sp]    ; get back the index
5406
        bltu    r2,r1,TV2       ; see if there's enough memory
5407
        jmp     QSORRY          ; if not, say "Sorry"
5408
TV2:
5409
        lea             r1,VARBGN   ; put address of array element...
5410
        subu    r1,r1,r2       ; into r1 (neg. offset is used)
5411
        bra     TSTVRT
5412
TV1:
5413
    call    getVarName      ; get variable name
5414
    beq     r1,r0,TSTVRT    ; if not, return r1=0
5415
    mov         r2,r5
5416
    call    findVar     ; find or allocate
5417
TSTVRT:
5418
        lw              r5,8[sp]
5419
        lw              lr,[sp]
5420
        ret             #24                     ; r1<>0 (found)
5421
tstv_notfound:
5422
        lw              r5,8[sp]
5423
    lw      lr,[sp]
5424
    setlo   r1,#0       ; r1=0 if not found
5425
    ret         #24
5426
 
5427
 
5428
; Returns
5429
;   r1 = 6 character variable name + type
5430
;
5431
getVarName:
5432
    subui   sp,sp,#24
5433
    sw      lr,[sp]
5434
    sw          r5,16[sp]
5435
 
5436
    lb      r1,[r8]     ; get first character
5437
    sw          r1,8[sp]        ; save off current name
5438
    call    isAlpha
5439
    beq     r1,r0,gvn1
5440
    setlo   r5,#5       ; loop six more times
5441
 
5442
        ; check for second/third character
5443
gvn4:
5444
        addui   r8,r8,#1
5445
        lb      r1,[r8]     ; do we have another char ?
5446
        call    isAlnum
5447
        beq     r1,r0,gvn2  ; nope
5448
        lw      r1,8[sp]    ; get varname
5449
        shli    r1,r1,#8
5450
        lb      r2,[r8]
5451
        or      r1,r1,r2   ; add in new char
5452
    sw      r1,8[sp]   ; save off name again
5453
    loop        r5,gvn4
5454
 
5455
    ; now ignore extra variable name characters
5456
gvn6:
5457
    addui   r8,r8,#1
5458
    lb      r1,[r8]
5459
    call    isAlnum
5460
    bne     r1,r0,gvn6  ; keep looping as long as we have identifier chars
5461
 
5462
    ; check for a variable type
5463
gvn2:
5464
        lb              r1,[r8]
5465
    beq     r1,#'%',gvn3
5466
    beq     r1,#'$',gvn3
5467
    setlo   r1,#0
5468
    subui   r8,r8,#1
5469
 
5470
    ; insert variable type indicator and return
5471
gvn3:
5472
    addui   r8,r8,#1
5473
    lw      r2,8[sp]
5474
    shli        r2,r2,#8
5475
    or      r1,r1,r2    ; add in variable type
5476
    lw      lr,[sp]
5477
    lw          r5,16[sp]
5478
    ret         #24                     ; return Z = 0, r1 = varname
5479
 
5480
    ; not a variable name
5481
gvn1:
5482
    lw      lr,[sp]
5483
    lw          r5,16[sp]
5484
    setlo   r1,#0       ; return Z = 1 if not a varname
5485
    ret         #24
5486
 
5487
 
5488
; Find variable
5489
;   r1 = varname
5490
;       r2 = allocate flag
5491
; Returns
5492
;   r1 = variable address, Z =0 if found / allocated, Z=1 if not found
5493
 
5494
findVar:
5495
    subui   sp,sp,#16
5496
    sw      lr,[sp]
5497
    sw      r7,8[sp]
5498
    lw      r3,VARBGN
5499
fv4:
5500
    lw      r7,[r3]     ; get varname / type
5501
    beq     r7,r0,fv3   ; no more vars ?
5502
    beq     r1,r7,fv1   ; match ?
5503
    add     r3,r3,#8    ; move to next var
5504
    lw      r7,STKBOT
5505
    blt     r3,r7,fv4   ; loop back to look at next var
5506
 
5507
    ; variable not found
5508
    ; no more memory
5509
    setlo       r1,#<msgVarSpace
5510
    sethi       r1,#>msgVarSpace
5511
    bra     ERROR
5512
;    lw      lr,[sp]
5513
;    lw      r7,4[sp]
5514
;    add     sp,sp,#8
5515
;    lw      r1,#0
5516
;    ret
5517
 
5518
    ; variable not found
5519
    ; allocate new ?
5520
fv3:
5521
        beq             r2,r0,fv2
5522
    sw      r1,[r3]     ; save varname / type
5523
    ; found variable
5524
    ; return address
5525
fv1:
5526
    addui   r1,r3,#8
5527
    lw      lr,[sp]
5528
    lw      r7,8[sp]
5529
    ret         #16    ; Z = 0, r1 = address
5530
 
5531
    ; didn't find var and not allocating
5532
fv2:
5533
    lw      lr,[sp]
5534
    lw      r7,8[sp]
5535
    addui   sp,sp,#16   ; Z = 0, r1 = address
5536
        setlo   r1,#0            ; Z = 1, r1 = 0
5537
    ret
5538
 
5539
 
5540
; ===== Multiplies the 32 bit values in r1 and r2, returning
5541
;       the 32 bit result in r1.
5542
;
5543
 
5544
; ===== Divide the 32 bit value in r2 by the 32 bit value in r3.
5545
;       Returns the 32 bit quotient in r1, remainder in r2
5546
;
5547
; r2 = a
5548
; r3 = b
5549
; r6 = remainder
5550
; r7 = iteration count
5551
; r8 = sign
5552
;
5553
 
5554
; q = a / b
5555
; a = r1
5556
; b = r2
5557
; q = r2
5558
 
5559
 
5560
; ===== The PEEK function returns the byte stored at the address
5561
;       contained in the following expression.
5562
;
5563
PEEK:
5564
        call    PARN            ; get the memory address
5565
        lbu             r1,[r1]         ; get the addressed byte
5566
        lw              lr,[sp]         ; and return it
5567
        ret             #24
5568
 
5569
; ===== The PEEK function returns the byte stored at the address
5570
;       contained in the following expression.
5571
;
5572
PEEKC:
5573
        call    PARN            ; get the memory address
5574
        andi    r1,r1,#-2       ; align to char address
5575
        lcu             r1,[r1]         ; get the addressed char
5576
        lw              lr,[sp]         ; and return it
5577
        ret             #24
5578
 
5579
; ===== The PEEK function returns the byte stored at the address
5580
;       contained in the following expression.
5581
;
5582
PEEKH:
5583
        call    PARN            ; get the memory address
5584
        andi    r1,r1,#-4       ; align to half-word address
5585
        lhu             r1,[r1]         ; get the addressed char
5586
        lw              lr,[sp]         ; and return it
5587
        ret             #24
5588
 
5589
; ===== The PEEK function returns the byte stored at the address
5590
;       contained in the following expression.
5591
;
5592
PEEKW:
5593
        call    PARN            ; get the memory address
5594
        andi    r1,r1,#-8               ; align to word address
5595
        lw              r1,[r1]         ; get the addressed word
5596
        lw              lr,[sp]         ; and return it
5597
        ret             #24
5598
 
5599
; user function call
5600
; call the user function with argument in r1
5601
USRX:
5602
        call    PARN            ; get expression value
5603
        sw              r8,8[sp]        ; save the text pointer
5604
        lw      r2,usrJmp   ; get usr vector
5605
        jal             r31,[r2]        ; jump to the subroutine
5606
        lw              r8,8[sp]        ; restore the text pointer
5607
        lw              lr,[sp]
5608
        ret             #24
5609
 
5610
 
5611
; ===== The RND function returns a random number from 1 to
5612
;       the value of the following expression in D0.
5613
;
5614
RND:
5615
        call    PARN            ; get the upper limit
5616
        beq             r1,r0,rnd2      ; it must be positive and non-zero
5617
        blt             r1,r0,rnd1
5618
        lw              r2,r1
5619
        gran                            ; generate a random number
5620
        mfspr   r1,rand         ; get the number
5621
        call    modu4           ; RND(n)=MOD(number,n)+1
5622
        addui   r1,r1,#1
5623
        lw              lr,[sp]
5624
        ret             #24
5625
rnd1:
5626
        lea             r1,msgRNDBad
5627
        bra             ERROR
5628
rnd2:
5629
        gran
5630
        mfspr   r1,rand
5631
        lw              lr,[sp]
5632
        ret             #24
5633
 
5634
 
5635
; r = a mod b
5636
; a = r1
5637
; b = r2 
5638
; r = r6
5639
modu4:
5640
        subui   sp,sp,#32
5641
        sw              r3,[sp]
5642
        sw              r5,8[sp]
5643
        sw              r6,16[sp]
5644
        sw              r7,24[sp]
5645
        lw      r7,#63          ; n = 64
5646
        xor             r5,r5,r5        ; w = 0
5647
        xor             r6,r6,r6        ; r = 0
5648
mod2:
5649
        roli    r1,r1,#1        ; a <<= 1
5650
        andi    r3,r1,#1
5651
        shli    r6,r6,#1        ; r <<= 1
5652
        or              r6,r6,r3
5653
        andi    r1,r1,#-2
5654
        bgtu    r2,r6,mod1      ; b < r ?
5655
        subu    r6,r6,r2        ; r -= b
5656
mod1:
5657
    loop        r7,mod2         ; n--
5658
        mov             r1,r6
5659
        lw              r3,[sp]
5660
        lw              r5,8[sp]
5661
        lw              r6,16[sp]
5662
        lw              r7,24[sp]
5663
        ret             #32
5664
 
5665
 
5666
; ===== The ABS function returns an absolute value in r2.
5667
;
5668
ABS:
5669
        call    PARN            ; get the following expr.'s value
5670
        abs             r1,r1
5671
        lw              lr,[sp]
5672
        ret             #24
5673
 
5674
; ===== The SGN function returns the sign in r1. +1,0, or -1
5675
;
5676
SGN:
5677
        call    PARN            ; get the following expr.'s value
5678
        sgn             r1,r1
5679
        lw              lr,[sp]
5680
        ret             #24
5681
 
5682
; ===== The SIZE function returns the size of free memory in r1.
5683
;
5684
SIZEX:
5685
        lw              r1,VARBGN       ; get the number of free bytes...
5686
        lw              r2,TXTUNF       ; between 'TXTUNF' and 'VARBGN'
5687
        subu    r1,r1,r2
5688
        lw              lr,[sp]
5689
        ret             #24                     ; return the number in r2
5690
 
5691
 
5692
;******************************************************************
5693
;
5694
; *** SETVAL *** FIN *** ENDCHK *** ERROR (& friends) ***
5695
;
5696
; 'SETVAL' expects a variable, followed by an equal sign and then
5697
; an expression.  It evaluates the expression and sets the variable
5698
; to that value.
5699
;
5700
; 'FIN' checks the end of a command.  If it ended with ":",
5701
; execution continues.  If it ended with a CR, it finds the
5702
; the next line and continues from there.
5703
;
5704
; 'ENDCHK' checks if a command is ended with a CR. This is
5705
; required in certain commands, such as GOTO, RETURN, STOP, etc.
5706
;
5707
; 'ERROR' prints the string pointed to by r1. It then prints the
5708
; line pointed to by CURRNT with a "?" inserted at where the
5709
; old text pointer (should be on top of the stack) points to.
5710
; Execution of Tiny BASIC is stopped and a warm start is done.
5711
; If CURRNT is zero (indicating a direct command), the direct
5712
; command is not printed. If CURRNT is -1 (indicating
5713
; 'INPUT' command in progress), the input line is not printed
5714
; and execution is not terminated but continues at 'INPERR'.
5715
;
5716
; Related to 'ERROR' are the following:
5717
; 'QWHAT' saves text pointer on stack and gets "What?" message.
5718
; 'AWHAT' just gets the "What?" message and jumps to 'ERROR'.
5719
; 'QSORRY' and 'ASORRY' do the same kind of thing.
5720
; 'QHOW' and 'AHOW' also do this for "How?".
5721
;
5722
 
5723
; returns
5724
; r2 = variable's address
5725
;
5726
SETVAL:
5727
    subui   sp,sp,#16
5728
    sw      lr,[sp]
5729
    setlo       r1,#1           ; allocate var
5730
    call        TSTV            ; variable name?
5731
    bne         r1,r0,sv2
5732
        lea             r1,msgVar
5733
        bra             ERROR
5734
sv2:
5735
        sw      r1,8[sp]    ; save the variable's address
5736
        setlo   r3,#'='
5737
        lea             r4,SV1
5738
        call    TSTC            ; get past the "=" sign
5739
        call    OREXPR          ; evaluate the expression
5740
        lw      r2,8[sp]    ; get back the variable's address
5741
        sw      r1,[r2]     ; and save value in the variable
5742
        lw              r1,r2           ; return r1 = variable address
5743
        lw      lr,[sp]
5744
        ret             #16
5745
SV1:
5746
    bra     QWHAT               ; if no "=" sign
5747
 
5748
 
5749
FIN:
5750
        subui   sp,sp,#8
5751
        sw              lr,[sp]
5752
        setlo   r3,#':'
5753
        lea             r4,FI1
5754
        call    TSTC            ; *** FIN ***
5755
        addui   sp,sp,#8        ; if ":", discard return address
5756
        bra             RUNSML          ; continue on the same line
5757
FI1:
5758
        setlo   r3,#CR
5759
        lea             r4,FI2
5760
        call    TSTC            ; not ":", is it a CR?
5761
        lw              lr,[sp] ; else return to the caller
5762
        addui   sp,sp,#8        ; yes, purge return address
5763
        bra             RUNNXL          ; execute the next line
5764
FI2:
5765
        lw              lr,[sp] ; else return to the caller
5766
        ret             #8
5767
 
5768
 
5769
; Check that there is nothing else on the line
5770
; Registers Affected
5771
;   r1
5772
;
5773
ENDCHK:
5774
        subui   sp,sp,#8
5775
        sw              lr,[sp]
5776
        call    IGNBLK
5777
        lb              r1,[r8]
5778
        beq             r1,#CR,ec1      ; does it end with a CR?
5779
        setlo   r1,#<msgExtraChars
5780
        sethi   r1,#>msgExtraChars
5781
        jmp             ERROR
5782
ec1:
5783
        lw              lr,[sp]
5784
        ret             #8
5785
 
5786
 
5787
TOOBIG:
5788
        lea             r1,msgTooBig
5789
        bra             ERROR
5790
QSORRY:
5791
    lea         r1,SRYMSG
5792
        bra         ERROR
5793
QWHAT:
5794
        lea             r1,msgWhat
5795
ERROR:
5796
        call    PRMESG          ; display the error message
5797
        lw              r1,CURRNT       ; get the current line number
5798
        beq             r1,r0,WSTART    ; if zero, do a warm start
5799
        beq             r1,#-1,INPERR           ; is the line no. pointer = -1? if so, redo input
5800
        lb              r5,[r8]         ; save the char. pointed to
5801
        sb              r0,[r8]         ; put a zero where the error is
5802
        lw              r1,CURRNT       ; point to start of current line
5803
        call    PRTLN           ; display the line in error up to the 0
5804
        or      r6,r1,r0    ; save off end pointer
5805
        sb              r5,[r8]         ; restore the character
5806
        setlo   r1,#'?'         ; display a "?"
5807
        call    GOOUT
5808
        setlo   r2,#0       ; stop char = 0
5809
        subui   r1,r6,#1        ; point back to the error char.
5810
        call    PRTSTG          ; display the rest of the line
5811
        jmp         WSTART              ; and do a warm start
5812
 
5813
;******************************************************************
5814
;
5815
; *** GETLN *** FNDLN (& friends) ***
5816
;
5817
; 'GETLN' reads in input line into 'BUFFER'. It first prompts with
5818
; the character in r3 (given by the caller), then it fills the
5819
; buffer and echos. It ignores LF's but still echos
5820
; them back. Control-H is used to delete the last character
5821
; entered (if there is one), and control-X is used to delete the
5822
; whole line and start over again. CR signals the end of a line,
5823
; and causes 'GETLN' to return.
5824
;
5825
;
5826
GETLN:
5827
        subui   sp,sp,#16
5828
        sw              lr,[sp]
5829
        sw              r5,8[sp]
5830
        call    GOOUT           ; display the prompt
5831
        setlo   r1,#1           ; turn on cursor flash
5832
        sb              r1,cursFlash
5833
        setlo   r1,#' '         ; and a space
5834
        call    GOOUT
5835
        setlo   r8,#<BUFFER     ; r8 is the buffer pointer
5836
        sethi   r8,#>BUFFER
5837
GL1:
5838
        call    CHKIO           ; check keyboard
5839
        beq             r1,r0,GL1       ; wait for a char. to come in
5840
        beq             r1,#CTRLH,GL3   ; delete last character? if so
5841
        beq             r1,#CTRLX,GL4   ; delete the whole line?
5842
        beq             r1,#CR,GL2      ; accept a CR
5843
        bltu    r1,#' ',GL1     ; if other control char., discard it
5844
GL2:
5845
        sb              r1,[r8]         ; save the char.
5846
        add             r8,r8,#1
5847
        call    GOOUT           ; echo the char back out
5848
        lb      r1,-1[r8]   ; get char back (GOOUT destroys r1)
5849
        beq             r1,#CR,GL7      ; if it's a CR, end the line
5850
        cmpui   r1,r8,#BUFFER+BUFLEN-1  ; any more room?
5851
        blt             r1,r0,GL1       ; yes: get some more, else delete last char.
5852
GL3:
5853
        setlo   r1,#CTRLH       ; delete a char. if possible
5854
        call    GOOUT
5855
        setlo   r1,#' '
5856
        call    GOOUT
5857
        cmpui   r1,r8,#BUFFER   ; any char.'s left?
5858
        ble             r1,r0,GL1               ; if not
5859
        setlo   r1,#CTRLH       ; if so, finish the BS-space-BS sequence
5860
        call    GOOUT
5861
        sub             r8,r8,#1        ; decrement the text pointer
5862
        bra             GL1                     ; back for more
5863
GL4:
5864
        or              r1,r8,r0                ; delete the whole line
5865
        subui   r5,r1,#BUFFER   ; figure out how many backspaces we need
5866
        beq             r5,r0,GL6               ; if none needed, brnch
5867
GL5:
5868
        setlo   r1,#CTRLH       ; and display BS-space-BS sequences
5869
        call    GOOUT
5870
        setlo   r1,#' '
5871
        call    GOOUT
5872
        setlo   r1,#CTRLH
5873
        call    GOOUT
5874
        loop    r5,GL5
5875
GL6:
5876
        lea             r8,BUFFER       ; reinitialize the text pointer
5877
        bra             GL1                     ; and go back for more
5878
GL7:
5879
        setlo   r1,#0            ; turn off cursor flash
5880
        sb              r1,cursFlash
5881
        setlo   r1,#LF          ; echo a LF for the CR
5882
        call    GOOUT
5883
        lw              lr,[sp]
5884
        lw              r5,8[sp]
5885
        ret             #16
5886
 
5887
 
5888
; 'FNDLN' finds a line with a given line no. (in r1) in the
5889
; text save area.  r9 is used as the text pointer. If the line
5890
; is found, r9 will point to the beginning of that line
5891
; (i.e. the high byte of the line no.), and flags are Z.
5892
; If that line is not there and a line with a higher line no.
5893
; is found, r9 points there and flags are NC & NZ. If we reached
5894
; the end of the text save area and cannot find the line, flags
5895
; are C & NZ.
5896
; Z=1 if line found
5897
; N=1 if end of text save area
5898
; Z=0 & N=0 if higher line found
5899
; r0 = 1        <= line is found
5900
;       r9 = pointer to line
5901
; r0 = 0    <= line is not found
5902
;       r9 = zero, if end of text area
5903
;       r9 = otherwise higher line number
5904
;
5905
; 'FNDLN' will initialize r9 to the beginning of the text save
5906
; area to start the search. Some other entries of this routine
5907
; will not initialize r9 and do the search.
5908
; 'FNDLNP' will start with r9 and search for the line no.
5909
; 'FNDNXT' will bump r9 by 2, find a CR and then start search.
5910
; 'FNDSKP' uses r9 to find a CR, and then starts the search.
5911
; return Z=1 if line is found, r9 = pointer to line
5912
;
5913
; Parameters
5914
;       r1 = line number to find
5915
;
5916
FNDLN:
5917
        bleui   r1,#0xFFFF,fl1  ; line no. must be < 65535
5918
        lea             r1,msgLineRange
5919
        bra             ERROR
5920
fl1:
5921
        lw              r9,TXTBGN       ; init. the text save pointer
5922
 
5923
FNDLNP:
5924
        lw              r10,TXTUNF      ; check if we passed the end
5925
        subui   r10,r10,#1
5926
        bgtu    r9,r10,FNDRET1          ; if so, return with r9=0,r1=0
5927
        lbu             r3,[r9]         ; get low order byte of line number
5928
        lbu             r2,1[r9]        ; get high order byte
5929
        shli    r2,r2,#8
5930
        or              r2,r2,r3        ; build whole line number
5931
        bgtu    r1,r2,FNDNXT    ; is this the line we want? no, not there yet
5932
        beq             r1,r2,FNDRET2
5933
FNDRET:
5934
        xor             r1,r1,r1        ; line not found, but r9=next line pointer
5935
        ret                     ; return the cond. codes
5936
FNDRET1:
5937
        xor             r9,r9,r9        ; no higher line
5938
        xor             r1,r1,r1        ; line not found
5939
        ret
5940
FNDRET2:
5941
        setlo   r1,#1           ; line found
5942
        ret
5943
 
5944
FNDNXT:
5945
        addui   r9,r9,#2        ; find the next line
5946
 
5947
FNDSKP:
5948
        lbu             r2,[r9]
5949
        addui   r9,r9,#1
5950
        bnei    r2,#CR,FNDSKP           ; try to find a CR, keep looking
5951
        bra             FNDLNP          ; check if end of text
5952
 
5953
 
5954
;******************************************************************
5955
; 'MVUP' moves a block up from where r1 points to where r2 points
5956
; until r1=r3
5957
;
5958
MVUP1:
5959
        lb              r4,[r1]
5960
        sb              r4,[r2]
5961
        add             r1,r1,#1
5962
        add             r2,r2,#1
5963
MVUP:
5964
        bne             r1,r3,MVUP1
5965
MVRET:
5966
        ret
5967
 
5968
 
5969
; 'MVDOWN' moves a block down from where r1 points to where r2
5970
; points until r1=r3
5971
;
5972
MVDOWN1:
5973
        sub             r1,r1,#1
5974
        sub             r2,r2,#1
5975
        lb              r4,[r1]
5976
        sb              r4,[r2]
5977
MVDOWN:
5978
        bne             r1,r3,MVDOWN1
5979
        ret
5980
 
5981
 
5982
; 'POPA' restores the 'FOR' loop variable save area from the stack
5983
;
5984
; 'PUSHA' stacks for 'FOR' loop variable save area onto the stack
5985
;
5986
; Note: a single zero word is stored on the stack in the
5987
; case that no FOR loops need to be saved. This needs to be
5988
; done because PUSHA / POPA is called all the time.
5989
 
5990
POPA:
5991
        lw              r1,[sp]         ; restore LOPVAR, but zero means no more
5992
        sw              r1,LOPVAR
5993
        beq             r1,r0,PP1
5994
        lw              r1,32[sp]       ; if not zero, restore the rest
5995
        sw              r1,LOPPT
5996
        lw              r1,24[sp]
5997
        sw              r1,LOPLN
5998
        lw              r1,16[sp]
5999
        sw              r1,LOPLMT
6000
        lw              r1,8[sp]
6001
        sw              r1,LOPINC
6002
        ret             #40
6003
PP1:
6004
        ret             #8
6005
 
6006
 
6007
PUSHA:
6008
        lw              r1,STKBOT       ; Are we running out of stack room?
6009
        addui   r1,r1,#40       ; we might need this many bytes
6010
        bltu    sp,r1,QSORRY    ; out of stack space
6011
        lw              r1,LOPVAR       ; save loop variables
6012
        beq             r1,r0,PU1       ; if LOPVAR is zero, that's all
6013
        subui   sp,sp,#40
6014
        sw              r1,[sp]
6015
        lw              r1,LOPPT
6016
        sw              r1,32[sp]       ; else save all the others
6017
        lw              r1,LOPLN
6018
        sw              r1,24[sp]
6019
        lw              r1,LOPLMT
6020
        sw              r1,16[sp]
6021
        lw              r1,LOPINC
6022
        sw              r1,8[sp]
6023
        ret
6024
PU1:
6025
        subui   sp,sp,#8
6026
        sw              r1,[sp]
6027
        ret
6028
 
6029
 
6030
;******************************************************************
6031
;
6032
; *** PRTSTG *** QTSTG *** PRTNUM *** PRTLN ***
6033
;
6034
; 'PRTSTG' prints a string pointed to by r3. It stops printing
6035
; and returns to the caller when either a CR is printed or when
6036
; the next byte is the same as what was passed in r4 by the
6037
; caller.
6038
;
6039
; 'QTSTG' looks for an underline (back-arrow on some systems),
6040
; single-quote, or double-quote.  If none of these are found, returns
6041
; to the caller.  If underline, outputs a CR without a LF.  If single
6042
; or double quote, prints the quoted string and demands a matching
6043
; end quote.  After the printing, the next i-word of the caller is
6044
; skipped over (usually a branch instruction).
6045
;
6046
; 'PRTNUM' prints the 32 bit number in r3, leading blanks are added if
6047
; needed to pad the number of spaces to the number in r4.
6048
; However, if the number of digits is larger than the no. in
6049
; r4, all digits are printed anyway. Negative sign is also
6050
; printed and counted in, positive sign is not.
6051
;
6052
; 'PRTLN' prints the saved text line pointed to by r3
6053
; with line no. and all.
6054
;
6055
 
6056
; r1 = pointer to string
6057
; r2 = stop character
6058
; return r1 = pointer to end of line + 1
6059
 
6060
PRTSTG:
6061 46 robfinch
    subui   sp,sp,#32
6062 43 robfinch
    sw          r5,[sp]
6063
    sw          r5,8[sp]
6064
    sw          r7,16[sp]
6065
    sw          lr,24[sp]
6066
    mov     r5,r1       ; r5 = pointer
6067
    mov     r6,r2       ; r6 = stop char
6068
PS1:
6069
    lbu     r7,[r5]     ; get a text character
6070
    addui   r5,r5,#1
6071
        beq         r7,r6,PRTRET                ; same as stop character? if so, return
6072
        mov     r1,r7
6073
        call    GOOUT           ; display the char.
6074
        bnei    r7,#CR,PS1  ; is it a C.R.? no, go back for more
6075
        setlo   r1,#LF      ; yes, add a L.F.
6076
        call    GOOUT
6077
PRTRET:
6078
    mov     r2,r7       ; return r2 = stop char
6079
        mov             r1,r5           ; return r1 = line pointer
6080
    lw          lr,24[sp]
6081
    lw          r7,16[sp]
6082
    lw          r5,8[sp]
6083
    lw          r5,[sp]
6084
    ret         #32             ; then return
6085
 
6086
 
6087
QTSTG:
6088
        subui   sp,sp,#8
6089
        sw              lr,[sp]
6090
        setlo   r3,#'"'
6091 46 robfinch
        lea             r4,QT3
6092 43 robfinch
        call    TSTC            ; *** QTSTG ***
6093
        setlo   r2,#'"'         ; it is a "
6094
QT1:
6095
        or              r1,r8,r0
6096
        call    PRTSTG          ; print until another
6097
        lw              r8,r1
6098
        bne             r2,#LF,QT2      ; was last one a CR?
6099
        addui   sp,sp,#8
6100
        bra             RUNNXL          ; if so, run next line
6101
QT3:
6102
        setlo   r3,#''''
6103 46 robfinch
        lea             r4,QT4
6104 43 robfinch
        call    TSTC            ; is it a single quote?
6105
        setlo   r2,#''''        ; if so, do same as above
6106
        bra             QT1
6107
QT4:
6108
        setlo   r3,#'_'
6109 46 robfinch
        lea             r4,QT5
6110 43 robfinch
        call    TSTC            ; is it an underline?
6111
        setlo   r1,#CR          ; if so, output a CR without LF
6112
        call    GOOUT
6113
QT2:
6114
        lw              lr,[sp]
6115
        addui   sp,sp,#8
6116
        jal             r0,4[lr]                ; skip over next i-word when returning
6117
QT5:                                            ; not " ' or _
6118
        lw              lr,[sp]
6119
        ret             #8
6120
 
6121
 
6122
; Output a CR LF sequence
6123
;
6124
prCRLF:
6125
        subui   sp,sp,#8
6126
        sw              lr,[sp]
6127
        setlo   r1,#CR
6128
        call    GOOUT
6129
        setlo   r1,#LF
6130
        call    GOOUT
6131
        lw              lr,[sp]
6132
        ret             #8
6133
 
6134
 
6135
; r1 = number to print
6136
; r2 = number of digits
6137
; Register Usage
6138
;       r5 = number of padding spaces
6139
PRTNUM:
6140
        subui   sp,sp,#40
6141
        sw              r3,[sp]
6142
        sw              r5,8[sp]
6143
        sw              r6,16[sp]
6144
        sw              r7,24[sp]
6145
        sw              lr,32[sp]
6146 46 robfinch
        lea             r7,NUMWKA       ; r7 = pointer to numeric work area
6147 43 robfinch
        mov             r6,r1           ; save number for later
6148
        mov             r5,r2           ; r5 = min number of chars
6149 46 robfinch
        bgt             r1,r0,PN2       ; is it negative? if not
6150 43 robfinch
        neg             r1,r1           ; else make it positive
6151
        subui   r5,r5,#1        ; one less for width count
6152 46 robfinch
PN2:
6153
        lw              r3,#10
6154 43 robfinch
PN1:
6155 46 robfinch
        modu    r2,r1,r3        ; r2 = r1 mod 10
6156 43 robfinch
        divui   r1,r1,#10       ; r1 /= 10 divide by 10
6157
        addui   r2,r2,#'0'      ; convert remainder to ascii
6158
        sb              r2,[r7]         ; and store in buffer
6159
        addui   r7,r7,#1
6160
        subui   r5,r5,#1        ; decrement width
6161
        bne             r1,r0,PN1
6162
PN6:
6163
        ble             r5,r0,PN4       ; test pad count, skip padding if not needed
6164
PN3:
6165
        setlo   r1,#' '         ; display the required leading spaces
6166
        call    GOOUT
6167
        loop    r5,PN3
6168
PN4:
6169 46 robfinch
        bge             r6,r0,PN5       ; is number negative?
6170 43 robfinch
        setlo   r1,#'-'         ; if so, display the sign
6171
        call    GOOUT
6172
PN5:
6173
        subui   r7,r7,#1
6174
        lb              r1,[r7]         ; now unstack the digits and display
6175
        call    GOOUT
6176
        cmpui   r1,r7,#NUMWKA
6177
        bgtu    r1,r0,PN5
6178
PNRET:
6179
        lw              lr,32[sp]
6180
        lw              r7,24[sp]
6181
        lw              r6,16[sp]
6182
        lw              r5,8[sp]
6183
        lw              r3,[sp]
6184
        ret             #40
6185
 
6186
 
6187
; r1 = number to print
6188
; r2 = number of digits
6189
PRTHEXNUM:
6190
        subui   sp,sp,#40
6191
        sw              r5,[sp]
6192
        sw              r6,8[sp]
6193
        sw              r7,16[sp]
6194
        sw              r8,24[sp]
6195
        sw              lr,32[sp]
6196 46 robfinch
        lea             r7,NUMWKA       ; r7 = pointer to numeric work area
6197 43 robfinch
        or              r6,r1,r0        ; save number for later
6198
        setlo   r5,#20          ; r5 = min number of chars
6199 46 robfinch
        mov             r4,r1
6200 43 robfinch
        bgt             r4,r0,PHN1              ; is it negative? if not
6201
        neg             r4,r4                   ; else make it positive
6202 46 robfinch
        subui   r5,r5,#1        ; one less for width count
6203 43 robfinch
        setlo   r8,#20          ; maximum of 10 digits
6204
PHN1:
6205 46 robfinch
        mov             r1,r4
6206 43 robfinch
        andi    r1,r1,#15
6207
        blt             r1,#10,PHN7
6208
        addui   r1,r1,#'A'-10
6209
        bra             PHN8
6210
PHN7:
6211
        add             r1,r1,#'0'              ; convert remainder to ascii
6212
PHN8:
6213
        sb              r1,[r7]         ; and store in buffer
6214 46 robfinch
        addui   r7,r7,#1
6215
        subui   r5,r5,#1        ; decrement width
6216
        shrui   r4,r4,#4
6217 43 robfinch
        beq             r4,r0,PHN6                      ; is it zero yet ?
6218
        loop    r8,PHN1         ; safety
6219
PHN6:   ; test pad count
6220
        ble             r5,r0,PHN4      ; skip padding if not needed
6221
PHN3:
6222
        setlo   r1,#' '         ; display the required leading spaces
6223
        call    GOOUT
6224
        loop    r5,PHN3
6225
PHN4:
6226
        bgt             r6,r0,PHN5      ; is number negative?
6227
        setlo   r1,#'-'         ; if so, display the sign
6228
        call    GOOUT
6229
PHN5:
6230 46 robfinch
        subui   r7,r7,#1
6231 43 robfinch
        lb              r1,[r7]         ; now unstack the digits and display
6232
        call    GOOUT
6233
        cmpui   r1,r7,#NUMWKA
6234
        bgt             r1,r0,PHN5
6235
PHNRET:
6236
        lw              lr,32[sp]
6237
        lw              r8,24[sp]
6238
        lw              r7,16[sp]
6239
        lw              r6,8[sp]
6240
        lw              r5,[sp]
6241
        ret             #40
6242
 
6243
 
6244
; r1 = pointer to line
6245
; returns r1 = pointer to end of line + 1
6246
PRTLN:
6247
    subui   sp,sp,#16
6248
    sw          r5,[sp]
6249
    sw          lr,8[sp]
6250
    addi    r5,r1,#2
6251
    lbu         r1,-2[r5]       ; get the binary line number
6252
    lbu         r2,-1[r5]
6253
    shli        r2,r2,#8
6254
    or          r1,r1,r2
6255
    setlo   r2,#0       ; display a 0 or more digit line no.
6256
        call    PRTNUM
6257
        setlo   r1,#' '     ; followed by a blank
6258
        call    GOOUT
6259
        setlo   r2,#0       ; stop char. is a zero
6260
        or      r1,r5,r0
6261
        call    PRTSTG          ; display the rest of the line
6262
        lw              lr,8[sp]
6263
        lw              r5,[sp]
6264
        ret             #16
6265
 
6266
 
6267
; ===== Test text byte following the call to this subroutine. If it
6268
;       equals the byte pointed to by r8, return to the code following
6269
;       the call. If they are not equal, brnch to the point
6270
;       indicated in r4.
6271
;
6272
; Registers Affected
6273
;   r3,r8
6274
; Returns
6275
;       r8 = updated text pointer
6276
;
6277
TSTC
6278
        subui   sp,sp,#16
6279
        sw              lr,[sp]
6280
        sw              r1,8[sp]
6281
        call    IGNBLK          ; ignore leading blanks
6282
        lb              r1,[r8]
6283
        beq             r3,r1,TC1       ; is it = to what r8 points to? if so
6284
        lw              r1,8[sp]
6285
        lw              lr,[sp]
6286
        addui   sp,sp,#16
6287
        jal             r0,[r4]         ; jump to the routine
6288
TC1:
6289 46 robfinch
        addui   r8,r8,#1        ; if equal, bump text pointer
6290 43 robfinch
        lw              r1,8[sp]
6291
        lw              lr,[sp]
6292
        ret             #16
6293
 
6294
; ===== See if the text pointed to by r8 is a number. If so,
6295
;       return the number in r2 and the number of digits in r3,
6296
;       else return zero in r2 and r3.
6297
; Registers Affected
6298
;   r1,r2,r3,r4
6299
; Returns
6300
;       r1 = number
6301
;       r2 = number of digits in number
6302
;       r8 = updated text pointer
6303
;
6304
TSTNUM:
6305
        subui   sp,sp,#8
6306
        sw              lr,[sp]
6307
        call    IGNBLK          ; skip over blanks
6308
        setlo   r1,#0            ; initialize return parameters
6309
        setlo   r2,#0
6310
TN1:
6311
        lb              r3,[r8]
6312
        bltui   r3,#'0',TSNMRET ; is it less than zero?
6313
        bgtui   r3,#'9',TSNMRET ; is it greater than nine?
6314 46 robfinch
        lw              r4,#0x07FFFFFF_FFFFFFFF
6315 43 robfinch
        bleu    r1,r4,TN2       ; see if there's room for new digit
6316 46 robfinch
        lea             r1,msgNumTooBig
6317 43 robfinch
        bra             ERROR           ; if not, we've overflowd
6318
TN2:
6319
        mului   r1,r1,#10       ; quickly multiply result by 10
6320 46 robfinch
        addui   r8,r8,#1        ; adjust text pointer
6321 43 robfinch
        andi    r3,r3,#0x0F     ; add in the new digit
6322 46 robfinch
        addu    r1,r1,r3
6323
        addui   r2,r2,#1        ; increment the no. of digits
6324 43 robfinch
        bra             TN1
6325
TSNMRET:
6326
        lw              lr,[sp]
6327
        ret             #8
6328
 
6329
 
6330
;===== Skip over blanks in the text pointed to by r8.
6331
;
6332
; Registers Affected:
6333
;       r8
6334
; Returns
6335
;       r8 = pointer updateded past any spaces or tabs
6336
;
6337
IGNBLK:
6338
        subui   sp,sp,#8
6339
        sw              r1,[sp]
6340
IGB2:
6341
        lb              r1,[r8]                 ; get char
6342
        beqi    r1,#' ',IGB1    ; see if it's a space
6343
        bnei    r1,#'\t',IGBRET ; or a tab
6344
IGB1:
6345 46 robfinch
        addui   r8,r8,#1                ; increment the text pointer
6346 43 robfinch
        bra             IGB2
6347
IGBRET:
6348
        lw              r1,[sp]
6349
        ret             #8
6350
 
6351
 
6352
; ===== Convert the line of text in the input buffer to upper
6353
;       case (except for stuff between quotes).
6354
;
6355
; Registers Affected
6356
;   r1,r3
6357
; Returns
6358
;       r8 = pointing to end of text in buffer
6359
;
6360
TOUPBUF:
6361
        subui   sp,sp,#8
6362
        sw              lr,[sp]
6363 46 robfinch
        lea             r8,BUFFER       ; set up text pointer
6364 43 robfinch
        setlo   r3,#0            ; clear quote flag
6365
TOUPB1:
6366
        lb              r1,[r8]         ; get the next text char.
6367 46 robfinch
        addui   r8,r8,#1
6368 43 robfinch
        beqi    r1,#CR,TOUPBRT          ; is it end of line?
6369
        beqi    r1,#'"',DOQUO   ; a double quote?
6370
        beqi    r1,#'''',DOQUO  ; or a single quote?
6371
        bne             r3,r0,TOUPB1    ; inside quotes?
6372
        call    toUpper         ; convert to upper case
6373
        sb              r1,-1[r8]       ; store it
6374
        bra             TOUPB1          ; and go back for more
6375
DOQUO:
6376
        bne             r3,r0,DOQUO1; are we inside quotes?
6377 46 robfinch
        mov             r3,r1           ; if not, toggle inside-quotes flag
6378 43 robfinch
        bra             TOUPB1
6379
DOQUO1:
6380
        bne             r3,r1,TOUPB1            ; make sure we're ending proper quote
6381
        setlo   r3,#0            ; else clear quote flag
6382
        bra             TOUPB1
6383
TOUPBRT:
6384
        lw              lr,[sp]
6385
        ret             #8
6386
 
6387
 
6388
; ===== Convert the character in r1 to upper case
6389
;
6390
toUpper
6391 46 robfinch
        blti    r1,#'a',TOUPRET ; is it < 'a'?
6392
        bgti    r1,#'z',TOUPRET ; or > 'z'?
6393
        subui   r1,r1,#32       ; if not, make it upper case
6394 43 robfinch
TOUPRET
6395
        ret
6396
 
6397
 
6398
; 'CHKIO' checks the input. If there's no input, it will return
6399
; to the caller with the r1=0. If there is input, the input byte is in r1.
6400
; However, if a control-C is read, 'CHKIO' will warm-start BASIC and will
6401
; not return to the caller.
6402
;
6403
CHKIO:
6404
        subui   sp,sp,#8        ; save link reg
6405
        sw              lr,[sp]
6406
        call    GOIN            ; get input if possible
6407 46 robfinch
        beqi    r1,#-1,CHKRET2          ; if Zero, no input
6408 43 robfinch
        bnei    r1,#CTRLC,CHKRET        ; is it control-C?
6409
        jmp             WSTART          ; if so, do a warm start
6410
CHKRET2:
6411
        xor             r1,r1,r1
6412
CHKRET:
6413
        lw              lr,[sp]         ;r1=0
6414
        ret             #8
6415
 
6416
 
6417
; ===== Display a CR-LF sequence
6418
;
6419
CRLF:
6420
        setlo   r1,CLMSG
6421
 
6422
 
6423
; ===== Display a zero-ended string pointed to by register r1
6424
; Registers Affected
6425
;   r1,r2,r4
6426
;
6427
PRMESG:
6428
        subui   sp,sp,#16
6429
        sw              r5,[sp]
6430
        sw              lr,8[sp]
6431
        mov     r5,r1       ; r5 = pointer to message
6432
PRMESG1:
6433 46 robfinch
        addui   r5,r5,#1
6434
        lbu             r1,-1[r5]       ;       get the char.
6435 43 robfinch
        beq             r1,r0,PRMRET
6436
        call    GOOUT           ;else display it trashes r4
6437
        bra             PRMESG1
6438
PRMRET:
6439
        mov             r1,r5
6440
        lw              lr,8[sp]
6441
        lw              r5,[sp]
6442
        ret             #16
6443
 
6444
 
6445
; ===== Display a zero-ended string pointed to by register r1
6446
; Registers Affected
6447
;   r1,r2,r3
6448
;
6449
PRMESGAUX:
6450
        subui   sp,sp,#16
6451
        sw              r5,[sp]
6452
        sw              lr,8[sp]
6453
        mov     r5,r1       ; r3 = pointer
6454
PRMESGA1:
6455
        addui   r5,r5,#1
6456
        lb              r1,-1[r5]       ;       get the char.
6457
        beq             r1,r0,PRMRETA
6458
        call    GOAUXO          ;else display it
6459
        bra             PRMESGA1
6460
PRMRETA:
6461
        mov             r1,r5
6462
        lw              lr,8[sp]
6463
        lw              r5,[sp]
6464
        ret             #16
6465
 
6466
;*****************************************************
6467
; The following routines are the only ones that need *
6468
; to be changed for a different I/O environment.     *
6469
;*****************************************************
6470
 
6471
 
6472
; ===== Output character to the console (Port 1) from register r1
6473
;       (Preserves all registers.)
6474
;
6475
OUTC:
6476
        jmp             DisplayChar
6477
 
6478
 
6479 46 robfinch
; ===== Input a character from the console into register R1 (or
6480 43 robfinch
;       return Zero status if there's no character available).
6481
;
6482
INC:
6483
        jmp             KeybdGetChar
6484
 
6485
 
6486
;*
6487
;* ===== Input a character from the host into register r1 (or
6488 27 robfinch
;*      return Zero status if there's no character available).
6489
;*
6490
AUXIN:
6491 43 robfinch
        call    SerialGetChar
6492
        beqi    r1,#-1,AXIRET_ZERO
6493 27 robfinch
        andi    r1,r1,#0x7f             ;zero out the high bit
6494
AXIRET:
6495
        ret
6496 43 robfinch
AXIRET_ZERO:
6497
        xor             r1,r1,r1
6498
        ret
6499 27 robfinch
 
6500 43 robfinch
; ===== Output character to the host (Port 2) from register r1
6501
;       (Preserves all registers.)
6502
;
6503
AUXOUT
6504
        jmp             SerialPutChar   ; call boot rom routine
6505
 
6506
 
6507
_cls
6508
        call    clearScreen
6509
        bra             FINISH
6510
 
6511
_wait10
6512
        ret
6513
_getATAStatus
6514
        ret
6515
_waitCFNotBusy
6516
        ret
6517
_rdcf
6518
        br              FINISH
6519
rdcf6
6520
        br              ERROR
6521
 
6522
 
6523
; ===== Return to the resident monitor, operating system, etc.
6524
;
6525 27 robfinch
BYEBYE:
6526 43 robfinch
        lw              sp,OSSP
6527
    lw      lr,[sp]
6528
        ret             #8
6529
 
6530
;       MOVE.B  #228,D7         return to Tutor
6531 27 robfinch
;       TRAP    #14
6532
 
6533 46 robfinch
msgInit db      CR,LF,"Raptor64 Tiny BASIC v1.0",CR,LF,"(C) 2013  Robert Finch",CR,LF,LF,0
6534 27 robfinch
OKMSG   db      CR,LF,"OK",CR,LF,0
6535
msgWhat db      "What?",CR,LF,0
6536
SRYMSG  db      "Sorry."
6537
CLMSG   db      CR,LF,0
6538
msgReadError    db      "Compact FLASH read error",CR,LF,0
6539
msgNumTooBig    db      "Number is too big",CR,LF,0
6540
msgDivZero              db      "Division by zero",CR,LF,0
6541
msgVarSpace     db  "Out of variable space",CR,LF,0
6542
msgBytesFree    db      " bytes free",CR,LF,0
6543
msgReady                db      CR,LF,"Ready",CR,LF,0
6544
msgComma                db      "Expecting a comma",CR,LF,0
6545
msgLineRange    db      "Line number too big",CR,LF,0
6546
msgVar                  db      "Expecting a variable",CR,LF,0
6547
msgRNDBad               db      "RND bad parameter",CR,LF,0
6548
msgSYSBad               db      "SYS bad address",CR,LF,0
6549
msgInputVar             db      "INPUT expecting a variable",CR,LF,0
6550
msgNextFor              db      "NEXT without FOR",CR,LF,0
6551
msgNextVar              db      "NEXT expecting a defined variable",CR,LF,0
6552
msgBadGotoGosub db      "GOTO/GOSUB bad line number",CR,LF,0
6553
msgRetWoGosub   db      "RETURN without GOSUB",CR,LF,0
6554
msgTooBig               db      "Program is too big",CR,LF,0
6555
msgExtraChars   db      "Extra characters on line ignored",CR,LF,0
6556
 
6557 43 robfinch
        align   8
6558
LSTROM  equ     *               ; end of possible ROM area
6559
;       END
6560 27 robfinch
 
6561 43 robfinch
;*
6562
;* ===== Return to the resident monitor, operating system, etc.
6563
;*
6564
BYEBYE:
6565
        jmp             Monitor
6566
;    MOVE.B     #228,D7         ;return to Tutor
6567
;       TRAP    #14
6568 27 robfinch
 
6569
;==============================================================================
6570 10 robfinch
; Checkerboard RAM tester
6571
;==============================================================================
6572
;
6573 27 robfinch
        code
6574
        align   16
6575 10 robfinch
ramtest:
6576
        or              r8,r0,r0                ; r8 = 0
6577
        ori             r1,r0,#0xAAAA5555AAAA5555       ; checkerboard pattern
6578
ramtest2:
6579
        sw              r1,[r8]                 ; save the checkerboard to memory
6580
        lw              r2,[r8]                 ; read it back
6581
        cmp             r3,r1,r2                ; is it the same ?
6582 27 robfinch
        bne     r3,r0,ramtest1
6583
        addui   r8,r8,#8                ; increment RAM pointer
6584
        cmpi    r3,r8,#0x0000_0000_0400_0000
6585
        blt             r3,r0,ramtest2
6586 10 robfinch
ramtest1:
6587
        or              r10,r8,r0               ; r10 = max ram address
6588
        ; readback the checkerboard pattern
6589
        or              r8,r0,r0                ; r8 = 0
6590
ramtest4:
6591
        lw              r2,[r8]
6592
        cmpi    r3,r2,#0xAAAA5555AAAA5555
6593 27 robfinch
        bne             r3,r0,ramtest3
6594 10 robfinch
        addi    r8,r8,#8
6595
        cmpi    r3,r8,#0x0000_0000_0100_0000
6596 27 robfinch
        blt     r3,r0,ramtest4
6597 10 robfinch
ramtest3:
6598
        bne             r8,r10,ramtest8 ; check for equal maximum address
6599
 
6600
        ; perform ramtest again with inverted checkerboard
6601
        or              r8,r0,r0                ; r8 = 0
6602
        ori             r1,r0,#0x5555AAAA5555AAAA
6603
ramtest5:
6604
        sw              r1,[r8]
6605
        lw              r2,[r8]
6606
        cmp             r3,r1,r2
6607 27 robfinch
        bne             r3,r0,ramtest6
6608 10 robfinch
        addi    r8,r8,#8
6609
        cmpi    r3,r8,#0x0000_0000_0100_0000
6610 27 robfinch
        blt             r3,r0,ramtest5
6611 10 robfinch
ramtest6:
6612
        or              r11,r8,r0               ; r11 = max ram address
6613
        ; readback checkerboard
6614
        or              r8,r0,r0
6615
ramtest7:
6616
        lw              r2,[r8]
6617
        cmpi    r3,r2,#0x5555AAAA5555AAAA
6618 27 robfinch
        bne             r3,r0,ramtest8
6619 10 robfinch
        addi    r8,r8,#8
6620
        cmpi    r3,r8,#0x0000_0000_0100_0000
6621 27 robfinch
        blt             r3,r0,ramtest7
6622 10 robfinch
ramtest8:
6623
        beq             r8,r11,ramtest9
6624
        min             r8,r8,r11
6625
ramtest9:
6626
        beq             r8,r10,ramtest10
6627
        min             r8,r8,r10
6628
ramtest10:
6629
        sw              r8,0x00000400   ;memend
6630 27 robfinch
        ret
6631
 
6632
;-------------------------------------------
6633 43 robfinch
;-------------------------------------------
6634
;
6635
iberr_rout:
6636
        lea             r1,msgiberr
6637
        call    DisplayString
6638
        mfspr   r1,EPC
6639
        call    DisplayWord
6640
        wait
6641
        jmp             start
6642
dberr_rout:
6643 46 robfinch
        lw              sp,#0x100200100
6644 43 robfinch
        lea             r1,msgdberr
6645
        call    DisplayString
6646
        mfspr   r1,ERRADR
6647
        call    DisplayWord
6648
        lea             r1,msgEPC
6649
        call    DisplayString
6650
        mfspr   r1,EPC
6651
        call    DisplayWord
6652
        call    CRLF
6653
        lw              r2,#31
6654
dberr1:
6655
        mtspr   PCHI,r2
6656
        nop
6657
        nop
6658
        nop
6659
        mfspr   r1,PCHISTORIC
6660
        call    DisplayWord
6661
        call    CRLF
6662
        loop    r2,dberr1
6663
        wait
6664
        jmp             start
6665
        .align  16
6666
msgdberr:
6667
        db      "Data bus error at: ",0
6668
msgEPC:
6669
        db      " EPC: ",0
6670
msgiberr:
6671
        db      "Err fetching instruction at: ",0
6672 46 robfinch
        .align  4
6673 43 robfinch
 
6674
;------------------------------------------------------------------------------
6675 27 robfinch
; IRQ routine
6676 46 robfinch
;
6677
; Interrupts are automatically disabled at the time of the interrupt in order
6678
; to prevent nested interrupts from occuring. Interrupts are re-enabled by
6679
; the IRET instruction at the end of the interrupt routine. If the interrupt
6680
; turns out to not match a hardware interrupt, then a software context
6681
; switching interrupt is assumed.
6682
;
6683
; This routine uses it's own private interrupt stack; the stack of the
6684
; interrupted context is not used at all. A couple of working registers are
6685
; saved off not on the stack. We can get away with this because nested
6686
; interrupts are not allowed.
6687 43 robfinch
;------------------------------------------------------------------------------
6688
;
6689 27 robfinch
irqrout:
6690 46 robfinch
        sw              sp,sp_save                              ; use our own private stack for interrupt processing
6691
        sw              lr,lr_save                              ; so, save off the sp and working registers
6692
        sw              r26,r26_save
6693
        sw              r1,r1_save
6694
        sw              r2,r2_save
6695
 
6696
        lw              sp,#0x1_00001000                ; the second two kbytes
6697 43 robfinch
        inch    r1,PIC                                  ; r1= which IRQ line is active
6698 46 robfinch
 
6699
; Dispatch fork, in order of required timeliness
6700
 
6701
        beqi    r1,#2,irq1000Hz
6702
        beqi    r1,#3,irq100Hz
6703
        beqi    r1,#8,irqSerial
6704
        beqi    r1,#13,irqRaster
6705
        beqi    r1,#15,irqKeybd
6706
        beqi    r1,#1,irqColdStart              ; CTRL-ALT-DEL interrupt
6707
 
6708
; Here, none of the hardware interrupts were active so
6709
; assume software context switch interrupt
6710
;
6711
        lw              sp,sp_save
6712
        lw              lr,lr_save
6713
        lw              r26,r26_save
6714
        lw              r1,r1_save
6715
        lw              r2,r2_save
6716
        iepp
6717
        iret
6718 43 robfinch
 
6719
; 1000 Hz interrupt
6720 46 robfinch
; This IRQ must be fast, so it's placed inline. It's also the first
6721
; IRQ checked for in the interrupt dispatch.
6722 43 robfinch
; Increments the millisecond counter, and switches to the next context
6723
;
6724
irq1000Hz:
6725 46 robfinch
        outb    r0,0xDCFFFD                             ; acknowledge interrupt
6726 43 robfinch
        lw              r1,Milliseconds                 ; increment milliseconds count
6727
        addui   r1,r1,#1
6728
        sw              r1,Milliseconds
6729 46 robfinch
        lw              sp,sp_save
6730
        lw              lr,lr_save
6731
        lw              r26,r26_save
6732
        lw              r1,r1_save
6733
        lw              r2,r2_save
6734 43 robfinch
        iepp                                                    ; move to the next context
6735
        iret                                                    ; return to the next context
6736
 
6737
; 100 Hz interrupt
6738
; This IRQ could have some work to do, including flashing a cursor. So
6739
; we call a subroutine.
6740
;
6741
irq100Hz:
6742
        lw              r1,p100IRQvec
6743
;       jal             lr,[r1]
6744
        call    Pulse100
6745 46 robfinch
irqret:
6746
        lw              sp,sp_save
6747
        lw              lr,lr_save
6748
        lw              r26,r26_save
6749
        lw              r1,r1_save
6750
        lw              r2,r2_save
6751
        iret
6752 43 robfinch
 
6753
irqSerial:
6754
        lw              r1,serialIRQvec
6755
        jal             lr,[r1]
6756
        bra             irqret
6757
 
6758
irqRaster:
6759
        lw              r1,rasterIRQvec
6760
;       jal             lr,[r1]
6761
        call    RasterIRQfn
6762
        bra             irqret
6763
 
6764
irqKeybd:
6765
        lw              r1,keybdIRQvec
6766 27 robfinch
        call    KeybdIRQ
6767 43 robfinch
;       jal             lr,[r1]
6768 46 robfinch
        bra             irqret
6769 43 robfinch
 
6770 46 robfinch
irqColdStart:
6771
        jmp             ColdStart
6772
 
6773
;------------------------------------------------------------------------------
6774
; NMI routine
6775
;
6776
; The NMI line is tied to the parity error signal. But also any non-initialized
6777
; interrupts get sent here.
6778
;------------------------------------------------------------------------------
6779
;
6780
nmirout:
6781
        sw              sp,sp_save
6782
        sw              r1,r1_save
6783
        sw              r26,r26_save
6784
        lw              sp,#0x100001000
6785
        outb    r0,0xDCFFFE             ; acknowledge interrupt
6786
        lea             r1,msgPerr
6787
        call    DisplayString
6788
        mfspr   r1,IPC
6789
        call    DisplayWord
6790
        call    CRLF
6791
        lw              sp,sp_save
6792
        lw              r1,r1_save
6793
        lw              r26,r26_save
6794 27 robfinch
        iret
6795
 
6796 46 robfinch
msgPerr:
6797
        db      "Parity error at: ",0
6798
 
6799
 
6800 27 robfinch
;-------------------------------------------
6801 46 robfinch
; Unimplemented instructions end up here
6802 27 robfinch
;-------------------------------------------
6803 46 robfinch
        .align 4
6804
ui_irout:
6805
        subui   sp,sp,#8
6806
        sw              r1,[sp]
6807
        lea             r1,msgUnimp
6808
        call    DisplayString
6809
        mfspr   r1,IPC
6810
        call    DisplayWord
6811
        call    CRLF
6812
        lw              r1,[sp]
6813
        addui   sp,sp,#8
6814
        ; hang the context
6815
ui_irout1:
6816
        bra             ui_irout1
6817 27 robfinch
        iret
6818
 
6819 46 robfinch
msgUnimp:
6820
        db      "Unimplemented instruction at: ",0
6821
 
6822 27 robfinch
;-------------------------------------------
6823
; Handle miss on Data TLB
6824
;-------------------------------------------
6825 46 robfinch
        .align  4
6826 27 robfinch
DTLBHandler:
6827
        sw              r1,0xFFFF_FFFF_FFFF_0000
6828
        sw              r2,0xFFFF_FFFF_FFFF_0008
6829
dh1:
6830
        omgi    r1,#0            ; try open mutex gate #0 (TLB protector)
6831
        bne             r1,r0,dh1       ; spinlock if gate is closed
6832
        mfspr   r1,PTA          ; get the page table address
6833
        mfspr   r2,BadVAddr     ; get the bad virtual address
6834
        mtspr   TLBVirtPage,r2  ; which virtual address to update
6835
        shrui   r2,r2,#13       ; turn va into index
6836
        addu    r1,r1,r2
6837
        lw              r2,[r1]         ; get the physical address from the table
6838
        and             r2,r2,#FFFF_FFFF_FFFF_E000      ; mask off lower bits
6839
        mtspr   TLBPhysPage0,r2 ;
6840
        lw              r2,8[r1]        ; get the physical address from the table
6841
        and             r2,r2,#FFFF_FFFF_FFFF_E000      ; mask off lower bits
6842
        mtspr   TLBPhysPage1,r2 ;
6843
        tlbwr                           ; update a random entry in the TLB
6844
        cmgi    #0                       ; close the mutex gate
6845
        lw              r1,0xFFFF_FFFF_FFFF_0000
6846
        lw              r2,0xFFFF_FFFF_FFFF_0008
6847
        iret
6848 43 robfinch
        .align  32
6849
 
6850 27 robfinch
        org             0xFFFF_FFFF_FFFF_FFB0
6851
        jmp             DTLBHandler
6852 10 robfinch
        nop
6853
        nop
6854 27 robfinch
        org             0xFFFF_FFFF_FFFF_FFC0
6855
        jmp             DTLBHandler
6856 10 robfinch
        nop
6857
        nop
6858 43 robfinch
 
6859 27 robfinch
        org     0xFFFF_FFFF_FFFF_FFE0
6860 46 robfinch
        dw              0                ; 
6861
        dw              0                ;
6862 43 robfinch
 
6863 46 robfinch
; RST vector
6864 10 robfinch
        org             0xFFFF_FFFF_FFFF_FFF0
6865
        jmp             start
6866 27 robfinch
 
6867 46 robfinch
; ROM checksum goes here
6868 27 robfinch
 
6869 46 robfinch
        org             0xFFFF_FFFF_FFFF_FFF8
6870
        dw              0

powered by: WebSVN 2.1.0

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