; > Commands ; BASIC commands ; 09-Feb-2008 Removed 80-BF from command table, OFF/ERROR/EXT checked for explicitly ; Started writing cmdON to split between subfunctions ; Started work on PRINT - comma doesn't work, rest untested ; 12-Feb-2008 PRINT works, including all print formatters! ; ; 04-Sep-2008: LIST, REPEAT/UNTIL, GOTO/GOSUB/RETURN, RESTORE, IF, =, ENDPROC, TRACE ; Command address table ; ===================== ; On entry to command subroutines, ; r5=>first non-space after command token ; r0=first non-space character after command token - (r5) ; .CommandTable EQUW cmdLEFT-$ ; &C0 - LEFT$( EQUW cmdMID-$ ; &C1 - MID$( EQUW cmdRIGHT-$ ; &C2 - RIGHT$( EQUW cmdSTR-$ ; &C3 - STR$( EQUW cmdSTRING-$ ; &C4 - STRING$( EQUW cmdEOF-$ ; &C5 - EOF EQUW cmdAUTO-$ ; &C6 - AUTO EQUW cmdDELETE-$ ; &C7 - DELETE EQUW cmdLOAD-$ ; &C8 - LOAD EQUW cmdLIST-$ ; &C9 - LIST EQUW cmdNEW-$ ; &CA - NEW EQUW cmdOLD-$ ; &CB - OLD EQUW cmdRENUMBER-$ ; &CC - RENUMBER EQUW cmdSAVE-$ ; &CD - SAVE EQUW cmdPUT-$ ; &CE - PUT EQUW cmdPTR-$ ; &CF - PTR EQUW cmdPAGE-$ ; &D0 - PAGE EQUW cmdTIME-$ ; &D1 - TIME EQUW cmdLOMEM-$ ; &D2 - LOMEM EQUW cmdHIMEM-$ ; &D3 - HIMEM EQUW cmdSOUND-$ ; &D4 - SOUND EQUW cmdBPUT-$ ; &D5 - BPUT EQUW cmdCALL-$ ; &D6 - CALL EQUW cmdCHAIN-$ ; &D7 - CHAIN EQUW cmdCLEAR-$ ; &D8 - CLEAR EQUW cmdCLOSE-$ ; &D9 - CLOSE EQUW cmdCLG-$ ; &DA - CLG EQUW cmdCLS-$ ; &DB - CLS EQUW cmdDATA-$ ; &DC - DATA EQUW cmdDEF-$ ; &DD - DEF EQUW cmdDIM-$ ; &DE - DIM EQUW cmdDRAW-$ ; &DF - DRAW EQUW cmdEND-$ ; &E0 - END EQUW cmdENDPROC-$ ; &E1 - ENDPROC EQUW cmdENVELOPE-$ ; &E2 - ENVELOPE EQUW cmdFOR-$ ; &E3 - FOR EQUW cmdGOSUB-$ ; &E4 - GOSUB EQUW cmdGOTO-$ ; &E5 - GOTO EQUW cmdGCOL-$ ; &E6 - GCOL EQUW cmdIF-$ ; &E7 - IF EQUW cmdINPUT-$ ; &E8 - INPUT EQUW cmdLET-$ ; &E9 - LET EQUW cmdLOCAL-$ ; &EA - LOCAL EQUW cmdMODE-$ ; &EB - MODE EQUW cmdMOVE-$ ; &EC - MOVE EQUW cmdNEXT-$ ; &ED - NEXT EQUW cmdON-$ ; &EE - ON EQUW cmdVDU-$ ; &EF - VDU EQUW cmdPLOT-$ ; &F0 - PLOT EQUW cmdPRINT-$ ; &F1 - PRINT EQUW cmdPROC-$ ; &F2 - PROC EQUW cmdREAD-$ ; &F3 - READ EQUW cmdREM-$ ; &F4 - REM EQUW cmdREPEAT-$ ; &F5 - REPEAT EQUW cmdREPORT-$ ; &F6 - REPORT EQUW cmdRESTORE-$ ; &F7 - RESTORE EQUW cmdRETURN-$ ; &F8 - RETURN EQUW cmdRUN-$ ; &F9 - RUN EQUW cmdSTOP-$ ; &FA - STOP EQUW cmdCOLOUR-$ ; &FB - COLOUR EQUW cmdTRACE-$ ; &FC - TRACE EQUW cmdUNTIL-$ ; &FD - UNTIL EQUW cmdWIDTH-$ ; &FE - WIDTH EQUW cmdOSCLI-$ ; &FF - OSCLI .errSyntax jsr pc,Error equb 16,"Syntax error",0 align ; Not a command, must be a variable assignment ; -------------------------------------------- .cmdAssign .cmdLET jsr pc,PrintInline equs "Variable assignment",13,0 align ; jsr pc,SkipLine rts pc ; STOP ; ==== .cmdSTOP jsr pc,Error equb 0,"STOP",0 align ; ERROR [EXT] errnum,errstr$ ; ========================== .cmdERROR cmpb r0,#tknEXT ; ERROR EXT? bne cmdERROR1 inc r5 ; Step past EXT .cmdERROR1 jsr pc,EvalNumeric ; Get error number jsr pc,CheckComma ; Step past comma movb r4,-(sp) ; Save error number jsr pc,EvalString ; Get error string adr SV_INPUT,r0 ; Use command input buffer to hold error movb (sp)+,(r0)+ ; Pop error number to buffer tst r3 ; Zero-length string? beq cmdERRORdone ; Jump to finish .cmdERRORlp movb (r4)+,(r0)+ ; Copy character to error buffer dec r3 ; Decrement string count bne cmdERRORlp ; Loop to copy whole string .cmdERRORdone movb r3,(r0) ; Put terminating zero in adr SV_INPUT,r0 ; Point to error block mov r0,-(sp) ; Stack it jmp Error ; Jump to error handler ; Program environment commands ; ============================ ; PAGE= - Set default program start ; --------------------------------- ; Check for '=', evaluate integer ; Set PAGE .cmdPAGE jsr pc,EvalEqual ; Check for '=', get integer mov r4,SV_PAGE ; Set PAGE rts pc ; LOMEM= - Set heap start, clearing heap ; -------------------------------------- ; Check for '=', evaluate integer ; Set LOMEM ; Set VAREND=LOMEM ; Clear dynamic variables .cmdLOMEM jsr pc,EvalEqual ; Check for '=', get integer mov r4,SV_LOMEM ; Set LOMEM mov r4,SV_VAREND ; Set VAREND=LOMEM, clearing heap jsr pc,VarsClear ; Clear dynamic variables rts pc ; HIMEM= - Set top of BASIC memory, clearing stack ; ------------------------------------------------ ; Check for '=', evaluate integer ; Set HIMEM ; Set STACK=HIMEM ; Set machine stack = HIMEM ; Jump to execution loop as stack cleared .cmdHIMEM jsr pc,EvalEqual ; Check for '=', get integer bic #1,r4 ; Ensure even address mov r4,SV_HIMEM ; Set HIMEM mov r4,SV_STACK ; Set STACK=HIMEM, clearing BASIC stack mov r4,sp ; Reset machine stack jmp Execute ; WIDTH - Set output width ; ------------------------ ; Evaluate integer ; Set WIDTH .cmdWIDTH jsr pc,EvalInteger ; Get integer mov r4,SV_WIDTH ; Set WIDTH rts pc ; TRACE [ON|OFF|] ; ------------------------ .cmdTRACE clr r4 ; TRACE OFF is same as TRACE 0 cmpb r0,#tknOFF ; Is it TRACE OFF? beq cmdTRACEon ; Yes, jump to turn TRACE OFF mov #&FFFF,r4 ; TRACE ON is same as TRACE 65535 cmpb r0,#tknON ; Is it TRACE ON? beq cmdTRACEon jsr pc,EvalInteger ; Get line number .cmdTRACEon mov r4,SV_TRACE rts pc ; Program Editing commands ; ======================== ; NEW - Terminate program in memory ; ================================= ; TOP=PAGE+2 ; PAGE?0=13 ; PAGE?1=255 ; LOMEM=TOP ; VAREND=TOP ; DATAPTR=PAGE ; STACK=HIMEM ; Clear dynamic variables ; Jump to immediate mode .cmdNEW mov SV_PAGE,r0 ; Get start of program mov #&FF0D,(r0) ; Put in program terminator add #2,r0 ; TOP=PAGE+2 mov r0,SV_TOP ; Set TOP jsr pc,VarsHeapInit ; LOMEM=TOP, VAREND=TOP, DATAPTR=PAGE, STACK=HIMEM jmp Immediate ; Jump to immediate mode ; OLD - Attempt to recover program in memory ; ========================================== ; PAGE?0=13 ; PAGE?1=0 ; Find TOP ; LOMEM=TOP ; VAREND=TOP ; DATAPTR=PAGE ; STACK=HIMEM ; Clear dynamic variables ; Jump to immediate mode .cmdOLD mov SV_PAGE,r0 ; Get start of program mov #&000D,(r0) ; Remove program terminator jsr pc,FindTOP jsr pc,VarsHeapInit ; LOMEM=TOP, VAREND=TOP, DATAPTR=PAGE, STACK=HIMEM jmp Immediate ; Jump to immediate mode ; LIST - List program in memory ; ============================= .cmdLIST ; should parse parameters for start,end mov SV_PAGE,r5 ; Point to start of program inc r5 ; Point to line number high byte .cmdLISTlp movb (r5)+,r4 ; Get line high/terminator cmpb r4,#&FF beq cmdLISTend ; End of program swab r4 ; Put high byte right way around movb (r5)+,r0 ; Get line number low byte inc r5 ; Step past length byte bic #&00FF,r4 bic #&FF00,r0 bis r0,r4 ; Merge each byte together mov #5,r1 ; Pad decimal with 5 spaces .cmdLISTnumber jsr pc,PrintLineNumber ; Output R4 as line number .cmdLISTbyte movb (r5)+,r0 ; Get character from line cmpb r0,#13 ; End of line? beq cmdLISTcr cmpb r0,#tknLINENUM ; Inline line number? beq cmdLISTline jsr pc,PrintR0Token ; Print character or token, corrupts r0,r1,r2 br cmdLISTbyte ; Loop for next byte .cmdLISTline jsr pc,fnLineNum ; Get inline line number clr r1 ; Decimal, no padding br cmdLISTnumber .cmdLISTcr jsr pc,cmdPrintNewline ; Print newline jsr pc,IO_Escape ; Check for Escape br cmdLISTlp ; Loop for next line .cmdLISTend jmp Immediate ; Jump to immediate mode ; = ; ======== ; On entry, sp=> cmdret, fnFNret, num of locals, locals..., saved r5, cmdret .cmdEquals jsr pc,Evaluate adr fnFNret,r0 cmp r0,2(sp) beq cmdEqualsReturn jsr pc,Error equb 7,"Not in a function",0 align .cmdEqualsReturn tst (sp)+ ; Drop return address rts pc ; Return to calling FN ; PROC() ; ======================== .cmdPROC .cmdPROCret .fnFNret rts pc ; ENDPROC ; ======= ; On entry, sp=> cmdret, cmdPROCret, num of locals, locals..., saved r5, cmdret .cmdENDPROC adr cmdPROCret,r0 cmp r0,2(sp) beq cmdEqualsReturn jsr pc,Error equb 13,"Not in a PROC",0 align ; REPEAT ; ====== .cmdREPEAT mov r5,-(sp) ; Save line pointer jsr pc,Execute ; Call execution code .cmdREPEATret mov (sp)+,r5 ; Get line pointer back br cmdREPEAT ; Loop to re-enter REPEAT block ; UNTIL x ; ======= ; On entry, sp=> cmdret, cmdREPEATret, saved r5, cmdret .cmdUNTIL adr cmdREPEATret,r0 cmp r0,2(sp) beq cmdUNTILtest jsr pc,Error equb 43,"No REPEAT",0 align .cmdUNTILtest tst (sp)+ ; Drop UNTIL return address jsr pc,EvalInteger bis r3,r4 ; Is it zero? beq cmdUNTILfalse ; UNTIL FALSE, return to REPEAT routine .cmdUNTILtrue ; UNTIL TRUE, drop stacked REPEAT tst (sp)+ ; Drop cmdREPEATret address tst (sp)+ ; Drop saved R5 .cmdUNTILfalse .cmdIFexit rts pc ; Return to continue executing ; IF [THEN ...] [ELSE ...] ; ================================== .cmdIF JSR pc,EvalInteger bis r3,r4 ; Is it zero? bne cmdIFexit ; Continue .cmdIFelse movb (r5),r0 cmpb r0,#13 beq cmdIFexit ; No ELSE found, continue on next line inc r5 cmpb r0,#tknELSE beq cmdIFexit ; ELSE found, continue from here cmpb r0,#34 bne cmdIFelse ; Not a quote, keep looking for ELSE .cmdIFquote movb (r5),r0 ; Look for closing quote cmpb r0,#13 beq cmdIFexit ; End of line found, continue on next line inc r5 cmpb r0,#34 bne cmdIFquote ; Loop until closing quote found br cmdIFelse ; Loop back to look for ELSE ; RESTORE () ; =================== .cmdRESTORE jsr pc,CheckEndToken bne cmdRESTOREline mov SV_PAGE,SV_DATA rts pc .cmdRESTOREline jsr pc,EvalInteger jsr pc,LineFind mov r4,SV_DATA rts pc ; GOTO ; ============== .cmdGOTO jsr pc,EvalInteger ; r4/r3=destination line number jsr pc,LineFind ; r4=destination line pointer mov r4,r5 ; Point to GOTO destination rts pc ; Continue executing ; GOSUB ; =============== .cmdGOSUB jsr pc,EvalInteger ; r4/r3=destination line number jsr pc,LineFind ; r4=destination line pointer mov r5,-(sp) ; Save line pointer mov r4,r5 ; Point to GOSUB destination jsr pc,Execute ; Call execution code .cmdGOSUBret mov (sp)+,r5 ; Restore line pointer rts pc ; RETURN ; ====== ; On entry, sp=> cmdret, cmdGOSUBret, saved r5, cmdret .cmdRETURN adr cmdGOSUBret,r0 cmp r0,2(sp) beq cmdRETURNok jsr pc,Error equb 38,"No GOSUB",0 align .cmdRETURNok tst (sp)+ ; Drop RETURN return address rts pc ; Return to calling GOSUB ; ON, ON ERROR, ON x GOTO, ON x GOSUB, ON x PROC ; ============================================== .cmdON jsr pc,CheckEndToken bne cmdON1 jmp cmdOFFon ; ON - turn on cursor .cmdON1 cmp r0,#tknERROR ; Is it ON ERROR? bne cmdONswitch ; No, jump to ON x [GOTO|PROC] jsr pc,SkipSpaces cmp r0,#tknOFF ; Is it ON ERROR OFF? beq cmdONErrorOff ; Yes, jump to turn ON ERROR OFF mov r5,SV_ONERR ; Point ON ERROR to here jmp SkipLine ; Skip rest of line and continue .cmdONErrorOff clr SV_ONERR ; ON ERROR OFF rts pc .cmdONswitch ; ON x [GOTO|PROC] ; fall through ; UNIMPLEMENTED COMMANDS ; ====================== .cmdLEFT .cmdMID .cmdRIGHT .cmdPUT .cmdDIM .cmdINPUT .cmdLOCAL .cmdFOR .cmdNEXT .cmdREAD .cmdPRINTchn .cmdAUTO .cmdDELETE .cmdRENUMBER JSR PC,PrintInline EQUS "Unimplemented command",13,0 ALIGN JSR pc,SkipLine RTS PC ; PRINT - Print to output stream or to file ; ========================================= .cmdPRINT cmp r0,#ASC"#" ; Is it PRINT # ? bne cmdPrintLoop ; Jump for normal PRINT br cmdPRINTchn ; Jump to print to file ; PRINT main code ; --------------- .cmdPrintComma movb SV_VARS,r0 ; Get field width beq cmdPrintLoop ; Zero, no padding needed, return to main loop bic #&FF00,r0 ; Remove any sign-extension movb SV_COUNT,r1 ; Get field width bic #&FF00,r1 ; Remove any sign-extension .cmdPrintCommaLp beq cmdPrintLoop ; Zero, start of new line or field, no padding needed, return to main loop sub r0,r1 ; r1=COUNT-width bcc cmdPrintCommaLp ; Loop until reduced below zero mov #32,r0 .cmdPrintCommaSpc jsr pc,PrintR0 ; Print padding spaces inc r1 bne cmdPrintCommaSpc ; Loop until reached next field ; .cmdPrintLoop movb SV_VARS,r1 ; Get field width from @% bic #&FF00,r1 ; b7=0 - decimal .cmdPrintNext jsr pc,SkipSpaces ; Get next char jsr pc,CheckEndToken ; End of statement? bne cmdPrintItem ; No, jump to process items .cmdPrintNewline clrb SV_COUNT ; Clear COUNT jsr pc,IO_NEWL ; Finish with newline clc ; Signal print item done rts pc ; ;.cmdPrintHex ;bis #&8400,r1 ; Set hex output flag ;br cmdPrintNext ; Check next item ; .cmdPrintSemi clr r1 ; Set field width=0, flag=dec jsr pc,SkipSpaces ; Get next char jsr pc,CheckEndToken ; End of statement? beq cmdPrintDone ; Exit without printing newline .cmdPrintItem jsr pc,fnConversion bcs cmdPrintNext ;inc r5 ; Step past current character ;cmp r0,#ASC"~" ; Hex output prefix? ;beq cmdPrintHex ; Jump to set hex flag inc r5 ; Step past current character cmp r0,#ASC"," ; Print comma? beq cmdPrintComma ; Jump to pad to next field cmp r0,#&3B ; Semicolon? beq cmdPrintSemi ; Jump to check for end of print statement ; jsr pc,cmdPrintFormat ; Check for ' TAB SPC print formatting bcc cmdPrintNext ; Formatting item printed, check next item mov r1,-(sp) ; Save print flag (as evaluation may call print) jsr pc,Evaluate ; Evalute current item mov (sp)+,r1 ; Get print flag back jsr pc,cmdPrintResult br cmdPrintNext .PrintLineNum clr r1 ; No space padding ; .PrintLineNumber ; On entry, r4=line number ; r1=max number of padding spaces ; clr r3 ; 16-bit number clr r2 ; type=integer .cmdPrintResult ; On entry, r2/r3/r4=value ; r1=field width+hex flag ; On exit, r0/r2/r3/r4 corrupted ; tst r2 ; Check result type bmi cmdPrintString ; String, print it jsr pc,NumberToString ; Convert numeric to string ; r4=>string, r3=length, r1=field width+hex flag mov r1,r2 ; r2=field width bic #&FF00,r2 ; Remove any sign extension sub r3,r2 ; r2=width-length bcs cmdPrintString ; Item wider than width, no padding beq cmdPrintString ; Item same as width, no padding mov r1,-(sp) ; Save field width/hex flag mov r2,r1 jsr pc,PrintR1Spaces ; Print spaces to pad to number mov (sp)+,r1 ; Get field/hex flag back .cmdPrintString tst r3 ; Check string length beq cmdPrintResultDone ; Null string, nothing to print .cmdPrintStrLp movb (r4)+,r0 ; Get a character jsr pc,PrintR0 ; Print it dec r3 bne cmdPrintStrLp ; Loop for all characters .cmdPrintResultDone rts pc ; PRINT formatting item - ', TAB, SPC ; ----------------------------------- .cmdPrintFormat cmp r0,#ASC"'" ; It it single quote? beq cmdPrintNewline ; Jump to print newline cmp r0,#tknTAB ; Is it TAB? beq cmdPrintTAB ; Jump to do TAB(x) or TAB(x,y) cmp r0,#tknSPC ; Is it SPC? beq cmdPrintSPC ; Jump to do SPCx dec r5 ; Point back to current item sec ; Signal 'not print item' rts pc ; PRINT TAB() ; ----------- .cmdPrintTAB jsr pc,EvalInteger ; Get first parameter jsr pc,SkipSpaces ; Check next character cmp r0,#ASC"," ; Is there a comma? beq cmdPrintTABXY ; Jump to do TAB(x,y) jsr pc,CheckClose1 ; Check for closing bracket movb SV_COUNT,r0 ; Get COUNT mov r4,r1 ; r1=required column sub r0,r1 ; r1=r1-r0 - r1=tab-COUNT beq cmdPrintDone ; No spaces needed bcc PrintR1Spaces ; Jump to output required spaces jsr pc,cmdPrintNewline ; Output newline, zero count, signal done mov r4,r1 ; R1=number of spaces br PrintR1Spaces ; Jump to output required spaces ; PRINT TAB(x,y) ; -------------- .cmdPrintTABXY inc r5 ; Step past comma mov r4,-(sp) ; Save current value jsr pc,EvalInteger ; Get next integer jsr pc,CheckClose ; Step past ')' mov #31,r0 jsr pc,IO_WRCH ; Send TAB mov (sp)+,r0 jsr pc,IO_WRCH ; Send X mov r4,r0 jsr pc,IO_WRCH ; Send Y .cmdPrintDone clc ; Signal print formatting item rts pc ; PRINT SPC(n) ; ------------ .cmdPrintSPC jsr pc,EvalInteger ; Get next integer mov r4,r1 ; Move to R1 beq cmdPrintDone ; Zero - clear carry and return .PrintR1Spaces mov #32,r0 .PrintR1SpcLp jsr pc,PrintR0 ; Print space dec r1 bne PrintR1SpcLp ; Loop until required spaces printed br cmdPrintDone ; Clear carry and return