REM > Em65v044/src REM Source for 6502 Tube Client for Arthur65 24-bit 6502 CoPro emulator REM Modified slightly to become 6502 Client for 65Tube 16-bit 6502 CoPro emulator : load%=&F800:DIM mcode% &900 : USERV=&200: BRKV=&202:IRQ1V=&204:IRQ2V=&206 CLIV=&208:BYTEV=&20A:WORDV=&20C:WRCHV=&20E RDCHV=&210:FILEV=&212:ARGSV=&214:BGetV=&216 BPutV=&218:GBPBV=&21A:FINDV=&21C: FSCV=&21E EVNTV=&220: UPTV=&222: NETV=&224: VduV=&226 KEYV=&228: INSV=&22A: RemV=&22C: CNPV=&22E IND1V=&230:IND2V=&232:IND3V=&234 : FOR P=0TO1 P%=load%:O%=mcode% [OPT P*3+4 \ &EE/F= current program \ &F0/1= membot, if &F0<>0, membot=0000, memtop=0000 \ &F2/3=>command string \ &F4/5= memtop \ &F6/7= readhex accumulator, ";params" pointer \ &F8/9=>control block \ &FA/B=>String to print with PrString \ &FC = IRQ A store \ &FD/E=>last error \ &FF = escape flag \ &0236= command input buffer \ &03xx= bit16-bit23 of Turbo65 (zp),Y addresses \ &03F3= b16-b23 of (&F2),Y command string pointer \ &03F5= b16-b23 of (&F4),Y memtop pointer \ &03F9= b16-b23 of (&F8),Y control block pointer \ &03FB= b16-b23 of (&FA),Y string pointer \ &03FE= b16-b23 of (&FD),Y error pointer \ Emulator opcodes \ &03 - OSCLI \ &13 - OSBYTE \ &23 - OSWORD \ &33 - OSWRCH \ &43 - OSRDCH \ &53 - OSFILE \ &63 - OSARGS \ &73 - OSBGET \ &83 - OSBPUT \ &93 - OSGBPB \ &A3 - OSFIND \ &B3 - Called by *QUIT \ &C3 - Called by *BASIC and OSBYTE 142 \ &D3 \ &E3 \ &F3 .LF800 .RESET \ Reset vectors and set memory limits \ =================================== .LF87F CLD:LDX #&35 .LF882 LDA LFC0E,X:STA &0200,X :\ Copy from default vectors DEX:BPL LF882 TXS :\ Clear stack LDX #&00:STX &FF :\ Clear escape flag STA &F0 :\ Typo? Should be STX? LDX #&08:STX &F1 :\ Set F0/1=>bottom of memory at &0800 LDX #&00:LDY #&F8 :\ XY=&F800 STX &F4:STY &F5 :\ Set F4/5=>top of memory at &F800 JSR LFADD :\ ErrorInit - Claim BRKV JSR LFAFB :\ HelpBanner - Display banner LDY #&04:JSR OSByteA3 :\ Ask host something TYA:BEQ L830 :\ If Y=0, enter command prompt JMP JumpToCode ; FA22 :\ If Y<>0, enter code at XY \ *OS - Enter command prompt \ ========================== .LF830 .CmdOSLoop JSR PrText :\ Display prompt EQUB 23,17,5,0,0,0,0,0,0,0 :\ Swap colours EQUS "65*" EQUB 23,17,5,0,0,0,0,0,0,0 :\ Swap colours back NOP : LDA #&00 LDX #LF84A AND 255 LDY #LF84A DIV 256 JSR OSWORD:BCS OSEscape :\ Input a command LDX #&36:LDY #&02:JSR OS_CLI :\ Execute command JMP CmdOSLoop :\ Jump back for another .OSEscape LDA #&7E:JSR OSBYTE :\ Ack. escape BRK:EQUB 17:EQUS "Escape":BRK \ Interupt handler \ ================ .LF86E .InterruptHandler STA &FC:PLA:PHA :\ Save A, get flags from stack AND #&10:BNE BRKHandler :\ If BRK, jump to BRK handler JMP (IRQ1V) :\ Continue via IRQ1V handler .IRQ1Handler JMP (IRQ2V) :\ No handlers, pass staight on to IRQ2V .BRKHandler TXA:PHA :\ Save X TSX:LDA &0103,X :\ Get address from stack CLD:SEC:SBC #&01:STA &FD LDA &0104,X:SBC #&00:STA &FE :\ &FD/E=>after BRK opcode LDA #&00:STA &03FE :\ Error block at (&FD),Y is in block &00 PLA:TAX:LDA &FC :\ Restore X, get saved A CLI:JMP (BRKV) :\ Restore IRQs and jump to Error Handler \ Default error handler \ ===================== .LF89C .ErrorHandler LDX #&FF:TXS :\ Clear stack INX:STX &03FE :\ Error block at (&FD),Y is in block &00 CLI:JSR OSNEWL LDY #&01 .LF8D7 LDA (&FD),Y:BEQ LF8E1 :\ Print error string JSR OSWRCH:INY:BNE LF8D7 .LF8E1 JSR OSNEWL:JMP CmdOSLoop :\ Jump to command prompt \ OSCLI handler \ ============= .osCLI :\ OSCLI STX &F2:STY &F3 :\ &F2/3=>command string LDY #&00:STY &03F3 :\ String at (&F2),Y is in block &00 .LFBC6 LDA (&F2),Y:STA LFC44,Y :\ Copy command line to command buffer CMP #&0D:BEQ LFBD3 :\ Loop until INY:BNE LFBC6 :\ Loop for up to 256 characters .LFBD2 RTS :\ No found, exit \ OSCLI parser \ ------------ .LFBD3 LDX #LFC44 AND 255 LDY #LFC44 DIV 256 :\ Point XY to command buffer STX &F2:STY &F3 :\ Point &F2/3 to command buffer LDX #&00:LDY #&FF .LFBDF INY:JSR SkipSpaces :\ Move past and skip spaces CMP #ASC"*":BEQ LFBDF :\ Skip past '*'s CMP #&0D:BEQ LFBD2 :\ Null string, exit .LF8E7 CLC:TYA:ADC &F2:STA &F2 :\ Adjust &F2/3 to point to start of command BCC LFBF8:INC &F3 .LFBF8 LDY #&00:LDA (&F2),Y :\ Get first character CMP #ASC".":BEQ LFC45 :\ '*.', jump to pass to host .LFC00 TYA:PHA :\ Save command pointer JSR SkipSpaces :\ Skip any more spaces .LFC05 LDA LF958,X:BMI LFC20 :\ Jump if at end of command table EOR (&F2),Y :\ Compare with command table AND #&DF:BNE LFC14 :\ Ignore case, jump if no match INX:INY:BRA LFC05 :\ Loop to check next character .LFC14 LDA (&F2),Y:INY :\ Get command character CMP #ASC".":BEQ LFC29 :\ Abbreviated, jump to execute .LFC1B PLA:TAY :\ Get command pointer back SEC:BRA LFC2B :\ Step to next entry .LFC20 ASL A:BMI LFC29 LDA (&F2),Y :\ Get next character CMP #ASC"A":BCS LFC1B :\ Still more letters, try next entry .LFC29 PLA:CLC :\ Drop command pointer .LFC2B DEX .LFC2C INX:LDA LF958,X:BPL LFC2C :\ Find end of entry BCC LFC3C INX:LDA LF958,X BNE LFC00:BEQ LFC45 .LFC3C ASL A:AND #&7F :\ Index into command table TAX:JSR LFC4B :\ Call command routine BCC LFC4A :\ If CLC, exit with call claimed : :\ Otherwise, fall thru to pass to host .LFC45 LDX &F2:LDY &F3 :\ &F2/3=XY EQUB &03 :\ Pass command to host .LFC4A RTS .SkipSpaces DEY .SkipSpaces1 INY LDA (&F2),Y:CMP #&20:BEQ SkipSpaces1 CMP #&0D:RTS .LFC4B LDA LF974+1,X:PHA :\ Stack address high byte LDA LF974+0,X:PHA :\ Stack address low byte RTS :\ Jump to routine \ Command table \ ------------- .LF958 EQUS "GO" :EQUB &C0 EQUS "QUIT" :EQUB &81 EQUS "HELP" :EQUB &82 EQUS "BASIC":EQUB &83 EQUS "OS" :EQUB &84 EQUS "PAGE" :EQUB &C5 EQUB &00 \ Command addresses \ ----------------- .LFC5E EQUW CmdGO-1 :\ *Go EQUW CmdQUIT-1 :\ *Quit EQUW CmdHELP-1 :\ *Help EQUW CmdBASIC-1 :\ *Basic EQUW CmdOS-1 :\ *OS EQUW CmdPAGE-1 :\ *Page \ *BASIC \ ====== .CmdBASIC EQUB &C3 :\ Pass to host .LF981 JMP LFA1D \ Scan hex \ ======== .ScanHex LDX #&00:STX &F6:STX &F7 :\ Clear hex accumulator STX &03F3 :\ String at (&F2),Y is in block &00 .LF8F7 LDA (&F2),Y :\ Get current character SEC:SBC #&30:BCC LF921 :\ <'0', exit CMP #&0A:BCC LF90E :\ '0'..'9', add into accumator AND #&DF:SBC #&07 :\ Ignore case, convert letters CMP #&0A:BCC LF921 :\ <'A', exit CMP #&10:BCS LF921 :\ >'F', exit .LF90E ASL A:ASL A:ASL A:ASL A :\ *16 LDX #&03 .LF914 ASL A:ROL &F6:ROL &F7 :\ Move bits into accumulator BCS LF959 :\ Overflowed, jump to error DEX:BPL LF914 :\ Loop for four bits INY:BNE LF8F7 :\ Move to next character .LF921 RTS \ *PAGE - Set PAGE address \ ======================== .LF9B8 .CmdPAGE JSR SkipSpaces JSR ScanHex :\ Scan hex parameter JSR SkipSpaces:BNE LF94A :\ No parameters, jump to use &0800 TXA:BNE LF959 :\ Error if more parameters LDY &F7:LDX &F6:BNE LF94E :\ addr<>&xx00, error as must by 256-byte aligned CPY #&08:BCC LF94E :\ addr<&0800, error as too low CPY #&80:BCS LF94E :\ addr>&8000, error as too high .LF946 STY &F1:CLC:RTS :\ Store PAGE high byte .LF94A LDY #&08:BRA LF946 :\ Default to &0800 .LF94E BRK BRK:EQUS "Bad PAGE":BRK :\ Unusable PAGE value .LF959 BRK BRK:EQUS "Bad hex":BRK :\ Bad hex \ *GO - Call machine code \ ======================= .CmdGO .LF9F2 JSR SkipSpaces JSR ScanHex :\ Scan hex parameter JSR SkipSpaces:BNE LF9F9 :\ If more parameters, error TXA:BEQ LF966 :\ Hex parameter, use it LDA &F6:STA &F4 :\ No parameter, use last address LDA &F7:STA &F5 .LF966 .LFA08 LDA &EF:PHA:LDA &EE:PHA :\ Save current program JSR EnterCode PLA:STA &EE:STA &F4 :\ Restore current program and also set memtop PLA:STA &EF:STA &F5 CLC:RTS :\ CLC=command done \ NMI Handler \ =========== .NMIHandler .LFA1D LDY #&04:JSR OSByteA3 :\ Ask host something .EnterCodeXY STX &F4:STY &F5 :\ Set memtop to entry address JMP LFA08 .OSByteA3 LDA #&A3:LDX #&F3 :\ OSBYTE &A3,&F3 EQUB &13 :\ Host OSBYTE RTS \ Enter code at &F4/5 \ =================== .EnterCode LDA &F4:STA &EE :\ Current program starts at memtop LDA &F5:STA &EF LDX #&00:STX &03F5:STX &03FE :\ Set memtop and errptr are in block &00 LDY #&07:LDA (&F4),Y :\ Get copyright offset CLD:CLC:ADC &F4:STA &FD LDA #&00:ADC &F5:STA &FE :\ &FD/E=>copyright message \ Check for &00,"(C)" LDY #&00:LDA (&FD),Y:BNE LF9FC :\ Check for initial &00 INY:LDA (&FD),Y:CMP #&28:BNE LF9FC :\ Check for '(' INY:LDA (&FD),Y:CMP #&43:BNE LF9FC :\ Check for 'C' INY:LDA (&FD),Y:CMP #&29:BNE LF9FC :\ Check for ')' \ &00,"(C)" exists LDY #&06:LDA (&F4),Y :\ Get ROM type AND #&4D:CMP #&40:BCC LFA2A :\ b6=0, Not a language AND #&0D:BEQ LF9E6 :\ code=%x1xx00x0, enter 6502 code CMP #&01:BNE LFA0E :\ code<>%x1xx00x1, not 6502 code .LF9E6 \ romtype=%0000 - A=0 - 6502 BASIC \ romtype=%0001 - A=1 - Turbo6502 \ romtype=%0010 - A=0 - 6502 nonBASIC \ romtype=%0011 - A=1 - reserved PHA:LDY #&09 :\ Save flag value &00 or &01 .LF9E9 LDA (&F4),Y:BEQ LF9F3 :\ Print ROM title JSR OSWRCH:INY:BNE LF9E9 .LF9F3 JSR OSNEWL:JSR OSNEWL :\ Print two NLs PLA:BRA LF9FE :\ Get entry value back .LF9FC :\ No (C) string, enter as raw code LDA #&00 :\ Set flag=0 .LF9FE STA &F0 :\ Store flag at &F0 \ If flag=0, membot=&F0/1, memtop=&F4/5 \ If flag<>0, membot=0000, memtop=0000 LDY #&00:TYA .LFA03 STA &0300,Y:DEY:BNE LFA03 :\ All (zp),Y accesses to block &00 LDA #&01:JMP (&00F4) :\ Enter code with A=1 .LFA0E JSR ErrorInit BRK BRK:EQUS "I cannot run this code":BRK .LFA2A JSR ErrorInit BRK BRK:EQUS "This is not a language":BRK .ErrorInit LDA #ErrorHandler AND 255:STA BRKV :\ Claim BRKV LDA #ErrorHandler DIV 256:STA &0203 RTS \ *QUIT \ ===== .LFAE8 .CmdQUIT LDY #5:JSR OSByteA3 EQUB &B3 :\ Pass to host \ *HELP - Display help \ ==================== .CmdHELP .LFAEE JSR SkipSpaces:BNE LFA5C :\ Exit if parameters JSR OSNEWL:JSR HelpBanner:\ Display startup banner .LFA5C SEC:RTS :\ Return, SEC to pass to host .LFAFB .HelpBanner JSR PrText EQUS "Acorn 6502 Tube 0.44 (14 Oct 1987)" EQUB 10:EQUB 13 NOP RTS \ OSBYTE handler \ ============== .osBYTE CMP #&82:BEQ BYTE82 :\ Read memory high word CMP #&83:BEQ BYTE83 :\ Read bottom of memory CMP #&84:BEQ BYTE84 :\ Read top of memory CMP #&EA:BEQ BYTEEA :\ Read Tube presence flag CMP #&A3:BNE BYTEnn :\ Jump if not Application OSBYTE CPX #&FE:BCC BYTEnn :\ Jump if X<&FE \ OSBYTE &A3,&FE and OSBYTE &A3,FF - return unchanged RTS .BYTEnn :\ Pass OSBYTE to host EQUB &13 :\ MOS_BYTE RTS :\ Return .BYTE82 :\ Read memory high word LDX #&00:LDY #&00 :\ High word=&0000 RTS .BYTE83 :\ Read bottom of memory LDX &F0:BEQ LFABC :\ If &F0=0, &F0/F1=>memory bottom LDA #&01 :\ Set A=&01 LDX #&00:LDY #&00 :\ Return memory bottom=&0000 RTS .LFABC LDX #&00:LDY &F1 :\ Get memory bottom from &F0/F1 RTS .BYTE84 :\ Read top of memory LDX &F0:BEQ LFACD :\ If &F0=0, &F4/5=>memory top LDA #&04 :\ Set A=&04 LDX #&00:LDY #&00 :\ Return memory top=&0000 RTS .LFACD LDX &F4:LDY &F5 :\ Get memory top from &F4/F5 RTS .BYTE85 :\ Read top of memory for screem LDX #&00:LDY #&80 :\ Return top of memory=&8000 PLA:RTS :\ Restore A and return .BYTE8E :\ Enter language JMP CmdBASIC :\ Jump to enter BASIC .BYTExx LDX #&0F:RTS .BYTEEA LDX #&FF:RTS :\ Return 'Tube present' \ OSWORD handler \ ============== .osWORD .LFB72 CMP #&05:BNE LFB0C :\ Jump if not Read I/O memory : \ OSWORD 5 - Read I/O memory \ Reads from Tube memory STX &F8:STY &F9 :\ &F8/9=>control block LDY #&00:STY &03F9 :\ Control block at (&F8),Y in block &00 LDA (&F8),Y:STA &FA INY LDA (&F8),Y:STA &FB :\ &FA/B=address to read LDX #&00:LDA (&FA,X) :\ Read from address LDY #&04:STA (&F8),Y :\ Store byte read in control block LDX &F8:LDY &F9 :\ Restore X, Y RTS .LFB0C EQUB &23 :\ Pass OSWORD to host RTS .osWRCH EQUB &33 :\ Pass OSWRCH to host RTS .osRDCH EQUB &43 :\ Pass OSRDCH to host RTS \ OSARGS handler \ ============== .osARGS CMP #&01:BNE LFB3C :\ Jump if not command line or PTR CPY #&00:BNE LFB3C :\ Jump if not command line : \ OSARGS 1,0 - Read address of command line STY &03F3:DEY :\ String at (&F2),Y is in block &00 .LFB1A INY:LDA (&F2),Y :\ Get character from command line CMP #&20:BCC LFB26 :\ Control character found BNE LFB1A :\ Loop if not space JSR SkipSpaces :\ Skip any more spaces .LFB26 CLC:TYA:ADC &F2:STA &00,X :\ Add Y to base LDA &F3:ADC #&00:STA &01,X :\ Set returned address LDY #&FF:STY &02,X:STY &03,X :\ Set to &FFFFxxxx INY:LDA #&01 :\ Return Y=&00, A=&01 RTS .LFB3C EQUB &63 :\ Pass OSARGS to host RTS .osGBPB EQUB &93 :\ Pass OSGBPB to host RTS .osBGet EQUB &73 :\ Pass OSBGet to host RTS .osBPut EQUB &83 :\ Pass OSBPut to host RTS .osFIND EQUB &A3 :\ Pass OSFIND to host RTS .osFILE EQUB &53 :\ Pass OSFILE to host RTS \ Print embedded string \ ===================== .PrText PLA:STA &FA:PLA:STA &FB :\ &FA/B=>embedded string LDY #&00:STY &03FB :\ String at (&FA),Y is in block &00 INY .LFB4A LDA (&FA),Y :\ Get character CMP #&EA:BEQ LFB56 :\ Exit if NOP JSR OSASCI:INY:BNE LFB4A :\ Print char and loop for next .LFB56 TYA:CLC:ADC &FA TAX:LDA #&00:ADC &FB :\ Update return address PHA:TXA:PHA :\ Points after string .NullReturn RTS .LFBFB EQUW &0236 :\ Input buffer at &0236 EQUB &CA :\ Max. &CA characters (error, should be &C9) EQUB &20 :\ Minimum character EQUB &FF :\ Maximum character .Unsupported BRK BRK:EQUS "Unsupported":BRK \ Default vectors \ =============== .LFB87 EQUW Unsupported :\ &200 - USERV EQUW ErrorHandler :\ &202 - BRKV EQUW IRQ1Handler :\ &204 - IRQ1V EQUW Unsupported :\ &206 - IRQ2V EQUW osCLI :\ &208 - CLIV EQUW osBYTE :\ &20A - BYTEV EQUW osWORD :\ &20C - WORDV EQUW osWRCH :\ &20E - WRCHV EQUW osRDCH :\ &210 - RDCHV EQUW osFILE :\ &212 - FILEV EQUW osARGS :\ &214 - ARGSV EQUW osBGet :\ &216 - BGetV EQUW osBPut :\ &218 - BPutV EQUW osGBPB :\ &21A - GBPBV EQUW osFIND :\ &21C - FINDV EQUW Unsupported :\ &21E - FSCV EQUW NullReturn :\ &220 - EVNTV EQUW NullReturn :\ &222 - UPTV EQUW NullReturn :\ &224 - NETV EQUW Unsupported :\ &226 - VduV EQUW Unsupported :\ &228 - KEYV EQUW Unsupported :\ &22A - INSV EQUW Unsupported :\ &22C - RemV EQUW Unsupported :\ &22E - CNPV EQUW NullReturn :\ &230 - IND1V EQUW NullReturn :\ &232 - IND2V EQUW NullReturn :\ &234 - IND3V \ OSCLI command buffer \ -------------------- .LFC6A EQUS STRING$(128,CHR$0) EQUS STRING$(128,CHR$0) STZ &75,X :\ FD44 74 75 tu STZ &75,X :\ FD46 74 75 tu BVS LFD4C :\ FD48 70 02 p. BRK :\ FD4A 00 . BRK :\ FD4B 00 . EQUS STRING$(&FE00-P%,CHR$255) EQUS STRING$(&FE80-P%,CHR$255) EQUS STRING$(&FF00-P%,CHR$255) EQUS STRING$(&FF80-P%,CHR$255) EQUS STRING$(&FFB6-P%,CHR$255) .VECDEF :EQUB &36:EQUW LFB87 .LFFxx :JMP Unsupported .LFFxx :JMP Unsupported .LFFxx :JMP Unsupported .LFFxx :JMP Unsupported .LFFxx :JMP Unsupported .NVRDCH :JMP osRDCH .NVWRCH :JMP osWRCH .OSFIND :JMP (FINDV) .OSGBPB :JMP (GBPBV) .OSBPUT :JMP (BPutV) .OSBGET :JMP (BGetV) .OSARGS :JMP (ARGSV) .OSFILE :JMP (FILEV) .OSRDCH :JMP (RDCHV) .OSASCI :CMP #&0D:BNE OSWRCH .OSNEWL :LDA #&0A:JSR OSWRCH .OSPRCR :LDA #&0D .OSWRCH :JMP (WRCHV) .OSWORD :JMP (WORDV) .OSBYTE :JMP (BYTEV) .OS_CLI :JMP (CLIV) .NMIV :EQUW NMIHandler .RESETV :EQUW RESET .IRQV :EQUW InterruptHandler ]:NEXT