PDP-11 CoProcessor Technical Reference ====================================== J.G.Harston, 70 Camm Street, Walkley, Sheffield, S6 3TR http://mdfs.net/Docs/Books/PDP11CoPro/Technical Date: 13-Jan-2008 Host Interface ============== The EMT opcode is used to communicate with the host. On return from an EMT call, if V is set, then R0 points to an error block, otherwise V is clear. All registers are preserved, unless otherwise stated. Flags are corrupted, unless a stated value is returned. EMT 0 - QUIT Calls the current Exit handler. All registers are passed to the exit handler, but only R0 is valid. R0 should contain 0 for a normal exit and should hold a non-zero exit code for an abnormal exit. If no exit handler has been installed, then this returns to the Supervisor prompt. EMT 1 - CLI Passes the command line pointed to by R0 to the host. If the command results in a file being run from disk that can be recognised as a PDP-11 file, it is loaded directly into the PDP-11 memory and entered. If the executed file or a selected ROM has a valid PDP-11 ROM header, then it is made the current program and is entered. The executed program can return a return value in R0, with R0=0 being 'ok'. EMT 2 - BYTE Does OSBYTE R0,R1,R2; returning results in R0, R1, R2 and Carry. The memory value request OSBYTEs &82, &83 and &84 return values appropriate to the PDP-11 environment. &82 (High order address) returns &0000, &83 returns the lowest usable address, &84 returns the address after the last usable address. Calls that return an address (such as OSBYTE &83 and &84) return b0-b15 in R1 and b8-b23 in R2, so a value of &100000 (1 megabyte) would return R1=&0000 and R2=&1000. EMT 3 - WORD Does OSWORD R0 with R1 pointing to the parameter block. OSWORD 0 (read line) returns values in R2 and Carry. EMT 4 - WRCH Outputs character in R0. EMT 5 - NEWL Outputs LF,CR and returns R0=13. EMT 6 - RDCH Read character to R0 and Carry. EMT 7 - FILE Calls OSFILE with R0=function, R1=>control block. EMT 8 - ARGS Calls OSARGS with R0=function, R1=channel, R2=>control block. EMT 9 - BGET Reads a byte from the channel in R1, returns character in R0 and Carry. If R1=0, then reads from OSRDCH input stream. EMT 10 - BPUT Writes byte in R0 to channel in R1. If R1=0, then writes to OSWRCH output stream. EMT 11 - GBPB Calls OSGBPB with R0=function, R1=control block. If the channel at (R1+0) is zero, then reads from OSRDCH or writes to OSWRCH as appropriate. EMT 12 - FIND Calls OSFIND with R0=0 and R1=channel or R0<>0 and R1=>filename. EMT 13 - SYST Various system control functions. R0=0 - loads and enters BBC BASIC R0=1 - reinitialises vectors, handlers and EMT dispatch table. R0=2 - reinitialises handlers and EMT dispatch table only. EMT 14 - CTRL Reads and writes handlers and EMT dispatch table entries. R0>=0 - reads or writes EMT dispatch address: R0=EMT number R1=address of EMT routine, or zero to read On exit: R0 preserved R1 previous EMT dispatch address R0<0 - reads or writes environment handler: R0=Environment handler number R1=address of environment hander or zero to read R2=address of environment data block or zero to read On exit: R0 preserved R1=previous environment handler address R2=previous environment data address Environment handler numbers are: R0 R1 R2 &FFFF Exit handler ignored &FFFE Escape handler Escape flag (one byte) &FFFD Error handler Error buffer (256 bytes) &FFFC Event handler ignored &FFFB Unknown IRQ handler ignored &FFFA ignored EMT dispatch table (512 bytes) The Exit handler is entered with R0=return value. The Escape handler is entered with R0=new escape state in b6, must preserve all registers other than R0 and return with RTS PC. The Error handler is entered with R0=>error block. Note that this may not be the address of the error buffer, the error buffer is used for dynamically generated error messages. The Event handler is entered with R0,R1,R2 holding the event parameters, must preserve all registers, and return with RTS PC. The Unknown IRQ handler must preserve all registers, and return with RTI. EMT 15 - ERROR Error block follows EMT opcode in the following manner: EMT 15 EQUB errornumber EQUS "error message" EQUB 0 ALIGN EMT 15 enters the current error handler with R0 pointing to the error block after the EMT 15. Executing Code ============== 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 ROM header. If it has, then it is set as the current program and is re-entered on soft Break. A PDP-11 ROM header has ROM type 7, and if there is a Tube transfer address, it is followed by an offset from the Tube transfer address to the code entry address. The lowest possible address to load code without a Unix header is &100. The code is entered with R0=1, unless there is also a Unix header at the entry point. The following code fragment shows this. ; > ROMHeader ORG &8000 .ROMStart EQUB 0 EQUW 0 EQUB &4C ; 6502 JMP for service entry EQUW ServiceCode EQUB &E7 ; Service+Language+Tube+PDP11 EQUB Copyright-ROMStart EQUB 0 ; Version EQUS "PDP-11 BASIC" ; ROM title EQUB 0 EQUS "0.01 (10 Feb 2008)" ; Version string .Copyright EQUB 0 EQUS "(C) J.G.Harston" ; Copyright message EQUB 0 EQUD &8000 ; Tube transfer address EQUD TubeEntry-ROMStart ; Offset to Tube execution address ; ALIGN .TubeEntry Executed code is also checked for a Unix file header. If a valid Unix header is found, then the code is moved and/or remapped so that the code from byte 16 onwards is located at logical address 0 onwards, and any uninitialised data segment is zeroed immediately after the initialised data. A stack frame is built at the top of memory and pointed to with SP, and the code is entered at location zero. The stack does not contain a return address, the code must exit with a call to exit() with TRAP 1 or QUIT with EMT 0. ; > UnixHeader EQUW &0107 ; Magic number &o000407, also branch to CodeStart EQUW CodeEnd-CodeStart ; size of text (code) EQUW DataEnd-CodeEnd ; size of initialised data EQUW ZeroEnd-DataEnd ; size of uninitialised data EQUW &0000 ; size of symbol data EQUW CodeEntry-CodeStart ; entry point EQUW &0000 ; not used EQUW &0001 ; no relocation info ; .CodeStart ; Program code goes here .CodeEntry ; Program code goes here .CodeEnd ; Initialised data goes here .DataEnd ; Uninitialised data goes here, does not need to exist ; in the file, will be zeroed by the program loader .ZeroEnd If there is no header of either kind, it is entered at it's start address - the execution address for a loaded file, or the first byte for code copied from a ROM or code entered with *GO. Program Environment =================== Code is entered with R5=&0BBC to indicate it is running in a BBC environment and the BBC EMT calls are available, R6=stack (and any stack frame) and the top of memory and R7=entry point. Code without a Unix header has a return address on the stack that can be returned to with RTS PC. R1 on entry points to any command line parameters. Code with a Unix header must be exited with exit() (TRAP 1) if Unix system calls are available, or with OS_QUIT (EMT 0). The command line is passed as a stack frame pointed to by SP. R0 to R4 are 0 on entry. If you set up any environment handlers, they must be restored on exit. If you set up an exit handler, it must restore the environment handlers, and then call the restored exit handler. Escape State ============ A program can read the current Escape state in three ways: - Read the Escape flag address, and poll that address to check bit 7. MOV #&FFFE,R0 ; Read/Write Escape handler MOV #0,R1 ; Read Escape handler address MOV #0,R2 ; Read Escape flag address EMT 14 TSTB (R2) ; Check Escape flag BMI EscapeState - Set an Escape flag address within the program's workspace, and poll that address to check bit 7. ; At program statup MOV #&FFFE,R0 ; Read/Write Escape handler MOV #0,R1 ; Read Escape handler address ADR MyEscFlag,R2 ; Set Escape flag address EMT 14 MOV R2,OldEscFlag ; Save old address ; To check Escape flag TSTB MyEscFlag ; Check Escape flag BMI EscapeState ; On program exit MOV #&FFFE,R0 ; Read/Write Escape handler MOV #0,R1 ; Read Escape handler address MOV OldEscFlag,R2 ; Restore old Escape flag address EMT 14 - Set an Escape handler process it yourself, such as by setting your own flag. ; At program statup MOV #&FFFE,R0 ; Read/Write Escape handler ADR MyEscHandler,R1 ; Set Escape handler address ADR MyEscFlag,R2 ; Set Escape flag address EMT 14 MOV R1,OldEscHandler ; Save old address MOV R2,OldEscFlag ; Save old address ; My Escape handler .MyEscHandler ADD R0,R0 MOV R0,MyEscFlag RTS PC ; To check Escape flag TSTB MyEscFlag ; Check Escape flag BMI EscapeState ; On program exit MOV #&FFFE,R0 ; Read/Write Escape handler MOV oldEschandler,R1 ; Read Escape handler address MOV OldEscFlag,R2 ; Restore old Escape flag address EMT 14 If you find that Escape is set, it must be acknowledged with OSBYTE &7E. User Memory vs Kernel Memory ============================