; > 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 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= of parameter mov r4,r2 swab r2 ; R2= of parameter bic #&FF00,r2 ; R2=<00000> of parameter mov (sp)+,r0 ; Get OSBYTE function back jsr pc,IO_BYTE ; Make the OSBYTE call, returns: ; ; R1= of result ; ; R2= 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 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 , 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 ; 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 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 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 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 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