AS09 Assembler for M6809 [1.40]. Copyright 1994-2005, Frank A. Kingswood Page 1 ----------------------------------------------------------- TUBE09.SRC ----------------------------------------------------------- 1740 lines read, no errors in pass 1. ; 6809 Tube Client Code ; ===================== ; Copyright (C)1989, 2008, 2012, 2014, 2017 J.G.Harston ; This can be assembled with: ; DOS as9: as9 Client09.src -l now bin > errors.txt ; Kingswood as09: as09-dos -i -lTube09.lst -oTube09.bin Client09.src ; 6809.org.uk asm6809: (not yet checked) ; ; v0.10 1989 JGH: Initial unfinished version. ; v0.20 11-Mar-2008 JGH: Inspired by Johan Heuseveldt to complete ; 12-Mar-2008 JGH: Fixed where A/B was wrong way around in D ; OSBYTE &8E no longer ends with unbalanced stack ; BYTE_HI sends X,Y correct way around ; Internal variables at same address as Z80 ; v0.21 07-Jan-2012 JGH: Added client error handler ; v0.22 20-Nov-2014 DMB: Bugfix in FIRQ code from David Banks ; JGH: Added PRHEX and HR2HEX, execute enters at PROGRAM ; 25-Nov-2014 JGH: Added OSWORD <>0 handler, preparing to merge source ; with 6809 Serial Tube client. Crunched some JSRs to BSRs. ; Shorter FIRQ dispatch code. Moved text buffers to $FF00. ; 28-Nov-2014 JGH: Replaced LDA #0 with CLRA, use returned flags from WAIT_BYTE. ; STARTUP and OSCLI use internal stack. ; MEMTOP moved below code if code is in high memory. ; v0.23 30-Nov-2014 DMB: JSR [,X] should be JSR ,X in EXEC_ENTER. ; JGH: Fixed off-by-one in PR_HEX and preserves A, added PR_STRING. ; PULS reg followed by RTS merged into PULS reg,PC ; 02-Dec-2014 JGH: Implemented KBDTST for 6809 BIOS calls. Execute checks code ; header. WARM resets MEMBOT & MEMTOP. ; v0.24 07-Dec-2014 JGH: EXECUTE enters code with A=1 or A=0, PROG saved and restored, ; soft Break will re-enter at PROG. OSCLI saves all registers. ; Bugfix: data transfer FIRQs corrupted foreground X and B. ; DMB: Bugfix: EXECUTE should use ADDRESS+2 big-endian address. ; JGH: Raw 6809 code is not made the current program. Supervisor ; prompt makes itself current program. Full header (C) check. ; RESET avoids overwriting PROG so Soft Reset will re-enter ; current program. ; 14-Dec-2014 JGH: When EXECUTE called on RESET, does not report 'Not 6809 code' ; error, but jumps directly to CLICOM. Gives a cleaner startup ; display, and this is hook for future check for booting disk ; operating system. ; DMB: Bug: Hangs on Ctrl-Break, but not on Soft-Break ; v0.25 20-Dec-2014 JGH: Bugfix: Fixed hang on Ctrl-Break, FIRQ6/7 was wrong way around. ; Added local *GO and *HELP commands, LPTR set to command line, ; OSBYTE 142 sets null LPTR. OSBYTE $82-$84 return address/256 ; in Y. Testing TxRDY uses ASLA instead of AND #$40. Squashed ; some JSRs into BSRs. ; v1.00 01-Jan-2015 JGH: Rolled over to version 1.00. ; v1.01 21-Jun-2017 DMB: Bugfix: Event handler status register was read wrong way. ; 22-Jun-2017 JGH: EXECUTE passes caller's stack to callee. EXECUTE does not set ; code as current program, that is now responsibility of ; INITERR/OSINIT. OSCLI stack saving is now recursable. ; 23-Jun-2017 JGH: Precheck for '*RUN' to point LPTR to correct parameters. ; More stack space for transient OSCLI commands. ; v1.02 25-Jun-2017 JGH: Rolled over to version 1.02. ; 28-Jun-2017 JGH: Added test for 6309 to SWI code, optimised PRHEX routines. ; 16-Jul-2017 JGH: Checking with 6502 Client, only Transfer Type 4 updates ADDRESS. ; Byte/Word transfers check DMADONE before doing transfers. ; 25-Jul-2017 DMB: Bugfix: FIRQ6/7 were using signed counter offset. ; JGH: FIRQ execute/transfer addresses now a seperate variable so able ; to rationalise and tidy ADDRHI/ADDR/TRANS/PROG variables. ; 30-Jul-2017 DMB: Swap Sync/EnableIRQ in data transfer. ; 31-Jul-2017 JGH: Slight optimisation to BYTE_HI. ; v1.03 06-Aug-2017 JGH: Rolled over to version 1.03. ; 08-Aug-2017 JGH: Command table re-ordered to optimise dispatch. Optimised some ; ADD #$80 into ASLA. Bugfix for */(space)filename. ; 12-Aug-2017 JGH: *HELP always displays help message, optimised *HELP message. ; SWI checks for 6309. ; 15-Aug-2017 JGH: Forced JMP opcode at RAWVDU entry. ; v1.04 22-Aug-2017 JGH: Rolled over to version 1.04. ; 24-Aug-2017 JGH: Optimised SEND_BLOCK and WAIT_BLOCK. ; v1.05 25-Aug-2017 JGH: OSFILE/OSGBPB/OSARGS use big-endian control blocks ; 02-Sep-2017 JGH: PRTEXT preserves X as with Z80 Client. ; 12-Jul-2019 JGH: KBDTST/KBDIN routines use pending character input 0001 = KBDPEND: EQU 1 ; KBDTST/KBDIN pending input ; v1.06 25-Jun-2017 JGH: Removed superflous use of U in EXECUTE. 0106 = VERSION: EQU $0106 0000 = BUILD: EQU 0 ; ; 0001 = BIGENDIAN: EQU 1 ; Big-endian control block contents for OSFILE/OSGBPB/OSARGS ; ; ; This code may be freely reused. ; ; Acknowledgements to: ; Johan Heuseveldt: mentioning 6809 CoPros on the BBC Mailing List inspired me to ; complete the code. ; David Banks: plenty of testing on the Matchbox CoPro "real" hardware. ; ; Notes: ; 07-Jan-2012: When I initially wrote this I didn't have any 6809 hardware, so didn't ; know if this executed. ; 20-Nov-2014: DMB has tested this on Matchbox emulated hardware and shown it to work. ; ; ; Memory layout: ; +-------------+--------------------------------------------------------+ ; | 0000- | vvv User memory vvv | ; | 00C0-00FF | Internal variables if in low RAM | ; | 0100-01FF | Text buffers if in low RAM | ; | | | ; | -F6FF | ^^^ User stack ^^^ | ; | F700-F7BF | Text buffers if in high RAM | ; | F7C0-F7FF | Internal variables if in high RAM | ; | -F7FF | ^^^ User stack if Client in RAM ^^^ | ; +-------------+--------------------------------------------------------+ ; | F800-FFFF | Client ROM, copied to RAM on startup | ; | F800-F815 | 6809 BIOS entry vectors | ; | | | ; | FEE0-FEEF | Tube registers | ; | FEF0-FEFF | Hardware vectors, remapped from &FFF0-&FFFF with BA/BS | ; | FF00-FF7F | Text buffers and internal stack if running from RAM | ; | FF80- | Internal variables if running from RAM | ; | -FFFF | BBC MOS entry block | ; +-------------+--------------------------------------------------------+ ; ; BA/BS Signals are used to remap hardware vectors from &FFFx to &FEFx. ; ROM copied to RAM at startup, then ROM paged out by accessing any I/O. Any ; write-only I/O hidden "under" ROM must be disabled until I/O at IOADDR is ; accessed. ; Client error implemented with SWI (equivalent of 6502 BRK, Z80 RST &38, etc.) ; SWI2 and SWI3 reserved for applications (eg FLEX, OS-9, etc). ; ; To distinguish between 6809 and 6309 the SWI handler checks that U does not ; equal where PC is expected on the stack. This will normally be under program ; control when you call SWI to generate an error. If your code does not know ; what the contents of U is when generating an error, ensure U is cleared with ; CLR U:SWI:error block. ; ; In all cases JSR OSERROR can be used to generate an error. ; ; START OF ROM CODE ; ================= f800 = ORG $F800 f800 : ROMSTART: 0000 = RAMSTART: EQU $0000 f800 = RAMEND: EQU ROMSTART ; 6809 BIOS entry block always at F800 ; ==================================== f800 = ORG $F800 f800 : f82c COLD: FDB RESET ; $F800 - cold start f802 : f86e WARM: FDB WARMS ; $F802 - warm start IF KBDPEND f804 : f8fe INCH: FDB INCHAR ; $F804 - char input ELSE INCH: FDB OSRDCH ; $F804 - char input ENDIF f806 : f8f9 INCHE: FDB INECHO ; $F806 - char input with echo f808 : f907 INCHECK: FDB KBDTST ; $F808 - test for char input f80a : ffee OUTCH: FDB OSWRCH ; $F80A - char output f80c : f8ee PDATA: FDB PRDAT ; $F80C - output string until EOT f80e : ffe7 PCRLF: FDB OSNEWL ; $F80E - output CR/LF f810 : f8eb PSTRING: FDB PRTST ; $F810 - output CR/LF then string until EOT f812 : f8ea LRA: FDB LREAL ; $F812 - Load Real Address f814 : 2058 BRA WARMS ; $F814 - for FLEX compatibility f816 : BANNER: f816 : 0d FCB 13 f817 : 36383039205455.. FCC "6809 TUBE 64K " f825 : 31 FCB ((VERSION >> 8) & 15) + $30 f826 : 2e FCB "." f827 : 30 FCB ((VERSION >> 4) & 15) +$30 f828 : 36 FCB (VERSION & 15) + $30 IF BUILD FCB BUILD+96 ELSE f829 : 20 FCB 32 ENDIF IF DEBUG FCC " DEBUG" ENDIF f82a : 0d00 FCB 13,0 f82c : RESET: f82c : 1a50 ORCC #$50 ; Ensure interupts disabled f82e : 10cef800 LDS #RAMEND ; Put stack at top of RAM IF RAMEND = ROMSTART f832 : 1f41 TFR S,X ; Start copying from start of ROM ELSE LDX #ROMSTART ; Start copying from start of ROM ENDIF f834 : RESETLP1: f834 : ec84 LDD ,X ; Get two bytes from ROM f836 : ed81 STD ,X++ ; Store to RAM and increment X f838 : 8cfec0 CMPX #IOADDRS f83b : 2603 BNE RESETLP2 ; Loop until hit I/O space f83d : 8efef0 LDX #ROMHIGH ; Point to ROM after I/O space f840 : RESETLP2: f840 : 8cff8c CMPX #ADDRESS ; Don't modify ADDRESS and PROG f843 : 2603 BNE RESETLP3 f845 : 8eff94 LDX #DMADONE f848 : RESETLP3: f848 : 8c0000 CMPX #0 f84b : 26e7 BNE RESETLP1 ; Copy top part of ROM to RAM f84d : b6fee0 LDA >TUBE1S ; Access I/O registers to page ROM out ; Once ROM is paged out we can do subroutine calls ; as we can now read from stack in RAM ; STARTUP ; ======= ; Tube data: via R1: string $00 -- via R2: $7F or $80 ; f850 : STARTUP: f850 : 1a50 ORCC #$50 ; Disable interupts f852 : 10ceff80 LDS #CLISTK ; Use internal stack f856 : 8d66 BSR MEM_INIT ; Reset user memory limits and error handler f858 : beff90 LDX PROGRAM ; Copy current PROGRAM to ADDRESS f85b : bfff8c STX ADDRESS ; so will re-enter on Soft Break ; At this point, if 6309 could change character at BANNER+2 and PROMPT+1 f85e : 1c00 ANDCC #$00 ; Clear all flags, enable interupts f860 : bdf962 JSR PR_HELP ; Print banner via Tube WRCH protocol f863 : bdffe7 JSR OSNEWL ; SEND_TXT will use 7 bytes on stack f866 : 4f CLRA ; Set A to zero ; STA >ESCFLG ; Clear Escape flag ; ECSFLG will have been cleared when copying ROM/initialising workspace f867 : bdffee JSR OSWRCH ; Send terminating zero byte ; This will use 3 bytes on stack f86a : 4f CLRA ; Carry Clear to indicate Reset f86b : bdfa6c JSR CLI_WAIT ; Wait for result byte and enter code ; This will use 14 bytes on stack including data transfer ; Data transfer may happen while waiting ; Fall through to CLICOM if nothing executed ; Supervisor command line prompt ; ============================== ; Allow user to enter *command ; f86e : WARMS: f86e : CLILOOP: f86e : 10ceff80 LDS #CLISTK ; Initially use internal stack f872 : 8d4a BSR COM_INIT ; Reset user memory limits and error handler f874 : 10feff8a LDS MEMTOP ; Reset stack to top of user memory ; LDX #CLICOM ; Make Supervisor the current program to re-enter f878 : 8ef86e LDX #WARMS ; Make Supervisor the current program to re-enter f87b : bfff90 STX PROGRAM ; on soft reset f87e : 1c00 ANDCC #$00 ; Clear all flags, enable interupts f880 : CLILOOP2: f880 : 8ef893 LDX #PROMPT f883 : bdf965 JSR SEND_TXT ; Display prompt ; CLRA ; Set A to zero (SEND_TXT returns A=0) ; LDX #COM_BLK ; Point to control block (SEND_TXT returned X=COM_BLK) f886 : bdfff1 JSR OSWORD ; OSWORD &00 - Read a line of text f889 : 2514 BCS COM_ESC ; Escape pressed f88b : 8eff00 LDX #CLIBUF f88e : bdfff7 JSR OS_CLI ; Execute command f891 : 20ed BRA CLILOOP2 ; Loop back for another line f893 : PROMPT: f893 : 363830393e2a FCC "6809>*" ; Command prompt f899 : 00 FCB 0 f89a : COM_BLK: f89a : ff00 FDB CLIBUF ; Input buffer f89c : 5f FCB CLIEND-CLIBUF-1 ; Buffer size f89d : 20 FCB 32 ; Lowest acceptable CHR$32 f89e : ff FCB 255 ; Highest acceptable CHR$255 f89f : COM_ESC: f89f : 867e LDA #126 f8a1 : bdfff4 JSR OSBYTE ; Acknowledge Escape f8a4 : ESCAPE: f8a4 : 3f SWI f8a5 : 11 FCB 17 f8a6 : 457363617065 FCC "Escape" f8ac : 00 FCB 0 f8ad : COM_ERR: f8ad : 10feff8a LDS MEMTOP ; Reset stack to top of user memory f8b1 : bdffe7 JSR OSNEWL f8b4 : a680 LDA ,X+ ; Step X past error number f8b6 : bdf965 JSR SEND_TXT ; Print text at X f8b9 : bdffe7 JSR OSNEWL f8bc : 20c2 BRA CLILOOP2 ; Return to command prompt f8be : MEM_INIT: f8be : COM_INIT: ; This has already been done by copying ROM to RAM. But, when entering ; Supervisor we want to ensure full memory available. f8be : cc0000 LDD #RAMSTART f8c1 : fdff88 STD MEMBOT ; Initialise bottom of user memory f8c4 : ccf800 LDD #RAMEND f8c7 : fdff8a STD MEMTOP ; Initialise top of user memory f8ca : COM_BRKV: f8ca : ccf8ad LDD #COM_ERR ; Get Supervisor error handler address f8cd : fdfffa STD BRKV ; Set error handler f8d0 : ERR_INIT: f8d0 : 4d TSTA f8d1 : 2606 BNE ERR_INIT2 ; A<>$00, just read values f8d3 : fcff8e LDD TRANSFER ; Set last entered code as current program f8d6 : fdff90 STD PROGRAM f8d9 : ERR_INIT2: f8d9 : ccfe51 LDD #SWI_HANDLE f8dc : fdfefa STD XSWIV ; Point SWI vector to error BRK handler f8df : 8efffa LDX #BRKV f8e2 : 108eff80 LDY #ESCFLG ; Return X=BRKV, Y=ESCFLG, MI=little-endian FS calls IF BIGENDIAN f8e6 : 5f CLRB f8e7 : 4f CLRA ; Return PL=big-endian filing system calls ENDIF f8e8 : 1f03 TFR D,U ; Set U to a defined value so SWI works f8ea : NULL: ; Null routines f8ea : PREND: f8ea : LREAL: f8ea : 39 RTS ; FLEX/OS-9 BIOS code ; =================== IF KBDPEND f8eb : bdffe7 PRTST: JSR OSNEWL f8ee : a680 PRDAT: LDA ,X+ ; Get character f8f0 : 8104 CMPA #4 ; EOT character? f8f2 : 27f6 BEQ PREND ; End printing f8f4 : bdffee JSR OSWRCH ; Print character f8f7 : 20f5 BRA PRDAT ; Loop to next f8f9 : 8d03 INECHO: BSR INCHAR f8fb : 7effee JMP OSWRCH f8fe : 8d07 INCHAR: BSR KBDTST f900 : 27fc BEQ INCHAR ; Loop until character available f902 : 8d25 BSR KBDFLAG ; Clear 'pending character' flag f904 : 8600 _PENDA: LDA #0 ; Get pending character f905 = PENDA: EQU _PENDA+1 ; Pending character is parameter of LDA f906 : 39 RTS ; LDA PENDA ; Get pending character ; RTS f907 : 3436 KBDTST: PSHS D,X,Y ; Save registers f909 : b6ff80 LDA ESCFLG f90c : 8440 ANDA #$40 f90e : 2617 BNE KBDTST2 ; Character pending, return with NE f910 : 8e0000 LDX #0 f913 : 1f12 TFR X,Y f915 : 8681 LDA #$81 f917 : bdfff4 JSR OSBYTE ; INKEY(0) - get any pending character ; Y=$00 - character, X=character ; Y=$1B - escape ; Y=$FF - nothing pending f91a : 1f10 TFR X,D ; B=character f91c : 108c00ff CMPY #$FF f920 : 2705 BEQ KBDTST2 ; Nothing pending, return with EQ f922 : f7f905 STB PENDA f925 : 8d02 BSR KBDFLAG ; Set 'pending character' flag ; Fall through with NE=character pending f927 : KBDTST2: f927 : 35b6 PULS D,X,Y,PC f929 : KBDFLAG: f929 : 3401 PSHS CC f92b : 1a50 ORCC #$50 ; Disable interupts f92d : 8640 LDA #$40 ; Toggle key pending flag f92f : b8ff80 EORA ESCFLG f932 : b7ff80 STA ESCFLG f935 : 3581 PULS CC,PC ; Restore IRQs and return ELSE INECHO: JSR OSRDCH JMP OSWRCH PRTST: JSR OSNEWL PRDAT: LDA ,X+ ; Get character CMPA #4 ; EOT character? BEQ PREND ; End printing JSR OSWRCH ; Print character BRA PRDAT ; Loop to next KBDTST: PSHS A,X,Y LDA #$80 LDX #$FFFF ; Should check ADVAL(-2) if Serial is current input stream TFR X,Y JSR OSBYTE ; ADVAL(-1) - keyboard input buffer CMPX #0 ; Set Z/NZ from X PULS A,X,Y,PC ENDIF ; ***************** ; Printout Routines ; ***************** ; Print X as 4-digit hex ; ====================== ; API allows A to be corrupted ; All other registers preserved (v1.04 including B) f937 : PR_HEX2: f937 : 3404 PSHS B ; Save B f939 : 1f10 TFR X,D ; Copy X to D, so copy b8-b15 to A f93b : 8d04 BSR PR_HEX1 ; Print it f93d : 1f98 TFR B,A ; Copy b0-b7 to A f93f : 3504 PULS B ; Restore B ; Fall through into PR_HEX1 ; Print A as 2-digit hex ; ====================== ; API allows A to be corrupted ; All other registers preserved f941 : PR_HEX1: f941 : 3402 PSHS A ; Standard hex-print code f943 : 44 LSRA f944 : 44 LSRA f945 : 44 LSRA f946 : 44 LSRA f947 : 8d02 BSR PR_NYBBLE f949 : 3502 PULS A ; Get A back ; Fall through into PR_NYBBLE f94b : PR_NYBBLE: f94b : 840f ANDA #$0F f94d : 810a CMPA #$0A f94f : 2502 BCS PR_DIGIT f951 : 8b07 ADDA #7 f953 : PR_DIGIT: f953 : 8b30 ADDA #$30 f955 : 7effee JMP OSWRCH ; Print inline text ; ================= ; On exit: A=$00 ; X= corrupted ; from v1.05 ; X= preserved f958 : PR_TEXT: IF VERSION*16+BUILD>$1050 f958 : 3410 PSHS X ; Save X f95a : ae62 LDX 2,S ; Get stacked PC to X f95c : 8d07 BSR SEND_TXT ; Print text f95e : af62 STX 2,S ; Update stacked PC f960 : 3590 PULS X,PC ; Restore X and return to updated PC ELSE PULS X ; Pop PC to X BSR SEND_TXT ; Print text PSHS X ; Push updated X SEND_END: RTS ; And return to it ENDIF ; Print text string at X ; ====================== ; On entry: X=>zero-terminated text string ; On exit: X=>byte after zero byte terminator ; A=$00 ; f962 : PR_HELP: f962 : 8ef816 LDX #BANNER ; Print banner as help message f965 : SEND_TXT: f965 : a680 LDA ,X+ ; Get byte from X, increment X f967 : 2746 BEQ SEND_END ; End if $00 byte f969 : bdffe3 JSR OSASCI ; Send to OSASCI f96c : 20f7 BRA SEND_TXT ; Loop until $00 sent ; ********************** ; Line scanning Routines ; ********************** ; Scan hex string ; =============== ; On entry, X=>start of hex string ; On exit, X=>first non-hex character ; Y=hex value ; A=terminating character ; B=corrupted ; CS if number terminated, eg 123 X or 123 ; CC if number not terminated, eg 123X ; f96e : RD_HEX: f96e : 108e0000 LDY #0 ; Clear hex accumulator f972 : RD_HEXLP: f972 : a680 LDA ,X+ ; Get current character f974 : 8130 CMPA #$30 ; <'0', exit f976 : 2533 BCS RD_HEXDONE f978 : 813a CMPA #$3A ; '0'..'9', add to accumulator f97a : 250a BCS RD_HEXADD f97c : 84df ANDA #$DF ; Ensure upper case letter f97e : 8007 SUBA #$07 ; Convert letter, if <'A', exit f980 : 2529 BCS RD_HEXDONE f982 : 8140 CMPA #$40 f984 : 2425 BCC RD_HEXDONE ; If >'F', exit f986 : RD_HEXADD: f986 : 840f ANDA #$0F ; AB=0Nxx, X=>line Y=acc f988 : 1e02 EXG D,Y ; AB=acc, X=>line Y=0Nxx f98a : 58 ASLB f98b : 49 ROLA f98c : 58 ASLB f98d : 49 ROLA f98e : 58 ASLB f98f : 49 ROLA f990 : 58 ASLB f991 : 49 ROLA ; AB=acc*16, X=>line, Y=0Nxx f992 : 1e12 EXG X,Y ; AB=acc*16, X=0Nxx, Y=>line f994 : 1e01 EXG D,X ; AB=0Nxx, X=acc*16, Y=>line f996 : 1e89 EXG A,B ; AB=xx0N, X=acc*16, Y=>line f998 : 3a ABX ; AB=xx0N, X=acc*16+N, Y=>line f999 : 1e12 EXG X,Y ; AB=xx0N, X=>line, Y=acc*16+N f99b : 20d5 BRA RD_HEXLP ; Move to next character ; Skip parameter word ; =================== ; On entry, X=>command line ; On exit, X=>first non-space character after current parameter word ; A=first non-space character f99d : SKIPWORD: f99d : a680 LDA ,X+ ; Step past parameter f99f : 8121 CMPA #'!' f9a1 : 24fa BCC SKIPWORD f9a3 : 301f LEAX -1,X ; Step back, then skip spaces ; Skip spaces ; =========== ; On entry, X=>command line ; On exit, X=>first non-space character ; A=first non-space character f9a5 : SKIPSPC: f9a5 : a680 LDA ,X+ f9a7 : 8120 CMPA #' ' f9a9 : 27fa BEQ SKIPSPC ; Skip space characters f9ab : RD_HEXDONE: f9ab : 301f LEAX -1,X ; Point to non-hex/non-space char f9ad : 8121 CMPA #'!' ; Return CS if no following character IF VERSION*16+BUILD>$1050 f9af : SEND_END: ENDIF f9af : 39 RTS ; ********************** ; MOS Interface Routines ; ********************** ; OSCLI - Execute command ; ======================= ; On entry: X=>command string ; On exit: A holds any return value ; ; First check for local commands, then pass on to host ; f9b0 : CLI: f9b0 : 347c PSHS B,DP,X,Y,U ; Save everything on caller's stack, except A and CC IF VERSION*16+BUILD<$1060 LEAU -8,S ; Make a note of caller's stack with space for calls ELSE f9b2 : 1f43 TFR S,U ; Make a note of caller's stack with space for calls ENDIF ; CMPS #ROMSTART ; Check where the stack is f9b4 : 118cff00 CMPS #BOTSTK ; Check where the stack is f9b8 : 2404 BCC CLI_SYSSTK1 ; We're already using internal stack f9ba : 10ceff80 LDS #CLISTK ; Use internal stack f9be : CLI_SYSSTK1: ; As a *command may result in data transfer, that data may end up overwriting ; a stack in user memory, so use a temporary stack to do OS_CLI. If OS_CLI ; ends up jumping to a new process, a new stack will need to be be set up by ; that new process. There is space on the CLISTK for about seven recursive ; OS_CLI calls. f9be : 3440 PSHS U ; Save caller's stack pointer f9c0 : 8d13 BSR CLI_GO ; Process the *command f9c2 : 3540 PULS U ; If we get back, get caller's stack pointer back IF VERSION*16+BUILD<$1060 LEAS 8,U ; Restore caller's stack ELSE f9c4 : 1f34 TFR U,S ; Restore caller's stack ENDIF f9c6 : 35fc PULS B,DP,X,Y,U,PC ; Restore everything and return contents of A. ; Local *commands ; --------------- f9c8 : CLI_TABLE: f9c8 : 474f FCC "GO" f9ca : 80 FCB $80 f9cb : 48454c50 FCC "HELP" f9cf : 81 FCB $81 f9d0 : 52554e FCC "RUN" f9d3 : 82 FCB $82 f9d4 : 00 FCB 0 ; OSCLI - Check for local commands ; -------------------------------- ; On entry: X=>command string ; f9d5 : CLI_GO: f9d5 : CLI_LP1: f9d5 : 8dce BSR SKIPSPC ; Skip leading spaces f9d7 : a680 LDA ,X+ f9d9 : 812a CMPA #'*' f9db : 27f8 BEQ CLI_LP1 ; Skip leading '*'s f9dd : 301f LEAX -1,X f9df : 3410 PSHS X ; Save start of command text f9e1 : 812f CMPA #'/' ; Skip to parameters for '*/name' and '*/ name' f9e3 : 2770 BEQ CMD_SLASH f9e5 : 8db6 BSR SKIPWORD ; Step past command f9e7 : bfff86 STX LPTR ; Point LPTR to command parameters f9ea : 108ef9c8 LDY #CLI_TABLE ; Point to command table f9ee : CLI_LOOP1: f9ee : aee4 LDX ,S ; Get start of command text back f9f0 : a684 LDA ,X ; Get first character f9f2 : 8141 CMPA #'A' f9f4 : 256a BCS CLI_TUBE ; Not a letter, pass to host f9f6 : CLI_LOOP2: f9f6 : a680 LDA ,X+ ; Get character from command line f9f8 : 84df ANDA #$DF ; Force to upper case f9fa : a1a0 CMPA ,Y+ ; Compare with table entry f9fc : 27f8 BEQ CLI_LOOP2 ; Characters match, check next f9fe : a6a2 LDA ,-Y ; Step to command token fa00 : 2b16 BMI CLI_MATCH ; Match fa02 : a61f LDA -1,X ; Get character from command line fa04 : 812e CMPA #'.' fa06 : 270a BEQ CLI_DOT ; Abbreviated command fa08 : CLI_NEXT: fa08 : a6a0 LDA ,Y+ ; Search for command token fa0a : 2afc BPL CLI_NEXT ; Step to end of table entry fa0c : a6a4 LDA ,Y fa0e : 26de BNE CLI_LOOP1 ; Not end of table fa10 : 204e BRA CLI_TUBE ; Pass to host fa12 : CLI_DOT: fa12 : a6a0 LDA ,Y+ ; Search for command token fa14 : 2afc BPL CLI_DOT ; Step to end of table entry fa16 : 2006 BRA CLI_MATCH2 fa18 : CLI_MATCH: fa18 : e682 LDB ,-X ; Get current character fa1a : c121 CMPB #'!' fa1c : 2442 BCC CLI_TUBE ; Command line longer than table entry fa1e : CLI_MATCH2: fa1e : 8181 CMPA #$81 fa20 : 2730 BEQ CMD_HELP fa22 : 2433 BCC CMD_RUN ; *GO ; parameters ; ----------------------- fa24 : CMD_GO: fa24 : bdf9a5 BSR SKIPSPC fa27 : 10beff90 LDY PROGRAM ; Default to re-enter current program fa2b : 810d CMPA #13 fa2d : 2718 BEQ CLI_GO2 ; *GO - enter current program fa2f : 813b CMPA #';' fa31 : 2712 BEQ CLI_GO1 ; *GO ;params - enter current program fa33 : bdffa1 JSR SCANHEX ; Get hex address to Y fa36 : 2428 BCC CLI_TUBE ; Malformed hex address, pass to host fa38 : bdf9a5 BSR SKIPSPC fa3b : 813b CMPA #';' ; Check for ';' parameter marker fa3d : 2706 BEQ CLI_GO1 ; *GO ;params or *GO ;params fa3f : 810d CMPA #13 fa41 : 261d BNE CLI_TUBE ; *GO ... or *GO .... fa43 : 301f LEAX -1,X ; Balance following 1,X fa45 : CLI_GO1: fa45 : 3001 LEAX 1,X ; Step past ';' fa47 : CLI_GO2: fa47 : bfff86 STX LPTR ; Save pointer to command parameters fa4a : 3510 PULS X ; Drop old line pointer fa4c : 1f21 TFR Y,X ; X=entry address fa4e : 1a01 ORCC #$01 ; Set Carry to indicate OSCLI fa50 : 2022 BRA EXECUTE2 ; *HELP () ; --------------- fa52 : CMD_HELP: fa52 : bdf962 JSR PR_HELP ; Print banner as help message ; Fall through to CLI_TUBE, harmlessly updating LPTR ; *RUN - updates LPTR to point to correct parameters ; -------------------------------------------------------------------------- fa55 : CMD_SLASH: fa55 : 3001 LEAX 1,X ; Step past '/' fa57 : CMD_RUN: fa57 : bdf9a5 BSR SKIPSPC fa5a : bdf99d BSR SKIPWORD ; Step past filename fa5d : bfff86 STX LPTR ; Update LPTR to parameters ; OSCLI - Send command line to host ; ================================= ; On entry: stacked X=>command string ; LPTR=>command parameters, prepared for EXECUTE ; On exit: All registers possibly corrupted ; Registers should be preserved by calling code ; ; Tube data: $02 string $0D -- $7F or $80 ; fa60 : CLI_TUBE: fa60 : 3510 PULS X ; Get command string back fa62 : 8602 LDA #2 fa64 : bdfd1a JSR SEND_CMD ; Send command $02 = OSCLI fa67 : bdfcc7 JSR SEND_STR ; Send string at X fa6a : CLI_WAIT1: fa6a : 1a01 ORCC #$01 ; Set Carry to indicate OSCLI fa6c : CLI_WAIT: fa6c : bdfaef JSR WAIT_BYTE ; Wait for result via Tube R2 (preserves Cy) ; Data transfer may happen while waiting ; TSTA ; Check return code ; WAIT_BYTE returns flags set from A fa6f : 2a51 BPL CLI_DONE ; Nothing to execute, return ; EXECUTE - Enter code at ADDRESS ; =============================== ; Checks for possible code header, makes code current PROGRAM. ; On entry, ADDRESS=code entry address ; CS=entering from OSCLI ; CC=entering from RESET ; ; If code in high memory, MEMTOP moved to below code. ; If code returns, MEMTOP and PROGRAM restored to previous value. ; ; If code has a header it is entered with A=1. If not, it is entered with A=0. ; Code has a small initial stack with 100 bytes available on it (eg 50 subroutine ; calls) unless OSCLI calls OSCLI recursively. If the code calls OSINIT it ; becomes the current program and is re-entered at soft reset. Code that becomes ; the current program must set up their own stack in user space. ; ; If called from RESET and not 6809 code, error not reported, jumps directly ; to CLICOM. In future this is the point where a disk operating system would ; be checked for and booted. fa71 : EXECUTE: fa71 : beff8c LDX ADDRESS ; Get execution address, note: big-endian fa74 : EXECUTE2: fa74 : 3401 PSHS CC ; Save RESET/OSCLI flag fa76 : 1f12 TFR X,Y ; Save address in Y fa78 : e607 LDB 7,X ; Get (C) offset fa7a : 3a ABX ; X=>(C) string fa7b : cefacf LDU #EXEC_CHK+4 ; U=>check string fa7e : c604 LDB #4 ; 4 bytes to check fa80 : EXEC_LP: fa80 : a680 LDA ,X+ ; Get byte from header fa82 : a1c2 CMPA ,-U ; Compare with check string fa84 : 263d BNE EXEC_JUMP ; No match, enter as raw code fa86 : 5a DECB fa87 : 26f7 BNE EXEC_LP ; Loop to check all four bytes fa89 : a626 LDA 6,Y ; Get code type fa8b : 48 ASLA ; Check b6 by moving it into b7 fa8c : 2a41 BPL ERR_NOTCODE fa8e : 841e ANDA #2*15 ; Byte has been moved up, so mask and compare with 2*n fa90 : 8106 CMPA #2*3 fa92 : 263b BNE ERR_NOT6809 IF FALSE LDA ,Y ; Get entry opcode. Check if 6809 BRA or JMP to ADDA #2 ; filter out 68000 code with ROMTYPE=3 ANDA #$5D ; Error if not 6809 BRA or JMP BNE ERR_NOT6809 ENDIF fa94 : 301c LEAX -4,X fa96 : bfff82 STX FAULT ; Point FAULT to (C) string (should be version string) fa99 : feff90 LDU PROGRAM fa9c : beff8a LDX MEMTOP fa9f : 3502 PULS A ; Get RESET/OSCLI flag to A faa1 : 3450 PSHS X,U ; Save current MEMTOP and PROGRAM faa3 : 108c8000 CMPY #$8000 faa7 : 2504 BCS EXEC_ENTER ; Entering code in low memory, leave MEMTOP where it is faa9 : 10bfff8a STY MEMTOP ; Entering in high memory, put MEMTOP below entered code faad : EXEC_ENTER: faad : 10bfff8e STY TRANSFER ; Set as last entered code fab1 : beff86 LDX LPTR ; X=>command line IF VERSION*16+BUILD<$1060 LDU 6,S ; U=>caller's stack *BUG* Faulty if not called from OSCLI ENDIF fab4 : 46 RORA ; Move RESET/OSCLI flag back into Carry fab5 : 8601 LDA #1 ; A=1 for code with a header fab7 : ada4 JSR ,Y ; Call program execution address fab9 : 3560 PULS Y,U fabb : 10bfff8a STY MEMTOP ; Restore previous MEMTOP if code returns fabf : ffff90 STU PROGRAM ; Restore previous PROGRAM fac2 : CLI_DONE: fac2 : 39 RTS ; Return fac3 : EXEC_JUMP: fac3 : beff86 LDX LPTR ; X=>command line IF VERSION*16+BUILD<$1060 LDU 3,S ; U=>caller's stack *BUG* Faulty if not called from OSCLI ENDIF fac6 : 4f CLRA ; A=0 for raw code fac7 : 3501 PULS CC ; Get RESET/OSCLI flag fac9 : 6ea4 JMP ,Y ; Enter raw code facb : EXEC_CHK: facb : 294328 FCC ")C(" ; Deliberately backwards so doesn't match itself face : 00 FCB 0 facf : ERR_NOTCODE: ; PULS CC ; Get RESET/OSCLI flag ; LBCC CLICOM ; If called from RESET, drop straight into Supervisor ; JSR COM_BRKV ; SWI ; FCB 249 ; FCC "Not code" ; FCB 0 facf : ERR_NOT6809: facf : 3501 PULS CC ; Get RESET/OSCLI flag fad1 : 102404e4 LBCC CLICOM ; If called from RESET, drop straight into Supervisor ; Here is where we would check if this is hard reset, ; and look for a disk operating system to boot instead. fad5 : bdf8ca JSR COM_BRKV ; Error handler may have been overwritten, so set up fad8 : 3f SWI ; Supervisor error handler fad9 : f9 FCB 249 fada : 4e6f7420363830.. FCC "Not 6809 code" fae7 : 00 FCB 0 ; OSRDCH - Wait for character from input stream ; ============================================= ; On exit: A=char, Cy=carry ; ; Tube data: $00 -- Carry Char ; fae8 : RDCH: fae8 : 4f CLRA fae9 : bdfd1a JSR SEND_CMD ; Send command $00 - OSRDCH faec : WAIT_CHAR: faec : 8d01 BSR WAIT_BYTE ; Get returned byte faee : 48 ASLA ; Move b7 into Carry ; Fall through to fetch byte from Tube R2 ; Wait for a byte from Tube Register 2 ; ==================================== ; On exit: A=byte read ; PL/MI, EQ/NE set from A ; Other flags preserved ; faef : WAIT_BYTE: faef : b6fee2 LDA >TUBE2S ; Read Tube R2 Status faf2 : 2afb BPL WAIT_BYTE ; Wait for b7 set faf4 : b6fee3 LDA >TUBE2 ; Get byte from Tube R2 faf7 : BYTE_DONE: faf7 : 39 RTS ; OSBYTE ; ====== ; On entry: A,X,Y=OSBYTE parameters ; On exit: A preserved ; If A<$80, X=returned value ; If A>$7F, X, Y, Carry=returned values ; ; Tube data: $04 X A -- X ; $06 X Y A -- Cy Y X ; faf8 : BYTE: faf8 : 3406 PSHS A,B fafa : 4d TSTA fafb : 2b23 BMI BYTE_HI fafd : 8604 LDA #4 faff : bdfd1a JSR SEND_CMD ; Send command $04 - short BYTE fb02 : 1f10 TFR X,D ; B=X fb04 : bdfd18 JSR SEND_BYTEB ; Send second parameter from B fb07 : 3506 PULS A,B fb09 : 3406 PSHS A,B fb0b : bdfd1a JSR SEND_BYTE ; Send first parameter fb0e : 8ddf JSR WAIT_BYTE ; Wait for response fb10 : 1f89 TFR A,B ; Move result to low byte fb12 : 4f CLRA ; Ensure AB is only 8-bit value fb13 : 1f01 TFR D,X fb15 : 3586 PULS A,B,PC fb17 : BYTE_WAIT: fb17 : 8ef816 LDX #BANNER ; Point LPTR to fb1a : bfff86 STX LPTR fb1d : 7efa6a BRA CLI_WAIT1 ; Wait for program start ; OSBYTE >$7F ; ----------- fb20 : BYTE_HI: fb20 : 8182 CMPA #$82 ; A bit of optimisation fb22 : 2506 BCS BYTE_HI1 ; <$82, not a memory OSBYTE fb24 : 2734 BEQ MEM82 ; =$82, fetch address high word fb26 : 8185 CMPA #$85 fb28 : 2532 BCS MEM83 ; <$85, fetch low/high memory limit fb2a : BYTE_HI1: fb2a : 8606 LDA #6 fb2c : bdfd1a JSR SEND_CMD ; Send command $06 - long byte fb2f : 1f10 TFR X,D ; B=X - second parameter fb31 : bdfd18 JSR SEND_BYTEB ; Send second parameter from B fb34 : bdfd16 JSR SEND_BYTEY ; Send third parameter from Y fb37 : 3506 PULS A,B fb39 : bdfd1a JSR SEND_BYTE ; Send first parameter fb3c : 819d CMPA #$9D ; Was it fast BPUT? fb3e : 27b7 BEQ BYTE_DONE ; Don't wait for response fb40 : 818e CMPA #$8E ; Was it start language? fb42 : 27d3 BEQ BYTE_WAIT ; Wait for program start fb44 : 3406 PSHS A,B fb46 : 8da7 JSR WAIT_BYTE ; Wait for response fb48 : 48 ASLA ; Move b7 into Carry fb49 : 3401 PSHS CC ; Save flags fb4b : 8da2 JSR WAIT_BYTE ; Wait for response fb4d : 1f89 TFR A,B ; Move result to low byte fb4f : 4f CLRA ; Ensure AB is only 8-bit value fb50 : 1f02 TFR D,Y ; Return result in Y fb52 : 8d9b JSR WAIT_BYTE ; Wait for response, high byte still in B fb54 : 1e89 EXG A,B ; Swap so high byte is Y, low byte is fetched byte fb56 : 1f01 TFR D,X ; Return result in X as returned Y*256+X value fb58 : 3587 PULS CC,A,B,PC ; Restore flags/A/B and return fb5a : MEM82: fb5a : 8688 LDA #$88 fb5c : MEM83: fb5c : MEM84: fb5c : 48 ASLA ; A=16,8,10 fb5d : 8eff82 LDX #MEMBOT-6 ; Point to addresses fb60 : ec86 LDD A,X ; Fetch address value fb62 : 1f01 TFR D,X ; Return X=address fb64 : 1f89 TFR A,B ; Copy top byte to bottom byte fb66 : 4f CLRA ; Clear top byte fb67 : 1f02 TFR D,Y ; Return Y=address DIV 256 fb69 : 3586 PULS A,B,PC ; OSWORD ; ====== ; On entry: A=OSWORD number ; X=>control block ; fb6b : WORD: fb6b : 4d TSTA fb6c : 274b BEQ RDLINE ; Jump with OSWORD 0 - RDLINE ; OSWORD <>&00 ; ------------ ; Tube data: &08 function in_length block out_length -- block ; fb6e : 3426 PSHS A,B,Y ; Save A, B and Y fb70 : 3410 PSHS X ; Save X=>control block fb72 : 1f89 TFR A,B ; B=function fb74 : 8608 LDA #$08 fb76 : bdfd1a JSR SEND_CMD ; Send command $08 - OSWORD fb79 : bdfd18 JSR SEND_BYTEB ; Send OSWORD function in B fb7c : 5d TSTB ; Check OSWORD function fb7d : 2b0a BMI WORD_SEND ; Jump to send control block with functions>&7F fb7f : WORD_TXLO: fb7f : 8610 LDA #$10 ; Default SendBlock length fb81 : c115 CMPB #$15 ; Check OSWORD function fb83 : 2406 BCC WORD_SEND1 ; Use 16 bytes for OSWORD &15 to &7F fb85 : 8efbe8 LDX #WORDTX-1 ; X=>send length table fb88 : 3a ABX ; X=X+B, X=>send length fb89 : WORD_SEND: fb89 : a684 LDA ,X ; Get block length from control block or table fb8b : WORD_SEND1: fb8b : 1f89 TFR A,B ; B=control block length fb8d : aee4 LDX ,S ; Get X=>control block back fb8f : bdfd18 JSR SEND_BYTEB ; Send outward block length fb92 : 5a DECB fb93 : 2b04 BMI WORD_NOTX ; Only send length 1 to 128 fb95 : 5c INCB fb96 : bdfcd0 JSR SEND_BLOCK ; B=length, X=>block, returns B=0, X=>block fb99 : WORD_NOTX: fb99 : e662 LDB 2,S ; Get OSWORD function fb9b : 2b0a BMI WORD_RECV ; Jump to send control block with function>&7F fb9d : WORD_RXLO: fb9d : 8610 LDA #$10 ; Default ReceiveBlock length fb9f : c115 CMPB #$15 ; Check OSWORD function fba1 : 2406 BCC WORD_RECV1 ; Use 16 bytes for OSWORD &15 to &7F fba3 : 8efbfb LDX #WORDRX-2 ; X=>receive length table fba6 : 3a ABX ; X=X+B, X=>receive length fba7 : WORD_RECV: fba7 : a601 LDA 1,X ; Get receive length from table or control block fba9 : WORD_RECV1: fba9 : 1f89 TFR A,B ; B=send block length fbab : 3510 PULS X ; Get X=>control block back fbad : bdfd18 JSR SEND_BYTEB ; Send inward block length fbb0 : 5a DECB fbb1 : 2b04 BMI WORD_NORX ; Only receive length 1 to 128 fbb3 : 5c INCB fbb4 : bdfcd9 JSR WAIT_BLOCK ; Wait for returned control block fbb7 : WORD_NORX: fbb7 : 35a6 PULS A,B,Y,PC ; Restore A,B,Y and return ; OSWORD 0 - Read a line of text ; ------------------------------ ; On entry: X=>addr.hi, addr.lo, maxlen, charlo, charhi ; On exit: Cy=0: Ok, Cy=1: Escape ; Y=length of returned string in buffer at addr (Y=0 if escape) ; ; Note: Address of text string in control block is local big-endian address ; All other OSWORD calls use little-endian addresses to match Host ; ; Tube data: $0A block -- $FF or $7F string $0D ; fbb9 : RDLINE: fbb9 : 860a LDA #10 fbbb : bdfd1a JSR SEND_CMD ; Send command $0A - RDLINE fbbe : 3404 PSHS B fbc0 : 3002 LEAX 2,X ; X=X+2, point to parameters fbc2 : c603 LDB #3 fbc4 : bdfcd0 JSR SEND_BLOCK ; Send 3-byte control block fbc7 : 8607 LDA #7 fbc9 : bdfd1a JSR SEND_BYTE ; Send $0700 fbcc : bdfd18 JSR SEND_BYTEB ; Send $00 as B=0 from SEND_BLK fbcf : bdfaef JSR WAIT_BYTE ; Wait for response fbd2 : 48 ASLA ; Move bit 7 into Carry fbd3 : 250d BCS RD_DONE fbd5 : ae83 LDX ,--X ; Get text pointer from control block ; LDB #0 ; B=number received (B already zero from SEND_BLK) fbd7 : RD_STR: fbd7 : bdfaef JSR WAIT_BYTE ; Wait for bytes from Tube R2 fbda : a780 STA ,X+ ; Store in text buffer, increment X fbdc : 5c INCB ; Increment character count fbdd : 810d CMPA #13 ; Check current byte fbdf : 26f6 BNE RD_STR ; Loop until fbe1 : 5a DECB ; Decrement character count to balance ; ANDCC #$FE ; Clear carry (already CC from CMPA #13) fbe2 : RD_DONE: fbe2 : 8600 LDA #0 ; Clear A without clearing Carry fbe4 : 1f02 TFR D,Y ; Y=length fbe6 : 3504 PULS B ; Restore B fbe8 : 39 RTS ; Table of OSWORD control block lengths for &01-&14 ; ------------------------------------------------- fbe9 : WORDTX: fbe9 : 0005000504 FCB $00,$05,$00,$05,$04 fbee : 05080e0401 FCB $05,$08,$0E,$04,$01 fbf3 : 0105001020 FCB $01,$05,$00,$10,$20 fbf8 : 100d000880 FCB $10,$0D,$00,$08,$80 fbfd : WORDRX: fbfd : 0500050005 FCB $05,$00,$05,$00,$05 fc02 : 0000000509 FCB $00,$00,$00,$05,$09 fc07 : 0500081900 FCB $05,$00,$08,$19,$00 fc0c : 010d800880 FCB $01,$0D,$80,$08,$80 ; OSARGS - Read info on open file ; =============================== ; On entry: A=action ; X=>data (little-endian) ; Y=handle ; On exit: A=returned value ; X preserved ; X=>any returned data ; Y preserved ; ; Tube Data: $0C handle block function -- result block ; fc11 : ARGS: fc11 : 3426 PSHS A,B,Y ; Save handle, B and function fc13 : 860c LDA #$0C fc15 : bdfd1a JSR SEND_CMD ; Send command $0C - OSARGS fc18 : bdfd16 JSR SEND_BYTEY ; Send handle IF BIGENDIAN fc1b : 5f CLRB ; Point to first byte of word to send fc1c : bdfce3 JSR SEND_WORDS ; Send four-byte control block ELSE LDB #4 ; Four bytes to send JSR SEND_BLOCK ; Send four-byte control block ENDIF fc1f : 3502 PULS A ; Get action back fc21 : bdfd1a JSR SEND_BYTE ; Send action fc24 : bdfaef JSR WAIT_BYTE ; Wait for returned result fc27 : 3402 PSHS A ; Save result IF BIGENDIAN fc29 : 5f CLRB ; Point to first byte of word to read fc2a : bdfcf5 JSR WAIT_WORDS ; Wait for four-byte control block ELSE LDB #4 ; Four bytes to read JSR WAIT_BLOCK ; Wait for four-byte control block ENDIF fc2d : 35a6 PULS A,B,Y,PC ; Get result and original handle back, and return ; OSBGet - Get a byte from open file ; ================================== ; On entry: Y=handle ; On exit: A=byte Read ; Y=preserved ; Cy set if EOF ; ; Tube data: $0E handle -- Carry byte ; fc2f : BGet: fc2f : 3404 PSHS B fc31 : 860e LDA #$0E fc33 : bdfd1a JSR SEND_CMD ; Send command $0E - OSBGet fc36 : bdfd16 JSR SEND_BYTEY ; Send handle fc39 : 3504 PULS B fc3b : 7efaec JMP WAIT_CHAR ; Wait for Carry, Byte ; OSBPut - Put a byte to an open file ; =================================== ; On entry: A=byte to write ; Y=handle ; On exit: A=preserved ; Y=preserved ; ; Tube data: $10 handle byte -- $7F ; fc3e : BPut: fc3e : 3406 PSHS A,B ; Save byte and B fc40 : 8610 LDA #$10 fc42 : bdfd1a JSR SEND_CMD ; Send command $10 - OSBPut fc45 : bdfd16 JSR SEND_BYTEY ; Send handle fc48 : 3506 PULS A,B ; Get A and B back fc4a : 3406 PSHS A,B fc4c : bdfd1a JSR SEND_BYTE ; Send byte to Tube fc4f : bdfaef JSR WAIT_BYTE ; Wait for acknowledgement fc52 : 3586 PULS A,B,PC ; Restore A/B and return ; OSFIND - Open or Close a file ; ============================= ; On entry: A=function ; Y=handle or X=>filename ; On exit: A=zero or handle ; X,Y preserved ; ; Tube data: $12 function string $0D -- handle ; $12 $00 handle -- $7F ; fc54 : FIND: fc54 : 3406 PSHS A,B ; Save A fc56 : 8612 LDA #$12 fc58 : bdfd1a JSR SEND_CMD ; Send command $12 - OSFIND fc5b : 3506 PULS A,B ; Get function back fc5d : bdfd1a JSR SEND_BYTE ; Send function fc60 : 4d TSTA ; Check function fc61 : 2706 BEQ Close ; Jump to deal with Close fc63 : bdfcc7 JSR SEND_STR ; Send string at X fc66 : 7efaef JMP WAIT_BYTE ; Wait for returned handle fc69 : Close: fc69 : 3404 PSHS B fc6b : bdfd16 JSR SEND_BYTEY ; Send handle to Tube fc6e : bdfaef JSR WAIT_BYTE ; Wait for acknowledgement fc71 : 4f CLRA ; Zero A fc72 : 3584 PULS B,PC ; Restore B and return ; OSFILE - Operate on whole files ; =============================== ; On entry: A=function ; X=>control block ; On exit: A=result ; X preserved ; control block updated ; ; Note: Address of text string in control block is local big-endian address ; ; Tube data: $14 block string function -- result block ; fc74 : FILE: fc74 : 3436 PSHS A,B,X,Y ; Save B,X,Y registers and function in A fc76 : 8614 LDA #$14 fc78 : bdfd1a JSR SEND_CMD ; Send command $14 - OSFILE fc7b : 3002 LEAX 2,X ; Point to control block contents IF BIGENDIAN fc7d : c60c LDB #12 ; Point to first byte to send fc7f : bdfce3 JSR SEND_WORDS ; Send 16-byte control block ELSE LDB #16 ; 16 bytes to send JSR SEND_BLOCK ; Send 16-byte control block ENDIF fc82 : ae83 LDX ,--X ; Get big-endian filename pointer to X fc84 : bdfcc7 JSR SEND_STR ; Send filename string fc87 : 3502 PULS A ; Get function back fc89 : bdfd1a JSR SEND_BYTE ; Send function fc8c : bdfaef JSR WAIT_BYTE ; Wait for returned result ; Data transfer via interupts may happen while waiting fc8f : 3514 PULS B,X ; Restore B, get control block pointer back fc91 : 3406 PSHS A,B ; Save result and B again fc93 : 3002 LEAX 2,X ; Point to control block contents IF BIGENDIAN fc95 : c60c LDB #12 ; Point to first byte to read fc97 : bdfcf5 JSR WAIT_WORDS ; Wait for 16-byte control block ELSE LDB #16 ; 16 bytes to read JSR WAIT_BLOCK ; Wait for 16-byte control block ENDIF fc9a : 301e LEAX -2,X ; Restore X fc9c : 35a6 PULS A,B,Y,PC ; Get result, restore registers, and return ; OSGBPB - Multiple byte Read and write ; ===================================== ; On entry: A=function ; X=>control block ; On exit: A=returned value ; control block updated ; ; Tube data: $16 block function -- block Carry result ; fc9e : GBPB: fc9e : 3426 PSHS A,B,Y ; Save Y and function fca0 : 8616 LDA #$16 fca2 : bdfd1a JSR SEND_CMD ; Send command $16 - OSGBPB IF BIGENDIAN fca5 : 3001 LEAX 1,X ; Step past handle fca7 : c608 LDB #8 ; Point to first byte to send fca9 : bdfce3 JSR SEND_WORDS ; Send 12-byte control block fcac : a682 LDA ,-X ; Get handle fcae : bdfd1a JSR SEND_BYTE ; Send 0th byte of control block ELSE LDB #13 JSR SEND_BLOCK ; Send 13-byte control block ENDIF fcb1 : 3502 PULS A fcb3 : bdfd1a JSR SEND_BYTE ; Send function IF BIGENDIAN fcb6 : 3001 LEAX 1,X ; Step past handle fcb8 : c608 LDB #8 ; Point to first byte to read fcba : bdfcf5 JSR WAIT_WORDS ; Read 12-byte control block fcbd : bdfaef JSR WAIT_BYTE ; Get 0th byte of control block fcc0 : a782 STA ,-X ELSE LDB #13 JSR WAIT_BLOCK ; Wait for 13-byte control block ENDIF fcc2 : 3524 PULS B,Y ; Get B and Y back fcc4 : 7efaec JMP WAIT_CHAR ; Get Carry and result byte ; ***************** ; Tube I/O routines ; ***************** ; Send cr-string at X to Tube Register 2 ; ========================================= fcc7 : SEND_STR: fcc7 : a680 LDA ,X+ ; Get byte from X, increment X fcc9 : 8d4f BSR SEND_BYTE ; Send byte via Tube R2 fccb : 810d CMPA #13 ; Test current character ; EORA #13 would preserve carry fccd : 26f8 BNE SEND_STR ; Loop until CR sent fccf : 39 RTS ; Send block at X to Tube Register 2, B=block length ; ================================================== ; Returns X=preserved, B=0 fcd0 : SEND_BLOCK: fcd0 : 3a ABX ; X=X+B, X=>after last byte to send fcd1 : SEND_BLKLP: fcd1 : a682 LDA ,-X ; Decrement X, get byte from X fcd3 : 8d45 BSR SEND_BYTE ; Send byte via Tube R2 fcd5 : 5a DECB ; Decrement count of bytes to send fcd6 : 26f9 BNE SEND_BLKLP ; Loop until all bytes sent fcd8 : 39 RTS ; Wait for block at X from Tube Register 2, B=block length ; ======================================================== ; Returns X=preserved, B=0 fcd9 : WAIT_BLOCK: fcd9 : 3a ABX ; X=X+B, X=>after last byte to receive fcda : WAIT_BLKLP: fcda : bdfaef JSR WAIT_BYTE ; Get byte via Tube R2 fcdd : a782 STA ,-X ; Decrement X, store byte at X fcdf : 5a DECB ; Decrement count of bytes fce0 : 26f8 BNE WAIT_BLKLP ; Loop until all bytes sent fce2 : 39 RTS IF BIGENDIAN ; Send big-endian block at X to Tube Register 2, B=>first word ; ============================================================= ; Returns X=preserved, B<0 fce3 : SEND_WORDS: fce3 : 3a ABX ; X=X+B, X=>first byte to send fce4 : SEND_WDLP: fce4 : a680 LDA ,X+ ; Get byte from X, increment X fce6 : 8d32 BSR SEND_BYTE ; Send byte via Tube R2 fce8 : 5a DECB ; Decrement byte count fce9 : c503 BITB #3 fceb : 26f7 BNE SEND_WDLP ; Loop for four bytes fced : 3018 LEAX -8,X ; Point to next word down fcef : 5d TSTB fcf0 : 2af2 BPL SEND_WDLP ; Another word to do fcf2 : 3004 LEAX 4,X ; Restore X fcf4 : 39 RTS ; Wait for big-endian block at X from Tube Register 2, B=>first word ; ================================================================== ; Returns X=preserved, B<0 fcf5 : WAIT_WORDS: fcf5 : 3a ABX ; X=X+B, X=>first byte to receive fcf6 : WAIT_WDLP: fcf6 : bdfaef JSR WAIT_BYTE ; Get byte via Tube R2 fcf9 : a780 STA ,X+ ; Store byte at X, increment X fcfb : 5a DECB ; Decrement count of bytes fcfc : c503 BITB #3 fcfe : 26f6 BNE WAIT_WDLP ; Loop for four bytes fd00 : 3018 LEAX -8,X ; Point to next word down fd02 : 5d TSTB fd03 : 2af1 BPL WAIT_WDLP ; Another word to do fd05 : 3004 LEAX 4,X ; Restore X fd07 : 39 RTS ENDIF ; OSWRCH - Send character in A to Tube Register 1 ; =============================================== ; Preserves A, corrupts flags ; fd08 : WRCH: fd08 : 3402 PSHS A ; Save A fd0a : SEND_R1LP: fd0a : b6fee0 LDA >TUBE1S ; Read Tube R1 status fd0d : 48 ASLA ; Move TxRDY from b6 to b7 fd0e : 2afa BPL SEND_R1LP ; Loop until TxRDY set fd10 : 3502 PULS A ; Get A back fd12 : b7fee1 STA >TUBE1 ; Send byte to Tube R1 fd15 : 39 RTS ; Send byte in Y to Tube Register 2 via B ; ======================================= fd16 : SEND_BYTEY: fd16 : 1f20 TFR Y,D ; ; Fall through into SEND_BYTEB ; Send byte in B to Tube Register 2 ; ================================== fd18 : SEND_BYTEB: fd18 : 1f98 TFR B,A ; ; Fall through into SendByte ; Send byte in A to Tube Register 2 ; ================================== ; Preserves A, corrupts flags ; fd1a : SEND_CMD: fd1a : SEND_BYTE: fd1a : 3402 PSHS A ; Save A fd1c : SEND_BYTELP: fd1c : b6fee2 LDA >TUBE2S ; Read Tube R2 status fd1f : 48 ASLA ; Move TxRDY from b6 to b7 ; ANDA #$40 would preserve carry fd20 : 2afa BPL SEND_BYTELP ; Loop until TxRDY set fd22 : 3502 PULS A ; Get A back fd24 : b7fee3 STA >TUBE2 ; Send byte to Tube R2 fd27 : 39 RTS ; **************************************** ; Host->Client communication via interupts ; **************************************** ; When Host sends a byte to R1 or R4 it generates a Client IRQ. ; Data transfers are syncronised with client NMIs. Graham Toal's ; design sends Tube IRQs to 6809 FIRQs and Tube NMIs to 6809 IRQs. ; Transfers are synchronised with SYNC instruction waiting for IRQs. ; ; This code manually translated from Graham Toal's Skimp code ; with half an eye on the PDP-11, Z80 and 6502 code. ; Most code before this point translated from JGH PDP-11 client. ; Interupt handler ; ================ ; Stack holds: CC with E=0, PC ; CC has I and F set to disable further IRQs and FIRQs ; fd28 : FIRQ_HANDLE: fd28 : 3402 PSHS A fd2a : b6fee6 LDA >TUBE4S ; Read Tube R4 status fd2d : 2b51 BMI FIRQ_R4 ; If data in Tube R4, jump to process errors and transfers fd2f : b6fee0 LDA >TUBE1S ; Read Tube R1 status fd32 : 2b06 BMI FIRQ_R1 ; If data in Tube R1, jump to process Escape and Events fd34 : 3502 PULS A ; Get A back fd36 : 6e9fffb1 JMP [IRQ2V] ; Pass interupt onwards ; Interupt generated by data in Tube R1 ; ------------------------------------- fd3a : FIRQ_R1: fd3a : b6fee1 LDA >TUBE1 fd3d : 2b1b BMI FIRQ_Escape ; b7=1, jump to set Escape state ; ; A<$80 - Host event being passed to client ; Tube data: via R1: $00 Y X A ; fd3f : 3502 PULS A ; Pop A to restack all registers fd41 : 3476 PSHS A,B,X,Y,U ; Save everything fd43 : 8d1c BSR Get_R1 ; Get event Y parameter fd45 : 1f89 TFR A,B fd47 : 4f CLRA ; Ensure AB is 8-bit value fd48 : 1f02 TFR D,Y fd4a : 8d15 BSR Get_R1 ; Get event X parameter fd4c : 1f89 TFR A,B fd4e : 4f CLRA ; Ensure AB is 8-bit value fd4f : 1f01 TFR D,X fd51 : 8d0e BSR Get_R1 ; Get event A parameter fd53 : ad9ffffc JSR [EVENTV] ; Dispatch event fd57 : 3576 PULS U,Y,X,B,A ; Restore registers fd59 : 3b RTI ; Return from interupt ; A>$7F - Host changing Escape state ; Tube data: via R1: flag, b7=1, b6=state ; fd5a : FIRQ_Escape: fd5a : 48 ASLA ; Move b6 into b7 fd5b : b7ff80 STA >ESCFLG ; Store Escape flag fd5e : 3502 PULS A ; Restore A fd60 : 3b RTI ; Return from interupt ; Read byte from Tube R1, allowing Tube R4 transfers to take place ; ---------------------------------------------------------------- fd61 : Get_R1: fd61 : b6fee6 LDA >TUBE4S ; Read Tube R4 status fd64 : 2a02 BPL NotFIRQ_R4 ; Pending R4 transfer higher priority than R1 transfer fd66 : 8d12 BSR FIRQ_R4_CC ; Deal with R4 interupt fd68 : NotFIRQ_R4: fd68 : b6fee0 LDA >TUBE1S ; Read Tube R1 status fd6b : 2af4 BPL Get_R1 ; Loop until b7 set fd6d : b6fee1 LDA >TUBE1 ; Get byte from Tube R1 fd70 : 39 RTS ; Read byte from Tube R4 ; ---------------------- fd71 : Get_R4: fd71 : b6fee6 LDA >TUBE4S ; Read Tube R4 status fd74 : 2afb BPL Get_R4 ; Loop until b7 set fd76 : b6fee7 LDA >TUBE4 ; Get byte from Tube R4 fd79 : 39 RTS ; Interrupt generated by data in Tube R4 ; -------------------------------------- fd7a : FIRQ_R4_CC: fd7a : 1c7f ANDCC #$7F ; Clear 'all registers' bit fd7c : 3401 PSHS CC ; Push CC to let this be a subroutine fd7e : 3402 PSHS A ; Push A to balance following Pull fd80 : FIRQ_R4: fd80 : 3502 PULS A ; Pop A to restack registers fd82 : 3416 PSHS A,B,X ; Rearrange stack contents fd84 : b6fee7 LDA >TUBE4 fd87 : 2a22 BPL FIRQ_Data ; b7=0, jump for data transfer ; A>$7F - Error occured ; Tube data: via R2: $00 err string $00 ; fd89 : 10ceff80 LDS #ERRSTK ; Collapse stack fd8d : 8eff00 LDX #ERRBLK ; Point to error buffer fd90 : bdfaef JSR WAIT_BYTE ; Wait for BRK error code fd93 : 863f LDA #$3F ; SWI opcode fd95 : a780 STA ,X+ ; Store SWI opcode fd97 : bdfaef JSR WAIT_BYTE ; Get error number fd9a : a780 STA ,X+ ; Store error number fd9c : FIRQ_R4LP: fd9c : bdfaef JSR WAIT_BYTE ; Wait for byte of error string fd9f : a780 STA ,X+ ; Store in error buffer ; WAIT_BYTE returns flags set from A fda1 : 26f9 BNE FIRQ_R4LP ; Loop until terminating $00 received fda3 : 8eff01 LDX #ERRBLK+1 ; Point to error block after SWI opcode fda6 : 3410 PSHS X ; Push error pointer onto stack fda8 : 7effbc JMP OSERROR ; Jump to generate error ; FIRQ and IRQ will be enabled by error handler ; Data transfer via FIRQs ; ----------------------- ; R4<$80 - Data transfer ; Tube data: via R4: action ID block sync, via R3: data ; ; Cribbed from Graham Toal's Skimp code ; fdab : FIRQ_Data: ; A=transfer type ; fdab : 3402 PSHS A ; Save transfer type fdad : 8dc2 BSR Get_R4 ; Wait for caller ID fdaf : 3502 PULS A ; Get transfer type back fdb1 : 8105 CMPA #5 ; Is it 'release'? fdb3 : 2606 BNE FIRQ_NotDone; No, jump to do transfer DMB: fixed BEQ/BNE error fdb5 : 7fff94 CLR DMADONE ; Signal 'transfer done' fdb8 : 3516 PULS A,B,X ; Restore registers fdba : 3b RTI ; and return from interupt ; fdbb : FIRQ_NotDone: fdbb : 3402 PSHS A ; Save transfer type again fdbd : 8db2 BSR Get_R4 ; Get data address MSB fdbf : 8db0 BSR Get_R4 ; Get data address fdc1 : 8dae BSR Get_R4 ; Get data address fdc3 : 1e89 EXG A,B fdc5 : 8daa BSR Get_R4 ; Get data address LSB fdc7 : 1e89 EXG A,B ; D=data address fdc9 : 1f01 TFR D,X ; X=data address ; LDA >TUBE3S ; Read from Tube R3 twice to clear FIFO ; LDA >TUBE3S ; Z80, 32016 and 80x86 client don't actually do this fdcb : 86ff LDA #$FF fdcd : b7ff94 STA DMADONE ; Signal 'transfer in progress' fdd0 : 8d9f BSR Get_R4 ; Get sync byte fdd2 : 1cbf ANDCC #$BF ; DMB: re-enable FIRQ interrupts to allow Release FIRQ fdd4 : a6e0 LDA ,S+ ; Pop A from stack and set Z flag fdd6 : 2766 BEQ FIRQ0 ; Dispatch to FIRQ subhandler fdd8 : 8102 CMPA #2 fdda : 2555 BCS FIRQ1 fddc : 2743 BEQ FIRQ2 fdde : 8104 CMPA #4 fde0 : 252f BCS FIRQ3 fde2 : 2767 BEQ FIRQ4 fde4 : 5f CLRB ; B=counter for 256-byte transfers fde5 : 8107 CMPA #7 ; We will never get a FIRQ5 here as filtered out earlier fde7 : 2511 BCS FIRQ6 fde9 : 2663 BNE FIRQ_DONE ; 1-byte and 2-byte Tube R3 interrupts done via IRQ/SYNC mechanism ; 256-byte transfers done by polling transfer register ; Transfer 7 - Multiple byte host -> parasite ; ------------------------------------------- fdeb : FIRQ7: fdeb : FIRQ7lp: fdeb : b6fee4 LDA >TUBE3S ; Wait for Tube R3 ready fdee : 2afb BPL FIRQ7lp fdf0 : b6fee5 LDA >TUBE3 ; Get byte from Tube host via R3 fdf3 : a780 STA ,X+ ; Store in parasite memory at X fdf5 : 5a DECB ; Decrement counter fdf6 : 26f3 BNE FIRQ7lp ; Loop 256 times fdf8 : 2054 BRA FIRQ_DONE ; Transfer 6 - Multiple byte parasite -> host ; ------------------------------------------- fdfa : FIRQ6: fdfa : FIRQ6lp: fdfa : b6fee4 LDA >TUBE3S ; Wait for Tube R3 ready fdfd : 2afb BPL FIRQ6lp fdff : a680 LDA ,X+ ; Get byte from parasite memory at X fe01 : b7fee5 STA >TUBE3 ; Send to Tube host via R3 fe04 : 5a DECB ; Decrement counter fe05 : 26f3 BNE FIRQ6lp ; Loop 256 times fe07 : FIRQ6lp2: fe07 : b6fee4 LDA >TUBE3S ; Wait for Tube R3 ready fe0a : 2afb BPL FIRQ6lp2 fe0c : b7fee5 STA >TUBE3 ; Send 257th byte to flush FIFO fe0f : 203d BRA FIRQ_DONE ; Transfer 3 - Double byte host -> parasite ; ----------------------------------------- fe11 : FIRQ3: fe11 : FIRQ3lp: fe11 : 13 SYNC ; Wait for IRQ fe12 : b6ff94 LDA DMADONE ; Has flag changed? fe15 : 2737 BEQ FIRQ_DONE ; FIRQ5 has cleared flag fe17 : b6fee5 LDA >TUBE3 ; Get two bytes from Tube host fe1a : f6fee5 LDB >TUBE3 fe1d : ed81 STD ,X++ ; Store them in parasite memory fe1f : 20f0 BRA FIRQ3lp ; Loop until FIRQ5 clears flag ; Transfer 2 - Double byte parasite -> host ; ----------------------------------------- fe21 : FIRQ2: fe21 : FIRQ2lp: fe21 : 13 SYNC ; Wait for IRQ fe22 : b6ff94 LDA DMADONE ; Has flag changed? fe25 : 2727 BEQ FIRQ_DONE ; FIRQ5 has cleared flag fe27 : ec81 LDD ,X++ ; Fetch two bytes from parasite memory fe29 : b7fee5 STA >TUBE3 ; Send them to Tube host fe2c : f7fee5 STB >TUBE3 fe2f : 20f0 BRA FIRQ2lp ; Loop until FIRQ5 clears flag ; Transfer 1 - Single bytes host -> parasite ; ------------------------------------------ fe31 : FIRQ1: fe31 : FIRQ1lp: fe31 : 13 SYNC ; Wait for IRQ fe32 : b6ff94 LDA DMADONE ; Has flag changed? fe35 : 2717 BEQ FIRQ_DONE ; FIRQ5 has cleared flag fe37 : b6fee5 LDA >TUBE3 ; Get byte from Tube host fe3a : a780 STA ,X+ ; Store in parasite memory fe3c : 20f3 BRA FIRQ1lp ; Loop until FIRQ5 clears flag ; Transfer 0 - Single bytes parasite -> host ; ------------------------------------------ fe3e : FIRQ0: fe3e : FIRQ0lp: fe3e : 13 SYNC ; Wait for IRQ fe3f : b6ff94 LDA DMADONE ; Has flag changed? fe42 : 270a BEQ FIRQ_DONE ; FIRQ5 has cleared flag fe44 : a680 LDA ,X+ ; Get byte from parasite memory fe46 : b7fee5 STA >TUBE3 ; Send to Tube host fe49 : 20f3 BRA FIRQ0lp ; Loop until FIRQ5 clears flag ; Transfer 4 - Set program execute address ; ---------------------------------------- fe4b : FIRQ4: fe4b : bfff8c STX ADDRESS ; Update Execution Address fe4e : FIRQ_DONE: fe4e : FIRQ_EXIT: fe4e : 3516 PULS A,B,X ; After a FIRQ4 the Host will then send a FIRQ5 to release the Tube and ; clear DNA_DONE. OSCLI handler will pick up execution address and pass ; it to EXECUTE. ; Null interupt routines ; ====================== ; OS-9 and FLEX use a timer on IRQ to poll background processes ; fe50 : NULL_RTI: fe50 : RES_HANDLE: fe50 : SWI2_HANDLE: fe50 : SWI3_HANDLE: fe50 : IRQ_HANDLE: fe50 : NMI_HANDLE: fe50 : 3b RTI ; SWI - Generate an error ; ======================= 0001 = M6309: EQU 1 ; Check for 6309 CPU fe51 : SWI_HANDLE: IF M6309 fe51 : 11a36a CMPU 10,S ; Compare U with stacked U or stacked PC fe54 : 2602 BNE SWI_6809 ; It's stacked PC, so is not 6309 native mode fe56 : 3262 LEAS 2,S ; Step past stacked W fe58 : SWI_6809: ENDIF fe58 : 326a LEAS 10,S ; Point to stacked PC fe5a : ERR_HANDLE: fe5a : 3510 PULS X ; Pop address of error block after SWI opcode fe5c : bfff82 STX FAULT ; Save pointer to last error fe5f : 1c00 ANDCC #$00 ; Clear all flags, enable interupts fe61 : 6e9ffffa JMP [BRKV] ; Jump to current error handler with X=>error ; I/O address space ; ================= fec0 = ORG $FEC0 fec0 : IOADDRS: ; Add any extra I/O devices here ; For example: ; $FECx VIA ; $FEDx MMU ; $FEEx TUBE fee0 = ORG $FEE0 fee0 : 00 TUBE1S: FCB 0 ; $FEE0 ; Tube registers fee1 : 00 TUBE1: FCB 0 ; $FEE1 fee2 : 00 TUBE2S: FCB 0 ; $FEE2 fee3 : 00 TUBE2: FCB 0 ; $FEE3 fee4 : 00 TUBE3S: FCB 0 ; $FEE4 fee5 : 00 TUBE3: FCB 0 ; $FEE5 fee6 : 00 TUBE4S: FCB 0 ; $FEE6 fee7 : 00 TUBE4: FCB 0 ; $FEE7 ; If Tube registers fully decoded, space for 8 I/O addresses here ; For example: ; $FEE8/9 ACIA ; Remapped hardware vectors ; ========================= ; BA/BS decoded to toggle address line A8 to map hardware vectors to $FEF0 ; fef0 = ORG $FEF0 fef0 : ROMHIGH: fef0 : fe50 XTRAPV: FDB RES_HANDLE ; $FEF0 ; Hardware vectors, paged in to $FFFx fef2 : fe50 XSWI3V: FDB SWI3_HANDLE ; $FEF2 fef4 : fe50 XSWI2V: FDB SWI2_HANDLE ; $FEF4 fef6 : fd28 XFIRQV: FDB FIRQ_HANDLE ; $FEF6 fef8 : fe50 XIRQV: FDB IRQ_HANDLE ; $FEF8 fefa : fe51 XSWIV: FDB SWI_HANDLE ; $FEFA fefc : fe50 XNMIV: FDB NMI_HANDLE ; $FEFC fefe : f82c XRESETV: FDB RESET ; $FEFE ; Text buffers ; ============ ff00 = ORG $FF00 ff00 : ERRBLK: ; Buffer to store host error block ff00 : BOTSTK: ; Bottom of internal stack ff00 : 00000000000000.. CLIBUF: RMB 128-32 ; Space to enter command line from CLI prompt ff60 : 00000000000000.. CLIEND: RMB 32 ff80 : ERRSTK: ; Internal stack for host errors ff80 : CLISTK: ; Internal stack for CLI commands ; as main memory may be overwritten ; Tube system workspace and MOS entry block ; ========================================= ff80 = ORG $FF80 ff80 : WORKSP: ; Use same addresses as Z80 ff80 : 00 ESCFLG: FCB 0 ; $FF80 ; Escape and pending input flag ff81 : 00 TEMPA: FCB 0 ; $FF81 ; TempA/Personality ff82 : f816 FAULT: FDB BANNER ; $FF82 ; Last error message ff84 : f8ad DEFERR: FDB COM_ERR ; $FF84 ; Default error handler ff86 : f816 LPTR: FDB BANNER ; $FF86 ; Command line tail ff88 : 0000 MEMBOT: FDB RAMSTART ; $FF88 ; Bottom of user memory ff8a : f800 MEMTOP: FDB RAMEND ; $FF8A ; Top of user memory ff8c : ffb9 ADDRESS: FDB CLICOM ; $FF8C ; Execution address ff8e : ffb9 TRANSFER: FDB CLICOM ; $FF8E ; Transfer address ff90 : ffb9 PROGRAM: FDB CLICOM ; $FF90 ; Current program address ff92 : 0000 ADDRHI: FDB 0 ; $FF92 ; Memory address high word ff94 : 00 DMADONE: FCB 0 ; $FF94 ; Transfer completion flag ; BBC MOS entry points ; -------------------- ff95 = ORG $FF95 ff95 : 7ef8ea JMP >NULL ; &FF95 ; Service ff98 : 7ef82c OSCOLD: JMP >RESET ; &FF98 ; Cold ff9b : 7ef965 PRSTRING: JMP >SEND_TXT ; &FF9B ; Print ASCIIZ text at X ff9e : 7e FCB $7E ; &FF9E ; Force a JMP opcode ff9f : ffee FDB OSWRCH ffa1 : 7ef96e SCANHEX: JMP >RD_HEX ; &FFA1 ; ReadHex ffa4 : 7ef8ea DISKACC: JMP >NULL ; &FFA4 ; DiskAccess ffa7 : 7ef8ea DISKCCP: JMP >NULL ; &FFA7 ffaa : 7ef941 PRHEX: JMP >PR_HEX1 ; &FFAA ; Print A as 8-bit hex ffad : 7ef937 PR2HEX: JMP >PR_HEX2 ; &FFAD ; Print X as 16-bit hex ffb0 : 7efe50 USERINT: JMP >NULL_RTI ; &FFB0 ; Pass on FIRQs if not Tube FIRQ ffb1 = IRQ2V: EQU USERINT+1 ffb3 : 7ef958 PRTEXT: JMP >PR_TEXT ; &FFB3 ; Print inline ASCIIZ text ffb6 : 7ef8ea JMP >NULL ; &FFB6 ; VecDef/PrntC ffb9 : CLICOM: ffb9 : 7ef86e OSQUIT: JMP >CLILOOP ; &FFB9 ; Quit current process, enter Supervisor ffbc : ERRJMP: ffbc : 7efe5a OSERROR: JMP >ERR_HANDLE; &FFBC ; Generate an error ffbf : INITERR: ffbf : 7ef8d0 OSINIT: JMP >ERR_INIT ; &FFBF ; Initialise program environment ffc2 : 7ef8ea DISKRST: JMP >NULL ; &FFC2 ; DiskReset ffc5 : 7ef8ea JMP >NULL ; &FFC5 ; Deprecated ffc8 : 7ef8ea JMP >NULL ; &FFC8 ffcb : 7ef8ea JMP >NULL ; &FFCB ; BBC MOS file entry points ; ------------------------- ffce : 7efc54 OSFIND: JMP >FIND ; $FFCE ffd1 : 7efc9e OSGBPB: JMP >GBPB ; $FFD1 ffd4 : 7efc3e OSBPUT: JMP >BPut ; $FFD4 ffd7 : 7efc2f OSBGET: JMP >BGet ; $FFD7 ffda : 7efc11 OSARGS: JMP >ARGS ; $FFDA ffdd : 7efc74 OSFILE: JMP >FILE ; $FFDD ; BBC MOS character entry points ; ------------------------------ ffe0 : 7efae8 OSRDCH: JMP >RDCH ; $FFE0 ffe3 : 810d OSASCI: CMPA #13 ; $FFE3 ffe5 : 2607 BNE OSWRCH ffe7 : 860a OSNEWL: LDA #10 ; $FFE7 ffe9 : bdffee JSR >OSWRCH ffec : 860d OSWRCR: LDA #13 ; $FFEC ffee : 7efd08 OSWRCH: JMP >WRCH ; $FFEE ; BBC MOS system entry points ; --------------------------- fff1 : 7efb6b OSWORD: JMP >WORD ; $FFF1 fff4 : 7efaf8 OSBYTE: JMP >BYTE ; $FFF4 fff7 : 7ef9b0 OS_CLI: JMP >CLI ; $FFF7 ; System vectors ; -------------- fffa : f8ad BRKV: FDB COM_ERR ; $FFFA ; Error handler fffc : f8ea EVENTV: FDB NULL ; $FFFC ; Event vector fffe : f82c L_FFFE: FDB RESET ; $FFFE ; Reset vector ; Memory Mapping Unit/Dynamic Address Translation ; =============================================== ; SWTPC clones have write-only MMU/DAT at $FFF0 No errors in pass 2. Wrote binary from address $f800 through $ffff. Total size 2048 bytes.