mirror of
https://github.com/MajenkoProjects/pdp11-bbcbasic.git
synced 2026-08-23 20:21:33 +01:00
Original import of base code
This commit is contained in:
+873
@@ -0,0 +1,873 @@
|
||||
; > Interface
|
||||
; Interface to host system
|
||||
; IO commands/functions/queries/etc
|
||||
|
||||
; Done, tested:
|
||||
; CLS, CLG, COLOUR, MODE, =MODE, =POS, =VPOS, OSCLI, DRAW, MOVE, PLOT, GCOL, VDU
|
||||
; =POINT, =VDU, TIME=, TIME$=, =TIME, =TIME$, SOUND ON|OFF, =TIME$ checks for null return
|
||||
; GET$#chn, BPUT#chn,s$, GCOL c, COLOUR l,[p|r,g,b], PLOT x,y, SOUND, ENVELOPE, LOAD s$,n
|
||||
; 09-Mar-2009 LoadProgram can load and tokenise text file
|
||||
; 24-Jun-2010 SAVE name$,start,end[,exec[,load]]
|
||||
; 02-Jul-2010 QUIT [retval]
|
||||
; 16-Aug-2013 TextLoad calls LineTokeniser and LineInsert
|
||||
; 07-Dec-2013 SAVE <cr> saves with inline filename
|
||||
; 16-Aug-2015 v0.20a VDU(n) returns 8-bit value
|
||||
; 26-Aug-2015 v0.20b Optimised some common OSBYTE-calling code
|
||||
; 14-Jul-2017 Optimised TextLoad with modified Tokeniser API
|
||||
; 04-Jul-2018 v0.27 Optimised various I/O calls by using token in R0
|
||||
; Merged a lot of common code in OSBYTE calls and some OSWRCH calls
|
||||
; 15-Apr-2020 Optimised POINT by using stack for control block
|
||||
; 18-Mar-2024 LOAD/SAVE checks for end-of-statement if immediate command, tweeked
|
||||
; textload and FindTOP.
|
||||
|
||||
|
||||
; On entry to command subroutines,
|
||||
; r5=>character after command token, no spaces skipped
|
||||
; r0=(token-&C6)*2
|
||||
; r1=dispatch address
|
||||
;
|
||||
; On entry to function subroutines,
|
||||
; r5=>character after function token, no spaces skipped
|
||||
; r0=function token
|
||||
; r1=dispatch address
|
||||
;
|
||||
; On exit from function subroutines,
|
||||
; r4=b0-b15 or string start
|
||||
; r3=b16-b31 or string length
|
||||
; r2=type with flags set
|
||||
|
||||
|
||||
; VDU Commands
|
||||
; ============
|
||||
|
||||
; CLS - Clear Text Window
|
||||
; =======================
|
||||
.cmdCLS
|
||||
clrb SV_COUNT
|
||||
mov #36,r0 ; R0=12+24
|
||||
|
||||
; CLG - Clear graphics window
|
||||
; ===========================
|
||||
.cmdCLG
|
||||
sub #24,r0 ; R0=16 or 12
|
||||
jmp IO_WRCH
|
||||
|
||||
; DRAW x,y - Send DRAW command, entered with R0=&32
|
||||
; MOVE x,y - Send MOVE command, entered with R0=&4C
|
||||
; =================================================
|
||||
.cmdDRAW
|
||||
mov #5,r0 ; DRAW is PLOT 5
|
||||
.cmdMOVE
|
||||
bic #&FFF8,r0 ; MOVE is PLOT 4
|
||||
mov r0,-(sp)
|
||||
jsr pc,EvalInteger
|
||||
mov r4,-(sp) ; Save X coord
|
||||
br cmdPLOTetc
|
||||
|
||||
; PLOT [k,]x,y - Send PLOT command
|
||||
; ================================
|
||||
.cmdPLOT
|
||||
mov #69,-(sp) ; PLOT is PLOT 69
|
||||
jsr pc,EvalInteger
|
||||
mov r4,-(sp) ; Save X coord or PLOT command
|
||||
jsr pc,EvalComma ; Get Y coord or X coord
|
||||
jsr pc,CheckEndStatement
|
||||
beq cmdPLOTxy ; Jump to do PLOT 69,x,y
|
||||
mov (sp),2(sp) ; Move first param to command
|
||||
mov r4,(sp) ; Save second param as X coord
|
||||
.cmdPLOTetc
|
||||
jsr pc,EvalComma ; Get Y coord
|
||||
.cmdPLOTxy
|
||||
mov #25,r0
|
||||
jsr pc,IO_WRCH ; PLOT
|
||||
mov (sp)+,r3 ; R3=X coord
|
||||
mov (sp)+,r0 ; R0=command
|
||||
jsr pc,IO_WRCH ; k
|
||||
mov r3,r0
|
||||
jsr pc,WrchWord ; X low byte, high byte
|
||||
mov r4,r0 ; Y low byte, high byte
|
||||
.WrchWord
|
||||
jsr pc,IO_WRCH ; low byte
|
||||
swab r0
|
||||
jmp IO_WRCH ; high byte
|
||||
|
||||
; MODE m - Set screen mode
|
||||
; ========================
|
||||
.cmdMODE
|
||||
jsr pc,EvalInteger
|
||||
clrb SV_COUNT
|
||||
mov #22,r3
|
||||
br WrchR3R4
|
||||
|
||||
; GCOL [a,]c - Set graphics colour
|
||||
; ================================
|
||||
.cmdGCOL
|
||||
clr -(sp) ; Prepare for GCOL c
|
||||
jsr pc,EvalInteger
|
||||
jsr pc,CheckEndStatement
|
||||
beq cmdGCOL2
|
||||
mov r4,(sp) ; Overwrite action on stack
|
||||
jsr pc,EvalComma
|
||||
.cmdGCOL2
|
||||
mov (sp)+,r3 ; r3=action, r4=colour
|
||||
mov #18,r0
|
||||
jsr pc,IO_WRCH
|
||||
.WrchR3R4
|
||||
mov r3,r0
|
||||
jsr pc,IO_WRCH
|
||||
.WrchR4
|
||||
mov r4,r0
|
||||
jmp IO_WRCH
|
||||
|
||||
; COLOUR l[,p|,r,g,b] - Set text or palette colour
|
||||
; =================================================
|
||||
.cmdCOLOUR
|
||||
jsr pc,EvalInteger
|
||||
mov #17,r3
|
||||
jsr pc,CheckEndStatement
|
||||
beq WrchR3R4 ; Jump with COLOUR l
|
||||
mov r4,-(sp) ; Save logical colour
|
||||
jsr pc,EvalComma ; Get p or r
|
||||
mov r4,r1 ; R1=P
|
||||
clr r2 ; R2=R=0
|
||||
clr r3 ; R3=G=0
|
||||
clr r4 ; R4=B=0
|
||||
jsr pc,CheckEndStatement
|
||||
beq cmdCOLOURrgb ; Jump to do COLOUR l,p with VDU 19,l,p,0,0,0
|
||||
mov r1,-(sp) ; Save R, SP=>R,L
|
||||
jsr pc,EvalComma
|
||||
mov r4,-(sp) ; Save G, SP=>G,R,L
|
||||
jsr pc,EvalComma ; R4=B, SP=>G,R,L
|
||||
mov (sp)+,r3 ; R3=G
|
||||
mov (sp)+,r2 ; R2=R
|
||||
mov #16,r1 ; R1=P=16 for screen colour
|
||||
tst (sp) ; Test logical colour
|
||||
bpl cmdCOLOURrgb ; L>=0 - set screen colour
|
||||
mov #24,r1 ; R1=P=24 for border colour
|
||||
;
|
||||
.cmdCOLOURrgb
|
||||
; (sp)=LOGICAL, R1=PHYSICAL, R2=RED, R3=GREEN, R4=BLUE
|
||||
mov (sp)+,r0 ; Get logical colour
|
||||
swab r0 ; Move to top byte
|
||||
bic #&00FF,r0
|
||||
bis #&0013,r0 ; Make bottom byte=19
|
||||
jsr pc,WrchWord ; VDU 19,L
|
||||
mov r1,r0
|
||||
jsr pc,IO_WRCH ; VDU 19,L,P
|
||||
mov r2,r0
|
||||
jsr pc,IO_WRCH ; VDU 19,L,P,R
|
||||
br WrchR3R4 ; VDU 19,L,P,R,G,B
|
||||
|
||||
; VDU n[,|;[n]] - Send to VDU stream
|
||||
; ==================================
|
||||
.cmdVDUsemi
|
||||
mov r4,r0
|
||||
swab r0
|
||||
jsr pc,IO_WRCH ; Send top byte
|
||||
.cmdVDU
|
||||
jsr pc,CheckEndStatement
|
||||
beq cmdVDUexit ; End of statement, exit
|
||||
jsr pc,EvalInteger
|
||||
jsr pc,WrchR4 ; Send low byte to output
|
||||
;jsr pc,SkipSpaceThis ; Next
|
||||
;inc r5 ; Step past comma, semi or bar
|
||||
jsr pc,SkipSpaceNext
|
||||
cmp r0,#ASC","
|
||||
beq cmdVDU ; Loop back if comma
|
||||
cmp r0,#&3B ; Semicolon
|
||||
beq cmdVDUsemi ; Loop back to send high byte for semi
|
||||
mov #9,r1 ; Prepare to send 9 zeros
|
||||
cmp r0,#ASC"|"
|
||||
beq cmdOFFzero ; Jump to send zeros if bar
|
||||
dec r5 ; Point back to current character
|
||||
.cmdVDUexit
|
||||
rts pc
|
||||
|
||||
; OFF - turn cursor off
|
||||
; ON - turn cursor on
|
||||
; =====================
|
||||
; OFF entered with R0=&7E
|
||||
.cmdONvdu
|
||||
mov #1,r0 ; ON is VDU 23,1,1,...
|
||||
.cmdOFF
|
||||
bic #-2,r0 ; OFF is VDU 23,1,0,...
|
||||
mov r0,r4
|
||||
;mov r0,r1
|
||||
mov #&0117,r0
|
||||
jsr pc,WrchWord ; VDU 23,1
|
||||
;mov r1,r0
|
||||
;jsr pc,IO_WRCH ; Send ON/OFF byte
|
||||
jsr pc,WrchR4 ; Send ON/OFF byte
|
||||
mov #7,r1 ; Finish VDU sequence with 7 NULLs
|
||||
.cmdOFFzero
|
||||
clr r0
|
||||
.cmdOFFlp
|
||||
jsr pc,IO_WRCH
|
||||
dec r1
|
||||
bne cmdOFFlp
|
||||
rts pc
|
||||
|
||||
|
||||
; Character Input Functions
|
||||
; =========================
|
||||
|
||||
; =POINT(x,y) - read colour at point
|
||||
; ==================================
|
||||
.fnPOINT
|
||||
jsr pc,EvalInteger ; Get X parameter
|
||||
mov #-1,-(sp) ; Stack default result
|
||||
mov r4,-(sp) ; Put X on the stack
|
||||
jsr pc,EvalComma ; Step past ',', get Y parameter
|
||||
jsr pc,CheckClose ; Step past ')'
|
||||
mov (sp),-(sp) ; Copy X lower down on stack
|
||||
mov r4,2(sp) ; Put Y on stack
|
||||
mov sp,r1 ; r1=>control block on stack
|
||||
mov #9,r0
|
||||
jsr pc,IO_WORD ; OSWORD 9 - call POINT routine
|
||||
cmp (sp)+,(sp)+ ; Drop X and Y from stack
|
||||
mov (sp)+,r4 ; Get pixel value from stack
|
||||
br fnReturnExtendR4 ; Return value, extending &xx80+x to &FFFFFF80+x
|
||||
|
||||
; =GET$[#chn] - wait for character from input or string from channel
|
||||
; ==================================================================
|
||||
; Also =GET$(x,y) - read char from screen
|
||||
.fnGETs
|
||||
CMPB (R5),#ASC"#"
|
||||
BNE fnGETrdch
|
||||
JSR PC,EvalHashVal ; Get channel number
|
||||
MOV R4,R1 ; R1=channel
|
||||
ADR SV_STRING,R4 ; Point to string buffer
|
||||
CLR R3 ; String length=0
|
||||
.fnGETlp
|
||||
JSR PC,IO_BGET
|
||||
BCS fnGETend ; End of file
|
||||
CMP R0,#10
|
||||
BEQ fnGETend ; LF - end of line
|
||||
CMP R0,#13
|
||||
BEQ fnGETend ; CR - end of line
|
||||
MOVB R0,(R4)+ ; Store in string buffer
|
||||
INC R3
|
||||
CMP R3,#255
|
||||
BCS fnGETlp ; Loop for up to 255 characters
|
||||
.fnGETend
|
||||
ADR SV_STRING,R4 ; R4=string start, R3=length
|
||||
MOV #&8000,R2 ; R2=string
|
||||
RTS PC
|
||||
|
||||
.fnGETrdch
|
||||
JSR PC,IO_RDCH ; Wait for key
|
||||
MOV #1,R3 ; R3=string length
|
||||
.fnReadChar
|
||||
ADR SV_STRING,R4 ; R4=>string buffer
|
||||
MOV R0,(R4) ; Put character into buffer
|
||||
MOV #&8000,R2 ; R2=string type
|
||||
RTS PC
|
||||
|
||||
; =INKEY$ time - wait specified time for character
|
||||
; ================================================
|
||||
.fnINKEYs
|
||||
JSR PC,fnINKEY ; call INKEY routine
|
||||
MOV R4,R0 ; Move result to R0
|
||||
INC R3 ; Change -1/0 to 0/1
|
||||
BR fnReadChar ; Jump to store 0 or 1 characters
|
||||
|
||||
; =INKEY time - wait specified time for character
|
||||
; ===============================================
|
||||
.fnINKEY
|
||||
mov #&81,r0
|
||||
jsr pc,CallOsbyte16 ; Make OSBYTE call
|
||||
tst r4
|
||||
.fnReturnExtend
|
||||
sxt r3 ; Sign extend into r3
|
||||
clr r2 ; Type=Integer
|
||||
rts pc
|
||||
|
||||
; =MODE - read current screen mode
|
||||
; ================================
|
||||
.fnMODE
|
||||
jsr pc,fnMODEcall
|
||||
.fnReturnExtendR4
|
||||
movb r4,r4
|
||||
br fnReturnExtend
|
||||
|
||||
; =ADVAL device - read device status
|
||||
; ==================================
|
||||
.fnADVAL
|
||||
mov #&80,r0 ; R0=ADVAL
|
||||
;
|
||||
.CallOsbyte16
|
||||
mov r0,-(sp) ; Save OSBYTE function
|
||||
jsr pc,EvalIntVal ; Evaluate parameter
|
||||
mov r4,r1 ; R1=<b15-b8><b7-b0> of parameter
|
||||
mov r4,r2
|
||||
swab r2 ; R2=<b7-b0><b15-b8> of parameter
|
||||
bic #&FF00,r2 ; R2=<00000><b15-b8> of parameter
|
||||
mov (sp)+,r0 ; Get OSBYTE function back
|
||||
jsr pc,IO_BYTE ; Make the OSBYTE call, returns:
|
||||
; ; R1= <b15-b8><b7-b0> of result
|
||||
; ; R2=<b23-b16><b15-b8> of result
|
||||
mov r1,r4 ; Get b0-b15 from R1
|
||||
br fnReturnR4 ; Return 16-bit result
|
||||
|
||||
; =VDU n - read VDU variable
|
||||
; ==========================
|
||||
.fnVDU
|
||||
mov #&A0,r0
|
||||
jsr pc,CallOsbyte16 ; Returns flags from R4
|
||||
br fnReturn8bitR1 ; Reduce to 8-bit result
|
||||
|
||||
; =POS - read horizontal cursor position
|
||||
; ======================================
|
||||
.fnPOS
|
||||
jsr pc,fnVPOS ; Read POS and VPOS
|
||||
.fnReturn8bitR1
|
||||
mov r1,r0
|
||||
br fnReturn8bitR0
|
||||
|
||||
; =VPOS - read vertical cursor position
|
||||
; =====================================
|
||||
.fnVPOS
|
||||
mov #&86+&64,r0 ; R0=&86 for =VPOS
|
||||
.fnMODEcall
|
||||
sub #&64,r0 ; R0=&87 for =MODE
|
||||
clr r1 ; Prepare R1=0 for default, R2 already 0
|
||||
jsr pc,IO_BYTE
|
||||
mov r2,r0
|
||||
br fnReturn8bitR0
|
||||
|
||||
; =GET - wait for character from input
|
||||
; ====================================
|
||||
; Also =GET(port), =GET(x,y) - read char from screen
|
||||
.fnGET
|
||||
JSR pc,IO_RDCH ; Wait for key
|
||||
.fnReturn8bitR0
|
||||
bic #&FF00,r0
|
||||
.fnReturnR0
|
||||
mov r0,r4 ; R4=returned result from R0
|
||||
.fnReturnR4
|
||||
clr r3 ; R3=b16-b31=0
|
||||
clr r2 ; R2=integer type
|
||||
rts pc
|
||||
|
||||
|
||||
; Time Commands and Functions
|
||||
; ===========================
|
||||
|
||||
; TIME=val, TIME$=s$ - set TIME or TIME$
|
||||
; ======================================
|
||||
.cmdTIME
|
||||
cmpb (r5),#ASC"$" ; Check for '$'
|
||||
beq cmdTIMEs ; TIME$
|
||||
;
|
||||
jsr pc,EvalEqual ; Step past '=', get integer
|
||||
clr -(sp) ; Use control block on stack
|
||||
mov r3,-(sp) ; Stack value to write
|
||||
mov r4,-(sp)
|
||||
mov sp,r1 ; R1=>control block
|
||||
mov #2,r0 ; R0=2 - write TIME
|
||||
jsr pc,IO_WORD
|
||||
add #6,sp ; Drop control block
|
||||
rts pc
|
||||
;
|
||||
.cmdTIMEs
|
||||
inc r5 ; Step past '$'
|
||||
jsr pc,CheckEqual ; Check for '='
|
||||
jsr pc,EvalString ; Get string
|
||||
jsr pc,EvalStoreCRString ; Copy to string buffer
|
||||
dec r4 ; R4=>byte before the string
|
||||
dec r3 ; R3=string length minus <cr>
|
||||
movb r3,(r4) ; Store string length
|
||||
mov r4,r1 ; R4=>control block
|
||||
mov #15,r0 ; TIME$ is OSWORD 15
|
||||
jmp IO_WORD ; Set TIME$
|
||||
|
||||
; =TIME, =TIME$ - read TIME or TIME$
|
||||
; ==================================
|
||||
.fnTIME
|
||||
cmpb (r5),#ASC"$"
|
||||
beq fnTIMEs ; =TIME$
|
||||
;
|
||||
sub #6,sp ; Use control block on stack
|
||||
mov sp,r1 ; R1=>control block
|
||||
mov #1,r0 ; R0=1 - read TIME
|
||||
jsr pc,IO_WORD
|
||||
br fnReturnArgs ; Pop from stack and return
|
||||
;
|
||||
.fnTIMEs
|
||||
inc r5 ; Step past '$'
|
||||
adr SV_STRING,r1 ; Point to control block
|
||||
clr (r1) ; Read time as string
|
||||
mov #14,r0
|
||||
jsr pc,IO_WORD ; Read TIME$
|
||||
adr SV_STRING,r4 ; Start=SV_STRING
|
||||
mov (r4),r3 ; Check returned string
|
||||
beq fnTIMEnull ; Still zero, nothing returned
|
||||
mov #24,r3 ; Length=24
|
||||
.fnTIMEnull
|
||||
mov #&8000,r2 ; Type=String
|
||||
rts pc
|
||||
|
||||
|
||||
; File Functions
|
||||
; ==============
|
||||
|
||||
; =EOF#chn - read end-of-file status
|
||||
; ==================================
|
||||
.fnEOF
|
||||
jsr pc,EvalHashVal ; Step past '#', get handle
|
||||
mov r4,r1
|
||||
mov #127,r0 ; OSBYTE 127,channel to read EOF
|
||||
jsr pc,IO_BYTE
|
||||
clr r4 ; Prepare R4=0
|
||||
cmp #1,r1 ; If R1=0, Cy=0 if R1>0, Cy=1
|
||||
sbc r4 ; R4=0-0=0 R4=0-1=FFFF
|
||||
br fnReturnExtend ; Return 32-bit sign extended value
|
||||
|
||||
; =BGET#chn - read byte from channel
|
||||
; ==================================
|
||||
.fnBGET
|
||||
jsr pc,EvalHashVal ; Step past '#', get integer handle
|
||||
mov r4,r1 ; R1=handle
|
||||
jsr pc,IO_BGET ; Call MOS to read on this channel
|
||||
br fnReturn8bitR0
|
||||
|
||||
; OSCLI - Execute command
|
||||
; =======================
|
||||
#ifdef NOEXTRAFN
|
||||
.cmdOSCLI
|
||||
jsr pc,EvalStringCR
|
||||
mov r4,r0
|
||||
jmp IO_CLI
|
||||
#else
|
||||
.cmdOSCLI
|
||||
jsr pc,EvalStringCR
|
||||
br fnOSCLI2
|
||||
.fnOSCLI
|
||||
jsr pc,EvalStrValCR
|
||||
.fnOSCLI2
|
||||
mov r4,r0
|
||||
jsr pc,IO_CLI
|
||||
br fnReturnR0
|
||||
#endif
|
||||
|
||||
; =OPEN(IN|OUT|UP) f$ - open file
|
||||
; ===============================
|
||||
; On entry, R0=AD - OPENUP
|
||||
; R0=AE - OPENOUT
|
||||
; R0=8E - OPENIN
|
||||
.fnOPENUP
|
||||
mov #&CE,r0
|
||||
.fnOPENIN
|
||||
.fnOPENOUT
|
||||
asl r0 ; R0=11C,15C,19C
|
||||
sub #&DC,r0 ; R0=40,80,C0
|
||||
mov r0,-(sp) ; Save OPEN function
|
||||
jsr pc,EvalStrValCR ; Get cr-string
|
||||
mov r4,r1 ; r1=>filename
|
||||
mov (sp)+,r0 ; r0=function
|
||||
jsr pc,IO_FIND
|
||||
br fnReturnR0
|
||||
|
||||
; Open file information
|
||||
; =====================
|
||||
|
||||
; =PTR#chn - Read file pointer
|
||||
; =EXT#chn - read file extent
|
||||
; PTR#chn=val - Set file pointer
|
||||
; EXT#chn=val - Set file extent
|
||||
; =============================
|
||||
; On entry, R0=8F - =PTR
|
||||
; R0=12 - PTR=
|
||||
; R0=A2 - =EXT
|
||||
; R0=86 - EXT=
|
||||
.cmdPTR
|
||||
clr r0 ; Becomes R0=1 for =PTR
|
||||
.cmdEXT
|
||||
.fnPTR
|
||||
inc r0 ; Becomes R0=7 for EXT=, R0=0 for =PTR
|
||||
.fnEXT
|
||||
bic #&FFFC,r0 ; Reduce to OSARGS action 0-3
|
||||
mov r0,-(sp) ; Save OSARGS action
|
||||
jsr pc,EvalHashVal ; Step past '#', get integer handle
|
||||
mov (sp),r0 ; Get OSARGS action
|
||||
mov r4,-(sp) ; Save handle
|
||||
asr r0 ; Check bit 0 of action, read/write
|
||||
bcc callARGS2 ; b0=0, read function
|
||||
jsr pc,EvalEqual ; Step past '=', get integer
|
||||
.callARGS2
|
||||
mov (sp)+,r1 ; R1=handle
|
||||
mov (sp),r0 ; R0=function, leave on stack as padding
|
||||
mov r3,-(sp) ; sp=>data word
|
||||
mov r4,-(sp)
|
||||
mov sp,r2 ; R2=>data word
|
||||
jsr pc,IO_ARGS ; Make the OSARGS call
|
||||
.fnReturnArgs
|
||||
mov (sp)+,r4 ; R3/R3=returned data word
|
||||
mov (sp)+,r3
|
||||
tst (sp)+ ; Drop padding/byte 5
|
||||
clr r2 ; R2=integer
|
||||
.cmdBPUTend
|
||||
rts pc
|
||||
|
||||
|
||||
; File Commands
|
||||
; =============
|
||||
|
||||
; CLOSE#chn - Close channel
|
||||
; =========================
|
||||
.cmdCLOSE
|
||||
jsr pc,EvalHashVal ; Step past '#', get integer
|
||||
mov r4,r1 ; Pass handle to R1
|
||||
clr r0
|
||||
jmp IO_FIND
|
||||
|
||||
; BPUT#chn,[byte|string(;)] - Write byte or string to channel
|
||||
; ===========================================================
|
||||
.cmdBPUT
|
||||
jsr pc,EvalHashVal ; Step past '#', get integer handle
|
||||
mov r4,-(sp) ; Save handle
|
||||
jsr pc,CheckComma ; Step past ','
|
||||
jsr pc,Evaluate ; Get data to send
|
||||
bmi cmdBPUTs ; Send string
|
||||
jsr pc,EnsureInteger ; Convert float
|
||||
mov (sp)+,r1 ; Get handle to R1
|
||||
mov r4,r0 ; Move byte to R0
|
||||
jmp IO_BPUT ; Call MOS to write byte
|
||||
|
||||
.cmdBPUTs
|
||||
mov (sp)+,r1 ; Get handle to R1
|
||||
tst r3
|
||||
beq cmdBPUTzero ; Zero-length string
|
||||
.cmdBPUTlp
|
||||
movb (r4)+,r0
|
||||
jsr pc,IO_BPUT ; Send character
|
||||
dec r3
|
||||
bne cmdBPUTlp ; Loop until all sent
|
||||
.cmdBPUTzero
|
||||
;jsr pc,SkipSpaceThis ; Next
|
||||
;inc r5 ; Step past ';'
|
||||
jsr pc,SkipSpaceNext
|
||||
cmp r0,#&3B ; Terminating ';'?
|
||||
beq cmdBPUTend ; Don't output end-of-line
|
||||
dec r5 ; No ';', step back again
|
||||
mov #10,r0
|
||||
jmp IO_BPUT ; Write line-feed terminator
|
||||
|
||||
; QUIT [num] - Quit interpreter
|
||||
; =============================
|
||||
.cmdQUIT
|
||||
clr r4 ; Prepare to use zero as return value
|
||||
inc r5 ; Step past double token
|
||||
jsr pc,CheckEndStatement
|
||||
;jsr pc,FetchNextChar ; Step past second token byte
|
||||
;jsr pc,CheckEndToken
|
||||
beq cmdQUIT2 ; End of statement, use zero
|
||||
jsr pc,EvalInteger ; Get return value
|
||||
.cmdQUIT2
|
||||
mov r4,r0 ; Pass to R0
|
||||
jmp IO_QUIT
|
||||
|
||||
; LOAD str$[,addr] - Load program/data
|
||||
; ====================================
|
||||
; Fetch CR-string parameter
|
||||
; Call LoadProgram (finding TOP)
|
||||
; Jump to Immediate mode
|
||||
.cmdLOAD
|
||||
cmpb (r5),#tknQUIT
|
||||
beq cmdQUIT ; C898 - QUIT
|
||||
; cmpb r0,#tknSYS
|
||||
; beq cmdSYS ; C899 - SYS
|
||||
jsr pc,EvalStringCR ; Get filename to R4
|
||||
#ifdef FILEEXTN
|
||||
jsr pc,SkipSpaceNext
|
||||
cmp r0,#ASC","
|
||||
beq cmdLoadData
|
||||
dec r5
|
||||
#endif
|
||||
jsr pc,EnsureEndStatement
|
||||
jsr pc,LoadProgram ; Load program, check TOP
|
||||
jmp ImmediateClear ; Clear heap, drop to immediate mode
|
||||
|
||||
#ifdef FILEEXTN
|
||||
; LOAD str$,addr - load data
|
||||
; --------------------------
|
||||
.cmdLoadData
|
||||
jsr pc,StackStringAndOp
|
||||
jsr pc,EvalInteger
|
||||
mov r4,FILE_LOAD+0
|
||||
mov r3,FILE_LOAD+2
|
||||
jsr pc,UnstackStringDropOp
|
||||
br LoadData
|
||||
#endif
|
||||
|
||||
; Load program named at R4 to memory at R1
|
||||
; ----------------------------------------
|
||||
.LoadProgFile
|
||||
mov r1,FILE_LOAD+0 ; Address to load to
|
||||
mov #&82,r0
|
||||
jsr pc,IO_BYTE
|
||||
mov r1,FILE_LOAD+2 ; High word of address
|
||||
|
||||
; Load data named at R4 to address in FILE_LOAD
|
||||
; ---------------------------------------------
|
||||
.LoadData
|
||||
mov #255,r0 ; r0=&FF - LOAD
|
||||
clr FILE_EXEC ; Load to specified address
|
||||
.FileData
|
||||
mov r4,FILE_NAME ; Point to filename
|
||||
adr FILE_NAME,r1 ; r1=>control block
|
||||
jmp IO_FILE ; Perform file action
|
||||
|
||||
; Load program named at R4
|
||||
; ------------------------
|
||||
.LoadProgram
|
||||
mov SV_PAGE,r1
|
||||
jsr pc,LoadProgFile
|
||||
mov SV_PAGE,r1
|
||||
;movb (r1),r0
|
||||
;cmpb r0,#13
|
||||
cmpb (r1),#13
|
||||
beq FindTopLp ; Starts with <cr>, assume 6502 BASIC
|
||||
; Should also check for Z80/8086 BASIC
|
||||
;
|
||||
; Check for loaded text and tokenise
|
||||
; ----------------------------------
|
||||
; Need to reload higher up in memory to prevent overwriting itself
|
||||
mov r4,FILE_NAME ; Don't rely on being preserved
|
||||
mov #5,r0
|
||||
adr FILE_NAME,r1
|
||||
jsr pc,IO_FILE ; Get file length, can't depend on return from OSFILE_LOAD
|
||||
mov FILE_LENGTH,r0 ; If OSFILE 5 not implemented, will use length left by initial LOAD
|
||||
; Load text file to PAGE+256
|
||||
mov SV_PAGE,r1
|
||||
add #256,r1
|
||||
;
|
||||
; Load text file to SP-length-256
|
||||
;mov sp,r1
|
||||
;sub r0,r1 ; r1=stack-length
|
||||
;sub #256,r1 ; r1=stack-length-256
|
||||
;bic #1,r1 ; Ensure even address
|
||||
;
|
||||
mov r0,-(sp) ; Save length
|
||||
mov r1,-(sp) ; Save start
|
||||
jsr pc,LoadProgFile ; Load program file
|
||||
mov (sp)+,r5 ; Point to start of loaded text source
|
||||
mov (sp)+,r0 ; Get length
|
||||
mov SV_PAGE,-(sp) ; Stack start of dest
|
||||
add r5,r0 ; Point to end of loaded data
|
||||
clrb (r0) ; Put zero terminator after loaded text
|
||||
clr SV_LINE ; Start at line zero before incrementing
|
||||
mov (r5),r0 ; Get first two characters
|
||||
cmp r0,#ASC"#"+256*ASC"!" ; Program starts with #!
|
||||
bne LoadText
|
||||
.LoadTextSkip
|
||||
movb (r5)+,r0 ; Skip past first line
|
||||
cmp r0,#32
|
||||
bcc LoadTextSkip
|
||||
.LoadText
|
||||
add #10,SV_LINE ; Step to next line number
|
||||
.LoadTextNext
|
||||
; r5=>source
|
||||
; (sp)=>dest
|
||||
tstb (r5) ; r5=>source text
|
||||
beq LoadTextEnd ; End of source text
|
||||
jsr pc,TokeniseLine
|
||||
;
|
||||
; R5=>after end of untokenised line
|
||||
; R4=>start of tokenised line
|
||||
; R3= length of tokenised line excluding <cr>
|
||||
; R2= linenum
|
||||
;
|
||||
tst r3 ; Check tokenised line length
|
||||
beq LoadTextNext ; Zero-length line, skip to next
|
||||
add #4,r3 ; r3=BASIC line length
|
||||
mov (sp)+,r1 ; r1=>insertion point
|
||||
movb #13,(r1)+ ; Insert <cr>
|
||||
mov r5,-(sp)
|
||||
mov r4,r5 ; R5=tokenised source
|
||||
mov r2,r4 ; R4=linenum
|
||||
jsr pc,InsertLine ; Insert the tokenised line
|
||||
mov (sp)+,r5
|
||||
dec r1 ; Point dest to <cr>
|
||||
mov r1,-(sp) ; Restack dest for next line
|
||||
br LoadText ; Loop for another line
|
||||
.LoadTextEnd
|
||||
mov (sp)+,r1 ; Get insertion point back
|
||||
movb #13,(r1)+ ; Put final <cr> in
|
||||
movb #&FF,(r1) ; Put terminator in place
|
||||
;
|
||||
; Check program consistancy, set TOP, return R1=TOP, R0=corrupted
|
||||
; ---------------------------------------------------------------
|
||||
.FindTOP
|
||||
mov SV_PAGE,r1 ; Start at PAGE
|
||||
.FindTopLp
|
||||
mov r1,r0 ; r0=>start of this line
|
||||
cmpb (r1)+,#13
|
||||
bne BadProgram
|
||||
cmpb (r1)+,#&FF
|
||||
beq FindTopFound
|
||||
inc r1 ; Step past line number
|
||||
movb (r1),r1 ; Get length byte
|
||||
bic #&FF00,r1 ; Ensure 8-bit value
|
||||
cmp r1,#4
|
||||
bcs BadProgram ; If len<4, invalid
|
||||
add r0,r1 ; Point to next CR
|
||||
br FindTopLp ; Loop to check next line
|
||||
;bcc FindTopLp ; Loop if not past end of memory
|
||||
.BadProgram
|
||||
jsr pc,PrintInline
|
||||
equs "Bad program",13,0
|
||||
align
|
||||
jmp ImmediateClearStop
|
||||
.FindTopFound
|
||||
mov r1,SV_TOP ; r1=>byte after end of program
|
||||
rts pc
|
||||
|
||||
; SAVE str$[,start,end[,exec[,load]] - Save program/data
|
||||
; ======================================================
|
||||
.cmdSAVE
|
||||
jsr pc,CheckEndStatement
|
||||
bne cmdSAVE1 ; Not SAVE<cr>
|
||||
mov r5,-(sp) ; Save LPTR
|
||||
mov SV_PAGE,r5
|
||||
inc r5
|
||||
cmpb (r5)+,#&FF
|
||||
bcc cmdSAVE0 ; Null program
|
||||
inc r5
|
||||
jsr pc,FetchNextChar
|
||||
cmpb r0,#tknREM
|
||||
bne cmdSAVE0 ; First line not REM
|
||||
jsr pc,FetchNextChar
|
||||
cmpb r0,#ASC">"
|
||||
bne cmdSAVE0 ; First line not REM >
|
||||
inc r5
|
||||
mov r5,r4 ; Point to inline filename
|
||||
mov (sp)+,r5 ; Restore LPTR
|
||||
br cmdSAVEprog ; Save program
|
||||
.cmdSAVE0
|
||||
mov (sp)+,r5 ; Restore LPTR
|
||||
.cmdSAVE1
|
||||
jsr pc,EvalStringCR ; Get filename to R4
|
||||
#ifdef FILEEXTN
|
||||
jsr pc,SkipSpaceNext
|
||||
cmp r0,#ASC","
|
||||
beq cmdSaveData
|
||||
dec r5
|
||||
#endif
|
||||
jsr pc,EnsureEndStatement
|
||||
.cmdSAVEprog
|
||||
mov SV_PAGE,FILE_START+0
|
||||
mov SV_TOP,FILE_END+0
|
||||
mov #&82,r0
|
||||
jsr pc,IO_BYTE
|
||||
mov r1,FILE_START+2 ; High word of address
|
||||
mov r1,FILE_END+2
|
||||
mov #&FB00,FILE_LOAD+0
|
||||
mov #&FFFF,FILE_LOAD+2
|
||||
clr FILE_EXEC+0
|
||||
clr FILE_EXEC+2
|
||||
clr r0
|
||||
jsr pc,FileData ; Perform OSFILE with R0=action, R4=>filename
|
||||
jmp ImmediateLoop
|
||||
|
||||
#ifdef FILEEXTN
|
||||
; SAVE str$,start,end[,exec[,load]] - save data
|
||||
; ---------------------------------------------
|
||||
.cmdSaveData
|
||||
jsr pc,StackStringAndOp
|
||||
; inc r5 ; Step past comma
|
||||
jsr pc,EvalInteger
|
||||
mov r3,-(sp)
|
||||
mov r4,-(sp) ; Save start
|
||||
jsr pc,EvalComma
|
||||
mov r3,-(sp)
|
||||
mov r4,-(sp) ; Save end
|
||||
cmp r0,#ASC","
|
||||
bne cmdSave2 ; SAVE str$,start,end
|
||||
inc r5
|
||||
jsr pc,EvalInteger
|
||||
mov r3,-(sp)
|
||||
mov r4,-(sp) ; Save exec
|
||||
cmp r0,#ASC","
|
||||
bne cmdSave3 ; SAVE str$,start,end,exec
|
||||
inc r5
|
||||
jsr pc,EvalInteger
|
||||
br cmdSave4
|
||||
.cmdSave2 ; sp=>end, start
|
||||
mov 6(sp),-(sp) ; sp=>start.hi, end, start
|
||||
mov 6(sp),-(sp) ; sp=>start, end, start
|
||||
.cmdSave3 ; sp=>exec, end, start
|
||||
mov 8(sp),r4
|
||||
mov 10(sp),r3 ; r3/r4=load, sp=>exec, end, start
|
||||
.cmdSave4 ; r3/r4=load, sp=>exec, end, start
|
||||
mov r4,FILE_LOAD+0
|
||||
mov r3,FILE_LOAD+2
|
||||
mov (sp)+,FILE_EXEC+0
|
||||
mov (sp)+,FILE_EXEC+2
|
||||
mov (sp)+,FILE_END+0
|
||||
mov (sp)+,FILE_END+2
|
||||
mov (sp)+,FILE_START+0
|
||||
mov (sp)+,FILE_START+2
|
||||
jsr pc,UnstackStringDropOp
|
||||
clr r0 ; OSFILE 0 - Save
|
||||
jmp FileData ; Save data and return
|
||||
#endif
|
||||
|
||||
|
||||
; SOUND commands
|
||||
; ==============
|
||||
|
||||
; ENVELOPE a,b,c,d,e,f,g,h,i,j,k,l,m,n
|
||||
; ====================================
|
||||
.cmdENVELOPE
|
||||
jsr pc,EvalInteger ; Get first parameter
|
||||
adr MOS_BUF,r1
|
||||
movb r4,(r1)+
|
||||
mov #13,-(sp) ; Stack remaining number of parameters
|
||||
mov r1,-(sp) ; Stack pointer to paramter block
|
||||
.cmdENVlp
|
||||
jsr pc,EvalComma
|
||||
mov (sp),r1 ; Get pointer to parameter block
|
||||
movb r4,(r1)+ ; Store parameter
|
||||
mov r1,(sp) ; Save updated pointer
|
||||
dec 2(sp) ; Decrement number of remaining parameters
|
||||
bne cmdENVlp
|
||||
mov #8,r0 ; R0=8 for ENVELOPE
|
||||
br cmdSOUNDdo
|
||||
|
||||
; SOUND [ON|OFF|c,a,p,d] - Issue SOUND command
|
||||
; ============================================
|
||||
.cmdSOUND
|
||||
;jsr pc,SkipSpaceThis ; could be Next, swap inc for dec
|
||||
jsr pc,SkipSpaceNext
|
||||
clr r1 ; SOUND ON is *FX210,0
|
||||
cmpb r0,#tknON
|
||||
beq cmdSOUNDon ; Jump to do SOUND ON
|
||||
dec r1 ; SOUND OFF is *FX210,255
|
||||
cmpb r0,#tknOFF
|
||||
bne cmdSOUND2 ; Not SOUND OFF, jump past
|
||||
.cmdSOUNDon
|
||||
;inc r5 ; Step past ON/OFF
|
||||
mov #210,r0
|
||||
clr r2
|
||||
jmp IO_BYTE
|
||||
.cmdSOUND2 ; SOUND c,a,p,d
|
||||
dec r5
|
||||
jsr pc,EvalInteger ; Get first parameter
|
||||
adr MOS_BUF,r1
|
||||
mov r4,(r1)+
|
||||
mov #3,-(sp) ; Stack remaining number of parameters
|
||||
mov r1,-(sp) ; Stack pointer to parameter block
|
||||
.cmdSOUNDlp
|
||||
jsr pc,EvalComma ; If this evaluation calls something that uses MOS_BUF,
|
||||
mov (sp),r1 ; MOS_BUF will get overwritten
|
||||
mov r4,(r1)+ ; Store in parameter block
|
||||
mov r1,(sp) ; Save updated pointer
|
||||
dec 2(sp) ; Decrement number of remaining parameters
|
||||
bne cmdSOUNDlp
|
||||
mov #7,r0 ; R0=7 for SOUND
|
||||
.cmdSOUNDdo
|
||||
cmp (sp)+,(sp)+ ; Drop pointer and count from stack
|
||||
adr MOS_BUF,r1
|
||||
jmp IO_WORD
|
||||
|
||||
Reference in New Issue
Block a user