6309/6809/6811/6812 CoProcessor Technical Reference =================================================== J.G.Harston, 70 Camm Street, Walkley, Sheffield S6 3TR http://mdfs.net/Docs/Books/6809CoPro/Technical Date: 01-Sep-2017 The 68xx CoProcessor system is a 68xx system that communicates with the Acorn Tube protocol with a host computer system via some form of communication channel, such as a hardware Tube or a serial link. It should be able to run on any 68xx system such as a custom 6809 CoPro, a Dragon, a SWTPC-09 or a CoCo. The documentation is the same for a Tube client running on a 6800, 6309, 6809, 6811 or 6812. This document also defines the Acorn MOS API for any 68xx platform, and any implementation must adhere to this document. Host Interface ============== The 68xx Tube client provides both a standard 68xx BIOS entry block at &F800 and a standard Acorn MOS entry block at &FF80. On calling, any registers not mentioned are preserved, other than the flags in CC which may be modified. The interupt state is preserved. 68xx BIOS --------- Called with JMP [addr] or JSR [addr]. COLD $F800 - cold start WARM $F802 - warm start INCH $F804 - char input INCHE $F806 - char input with echo INCHECK $F808 - test for char input OUTCH $F80A - char output PDATA $F80C - output string at X until EOT PCRLF $F80E - output LF/CR PSTRING $F810 - output LF/CR then string at X until EOT LRA $F812 - Load Real Address MONITOR $F814 - for FLEX compatibility, called with JMP $F814 Acorn MOS system entry points ----------------------------- Called with JMP addr or JSR addr. OS_CLI $FFF7 Execute -terminated command string pointed to by X. On return, A may have a return value with A=0 being 'ok'. OSBYTE $FFF4 Read/write information passed in A, X, Y. On return, b0-b7 of Y is copied to b8-b16 of X so that X can be used as a 16-bit value. OSWORD $FFF1 Read/write information passed in control block at X, function in A. Note: address of text buffer in X+0,X+1 in OSWORD 0 is native 68xx big-endian address. All other calls use control block contents as specified for the BBC host. OSWORD 0 returns values in Y and Carry. Acorn MOS character entry points -------------------------------- OSWRCH $FFEE Writes raw character to output stream. OSWRCR $FFEC Writes to output stream. OSNEWL $FFE7 Writes newline sequence to output stream. OSASCI $FFE3 Writes ASCII character in A to output stream. OSRDCH $FFE0 Waits for character from input, returns in A and Carry. Acorn MOS file entry points --------------------------- OSFILE $FFDD OSFILE with A=function, X=>control block. Returns A=result, control block updated, X preserved. OSARGS $FFDA Calls OSARGS with A=function, Y=channel, X=>control block. Returns A=result, control block updated, X and Y preserved. OSBGET $FFD7 Reads a byte from the channel in Y. Returns character in A and EOF in Carry, Y preserved. OSBPUT $FFD4 Writes byte in A to channel in Y. Returns A and Y preserved. OSGBPB $FFD1 Calls OSGBPB with A=function, X=>control block. Returns A=result, Cy=EOF, control block updated, X preserved. OSFIND $FFCE Calls OSFIND with A=0 and Y=channel or A<>0 and X=>filename. Returns A=0 or channel, X and Y preserved. Acorn 6809 MOS entry points --------------------------- OSINIT $FFBF Initialise error handler and other environment settings. On entry, A=$00 to become the current program A=$FF to read the current settings Returns X=>BRKV, Y=>ESCFLG, DP=>Direct Page, A,B=various CC set from contents of A on return A.b7=1: little-endian filing system calls (CC=MI) A.b7=0: big-endian filing system calls (CC=PL) This must be called by application code as part of its startup, before writing anything to memory. Before making this call, code does not known where BRKV and ESCFLG are, as they can be anywhere in memory. OSERROR $FFBC Generate an inline error. Can be used when not possible to generate an error with SWI. Entered with the address of the error block on the stack. OSQUIT $FFB9 Quit current process, A=return value. Returns to any calling process. By default, returns to the Supervisor. PRTEXT $FFB3 Print inline text terminated with $00. Execution continues after the $00 terminator. On return, A=$00. USERINT $FFB0 Pass on FIRQs if not Tube FIRQ. PR2HEX $FFAD Print X as 16-bit hex. On return A/B is corrupted. PR1HEX $FFAA Print A as 8-bit hex. On return A is corrupted. SCANHEX $FFA1 Scan line at X for hex number. Returns Y=number, X=>terminating character, D corrupted. PRSTRING $FF9B Print text at X terminated with $00. Returns A=$00, X=>byte after terminating $00 so multiple strings can be called by multiple calls to PRSTRING. Program Environment =================== Code can be executed by selecting a ROM, running a file from disk, or entering it with *GO. When code is entered it is checked to see if it has a 68xx code header with ROM type 3 at the code entry point. Code is entered with the registers holding the following values: A: 0=raw code (code without a header), 1=code has ROM header X=>command line parameters, terminated with a control character CC=entered at RESET, CS=entered from OSCLI/OSBYTE B,Y,U: reserved Code is initially run as transient code, any errors will enter the caller's error handler, a RTS will return to the caller, and Soft Reset will re-enter the current application program. If the code wants to become the current application program, it must call OSINIT and claim the Error and Escape handlers. After this, a Soft Reset will re-enter the code. Memory available is from MEMBOT read with OSBYTE $83 up to MEMTOP read with OSBYTE $84. On the 6800 and 6809 MEMBOT is usually $0000 as most code expects to have memory from $0000 upwards. If the code entered is in high memory ($8000+) then MEMTOP is put just below the entered code until it returns. Executing code has a small stack of at least 64 bytes, enough for 32 subroutine calls or about six recursive OSCLI calls. An application would normally set up a new user stack at MEMTOP. If the stack is not changed, the code can return with RTS or OSQUIT. If the stack is changed the code must return by jumping to OSQUIT. Executing code is allowed to trash all registers, they are restored on OSQUIT or RTS. The executed program can return a return value in A, with A=$00 being 'ok', by returning or jumping to OSQUIT. Program startup --------------- Code that wants to become the current application needs to start with code similar to the following: STARTUP: CLR A TFR A,DP ; Set default DirectPage JSR OSINIT ; Claim Error and Escape handles ; We can now claim Escapes and Errors, access Direct Page and ask ; for memory limits. At the moment the only memory we can access ; is Direct Page, so ESCADDR, MEMBOT and MEMTOP must be in Direct ; Page. ; STY ESCADDR ; Note where EscapeFlag is LEAY ERRORHANDLER,PCR ; Point to our error handler STY ,X ; Claim Error vector ; LDA #&83 JSR OSBYTE ; Find bottom of memory STX MEMBOT INC A JSR OSBYTE ; Find top of memory STX MEMTOP TFR X,S ; Put stack at top of memory ; We can now access Direct Page and user memory from MEMBOT to ; MEMTOP. Escape State ------------ A program can read the current Escape state by reading the ESCFLG memory location with an instruction such as LDA [ESCADDR]. Bit 7 will be set if an Escape state is pending, which must be acknowledged with OSBYTE $7E. The location of the Escape Flag is found by calling OSINIT, being returned in the Y register. Once the address is stored, it can be tested with code similar to: CHKESCAPE: LDA [ESCFLAG] BPL NOESCAPE BMI ESCAPE A slower method to test the Escape flag is the following. While slower, it has the advantage of not needing to call OSINIT and storing the Escape Flag address. CHKESCAPE: LDA #&7E JSR OSBYTE ; Acknowledge any pending Escape CMPX #0 BEQ NOESCAPE ; No Escape was pending BNE ESCAPE ; An Escape was pending If not tested by calling OSBYTE $7E the Escape state must be acknowledged with OSBYTE $7E. This can be done in the Escape polling code, or in the Error handler if the Escape polling code generates an "Escape" error. Errors ------ Errors are generated with the SWI opcode: SWI FCB errornumber FCC "error message" FCB 0 If code is unable to generate an error with a SWI, it can generate an error by jumping to or calling OSERROR. It is called with: JSR OSERROR FCB errnum,"errorstring",0 or with: LDR #error ; Point to error block PSHS R ; Push address on stack JMP OSERROR Errors set up an internal location pointing to the error block after the SWI opcode, enable all interupts, and then jump via BRKV with X pointing to the error block. BRKV is a location in the Client's workspace RAM. Its address is returned in the X register after calling OSINIT. After calling OSINIT code can claim BRKV to set up an error handler with code similar to: JSR OSINIT STY ESCFLAG LEAY ERRHANDLER,PCR or LDD #ERRHANDLER STY ,X STD ,X The error handler is entered with X pointing to the error block and DP pointing to the code's Direct Page. The stack pointer will point to where-ever the error occured, so the error handler must set up a new stack. The error handler should start with code similar to: ERRHANDLER: LDS STACK ; Set up a stack STX ERRADDR ; Store pointer to error block Code header ----------- Executed code can have a header to identify it as 68xx code: .CodeStart CodeStart+0 NOP: BRA CodeEntry ; $01 $20 xxx for 6800 code ; or BRA CodeEntry:FCB 0 ; $20 xxx $00 for 6309/6809/6811 relative code ; or JMP >CodeEntry ; $7E xxx xxx for 6309/6809/6811 absolute code ; or NOP: BRA CodeEntry ; $A7 $20 xxx for 6812 relative code ; or JMP >CodeEntry ; $06 nnn nnn for 6812 absolute code CodeStart+3 FCB 0,0,0 CodeStart+6 FCB $63 ; Code+Address+68xx CodeStart+7 FCB Copyright-CodeStart ; Offset to (C) CodeStart+8 FCB 0 ; Version CodeStart+9 FCC "6809 BASIC" ; Code title FCB 0 FCC "0.01 (10 Feb 2008)" ; Version string CodeStart+Offset .Copyright FCB 0 FCC "(C)J.G.Harston" ; Copyright message FCB 0 FCB CodeStart % 256 ; If CodeStart+6 has bit 5 set, FCB CodeStart / 256 ; 32-bit transfer address. FCB 0 ; Must be little-endian. This FCB 0 ; is ignored by the 68xx Client. ; .CodeEntry As the 68xx makes it easy to write position-independent code the instruction at CodeStart+0 should be a relative BRA if the code is position independent, or an absolute JMP if the code is not position independent. As 6800, 6809, 6811, 6812 and 68000 code all use ROM type 3 the instruction at the code start is used to distinhuish between them. The code transfer address is only used by the host computer if the code is in a sideways ROM/RAM or is loaded from a host that does not have load/exec addresses, such DOS/Windows. It is the equivalent of the load/exec address of a file run from disk. *Commands ========= The client may implement some local *commands executed by calling OSCLI. *HELP ----- *HELP displays the Client title and version and is then passed to the host. *GO () (;parameters) -------------------------- *GO will call some code. It is called in the same way as code run from disk or ROM. *GO with no address will call the current program. The command line pointer is set to point to any text after any semicolon. Memory Map ========== Typical values: 0000 +-----------------------+ MEMBOT +-----------------------+ 0000 0000 0000 0000 1000 0E00 | | CoPro SWTPC Flex-09 OS/9 68HC12 BBC09 | | | | | | | | | | | | CoPro SWTPC Flex-09 OS/9 68HC12 BBC09 MEMTOP +-----------------------+ F800 DF00 C000 C000 8000 8000 | | F800 +-----------------------+ | 68xx BIOS Entry Block | | | FF80 +-----------------------+ | MOS Entry Block | +-----------------------+ The Tube Client can be built to run from ROM or RAM. Code must call OSINIT at $FFBF to find out where the Tube Client's workspace is. Vectors ======= Vectors are at an offset from BRKV found by calling OSINIT. If BRKV<$FF00: If BRKV>=$FF00 Vectors in vector page Vectors in JMP address fields BRKV+$00 BRKV BRKV+$10 FILEV BRKV-$00 BRKV BRKV-$1C FILEV BRKV+$06 CLIV BRKV+$12 ARGSV BRKV-$02 CLIV BRKV-$1F ARGSV BRKV+$08 BYTEV BRKV+$14 BGETV BRKV-$05 BYTEV BRKV-$22 BGETV BRKV+$0A WORDV BRKV+$16 BPUTV BRKV-$08 WORDV BRKV-$25 BPUTV BRKV+$0C WRCHV BRKV+$18 GBPBV BRKV-$0B WRCHV BRKV-$28 GBPBV BRKV+$0E RDCHV BRKV+$1A FINDV BRKV-$19 RDCHV BRKV-$2B FINDV Filing System Addresses ======================= Filing system calls OSFILE, OSARGS and OSGBPB use native big-endian 68xx addresses. Early versions of the Tube Client used little-endian addresses to match the Tube host. OSINIT returns the A register and MI/PL differently to indicate what addresses the client uses. If code needs to check for this it can do it with code similar to: JSR OSINIT BMI error_CantRunOnOldClient On return from OSINIT, A.b7=1 with clients that use little-endian addresses, A.b7=0 with clients that use big-endian addresses. Future clients may return additional information in A and B. 6809 Disk Operating Systems =========================== Flex-09 and OS/9 is able to run on the 6809 Tube client with an appropriate BIOS to convert Flex-09 or OS/9 disk calls to the appropriate Tube MOS calls. DISKACC and DISKRST are reserved to support a disk BIOS. TRAP instruction ================ The 6812 Client implements TRAP $nn to call MOS functions. TRAP $FF is OSQUIT, TRAP $FE..$F4 is OSCLI..OSFIND. On exit, VC=no error, VS=error.