; > 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 ; VDU Commands ; ============ ; CLS - Clear Text Window ; ======================= .cmdCLS clrb SV_COUNT mov #12,r0 jmp IO_WRCH ; CLG - Clear graphics window ; =========================== .cmdCLG mov #16,r0 jmp IO_WRCH ; DRAW x,y - Send DRAW command ; ============================ .cmdDRAW mov #5,-(sp) ; DRAW is PLOT 5 br cmdMOVEetc ; MOVE x,y - Send MOVE command ; ============================ .cmdMOVE mov #4,-(sp) ; MOVE is PLOT 4 .cmdMOVEetc 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 (sp)+,r3 ; R3=X, R4=Y mov (sp)+,r2 ; R0=command mov #25,r0 jsr pc,IO_WRCH ; PLOT mov r2,r0 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 clrb SV_COUNT jsr pc,EvalInteger 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 r2,r3 ; Prepare r,g,b=0 mov r2,r1 jsr pc,CheckEndStatement beq cmdCOLOURrgb ; Jump to do COLOUR l,p mov r4,-(sp) ; Save r jsr pc,EvalComma mov r4,-(sp) ; Save g jsr pc,EvalComma ; Get b mov r4,r1 ; r1=b mov #16,r4 ; r4=p=16 for screen tst 4(sp) ; Check stacked logical colour bpl cmdCOLOURscrn mov #24,r4 ; l<0, set r4=p=24 for border .cmdCOLOURscrn mov (sp)+,r2 ; r2=g mov (sp)+,r3 ; r3=r .cmdCOLOURrgb ; (sp)=l, r4=p, r3=r, r2=g, r1=b mov #19,r0 jsr pc,IO_WRCH ; VDU 19 mov (sp)+,r0 jsr pc,IO_WRCH ; VDU 19,l ;mov r4,r0 ;jsr pc,IO_WRCH ; VDU 19,l,p jsr pc,WrchR4 ; VDU 19,l,p mov r3,r0 jsr pc,IO_WRCH ; VDU 19,l,p,r mov r2,r0 jsr pc,IO_WRCH ; VDU 19,l,p,r,g mov r1,r0 jmp IO_WRCH ; 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,SkipSpaces inc r5 ; Step past comma, semi or bar cmp r0,#ASC"," beq cmdVDU ; Loop back if comma cmp r0,#&3B ; Semicolon beq cmdVDUsemi ; Loop back to send high byte for semi mov #8,r1 ; Prepare to send 8+1 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 ; ===================== .cmdOFF clr r1 br cmdOFF1 ; ON - turn cursor on ; =================== .cmdOFFon mov #1,r1 .cmdOFF1 mov #23,r0 jsr pc,IO_WRCH mov #1,r0 jsr pc,IO_WRCH mov r1,r0 jsr pc,IO_WRCH mov #7,r1 .cmdOFFzero clr r0 .cmdOFFlp jsr pc,IO_WRCH dec r1 bne cmdOFFlp rts pc ; Character Input Functions ; ========================= ; =GET$[#chn] - wait for character from input or string from channel ; ================================================================== ; Also =GET$(x,y) - read char from screen .fnGETs CMP R0,#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 JSR PC,EvalIntVal ; Evaluate parameter MOV R4,R1 ; R1=parameter b0-b7 SWAB R4 MOV R4,R2 ; R2=parameter b8-b15 MOV #&81,R0 ; R0=INKEY JSR PC,IO_BYTE ; Read keypress MOV R1,R0 BCC fnGETreturn MOV #&FFFF,R4 ; R4/3=-1 MOV #&FFFF,R3 CLR R2 ; R2=integer type RTS PC ; =GET - wait for character from input ; ==================================== ; Also =GET(port), =GET(x,y) - read char from screen .fnGET JSR PC,IO_RDCH ; Wait for key .fnGETreturn MOV R0,R4 ; R4=keypress CLR R3 ; R3=b16-b31=0 CLR R2 ; R2=integer type RTS PC ; =POS - read horizontal cursor position ; ====================================== .fnPOS JSR PC,fnVPOS MOV R1,R4 BIC #&FF00,R4 CLR R2 RTS PC ; =VPOS - read vertical cursor position ; ===================================== .fnVPOS MOV #&86,R0 JSR PC,IO_BYTE ;.fnReturnR2 MOV R2,R4 CLR R3 CLR R2 RTS PC ; =MODE - read current screen mode ; ================================ .fnMODE mov #&87,r0 jsr pc,IO_BYTE MOV R2,R4 br fnReturnExtend ; =POINT(x,y) - read colour at point ; ================================== .fnPOINT jsr pc,EvalInteger ; Get X parameter mov r4,-(sp) ; Save it jsr pc,EvalComma ; Step past ',', get Y parameter jsr pc,CheckClose ; Step past ')' mov r4,MOS_BUF+2 ; Put Y in control block mov (sp)+,MOS_BUF+0 ; Put X in control block adr MOS_BUF,r1 mov #9,r0 jsr pc,IO_WORD ; Call POINT routine movb MOS_BUF+4,r4 ; Get pixel value .fnReturnExtend sxt r3 ; Sign extend into r3 clr r2 ; Type=Integer rts pc ; =VDU n - read VDU variable ; ========================== .fnVDU jsr pc,EvalIntVal ; Get VDU variable number mov #160,r0 mov r4,r1 jsr pc,IO_BYTE ; Read VDU variable .fnReturnR1 mov r1,r4 ; r4=vdu variable clr r3 ; r3=0000 clr r2 ; Type=Integer .cmdBPUTend rts pc ; =ADVAL device - read device status ; ================================== .fnADVAL jsr pc,EvalIntVal mov r4,r1 mov r3,r2 mov #&80,r0 jsr pc,IO_BYTE br fnReturnR1 ; File Commands ; ============= ; CLOSE#chn - Close channel ; ========================= .cmdCLOSE jsr pc,EvalHash ; 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,EvalHash ; 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,SkipSpaces inc r5 ; Step past ';' cmp r0,#&3B ; Terminating ';'? beq cmdBPUTend ; Don't output end-of-line dec r5 ; No ';', step back again mov #13,r0 jmp IO_BPUT ; Write end-of-line terminator ; PTR#chn=val - Set file pointer ; ============================== .cmdPTR mov #1,r0 ; R0=1 for write PTR br cmdPTR1 ; EXT#chn=val - Set file extent ; ============================= .cmdEXT mov #3,r0 ; R0=3 for write EXT .cmdPTR1 mov r0,-(sp) ; Save function jsr pc,EvalHash ; Step past '#', get integer handle mov r4,-(sp) ; Save handle jsr pc,EvalEqual ; Step past '=', get integer pointer mov r4,(ARGS_ADDR+0) ; Store pointer in ARGS block mov r3,(ARGS_ADDR+2) adr ARGS_ADDR,r2 ; R2=>ARGS block mov (sp)+,r1 ; R1=handle mov (sp)+,r0 ; R0=function number jmp IO_ARGS ; Call MOS to write PTR or EXT ; LOAD str$ - Load program ; ======================== ; Fetch CR-string parameter ; Call LoadProgram (finding TOP) ; Jump to Immediate mode .cmdLOAD JSR PC,EvalStringCR ; Get filename to R4 JSR PC,LoadProgram ; Load program, check TOP JMP Immediate ; Drop to immediate mode ; Load program named at R4 ; ------------------------ .LoadProgram MOV R4,FILE_NAME MOV SV_PAGE,FILE_LOAD MOV #&82,R0 JSR PC,IO_BYTE MOV R1,FILE_LOAD+2 CLR FILE_EXEC ADR FILE_NAME,R1 MOV #255,R0 JSR PC,IO_FILE ; ; Check for loaded text and tokenise ; ; Check program consistancy and set TOP ; ------------------------------------- .FindTOP mov SV_PAGE,R1 ; Start at PAGE ; ; check program, find TOP ; rts pc ; SAVE str$ - Save program ; ======================== .cmdSAVE JSR PC,EvalStringCR ; Get filename to R4 MOV R4,FILE_NAME MOV SV_PAGE,FILE_START CLR FILE_LOAD+2 MOV SV_TOP,FILE_END CLR FILE_END+2 MOV #&FB00,FILE_LOAD MOV #&FFFF,FILE_LOAD+1 MOV #&0000,FILE_EXEC MOV #&0000,FILE_EXEC+2 ADR FILE_NAME,R1 CLR R0 JMP IO_FILE ; Time Commands and Functions ; =========================== ; TIME=val, TIME$=s$ - set TIME or TIME$ ; ====================================== .cmdTIME cmp r0,#ASC"$" ; Check for '$' beq cmdTIMEs ; TIME$ jsr pc,EvalEqual ; Step past '=', get integer mov r4,MOS_BUF+0 mov r3,MOS_BUF+2 clr MOS_BUF+4 adr MOS_BUF,r1 mov #2,r0 jmp IO_WORD ; Set TIME .cmdTIMEs inc r5 ; Step past '$' jsr pc,CheckEqual ; Check for '=' jsr pc,EvalString ; Get string add r3,r4 ; r4=>end of string adr SV_STRING+1,r1 add r3,r1 ; r1=>past end of string buffer mov r3,r0 ; Save string length beq cmdTIME2 ; Null string .cmdTIMElp movb -(r4),-(r1) ; Copy byte to string buffer dec r3 bne cmdTIMElp .cmdTIME2 ; r1=>SV_STRING+1, r0=string length movb r0,-(r1) ; Put length at start of buffer mov #15,r0 ; TIME$= is OSWORD 15 jmp IO_WORD ; Set TIME$ ; =TIME, =TIME$ - read TIME or TIME$ ; ================================== .fnTIME cmp r0,#ASC"$" beq fnTIMEs ; =TIME$ adr ARGS_ADDR,r1 mov #1,r0 jsr pc,IO_WORD ; Read TIME br fnReturnARGS .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=MOS_BUF 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 ; ============== ; =PTR#chn - Read file pointer ; ============================ .fnPTR clr r0 ; R0=0 for read PTR br fnPTR1 ; =EXT#chn - read file extent ; =========================== .fnEXT mov #2,r0 ; R0=2 for read EXT .fnPTR1 mov r0,-(sp) ; Save function number jsr pc,EvalHashVal ; Step past '#', get integer handle adr ARGS_ADDR,r2 ; R2=>ARGS block mov r4,r1 ; R1=handle mov (sp)+,r0 ; R0=function number back jsr pc,IO_ARGS ; Call MOS to read PTR or EXT .fnReturnARGS mov ARGS_ADDR+0,r4 mov ARGS_ADDR+2,r3 ; Get returned extent clr r2 ; Return integer rts pc ; =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 fnReturnR0 ; =EOF#chn - read end-of-file status ; ================================== .fnEOF jsr pc,EvalHashVal ; Step past '#', get integer handle mov #127,r0 ; OSBYTE 127,channel to read EOF mov r4,r1 jsr pc,IO_BYTE mov r1,r4 ; Move result to r3/r4 mov r1,r3 clr r2 ; Return integer rts pc ; OSCLI - Execute command ; ======================= .cmdOSCLI jsr pc,EvalStringCR mov r4,r0 jmp IO_CLI .fnOSCLI jsr pc,EvalStrValCR mov r4,r0 jsr pc,IO_CLI br fnReturnR0 ; =OPENIN f$ - open file for input ; ================================ .fnOPENIN mov #&40,r0 ; OPENIN is OSFIND &40 br fnOPEN ; =OPENOUT f$ - open file for output ; ================================== .fnOPENOUT mov #&80,r0 ; OPENOUT is OSFIND &80 br fnOPEN ; =OPENUP f$ - open file for update ; ================================= .fnOPENUP mov #&C0,r0 ; OPENUP is OSFIND &C0 .fnOPEN mov r0,-(sp) jsr pc,EvalStrValCR ; Get cr-string mov r4,r1 ; r1=>filename mov (sp)+,r0 ; r0=function jsr pc,IO_FIND .fnReturnR0 MOV R0,R4 ; R4=returned result CLR R3 ; R3=b16-b31=0 CLR R2 ; R2=integer type RTS PC ; SOUND commands ; ============== ; ENVELOPE a,b,c,d,e,f,g,h,i,j,k,l,m,n ; ==================================== .cmdENVELOPE jsr pc,EvalInteger adr MOS_BUF,r1 movb r4,(r1)+ mov r1,-(sp) mov #13,-(sp) .cmdENVlp jsr pc,EvalComma mov 2(sp),r1 movb r4,(r1)+ mov r1,2(sp) dec (sp) bne cmdENVlp mov #8,r0 br cmdSOUNDdo ; SOUND [ON|OFF|c,a,p,d] - Issue SOUND command ; ============================================ .cmdSOUND clr r1 ; SOUND ON is *FX210,0 cmp r0,#tknON beq cmdSOUNDon ; Jump to do SOUND ON dec r1 ; SOUND OFF is *FX210,255 cmp 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 jsr pc,EvalInteger adr MOS_BUF,r1 mov r4,(r1)+ mov r1,-(sp) mov #3,-(sp) .cmdSOUNDlp jsr pc,EvalComma mov 2(sp),r1 mov r4,(r1)+ mov r1,2(sp) dec (sp) bne cmdSOUNDlp mov #7,r0 .cmdSOUNDdo tst (sp)+ tst (sp)+ adr MOS_BUF,r1 jmp IO_WORD ; Acknowledge Escape state ; ======================== .IO_AckEsc mov #&DA,r0 clr r1 clr r2 jsr pc,IO_BYTE ; Clear VDU queue clrb SV_ESCFLG ; Clear local Escape flag mov #126,r0 jmp IO_BYTE ; Acknowledge any Escape state