Line 1... |
Line 1... |
; ============================================================================
|
; ============================================================================
|
; (C) 2012 Robert Finch
|
; (C) 2012,2013 Robert Finch, Stratford
|
; All Rights Reserved.
|
; All Rights Reserved.
|
; robfinch<remove>@opencores.org
|
; robfinch<remove>@opencores.org
|
;
|
;
|
; This source file is free software: you can redistribute it and/or modify
|
; This source file is free software: you can redistribute it and/or modify
|
; it under the terms of the GNU Lesser General Public License as published
|
; it under the terms of the GNU Lesser General Public License as published
|
Line 23... |
Line 23... |
TAB EQU 0x09
|
TAB EQU 0x09
|
CTRLC EQU 0x03
|
CTRLC EQU 0x03
|
CTRLH EQU 0x08
|
CTRLH EQU 0x08
|
CTRLS EQU 0x13
|
CTRLS EQU 0x13
|
CTRLX EQU 0x18
|
CTRLX EQU 0x18
|
|
XON EQU 0x11
|
|
XOFF EQU 0x13
|
|
|
STACKTOP EQU 0xFFFF_FFFF_FFFE_FFF8
|
DATA_PRESENT EQU 0x01 ; there is data preset at the serial port bc_uart3
|
Milliseconds EQU 0x400
|
XMIT_NOT_FULL EQU 0x20
|
Lastloc EQU 0x408
|
|
ScreenColor EQU 0x414
|
BUFLEN EQU 80 ; length of keyboard input buffer
|
CursorRow EQU 0x416
|
|
CursorCol EQU 0x418
|
; Initial stack tops for contexts
|
KeybdEcho EQU 0x41A
|
; Each context gets 1k from the special 16k startup stack memory
|
KeybdBuffer EQU 0x440
|
;
|
KeybdHead EQU 0x450
|
STACKTOP0 EQU 0xFFFF_FFFF_FFFE_FFF8
|
KeybdTail EQU 0x451
|
STACKTOP1 EQU 0xFFFF_FFFF_FFFE_FBF8
|
TEXTSCR EQU 0xFFFF_FFFF_FFD0_0000
|
STACKTOP2 EQU 0xFFFF_FFFF_FFFE_F7F8
|
COLORSCR EQU 0xFFFF_FFFF_FFD1_0000
|
STACKTOP3 EQU 0xFFFF_FFFF_FFFE_F3F8
|
TEXTREG EQU 0xFFFFFFFF_FFDA0000
|
STACKTOP4 EQU 0xFFFF_FFFF_FFFE_EFF8
|
|
STACKTOP5 EQU 0xFFFF_FFFF_FFFE_EBF8
|
|
STACKTOP6 EQU 0xFFFF_FFFF_FFFE_E7F8
|
|
STACKTOP7 EQU 0xFFFF_FFFF_FFFE_E3F8
|
|
STACKTOP8 EQU 0xFFFF_FFFF_FFFE_DFF8
|
|
STACKTOP9 EQU 0xFFFF_FFFF_FFFE_DBF8
|
|
STACKTOP10 EQU 0xFFFF_FFFF_FFFE_D7F8
|
|
STACKTOP11 EQU 0xFFFF_FFFF_FFFE_D3F8
|
|
STACKTOP12 EQU 0xFFFF_FFFF_FFFE_CFF8
|
|
STACKTOP13 EQU 0xFFFF_FFFF_FFFE_CBF8
|
|
STACKTOP14 EQU 0xFFFF_FFFF_FFFE_C7F8
|
|
STACKTOP15 EQU 0xFFFF_FFFF_FFFE_C3F8
|
|
|
|
|
|
; BOOT ROM routines
|
|
|
|
TCBSize EQU 0x200 ; 512 bytes per TCB
|
|
TCBBase EQU 0x00000001_00000000 ; TCB pages
|
|
TCBr1 EQU 0x00
|
|
TCBr2 EQU 0x08
|
|
TCBr3 EQU 0x10
|
|
TCBr4 EQU 0x18
|
|
TCBr5 EQU 0x20
|
|
TCBr6 EQU 0x28
|
|
TCBr7 EQU 0x30
|
|
TCBr8 EQU 0x38
|
|
TCBr9 EQU 0x40
|
|
TCBr10 EQU 0x48
|
|
TCBr11 EQU 0x50
|
|
TCBr12 EQU 0x58
|
|
TCBr13 EQU 0x60
|
|
TCBr14 EQU 0x68
|
|
TCBr15 EQU 0x70
|
|
TCBr16 EQU 0x78
|
|
TCBr17 EQU 0x80
|
|
TCBr18 EQU 0x88
|
|
TCBr19 EQU 0x90
|
|
TCBr20 EQU 0x98
|
|
TCBr21 EQU 0xA0
|
|
TCBr22 EQU 0xA8
|
|
TCBr23 EQU 0xB0
|
|
TCBr24 EQU 0xB8
|
|
TCBr25 EQU 0xC0
|
|
TCBr26 EQU 0xC8
|
|
TCBr27 EQU 0xD0
|
|
TCBr28 EQU 0xD8
|
|
TCBr29 EQU 0xE0
|
|
TCBr30 EQU 0xE8
|
|
TCBr31 EQU 0xF0
|
|
|
|
warmStart EQU 0x1020
|
|
usrJmp EQU 0x1028
|
|
TickIRQAddr EQU 0x1030
|
|
TaskBlock EQU 0x1038
|
|
tencount EQU 0x13F8
|
|
Milliseconds EQU 0x1400
|
|
Lastloc EQU 0x1408
|
|
ScreenColor EQU 0x1414
|
|
CursorRow EQU 0x1416
|
|
CursorCol EQU 0x1418
|
|
CursorFlash EQU 0x141A
|
|
KeybdEcho EQU 0x141C
|
|
KeybdBuffer EQU 0x1440
|
|
KeybdHead EQU 0x1450
|
|
KeybdTail EQU 0x1451
|
|
Score EQU 0x1500
|
|
Manpos EQU 0x1508
|
|
MissileActive EQU 0x1510
|
|
MissileX EQU 0x1512
|
|
MissileY EQU 0x1514
|
|
InvadersRow1 EQU 0x1520
|
|
InvadersRow2 EQU 0x1530
|
|
InvadersRow3 EQU 0x1540
|
|
InvadersRow4 EQU 0x1550
|
|
InvadersRow5 EQU 0x1560
|
|
InvadersColpos EQU 0x1570
|
|
InvadersRowpos EQU 0x1571
|
|
Uart_rxfifo EQU 0x1600
|
|
Uart_rxhead EQU 0x1800
|
|
Uart_rxtail EQU 0x1802
|
|
Uart_ms EQU 0x1808
|
|
Uart_rxrts EQU 0x1809
|
|
Uart_rxdtr EQU 0x180A
|
|
Uart_rxxon EQU 0x180B
|
|
Uart_rxflow EQU 0x180C
|
|
Uart_fon EQU 0x180E
|
|
Uart_foff EQU 0x1810
|
|
Uart_txrts EQU 0x1812
|
|
Uart_txdtr EQU 0x1813
|
|
Uart_txxon EQU 0x1814
|
|
Uart_txxonoff EQU 0x1815
|
|
TaskList EQU 0x2000
|
|
ReadyList1 EQU 0x2000
|
|
ReadyList2 EQU 0x2020
|
|
ReadyList3 EQU 0x2040
|
|
ReadyList4 EQU 0x2060
|
|
ReadyList5 EQU 0x2080
|
|
ReadyNdx1 EQU 0x20A0
|
|
ReadyNdx2 EQU 0x20A1
|
|
ReadyNdx3 EQU 0x20A2
|
|
ReadyNdx4 EQU 0x20A3
|
|
ReadyNdx5 EQU 0x20A4
|
|
RunningTCB EQU 0x20A6
|
|
NextToRunTCB EQU 0x20A8
|
|
r1save EQU 0x20B0
|
|
r2save EQU 0x20B8
|
|
AXCstart EQU 0x20C0
|
|
|
|
p100IRQvec EQU 0x3000
|
|
keybdIRQvec EQU 0x3008
|
|
serialIRQvec EQU 0x3010
|
|
rasterIRQvec EQU 0x3018
|
|
|
|
TEXTSCR EQU 0xD0_0000
|
|
COLORSCR EQU 0xD1_0000
|
|
TEXTREG EQU 0xDA_0000
|
TEXT_COLS EQU 0x0
|
TEXT_COLS EQU 0x0
|
TEXT_ROWS EQU 0x2
|
TEXT_ROWS EQU 0x2
|
TEXT_CURPOS EQU 0x16
|
TEXT_CURPOS EQU 0x16
|
KEYBD EQU 0xFFFF_FFFF_FFDC_0000
|
KEYBD EQU 0xDC_0000
|
KEYBDCLR EQU 0xFFFF_FFFF_FFDC_0002
|
KEYBDCLR EQU 0xDC_0002
|
UART EQU 0xFFFF_FFFF_FFDC_0A00
|
|
UART_LS EQU 0xFFFF_FFFF_FFDC_0A01
|
UART EQU 0xDC_0A00
|
PIC EQU 0xFFFF_FFFF_FFDC_0FF0
|
UART_LS EQU 0xDC_0A01
|
PSG EQU 0xFFFF_FFFF_FFD5_0000
|
UART_MS EQU 0xDC_0A02
|
AC97 EQU 0xFFFF_FFFF_FFDC_1000
|
UART_IS EQU 0xDC_0A03
|
|
UART_IE EQU 0xDC_0A04
|
|
UART_MC EQU 0xDC_0A06
|
|
DATETIME EQU 0xDC_0400
|
|
PIC EQU 0xDC_0FF0
|
|
PIC_IE EQU 0xDC_0FF2
|
|
|
|
PSG EQU 0xD5_0000
|
|
PSGFREQ0 EQU 0xD5_0000
|
|
PSGPW0 EQU 0xD5_0002
|
|
PSGCTRL0 EQU 0xD5_0004
|
|
PSGADSR0 EQU 0xD5_0006
|
|
|
|
SPRRAM EQU 0xD8_0000
|
|
AC97 EQU 0xDC_1000
|
|
LED EQU 0xDC_0600
|
|
GACCEL EQU 0xDA_E000
|
|
RASTERIRQ EQU 0xDA_0100
|
BOOT_STACK EQU 0xFFFF_FFFF_FFFE_FFF8
|
BOOT_STACK EQU 0xFFFF_FFFF_FFFE_FFF8
|
|
SPRITEREGS EQU 0xDA_D000
|
BITMAPSCR EQU 0x00000001_00200000
|
BITMAPSCR EQU 0x00000001_00200000
|
|
|
txempty EQU 0x40
|
txempty EQU 0x40
|
rxfull EQU 0x01
|
rxfull EQU 0x01
|
|
|
|
;
|
|
; Internal variables follow:
|
|
;
|
|
bss
|
|
org 0x1038
|
|
txtWidth db 0 ; BIOS var =56
|
|
txtHeight db 0 ; BIOS var =31
|
|
cursx db 0 ; cursor x position
|
|
cursy db 0 ; cursor y position
|
|
pos dh 0 ; text screen position
|
|
org 0x1040
|
|
charToPrint dc 0
|
|
fgColor db 0
|
|
bkColor db 0
|
|
cursFlash db 0 ; flash the cursor ?
|
|
|
|
lineLinkTbl fill.b 25,0 ; screen line link table
|
|
align 8
|
|
|
|
org 0x1080
|
|
typef db 0 ; variable / expression type
|
|
align 8
|
|
OSSP dw 1 ; OS value of sp
|
|
CURRNT dw 1 ; Current line pointer
|
|
STKGOS dw 1 ; Saves stack pointer in 'GOSUB'
|
|
STKINP dw 1 ; Saves stack pointer during 'INPUT'
|
|
LOPVAR dw 1 ; 'FOR' loop save area
|
|
LOPINC dw 1 ; increment
|
|
LOPLMT dw 1 ; limit
|
|
LOPLN dw 1 ; line number
|
|
LOPPT dw 1 ; text pointer
|
|
TXTUNF dw 1 ; points to unfilled text area
|
|
VARBGN dw 1 ; points to variable area
|
|
IVARBGN dw 1 ; points to integer variable area
|
|
SVARBGN dw 1 ; points to string variable area
|
|
FVARBGN dw 1 ; points to float variable area
|
|
STKBOT dw 1 ; holds lower limit for stack growth
|
|
NUMWKA fill.b 24,0 ; numeric work area
|
|
BUFFER fill.b BUFLEN,0x00 ; Keyboard input buffer
|
|
|
|
bss
|
|
org 0x1_00600000
|
|
TXT equ 0x1_00600000 ; Beginning of program area
|
|
|
; org 0x070
|
; org 0x070
|
; iret
|
; iret
|
; nop
|
; nop
|
; nop
|
; nop
|
; nop
|
; nop
|
Line 64... |
Line 243... |
; nop
|
; nop
|
; nop
|
; nop
|
; nop
|
; nop
|
;
|
;
|
code
|
code
|
org 0xFFFF_FFFF_FFFF_E800
|
org 0xFFFF_FFFF_FFFF_B000
|
|
|
; jump table
|
; jump table
|
;
|
;
|
jmp SerialGetChar
|
jmp SerialGetChar
|
jmp SerialPutChar
|
jmp SerialPutChar
|
Line 82... |
Line 261... |
; lea MSGRAM,a1
|
; lea MSGRAM,a1
|
; jsr DisplayString
|
; jsr DisplayString
|
|
|
ColdStart:
|
ColdStart:
|
icache_on ; turn on the ICache
|
icache_on ; turn on the ICache
|
dcache_on ; turn on the DCache
|
dcache_off ; turn on the DCache
|
setlo sp,#STACKTOP ; top of stack
|
|
|
; Initialize the context schedule with all contexts treated equally
|
|
; There are only 16 contexts, but 256 schedule slots. Each context is
|
|
; given 16 slots distributed evenly throughout the execution pattern
|
|
; table.
|
|
;
|
|
xor r1,r1,r1 ; r1 = 0
|
|
ict1:
|
|
mtep r1,r1 ; only the low order four bits of r1 will move to the pattern table
|
|
addui r1,r1,#1
|
|
cmpi r2,r1,#255
|
|
bne r2,r0,ict1
|
|
|
|
; Point the interrupt return address register of the context to the
|
|
; context startup code. The context will start up when an interrupt return
|
|
; occurs.
|
|
;
|
|
; We cannot use a loop for this. Fortunately there's only 16 contexts.
|
|
;
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP0
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP1
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP2
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP3
|
|
iepp
|
|
nop
|
|
nop
|
|
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP4
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP5
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP6
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP7
|
|
iepp
|
|
nop
|
|
nop
|
|
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP8
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP9
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP10
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP11
|
|
iepp
|
|
nop
|
|
nop
|
|
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP12
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP13
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP14
|
|
iepp
|
|
nop
|
|
nop
|
|
lea r25,ctxstart
|
|
lea r30,STACKTOP15
|
|
iepp
|
|
nop
|
|
nop
|
|
|
|
; Ensure that context zero is the active context
|
|
;
|
|
ctxstart3:
|
|
mfspr r1,AXC
|
|
beq r1,r0,ctxstart2
|
|
iepp
|
|
nop
|
|
nop
|
|
bra ctxstart3
|
|
ctxstart2:
|
|
sb r1,AXCstart ; save off the startup context which should be context zero
|
|
|
|
; Entry point for context startup
|
|
;
|
|
; Avoid repeating all the system initialization when a context starts up by testing whether
|
|
; or not the context is the starting context.
|
|
;
|
|
ctxstart:
|
|
mfspr r1,AXC
|
|
lbu r2,AXCstart
|
|
bne r1,r2,ctxstart1
|
|
|
|
;
|
|
; set system vectors
|
|
; TBA defaults to zero on reset
|
|
;
|
|
setlo r3,#0
|
|
setlo r2,#511
|
|
lea r1,nmirout
|
|
csj5:
|
|
sw r1,[r3]
|
|
addui r3,r3,#8
|
|
loop r2,csj5
|
|
lea r1,KeybdSC ; keyboard BIOS vector
|
|
sw r1,0xD08
|
|
lea r1,irqrout
|
|
sw r1,0xE08 ; set IRQ vector
|
|
lea r1,dberr_rout
|
|
sw r1,0xFE0 ; set Bus error vector
|
|
lea r1,iberr_rout
|
|
sw r1,0xFE8 ; set Bus error vector
|
|
lea r1,nmirout
|
|
sw r1,0xFF0 ; set NMI vector
|
|
|
|
lea r1,KeybdIRQ
|
|
sw r1,keybdIRQvec
|
|
lea r1,Pulse100
|
|
sw r1,p100IRQvec
|
|
lea r1,SerialIRQ
|
|
sw r1,serialIRQvec
|
|
lea r1,RasterIRQfn
|
|
sw r1,rasterIRQvec
|
|
|
|
;-------------------------------
|
|
; Initialize I/O devices
|
|
;-------------------------------
|
|
call SerialInit
|
call KeybdInit
|
call KeybdInit
|
call PICInit
|
call PICInit
|
|
call SetupRasterIRQ
|
cli ; enable interrupts
|
cli ; enable interrupts
|
|
; call HelloWorld
|
setlo r3,#0xCE ; blue on blue
|
setlo r3,#0xCE ; blue on blue
|
sc r3,ScreenColor
|
sc r3,ScreenColor
|
lc r3,0x414
|
lc r3,0x1414
|
setlo r3,#32
|
setlo r3,#32
|
sc r3,0x416 ; we do a store, then a load through the dcache
|
sc r3,0x1416 ; we do a store, then a load through the dcache
|
lc r2,0x416 ;
|
lc r2,0x1416 ;
|
lc r2,0x416 ;
|
|
beq r2,r3,dcokay
|
beq r2,r3,dcokay
|
dcache_off ; data cache failed
|
dcache_off ; data cache failed
|
dcokay:
|
dcokay:
|
lc r3,ScreenColor
|
sc r0,NextToRunTCB
|
|
sc r0,RunningTCB
|
call ClearScreen
|
call ClearScreen
|
call ClearBmpScreen
|
call ClearBmpScreen
|
|
call RandomizeSprram
|
sc r0,CursorRow
|
sc r0,CursorRow
|
sc r0,CursorCol
|
sc r0,CursorCol
|
setlo r1,#<MSGSTART
|
setlo r1,#1
|
sethi r1,#>MSGSTART
|
sb r1,CursorFlash
|
call DisplayString
|
lea r1,MSGSTART
|
; call SetupAC97 ; and Beep
|
call DisplayStringCRLF
|
|
jmp Monitor
|
|
call SetupAC97 ; and Beep
|
|
setlo r3,#4
|
|
outb r3,LED
|
|
call Beep
|
|
|
; Allow some other contexts to start up
|
|
; equal processing time for sixteen contexts
|
|
;
|
|
mfspr r1,AXC ; which context am I
|
|
bne r1,r0,j4
|
|
setlo r1,#0x76543210
|
|
mtspr EP0,r1
|
|
mtspr EP2,r1
|
|
setlo r1,#0xFEDCBA98
|
|
mtspr EP1,r1
|
|
mtspr EP3,r1
|
|
j4:
|
j4:
|
jmp Monitor
|
jmp Monitor
|
bra j4
|
bra j4
|
|
|
|
; for now hang the contexts
|
|
;
|
|
ctxstart1:
|
|
bra ctxstart1
|
|
|
; call ramtest
|
; call ramtest
|
|
|
;-----------------------------------------
|
;-----------------------------------------
|
; Hello World!
|
; Hello World!
|
;-----------------------------------------
|
;-----------------------------------------
|
HelloWorld:
|
HelloWorld:
|
subui r30,r30,#24
|
subui r30,r30,#24
|
sm [r30],r1/r2/r31
|
sw r1,[sp]
|
setlo r2,#MSG
|
sw r2,8[sp]
|
|
sw lr,16[sp]
|
|
lea r2,MSG
|
j3:
|
j3:
|
lb r1,[r2]
|
lb r1,[r2]
|
beq r1,r0,j2
|
beq r1,r0,j2
|
call SerialPutChar
|
call SerialPutChar
|
addui r2,r2,#1
|
addui r2,r2,#1
|
bra j3
|
bra j3
|
j2:
|
j2:
|
lm [r30],r1/r2/r31
|
sw lr,16[sp]
|
|
sw r2,8[sp]
|
|
sw r1,[sp]
|
ret #24
|
ret #24
|
|
|
|
|
align 16
|
align 16
|
MSG:
|
MSG:
|
DB "Hello World!",0,0,0,0
|
db "Hello World!",0
|
align 16
|
|
MSGSTART:
|
MSGSTART:
|
db "Raptor64 system starting....",CR,LF,0,0
|
db "Raptor64 system starting....",0
|
|
|
align 16
|
align 16
|
|
|
;----------------------------------------------------------
|
;----------------------------------------------------------
|
; Initialize programmable interrupt controller (PIC)
|
; Initialize programmable interrupt controller (PIC)
|
; 0 = nmi
|
; 0 = nmi
|
; 1 = keyboard reset
|
; 1 = keyboard reset
|
; 2 = 1000Hz pulse (cursor flash)
|
; 2 = 1000Hz pulse (context switcher)
|
|
; 3 = 100Hz pulse (cursor flash)
|
|
; 8 = uart
|
|
; 13 = raster interrupt
|
; 15 = keyboard char
|
; 15 = keyboard char
|
;----------------------------------------------------------
|
;----------------------------------------------------------
|
PICInit:
|
PICInit:
|
setlo r1,#0x8007 ; enable nmi,kbd_rst,and kbd_irq
|
lea r1,PICret
|
outc r1,PIC+2
|
sw r1,TickIRQAddr
|
|
; enable: raster irq,
|
|
setlo r1,#0xA00F ; enable nmi,kbd_rst,and kbd_irq
|
|
; A10F enable serial IRQ
|
|
outc r1,PIC_IE
|
|
PICret:
|
ret
|
ret
|
|
|
|
;==============================================================================
|
|
; Serial port
|
|
;==============================================================================
|
;-----------------------------------------
|
;-----------------------------------------
|
; Get character from serial port
|
; Initialize the serial port
|
;-----------------------------------------
|
;-----------------------------------------
|
SerialGetChar:
|
;
|
subui r30,r30,#8
|
SerialInit:
|
sw r3,[r30]
|
sc r0,Uart_rxhead ; reset buffer indexes
|
setlo r1,#UART
|
sc r0,Uart_rxtail
|
|
setlo r1,#0x1f0
|
|
sc r1,Uart_foff ; set threshold for XOFF
|
|
setlo r1,#0x010
|
|
sc r1,Uart_fon ; set threshold for XON
|
|
setlo r1,#1
|
|
outb r1,UART_IE ; enable receive interrupt only
|
|
sb r0,Uart_rxrts ; no RTS/CTS signals available
|
|
sb r0,Uart_txrts ; no RTS/CTS signals available
|
|
sb r0,Uart_txdtr ; no DTR signals available
|
|
sb r0,Uart_rxdtr ; no DTR signals available
|
|
setlo r1,#1
|
|
sb r1,Uart_txxon ; for now
|
|
ret
|
|
|
|
;---------------------------------------------------------------------------------
|
|
; Get character directly from serial port. Blocks until a character is available.
|
|
;---------------------------------------------------------------------------------
|
|
;
|
|
SerialGetCharDirect:
|
sgc1:
|
sgc1:
|
inb r3,1[r1] ; uart status
|
inb r1,UART_LS ; uart status
|
andi r3,r3,#rxfull ; is there a char available ?
|
andi r1,r1,#rxfull ; is there a char available ?
|
beq r3,r0,sgc1
|
beq r1,r0,sgc1
|
lw r3,[r30]
|
inb r1,UART
|
inb r1,[r1]
|
ret
|
ret #8
|
|
|
;------------------------------------------------
|
|
; Check for a character at the serial port
|
|
; returns r1 = 1 if char available, 0 otherwise
|
|
;------------------------------------------------
|
|
;
|
|
SerialCheckForCharDirect:
|
|
inb r1,UART_LS ; uart status
|
|
andi r1,r1,#rxfull ; is there a char available ?
|
|
sne r1,r1,r0
|
|
ret
|
|
|
;-----------------------------------------
|
;-----------------------------------------
|
; Put character to serial port
|
; Put character to serial port
|
|
; r1 = char to put
|
;-----------------------------------------
|
;-----------------------------------------
|
|
;
|
SerialPutChar:
|
SerialPutChar:
|
subui r30,r30,#16
|
subui sp,sp,#32
|
sw r2,8[r30]
|
sw r2,[sp]
|
sw r3,[r30]
|
sw r3,8[sp]
|
setlo r3,#UART
|
sw r4,16[sp]
|
spc1:
|
sw r5,24[sp]
|
inb r2,1[r3] ; uart status
|
inb r2,UART_MC
|
andi r2,r2,#txempty ; is there a char available ?
|
ori r2,r2,#3 ; assert DTR / RTS
|
beq r2,r0,spc1
|
outb r2,UART_MC
|
outb r1,[r3]
|
lb r2,Uart_txrts
|
lw r3,[r30]
|
beq r2,r0,spcb1
|
lw r2,8[r30]
|
lw r4,Milliseconds
|
ret #16
|
setlo r3,#100 ; delay count (1 s)
|
|
spcb3:
|
|
inb r2,UART_MS
|
|
andi r2,r2,#10 ; is CTS asserted ?
|
|
bne r2,r0,spcb1
|
|
lw r5,Milliseconds
|
|
beq r4,r5,spcb3
|
|
mov r4,r5
|
|
loop r3,spcb3
|
|
bra spcabort
|
|
spcb1:
|
|
lb r2,Uart_txdtr
|
|
beq r2,r0,spcb2
|
|
lw r4,Milliseconds
|
|
setlo r3,#100 ; delay count
|
|
spcb4:
|
|
inb r2,UART_MS
|
|
andi r2,r2,#20 ; is DSR asserted ?
|
|
bne r2,r0,spcb2
|
|
lw r5,Milliseconds
|
|
beq r4,r5,spcb4
|
|
mov r4,r5
|
|
loop r3,spcb4
|
|
bra spcabort
|
|
spcb2:
|
|
lb r2,Uart_txxon
|
|
beq r2,r0,spcb5
|
|
spcb6:
|
|
lb r2,Uart_txxonoff
|
|
beq r2,r0,spcb5
|
|
inb r4,UART_MS
|
|
andi r4,r4,#0x80 ; DCD ?
|
|
bne r4,r0,spcb6
|
|
spcb5:
|
|
lw r4,Milliseconds
|
|
setlo r3,#100 ; wait up to 1s
|
|
spcb8:
|
|
inb r2,UART_LS
|
|
andi r2,r2,#0x20 ; tx not full ?
|
|
bne r2,r0,spcb7
|
|
lw r5,Milliseconds
|
|
beq r4,r5,spcb8
|
|
mov r4,r5
|
|
loop r3,spcb8
|
|
bra spcabort
|
|
spcb7:
|
|
outb r1,UART
|
|
spcabort:
|
|
lw r2,[sp]
|
|
lw r3,8[sp]
|
|
lw r4,16[sp]
|
|
lw r5,24[sp]
|
|
ret #32
|
|
|
|
;-------------------------------------------------
|
|
; Compute number of characters in recieve buffer.
|
|
; r4 = number of chars
|
|
;-------------------------------------------------
|
|
CharsInRxBuf:
|
|
lc r4,Uart_rxhead
|
|
lc r2,Uart_rxtail
|
|
subu r4,r4,r2
|
|
bgt r4,r0,cirxb1
|
|
setlo r4,#0x200
|
|
addu r4,r4,r2
|
|
lc r2,Uart_rxhead
|
|
subu r4,r4,r2
|
|
cirxb1:
|
|
ret
|
|
|
|
;----------------------------------------------
|
|
; Get character from rx fifo
|
|
; If the fifo is empty enough then send an XON
|
|
;----------------------------------------------
|
|
;
|
|
SerialGetChar:
|
|
subui sp,sp,#32
|
|
sw r2,[sp]
|
|
sw r3,8[sp]
|
|
sw r4,16[sp]
|
|
sw lr,24[sp]
|
|
lc r3,Uart_rxhead
|
|
lc r2,Uart_rxtail
|
|
beq r2,r3,sgcfifo1 ; is there a char available ?
|
|
lea r3,Uart_rxfifo
|
|
lb r1,[r2+r3] ; get the char from the fifo into r1
|
|
addui r2,r2,#1 ; increment the fifo pointer
|
|
andi r2,r2,#0x1ff
|
|
sc r2,Uart_rxtail
|
|
lb r2,Uart_rxflow ; using flow control ?
|
|
beq r2,r0,sgcfifo2
|
|
lc r3,Uart_fon ; enough space in Rx buffer ?
|
|
call CharsInRxBuf
|
|
bgt r4,r3,sgcfifo2
|
|
sb r0,Uart_rxflow ; flow off
|
|
lb r4,Uart_rxrts
|
|
beq r4,r0,sgcfifo3
|
|
inb r4,UART_MC ; set rts bit in MC
|
|
ori r4,r4,#2
|
|
outb r4,UART_MC
|
|
sgcfifo3:
|
|
lb r4,Uart_rxdtr
|
|
beq r4,r0,sgcfifo4
|
|
inb r4,UART_MC ; set DTR
|
|
ori r4,r4,#1
|
|
outb r4,UART_MC
|
|
sgcfifo4:
|
|
lb r4,Uart_rxxon
|
|
beq r4,r0,sgcfifo5
|
|
setlo r4,#XON
|
|
outb r4,UART
|
|
sgcfifo5:
|
|
sgcfifo2: ; return with char in r1
|
|
lw r2,[sp]
|
|
lw r3,8[sp]
|
|
lw r4,16[sp]
|
|
lw lr,24[sp]
|
|
ret #32
|
|
sgcfifo1:
|
|
setlo r1,#-1 ; no char available
|
|
lw r2,[sp]
|
|
lw r3,8[sp]
|
|
lw r4,16[sp]
|
|
lw lr,24[sp]
|
|
ret #32
|
|
|
|
;-----------------------------------------
|
|
; Serial port IRQ
|
|
;-----------------------------------------
|
|
;
|
|
SerialIRQ:
|
|
subui sp,sp,#40
|
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw r4,24[sp]
|
|
sw lr,32[sp]
|
|
inb r1,UART_IS ; get interrupt status
|
|
bge r1,r0,sirq1
|
|
andi r1,r1,#0x7f ; switch on interrupt type
|
|
beqi r1,#4,srxirq
|
|
beqi r1,#0xC,stxirq
|
|
beqi r1,#0x10,smsirq
|
|
sirq1:
|
|
lw r1,[sp]
|
|
lw r2,8[sp]
|
|
lw r3,16[sp]
|
|
lw r4,24[sp]
|
|
lw lr,32[sp]
|
|
ret #40
|
|
|
|
; Get the modem status and record it
|
|
smsirq:
|
|
inb r1,UART_MS
|
|
sb r1,Uart_ms
|
|
bra sirq1
|
|
|
|
stxirq:
|
|
bra sirq1
|
|
|
|
; Get a character from the uart and store it in the rx fifo
|
|
srxirq:
|
|
srxirq1:
|
|
inb r1,UART ; get the char (clears interrupt)
|
|
lb r2,Uart_txxon
|
|
beq r2,r0,srxirq3
|
|
bnei r1,#XOFF,srxirq2
|
|
setlo r1,#1
|
|
sb r1,Uart_txxonoff
|
|
bra srxirq5
|
|
srxirq2:
|
|
bnei r1,#XON,srxirq3
|
|
sb r0,Uart_txxonoff
|
|
bra srxirq5
|
|
srxirq3:
|
|
sb r0,Uart_txxonoff
|
|
lc r2,Uart_rxhead
|
|
lea r3,Uart_rxfifo
|
|
sb r1,[r3+r2] ; store in buffer
|
|
addui r2,r2,#1
|
|
andi r2,r2,#0x1ff
|
|
sc r2,Uart_rxhead
|
|
srxirq5:
|
|
inb r1,UART_LS ; check for another ready character
|
|
andi r1,r1,#rxfull
|
|
bne r1,r0,srxirq1
|
|
lb r1,Uart_rxflow ; are we using flow controls?
|
|
bne r1,r0,srxirq8
|
|
call CharsInRxBuf
|
|
lc r1,Uart_foff
|
|
blt r4,r1,srxirq8
|
|
setlo r1,#1
|
|
sb r1,Uart_rxflow
|
|
lb r1,Uart_rxrts
|
|
beq r1,r0,srxirq6
|
|
inb r1,UART_MC
|
|
andi r1,r1,#0xFD ; turn off RTS
|
|
outb r1,UART_MC
|
|
srxirq6:
|
|
lb r1,Uart_rxdtr
|
|
beq r1,r0,srxirq7
|
|
inb r1,UART_MC
|
|
andi r1,r1,#0xFE ; turn off DTR
|
|
outb r1,UART_MC
|
|
srxirq7:
|
|
lb r1,Uart_rxxon
|
|
beq r1,r0,srxirq8
|
|
setlo r1,#XOFF
|
|
outb r1,UART
|
|
srxirq8:
|
|
bra sirq1
|
|
|
;==============================================================================
|
;==============================================================================
|
; Keyboard
|
; Keyboard BIOS
|
|
; BIOS interrupt #417
|
|
;
|
|
; Function in R1
|
|
; 0 = initialize keyboard
|
|
; 1 = set keyboard echo
|
|
; 2 = get keyboard character
|
|
; 3 = check for key available
|
;==============================================================================
|
;==============================================================================
|
|
;
|
|
KeybdSC:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
bnei r1,#0,kbdsc1
|
|
call KeybdInit
|
|
bra kbdscRet
|
|
kbdsc1:
|
|
bnei r1,#1,kbdsc2
|
|
mov r1,r2
|
|
call SetKeyboardEcho
|
|
bra kbdscRet
|
|
kbdsc2:
|
|
bnei r1,#2,kbdsc3
|
|
call KeybdGetChar
|
|
bra kbdscRet
|
|
kbdsc3:
|
|
bnei r1,#3,kbdsc4
|
|
call KeybdCheckForKey
|
|
bra kbdscRet
|
|
kbdsc4:
|
|
kbdscRet:
|
|
lw lr,[sp]
|
|
addui sp,sp,#8
|
|
eret
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Initialize keyboard
|
; Initialize keyboard
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
KeybdInit:
|
KeybdInit:
|
sb r0,KeybdHead
|
sb r0,KeybdHead
|
Line 214... |
Line 842... |
; Normal keyboard interrupt, the lowest priority interrupt in the system.
|
; Normal keyboard interrupt, the lowest priority interrupt in the system.
|
; Grab the character from the keyboard device and store it in a buffer.
|
; Grab the character from the keyboard device and store it in a buffer.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
KeybdIRQ:
|
KeybdIRQ:
|
subui sp,sp,#24
|
subui sp,sp,#8
|
sm [sp],r1/r2/r3
|
sw r2,[sp]
|
lbu r1,KeybdHead
|
lbu r1,KeybdHead
|
andi r1,r1,#0x0f ; r1 = index into buffer
|
andi r1,r1,#0x0f ; r1 = index into buffer
|
setlo r3,#<KeybdBuffer
|
|
sethi r3,#>KeybdBuffer
|
|
KeybdIRQa:
|
KeybdIRQa:
|
inch r2,KEYBD ; get keyboard character
|
inch r2,KEYBD ; get keyboard character
|
outc r0,KEYBD+2 ; clear keyboard strobe (turns off the IRQ)
|
outc r0,KEYBD+2 ; clear keyboard strobe (turns off the IRQ)
|
sb r2,[r3+r1] ; store character in buffer
|
sb r2,KeybdBuffer[r1] ; store character in buffer
|
addui r1,r1,#1 ; increment head index
|
addui r1,r1,#1 ; increment head index
|
andi r1,r1,#0x0f
|
andi r1,r1,#0x0f
|
sb r1,KeybdHead
|
sb r1,KeybdHead
|
KeybdIRQb:
|
KeybdIRQb:
|
lbu r2,KeybdTail ; check to see if we've collided
|
lbu r2,KeybdTail ; check to see if we've collided
|
bne r1,r2,KeybdIRQc ; with the tail
|
bne r1,r2,KeybdIRQc ; with the tail
|
addui r2,r2,#1 ; if so, increment the tail index
|
addui r2,r2,#1 ; if so, increment the tail index
|
andi r2,r2,#0x0f ; the oldest character will be lost
|
andi r2,r2,#0x0f ; the oldest character will be lost
|
sb r2,KeybdTail
|
sb r2,KeybdTail
|
KeybdIRQc:
|
KeybdIRQc:
|
lm [sp],r1/r2/r3
|
lw r2,[sp]
|
addui sp,sp,#24
|
ret #8
|
ret
|
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; r1 0=echo off, non-zero = echo on
|
; r1 0=echo off, non-zero = echo on
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
SetKeyboardEcho:
|
SetKeyboardEcho:
|
Line 250... |
Line 875... |
;-----------------------------------------
|
;-----------------------------------------
|
; Get character from keyboard buffer
|
; Get character from keyboard buffer
|
;-----------------------------------------
|
;-----------------------------------------
|
KeybdGetChar:
|
KeybdGetChar:
|
subui sp,sp,#16
|
subui sp,sp,#16
|
sm [sp],r2/r3
|
sw r2,[sp]
|
|
sw lr,8[sp]
|
lbu r2,KeybdTail
|
lbu r2,KeybdTail
|
lbu r1,KeybdHead
|
lbu r1,KeybdHead
|
beq r1,r2,nochar
|
beq r1,r2,nochar
|
setlo r3,#KeybdBuffer
|
lbu r1,KeybdBuffer[r2]
|
lbu r1,[r3+r2]
|
|
addui r2,r2,#1
|
addui r2,r2,#1
|
andi r2,r2,#0x0f
|
andi r2,r2,#0x0f
|
sb r2,KeybdTail
|
sb r2,KeybdTail
|
lm [sp],r2/r3
|
lb r2,KeybdEcho
|
ret #16
|
beq r2,r0,kgc3
|
|
bnei r1,#CR,kgc2
|
|
call CRLF ; convert CR keystroke into CRLF
|
|
bra kgc3
|
|
kgc2:
|
|
call DisplayChar
|
|
bra kgc3
|
nochar:
|
nochar:
|
setlo r1,#-1
|
setlo r1,#-1
|
lm [sp],r2/r3
|
kgc3:
|
|
lw lr,8[sp]
|
|
lw r2,[sp]
|
ret #16
|
ret #16
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Check if there is a keyboard character available in the keyboard buffer.
|
; Check if there is a keyboard character available in the keyboard buffer.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
KeybdCheckForKey:
|
KeybdCheckForKey:
|
lbu r1,KeybdTail
|
lbu r1,KeybdTail
|
lbu r2,KeybdHead
|
lbu r2,KeybdHead
|
beq r1,r2,kck1
|
sne r1,r1,r2
|
setlo r1,#1
|
|
ret
|
|
kck1:
|
|
xor r1,r1,r1 ; return zero
|
|
ret
|
ret
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Check if there is a keyboard character available. If so return true (1)
|
; Check if there is a keyboard character available. If so return true (1)
|
; otherwise return false (0) in r1.
|
; otherwise return false (0) in r1.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
KeybdCheckForKeyDirect:
|
KeybdCheckForKeyDirect:
|
inch r1,KEYBD
|
inch r1,KEYBD
|
bge r1,r0,cfkd1
|
slt r1,r1,r0
|
setlo r1,#1
|
|
ret
|
|
cfkd1:
|
|
xor r1,r1,r1 ; return 0 in r1
|
|
ret
|
ret
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Get character directly from keyboard. This routine blocks until a key is
|
; Get character directly from keyboard. This routine blocks until a key is
|
; available.
|
; available.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
KeybdGetCharDirect:
|
KeybdGetCharDirect:
|
subui sp,sp,#16
|
subui sp,sp,#16
|
sm [sp],r2/r31
|
sw r2,[sp]
|
|
sw lr,8[sp]
|
setlo r2,KEYBD
|
setlo r2,KEYBD
|
kgc1:
|
kgc1:
|
inch r1,KEYBD
|
inch r1,KEYBD
|
bge r1,r0,kgc1
|
bge r1,r0,kgc1
|
outc r0,KEYBD+2 ; clear keyboard strobe
|
outc r0,KEYBD+2 ; clear keyboard strobe
|
Line 316... |
Line 942... |
call CRLF
|
call CRLF
|
bra gk1
|
bra gk1
|
gk2:
|
gk2:
|
call DisplayChar
|
call DisplayChar
|
gk1:
|
gk1:
|
lm [sp],r2/r31
|
lw r2,[sp]
|
|
lw lr,8[sp]
|
ret #16
|
ret #16
|
|
|
;==============================================================================
|
;==============================================================================
|
;==============================================================================
|
;==============================================================================
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; 1000 Hz interrupt
|
; 100 Hz interrupt
|
; - takes care of "flashing" the cursor
|
; - takes care of "flashing" the cursor
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
Pulse1000:
|
Pulse100:
|
subui sp,sp,#24
|
subui sp,sp,#8
|
sm [sp],r1/r2/lr
|
sw lr,[sp]
|
lw r1,Milliseconds
|
lea r2,TEXTSCR
|
addui r1,r1,#1
|
inch r1,334[r2]
|
sw r1,Milliseconds
|
|
setlo r2,TEXTSCR
|
|
lc r1,222[r2]
|
|
addui r1,r1,#1
|
addui r1,r1,#1
|
sc r1,222[r2]
|
outc r1,334[r2]
|
lc r0,0xFFFF_FFFF_FFFF_0000 ; clear interrupt
|
call DisplayDatetime
|
lw r1,Milliseconds
|
call SelectNextToRunTCB
|
andi r1,r1,#0x7f
|
call SwitchTask
|
bnei r1,#64,p10001
|
sb r0,0xFFFF_FFFF_FFFF_0010 ; clear interrupt
|
call FlashCursor
|
; lw r1,TickIRQAddr
|
p10001:
|
; jal r31,[r1]
|
lm [sp],r1/r2/lr
|
; lw r1,Milliseconds
|
ret #24
|
; andi r1,r1,#0x0f
|
|
; bnei r1,#5,p1001
|
|
; call FlashCursor
|
|
p1001:
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
;------------------------------------------------------------------------------
|
|
;------------------------------------------------------------------------------
|
|
SelectNextToRunTCB:
|
|
sc r0,NextToRunTCB
|
|
ret
|
|
|
|
;------------------------------------------------------------------------------
|
|
; Switch from the RunningTCB to the NextToRunTCB
|
|
;------------------------------------------------------------------------------
|
|
SwitchTask:
|
|
sw r1,r1save
|
|
sw r2,r2save
|
|
lcu r1,NextToRunTCB
|
|
lcu r2,RunningTCB
|
|
bne r1,r2,swtsk1 ; are we already running this TCB ?
|
|
lw r1,r1save
|
|
lw r2,r2save
|
|
ret
|
|
swtsk1:
|
|
andi r2,r2,#0x1ff ; max 512 TCB's
|
|
mului r2,r2,#TCBSize
|
|
addui r2,r2,#TCBBase
|
|
lw r1,r1save ; get back r1
|
|
sw r1,TCBr1[r2]
|
|
lw r1,r2save ; get back r2
|
|
sw r1,TCBr2[r2]
|
|
sw r3,TCBr3[r2]
|
|
sw r4,TCBr4[r2]
|
|
sw r5,TCBr5[r2]
|
|
sw r6,TCBr6[r2]
|
|
sw r7,TCBr7[r2]
|
|
sw r8,TCBr8[r2]
|
|
sw r9,TCBr9[r2]
|
|
sw r10,TCBr10[r2]
|
|
sw r11,TCBr11[r2]
|
|
sw r12,TCBr12[r2]
|
|
sw r13,TCBr13[r2]
|
|
sw r14,TCBr14[r2]
|
|
sw r15,TCBr15[r2]
|
|
sw r16,TCBr16[r2]
|
|
sw r17,TCBr17[r2]
|
|
sw r18,TCBr18[r2]
|
|
sw r19,TCBr19[r2]
|
|
sw r20,TCBr20[r2]
|
|
sw r21,TCBr21[r2]
|
|
sw r22,TCBr22[r2]
|
|
sw r23,TCBr23[r2]
|
|
sw r24,TCBr24[r2]
|
|
sw r25,TCBr25[r2]
|
|
sw r26,TCBr26[r2]
|
|
sw r27,TCBr27[r2]
|
|
sw r28,TCBr28[r2]
|
|
sw r29,TCBr29[r2]
|
|
sw r30,TCBr30[r2]
|
|
sw r31,TCBr31[r2]
|
|
|
|
lcu r2,NextToRunTCB
|
|
sc r2,RunningTCB
|
|
mului r2,r2,#TCBSize
|
|
addui r2,r2,#TCBBase
|
|
|
|
lw r1,TCBr1[r2]
|
|
lw r3,TCBr3[r2]
|
|
lw r4,TCBr4[r2]
|
|
lw r5,TCBr5[r2]
|
|
lw r6,TCBr6[r2]
|
|
lw r7,TCBr7[r2]
|
|
lw r8,TCBr8[r2]
|
|
lw r9,TCBr9[r2]
|
|
lw r10,TCBr10[r2]
|
|
lw r11,TCBr11[r2]
|
|
lw r12,TCBr12[r2]
|
|
lw r13,TCBr13[r2]
|
|
lw r14,TCBr14[r2]
|
|
lw r15,TCBr15[r2]
|
|
lw r16,TCBr16[r2]
|
|
lw r17,TCBr17[r2]
|
|
lw r18,TCBr18[r2]
|
|
lw r19,TCBr19[r2]
|
|
lw r20,TCBr20[r2]
|
|
lw r21,TCBr21[r2]
|
|
lw r22,TCBr22[r2]
|
|
lw r23,TCBr23[r2]
|
|
lw r24,TCBr24[r2]
|
|
lw r25,TCBr25[r2]
|
|
lw r26,TCBr26[r2]
|
|
lw r27,TCBr27[r2]
|
|
lw r28,TCBr28[r2]
|
|
lw r29,TCBr29[r2]
|
|
lw r30,TCBr30[r2]
|
|
lw r31,TCBr31[r2]
|
|
lw r2,TCBr2[r2]
|
|
ret
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Flash Cursor
|
; Flash Cursor
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
FlashCursor:
|
FlashCursor:
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/r31
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
call CalcScreenLoc
|
call CalcScreenLoc
|
addui r1,r1,#0x10000
|
addui r1,r1,#0x10000
|
|
lb r2,CursorFlash
|
|
beq r2,r0,flshcrsr2
|
; causes screen colors to flip around
|
; causes screen colors to flip around
|
lc r2,[r1]
|
inch r2,[r1]
|
addui r2,r2,#1
|
addui r2,r2,#1
|
sc r2,[r1]
|
outc r2,[r1]
|
|
flshcrsr3:
|
lw r2,Lastloc
|
lw r2,Lastloc
|
beq r1,r2,flshcrsr1
|
beq r1,r2,flshcrsr1
|
; restore the screen colors of the previous cursor location
|
; restore the screen colors of the previous cursor location
|
lc r3,ScreenColor
|
lc r3,ScreenColor
|
sc r3,[r2]
|
outc r3,[r2]
|
sw r1,Lastloc
|
sw r1,Lastloc
|
flshcrsr1:
|
flshcrsr1:
|
lm [sp],r1/r2/r3/r31
|
lw r1,[sp]
|
|
lw r2,8[sp]
|
|
lw r3,16[sp]
|
|
lw lr,24[sp]
|
ret #32
|
ret #32
|
|
flshcrsr2:
|
|
lc r3,ScreenColor
|
|
outc r3,[r1]
|
|
bra flshcrsr3
|
|
|
|
CursorOff:
|
|
lw r1,#0xA0
|
|
outc r1,TEXTREG+16 ; turn off cursor
|
|
ret
|
|
CursorOn:
|
|
lw r1,#0xE0
|
|
outc r1,TEXTREG+16 ; turn on cursor
|
|
ret
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
ClearBmpScreen:
|
ClearBmpScreen:
|
subui sp,sp,#40
|
subui sp,sp,#24
|
sm [sp],r1/r2/r3/r4/r31
|
sw r1,[sp]
|
setlo r1,#1364 ; calc number to clear
|
sw r2,8[sp]
|
setlo r2,#768
|
sw r3,16[sp]
|
mulu r2,r1,r2 ; r2 = # pixels to clear
|
lw r2,#1364*768
|
or r4,r0,r2 ; r4 = # pixels to clear
|
shrui r2,r2,#3 ; r2 = # words to clear
|
setlo r1,#0x29292929 ;
|
lea r1,0x2929292929292929 ; r1 = color for eight pixels
|
setlo r3,#<BITMAPSCR ; screen address
|
lea r3,BITMAPSCR ; r3 = screen address
|
sethi r3,#>BITMAPSCR
|
|
csj4:
|
csj4:
|
sh r1,[r3]
|
sw r1,[r3] ; store pixel data
|
addui r3,r3,#4
|
addui r3,r3,#8 ; advance screen address by eight
|
loop r2,csj4
|
loop r2,csj4 ; decrement pixel count and loop back
|
lm [sp],r1/r2/r3/r4/r31
|
lw r1,[sp]
|
ret #40
|
lw r2,8[sp]
|
|
lw r3,16[sp]
|
|
ret #24
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Clear the screen and the screen color memory
|
; Clear the screen and the screen color memory
|
; We clear the screen to give a visual indication that the system
|
; We clear the screen to give a visual indication that the system
|
; is working at all.
|
; is working at all.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
ClearScreen:
|
ClearScreen:
|
subui sp,sp,#40
|
subui sp,sp,#40
|
sm [sp],r1/r2/r3/r4/r31
|
sw r1,[sp]
|
setlo r3,#TEXTREG
|
sw r2,8[sp]
|
lc r1,TEXT_COLS[r3] ; calc number to clear
|
sw r3,16[sp]
|
lc r2,TEXT_ROWS[r3]
|
sw r4,24[sp]
|
|
sw lr,32[sp]
|
|
lea r3,TEXTREG
|
|
inch r1,TEXT_COLS[r3] ; calc number to clear
|
|
inch r2,TEXT_ROWS[r3]
|
mulu r2,r1,r2 ; r2 = # chars to clear
|
mulu r2,r1,r2 ; r2 = # chars to clear
|
setlo r1,#32 ; space char
|
setlo r1,#32 ; space char
|
lc r4,ScreenColor
|
lc r4,ScreenColor
|
call AsciiToScreen
|
call AsciiToScreen
|
setlo r3,#TEXTSCR ; text screen address
|
lea r3,TEXTSCR ; text screen address
|
csj4:
|
csj4:
|
sc r1,[r3]
|
outc r1,[r3]
|
sc r4,0x10000[r3] ; color screen is 0x10000 higher
|
outc r4,0x10000[r3] ; color screen is 0x10000 higher
|
addu r3,r3,#2
|
addui r3,r3,#2
|
loop r2,csj4
|
loop r2,csj4
|
lm [sp],r1/r2/r3/r4/r31
|
lw lr,32[sp]
|
|
lw r4,24[sp]
|
|
lw r3,16[sp]
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
ret #40
|
ret #40
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Scroll text on the screen upwards
|
; Scroll text on the screen upwards
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
ScrollUp:
|
ScrollUp:
|
subui sp,sp,#40
|
subui sp,sp,#40
|
sm [sp],r1/r2/r3/r4/r31
|
sw r1,[sp]
|
setlo r3,#TEXTREG
|
sw r2,8[sp]
|
lc r1,TEXT_COLS[r3] ; r1 = # text columns
|
sw r3,16[sp]
|
lc r2,TEXT_ROWS[r3]
|
sw r4,24[sp]
|
|
sw lr,32[sp]
|
|
lea r3,TEXTREG
|
|
inch r1,TEXT_COLS[r3] ; r1 = # text columns
|
|
inch r2,TEXT_ROWS[r3]
|
mulu r2,r1,r2 ; calc number of chars to scroll
|
mulu r2,r1,r2 ; calc number of chars to scroll
|
subu r2,r2,r1 ; one less row
|
subu r2,r2,r1 ; one less row
|
setlo r3,#TEXTSCR
|
lea r3,TEXTSCR
|
scrup1:
|
scrup1:
|
lc r4,[r3+r1] ; indexed addressing example
|
inch r4,[r3+r1] ; indexed addressing example
|
sc r4,[r3]
|
outc r4,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
loop r2,scrup1
|
loop r2,scrup1
|
|
|
setlo r3,#TEXTREG
|
lea r3,TEXTREG
|
lc r1,TEXT_ROWS[r3]
|
inch r1,TEXT_ROWS[r3]
|
subui r1,r1,#1
|
subui r1,r1,#1
|
call BlankLine
|
call BlankLine
|
lm [sp],r1/r2/r3/r4/r31
|
lw r1,[sp]
|
|
lw r2,8[sp]
|
|
lw r3,16[sp]
|
|
lw r4,24[sp]
|
|
lw lr,32[sp]
|
ret #40
|
ret #40
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Blank out a line on the display
|
; Blank out a line on the display
|
; line number to blank is in r1
|
; line number to blank is in r1
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
BlankLine:
|
BlankLine:
|
subui sp,sp,#24
|
subui sp,sp,#24
|
sm [sp],r1/r2/r3
|
sw r1,[sp]
|
setlo r3,TEXTREG ; r3 = text register address
|
sw r2,8[sp]
|
lc r2,TEXT_COLS[r3] ; r2 = # chars to blank out
|
sw r3,16[sp]
|
|
lea r3,TEXTREG ; r3 = text register address
|
|
inch r2,TEXT_COLS[r3] ; r2 = # chars to blank out
|
mulu r3,r2,r1
|
mulu r3,r2,r1
|
shli r3,r3,#1
|
shli r3,r3,#1
|
addui r3,r3,#TEXTSCR ; r3 = screen address
|
addui r3,r3,#TEXTSCR ; r3 = screen address
|
setlo r1,#' '
|
setlo r1,#' '
|
blnkln1:
|
blnkln1:
|
sc r1,[r3]
|
outc r1,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
loop r2,blnkln1
|
loop r2,blnkln1
|
lm [sp],r1/r2/r3
|
lw r1,[sp]
|
|
lw r2,8[sp]
|
|
lw r3,16[sp]
|
ret #24
|
ret #24
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Convert ASCII character to screen display character.
|
; Convert ASCII character to screen display character.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
Line 495... |
Line 1261... |
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
CalcScreenLoc:
|
CalcScreenLoc:
|
lc r1,CursorRow
|
lc r1,CursorRow
|
andi r1,r1,#0x7f
|
andi r1,r1,#0x7f
|
setlo r3,TEXTREG
|
lea r3,TEXTREG
|
inch r2,TEXT_COLS[r3]
|
inch r2,TEXT_COLS[r3]
|
mulu r2,r2,r1
|
mulu r2,r2,r1
|
lc r1,CursorCol
|
lc r1,CursorCol
|
andi r1,r1,#0x7f
|
andi r1,r1,#0x7f
|
addu r2,r2,r1
|
addu r2,r2,r1
|
Line 514... |
Line 1280... |
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
DisplayChar:
|
DisplayChar:
|
bnei r1,#'\r',dccr ; carriage return ?
|
bnei r1,#'\r',dccr ; carriage return ?
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/lr
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
sc r0,CursorCol ; just set cursor column to zero on a CR
|
sc r0,CursorCol ; just set cursor column to zero on a CR
|
bra dcx7
|
bra dcx7
|
dccr:
|
dccr:
|
bnei r1,#0x91,dcx6 ; cursor right ?
|
bnei r1,#0x91,dcx6 ; cursor right ?
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/lr
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
lc r2,CursorCol
|
lc r2,CursorCol
|
beqi r2,#56,dcx7
|
beqi r2,#56,dcx7
|
addui r2,r2,#1
|
addui r2,r2,#1
|
sc r2,CursorCol
|
sc r2,CursorCol
|
dcx7:
|
dcx7:
|
call CalcScreenLoc
|
call CalcScreenLoc
|
lm [sp],r1/r2/r3/lr
|
lw lr,24[sp]
|
|
lw r3,16[sp]
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
ret #32
|
ret #32
|
dcx6:
|
dcx6:
|
bnei r1,#0x90,dcx8 ; cursor up ?
|
bnei r1,#0x90,dcx8 ; cursor up ?
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/lr
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
lc r2,CursorRow
|
lc r2,CursorRow
|
beqi r2,#0,dcx7
|
beqi r2,#0,dcx7
|
subui r2,r2,#1
|
subui r2,r2,#1
|
sc r2,CursorRow
|
sc r2,CursorRow
|
bra dcx7
|
bra dcx7
|
dcx8:
|
dcx8:
|
bnei r1,#0x93,dcx9 ; cursor left ?
|
bnei r1,#0x93,dcx9 ; cursor left ?
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/lr
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
lc r2,CursorCol
|
lc r2,CursorCol
|
beqi r2,#0,dcx7
|
beqi r2,#0,dcx7
|
subui r2,r2,#1
|
subui r2,r2,#1
|
sc r2,CursorCol
|
sc r2,CursorCol
|
bra dcx7
|
bra dcx7
|
dcx9:
|
dcx9:
|
bnei r1,#0x92,dcx10 ; cursor down ?
|
bnei r1,#0x92,dcx10 ; cursor down ?
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/lr
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
lc r2,CursorRow
|
lc r2,CursorRow
|
beqi r2,#30,dcx7
|
beqi r2,#30,dcx7
|
addui r2,r2,#1
|
addui r2,r2,#1
|
sc r2,CursorRow
|
sc r2,CursorRow
|
bra dcx7
|
bra dcx7
|
dcx10:
|
dcx10:
|
bnei r1,#0x94,dcx11 ; cursor home ?
|
bnei r1,#0x94,dcx11 ; cursor home ?
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/lr
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
lc r2,CursorCol
|
lc r2,CursorCol
|
beq r2,r0,dcx12
|
beq r2,r0,dcx12
|
sc r0,CursorCol
|
sc r0,CursorCol
|
bra dcx7
|
bra dcx7
|
dcx12:
|
dcx12:
|
sc r0,CursorRow
|
sc r0,CursorRow
|
bra dcx7
|
bra dcx7
|
dcx11:
|
dcx11:
|
subui sp,sp,#48
|
subui sp,sp,#48
|
sm [sp],r1/r2/r3/r4/r5/r31
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw r4,24[sp]
|
|
sw r5,32[sp]
|
|
sw lr,40[sp]
|
bnei r1,#0x99,dcx13 ; delete ?
|
bnei r1,#0x99,dcx13 ; delete ?
|
call CalcScreenLoc
|
call CalcScreenLoc
|
or r3,r0,r1 ; r3 = screen location
|
or r3,r0,r1 ; r3 = screen location
|
lc r1,CursorCol ; r1 = cursor column
|
lc r1,CursorCol ; r1 = cursor column
|
bra dcx5
|
bra dcx5
|
Line 585... |
Line 1377... |
sc r2,CursorCol
|
sc r2,CursorCol
|
call CalcScreenLoc ; a0 = screen location
|
call CalcScreenLoc ; a0 = screen location
|
or r3,r0,r1 ; r3 = screen location
|
or r3,r0,r1 ; r3 = screen location
|
lc r1,CursorCol
|
lc r1,CursorCol
|
dcx5:
|
dcx5:
|
lc r2,2[r3]
|
inch r2,2[r3]
|
sc r2,[r3]
|
outc r2,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
addui r1,r1,#1
|
addui r1,r1,#1
|
setlo r4,#TEXTREG
|
lea r4,TEXTREG
|
inch r5,TEXT_COLS[r4]
|
inch r5,TEXT_COLS[r4]
|
bltu r1,r5,dcx5
|
bltu r1,r5,dcx5
|
setlo r2,#' '
|
setlo r1,#' '
|
sc r2,-2[r3]
|
call AsciiToScreen
|
|
outc r1,-2[r3]
|
bra dcx4
|
bra dcx4
|
dcx3:
|
dcx3:
|
beqi r1,#'\n',dclf ; linefeed ?
|
beqi r1,#'\n',dclf ; linefeed ?
|
or r4,r0,r1 ; save r1 in r4
|
or r4,r0,r1 ; save r1 in r4
|
call CalcScreenLoc ; r1 = screen location
|
call CalcScreenLoc ; r1 = screen location
|
or r3,r0,r1 ; r3 = screen location
|
or r3,r0,r1 ; r3 = screen location
|
or r1,r0,r4 ; restore r1
|
or r1,r0,r4 ; restore r1
|
call AsciiToScreen ; convert ascii char to screen char
|
call AsciiToScreen ; convert ascii char to screen char
|
sc r1,[r3]
|
outc r1,[r3]
|
call IncCursorPos
|
call IncCursorPos
|
lm [sp],r1/r2/r3/r4/r5/r31
|
bra dcx4
|
ret #48
|
|
dclf:
|
dclf:
|
call IncCursorRow
|
call IncCursorRow
|
dcx4:
|
dcx4:
|
lm [sp],r1/r2/r3/r4/r5/r31
|
lw lr,40[sp]
|
|
lw r5,32[sp]
|
|
lw r4,24[sp]
|
|
lw r3,16[sp]
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
ret #48
|
ret #48
|
|
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Increment the cursor position, scroll the screen if needed.
|
; Increment the cursor position, scroll the screen if needed.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
IncCursorPos:
|
IncCursorPos:
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [r30],r1/r2/r3/r31
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
lc r1,CursorCol
|
lc r1,CursorCol
|
addui r1,r1,#1
|
addui r1,r1,#1
|
sc r1,CursorCol
|
sc r1,CursorCol
|
inch r2,TEXTREG+TEXT_COLS
|
inch r2,TEXTREG+TEXT_COLS
|
bleu r1,r2,icc1
|
bleu r1,r2,icc1
|
sc r0,CursorCol ; column = 0
|
sc r0,CursorCol ; column = 0
|
bra icr1
|
bra icr1
|
IncCursorRow:
|
IncCursorRow:
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r1/r2/r3/r31
|
sw r1,[sp]
|
|
sw r2,8[sp]
|
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
icr1:
|
icr1:
|
lc r1,CursorRow
|
lc r1,CursorRow
|
addui r1,r1,#1
|
addui r1,r1,#1
|
sc r1,CursorRow
|
sc r1,CursorRow
|
inch r2,TEXTREG+TEXT_ROWS
|
inch r2,TEXTREG+TEXT_ROWS
|
Line 641... |
Line 1444... |
subui r2,r2,#1 ; backup the cursor row, we are scrolling up
|
subui r2,r2,#1 ; backup the cursor row, we are scrolling up
|
sc r2,CursorRow
|
sc r2,CursorRow
|
call ScrollUp
|
call ScrollUp
|
icc1:
|
icc1:
|
call CalcScreenLoc
|
call CalcScreenLoc
|
lm [sp],r1/r2/r3/r31
|
lw lr,24[sp]
|
|
lw r3,16[sp]
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
ret #32
|
ret #32
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Display a string on the screen.
|
; Display a string on the screen.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
DisplayString:
|
DisplayString:
|
subi sp,sp,#24
|
subi sp,sp,#24
|
sm [sp],r1/r2/r31
|
sw r1,[sp]
|
or r2,r1,r0 ; r2 = pointer to string
|
sw r2,8[sp]
|
|
sw lr,16[sp]
|
|
mov r2,r1 ; r2 = pointer to string
|
dspj1:
|
dspj1:
|
lbu r1,[r2] ; move string char into r1
|
lbu r1,[r2] ; move string char into r1
|
addui r2,r2,#1 ; increment pointer
|
addui r2,r2,#1 ; increment pointer
|
beq r1,r0,dsret ; is it end of string ?
|
beq r1,r0,dsret ; is it end of string ?
|
call DisplayChar ; display character
|
call DisplayChar ; display character
|
bra dspj1 ; go back for next character
|
bra dspj1 ; go back for next character
|
dsret:
|
dsret:
|
lm [r30],r1/r2/r31
|
lw lr,16[sp]
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
ret #24
|
ret #24
|
|
|
DisplayStringCRLF:
|
DisplayStringCRLF:
|
subui r30,r30,#8
|
subui r30,r30,#8
|
sw r31,[r30]
|
sw r31,[r30]
|
Line 671... |
Line 1481... |
lw r31,[r30]
|
lw r31,[r30]
|
addui r30,r30,#8
|
addui r30,r30,#8
|
|
|
CRLF:
|
CRLF:
|
subui r30,r30,#16
|
subui r30,r30,#16
|
sw r1,[r30]
|
sw r1,[sp]
|
sw r31,8[r30]
|
sw lr,8[sp]
|
setlo r1,#'\r'
|
setlo r1,#'\r'
|
call DisplayChar
|
call DisplayChar
|
setlo r1,#'\n'
|
setlo r1,#'\n'
|
call DisplayChar
|
call DisplayChar
|
lw r1,[r30]
|
lw lr,8[sp]
|
lw r31,8[r30]
|
lw r1,[sp]
|
ret #16
|
ret #16
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Display nybble in r1
|
; Display nybble in r1
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
DisplayNybble:
|
DisplayNybble:
|
subui r30,r30,#16
|
subui sp,sp,#16
|
sw r31,8[r30]
|
sw r1,[sp]
|
sw r1,[r30]
|
sw lr,8[sp]
|
andi r1,r1,#0x0F
|
andi r1,r1,#0x0F
|
addui r1,r1,#'0'
|
addui r1,r1,#'0'
|
bleui r1,#'9',dispnyb1
|
bleui r1,#'9',dispnyb1
|
addui r1,r1,#7
|
addui r1,r1,#7
|
dispnyb1:
|
dispnyb1:
|
call DisplayChar
|
call DisplayChar
|
lw r1,[r30]
|
lw lr,8[sp]
|
lw r31,8[r30]
|
lw r1,[sp]
|
ret #16
|
ret #16
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Display the byte in r1
|
; Display the byte in r1
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
DisplayByte:
|
DisplayByte:
|
subui sp,sp,#16
|
subui sp,sp,#16
|
sm [sp],r1/r31
|
sw r1,[sp]
|
|
sw lr,8[sp]
|
rori r1,r1,#4
|
rori r1,r1,#4
|
call DisplayNybble
|
call DisplayNybble
|
roli r1,r1,#4
|
roli r1,r1,#4
|
call DisplayNybble
|
call DisplayNybble
|
lm [sp],r1/r31
|
lw lr,8[sp]
|
|
lw r1,[sp]
|
ret #16
|
ret #16
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Display the 64 bit word in r1
|
; Display the 64 bit word in r1
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
DisplayWord:
|
DisplayWord:
|
subui sp,sp,#24
|
subui sp,sp,#24
|
sm [sp],r1/r3/r31
|
sw r1,[sp]
|
|
sw r3,8[sp]
|
|
sw lr,16[sp]
|
setlo r3,#7
|
setlo r3,#7
|
dspwd1:
|
dspwd1:
|
roli r1,r1,#8
|
roli r1,r1,#8
|
call DisplayByte
|
call DisplayByte
|
loop r3,dspwd1
|
loop r3,dspwd1
|
lm [sp],r1/r3/r31
|
lw lr,16[sp]
|
|
lw r3,8[sp]
|
|
lw r1,[sp]
|
ret #24
|
ret #24
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Display memory pointed to by r2.
|
; Display memory pointed to by r2.
|
; destroys r1,r3
|
; destroys r1,r3
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
DisplayMem:
|
DisplayMem:
|
subui sp,sp,#8
|
subui sp,sp,#24
|
sw lr,[sp]
|
sw r1,[sp]
|
|
sw r3,8[sp]
|
|
sw lr,16[sp]
|
setlo r1,#':'
|
setlo r1,#':'
|
call DisplayChar
|
call DisplayChar
|
or r1,r2,r0
|
mov r1,r2
|
call DisplayWord
|
call DisplayWord
|
setlo r3,#7
|
setlo r3,#7
|
dspmem1:
|
dspmem1:
|
setlo r1,#' '
|
setlo r1,#' '
|
call DisplayChar
|
call DisplayChar
|
lb r1,[r2]
|
lb r1,[r2]
|
call DisplayByte
|
call DisplayByte
|
addui r2,r2,#1
|
addui r2,r2,#1
|
loop r3,dspmem1
|
loop r3,dspmem1
|
call CRLF
|
call CRLF
|
lw lr,[sp]
|
lw lr,16[sp]
|
ret #8
|
lw r3,8[sp]
|
|
lw r1,[sp]
|
|
ret #24
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Converts binary number in r1 into BCD number in r2 and r1.
|
; Converts binary number in r1 into BCD number in r2 and r1.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
BinToBCD:
|
BinToBCD:
|
subui sp,sp,#48
|
subui sp,sp,#48
|
sm [sp],r3/r4/r5/r6/r7/r8
|
sw r3,[sp]
|
|
sw r4,8[sp]
|
|
sw r5,16[sp]
|
|
sw r6,24[sp]
|
|
sw r7,32[sp]
|
|
sw r8,40[sp]
|
setlo r2,#10
|
setlo r2,#10
|
setlo r8,#19 ; number of digits to produce - 1
|
setlo r8,#19 ; number of digits to produce - 1
|
bta1:
|
bta1:
|
mod r3,r1,r2
|
mod r3,r1,r2
|
shli r3,r3,#60 ; shift result to uppermost bits
|
shli r3,r3,#60 ; shift result to uppermost bits
|
Line 775... |
Line 1600... |
loop r8,bta1
|
loop r8,bta1
|
shrui r4,r4,#48 ; right align number in register
|
shrui r4,r4,#48 ; right align number in register
|
shli r6,r5,#16
|
shli r6,r5,#16
|
or r4,r4,r6 ; copy bits into r4
|
or r4,r4,r6 ; copy bits into r4
|
shrui r5,r5,#48
|
shrui r5,r5,#48
|
or r1,r0,r4
|
mov r1,r4
|
or r2,r0,r5
|
mov r2,r5
|
lm [sp],r3/r4/r5/r6/r7/r8
|
lw r3,[sp]
|
|
lw r4,8[sp]
|
|
lw r5,16[sp]
|
|
lw r6,24[sp]
|
|
lw r7,32[sp]
|
|
lw r8,40[sp]
|
ret #48
|
ret #48
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Converts BCD number in r1 into Ascii number in r2 and r1.
|
; Converts BCD number in r1 into Ascii number in r2 and r1.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
BCDToAscii:
|
BCDToAscii:
|
subui sp,sp,#32
|
subui sp,sp,#32
|
sm [sp],r3/r4/r5/r8
|
sw r3,[sp]
|
|
sw r4,8[sp]
|
|
sw r5,16[sp]
|
|
sw r8,24[sp]
|
setlo r8,#15
|
setlo r8,#15
|
bta2:
|
bta2:
|
andi r2,r1,#0x0F
|
andi r2,r1,#0x0F
|
ori r2,r2,#0x30
|
ori r2,r2,#0x30
|
shli r2,r2,#56
|
shli r2,r2,#56
|
Line 799... |
Line 1632... |
or r4,r4,r5
|
or r4,r4,r5
|
shrui r3,r3,#8
|
shrui r3,r3,#8
|
or r3,r3,r2
|
or r3,r3,r2
|
shrui r1,r1,#4
|
shrui r1,r1,#4
|
loop r8,bta2
|
loop r8,bta2
|
or r1,r0,r4
|
mov r1,r4
|
or r2,r0,r3
|
mov r2,r3
|
lm [sp],r3/r4/r5/r8
|
lw r3,[sp]
|
|
lw r4,8[sp]
|
|
lw r5,16[sp]
|
|
lw r8,24[sp]
|
ret #32
|
ret #32
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Convert a binary number into a 20 character ascii string.
|
; Convert a binary number into a 20 character ascii string.
|
; r1 = number to convert
|
; r1 = number to convert
|
; r2 = address of string buffer
|
; r2 = address of string buffer
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
BinToStr:
|
BinToStr:
|
subui sp,sp,#56
|
subui sp,sp,#56
|
sm [sp],r3/r7/r8/r9/r10/r11/r31
|
sw r3,[sp]
|
or r11,r0,r2
|
sw r7,8[sp]
|
|
sw r8,16[sp]
|
|
sw r9,24[sp]
|
|
sw r10,32[sp]
|
|
sw r11,40[sp]
|
|
sw lr,48[sp]
|
|
mov r11,r2
|
call BinToBCD
|
call BinToBCD
|
or r10,r0,r2 ; save off r2
|
mov r10,r2 ; save off r2
|
call BCDToAscii
|
call BCDToAscii
|
setlo r9,#1
|
setlo r9,#1
|
btos3:
|
btos3:
|
setlo r8,#7
|
setlo r8,#7
|
btos1:
|
btos1:
|
Line 828... |
Line 1670... |
addui r7,r7,#4
|
addui r7,r7,#4
|
andi r3,r1,#0xff
|
andi r3,r1,#0xff
|
sb r3,[r7+r11]
|
sb r3,[r7+r11]
|
shrui r1,r1,#8
|
shrui r1,r1,#8
|
loop r8,btos1
|
loop r8,btos1
|
or r1,r0,r2
|
mov r1,r2
|
loop r9,btos3
|
loop r9,btos3
|
; the last four digits
|
; the last four digits
|
or r1,r0,r10 ; get back r2
|
mov r1,r10 ; get back r2
|
call BCDToAscii
|
call BCDToAscii
|
setlo r8,#3
|
setlo r8,#3
|
btos2:
|
btos2:
|
andi r3,r1,#0xff
|
andi r3,r1,#0xff
|
sb r3,[r8+r11]
|
sb r3,[r8+r11]
|
shrui r1,r1,#8
|
shrui r1,r1,#8
|
loop r8,btos2
|
loop r8,btos2
|
sb r0,20[r11] ; null terminate
|
sb r0,20[r11] ; null terminate
|
lm [sp],r3/r7/r8/r9/r10/r11/r31
|
lw r3,[sp]
|
|
lw r7,8[sp]
|
|
lw r8,16[sp]
|
|
lw r9,24[sp]
|
|
lw r10,32[sp]
|
|
lw r11,40[sp]
|
|
lw lr,48[sp]
|
ret #56
|
ret #56
|
|
|
|
|
;==============================================================================
|
;==============================================================================
|
;==============================================================================
|
;==============================================================================
|
Monitor:
|
Monitor:
|
setlo sp,#STACKTOP ; top of stack; reset the stack pointer
|
lea sp,STACKTOP0 ; top of stack; reset the stack pointer
|
sb r0,KeybdEcho ; turn off keyboard echo
|
sb r0,KeybdEcho ; turn off keyboard echo
|
PromptLn:
|
PromptLn:
|
call CRLF
|
call CRLF
|
setlo r1,#'$'
|
setlo r1,#'$'
|
call DisplayChar
|
call DisplayChar
|
Line 869... |
Line 1717... |
;
|
;
|
Prompt1:
|
Prompt1:
|
sc r0,CursorCol ; go back to the start of the line
|
sc r0,CursorCol ; go back to the start of the line
|
call CalcScreenLoc ; r1 = screen memory location
|
call CalcScreenLoc ; r1 = screen memory location
|
or r3,r1,r0
|
or r3,r1,r0
|
lc r1,[r3]
|
inch r1,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
call ScreenToAscii
|
call ScreenToAscii
|
bnei r1,#'$',Prompt2 ; skip over '$' prompt character
|
bnei r1,#'$',Prompt2 ; skip over '$' prompt character
|
lc r1,[r3]
|
inch r1,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
call ScreenToAscii
|
call ScreenToAscii
|
|
|
; Dispatch based on command character
|
; Dispatch based on command character
|
;
|
;
|
Prompt2:
|
Prompt2:
|
beqi r1,#':',Editmem ; $: - edit memory
|
beqi r1,#':',Editmem ; $: - edit memory
|
beqi r1,#'D',Dumpmem ; $D - dump memory
|
beqi r1,#'D',Dumpmem ; $D - dump memory
|
beqi r1,#'B',START ; $B - start tiny basic
|
beqi r1,#'B',CSTART ; $B - start tiny basic
|
beqi r1,#'J',ExecuteCode ; $J - execute code
|
beqi r1,#'J',ExecuteCode ; $J - execute code
|
beqi r1,#'L',LoadS19 ; $L - load S19 file
|
beqi r1,#'L',LoadS19 ; $L - load S19 file
|
beqi r1,#'?',DisplayHelp ; $? - display help
|
beqi r1,#'?',DisplayHelp ; $? - display help
|
beqi r1,#'C',TestCLS ; $C - clear screen
|
beqi r1,#'C',TestCLS ; $C - clear screen
|
|
beqi r1,#'R',RandomLinesCall
|
|
beqi r1,#'I',Invaders
|
|
beqi r1,#'P',Piano
|
|
bra Monitor
|
|
|
|
RandomLinesCall:
|
|
call RandomLines
|
bra Monitor
|
bra Monitor
|
|
|
TestCLS:
|
TestCLS:
|
lc r1,[r3]
|
inch r1,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
call ScreenToAscii
|
call ScreenToAscii
|
bnei r1,#'L',Monitor
|
bnei r1,#'L',Monitor
|
lc r1,[r3]
|
inch r1,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
call ScreenToAscii
|
call ScreenToAscii
|
bnei r1,#'S',Monitor
|
bnei r1,#'S',Monitor
|
call ClearScreen
|
call ClearScreen
|
sb r0,CursorCol
|
sb r0,CursorCol
|
Line 917... |
Line 1772... |
db "CLS = clear screen",CR,LF
|
db "CLS = clear screen",CR,LF
|
db ": = Edit memory bytes",CR,LF
|
db ": = Edit memory bytes",CR,LF
|
db "L = Load S19 file",CR,LF
|
db "L = Load S19 file",CR,LF
|
db "D = Dump memory",CR,LF
|
db "D = Dump memory",CR,LF
|
db "B = start tiny basic",CR,LF
|
db "B = start tiny basic",CR,LF
|
db "J = Jump to code",CR,LF,0
|
db "J = Jump to code",CR,LF
|
|
db "I = Invaders",CR,LF
|
|
db "R = Random lines",CR,LF
|
|
db "P = Piano",CR,LF,0
|
align 16
|
align 16
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Ignore blanks in the input
|
; Ignore blanks in the input
|
; r3 = text pointer
|
; r3 = text pointer
|
Line 930... |
Line 1788... |
;
|
;
|
ignBlanks:
|
ignBlanks:
|
subui sp,sp,#8
|
subui sp,sp,#8
|
sw r31,[sp]
|
sw r31,[sp]
|
ignBlanks1:
|
ignBlanks1:
|
lc r1,[r3]
|
inch r1,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
call ScreenToAscii
|
call ScreenToAscii
|
beqi r1,#' ',ignBlanks1
|
beqi r1,#' ',ignBlanks1
|
subui r3,r3,#2
|
subui r3,r3,#2
|
lw r31,[sp]
|
lw r31,[sp]
|
Line 962... |
Line 1820... |
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
ExecuteCode:
|
ExecuteCode:
|
call ignBlanks
|
call ignBlanks
|
call GetHexNumber
|
call GetHexNumber
|
or r3,r1,r0
|
jal r31,[r1]
|
jal r31,[r3]
|
|
bra Monitor
|
bra Monitor
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Do a memory dump of the requested location.
|
; Do a memory dump of the requested location.
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
DumpMem:
|
DumpMem:
|
call ignBlanks
|
call ignBlanks
|
call GetHexNumber
|
call GetHexNumber
|
or r2,r1,r0
|
mov r2,r1
|
call CRLF
|
call CRLF
|
call DisplayMem
|
call DisplayMem
|
call DisplayMem
|
call DisplayMem
|
call DisplayMem
|
call DisplayMem
|
call DisplayMem
|
call DisplayMem
|
Line 988... |
Line 1845... |
bra Monitor
|
bra Monitor
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Get a hexidecimal number. Maximum of sixteen digits.
|
; Get a hexidecimal number. Maximum of sixteen digits.
|
; R3 = text pointer (updated)
|
; R3 = text pointer (updated)
|
|
; R1 = hex number
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
;
|
;
|
GetHexNumber:
|
GetHexNumber:
|
subui sp,sp,#24
|
subui sp,sp,#24
|
sm [sp],r2/r4/r31
|
sw r2,[sp]
|
|
sw r4,8[sp]
|
|
sw lr,16[sp]
|
setlo r2,#0
|
setlo r2,#0
|
setlo r4,#15
|
setlo r4,#15
|
gthxn2:
|
gthxn2:
|
lc r1,[r3]
|
inch r1,[r3]
|
addui r3,r3,#2
|
addui r3,r3,#2
|
call ScreenToAscii
|
call ScreenToAscii
|
call AsciiToHexNybble
|
call AsciiToHexNybble
|
beqi r1,#-1,gthxn1
|
beqi r1,#-1,gthxn1
|
shli r2,r2,#4
|
shli r2,r2,#4
|
andi r1,r1,#0x0f
|
andi r1,r1,#0x0f
|
or r2,r2,r1
|
or r2,r2,r1
|
loop r4,gthxn2
|
loop r4,gthxn2
|
gthxn1:
|
gthxn1:
|
or r1,r2,r0
|
mov r1,r2
|
lm [sp],r2/r4/r31
|
lw lr,16[sp]
|
|
lw r4,8[sp]
|
|
lw r2,[sp]
|
ret #24
|
ret #24
|
|
|
;------------------------------------------------------------------------------
|
;------------------------------------------------------------------------------
|
; Convert ASCII character in the range '0' to '9', 'a' to 'f' or 'A' to 'F'
|
; Convert ASCII character in the range '0' to '9', 'a' to 'f' or 'A' to 'F'
|
; to a hex nybble.
|
; to a hex nybble.
|
Line 1192... |
Line 2054... |
beq r1,r0,sgc1
|
beq r1,r0,sgc1
|
call KeybdGetchar
|
call KeybdGetchar
|
beqi r1,#CRTLC,Monitor
|
beqi r1,#CRTLC,Monitor
|
sgc1:
|
sgc1:
|
call AUXIN
|
call AUXIN
|
beq r1,r0,sgc2
|
ble r1,r0,sgc2
|
lw r31,[sp]
|
lw r31,[sp]
|
addui sp,sp,#8
|
ret #8
|
|
|
|
;--------------------------------------------------------------------------
|
|
; Draw random lines on the bitmap screen.
|
|
;--------------------------------------------------------------------------
|
|
RandomLines:
|
|
subui sp,sp,#24
|
|
sw r1,[sp]
|
|
sw r3,8[sp]
|
|
sw lr,16[sp]
|
|
rl5:
|
|
gran
|
|
mfspr r1,rand ; select a random color
|
|
outh r1,GACCEL
|
|
rl1: ; random X0
|
|
gran
|
|
mfspr r1,rand
|
|
lw r3,#1364
|
|
mod r1,r1,r3
|
|
outh r1,GACCEL+8
|
|
rl2: ; random X1
|
|
gran
|
|
mfspr r1,rand
|
|
lw r3,#1364
|
|
mod r1,r1,r3
|
|
outh r1,GACCEL+16
|
|
rl3: ; random Y0
|
|
gran
|
|
mfspr r1,rand
|
|
lw r3,#768
|
|
mod r1,r1,r3
|
|
outh r1,GACCEL+12
|
|
rl4: ; random Y1
|
|
gran
|
|
mfspr r1,rand
|
|
lw r3,#768
|
|
mod r1,r1,r3
|
|
outh r1,GACCEL+20
|
|
setlo r1,#2 ; draw line command
|
|
outh r1,GACCEL+60
|
|
rl8:
|
|
call KeybdGetChar
|
|
beqi r1,#CTRLC,rl7
|
|
beqi r1,#'r',rl5
|
|
bra rl8
|
|
rl7:
|
|
lw lr,16[sp]
|
|
lw r3,8[sp]
|
|
lw r1,[sp]
|
|
ret #24
|
|
|
|
;--------------------------------------------------------------------------
|
|
; Initialize sprite image caches with random data.
|
|
;--------------------------------------------------------------------------
|
|
RandomizeSprram:
|
|
lea r2,SPRRAM
|
|
setlo r4,#14335 ; number of chars to initialize
|
|
rsr1:
|
|
gran
|
|
mfspr r1,rand
|
|
outc r1,[r2]
|
|
addui r2,r2,#2
|
|
loop r4,rsr1
|
ret
|
ret
|
|
|
;--------------------------------------------------------------------------
|
;--------------------------------------------------------------------------
|
; Sound a 800 Hz beep
|
; Setup the AC97/LM4550 audio controller. Check keyboard for a CTRL-C
|
|
; interrupt which may be necessary if the audio controller isn't
|
|
; responding.
|
;--------------------------------------------------------------------------
|
;--------------------------------------------------------------------------
|
;
|
;
|
SetupAC97:
|
SetupAC97:
|
ori r1,r0,#0 ; trigger a read of register 26
|
subui sp,sp,#16
|
sc r1,AC97+0x26
|
sw r1,[sp]
|
|
sw lr,8[sp]
|
|
sac974:
|
|
outc r0,AC97+0x26 ; trigger a read of register 26 (status reg)
|
sac971: ; wait for status to register 0xF (all ready)
|
sac971: ; wait for status to register 0xF (all ready)
|
lc r1,AC97+0x26
|
call KeybdGetChar ; see if we needed to CTRL-C
|
bnei r1,#0x0F,sac971
|
beqi r1,#CTRLC,sac973
|
ori r1,r0,#0 ; master volume, 0db attenuation, mute off
|
outc r1,AC97+0x68 ; wait for dirty bit to clear
|
sc r1,AC97+2
|
bne r1,r0,sac971
|
sc r1,AC97+4 ; headphone volume, 0db attenuation, mute off
|
outc r1,AC97+0x26 ; check status at reg h26, wait for
|
ori r1,r0,#8000 ; wait a while for the settings to take effect
|
andi r1,r1,#0x0F ; analogue to be ready
|
|
bnei r1,#0x0F,sac974
|
|
sac973:
|
|
outc r0,AC97+2 ; master volume, 0db attenuation, mute off
|
|
outc r0,AC97+4 ; headphone volume, 0db attenuation, mute off
|
|
outc r0,AC97+0x18 ; PCM gain (mixer) mute off, no attenuation
|
|
outc r0,AC97+0x0A ; mute PC beep
|
|
setlo r1,#0x8000 ; bypass 3D sound
|
|
outc r1,AC97+0x20
|
sac972:
|
sac972:
|
loop r1,sac972
|
call KeybdGetChar
|
|
beqi r1,#CTRLC,sac975
|
|
outc r1,AC97+0x68 ; wait for dirty bits to clear
|
|
bne r1,r0,sac972 ; wait a while for the settings to take effect
|
|
sac975:
|
|
lw lr,8[sp]
|
|
lw r1,[sp]
|
|
ret #16
|
|
|
|
;--------------------------------------------------------------------------
|
|
; Sound a 800 Hz beep
|
|
;--------------------------------------------------------------------------
|
|
;
|
Beep:
|
Beep:
|
|
subui sp,sp,#16
|
|
sw r1,[sp]
|
|
sw lr,8[sp]
|
|
setlo r1,#8
|
|
outb r1,LED
|
ori r1,r0,#15 ; master volume to max
|
ori r1,r0,#15 ; master volume to max
|
sc r1,PSG+128
|
outc r1,PSG+128
|
ori r1,r0,#13422 ; 800Hz
|
ori r1,r0,#13422 ; 800Hz
|
sc r1,PSG
|
outc r1,PSGFREQ0
|
ori r1,r0,#32 ; attack (8.192 ms)
|
setlo r1,#9
|
sc r1,PSG+8
|
outb r1,LED
|
ori r1,r0,#64 ; decay (16.384 ms)
|
; decay (16.384 ms)2
|
sc r1,PSG+10
|
; attack (8.192 ms)1
|
ori r1,r0,#0xC0 ; sustain level
|
; release (1.024 s)A
|
sc r1,PSG+12
|
; sustain level C
|
ori r1,r0,#4000 ; release (1.024 s)
|
setlo r1,#0xCA12
|
sc r1,PSG+14
|
outc r1,PSGADSR0
|
ori r1,r0,#0x1104 ; gate, output enable, triangle waveform
|
ori r1,r0,#0x1104 ; gate, output enable, triangle waveform
|
sc r1,PSG+4
|
outc r1,PSGCTRL0
|
ori r1,r0,#25000000 ; delay about 1s
|
ori r1,r0,#25000000 ; delay about 1s
|
beep1:
|
beep1:
|
loop r1,beep1
|
loop r1,beep1
|
|
setlo r1,#13
|
|
outb r1,LED
|
|
ori r1,r0,#0x0104 ; gate off, output enable, triangle waveform
|
|
outc r1,PSGCTRL0
|
|
ori r1,r0,#25000000 ; delay about 1s
|
|
beep2:
|
|
loop r1,beep2
|
|
setlo r1,#16
|
|
outb r1,LED
|
ori r1,r0,#0x0000 ; gate off, output enable off, no waveform
|
ori r1,r0,#0x0000 ; gate off, output enable off, no waveform
|
ret
|
outc r1,PSGCTRL0
|
|
lw lr,8[sp]
|
|
lw r1,[sp]
|
|
ret #16
|
|
|
;*
|
;--------------------------------------------------------------------------
|
;* ===== Input a character from the host into register D0 (or
|
;--------------------------------------------------------------------------
|
;* return Zero status if there's no character available).
|
;
|
;*
|
Piano:
|
AUXIN:
|
ori r1,r0,#15 ; master volume to max
|
inb r1,UART_LS ; is character ready ?
|
outc r1,PSG+128
|
andi r1,r1,#rxfull
|
playnt:
|
beq r1,r0,AXIRET ;if not, return Zero status
|
call KeybdGetChar
|
inb r1,UART ; else get the character
|
beqi r1,#CTRLC,Monitor
|
andi r1,r1,#0x7f ;zero out the high bit
|
beqi r1,#'a',playnt1a
|
AXIRET:
|
beqi r1,#'b',playnt1b
|
|
beqi r1,#'c',playnt1c
|
|
beqi r1,#'d',playnt1d
|
|
beqi r1,#'e',playnt1e
|
|
beqi r1,#'f',playnt1f
|
|
beqi r1,#'g',playnt1g
|
|
bra playnt
|
|
|
|
playnt1a:
|
|
setlo r1,#7217
|
|
call Tone
|
|
bra playnt
|
|
playnt1b:
|
|
setlo r1,#8101
|
|
call Tone
|
|
bra playnt
|
|
playnt1c:
|
|
setlo r1,#4291
|
|
call Tone
|
|
bra playnt
|
|
playnt1d:
|
|
setlo r1,#4817
|
|
call Tone
|
|
bra playnt
|
|
playnt1e:
|
|
setlo r1,#5407
|
|
call Tone
|
|
bra playnt
|
|
playnt1f:
|
|
setlo r1,#5728
|
|
call Tone
|
|
bra playnt
|
|
playnt1g:
|
|
setlo r1,#6430
|
|
call Tone
|
|
bra playnt
|
|
|
|
Tone:
|
|
subui sp,sp,#16
|
|
sw r1,[sp]
|
|
sw lr,8[sp]
|
|
outc r1,PSGFREQ0
|
|
; decay (16.384 ms)2
|
|
; attack (8.192 ms)1
|
|
; release (1.024 s)A
|
|
; sustain level C
|
|
setlo r1,#0xCA12
|
|
outc r1,PSGADSR0
|
|
ori r1,r0,#0x1104 ; gate, output enable, triangle waveform
|
|
outc r1,PSGCTRL0
|
|
ori r1,r0,#250000 ; delay about 10ms
|
|
tone1:
|
|
loop r1,tone1
|
|
ori r1,r0,#0x0104 ; gate off, output enable, triangle waveform
|
|
outc r1,PSGCTRL0
|
|
ori r1,r0,#250000 ; delay about 10ms
|
|
tone2:
|
|
loop r1,tone2
|
|
ori r1,r0,#0x0000 ; gate off, output enable off, no waveform
|
|
outc r1,PSGCTRL0
|
|
lw lr,8[sp]
|
|
lw r1,[sp]
|
|
ret #16
|
|
|
|
;==============================================================================
|
|
;==============================================================================
|
|
SetupRasterIRQ:
|
|
subui sp,sp,#8
|
|
sw r1,[sp]
|
|
setlo r1,#200
|
|
outc r1,RASTERIRQ
|
|
setlo r1,#240
|
|
outc r1,RASTERIRQ+2
|
|
setlo r1,#280
|
|
outc r1,RASTERIRQ+4
|
|
setlo r1,#320
|
|
outc r1,RASTERIRQ+6
|
|
setlo r1,#360
|
|
outc r1,RASTERIRQ+8
|
|
lw r1,[sp]
|
|
ret #8
|
|
|
|
RasterIRQfn:
|
|
inch r1,RASTERIRQ+30 ; get the raster compare register # (clears IRQ)
|
|
beqi r1,#1,rirq1
|
|
beqi r1,#2,rirq2
|
|
beqi r1,#3,rirq3
|
|
beqi r1,#4,rirq4
|
|
beqi r1,#5,rirq5
|
|
beqi r1,#6,rirq6
|
|
beqi r1,#7,rirq7
|
|
beqi r1,#8,rirq8
|
|
ret
|
|
rirq1:
|
|
rirq2:
|
|
rirq3:
|
|
rirq4:
|
|
rirq5:
|
|
rirq6:
|
|
rirq7:
|
|
rirq8:
|
|
mului r1,r1,#40
|
|
addui r1,r1,#204
|
|
outc r1,SPRITEREGS+2
|
|
outc r1,SPRITEREGS+18
|
|
outc r1,SPRITEREGS+34
|
|
outc r1,SPRITEREGS+50
|
|
outc r1,SPRITEREGS+66
|
|
outc r1,SPRITEREGS+82
|
|
outc r1,SPRITEREGS+98
|
|
outc r1,SPRITEREGS+114
|
ret
|
ret
|
|
|
;*
|
;------------------------------------------------------------------------------
|
;* ===== Return to the resident monitor, operating system, etc.
|
;------------------------------------------------------------------------------
|
;*
|
DisplayDatetime:
|
BYEBYE:
|
subui sp,sp,#32
|
jmp Monitor
|
sw r1,[sp]
|
; MOVE.B #228,D7 ;return to Tutor
|
sw r2,8[sp]
|
; TRAP #14
|
sw r3,16[sp]
|
|
sw lr,24[sp]
|
|
call CursorOff
|
|
lc r2,CursorRow
|
|
lc r3,CursorCol
|
|
outw r0,DATETIME+24 ; trigger a snapshot
|
|
lw r1,#46 ; move cursor down to last display line
|
|
sc r1,CursorRow
|
|
lw r1,#64
|
|
sc r1,CursorCol
|
|
inw r1,DATETIME ; get the snapshotted date and time
|
|
call DisplayWord ; display on screen
|
|
sc r2,CursorRow ; restore cursor position
|
|
sc r3,CursorCol
|
|
call CalcScreenLoc
|
|
call CursorOn
|
|
lw lr,24[sp]
|
|
lw r3,16[sp]
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
|
ret #32
|
|
|
align 16
|
;==============================================================================
|
msgInit db CR,LF,"Raptor64 Tiny BASIC v1.0",CR,LF,"(C) 2012 Robert Finch",CR,LF,LF,0
|
;==============================================================================
|
OKMSG db CR,LF,"OK",CR,LF,0
|
InitializeGame:
|
msgWhat db "What?",CR,LF,0
|
subui sp,sp,#16
|
SRYMSG db "Sorry."
|
sm [sp],r3/lr
|
CLMSG db CR,LF,0
|
setlo r3,#320
|
msgReadError db "Compact FLASH read error",CR,LF,0
|
sc r3,Manpos
|
|
sc r0,Score
|
|
sb r0,MissileActive
|
|
sc r0,MissileX
|
|
sc r0,MissileY
|
|
lm [sp],r3/lr
|
|
ret #16
|
|
|
|
DrawScore:
|
|
subui sp,sp,#24
|
|
sm [sp],r1/r3/lr
|
|
setlo r3,#1
|
|
sb r3,CursorRow
|
|
setlo r3,#40
|
|
sb r3,CursorCol
|
|
lb r1,Score
|
|
call DisplayByte
|
|
lb r1,Score+1
|
|
call DisplayByte
|
|
lm [sp],r1/r3/lr
|
|
ret #24
|
|
|
|
DrawMissile:
|
|
subui sp,sp,#16
|
|
sm [sp],r1/lr
|
|
lc r1,MissileY
|
|
bleu r1,#2,MissileOff
|
|
lc r1,MissileX
|
|
shrui r1,r1,#3
|
|
sb r1,CursorCol
|
|
lc r1,MissileY
|
|
sb r1,CursorRow
|
|
subui r1,r1,#1
|
|
sc r1,MissileY
|
|
setlo r1,#'^'
|
|
call DisplayChar
|
|
lb r1,CursorCol
|
|
subui r1,r1,#1
|
|
sb r1,CursorCol
|
|
lb r1,CursorRow
|
|
subui r1,r1,#1
|
|
sb r1,CursorRow
|
|
setlo r1,#' '
|
|
call DisplayChar
|
|
lm [sp],r1/lr
|
|
ret #16
|
|
MissileOff:
|
|
sb r0,MissileActive
|
|
lc r1,MissileX
|
|
shrui r1,r1,#3
|
|
sb r1,CursorCol
|
|
lc r1,MissileY
|
|
sb r1,CursorRow
|
|
setlo r1,#' '
|
|
call DisplayChar
|
|
lm [sp],r1/lr
|
|
ret #16
|
|
|
|
DrawMan:
|
|
subui sp,sp,#24
|
|
sm [sp],r1/r3/lr
|
|
setlo r3,#46
|
|
sb r3,CursorRow
|
|
lc r3,Manpos
|
|
shrui r3,r3,#3
|
|
sb r3,CursorCol
|
|
setlo r1,#' '
|
|
call DisplayChar
|
|
setlo r1,#'#'
|
|
call DisplayChar
|
|
setlo r1,#'A'
|
|
call DisplayChar
|
|
setlo r1,#'#'
|
|
call DisplayChar
|
|
setlo r1,#' '
|
|
call DisplayChar
|
|
lm [sp],r1/r3/lr
|
|
ret #24
|
|
|
|
DrawInvader:
|
|
lw r3,InvaderPos
|
|
lw r1,#233
|
|
sc r1,[r3]
|
|
lw r1,#242
|
|
sc r1,1[r3]
|
|
lw r1,#223
|
|
sc r1,2[r3]
|
|
ret
|
|
|
|
DrawInvaders:
|
|
subui sp,sp,#40
|
|
sm [sp],r1/r2/r3/r4/lr
|
|
lc r1,InvadersRow1
|
|
lc r4,InvadersColpos
|
|
andi r2,r1,#1
|
|
beq r2,r0,dinv1
|
|
lb r3,InvadersRowpos
|
|
sb r3,CursorRow
|
|
sb r4,CursorCol
|
|
setlo r1,#' '
|
|
call DisplayByte
|
|
setlo r1,#'#'
|
|
call DisplayByte
|
|
setlo r1,#'#'
|
|
call DisplayByte
|
|
setlo r1,#'#'
|
|
call DisplayByte
|
|
setlo r1,#' '
|
|
call DisplayByte
|
|
lb r1,CursorRow
|
|
addui r1,r1,#1
|
|
sb r1,CursorRow
|
|
lb r1,CursorCol
|
|
subui r1,r1,#5
|
|
setlo r1,#' '
|
|
call DisplayByte
|
|
setlo r1,#'X'
|
|
call DisplayByte
|
|
setlo r1,#' '
|
|
call DisplayByte
|
|
setlo r1,#'X'
|
|
call DisplayByte
|
|
setlo r1,#' '
|
|
call DisplayByte
|
|
dinv1:
|
|
lm [sp],r1/r2/r3/r4/lr
|
|
ret #40
|
|
DrawBombs:
|
|
ret
|
|
|
|
Invaders:
|
|
subui sp,#240
|
|
sm [sp],r1/r2/r3/r4/lr
|
|
call InitializeGame
|
|
InvadersLoop:
|
|
call DrawScore
|
|
call DrawInvaders
|
|
call DrawBombs
|
|
call DrawMissile
|
|
call DrawMan
|
|
TestMoveMan:
|
|
call KeybdGetChar
|
|
beqi r1,#'k',MoveManRight
|
|
beqi r1,#'j',MoveManLeft
|
|
beqi r1,#' ',FireMissile
|
|
bra Invaders1
|
|
MoveManRight:
|
|
lc r2,Manpos
|
|
bgtu r2,#640,Invaders1
|
|
addui r2,r2,#8
|
|
sc r2,Manpos
|
|
bra Invaders1
|
|
MoveManLeft:
|
|
lc r2,Manpos
|
|
ble r2,r0,Invaders1
|
|
subui r2,r2,#8
|
|
sc r2,Manpos
|
|
bra Invaders1
|
|
FireMissile:
|
|
lb r2,MissileActive
|
|
bne r2,r0,Invaders1
|
|
setlo r2,#1
|
|
sb r2,MissileActive
|
|
lc r2,Manpos
|
|
sc r2,MissileX
|
|
setlo r2,#46
|
|
sc r2,MissileY
|
|
bra Invaders1
|
|
Invaders1:
|
|
beqi r1,#CTRLC,InvadersEnd
|
|
bra InvadersLoop
|
|
InvadersEnd:
|
|
lm [sp],r1/r2/r3/r4/lr
|
|
addui sp,sp,#240
|
|
bra Monitor
|
|
|
|
;==============================================================================
|
|
;==============================================================================
|
|
;****************************************************************;
|
|
; ;
|
|
; Tiny BASIC for the Raptor64 ;
|
|
; ;
|
|
; Derived from a 68000 derivative of Palo Alto Tiny BASIC as ;
|
|
; published in the May 1976 issue of Dr. Dobb's Journal. ;
|
|
; Adapted to the 68000 by: ;
|
|
; Gordon brndly ;
|
|
; 12147 - 51 Street ;
|
|
; Edmonton AB T5W 3G8 ;
|
|
; Canada ;
|
|
; (updated mailing address for 1996) ;
|
|
; ;
|
|
; Adapted to the Raptor64 by: ;
|
|
; Robert Finch ;
|
|
; Ontario, Canada ;
|
|
; robfinch<remove>@opencores.org ;
|
|
;****************************************************************;
|
|
; Copyright (C) 2012 by Robert Finch. This program may be ;
|
|
; freely distributed for personal use only. All commercial ;
|
|
; rights are reserved. ;
|
|
;****************************************************************;
|
|
;
|
|
; Register Usage
|
|
; r8 = text pointer (global usage)
|
|
; r3,r4 = inputs parameters to subroutines
|
|
; r2 = return value
|
|
;
|
|
;* Vers. 1.0 1984/7/17 - Original version by Gordon brndly
|
|
;* 1.1 1984/12/9 - Addition of '0x' print term by Marvin Lipford
|
|
;* 1.2 1985/4/9 - Bug fix in multiply routine by Rick Murray
|
|
|
|
;
|
|
; Standard jump table. You can change these addresses if you are
|
|
; customizing this interpreter for a different environment.
|
|
;
|
|
GOSTART:
|
|
jmp CSTART ; Cold Start entry point
|
|
GOWARM:
|
|
jmp WSTART ; Warm Start entry point
|
|
GOOUT:
|
|
jmp OUTC ; Jump to character-out routine
|
|
GOIN:
|
|
jmp INC ;Jump to character-in routine
|
|
GOAUXO:
|
|
jmp AUXOUT ; Jump to auxiliary-out routine
|
|
GOAUXI:
|
|
jmp AUXIN ; Jump to auxiliary-in routine
|
|
GOBYE:
|
|
jmp BYEBYE ; Jump to monitor, DOS, etc.
|
|
;
|
|
; Modifiable system constants:
|
|
;
|
|
align 8
|
|
TXTBGN dw 0x000000001_00600000 ;TXT ;beginning of program memory
|
|
ENDMEM dw 0x000000001_07FFFFF8 ; end of available memory
|
|
;
|
|
; The main interpreter starts here:
|
|
;
|
|
; Usage
|
|
; r1 = temp
|
|
; r8 = text buffer pointer
|
|
; r12 = end of text in text buffer
|
|
;
|
|
align 16
|
|
CSTART:
|
|
; First save off the link register and OS sp value
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
sw sp,OSSP
|
|
lw sp,ENDMEM ; initialize stack pointer
|
|
subui sp,sp,#8
|
|
sw lr,[sp] ; save off return address
|
|
sc r0,CursorRow ; set screen output
|
|
sc r0,CursorCol
|
|
sb r0,CursorFlash
|
|
sw r0,pos
|
|
lw r2,#0x10000020 ; black chars, yellow background
|
|
sh r2,charToPrint
|
|
call ClearScreen
|
|
lea r1,msgInit ; tell who we are
|
|
call PRMESGAUX
|
|
lea r1,msgInit ; tell who we are
|
|
call PRMESG
|
|
lw r1,TXTBGN ; init. end-of-program pointer
|
|
sw r1,TXTUNF
|
|
lw r1,ENDMEM ; get address of end of memory
|
|
subui r1,r1,#2048 ; reserve 2K for the stack
|
|
sw r1,STKBOT
|
|
subui r1,r1,#8192 ; 1000 vars
|
|
sw r1,VARBGN
|
|
call clearVars ; clear the variable area
|
|
lw r1,VARBGN ; calculate number of bytes free
|
|
lw r3,TXTUNF
|
|
sub r1,r1,r3
|
|
setlo r2,#0
|
|
call PRTNUM
|
|
lea r1,msgBytesFree
|
|
call PRMESG
|
|
WSTART:
|
|
sw r0,LOPVAR ; initialize internal variables
|
|
sw r0,STKGOS
|
|
sw r0,CURRNT ; current line number pointer = 0
|
|
lw sp,ENDMEM ; init S.P. again, just in case
|
|
lea r1,msgReady ; display "Ready"
|
|
call PRMESG
|
|
ST3:
|
|
setlo r1,#'>' ; Prompt with a '>' and
|
|
call GETLN ; read a line.
|
|
call TOUPBUF ; convert to upper case
|
|
mov r12,r8 ; save pointer to end of line
|
|
lea r8,BUFFER ; point to the beginning of line
|
|
call TSTNUM ; is there a number there?
|
|
call IGNBLK ; skip trailing blanks
|
|
; does line no. exist? (or nonzero?)
|
|
beq r1,r0,DIRECT ; if not, it's a direct statement
|
|
bleu r1,#0xFFFF,ST2 ; see if line no. is <= 16 bits
|
|
lea r1,msgLineRange ; if not, we've overflowed
|
|
bra ERROR
|
|
ST2:
|
|
; ugliness - store a character at potentially an
|
|
; odd address (unaligned).
|
|
mov r2,r1 ; r2 = line number
|
|
sb r2,-2[r8]
|
|
shrui r2,r2,#8
|
|
sb r2,-1[r8] ; store the binary line no.
|
|
subui r8,r8,#2
|
|
call FNDLN ; find this line in save area
|
|
mov r13,r9 ; save possible line pointer
|
|
beq r1,r0,ST4 ; if not found, insert
|
|
; here we found the line, so we're replacing the line
|
|
; in the text area
|
|
; first step - delete the line
|
|
setlo r1,#0
|
|
call FNDNXT ; find the next line (into r9)
|
|
bne r1,r0,ST7
|
|
beq r9,r0,ST6 ; no more lines
|
|
ST7:
|
|
mov r1,r9 ; r1 = pointer to next line
|
|
mov r2,r13 ; pointer to line to be deleted
|
|
lw r3,TXTUNF ; points to top of save area
|
|
call MVUP ; move up to delete
|
|
sw r2,TXTUNF ; update the end pointer
|
|
; we moved the lines of text after the line being
|
|
; deleted down, so the pointer to the next line
|
|
; needs to be reset
|
|
mov r9,r13
|
|
bra ST4
|
|
; here there were no more lines, so just move the
|
|
; end of text pointer down
|
|
ST6:
|
|
sw r13,TXTUNF
|
|
mov r9,r13
|
|
ST4:
|
|
; here we're inserting because the line wasn't found
|
|
; or it was deleted from the text area
|
|
mov r1,r12 ; calculate the length of new line
|
|
sub r1,r1,r8
|
|
blei r1,#3,ST3 ; is it just a line no. & CR? if so, it was just a delete
|
|
|
|
lw r11,TXTUNF ; compute new end of text
|
|
mov r10,r11 ; r10 = old TXTUNF
|
|
add r11,r11,r1 ; r11 = new top of TXTUNF (r1=line length)
|
|
|
|
lw r1,VARBGN ; see if there's enough room
|
|
bltu r11,r1,ST5
|
|
lea r1,msgTooBig ; if not, say so
|
|
jmp ERROR
|
|
|
|
; open a space in the text area
|
|
ST5:
|
|
sw r11,TXTUNF ; if so, store new end position
|
|
mov r1,r10 ; points to old end of text
|
|
mov r2,r11 ; points to new end of text
|
|
mov r3,r9 ; points to start of line after insert line
|
|
call MVDOWN ; move things out of the way
|
|
|
|
; copy line into text space
|
|
mov r1,r8 ; set up to do the insertion; move from buffer
|
|
mov r2,r13 ; to vacated space
|
|
mov r3,r12 ; until end of buffer
|
|
call MVUP ; do it
|
|
bra ST3 ; go back and get another line
|
|
|
|
;******************************************************************
|
|
;
|
|
; *** Tables *** DIRECT *** EXEC ***
|
|
;
|
|
; This section of the code tests a string against a table. When
|
|
; a match is found, control is transferred to the section of
|
|
; code according to the table.
|
|
;
|
|
; At 'EXEC', r8 should point to the string, r9 should point to
|
|
; the character table, and r10 should point to the execution
|
|
; table. At 'DIRECT', r8 should point to the string, r9 and
|
|
; r10 will be set up to point to TAB1 and TAB1_1, which are
|
|
; the tables of all direct and statement commands.
|
|
;
|
|
; A '.' in the string will terminate the test and the partial
|
|
; match will be considered as a match, e.g. 'P.', 'PR.','PRI.',
|
|
; 'PRIN.', or 'PRINT' will all match 'PRINT'.
|
|
;
|
|
; There are two tables: the character table and the execution
|
|
; table. The character table consists of any number of text items.
|
|
; Each item is a string of characters with the last character's
|
|
; high bit set to one. The execution table holds a 32-bit
|
|
; execution addresses that correspond to each entry in the
|
|
; character table.
|
|
;
|
|
; The end of the character table is a 0 byte which corresponds
|
|
; to the default routine in the execution table, which is
|
|
; executed if none of the other table items are matched.
|
|
;
|
|
; Character-matching tables:
|
|
align 8
|
|
TAB1:
|
|
db "LIS",'T'+0x80 ; Direct commands
|
|
db "LOA",'D'+0x80
|
|
db "NE",'W'+0x80
|
|
db "RU",'N'+0x80
|
|
db "SAV",'E'+0x80
|
|
TAB2:
|
|
db "NEX",'T'+0x80 ; Direct / statement
|
|
db "LE",'T'+0x80
|
|
db "I",'F'+0x80
|
|
db "GOT",'O'+0x80
|
|
db "GOSU",'B'+0x80
|
|
db "RETUR",'N'+0x80
|
|
db "RE",'M'+0x80
|
|
db "FO",'R'+0x80
|
|
db "INPU",'T'+0x80
|
|
db "PRIN",'T'+0x80
|
|
db "POKE",'C'+0x80
|
|
db "POKE",'H'+0x80
|
|
db "POKE",'W'+0x80
|
|
db "POK",'E'+0x80
|
|
db "STO",'P'+0x80
|
|
db "BY",'E'+0x80
|
|
db "SY",'S'+0x80
|
|
db "CL",'S'+0x80
|
|
db "CL",'R'+0x80
|
|
db "RDC",'F'+0x80
|
|
db 0
|
|
TAB4:
|
|
db "PEEK",'C'+0x80 ;Functions
|
|
db "PEEK",'H'+0x80 ;Functions
|
|
db "PEEK",'W'+0x80 ;Functions
|
|
db "PEE",'K'+0x80 ;Functions
|
|
db "RN",'D'+0x80
|
|
db "AB",'S'+0x80
|
|
db "SIZ",'E'+0x80
|
|
db "US",'R'+0x80
|
|
db 0
|
|
TAB5:
|
|
db "T",'O'+0x80 ;"TO" in "FOR"
|
|
db 0
|
|
TAB6:
|
|
db "STE",'P'+0x80 ;"STEP" in "FOR"
|
|
db 0
|
|
TAB8:
|
|
db '>','='+0x80 ;Relational operators
|
|
db '<','>'+0x80
|
|
db '>'+0x80
|
|
db '='+0x80
|
|
db '<','='+0x80
|
|
db '<'+0x80
|
|
db 0
|
|
TAB9:
|
|
db "AN",'D'+0x80
|
|
db 0
|
|
TAB10:
|
|
db "O",'R'+0x80
|
|
db 0
|
|
|
|
.align 8
|
|
|
|
;* Execution address tables:
|
|
TAB1_1:
|
|
dw LISTX ;Direct commands
|
|
dw LOAD
|
|
dw NEW
|
|
dw RUN
|
|
dw SAVE
|
|
TAB2_1:
|
|
dw NEXT ; Direct / statement
|
|
dw LET
|
|
dw IF
|
|
dw GOTO
|
|
dw GOSUB
|
|
dw RETURN
|
|
dw IF2 ; REM
|
|
dw FOR
|
|
dw INPUT
|
|
dw PRINT
|
|
dw POKEC
|
|
dw POKEH
|
|
dw POKEW
|
|
dw POKE
|
|
dw STOP
|
|
dw GOBYE
|
|
dw SYSX
|
|
dw _cls
|
|
dw _clr
|
|
dw _rdcf
|
|
dw DEFLT
|
|
TAB4_1:
|
|
dw PEEKC
|
|
dw PEEKH
|
|
dw PEEKW
|
|
dw PEEK ;Functions
|
|
dw RND
|
|
dw ABS
|
|
dw SIZEX
|
|
dw USRX
|
|
dw XP40
|
|
TAB5_1
|
|
dw FR1 ;"TO" in "FOR"
|
|
dw QWHAT
|
|
TAB6_1
|
|
dw FR2 ;"STEP" in "FOR"
|
|
dw FR3
|
|
TAB8_1
|
|
dw XP11 ;>= Relational operators
|
|
dw XP12 ;<>
|
|
dw XP13 ;>
|
|
dw XP15 ;=
|
|
dw XP14 ;<=
|
|
dw XP16 ;<
|
|
dw XP17
|
|
TAB9_1
|
|
dw XP_AND
|
|
dw XP_ANDX
|
|
TAB10_1
|
|
dw XP_OR
|
|
dw XP_ORX
|
|
|
|
.align 16
|
|
|
|
;*
|
|
; r3 = match flag (trashed)
|
|
; r9 = text table
|
|
; r10 = exec table
|
|
; r11 = trashed
|
|
DIRECT:
|
|
lea r9,TAB1
|
|
lea r10,TAB1_1
|
|
EXEC:
|
|
mov r11,lr ; save link reg
|
|
call IGNBLK ; ignore leading blanks
|
|
mov lr,r11 ; restore link reg
|
|
mov r11,r8 ; save the pointer
|
|
setlo r3,#0 ; clear match flag
|
|
EXLP:
|
|
lbu r1,[r8] ; get the program character
|
|
addui r8,r8,#1
|
|
lbu r2,[r9] ; get the table character
|
|
bne r2,r0,EXNGO ; If end of table,
|
|
mov r8,r11 ; restore the text pointer and...
|
|
bra EXGO ; execute the default.
|
|
EXNGO:
|
|
beq r1,r3,EXGO ; Else check for period... if so, execute
|
|
andi r2,r2,#0x7f ; ignore the table's high bit
|
|
beq r2,r1,EXMAT; is there a match?
|
|
addui r10,r10,#8 ;if not, try the next entry
|
|
mov r8,r11 ; reset the program pointer
|
|
setlo r3,#0 ; sorry, no match
|
|
EX1:
|
|
addui r9,r9,#1
|
|
lb r1,-1[r9] ; get to the end of the entry
|
|
bgt r1,r0,EX1
|
|
bra EXLP ; back for more matching
|
|
EXMAT:
|
|
setlo r3,#'.' ; we've got a match so far
|
|
addui r9,r9,#1
|
|
lb r1,-1[r9] ; end of table entry?
|
|
bgt r1,r0,EXLP ; if not, go back for more
|
|
EXGO:
|
|
lw r11,[r10] ; execute the appropriate routine
|
|
jal r0,[r11]
|
|
|
|
; lb r1,[r8] ; get token from text space
|
|
; bpl
|
|
; and r1,#0x7f
|
|
; shl r1,#2 ; * 4 - word offset
|
|
; add r1,r1,#TAB1_1
|
|
; lw r1,[r1]
|
|
; jmp [r1]
|
|
|
|
|
|
;******************************************************************
|
|
;
|
|
; What follows is the code to execute direct and statement
|
|
; commands. Control is transferred to these points via the command
|
|
; table lookup code of 'DIRECT' and 'EXEC' in the last section.
|
|
; After the command is executed, control is transferred to other
|
|
; sections as follows:
|
|
;
|
|
; For 'LISTX', 'NEW', and 'STOP': go back to the warm start point.
|
|
; For 'RUN': go execute the first stored line if any; else go
|
|
; back to the warm start point.
|
|
; For 'GOTO' and 'GOSUB': go execute the target line.
|
|
; For 'RETURN' and 'NEXT'; go back to saved return line.
|
|
; For all others: if 'CURRNT' is 0, go to warm start; else go
|
|
; execute next command. (This is done in 'FINISH'.)
|
|
;
|
|
;******************************************************************
|
|
;
|
|
; *** NEW *** STOP *** RUN (& friends) *** GOTO ***
|
|
;
|
|
; 'NEW<CR>' sets TXTUNF to point to TXTBGN
|
|
;
|
|
; 'STOP<CR>' goes back to WSTART
|
|
;
|
|
; 'RUN<CR>' finds the first stored line, stores its address
|
|
; in CURRNT, and starts executing it. Note that only those
|
|
; commands in TAB2 are legal for a stored program.
|
|
;
|
|
; There are 3 more entries in 'RUN':
|
|
; 'RUNNXL' finds next line, stores it's address and executes it.
|
|
; 'RUNTSL' stores the address of this line and executes it.
|
|
; 'RUNSML' continues the execution on same line.
|
|
;
|
|
; 'GOTO expr<CR>' evaluates the expression, finds the target
|
|
; line, and jumps to 'RUNTSL' to do it.
|
|
;
|
|
NEW:
|
|
call ENDCHK
|
|
lw r1,TXTBGN
|
|
sw r1,TXTUNF ; set the end pointer
|
|
call clearVars
|
|
|
|
STOP:
|
|
call ENDCHK
|
|
bra WSTART ; WSTART will reset the stack
|
|
|
|
RUN:
|
|
call ENDCHK
|
|
lw r8,TXTBGN ; set pointer to beginning
|
|
sw r8,CURRNT
|
|
call clearVars
|
|
|
|
RUNNXL: ; RUN <next line>
|
|
lw r1,CURRNT ; executing a program?
|
|
beq r1,r0,WSTART ; if not, we've finished a direct stat.
|
|
setlo r1,#0 ; else find the next line number
|
|
mov r9,r8
|
|
call FNDLNP ; search for the next line
|
|
bne r1,r0,RUNTSL
|
|
bne r9,r0,RUNTSL
|
|
bra WSTART ; if we've fallen off the end, stop
|
|
|
|
RUNTSL: ; RUN <this line>
|
|
sw r9,CURRNT ; set CURRNT to point to the line no.
|
|
lea r8,2[r9] ; set the text pointer to
|
|
|
|
RUNSML: ; RUN <same line>
|
|
call CHKIO ; see if a control-C was pressed
|
|
lea r9,TAB2 ; find command in TAB2
|
|
lea r10,TAB2_1
|
|
bra EXEC ; and execute it
|
|
|
|
GOTO:
|
|
call OREXPR ;evaluate the following expression
|
|
mov r5,r1
|
|
call ENDCHK ;must find end of line
|
|
mov r1,r5
|
|
call FNDLN ; find the target line
|
|
bne r1,r0,RUNTSL ; go do it
|
|
lea r1,msgBadGotoGosub
|
|
bra ERROR ; no such line no.
|
|
|
|
_clr:
|
|
call clearVars
|
|
bra FINISH
|
|
|
|
; Clear the variable area of memory
|
|
clearVars:
|
|
subui sp,sp,#16
|
|
sw r6,[sp]
|
|
sw lr,8[sp]
|
|
setlo r6,#2048 ; number of words to clear
|
|
lw r1,VARBGN
|
|
cv1:
|
|
sw r0,[r1]
|
|
add r1,r1,#8
|
|
loop r6,cv1
|
|
lw lr,8[sp]
|
|
lw r6,[sp]
|
|
ret #16
|
|
|
|
|
|
;******************************************************************
|
|
; LIST
|
|
;
|
|
; LISTX has two forms:
|
|
; 'LIST<CR>' lists all saved lines
|
|
; 'LIST #<CR>' starts listing at the line #
|
|
; Control-S pauses the listing, control-C stops it.
|
|
;******************************************************************
|
|
;
|
|
LISTX:
|
|
call TSTNUM ; see if there's a line no.
|
|
mov r5,r1
|
|
call ENDCHK ; if not, we get a zero
|
|
mov r1,r5
|
|
call FNDLN ; find this or next line
|
|
LS1:
|
|
bne r1,r0,LS4
|
|
beq r9,r0,WSTART ; warm start if we passed the end
|
|
LS4:
|
|
mov r1,r9
|
|
call PRTLN ; print the line
|
|
mov r9,r1 ; set pointer for next
|
|
call CHKIO ; check for listing halt request
|
|
beq r1,r0,LS3
|
|
bnei r1,#CTRLS,LS3 ; pause the listing?
|
|
LS2:
|
|
call CHKIO ; if so, wait for another keypress
|
|
beq r1,r0,LS2
|
|
LS3:
|
|
setlo r1,#0
|
|
call FNDLNP ; find the next line
|
|
bra LS1
|
|
|
|
|
|
;******************************************************************
|
|
; PRINT command is 'PRINT ....:' or 'PRINT ....<CR>'
|
|
; where '....' is a list of expressions, formats, back-arrows,
|
|
; and strings. These items a separated by commas.
|
|
;
|
|
; A format is a pound sign followed by a number. It controls
|
|
; the number of spaces the value of an expression is going to
|
|
; be printed in. It stays effective for the rest of the print
|
|
; command unless changed by another format. If no format is
|
|
; specified, 11 positions will be used.
|
|
;
|
|
; A string is quoted in a pair of single- or double-quotes.
|
|
;
|
|
; An underline (back-arrow) means generate a <CR> without a <LF>
|
|
;
|
|
; A <CR LF> is generated after the entire list has been printed
|
|
; or if the list is empty. If the list ends with a semicolon,
|
|
; however, no <CR LF> is generated.
|
|
;******************************************************************
|
|
;
|
|
PRINT:
|
|
lw r5,#11 ; D4 = number of print spaces
|
|
setlo r3,#':'
|
|
lea r4,PR2
|
|
call TSTC ; if null list and ":"
|
|
call CRLF ; give CR-LF and continue
|
|
bra RUNSML ; execution on the same line
|
|
PR2:
|
|
setlo r3,#CR
|
|
lea r4,PR0
|
|
call TSTC ;if null list and <CR>
|
|
call CRLF ;also give CR-LF and
|
|
bra RUNNXL ;execute the next line
|
|
PR0:
|
|
setlo r3,#'#'
|
|
lea r4,PR1
|
|
call TSTC ;else is it a format?
|
|
call OREXPR ; yes, evaluate expression
|
|
lw r5,r1 ; and save it as print width
|
|
bra PR3 ; look for more to print
|
|
PR1:
|
|
setlo r3,#'$'
|
|
lea r4,PR4
|
|
call TSTC ; is character expression? (MRL)
|
|
call OREXPR ; yep. Evaluate expression (MRL)
|
|
call GOOUT ; print low byte (MRL)
|
|
bra PR3 ;look for more. (MRL)
|
|
PR4:
|
|
call QTSTG ; is it a string?
|
|
; the following branch must occupy only two bytes!
|
|
bra PR8 ; if not, must be an expression
|
|
PR3:
|
|
setlo r3,#','
|
|
lea r4,PR6
|
|
call TSTC ; if ",", go find next
|
|
call FIN ;in the list.
|
|
bra PR0
|
|
PR6:
|
|
call CRLF ;list ends here
|
|
bra FINISH
|
|
PR8:
|
|
call OREXPR ; evaluate the expression
|
|
lw r2,r5 ; set the width
|
|
call PRTNUM ; print its value
|
|
bra PR3 ; more to print?
|
|
|
|
FINISH:
|
|
call FIN ; Check end of command
|
|
jmp QWHAT ; print "What?" if wrong
|
|
|
|
|
|
;*******************************************************************
|
|
;
|
|
; *** GOSUB *** & RETURN ***
|
|
;
|
|
; 'GOSUB expr:' or 'GOSUB expr<CR>' is like the 'GOTO' command,
|
|
; except that the current text pointer, stack pointer, etc. are
|
|
; saved so that execution can be continued after the subroutine
|
|
; 'RETURN's. In order that 'GOSUB' can be nested (and even
|
|
; recursive), the save area must be stacked. The stack pointer
|
|
; is saved in 'STKGOS'. The old 'STKGOS' is saved on the stack.
|
|
; If we are in the main routine, 'STKGOS' is zero (this was done
|
|
; in the initialization section of the interpreter), but we still
|
|
; save it as a flag for no further 'RETURN's.
|
|
;******************************************************************
|
|
;
|
|
GOSUB:
|
|
call PUSHA ; save the current 'FOR' parameters
|
|
call OREXPR ; get line number
|
|
call FNDLN ; find the target line
|
|
bne r1,r0,gosub1
|
|
lea r1,msgBadGotoGosub
|
|
bra ERROR ; if not there, say "How?"
|
|
gosub1:
|
|
sub sp,sp,#24
|
|
sw r8,[sp] ; save text pointer
|
|
lw r1,CURRNT
|
|
sw r1,8[sp] ; found it, save old 'CURRNT'...
|
|
lw r1,STKGOS
|
|
sw r1,16[sp] ; and 'STKGOS'
|
|
sw r0,LOPVAR ; load new values
|
|
sw sp,STKGOS
|
|
bra RUNTSL
|
|
|
|
|
|
;******************************************************************
|
|
; 'RETURN<CR>' undoes everything that 'GOSUB' did, and thus
|
|
; returns the execution to the command after the most recent
|
|
; 'GOSUB'. If 'STKGOS' is zero, it indicates that we never had
|
|
; a 'GOSUB' and is thus an error.
|
|
;******************************************************************
|
|
;
|
|
RETURN:
|
|
call ENDCHK ; there should be just a <CR>
|
|
lw r1,STKGOS ; get old stack pointer
|
|
bne r1,r0,return1
|
|
lea r1,msgRetWoGosub
|
|
bra ERROR ; if zero, it doesn't exist
|
|
return1:
|
|
mov sp,r1 ; else restore it
|
|
lw r1,16[sp]
|
|
sw r1,STKGOS ; and the old 'STKGOS'
|
|
lw r1,8[sp]
|
|
sw r1,CURRNT ; and the old 'CURRNT'
|
|
lw r8,[sp] ; and the old text pointer
|
|
add sp,sp,#24
|
|
call POPA ;and the old 'FOR' parameters
|
|
bra FINISH ;and we are back home
|
|
|
|
;******************************************************************
|
|
; *** FOR *** & NEXT ***
|
|
;
|
|
; 'FOR' has two forms:
|
|
; 'FOR var=exp1 TO exp2 STEP exp1' and 'FOR var=exp1 TO exp2'
|
|
; The second form means the same thing as the first form with a
|
|
; STEP of positive 1. The interpreter will find the variable 'var'
|
|
; and set its value to the current value of 'exp1'. It also
|
|
; evaluates 'exp2' and 'exp1' and saves all these together with
|
|
; the text pointer, etc. in the 'FOR' save area, which consists of
|
|
; 'LOPVAR', 'LOPINC', 'LOPLMT', 'LOPLN', and 'LOPPT'. If there is
|
|
; already something in the save area (indicated by a non-zero
|
|
; 'LOPVAR'), then the old save area is saved on the stack before
|
|
; the new values are stored. The interpreter will then dig in the
|
|
; stack and find out if this same variable was used in another
|
|
; currently active 'FOR' loop. If that is the case, then the old
|
|
; 'FOR' loop is deactivated. (i.e. purged from the stack)
|
|
;******************************************************************
|
|
;
|
|
FOR:
|
|
call PUSHA ; save the old 'FOR' save area
|
|
call SETVAL ; set the control variable
|
|
sw r1,LOPVAR ; save its address
|
|
lea r9,TAB5
|
|
lea r10,TAB5_1; use 'EXEC' to test for 'TO'
|
|
jmp EXEC
|
|
FR1:
|
|
call OREXPR ; evaluate the limit
|
|
sw r1,LOPLMT ; save that
|
|
lea r9,TAB6
|
|
lea r10,TAB6_1 ; use 'EXEC' to test for the word 'STEP
|
|
jmp EXEC
|
|
FR2:
|
|
call OREXPR ; found it, get the step value
|
|
bra FR4
|
|
FR3:
|
|
setlo r1,#1 ; not found, step defaults to 1
|
|
FR4:
|
|
sw r1,LOPINC ; save that too
|
|
FR5:
|
|
lw r2,CURRNT
|
|
sw r2,LOPLN ; save address of current line number
|
|
sw r8,LOPPT ; and text pointer
|
|
lw r3,sp ; dig into the stack to find 'LOPVAR'
|
|
lw r6,LOPVAR
|
|
bra FR7
|
|
FR6:
|
|
addui r3,r3,#40 ; look at next stack frame
|
|
FR7:
|
|
lw r2,[r3] ; is it zero?
|
|
beq r2,r0,FR8 ; if so, we're done
|
|
bne r2,r6,FR6 ; same as current LOPVAR? nope, look some more
|
|
|
|
lw r1,r3 ; Else remove 5 long words from...
|
|
addui r2,r3,#40 ; inside the stack.
|
|
lw r3,sp
|
|
call MVDOWN
|
|
add sp,sp,#40 ; set the SP 5 long words up
|
|
FR8:
|
|
bra FINISH ; and continue execution
|
|
|
|
|
|
;******************************************************************
|
|
; 'NEXT var' serves as the logical (not necessarily physical) end
|
|
; of the 'FOR' loop. The control variable 'var' is checked with
|
|
; the 'LOPVAR'. If they are not the same, the interpreter digs in
|
|
; the stack to find the right one and purges all those that didn't
|
|
; match. Either way, it then adds the 'STEP' to that variable and
|
|
; checks the result with against the limit value. If it is within
|
|
; the limit, control loops back to the command following the
|
|
; 'FOR'. If it's outside the limit, the save area is purged and
|
|
; execution continues.
|
|
;******************************************************************
|
|
;
|
|
NEXT:
|
|
setlo r1,#0 ; don't allocate it
|
|
call TSTV ; get address of variable
|
|
bne r1,r0,NX4
|
|
lea r1,msgNextVar
|
|
bra ERROR ; if no variable, say "What?"
|
|
NX4:
|
|
mov r9,r1 ; save variable's address
|
|
NX0:
|
|
lw r1,LOPVAR ; If 'LOPVAR' is zero, we never...
|
|
bne r1,r0,NX5 ; had a FOR loop
|
|
lea r1,msgNextFor
|
|
bra ERROR
|
|
NX5:
|
|
beq r1,r9,NX2 ; else we check them OK, they agree
|
|
call POPA ; nope, let's see the next frame
|
|
bra NX0
|
|
NX2:
|
|
lw r1,[r9] ; get control variable's value
|
|
lw r2,LOPINC
|
|
addu r1,r1,r2 ; add in loop increment
|
|
; BVS.L QHOW say "How?" for 32-bit overflow
|
|
sw r1,[r9] ; save control variable's new value
|
|
lw r3,LOPLMT ; get loop's limit value
|
|
bgt r2,r0,NX1 ; check loop increment, branch if loop increment is positive
|
|
blt r1,r3,NXPurge ; test against limit
|
|
bra NX3
|
|
NX1:
|
|
bgt r1,r3,NXPurge
|
|
NX3:
|
|
lw r8,LOPLN ; Within limit, go back to the...
|
|
sw r8,CURRNT
|
|
lw r8,LOPPT ; saved 'CURRNT' and text pointer.
|
|
bra FINISH
|
|
NXPurge:
|
|
call POPA ; purge this loop
|
|
bra FINISH
|
|
|
|
|
|
;******************************************************************
|
|
; *** REM *** IF *** INPUT *** LET (& DEFLT) ***
|
|
;
|
|
; 'REM' can be followed by anything and is ignored by the
|
|
; interpreter.
|
|
;
|
|
;REM
|
|
; br IF2 ; skip the rest of the line
|
|
; 'IF' is followed by an expression, as a condition and one or
|
|
; more commands (including other 'IF's) separated by colons.
|
|
; Note that the word 'THEN' is not used. The interpreter evaluates
|
|
; the expression. If it is non-zero, execution continues. If it
|
|
; is zero, the commands that follow are ignored and execution
|
|
; continues on the next line.
|
|
;******************************************************************
|
|
;
|
|
IF:
|
|
call OREXPR ; evaluate the expression
|
|
IF1:
|
|
bne r1,r0,RUNSML ; is it zero? if not, continue
|
|
IF2:
|
|
mov r9,r8 ; set lookup pointer
|
|
setlo r1,#0 ; find line #0 (impossible)
|
|
call FNDSKP ; if so, skip the rest of the line
|
|
bgt r1,r0,WSTART ; if no next line, do a warm start
|
|
IF3:
|
|
bra RUNTSL ; run the next line
|
|
|
|
|
|
;******************************************************************
|
|
; INPUT is called first and establishes a stack frame
|
|
INPERR:
|
|
lw sp,STKINP ; restore the old stack pointer
|
|
lw r8,16[sp]
|
|
sw r8,CURRNT ; and old 'CURRNT'
|
|
lw r8,8[sp] ; and old text pointer
|
|
addui sp,sp,#40 ; fall through will subtract 40
|
|
|
|
; 'INPUT' is like the 'PRINT' command, and is followed by a list
|
|
; of items. If the item is a string in single or double quotes,
|
|
; or is an underline (back arrow), it has the same effect as in
|
|
; 'PRINT'. If an item is a variable, this variable name is
|
|
; printed out followed by a colon, then the interpreter waits for
|
|
; an expression to be typed in. The variable is then set to the
|
|
; value of this expression. If the variable is preceeded by a
|
|
; string (again in single or double quotes), the string will be
|
|
; displayed followed by a colon. The interpreter the waits for an
|
|
; expression to be entered and sets the variable equal to the
|
|
; expression's value. If the input expression is invalid, the
|
|
; interpreter will print "What?", "How?", or "Sorry" and reprint
|
|
; the prompt and redo the input. The execution will not terminate
|
|
; unless you press control-C. This is handled in 'INPERR'.
|
|
;
|
|
INPUT:
|
|
subui sp,sp,#40 ; allocate stack frame
|
|
sw r5,32[sp]
|
|
IP6:
|
|
sw r8,[sp] ; save in case of error
|
|
call QTSTG ; is next item a string?
|
|
bra IP2 ; nope - this branch must take only two bytes
|
|
setlo r1,#1 ; allocate var
|
|
call TSTV ; yes, but is it followed by a variable?
|
|
beq r1,r0,IP4 ; if not, brnch
|
|
mov r10,r1 ; put away the variable's address
|
|
bra IP3 ; if so, input to variable
|
|
IP2:
|
|
sw r8,8[sp] ; save for 'PRTSTG'
|
|
setlo r1,#1
|
|
call TSTV ; must be a variable now
|
|
bne r1,r0,IP7
|
|
lea r1,msgInputVar
|
|
bra ERROR ; "What?" it isn't?
|
|
IP7:
|
|
mov r10,r1 ; put away the variable's address
|
|
lb r5,[r8] ; get ready for 'PRTSTG' by null terminating
|
|
sb r0,[r8]
|
|
lw r1,8[sp] ; get back text pointer
|
|
call PRTSTG ; print string as prompt
|
|
sb r5,[r8] ; un-null terminate
|
|
IP3
|
|
sw r8,8[sp] ; save in case of error
|
|
lw r1,CURRNT
|
|
sw r1,16[sp] ; also save 'CURRNT'
|
|
setlo r1,#-1
|
|
sw r1,CURRNT ; flag that we are in INPUT
|
|
sw sp,STKINP ; save the stack pointer too
|
|
sw r10,24[sp] ; save the variable address
|
|
setlo r1,#':' ; print a colon first
|
|
call GETLN ; then get an input line
|
|
lea r8,BUFFER ; point to the buffer
|
|
call OREXPR ; evaluate the input
|
|
lw r10,24[sp] ; restore the variable address
|
|
sw r1,[r10] ; save value in variable
|
|
lw r1,16[sp] ; restore old 'CURRNT'
|
|
sw r1,CURRNT
|
|
lw r8,8[sp] ; and the old text pointer
|
|
IP4:
|
|
setlo r3,#','
|
|
lea r4,IP5 ; is the next thing a comma?
|
|
call TSTC
|
|
bra IP6 ; yes, more items
|
|
IP5:
|
|
lw r5,32[sp]
|
|
add sp,sp,#40 ; clean up the stack
|
|
jmp FINISH
|
|
|
|
|
|
DEFLT:
|
|
lb r1,[r8]
|
|
beq r1,#CR,FINISH ; empty line is OK else it is 'LET'
|
|
|
|
|
|
;******************************************************************
|
|
; 'LET' is followed by a list of items separated by commas.
|
|
; Each item consists of a variable, an equals sign, and an
|
|
; expression. The interpreter evaluates the expression and sets
|
|
; the variable to that value. The interpreter will also handle
|
|
; 'LET' commands without the word 'LET'. This is done by 'DEFLT'.
|
|
;******************************************************************
|
|
;
|
|
LET:
|
|
call SETVAL ; do the assignment
|
|
setlo r3,#','
|
|
lea r4,FINISH
|
|
call TSTC ; check for more 'LET' items
|
|
bra LET
|
|
LT1:
|
|
bra FINISH ; until we are finished.
|
|
|
|
|
|
;******************************************************************
|
|
; *** LOAD *** & SAVE ***
|
|
;
|
|
; These two commands transfer a program to/from an auxiliary
|
|
; device such as a cassette, another computer, etc. The program
|
|
; is converted to an easily-stored format: each line starts with
|
|
; a colon, the line no. as 4 hex digits, and the rest of the line.
|
|
; At the end, a line starting with an '@' sign is sent. This
|
|
; format can be read back with a minimum of processing time by
|
|
; the Butterfly.
|
|
;******************************************************************
|
|
;
|
|
LOAD
|
|
lw r8,TXTBGN ; set pointer to start of prog. area
|
|
setlo r1,#CR ; For a CP/M host, tell it we're ready...
|
|
call GOAUXO ; by sending a CR to finish PIP command.
|
|
LOD1:
|
|
call GOAUXI ; look for start of line
|
|
ble r1,r0,LOD1
|
|
beq r1,#'@',LODEND ; end of program?
|
|
beq r1,#0x1A,LODEND ; or EOF marker
|
|
bne r1,#':',LOD1 ; if not, is it start of line? if not, wait for it
|
|
call GCHAR ; get line number
|
|
sb r1,[r8] ; store it
|
|
shrui r1,r1,#8
|
|
sb r1,1[r8]
|
|
addui r8,r8,#2
|
|
LOD2:
|
|
call GOAUXI ; get another text char.
|
|
ble r1,r0,LOD2
|
|
sb r1,[r8]
|
|
addui r8,r8,#1 ; store it
|
|
bne r1,#CR,LOD2 ; is it the end of the line? if not, go back for more
|
|
bra LOD1 ; if so, start a new line
|
|
LODEND:
|
|
sw r8,TXTUNF ; set end-of program pointer
|
|
bra WSTART ; back to direct mode
|
|
|
|
|
|
; get character from input (16 bit value)
|
|
GCHAR:
|
|
subui sp,sp,#24
|
|
sw r5,[sp]
|
|
sw r6,8[sp]
|
|
sw lr,16[sp]
|
|
setlo r6,#3 ; repeat four times
|
|
setlo r5,#0
|
|
GCHAR1:
|
|
call GOAUXI ; get a char
|
|
ble r1,r0,GCHAR1
|
|
call asciiToHex
|
|
shli r5,r5,#4
|
|
or r5,r5,r1
|
|
loop r6,GCHAR1
|
|
mov r1,r5
|
|
lw lr,16[sp]
|
|
lw r6,8[sp]
|
|
lw r5,[sp]
|
|
ret #24
|
|
|
|
|
|
; convert an ascii char to hex code
|
|
; input
|
|
; r1 = char to convert
|
|
|
|
asciiToHex:
|
|
blei r1,#'9',a2h1 ; less than '9'
|
|
subui r1,r1,#7 ; shift 'A' to '9'+1
|
|
a2h1:
|
|
subui r1,r1,#'0' ;
|
|
andi r1,r1,#15 ; make sure a nybble
|
|
ret
|
|
|
|
|
|
|
|
SAVE:
|
|
lw r8,TXTBGN ;set pointer to start of prog. area
|
|
lw r9,TXTUNF ;set pointer to end of prog. area
|
|
SAVE1:
|
|
call AUXOCRLF ; send out a CR & LF (CP/M likes this)
|
|
bgeu r8,r9,SAVEND ; are we finished?
|
|
setlo r1,#':' ; if not, start a line
|
|
call GOAUXO
|
|
lbu r1,[r8] ; get line number
|
|
lbu r2,1[r8]
|
|
shli r2,r2,#8
|
|
or r1,r1,r2
|
|
addui r8,r8,#2
|
|
call PWORD ; output line number as 4-digit hex
|
|
SAVE2:
|
|
lb r1,[r8] ; get a text char.
|
|
addui r8,r8,#1
|
|
beqi r1,#CR,SAVE1 ; is it the end of the line? if so, send CR & LF and start new line
|
|
call GOAUXO ; send it out
|
|
bra SAVE2 ; go back for more text
|
|
SAVEND:
|
|
setlo r1,#'@' ; send end-of-program indicator
|
|
call GOAUXO
|
|
call AUXOCRLF ; followed by a CR & LF
|
|
setlo r1,#0x1A ; and a control-Z to end the CP/M file
|
|
call GOAUXO
|
|
bra WSTART ; then go do a warm start
|
|
|
|
|
|
; output a CR LF sequence to auxillary output
|
|
; Registers Affected
|
|
; r3 = LF
|
|
AUXOCRLF:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
setlo r1,#CR
|
|
call GOAUXO
|
|
setlo r1,#LF
|
|
call GOAUXO
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
|
|
; output a word in hex format
|
|
; tricky because of the need to reverse the order of the chars
|
|
PWORD:
|
|
sub sp,sp,#16
|
|
sw lr,[sp]
|
|
sw r5,8[sp]
|
|
lea r5,NUMWKA+15
|
|
mov r4,r1 ; r4 = value
|
|
pword1:
|
|
mov r1,r4 ; r1 = value
|
|
shrui r4,r4,#4 ; shift over to next nybble
|
|
call toAsciiHex ; convert LS nybble to ascii hex
|
|
sb r1,[r5] ; save in work area
|
|
subui r5,r5,#1
|
|
cmpui r1,r5,#NUMWKA
|
|
bge r1,r0,pword1
|
|
pword2:
|
|
addui r5,r5,#1
|
|
lb r1,[r5] ; get char to output
|
|
call GOAUXO ; send it
|
|
cmpui r1,r5,#NUMWKA+15
|
|
blt r1,r0,pword2
|
|
lw r5,8[sp]
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
|
|
; convert nybble in r2 to ascii hex char2
|
|
; r2 = character to convert
|
|
|
|
toAsciiHex:
|
|
andi r1,r1,#15 ; make sure it's a nybble
|
|
blti r1,#10,tah1 ; > 10 ?
|
|
addi r1,r1,#7 ; bump it up to the letter 'A'
|
|
tah1:
|
|
addui r1,r1,#'0' ; bump up to ascii '0'
|
|
ret
|
|
|
|
|
|
|
|
;******************************************************************
|
|
; *** POKE *** & SYSX ***
|
|
;
|
|
; 'POKE expr1,expr2' stores the byte from 'expr2' into the memory
|
|
; address specified by 'expr1'.
|
|
;
|
|
; 'SYSX expr' jumps to the machine language subroutine whose
|
|
; starting address is specified by 'expr'. The subroutine can use
|
|
; all registers but must leave the stack the way it found it.
|
|
; The subroutine returns to the interpreter by executing an RET.
|
|
;******************************************************************
|
|
;
|
|
POKE:
|
|
subui sp,sp,#8
|
|
call OREXPR ; get the memory address
|
|
setlo r3,#','
|
|
lea r4,PKER ; it must be followed by a comma
|
|
call TSTC ; it must be followed by a comma
|
|
sw r1,[sp] ; save the address
|
|
call OREXPR ; get the byte to be POKE'd
|
|
lw r2,[sp] ; get the address back
|
|
sb r1,[r2] ; store the byte in memory
|
|
addui sp,sp,#8
|
|
bra FINISH
|
|
PKER:
|
|
lea r1,msgComma
|
|
bra ERROR ; if no comma, say "What?"
|
|
|
|
POKEC:
|
|
subui sp,sp,#8
|
|
call OREXPR ; get the memory address
|
|
setlo r3,#','
|
|
lea r4,PKER ; it must be followed by a comma
|
|
call TSTC ; it must be followed by a comma
|
|
sw r1,[sp] ; save the address
|
|
call OREXPR ; get the byte to be POKE'd
|
|
lw r2,[sp] ; get the address back
|
|
sc r1,[r2] ; store the char in memory
|
|
addui sp,sp,#8
|
|
jmp FINISH
|
|
|
|
POKEH:
|
|
subui sp,sp,#8
|
|
call OREXPR ; get the memory address
|
|
setlo r3,#','
|
|
lea r4,PKER ; it must be followed by a comma
|
|
call TSTC
|
|
sw r1,[sp] ; save the address
|
|
call OREXPR ; get the byte to be POKE'd
|
|
lw r2,[sp] ; get the address back
|
|
sh r1,[r2] ; store the word in memory
|
|
addui sp,sp,#8
|
|
jmp FINISH
|
|
|
|
POKEW:
|
|
subui sp,sp,#8
|
|
call OREXPR ; get the memory address
|
|
setlo r3,#','
|
|
lea r4,PKER ; it must be followed by a comma
|
|
call TSTC
|
|
sw r1,[sp] ; save the address
|
|
call OREXPR ; get the word to be POKE'd
|
|
lw r2,[sp] ; get the address back
|
|
sw r1,[r2] ; store the word in memory
|
|
addui sp,sp,#8
|
|
jmp FINISH
|
|
|
|
SYSX:
|
|
subui sp,sp,#8
|
|
call OREXPR ; get the subroutine's address
|
|
bne r1,r0,sysx1 ; make sure we got a valid address
|
|
lea r1,msgSYSBad
|
|
bra ERROR
|
|
sysx1:
|
|
sw r8,[sp] ; save the text pointer
|
|
jal r31,[r1] ; jump to the subroutine
|
|
lw r8,[sp] ; restore the text pointer
|
|
addui sp,sp,#8
|
|
bra FINISH
|
|
|
|
;******************************************************************
|
|
; *** EXPR ***
|
|
;
|
|
; 'EXPR' evaluates arithmetical or logical expressions.
|
|
; <OREXPR>::= <ANDEXPR> OR <ANDEXPR> ...
|
|
; <ANDEXPR>::=<EXPR> AND <EXPR> ...
|
|
; <EXPR>::=<EXPR2>
|
|
; <EXPR2><rel.op.><EXPR2>
|
|
; where <rel.op.> is one of the operators in TAB8 and the result
|
|
; of these operations is 1 if true and 0 if false.
|
|
; <EXPR2>::=(+ or -)<EXPR3>(+ or -)<EXPR3>(...
|
|
; where () are optional and (... are optional repeats.
|
|
; <EXPR3>::=<EXPR4>( <* or /><EXPR4> )(...
|
|
; <EXPR4>::=<variable>
|
|
; <function>
|
|
; (<EXPR>)
|
|
; <EXPR> is recursive so that the variable '@' can have an <EXPR>
|
|
; as an index, functions can have an <EXPR> as arguments, and
|
|
; <EXPR4> can be an <EXPR> in parenthesis.
|
|
;
|
|
|
|
; <OREXPR>::=<ANDEXPR> OR <ANDEXPR> ...
|
|
;
|
|
OREXPR:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
call ANDEXPR ; get first <ANDEXPR>
|
|
XP_OR1:
|
|
sw r1,4[sp] ; save <ANDEXPR> value
|
|
lea r9,TAB10 ; look up a logical operator
|
|
lea r10,TAB10_1
|
|
jmp EXEC ; go do it
|
|
XP_OR:
|
|
call ANDEXPR
|
|
lw r2,8[sp]
|
|
or r1,r1,r2
|
|
bra XP_OR1
|
|
XP_ORX:
|
|
lw r1,8[sp]
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
|
|
; <ANDEXPR>::=<EXPR> AND <EXPR> ...
|
|
;
|
|
ANDEXPR:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
call EXPR ; get first <EXPR>
|
|
XP_AND1:
|
|
sw r1,8[sp] ; save <EXPR> value
|
|
lea r9,TAB9 ; look up a logical operator
|
|
lea r10,TAB9_1
|
|
jmp EXEC ; go do it
|
|
XP_AND:
|
|
call EXPR
|
|
lw r2,8[sp]
|
|
and r1,r1,r2
|
|
bra XP_AND1
|
|
XP_ANDX:
|
|
lw r1,8[sp]
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
|
|
; Determine if the character is a digit
|
|
; Parameters
|
|
; r1 = char to test
|
|
; Returns
|
|
; r1 = 1 if digit, otherwise 0
|
|
;
|
|
isDigit:
|
|
blt r1,#'0',isDigitFalse
|
|
bgt r1,#'9',isDigitFalse
|
|
setlo r1,#1
|
|
ret
|
|
isDigitFalse:
|
|
setlo r1,#0
|
|
ret
|
|
|
|
|
|
; Determine if the character is a alphabetic
|
|
; Parameters
|
|
; r1 = char to test
|
|
; Returns
|
|
; r1 = 1 if alpha, otherwise 0
|
|
;
|
|
isAlpha:
|
|
blt r1,#'A',isAlphaFalse
|
|
ble r1,#'Z',isAlphaTrue
|
|
blt r1,#'a',isAlphaFalse
|
|
bgt r1,#'z',isAlphaFalse
|
|
isAlphaTrue:
|
|
setlo r1,#1
|
|
ret
|
|
isAlphaFalse:
|
|
setlo r1,#0
|
|
ret
|
|
|
|
|
|
; Determine if the character is a alphanumeric
|
|
; Parameters
|
|
; r1 = char to test
|
|
; Returns
|
|
; r1 = 1 if alpha, otherwise 0
|
|
;
|
|
isAlnum:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
or r2,r1,r0 ; save test char
|
|
call isDigit
|
|
bne r1,r0,isDigitx ; if it is a digit
|
|
or r1,r2,r0 ; get back test char
|
|
call isAlpha
|
|
isDigitx:
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
|
|
EXPR:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
call EXPR2
|
|
sw r1,8[sp] ; save <EXPR2> value
|
|
lea r9,TAB8 ; look up a relational operator
|
|
lea r10,TAB8_1
|
|
jmp EXEC ; go do it
|
|
XP11:
|
|
lw r1,8[sp]
|
|
call XP18 ; is it ">="?
|
|
bge r2,r1,XPRT1 ; no, return r2=1
|
|
bra XPRT0 ; else return r2=0
|
|
XP12:
|
|
lw r1,8[sp]
|
|
call XP18 ; is it "<>"?
|
|
bne r2,r1,XPRT1 ; no, return r2=1
|
|
bra XPRT0 ; else return r2=0
|
|
XP13:
|
|
lw r1,8[sp]
|
|
call XP18 ; is it ">"?
|
|
bgt r2,r1,XPRT1 ; no, return r2=1
|
|
bra XPRT0 ; else return r2=0
|
|
XP14:
|
|
lw r1,8[sp]
|
|
call XP18 ; is it "<="?
|
|
ble r2,r1,XPRT1 ; no, return r2=1
|
|
bra XPRT0 ; else return r2=0
|
|
XP15:
|
|
lw r1,8[sp]
|
|
call XP18 ; is it "="?
|
|
beq r2,r1,XPRT1 ; if not, return r2=1
|
|
bra XPRT0 ; else return r2=0
|
|
XP16:
|
|
lw r1,8[sp]
|
|
call XP18 ; is it "<"?
|
|
blt r2,r1,XPRT1 ; if not, return r2=1
|
|
bra XPRT0 ; else return r2=0
|
|
XPRT0:
|
|
lw lr,[sp]
|
|
setlo r1,#0 ; return r1=0 (false)
|
|
ret #16
|
|
XPRT1:
|
|
lw lr,[sp]
|
|
setlo r1,#1 ; return r1=1 (true)
|
|
ret #16
|
|
|
|
XP17: ; it's not a rel. operator
|
|
lw r1,8[sp] ; return r2=<EXPR2>
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
XP18:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
sw r1,8[sp]
|
|
call EXPR2 ; do a second <EXPR2>
|
|
lw r2,8[sp]
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
; <EXPR2>::=(+ or -)<EXPR3>(+ or -)<EXPR3>(...
|
|
|
|
EXPR2:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
setlo r3,#'-'
|
|
lea r4,XP21
|
|
call TSTC ; negative sign?
|
|
setlo r1,#0 ; yes, fake '0-'
|
|
sw r0,8[sp]
|
|
bra XP26
|
|
XP21:
|
|
setlo r3,#'+'
|
|
lea r4,XP22
|
|
call TSTC ; positive sign? ignore it
|
|
XP22:
|
|
call EXPR3 ; first <EXPR3>
|
|
XP23:
|
|
sw r1,8[sp] ; yes, save the value
|
|
setlo r3,#'+'
|
|
lea r4,XP25
|
|
call TSTC ; add?
|
|
call EXPR3 ; get the second <EXPR3>
|
|
XP24:
|
|
lw r2,8[sp]
|
|
add r1,r1,r2 ; add it to the first <EXPR3>
|
|
; BVS.L QHOW brnch if there's an overflow
|
|
bra XP23 ; else go back for more operations
|
|
XP25:
|
|
setlo r3,#'-'
|
|
lea r4,XP45
|
|
call TSTC ; subtract?
|
|
XP26:
|
|
call EXPR3 ; get second <EXPR3>
|
|
neg r1,r1 ; change its sign
|
|
bra XP24 ; and do an addition
|
|
XP45:
|
|
lw r1,8[sp]
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
|
|
; <EXPR3>::=<EXPR4>( <* or /><EXPR4> )(...
|
|
|
|
EXPR3:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
call EXPR4 ; get first <EXPR4>
|
|
XP31:
|
|
sw r1,8[sp] ; yes, save that first result
|
|
setlo r3,#'*'
|
|
lea r4,XP34
|
|
call TSTC ; multiply?
|
|
call EXPR4 ; get second <EXPR4>
|
|
lw r2,8[sp]
|
|
muls r1,r1,r2 ; multiply the two
|
|
bra XP31 ; then look for more terms
|
|
XP34:
|
|
setlo r3,#'/'
|
|
lea r4,XP47
|
|
call TSTC ; divide?
|
|
call EXPR4 ; get second <EXPR4>
|
|
or r2,r1,r0
|
|
lw r1,8[sp]
|
|
divs r1,r1,r2 ; do the division
|
|
bra XP31 ; go back for any more terms
|
|
XP47:
|
|
lw r1,8[sp]
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
|
|
; Functions are called through EXPR4
|
|
; <EXPR4>::=<variable>
|
|
; <function>
|
|
; (<EXPR>)
|
|
|
|
EXPR4:
|
|
subui sp,sp,#24
|
|
sw lr,[sp]
|
|
lea r9,TAB4 ; find possible function
|
|
lea r10,TAB4_1
|
|
jmp EXEC ; branch to function which does subsequent ret for EXPR4
|
|
XP40: ; we get here if it wasn't a function
|
|
setlo r1,#0
|
|
call TSTV
|
|
beq r1,r0,XP41 ; nor a variable
|
|
lw r1,[r1] ; if a variable, return its value in r1
|
|
lw lr,[sp]
|
|
ret #24
|
|
XP41:
|
|
call TSTNUM ; or is it a number?
|
|
bne r2,r0,XP46 ; (if not, # of digits will be zero) if so, return it in r1
|
|
call PARN ; check for (EXPR)
|
|
XP46:
|
|
lw lr,[sp]
|
|
ret #24
|
|
|
|
|
|
; Check for a parenthesized expression
|
|
PARN:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
setlo r3,#'('
|
|
lea r4,XP43
|
|
call TSTC ; else look for ( OREXPR )
|
|
call OREXPR
|
|
setlo r3,#')'
|
|
lea r4,XP43
|
|
call TSTC
|
|
XP42:
|
|
lw lr,[sp]
|
|
ret #8
|
|
XP43:
|
|
lea r1,msgWhat
|
|
bra ERROR
|
|
|
|
|
|
; ===== Test for a valid variable name. Returns Z=1 if not
|
|
; found, else returns Z=0 and the address of the
|
|
; variable in r1.
|
|
; Parameters
|
|
; r1 = 1 = allocate if not found
|
|
; Returns
|
|
; r1 = address of variable, zero if not found
|
|
|
|
TSTV:
|
|
subui sp,sp,#24
|
|
sw lr,[sp]
|
|
sw r5,8[sp]
|
|
or r5,r1,r0 ; allocate flag
|
|
call IGNBLK
|
|
lbu r1,[r8] ; look at the program text
|
|
blt r1,#'@',tstv_notfound ; C=1: not a variable
|
|
bne r1,#'@',TV1 ; brnch if not "@" array
|
|
addui r8,r8,#1 ; If it is, it should be
|
|
call PARN ; followed by (EXPR) as its index.
|
|
shli r1,r1,#3
|
|
; BCS.L QHOW say "How?" if index is too big
|
|
subui sp,sp,#24
|
|
sw r1,8[sp] ; save the index
|
|
sw lr,[sp]
|
|
call SIZEX ; get amount of free memory
|
|
lw lr,[sp]
|
|
lw r2,8[sp] ; get back the index
|
|
bltu r2,r1,TV2 ; see if there's enough memory
|
|
jmp QSORRY ; if not, say "Sorry"
|
|
TV2:
|
|
lea r1,VARBGN ; put address of array element...
|
|
subu r1,r1,r2 ; into r1 (neg. offset is used)
|
|
bra TSTVRT
|
|
TV1:
|
|
call getVarName ; get variable name
|
|
beq r1,r0,TSTVRT ; if not, return r1=0
|
|
mov r2,r5
|
|
call findVar ; find or allocate
|
|
TSTVRT:
|
|
lw r5,8[sp]
|
|
lw lr,[sp]
|
|
ret #24 ; r1<>0 (found)
|
|
tstv_notfound:
|
|
lw r5,8[sp]
|
|
lw lr,[sp]
|
|
setlo r1,#0 ; r1=0 if not found
|
|
ret #24
|
|
|
|
|
|
; Returns
|
|
; r1 = 6 character variable name + type
|
|
;
|
|
getVarName:
|
|
subui sp,sp,#24
|
|
sw lr,[sp]
|
|
sw r5,16[sp]
|
|
|
|
lb r1,[r8] ; get first character
|
|
sw r1,8[sp] ; save off current name
|
|
call isAlpha
|
|
beq r1,r0,gvn1
|
|
setlo r5,#5 ; loop six more times
|
|
|
|
; check for second/third character
|
|
gvn4:
|
|
addui r8,r8,#1
|
|
lb r1,[r8] ; do we have another char ?
|
|
call isAlnum
|
|
beq r1,r0,gvn2 ; nope
|
|
lw r1,8[sp] ; get varname
|
|
shli r1,r1,#8
|
|
lb r2,[r8]
|
|
or r1,r1,r2 ; add in new char
|
|
sw r1,8[sp] ; save off name again
|
|
loop r5,gvn4
|
|
|
|
; now ignore extra variable name characters
|
|
gvn6:
|
|
addui r8,r8,#1
|
|
lb r1,[r8]
|
|
call isAlnum
|
|
bne r1,r0,gvn6 ; keep looping as long as we have identifier chars
|
|
|
|
; check for a variable type
|
|
gvn2:
|
|
lb r1,[r8]
|
|
beq r1,#'%',gvn3
|
|
beq r1,#'$',gvn3
|
|
setlo r1,#0
|
|
subui r8,r8,#1
|
|
|
|
; insert variable type indicator and return
|
|
gvn3:
|
|
addui r8,r8,#1
|
|
lw r2,8[sp]
|
|
shli r2,r2,#8
|
|
or r1,r1,r2 ; add in variable type
|
|
lw lr,[sp]
|
|
lw r5,16[sp]
|
|
ret #24 ; return Z = 0, r1 = varname
|
|
|
|
; not a variable name
|
|
gvn1:
|
|
lw lr,[sp]
|
|
lw r5,16[sp]
|
|
setlo r1,#0 ; return Z = 1 if not a varname
|
|
ret #24
|
|
|
|
|
|
; Find variable
|
|
; r1 = varname
|
|
; r2 = allocate flag
|
|
; Returns
|
|
; r1 = variable address, Z =0 if found / allocated, Z=1 if not found
|
|
|
|
findVar:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
sw r7,8[sp]
|
|
lw r3,VARBGN
|
|
fv4:
|
|
lw r7,[r3] ; get varname / type
|
|
beq r7,r0,fv3 ; no more vars ?
|
|
beq r1,r7,fv1 ; match ?
|
|
add r3,r3,#8 ; move to next var
|
|
lw r7,STKBOT
|
|
blt r3,r7,fv4 ; loop back to look at next var
|
|
|
|
; variable not found
|
|
; no more memory
|
|
setlo r1,#<msgVarSpace
|
|
sethi r1,#>msgVarSpace
|
|
bra ERROR
|
|
; lw lr,[sp]
|
|
; lw r7,4[sp]
|
|
; add sp,sp,#8
|
|
; lw r1,#0
|
|
; ret
|
|
|
|
; variable not found
|
|
; allocate new ?
|
|
fv3:
|
|
beq r2,r0,fv2
|
|
sw r1,[r3] ; save varname / type
|
|
; found variable
|
|
; return address
|
|
fv1:
|
|
addui r1,r3,#8
|
|
lw lr,[sp]
|
|
lw r7,8[sp]
|
|
ret #16 ; Z = 0, r1 = address
|
|
|
|
; didn't find var and not allocating
|
|
fv2:
|
|
lw lr,[sp]
|
|
lw r7,8[sp]
|
|
addui sp,sp,#16 ; Z = 0, r1 = address
|
|
setlo r1,#0 ; Z = 1, r1 = 0
|
|
ret
|
|
|
|
|
|
; ===== Multiplies the 32 bit values in r1 and r2, returning
|
|
; the 32 bit result in r1.
|
|
;
|
|
|
|
; ===== Divide the 32 bit value in r2 by the 32 bit value in r3.
|
|
; Returns the 32 bit quotient in r1, remainder in r2
|
|
;
|
|
; r2 = a
|
|
; r3 = b
|
|
; r6 = remainder
|
|
; r7 = iteration count
|
|
; r8 = sign
|
|
;
|
|
|
|
; q = a / b
|
|
; a = r1
|
|
; b = r2
|
|
; q = r2
|
|
|
|
|
|
; ===== The PEEK function returns the byte stored at the address
|
|
; contained in the following expression.
|
|
;
|
|
PEEK:
|
|
call PARN ; get the memory address
|
|
lbu r1,[r1] ; get the addressed byte
|
|
lw lr,[sp] ; and return it
|
|
ret #24
|
|
|
|
; ===== The PEEK function returns the byte stored at the address
|
|
; contained in the following expression.
|
|
;
|
|
PEEKC:
|
|
call PARN ; get the memory address
|
|
andi r1,r1,#-2 ; align to char address
|
|
lcu r1,[r1] ; get the addressed char
|
|
lw lr,[sp] ; and return it
|
|
ret #24
|
|
|
|
; ===== The PEEK function returns the byte stored at the address
|
|
; contained in the following expression.
|
|
;
|
|
PEEKH:
|
|
call PARN ; get the memory address
|
|
andi r1,r1,#-4 ; align to half-word address
|
|
lhu r1,[r1] ; get the addressed char
|
|
lw lr,[sp] ; and return it
|
|
ret #24
|
|
|
|
; ===== The PEEK function returns the byte stored at the address
|
|
; contained in the following expression.
|
|
;
|
|
PEEKW:
|
|
call PARN ; get the memory address
|
|
andi r1,r1,#-8 ; align to word address
|
|
lw r1,[r1] ; get the addressed word
|
|
lw lr,[sp] ; and return it
|
|
ret #24
|
|
|
|
; user function call
|
|
; call the user function with argument in r1
|
|
USRX:
|
|
call PARN ; get expression value
|
|
sw r8,8[sp] ; save the text pointer
|
|
lw r2,usrJmp ; get usr vector
|
|
jal r31,[r2] ; jump to the subroutine
|
|
lw r8,8[sp] ; restore the text pointer
|
|
lw lr,[sp]
|
|
ret #24
|
|
|
|
|
|
; ===== The RND function returns a random number from 1 to
|
|
; the value of the following expression in D0.
|
|
;
|
|
RND:
|
|
call PARN ; get the upper limit
|
|
beq r1,r0,rnd2 ; it must be positive and non-zero
|
|
blt r1,r0,rnd1
|
|
lw r2,r1
|
|
gran ; generate a random number
|
|
mfspr r1,rand ; get the number
|
|
call modu4 ; RND(n)=MOD(number,n)+1
|
|
addui r1,r1,#1
|
|
lw lr,[sp]
|
|
ret #24
|
|
rnd1:
|
|
lea r1,msgRNDBad
|
|
bra ERROR
|
|
rnd2:
|
|
gran
|
|
mfspr r1,rand
|
|
lw lr,[sp]
|
|
ret #24
|
|
|
|
|
|
; r = a mod b
|
|
; a = r1
|
|
; b = r2
|
|
; r = r6
|
|
modu4:
|
|
subui sp,sp,#32
|
|
sw r3,[sp]
|
|
sw r5,8[sp]
|
|
sw r6,16[sp]
|
|
sw r7,24[sp]
|
|
lw r7,#63 ; n = 64
|
|
xor r5,r5,r5 ; w = 0
|
|
xor r6,r6,r6 ; r = 0
|
|
mod2:
|
|
roli r1,r1,#1 ; a <<= 1
|
|
andi r3,r1,#1
|
|
shli r6,r6,#1 ; r <<= 1
|
|
or r6,r6,r3
|
|
andi r1,r1,#-2
|
|
bgtu r2,r6,mod1 ; b < r ?
|
|
subu r6,r6,r2 ; r -= b
|
|
mod1:
|
|
loop r7,mod2 ; n--
|
|
mov r1,r6
|
|
lw r3,[sp]
|
|
lw r5,8[sp]
|
|
lw r6,16[sp]
|
|
lw r7,24[sp]
|
|
ret #32
|
|
|
|
|
|
; ===== The ABS function returns an absolute value in r2.
|
|
;
|
|
ABS:
|
|
call PARN ; get the following expr.'s value
|
|
abs r1,r1
|
|
lw lr,[sp]
|
|
ret #24
|
|
|
|
; ===== The SGN function returns the sign in r1. +1,0, or -1
|
|
;
|
|
SGN:
|
|
call PARN ; get the following expr.'s value
|
|
sgn r1,r1
|
|
lw lr,[sp]
|
|
ret #24
|
|
|
|
; ===== The SIZE function returns the size of free memory in r1.
|
|
;
|
|
SIZEX:
|
|
lw r1,VARBGN ; get the number of free bytes...
|
|
lw r2,TXTUNF ; between 'TXTUNF' and 'VARBGN'
|
|
subu r1,r1,r2
|
|
lw lr,[sp]
|
|
ret #24 ; return the number in r2
|
|
|
|
|
|
;******************************************************************
|
|
;
|
|
; *** SETVAL *** FIN *** ENDCHK *** ERROR (& friends) ***
|
|
;
|
|
; 'SETVAL' expects a variable, followed by an equal sign and then
|
|
; an expression. It evaluates the expression and sets the variable
|
|
; to that value.
|
|
;
|
|
; 'FIN' checks the end of a command. If it ended with ":",
|
|
; execution continues. If it ended with a CR, it finds the
|
|
; the next line and continues from there.
|
|
;
|
|
; 'ENDCHK' checks if a command is ended with a CR. This is
|
|
; required in certain commands, such as GOTO, RETURN, STOP, etc.
|
|
;
|
|
; 'ERROR' prints the string pointed to by r1. It then prints the
|
|
; line pointed to by CURRNT with a "?" inserted at where the
|
|
; old text pointer (should be on top of the stack) points to.
|
|
; Execution of Tiny BASIC is stopped and a warm start is done.
|
|
; If CURRNT is zero (indicating a direct command), the direct
|
|
; command is not printed. If CURRNT is -1 (indicating
|
|
; 'INPUT' command in progress), the input line is not printed
|
|
; and execution is not terminated but continues at 'INPERR'.
|
|
;
|
|
; Related to 'ERROR' are the following:
|
|
; 'QWHAT' saves text pointer on stack and gets "What?" message.
|
|
; 'AWHAT' just gets the "What?" message and jumps to 'ERROR'.
|
|
; 'QSORRY' and 'ASORRY' do the same kind of thing.
|
|
; 'QHOW' and 'AHOW' also do this for "How?".
|
|
;
|
|
|
|
; returns
|
|
; r2 = variable's address
|
|
;
|
|
SETVAL:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
setlo r1,#1 ; allocate var
|
|
call TSTV ; variable name?
|
|
bne r1,r0,sv2
|
|
lea r1,msgVar
|
|
bra ERROR
|
|
sv2:
|
|
sw r1,8[sp] ; save the variable's address
|
|
setlo r3,#'='
|
|
lea r4,SV1
|
|
call TSTC ; get past the "=" sign
|
|
call OREXPR ; evaluate the expression
|
|
lw r2,8[sp] ; get back the variable's address
|
|
sw r1,[r2] ; and save value in the variable
|
|
lw r1,r2 ; return r1 = variable address
|
|
lw lr,[sp]
|
|
ret #16
|
|
SV1:
|
|
bra QWHAT ; if no "=" sign
|
|
|
|
|
|
FIN:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
setlo r3,#':'
|
|
lea r4,FI1
|
|
call TSTC ; *** FIN ***
|
|
addui sp,sp,#8 ; if ":", discard return address
|
|
bra RUNSML ; continue on the same line
|
|
FI1:
|
|
setlo r3,#CR
|
|
lea r4,FI2
|
|
call TSTC ; not ":", is it a CR?
|
|
lw lr,[sp] ; else return to the caller
|
|
addui sp,sp,#8 ; yes, purge return address
|
|
bra RUNNXL ; execute the next line
|
|
FI2:
|
|
lw lr,[sp] ; else return to the caller
|
|
ret #8
|
|
|
|
|
|
; Check that there is nothing else on the line
|
|
; Registers Affected
|
|
; r1
|
|
;
|
|
ENDCHK:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
call IGNBLK
|
|
lb r1,[r8]
|
|
beq r1,#CR,ec1 ; does it end with a CR?
|
|
setlo r1,#<msgExtraChars
|
|
sethi r1,#>msgExtraChars
|
|
jmp ERROR
|
|
ec1:
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
|
|
TOOBIG:
|
|
lea r1,msgTooBig
|
|
bra ERROR
|
|
QSORRY:
|
|
lea r1,SRYMSG
|
|
bra ERROR
|
|
QWHAT:
|
|
lea r1,msgWhat
|
|
ERROR:
|
|
call PRMESG ; display the error message
|
|
lw r1,CURRNT ; get the current line number
|
|
beq r1,r0,WSTART ; if zero, do a warm start
|
|
beq r1,#-1,INPERR ; is the line no. pointer = -1? if so, redo input
|
|
lb r5,[r8] ; save the char. pointed to
|
|
sb r0,[r8] ; put a zero where the error is
|
|
lw r1,CURRNT ; point to start of current line
|
|
call PRTLN ; display the line in error up to the 0
|
|
or r6,r1,r0 ; save off end pointer
|
|
sb r5,[r8] ; restore the character
|
|
setlo r1,#'?' ; display a "?"
|
|
call GOOUT
|
|
setlo r2,#0 ; stop char = 0
|
|
subui r1,r6,#1 ; point back to the error char.
|
|
call PRTSTG ; display the rest of the line
|
|
jmp WSTART ; and do a warm start
|
|
|
|
;******************************************************************
|
|
;
|
|
; *** GETLN *** FNDLN (& friends) ***
|
|
;
|
|
; 'GETLN' reads in input line into 'BUFFER'. It first prompts with
|
|
; the character in r3 (given by the caller), then it fills the
|
|
; buffer and echos. It ignores LF's but still echos
|
|
; them back. Control-H is used to delete the last character
|
|
; entered (if there is one), and control-X is used to delete the
|
|
; whole line and start over again. CR signals the end of a line,
|
|
; and causes 'GETLN' to return.
|
|
;
|
|
;
|
|
GETLN:
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
sw r5,8[sp]
|
|
call GOOUT ; display the prompt
|
|
setlo r1,#1 ; turn on cursor flash
|
|
sb r1,cursFlash
|
|
setlo r1,#' ' ; and a space
|
|
call GOOUT
|
|
setlo r8,#<BUFFER ; r8 is the buffer pointer
|
|
sethi r8,#>BUFFER
|
|
GL1:
|
|
call CHKIO ; check keyboard
|
|
beq r1,r0,GL1 ; wait for a char. to come in
|
|
beq r1,#CTRLH,GL3 ; delete last character? if so
|
|
beq r1,#CTRLX,GL4 ; delete the whole line?
|
|
beq r1,#CR,GL2 ; accept a CR
|
|
bltu r1,#' ',GL1 ; if other control char., discard it
|
|
GL2:
|
|
sb r1,[r8] ; save the char.
|
|
add r8,r8,#1
|
|
call GOOUT ; echo the char back out
|
|
lb r1,-1[r8] ; get char back (GOOUT destroys r1)
|
|
beq r1,#CR,GL7 ; if it's a CR, end the line
|
|
cmpui r1,r8,#BUFFER+BUFLEN-1 ; any more room?
|
|
blt r1,r0,GL1 ; yes: get some more, else delete last char.
|
|
GL3:
|
|
setlo r1,#CTRLH ; delete a char. if possible
|
|
call GOOUT
|
|
setlo r1,#' '
|
|
call GOOUT
|
|
cmpui r1,r8,#BUFFER ; any char.'s left?
|
|
ble r1,r0,GL1 ; if not
|
|
setlo r1,#CTRLH ; if so, finish the BS-space-BS sequence
|
|
call GOOUT
|
|
sub r8,r8,#1 ; decrement the text pointer
|
|
bra GL1 ; back for more
|
|
GL4:
|
|
or r1,r8,r0 ; delete the whole line
|
|
subui r5,r1,#BUFFER ; figure out how many backspaces we need
|
|
beq r5,r0,GL6 ; if none needed, brnch
|
|
GL5:
|
|
setlo r1,#CTRLH ; and display BS-space-BS sequences
|
|
call GOOUT
|
|
setlo r1,#' '
|
|
call GOOUT
|
|
setlo r1,#CTRLH
|
|
call GOOUT
|
|
loop r5,GL5
|
|
GL6:
|
|
lea r8,BUFFER ; reinitialize the text pointer
|
|
bra GL1 ; and go back for more
|
|
GL7:
|
|
setlo r1,#0 ; turn off cursor flash
|
|
sb r1,cursFlash
|
|
setlo r1,#LF ; echo a LF for the CR
|
|
call GOOUT
|
|
lw lr,[sp]
|
|
lw r5,8[sp]
|
|
ret #16
|
|
|
|
|
|
; 'FNDLN' finds a line with a given line no. (in r1) in the
|
|
; text save area. r9 is used as the text pointer. If the line
|
|
; is found, r9 will point to the beginning of that line
|
|
; (i.e. the high byte of the line no.), and flags are Z.
|
|
; If that line is not there and a line with a higher line no.
|
|
; is found, r9 points there and flags are NC & NZ. If we reached
|
|
; the end of the text save area and cannot find the line, flags
|
|
; are C & NZ.
|
|
; Z=1 if line found
|
|
; N=1 if end of text save area
|
|
; Z=0 & N=0 if higher line found
|
|
; r0 = 1 <= line is found
|
|
; r9 = pointer to line
|
|
; r0 = 0 <= line is not found
|
|
; r9 = zero, if end of text area
|
|
; r9 = otherwise higher line number
|
|
;
|
|
; 'FNDLN' will initialize r9 to the beginning of the text save
|
|
; area to start the search. Some other entries of this routine
|
|
; will not initialize r9 and do the search.
|
|
; 'FNDLNP' will start with r9 and search for the line no.
|
|
; 'FNDNXT' will bump r9 by 2, find a CR and then start search.
|
|
; 'FNDSKP' uses r9 to find a CR, and then starts the search.
|
|
; return Z=1 if line is found, r9 = pointer to line
|
|
;
|
|
; Parameters
|
|
; r1 = line number to find
|
|
;
|
|
FNDLN:
|
|
bleui r1,#0xFFFF,fl1 ; line no. must be < 65535
|
|
lea r1,msgLineRange
|
|
bra ERROR
|
|
fl1:
|
|
lw r9,TXTBGN ; init. the text save pointer
|
|
|
|
FNDLNP:
|
|
lw r10,TXTUNF ; check if we passed the end
|
|
subui r10,r10,#1
|
|
bgtu r9,r10,FNDRET1 ; if so, return with r9=0,r1=0
|
|
lbu r3,[r9] ; get low order byte of line number
|
|
lbu r2,1[r9] ; get high order byte
|
|
shli r2,r2,#8
|
|
or r2,r2,r3 ; build whole line number
|
|
bgtu r1,r2,FNDNXT ; is this the line we want? no, not there yet
|
|
beq r1,r2,FNDRET2
|
|
FNDRET:
|
|
xor r1,r1,r1 ; line not found, but r9=next line pointer
|
|
ret ; return the cond. codes
|
|
FNDRET1:
|
|
xor r9,r9,r9 ; no higher line
|
|
xor r1,r1,r1 ; line not found
|
|
ret
|
|
FNDRET2:
|
|
setlo r1,#1 ; line found
|
|
ret
|
|
|
|
FNDNXT:
|
|
addui r9,r9,#2 ; find the next line
|
|
|
|
FNDSKP:
|
|
lbu r2,[r9]
|
|
addui r9,r9,#1
|
|
bnei r2,#CR,FNDSKP ; try to find a CR, keep looking
|
|
bra FNDLNP ; check if end of text
|
|
|
|
|
|
;******************************************************************
|
|
; 'MVUP' moves a block up from where r1 points to where r2 points
|
|
; until r1=r3
|
|
;
|
|
MVUP1:
|
|
lb r4,[r1]
|
|
sb r4,[r2]
|
|
add r1,r1,#1
|
|
add r2,r2,#1
|
|
MVUP:
|
|
bne r1,r3,MVUP1
|
|
MVRET:
|
|
ret
|
|
|
|
|
|
; 'MVDOWN' moves a block down from where r1 points to where r2
|
|
; points until r1=r3
|
|
;
|
|
MVDOWN1:
|
|
sub r1,r1,#1
|
|
sub r2,r2,#1
|
|
lb r4,[r1]
|
|
sb r4,[r2]
|
|
MVDOWN:
|
|
bne r1,r3,MVDOWN1
|
|
ret
|
|
|
|
|
|
; 'POPA' restores the 'FOR' loop variable save area from the stack
|
|
;
|
|
; 'PUSHA' stacks for 'FOR' loop variable save area onto the stack
|
|
;
|
|
; Note: a single zero word is stored on the stack in the
|
|
; case that no FOR loops need to be saved. This needs to be
|
|
; done because PUSHA / POPA is called all the time.
|
|
|
|
POPA:
|
|
lw r1,[sp] ; restore LOPVAR, but zero means no more
|
|
sw r1,LOPVAR
|
|
beq r1,r0,PP1
|
|
lw r1,32[sp] ; if not zero, restore the rest
|
|
sw r1,LOPPT
|
|
lw r1,24[sp]
|
|
sw r1,LOPLN
|
|
lw r1,16[sp]
|
|
sw r1,LOPLMT
|
|
lw r1,8[sp]
|
|
sw r1,LOPINC
|
|
ret #40
|
|
PP1:
|
|
ret #8
|
|
|
|
|
|
PUSHA:
|
|
lw r1,STKBOT ; Are we running out of stack room?
|
|
addui r1,r1,#40 ; we might need this many bytes
|
|
bltu sp,r1,QSORRY ; out of stack space
|
|
lw r1,LOPVAR ; save loop variables
|
|
beq r1,r0,PU1 ; if LOPVAR is zero, that's all
|
|
subui sp,sp,#40
|
|
sw r1,[sp]
|
|
lw r1,LOPPT
|
|
sw r1,32[sp] ; else save all the others
|
|
lw r1,LOPLN
|
|
sw r1,24[sp]
|
|
lw r1,LOPLMT
|
|
sw r1,16[sp]
|
|
lw r1,LOPINC
|
|
sw r1,8[sp]
|
|
ret
|
|
PU1:
|
|
subui sp,sp,#8
|
|
sw r1,[sp]
|
|
ret
|
|
|
|
|
|
;******************************************************************
|
|
;
|
|
; *** PRTSTG *** QTSTG *** PRTNUM *** PRTLN ***
|
|
;
|
|
; 'PRTSTG' prints a string pointed to by r3. It stops printing
|
|
; and returns to the caller when either a CR is printed or when
|
|
; the next byte is the same as what was passed in r4 by the
|
|
; caller.
|
|
;
|
|
; 'QTSTG' looks for an underline (back-arrow on some systems),
|
|
; single-quote, or double-quote. If none of these are found, returns
|
|
; to the caller. If underline, outputs a CR without a LF. If single
|
|
; or double quote, prints the quoted string and demands a matching
|
|
; end quote. After the printing, the next i-word of the caller is
|
|
; skipped over (usually a branch instruction).
|
|
;
|
|
; 'PRTNUM' prints the 32 bit number in r3, leading blanks are added if
|
|
; needed to pad the number of spaces to the number in r4.
|
|
; However, if the number of digits is larger than the no. in
|
|
; r4, all digits are printed anyway. Negative sign is also
|
|
; printed and counted in, positive sign is not.
|
|
;
|
|
; 'PRTLN' prints the saved text line pointed to by r3
|
|
; with line no. and all.
|
|
;
|
|
|
|
; r1 = pointer to string
|
|
; r2 = stop character
|
|
; return r1 = pointer to end of line + 1
|
|
|
|
PRTSTG:
|
|
sub sp,sp,#32
|
|
sw r5,[sp]
|
|
sw r5,8[sp]
|
|
sw r7,16[sp]
|
|
sw lr,24[sp]
|
|
mov r5,r1 ; r5 = pointer
|
|
mov r6,r2 ; r6 = stop char
|
|
PS1:
|
|
lbu r7,[r5] ; get a text character
|
|
addui r5,r5,#1
|
|
beq r7,r6,PRTRET ; same as stop character? if so, return
|
|
mov r1,r7
|
|
call GOOUT ; display the char.
|
|
bnei r7,#CR,PS1 ; is it a C.R.? no, go back for more
|
|
setlo r1,#LF ; yes, add a L.F.
|
|
call GOOUT
|
|
PRTRET:
|
|
mov r2,r7 ; return r2 = stop char
|
|
mov r1,r5 ; return r1 = line pointer
|
|
lw lr,24[sp]
|
|
lw r7,16[sp]
|
|
lw r5,8[sp]
|
|
lw r5,[sp]
|
|
ret #32 ; then return
|
|
|
|
|
|
QTSTG:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
setlo r3,#'"'
|
|
setlo r4,#<QT3
|
|
sethi r4,#>QT3
|
|
call TSTC ; *** QTSTG ***
|
|
setlo r2,#'"' ; it is a "
|
|
QT1:
|
|
or r1,r8,r0
|
|
call PRTSTG ; print until another
|
|
lw r8,r1
|
|
bne r2,#LF,QT2 ; was last one a CR?
|
|
addui sp,sp,#8
|
|
bra RUNNXL ; if so, run next line
|
|
QT3:
|
|
setlo r3,#''''
|
|
setlo r4,#<QT4
|
|
sethi r4,#>QT4
|
|
call TSTC ; is it a single quote?
|
|
setlo r2,#'''' ; if so, do same as above
|
|
bra QT1
|
|
QT4:
|
|
setlo r3,#'_'
|
|
setlo r4,#<QT5
|
|
sethi r4,#>QT5
|
|
call TSTC ; is it an underline?
|
|
setlo r1,#CR ; if so, output a CR without LF
|
|
call GOOUT
|
|
QT2:
|
|
lw lr,[sp]
|
|
addui sp,sp,#8
|
|
jal r0,4[lr] ; skip over next i-word when returning
|
|
QT5: ; not " ' or _
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
|
|
; Output a CR LF sequence
|
|
;
|
|
prCRLF:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
setlo r1,#CR
|
|
call GOOUT
|
|
setlo r1,#LF
|
|
call GOOUT
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
|
|
; r1 = number to print
|
|
; r2 = number of digits
|
|
; Register Usage
|
|
; r5 = number of padding spaces
|
|
PRTNUM:
|
|
subui sp,sp,#40
|
|
sw r3,[sp]
|
|
sw r5,8[sp]
|
|
sw r6,16[sp]
|
|
sw r7,24[sp]
|
|
sw lr,32[sp]
|
|
ori r7,r0,#NUMWKA ; r7 = pointer to numeric work area
|
|
mov r6,r1 ; save number for later
|
|
mov r5,r2 ; r5 = min number of chars
|
|
bgt r1,r0,PN1 ; is it negative? if not
|
|
neg r1,r1 ; else make it positive
|
|
subui r5,r5,#1 ; one less for width count
|
|
PN1:
|
|
lw r3,#10
|
|
mod r2,r1,r3 ; r2 = r1 mod 10
|
|
divui r1,r1,#10 ; r1 /= 10 divide by 10
|
|
addui r2,r2,#'0' ; convert remainder to ascii
|
|
sb r2,[r7] ; and store in buffer
|
|
addui r7,r7,#1
|
|
subui r5,r5,#1 ; decrement width
|
|
bne r1,r0,PN1
|
|
PN6:
|
|
ble r5,r0,PN4 ; test pad count, skip padding if not needed
|
|
PN3:
|
|
setlo r1,#' ' ; display the required leading spaces
|
|
call GOOUT
|
|
loop r5,PN3
|
|
PN4:
|
|
bgt r6,r0,PN5 ; is number negative?
|
|
setlo r1,#'-' ; if so, display the sign
|
|
call GOOUT
|
|
PN5:
|
|
subui r7,r7,#1
|
|
lb r1,[r7] ; now unstack the digits and display
|
|
call GOOUT
|
|
cmpui r1,r7,#NUMWKA
|
|
bgtu r1,r0,PN5
|
|
PNRET:
|
|
lw lr,32[sp]
|
|
lw r7,24[sp]
|
|
lw r6,16[sp]
|
|
lw r5,8[sp]
|
|
lw r3,[sp]
|
|
ret #40
|
|
|
|
|
|
; r1 = number to print
|
|
; r2 = number of digits
|
|
PRTHEXNUM:
|
|
subui sp,sp,#40
|
|
sw r5,[sp]
|
|
sw r6,8[sp]
|
|
sw r7,16[sp]
|
|
sw r8,24[sp]
|
|
sw lr,32[sp]
|
|
setlo r7,#<NUMWKA ; r7 = pointer to numeric work area
|
|
sethi r7,#>NUMWKA
|
|
or r6,r1,r0 ; save number for later
|
|
setlo r5,#20 ; r5 = min number of chars
|
|
or r4,r1,r0
|
|
bgt r4,r0,PHN1 ; is it negative? if not
|
|
neg r4,r4 ; else make it positive
|
|
sub r5,r5,#1 ; one less for width count
|
|
setlo r8,#20 ; maximum of 10 digits
|
|
PHN1:
|
|
or r1,r4,r0
|
|
andi r1,r1,#15
|
|
blt r1,#10,PHN7
|
|
addui r1,r1,#'A'-10
|
|
bra PHN8
|
|
PHN7:
|
|
add r1,r1,#'0' ; convert remainder to ascii
|
|
PHN8:
|
|
sb r1,[r7] ; and store in buffer
|
|
add r7,r7,#1
|
|
sub r5,r5,#1 ; decrement width
|
|
shru r4,r4,#4
|
|
beq r4,r0,PHN6 ; is it zero yet ?
|
|
loop r8,PHN1 ; safety
|
|
PHN6: ; test pad count
|
|
ble r5,r0,PHN4 ; skip padding if not needed
|
|
PHN3:
|
|
setlo r1,#' ' ; display the required leading spaces
|
|
call GOOUT
|
|
loop r5,PHN3
|
|
PHN4:
|
|
bgt r6,r0,PHN5 ; is number negative?
|
|
setlo r1,#'-' ; if so, display the sign
|
|
call GOOUT
|
|
PHN5:
|
|
sub r7,r7,#1
|
|
lb r1,[r7] ; now unstack the digits and display
|
|
call GOOUT
|
|
cmpui r1,r7,#NUMWKA
|
|
bgt r1,r0,PHN5
|
|
PHNRET:
|
|
lw lr,32[sp]
|
|
lw r8,24[sp]
|
|
lw r7,16[sp]
|
|
lw r6,8[sp]
|
|
lw r5,[sp]
|
|
ret #40
|
|
|
|
|
|
; r1 = pointer to line
|
|
; returns r1 = pointer to end of line + 1
|
|
PRTLN:
|
|
subui sp,sp,#16
|
|
sw r5,[sp]
|
|
sw lr,8[sp]
|
|
addi r5,r1,#2
|
|
lbu r1,-2[r5] ; get the binary line number
|
|
lbu r2,-1[r5]
|
|
shli r2,r2,#8
|
|
or r1,r1,r2
|
|
setlo r2,#0 ; display a 0 or more digit line no.
|
|
call PRTNUM
|
|
setlo r1,#' ' ; followed by a blank
|
|
call GOOUT
|
|
setlo r2,#0 ; stop char. is a zero
|
|
or r1,r5,r0
|
|
call PRTSTG ; display the rest of the line
|
|
lw lr,8[sp]
|
|
lw r5,[sp]
|
|
ret #16
|
|
|
|
|
|
; ===== Test text byte following the call to this subroutine. If it
|
|
; equals the byte pointed to by r8, return to the code following
|
|
; the call. If they are not equal, brnch to the point
|
|
; indicated in r4.
|
|
;
|
|
; Registers Affected
|
|
; r3,r8
|
|
; Returns
|
|
; r8 = updated text pointer
|
|
;
|
|
TSTC
|
|
subui sp,sp,#16
|
|
sw lr,[sp]
|
|
sw r1,8[sp]
|
|
call IGNBLK ; ignore leading blanks
|
|
lb r1,[r8]
|
|
beq r3,r1,TC1 ; is it = to what r8 points to? if so
|
|
lw r1,8[sp]
|
|
lw lr,[sp]
|
|
addui sp,sp,#16
|
|
jal r0,[r4] ; jump to the routine
|
|
TC1:
|
|
add r8,r8,#1 ; if equal, bump text pointer
|
|
lw r1,8[sp]
|
|
lw lr,[sp]
|
|
ret #16
|
|
|
|
; ===== See if the text pointed to by r8 is a number. If so,
|
|
; return the number in r2 and the number of digits in r3,
|
|
; else return zero in r2 and r3.
|
|
; Registers Affected
|
|
; r1,r2,r3,r4
|
|
; Returns
|
|
; r1 = number
|
|
; r2 = number of digits in number
|
|
; r8 = updated text pointer
|
|
;
|
|
TSTNUM:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
call IGNBLK ; skip over blanks
|
|
setlo r1,#0 ; initialize return parameters
|
|
setlo r2,#0
|
|
TN1:
|
|
lb r3,[r8]
|
|
bltui r3,#'0',TSNMRET ; is it less than zero?
|
|
bgtui r3,#'9',TSNMRET ; is it greater than nine?
|
|
setlo r4,#0xFFFFFFFF
|
|
sethi r4,#0x07FFFFFF
|
|
bleu r1,r4,TN2 ; see if there's room for new digit
|
|
setlo r1,msgNumTooBig
|
|
bra ERROR ; if not, we've overflowd
|
|
TN2:
|
|
mului r1,r1,#10 ; quickly multiply result by 10
|
|
addi r8,r8,#1 ; adjust text pointer
|
|
andi r3,r3,#0x0F ; add in the new digit
|
|
add r1,r1,r3
|
|
addi r2,r2,#1 ; increment the no. of digits
|
|
bra TN1
|
|
TSNMRET:
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
|
|
;===== Skip over blanks in the text pointed to by r8.
|
|
;
|
|
; Registers Affected:
|
|
; r8
|
|
; Returns
|
|
; r8 = pointer updateded past any spaces or tabs
|
|
;
|
|
IGNBLK:
|
|
subui sp,sp,#8
|
|
sw r1,[sp]
|
|
IGB2:
|
|
lb r1,[r8] ; get char
|
|
beqi r1,#' ',IGB1 ; see if it's a space
|
|
bnei r1,#'\t',IGBRET ; or a tab
|
|
IGB1:
|
|
add r8,r8,#1 ; increment the text pointer
|
|
bra IGB2
|
|
IGBRET:
|
|
lw r1,[sp]
|
|
ret #8
|
|
|
|
|
|
; ===== Convert the line of text in the input buffer to upper
|
|
; case (except for stuff between quotes).
|
|
;
|
|
; Registers Affected
|
|
; r1,r3
|
|
; Returns
|
|
; r8 = pointing to end of text in buffer
|
|
;
|
|
TOUPBUF:
|
|
subui sp,sp,#8
|
|
sw lr,[sp]
|
|
setlo r8,BUFFER ; set up text pointer
|
|
setlo r3,#0 ; clear quote flag
|
|
TOUPB1:
|
|
lb r1,[r8] ; get the next text char.
|
|
add r8,r8,#1
|
|
beqi r1,#CR,TOUPBRT ; is it end of line?
|
|
beqi r1,#'"',DOQUO ; a double quote?
|
|
beqi r1,#'''',DOQUO ; or a single quote?
|
|
bne r3,r0,TOUPB1 ; inside quotes?
|
|
call toUpper ; convert to upper case
|
|
sb r1,-1[r8] ; store it
|
|
bra TOUPB1 ; and go back for more
|
|
DOQUO:
|
|
bne r3,r0,DOQUO1; are we inside quotes?
|
|
or r3,r1,r0 ; if not, toggle inside-quotes flag
|
|
bra TOUPB1
|
|
DOQUO1:
|
|
bne r3,r1,TOUPB1 ; make sure we're ending proper quote
|
|
setlo r3,#0 ; else clear quote flag
|
|
bra TOUPB1
|
|
TOUPBRT:
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
|
|
; ===== Convert the character in r1 to upper case
|
|
;
|
|
toUpper
|
|
blt r1,#'a',TOUPRET ; is it < 'a'?
|
|
bgt r1,#'z',TOUPRET ; or > 'z'?
|
|
sub r1,r1,#32 ; if not, make it upper case
|
|
TOUPRET
|
|
ret
|
|
|
|
|
|
; 'CHKIO' checks the input. If there's no input, it will return
|
|
; to the caller with the r1=0. If there is input, the input byte is in r1.
|
|
; However, if a control-C is read, 'CHKIO' will warm-start BASIC and will
|
|
; not return to the caller.
|
|
;
|
|
CHKIO:
|
|
subui sp,sp,#8 ; save link reg
|
|
sw lr,[sp]
|
|
call GOIN ; get input if possible
|
|
beq r1,#-1,CHKRET2 ; if Zero, no input
|
|
bnei r1,#CTRLC,CHKRET ; is it control-C?
|
|
jmp WSTART ; if so, do a warm start
|
|
CHKRET2:
|
|
xor r1,r1,r1
|
|
CHKRET:
|
|
lw lr,[sp] ;r1=0
|
|
ret #8
|
|
|
|
|
|
; ===== Display a CR-LF sequence
|
|
;
|
|
CRLF:
|
|
setlo r1,CLMSG
|
|
|
|
|
|
; ===== Display a zero-ended string pointed to by register r1
|
|
; Registers Affected
|
|
; r1,r2,r4
|
|
;
|
|
PRMESG:
|
|
subui sp,sp,#16
|
|
sw r5,[sp]
|
|
sw lr,8[sp]
|
|
mov r5,r1 ; r5 = pointer to message
|
|
PRMESG1:
|
|
add r5,r5,#1
|
|
lb r1,-1[r5] ; get the char.
|
|
beq r1,r0,PRMRET
|
|
call GOOUT ;else display it trashes r4
|
|
bra PRMESG1
|
|
PRMRET:
|
|
mov r1,r5
|
|
lw lr,8[sp]
|
|
lw r5,[sp]
|
|
ret #16
|
|
|
|
|
|
; ===== Display a zero-ended string pointed to by register r1
|
|
; Registers Affected
|
|
; r1,r2,r3
|
|
;
|
|
PRMESGAUX:
|
|
subui sp,sp,#16
|
|
sw r5,[sp]
|
|
sw lr,8[sp]
|
|
mov r5,r1 ; r3 = pointer
|
|
PRMESGA1:
|
|
addui r5,r5,#1
|
|
lb r1,-1[r5] ; get the char.
|
|
beq r1,r0,PRMRETA
|
|
call GOAUXO ;else display it
|
|
bra PRMESGA1
|
|
PRMRETA:
|
|
mov r1,r5
|
|
lw lr,8[sp]
|
|
lw r5,[sp]
|
|
ret #16
|
|
|
|
;*****************************************************
|
|
; The following routines are the only ones that need *
|
|
; to be changed for a different I/O environment. *
|
|
;*****************************************************
|
|
|
|
|
|
; ===== Output character to the console (Port 1) from register r1
|
|
; (Preserves all registers.)
|
|
;
|
|
OUTC:
|
|
jmp DisplayChar
|
|
|
|
|
|
; ===== Input a character from the console into register D0 (or
|
|
; return Zero status if there's no character available).
|
|
;
|
|
INC:
|
|
jmp KeybdGetChar
|
|
|
|
|
|
;*
|
|
;* ===== Input a character from the host into register r1 (or
|
|
;* return Zero status if there's no character available).
|
|
;*
|
|
AUXIN:
|
|
call SerialGetChar
|
|
beqi r1,#-1,AXIRET_ZERO
|
|
andi r1,r1,#0x7f ;zero out the high bit
|
|
AXIRET:
|
|
ret
|
|
AXIRET_ZERO:
|
|
xor r1,r1,r1
|
|
ret
|
|
|
|
; ===== Output character to the host (Port 2) from register r1
|
|
; (Preserves all registers.)
|
|
;
|
|
AUXOUT
|
|
jmp SerialPutChar ; call boot rom routine
|
|
|
|
|
|
_cls
|
|
call clearScreen
|
|
bra FINISH
|
|
|
|
_wait10
|
|
ret
|
|
_getATAStatus
|
|
ret
|
|
_waitCFNotBusy
|
|
ret
|
|
_rdcf
|
|
br FINISH
|
|
rdcf6
|
|
br ERROR
|
|
|
|
|
|
; ===== Return to the resident monitor, operating system, etc.
|
|
;
|
|
BYEBYE:
|
|
lw sp,OSSP
|
|
lw lr,[sp]
|
|
ret #8
|
|
|
|
; MOVE.B #228,D7 return to Tutor
|
|
; TRAP #14
|
|
|
|
.align 16
|
|
msgInit db CR,LF,"Raptor64 Tiny BASIC v1.0",CR,LF,"(C) 2012 Robert Finch",CR,LF,LF,0
|
|
OKMSG db CR,LF,"OK",CR,LF,0
|
|
msgWhat db "What?",CR,LF,0
|
|
SRYMSG db "Sorry."
|
|
CLMSG db CR,LF,0
|
|
msgReadError db "Compact FLASH read error",CR,LF,0
|
msgNumTooBig db "Number is too big",CR,LF,0
|
msgNumTooBig db "Number is too big",CR,LF,0
|
msgDivZero db "Division by zero",CR,LF,0
|
msgDivZero db "Division by zero",CR,LF,0
|
msgVarSpace db "Out of variable space",CR,LF,0
|
msgVarSpace db "Out of variable space",CR,LF,0
|
msgBytesFree db " bytes free",CR,LF,0
|
msgBytesFree db " bytes free",CR,LF,0
|
msgReady db CR,LF,"Ready",CR,LF,0
|
msgReady db CR,LF,"Ready",CR,LF,0
|
Line 1281... |
Line 5151... |
msgBadGotoGosub db "GOTO/GOSUB bad line number",CR,LF,0
|
msgBadGotoGosub db "GOTO/GOSUB bad line number",CR,LF,0
|
msgRetWoGosub db "RETURN without GOSUB",CR,LF,0
|
msgRetWoGosub db "RETURN without GOSUB",CR,LF,0
|
msgTooBig db "Program is too big",CR,LF,0
|
msgTooBig db "Program is too big",CR,LF,0
|
msgExtraChars db "Extra characters on line ignored",CR,LF,0
|
msgExtraChars db "Extra characters on line ignored",CR,LF,0
|
|
|
INITMSG:
|
|
db CR,LF,'Raptor64 Tiny BASIC, v1.0',CR,LF,LF,0
|
|
OKMSG:
|
|
db CR,LF,'OK',CR,LF,0
|
|
HOWMSG:
|
|
db 'How?',CR,LF,0
|
|
WHTMSG:
|
|
db 'What?',CR,LF,0
|
|
SRYMSG:
|
|
db 'Sorry.'
|
|
CLMSG:
|
|
db CR,LF,0
|
|
; DC.B 0 ;<- for aligning on a word boundary
|
|
align 16
|
|
|
|
LSTROM EQU $
|
|
; end of possible ROM area
|
|
|
|
bss
|
|
align 16
|
|
|
|
org 0x0080
|
|
typef db 0 ; variable / expression type
|
|
align 8
|
align 8
|
OSSP dw 1 ; OS value of sp
|
LSTROM equ * ; end of possible ROM area
|
CURRNT dw 1 ; Current line pointer
|
; END
|
STKGOS dw 1 ; Saves stack pointer in 'GOSUB'
|
|
STKINP dw 1 ; Saves stack pointer during 'INPUT'
|
|
LOPVAR dw 1 ; 'FOR' loop save area
|
|
LOPINC dw 1 ; increment
|
|
LOPLMT dw 1 ; limit
|
|
LOPLN dw 1 ; line number
|
|
LOPPT dw 1 ; text pointer
|
|
TXTUNF dw 1 ; points to unfilled text area
|
|
VARBGN dw 1 ; points to variable area
|
|
IVARBGN dw 1 ; points to integer variable area
|
|
SVARBGN dw 1 ; points to string variable area
|
|
FVARBGN dw 1 ; points to float variable area
|
|
STKBOT dw 1 ; holds lower limit for stack growth
|
|
NUMWKA fill.b 12,0 ; numeric work area
|
|
BUFFER fill.b BUFLEN,0x00 ; Keyboard input buffer
|
|
|
|
|
;*
|
|
;* ===== Return to the resident monitor, operating system, etc.
|
|
;*
|
|
BYEBYE:
|
|
jmp Monitor
|
|
; MOVE.B #228,D7 ;return to Tutor
|
|
; TRAP #14
|
|
|
;==============================================================================
|
;==============================================================================
|
; Checkerboard RAM tester
|
; Checkerboard RAM tester
|
;==============================================================================
|
;==============================================================================
|
;
|
;
|
Line 1388... |
Line 5227... |
ramtest10:
|
ramtest10:
|
sw r8,0x00000400 ;memend
|
sw r8,0x00000400 ;memend
|
ret
|
ret
|
|
|
;-------------------------------------------
|
;-------------------------------------------
|
; IRQ routine
|
|
;-------------------------------------------
|
;-------------------------------------------
|
|
;
|
|
iberr_rout:
|
|
lea r1,msgiberr
|
|
call DisplayString
|
|
mfspr r1,EPC
|
|
call DisplayWord
|
|
wait
|
|
jmp start
|
|
dberr_rout:
|
|
lea r1,msgdberr
|
|
call DisplayString
|
|
mfspr r1,ERRADR
|
|
call DisplayWord
|
|
lea r1,msgEPC
|
|
call DisplayString
|
|
mfspr r1,EPC
|
|
call DisplayWord
|
|
call CRLF
|
|
lw r2,#31
|
|
dberr1:
|
|
mtspr PCHI,r2
|
|
nop
|
|
nop
|
|
nop
|
|
mfspr r1,PCHISTORIC
|
|
call DisplayWord
|
|
call CRLF
|
|
loop r2,dberr1
|
|
wait
|
|
jmp start
|
|
.align 16
|
|
msgdberr:
|
|
db "Data bus error at: ",0
|
|
msgEPC:
|
|
db " EPC: ",0
|
|
msgiberr:
|
|
db "Err fetching instruction at: ",0
|
|
.align 16
|
|
|
|
;------------------------------------------------------------------------------
|
|
; IRQ routine
|
|
;------------------------------------------------------------------------------
|
|
;
|
irqrout:
|
irqrout:
|
subui sp,sp,#16
|
subui sp,sp,#32
|
sm [sp],r1/lr
|
sw r1,[sp] ; save off a working register
|
inch r1,PIC
|
sw r2,8[sp] ; and a second work register
|
beqi r1,#1,ColdStart
|
sw r26,16[sp] ; save off implicit constant builder reg
|
irqrout3:
|
sw lr,24[sp]
|
bnei r1,#2,irqrout2
|
inch r1,PIC ; r1= which IRQ line is active
|
call Pulse1000
|
|
bra irqrout1
|
; 1000 Hz interrupt
|
irqrout2:
|
; This IRQ must be fast, so it's placed inline
|
bnei r1,#15,irqrout1
|
; Increments the millisecond counter, and switches to the next context
|
|
;
|
|
irq1000Hz:
|
|
bnei r1,#2,irq100Hz
|
|
outb r0,0xFFFFFFFF_FFFF0000 ; acknowledge interrupt
|
|
lw r1,Milliseconds ; increment milliseconds count
|
|
addui r1,r1,#1
|
|
sw r1,Milliseconds
|
|
lea r2,TEXTSCR
|
|
inch r1,332[r2]
|
|
addui r1,r1,#1
|
|
outc r1,332[r2]
|
|
lw lr,24[sp]
|
|
lw r26,16[sp] ; restore registers from stack
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
|
addui sp,sp,#32 ; restore stack pointer
|
|
iepp ; move to the next context
|
|
nop
|
|
nop
|
|
nop
|
|
iret ; return to the next context
|
|
|
|
; 100 Hz interrupt
|
|
; This IRQ could have some work to do, including flashing a cursor. So
|
|
; we call a subroutine.
|
|
;
|
|
irq100Hz:
|
|
bnei r1,#3,irqSerial
|
|
lw r1,p100IRQvec
|
|
; jal lr,[r1]
|
|
call Pulse100
|
|
bra irqret
|
|
|
|
irqSerial:
|
|
bnei r1,#8,irqRaster
|
|
lw r1,serialIRQvec
|
|
jal lr,[r1]
|
|
bra irqret
|
|
|
|
irqRaster:
|
|
bnei r1,#13,irqKeybd
|
|
lw r1,rasterIRQvec
|
|
; jal lr,[r1]
|
|
call RasterIRQfn
|
|
bra irqret
|
|
|
|
irqKeybd:
|
|
beqi r1,#1,ColdStart ; CTRL-ALT-DEL interrupt
|
|
bnei r1,#15,irqret
|
|
lw r1,keybdIRQvec
|
call KeybdIRQ
|
call KeybdIRQ
|
irqrout1:
|
; jal lr,[r1]
|
lm [sp],r1/lr
|
|
addui sp,sp,#16
|
irqret:
|
|
lw lr,24[sp]
|
|
lw r26,16[sp] ; restore registers from stack
|
|
lw r2,8[sp]
|
|
lw r1,[sp]
|
|
addui sp,sp,#32 ; restore stack pointer
|
iret
|
iret
|
|
|
;-------------------------------------------
|
;-------------------------------------------
|
; NMI routine
|
; NMI routine
|
;-------------------------------------------
|
;-------------------------------------------
|
Line 1438... |
Line 5374... |
tlbwr ; update a random entry in the TLB
|
tlbwr ; update a random entry in the TLB
|
cmgi #0 ; close the mutex gate
|
cmgi #0 ; close the mutex gate
|
lw r1,0xFFFF_FFFF_FFFF_0000
|
lw r1,0xFFFF_FFFF_FFFF_0000
|
lw r2,0xFFFF_FFFF_FFFF_0008
|
lw r2,0xFFFF_FFFF_FFFF_0008
|
iret
|
iret
|
nop
|
.align 32
|
nop
|
|
|
|
org 0xFFFF_FFFF_FFFF_FFB0
|
org 0xFFFF_FFFF_FFFF_FFB0
|
jmp DTLBHandler
|
jmp DTLBHandler
|
nop
|
nop
|
nop
|
nop
|
org 0xFFFF_FFFF_FFFF_FFC0
|
org 0xFFFF_FFFF_FFFF_FFC0
|
jmp DTLBHandler
|
jmp DTLBHandler
|
nop
|
nop
|
nop
|
nop
|
org 0xFFFF_FFFF_FFFF_FFD0
|
|
jmp irqrout
|
; NMI vector
|
nop
|
|
nop
|
|
org 0xFFFF_FFFF_FFFF_FFE0
|
org 0xFFFF_FFFF_FFFF_FFE0
|
jmp nmirout
|
jmp nmirout
|
nop
|
nop
|
nop
|
nop
|
|
|
|
; RST vector
|
org 0xFFFF_FFFF_FFFF_FFF0
|
org 0xFFFF_FFFF_FFFF_FFF0
|
jmp start
|
jmp start
|
nop
|
nop
|
nop
|
nop
|
|
|