000000 ; PDP11 Serial Tube Client Code 000000 ; ============================= 000000 ; Copyright (C)1989,2008,2014 J.G.Harston 000000 ; 000000 ; v0.10 11-Mar-1989 JGH: Initial version, untested proof of concept. 000000 ; v0.11 09-Sep-2005 JGH: Altered some labels to assemble from BASIC 000000 ; v0.12 12-Jul-2008 JGH: Interupt handler data transfers. 000000 ; v0.13 15-Jul-2008 JGH: Added EMT handler. 000000 ; v0.14 17-Jul-2008 JGH: Checks executed code for ROM and Unix headers. 000000 ; v0.15 06-Dec-2008 JGH: Rearranged MOS interface code around, changed some labels. 000000 ; v0.16 25-Dec-2014 JGH: Optimised some common calls to SEND_BYTE. 000000 ; Started adding Serial Tube I/O routines 000000 ; v0.20 22-Aug-2015 JGH: Brought up to date with Tube client 000000 VERSION: EQU &0022 000000 ; v0.22 25-Oct-2015 JGH: Brought up to date with Tube client 000000 ; 000000 ; 000000 SETLPTR: EQU 1 ; Set LPTR to command parameters 000000 JOINERR: EQU 1 ; Combine EXECUTE error messages 000000 NOCHNZERO: EQU 1 ; Remove bput/bget#0 -> wrch/rdch, saves about 100 bytes 000000 ; 000000 ; 000000 ; This code may be freely reused. 000000 ; 000000 ; Acknowledgements to: 000000 ; David Banks: Plenty of testing of the Tube client on the Matchbox CoPro "real" hardware. 000000 ; 000000 ; Notes: 000000 ; This code assumes a single memory space and assumes that code can access I/O devices, low memory 000000 ; vectors and user memory with ordinary MOV instructions. This will work with no seperate 000000 ; Kernal/User space, or with code never running in User mode. Running code can chose to switch to 000000 ; User mode. 000000 000000 ; Memory map: 000000 ; +-----------------------+ 0000 000000 ; | Hardware vectors, etc | 000000 ; MEMBOT +-----------------------+ 0100 000000 ; | | 000000 ; | | 000000 ; MEMTOP | ^^^User Stack^^^ | 000000 ; WORKSP +-----------------------+ F500 000000 ; | ERRBLK--> <--CLISTK | 000000 ; +-----------------------+ F530 000000 ; | CLIBUF--> <--ERRSTK | 000000 ; HANDLERS +-----------------------+ 000000 ; | EXITV EXITADDR | F5D8 000000 ; | ESCV ESCADDR | F5DC 000000 ; | ERRV ERRADDR | F5E0 000000 ; | EVENTV EVENTADDR | F5E4 000000 ; | USERIRQV USERIRQADDR | F5E8 000000 ; | EMTV EMTADDR | F5EC 000000 ; | SPARE LPTR | F5F0 000000 ; | MEMBOT MEMTOP | F5F4 000000 ; ADDR | Transfer address | F5F8 000000 ; PROG | Current program | F5FC 000000 ; PROG+2 | unused byte | F5FE 000000 ; ESCFLG | Escape flag | F5FF 000000 ; EMTTABLE +-----------------------+ 000000 ; | EMT 0 code address | F600 000000 ; | EMT 1 code address | F602 000000 ; | EMT 2 code address | F604 000000 ; | EMT 3 code address | F606 000000 ; | EMT 4 code address | F608 000000 ; | ... | 000000 ; | EMT 255 code address | F7FE 000000 ; START +-----------------------+ F800 000000 ; | Tube client code | 000000 ; +-----------------------+ FFF0 000000 ; | Tube I/O registers | 000000 ; +-----------------------+ FFFF 000000 000000 ; Some naming conventions 000000 ; xxxxVEC - hardware vectors, eg EMTVEC, NMIVEC, etc 000000 ; xxxxV - software vectors, eg ESCV, ERRV, etc. 000000 ; xxxx or xxxHAND - handler for xxxx, eg ESCHAND, ERRHAND, etc. 000000 ; OSxxx or _xxx - routines handled by xxx, eg OSFILE handled by _FILE 000000 000000 000000 ; PDP-11 hardware addresses 000000 ; ========================= 000000 STACKVEC: EQU &04 ; Stack too low 000000 EMTVEC: EQU &18 ; Vector called by EMT call 000000 TRAPVEC: EQU &1C ; Vector called by TRAP call DMB 000000 000000 000000 ; Tube client system configuration tweekables 000000 ; =========================================== 000000 START: EQU &F800 ; Start of code 000000 TUBEIO: EQU &FFF0 ; Base of Tube I/O registers 000000 NMIVEC: EQU &80 ; Vector called by Tube NMIs with priority 7 000000 IRQVEC: EQU &84 ; Vector called by Tube IRQs with priority 6 000000 000000 EMTMAX: EQU 256 ; Number of EMTs 000000 EMTTABLE: EQU START-EMTMAX*2 ; EMT dispatch table 000000 WORKSP: EQU EMTTABLE-256 ; 256 bytes for buffers, etc 000000 RAMSTART: EQU &0100 ; Lowest available user memory address 000000 RAMEND: EQU WORKSP ; Highest available user memory address 000000 000000 000000 ; Internal buffers, etc 000000 ; ===================== 000000 ERRBLK: EQU WORKSP ; Buffer to store host error block 000000 CLIBUF: EQU WORKSP+&30 ; Space to enter command line from CLI prompt 000000 CLISTK: EQU CLIBUF ; Internal stack for CLI commands 000000 ; as main memory may be overwritten 000000 CLIEND: EQU HANDLERS 000000 ERRSTK: EQU CLIEND ; Internal stack for host errors 000000 000000 WORKSPMAX: EQU 16 ; 16 bytes of general workspace 000000 HANDLEMAX: EQU 6 ; 6 environment handlers 000000 HANDLERS: EQU WORKSP+256-WORKSPMAX-4*HANDLEMAX ; Address of environment handlers 000000 EXITV: EQU HANDLERS+&00 ; Address of exit handler 000000 EXITADDR: EQU HANDLERS+&02 ; unused - holds client version 000000 ESCV: EQU HANDLERS+&04 ; Address of escape handler 000000 ESCADDR: EQU HANDLERS+&06 ; Address of escape flag 000000 ERRV: EQU HANDLERS+&08 ; Address of error handler 000000 ERRADDR: EQU HANDLERS+&0A ; Address of error buffer 000000 EVENTV: EQU HANDLERS+&0C ; Address of event handler 000000 EVENTADDR: EQU HANDLERS+&0E ; unused 000000 USERIRQV: EQU HANDLERS+&10 ; Address of unknown IRQ handler 000000 USERIRQADDR: EQU HANDLERS+&12 ; unused 000000 EMTV: EQU HANDLERS+&14 ; Old SP within EMT handler 000000 EMTADDR: EQU HANDLERS+&16 ; Address of EMT dispatch table 000000 000000 SPARE: EQU WORKSP+&F0 ; unused 000000 LPTR: EQU WORKSP+&F2 ; Point to command line 000000 MEMBOT: EQU WORKSP+&F4 ; Lowest user memory address 000000 MEMTOP: EQU WORKSP+&F6 ; Highest user memory address 000000 ADDR: EQU WORKSP+&F8 ; Transfer address 000000 PROG: EQU WORKSP+&FC ; Current program 000000 PROG2: EQU WORKSP+&FE ; unused 000000 ESCFLG: EQU WORKSP+&FF ; Escape flag 000000 000000 000000 ; Tube I/O devices 000000 ; ================ 000000 TUBE1S: EQU TUBEIO+0 ; Tube Status 1 000000 TUBE1: EQU TUBEIO+2 ; Tube Data 1 - VDU 000000 TUBE2S: EQU TUBEIO+4 ; Tube Status 2 000000 TUBE2: EQU TUBEIO+6 ; Tube Data 2 - Command 000000 TUBE3S: EQU TUBEIO+8 ; Tube Status 3 000000 TUBE3: EQU TUBEIO+10 ; Tube Data 3 - Data 000000 TUBE4S: EQU TUBEIO+12 ; Tube Status 4 000000 TUBE4: EQU TUBEIO+14 ; Tube Data 4 - Interrupt 000000 000000 000000 ; Code Entry 000000 ; ========== 000000 ; Set up vectors, hardware, memory, etc. 000000 ; Must be entered in Kernel mode. 174000 ORG START 174000 000167 000040 JMP STARTUP ; Jump to start up Tube code 174004 174004 174004 ; STARTUP 174004 ; ======= 174004 ; Tube data: via R1: string &00 -- via R2: &7F or &80 174004 ; 174004 BANNER: 174004 015 EQUB 13 174005 120 104 120 055 061 061 040 123 105 122 111 101 114 040 124 125 102 105 040 066 064 113 040 EQUS "PDP-11 SERIAL TUBE 64K " 174034 060 EQUB ((VERSION >> 8) AND 15)+48 174035 056 EQUS "." 174036 062 EQUB ((VERSION >> 4) AND 15)+48 174037 062 EQUB (VERSION AND 15)+48 174040 #ifdef BUILD 174040 EQUB 96+BUILD 174040 #else 174040 040 EQUS " " ; Fixed-length string so can be overwritten 174041 #endif 174041 015 EQUB 13 174042 015 EQUB 13 174043 000 EQUB 0 174044 ALIGN 174044 STARTUP: 174044 012706 172460 MOV #CLISTK,SP ; Use internal stack 174050 004767 002470 JSR PC,INIT_ENV ; Set up default handlers, preserving PROG 174054 013737 172774 172770 MOV @#PROG,@#ADDR ; Set current program as default entry address 174062 012701 174004 MOV #BANNER,R1 ; Point to startup banner 174066 004767 000176 JSR PC,SEND_TXT ; Print it via Tube WRCH protocol 174072 ;CLR R0 ; SEND_TXT returns R0=0 174072 004767 002134 JSR PC,_WRCH ; Send terminating zero byte 174076 000241 CLC ; Clear Carry Flag to indicate Reset 174100 004767 000352 JSR PC,CLI_WAIT ; Wait for and check result byte 174104 ; Fall through to CLICOM if nothing executed 174104 174104 ; Supervisor Command line prompt 174104 ; ============================== 174104 ; Allow user to enter *commands. 174104 ; We deliberately call _WORD and _CLI so if EMTs vectors are trashed we can still access MOS and so 174104 ; that errors go via ERRV instead of us having to check returned V flag. 174104 ; We will normally be running in Kernal mode so we can see the system vectors and high memory. 174104 ; 174104 CLICOM: 174104 EXITHAND: 174104 013706 172766 MOV @#MEMTOP,SP ; Put stack at top of user memory 174110 ; IRQ/NMI will already be set up, as will default environment 174110 ; If we've come from here from a failed EXECUTE, will have been given default environment 174110 CLILOOP: 174110 012701 174140 MOV #PROMPT,R1 174114 004767 000150 JSR PC,SEND_TXT ; Display prompt 174120 ;CLR R0 ; SEND_TXT returns R0=0 174120 ;MOV #COM_BLK,R1 ; Point to control block, SENT_TXT returns R1=COM_BLK 174120 004767 001124 JSR PC,_WORD ; Read a line of text 174124 103414 BCS COM_ESC ; Escape pressed 174126 013700 174150 MOV @#COM_BLK,R0 ; Get address of input buffer DMB 174132 004767 000140 JSR PC,_CLI ; Execute command 174136 000764 BR CLILOOP ; Loop back for another line 174140 PROMPT: 174140 120 104 120 061 061 076 052 EQUS "PDP11>*" ; Command prompt 174147 000 EQUB 0 174150 ALIGN 174150 ; 174150 COM_BLK: 174150 172460 EQUW CLIBUF ; Input buffer 174152 250 EQUB CLIEND-CLIBUF ; Buffer length 174153 040 EQUB 32 ; Lowest acceptable char 174154 377 EQUB 255 ; Highest acceptable char 174155 000 ALIGN 174156 ; 174156 COM_ESC: 174156 012700 000176 MOV #126,R0 174162 004767 000656 JSR PC,_BYTE ; Acknowledge Escape 174166 104017 EMT 15 174170 021 105 163 143 141 160 145 000 EQUB 17,"Escape",0 174200 ALIGN 174200 174200 ; Default error handler 174200 ; --------------------- 174200 ; On entry, R0=>error block 174200 ERRHAND: 174200 013706 172766 MOV @#MEMTOP,SP ; Reset stack to top of user memory 174204 010001 MOV R0,R1 ; Point R1=>error block 174206 005201 INC R1 ; Step past error number 174210 004767 002002 JSR PC,_NEWL ; Print a newline 174214 004767 000050 JSR PC,SEND_TXT ; Print error message 174220 004767 001772 JSR PC,_NEWL ; Print another newline 174224 000727 BR CLICOM 174226 174226 ; Default escape handler 174226 ; ---------------------- 174226 ESCHAND: 174226 060000 ADD R0,R0 ; Move b6 into b7 174230 110077 176502 MOVB R0,@ESCADDR ; Store Escape flag 174234 000207 RTS PC 174236 174236 174236 ; Fetch word from unaligned R1 to R1 174236 ; ================================== 174236 ; Unaligned version of MOV (R1),R1, corrupts R0 174236 ; FETCHWORD2 - R1=>word+2 174236 ; FETCHWORD - R1=>word 174236 ; 174236 FETCHWORD2: 174236 162701 000002 SUB #2,R1 ; Step back to point to word 174242 FETCHWORD: 174242 112100 MOVB (R1)+,R0 ; Fetch low byte 174244 042700 177400 BIC #&FF00,R0 ; Ensure 8-bit value 174250 111101 MOVB (R1),R1 ; Fetch high byte 174252 042701 177400 BIC #&FF00,R1 ; Ensure 8-bit word 174256 000301 SWAB R1 ; Swap high byte to top of register 174260 050001 BIS R0,R1 ; Merge together 174262 000207 RTS PC 174264 174264 174264 ; Print zero-terminated text string at R1 174264 ; ======================================= 174264 SEND_TXTLP: 174264 004767 001720 JSR PC,_ASCII ; Send to WRCH via Tube R1 174270 SEND_TXT: 174270 112100 MOVB (R1)+,R0 ; Get byte from R1, increment R1 174272 001374 BNE SEND_TXTLP ; Loop until &00 byte 174274 000207 RTS PC 174276 174276 174276 ; ************* 174276 ; MOS INTERFACE 174276 ; ************* 174276 174276 ; OSCLI - Send command line to host 174276 ; ================================= 174276 ; On entry: R0=>command string 174276 ; On exit: R0=return value 174276 ; 174276 ; Tube data: &02 string &0D -- &7F or &80 174276 ; 174276 _CLI: 174276 010146 MOV R1,-(SP) ; Save registers 174300 010246 MOV R2,-(SP) 174302 010346 MOV R3,-(SP) 174304 010446 MOV R4,-(SP) 174306 010546 MOV R5,-(SP) 174310 174310 ; As a *command may result in data transfer, that data may end up overwriting stack in user memory, 174310 ; so use a temporary stack to do OSCLI. If OSCLI ends up jumping to a new process, a new stack will 174310 ; be set up by that new process. If we are already using the internal stack we continue using it 174310 ; so that transient OSCLIs can call more OSCLIs. 174310 174310 010605 MOV SP,R5 ; Copy stack pointer so we can stack it 174312 020527 172400 CMP R5,#WORKSP ; Check where the stack is 174316 103002 BCC CLI_SYSSTK ; We're already using internal stack 174320 012706 172460 MOV #CLISTK,SP ; Use internal stack 174324 CLI_SYSSTK: 174324 010546 MOV R5,-(SP) ; Save caller's stack pointer 174326 013746 172766 MOV @#MEMTOP,-(SP) ; Save current top of memory 174332 013746 172774 MOV @#PROG,-(SP) ; Save current program as top item on stack 174336 004767 000030 JSR PC,CLI_GO ; Do the OSCLI call 174342 012637 172774 MOV (SP)+,@#PROG ; Restore current program 174346 012637 172766 MOV (SP)+,@#MEMTOP ; Restore top of memory 174352 011606 MOV (SP),SP ; Restore caller's stack pointer 174354 012605 MOV (SP)+,R5 ; Restore registers 174356 012604 MOV (SP)+,R4 174360 012603 MOV (SP)+,R3 174362 012602 MOV (SP)+,R2 174364 012601 MOV (SP)+,R1 174366 005000 CLR R0 ; Return R0=0 from OSCLI 174370 CLI_DONE: 174370 000207 RTS PC 174372 174372 CLI_GO: 174372 #ifndef SETLPTR 174372 MOV R0,R1 ; R1=pointer to command string 174372 #else 174372 CLI_SKIP1: 174372 112001 MOVB (R0)+,R1 ; Skip leading spaces and stars 174374 120127 000040 CMPB R1,#ASC" " 174400 001774 BEQ CLI_SKIP1 174402 120127 000052 CMPB R1,#ASC"*" 174406 001771 BEQ CLI_SKIP1 174410 005300 DEC R0 174412 010001 MOV R0,R1 ; R1=pointer to command string 174414 CLI_SKIP2: 174414 122027 000041 CMPB (R0)+,#ASC"!" ; Skip until space or 174420 103375 BCC CLI_SKIP2 174422 005300 DEC R0 174424 CLI_SKIP3: 174424 122027 000040 CMPB (R0)+,#ASC" " ; Skip spaces 174430 001775 BEQ CLI_SKIP3 174432 005300 DEC R0 174434 010067 176322 MOV R0,LPTR ; LPTR=>parameters or 174440 #endif 174440 012700 000002 MOV #2,R0 174444 004767 002456 JSR PC,SEND_CMD ; Send command &02 - OSCLI 174450 004767 002334 JSR PC,SEND_STR ; Send command string at R1 174454 CLI_WAIT1: 174454 000261 SEC ; Set Carry to indicate OSCLI 174456 CLI_WAIT: 174456 004767 002474 JSR PC,WAIT_BYTE ; Wait for result via Tube R2 (preserves Cy) 174462 ; WAIT_BYTE returns flags set from R0 174462 100342 BPL CLI_DONE ; No code to be executed 174464 ; Fall through into EXECUTE 174464 174464 174464 ; EXECUTE - Enter code at ADDR 174464 ; ============================ 174464 ; Checks for possible code header, makes code current PROGRAM. 174464 ; On entry, ADDRESS=code entry address 174464 ; CC=entering from RESET 174464 ; CS=entering from OSCLI/OSBYTE 174464 ; 174464 ; Caller should preserve registers before calling here. 174464 ; 174464 EXECUTE: 174464 013701 172770 MOV @#ADDR,R1 ; Get transfer address 174470 012705 000000 MOV #0,R5 ; R5=0 - prepare for raw code 174474 006105 ROL R5 ; Save RESET/OSCLI flag in Carry in R5 174476 010146 MOV R1,-(SP) ; Save entry address 174500 116102 000007 MOVB 7(R1),R2 ; Get copyright offset 174504 042702 177400 BIC #&FF00,R2 ; Ensure 8-bit value 174510 060201 ADD R2,R1 ; R1=>copyright string 174512 105721 TSTB (R1)+ ; Check for copyright string 174514 001046 BNE EXEC_NOTROM 174516 122127 000050 CMPB (R1)+,#ASC"(" 174522 001043 BNE EXEC_NOTROM 174524 122127 000103 CMPB (R1)+,#ASC"C" 174530 001040 BNE EXEC_NOTROM 174532 122127 000051 CMPB (R1)+,#ASC")" 174536 001035 BNE EXEC_NOTROM 174540 011601 MOV (SP),R1 ; Get entry address back 174542 116102 000006 MOVB 6(R1),R2 ; Get ROM type 174546 #ifdef JOINERR 174546 ; Can use the following if combined code header errors: 174546 042702 177660 BIC #&FFB0,R2 ; Mask out all but language+CPU 174552 020227 000107 CMP R2,#&47 ; Is it language+PDP11? 174556 001107 BNE EXEC_NOTPDP 174560 #else 174560 BIT #&40,R2 ; Is language bit set? 174560 BEQ EXEC_NOTLANG 174560 BIC #&FFF0,R2 ; Mask out non-CPU bits 174560 CMP R2,#&07 ; Is CPU set to PDP11? 174560 BNE EXEC_NOTPDP 174560 #endif 174560 116102 000006 MOVB 6(R1),R2 ; Get ROM type again 174564 032702 000040 BIT #&20,R2 ; Does Tube transfer address exist? 174570 001416 BEQ EXEC_ROM ; No, use stacked entry address 174572 116102 000007 MOVB 7(R1),R2 ; Get copyright offset 174576 042702 177400 BIC #&FF00,R2 ; Ensure 8-bit value 174602 060201 ADD R2,R1 ; Point to copyright message 174604 005201 INC R1 ; Step past first zero byte 174606 EXEC_SKIP: 174606 105721 TSTB (R1)+ ; Find terminating zero byte 174610 001376 BNE EXEC_SKIP 174612 062701 000004 ADD #4,R1 ; Step past transfer address 174616 004767 177420 JSR PC,FETCHWORD ; R1=offset from start address *NOTE* corrupts R0 174622 062601 ADD (SP)+,R1 ; Add start entry to offset, R1 is now entry address 174624 010146 MOV R1,-(SP) ; Push it back 174626 EXEC_ROM: 174626 052705 000002 BIS #2,R5 ; R5.1=1 to indicate code with header (will become R0=1) 174632 ; Now see if a Unix header also exists 174632 ; 174632 EXEC_NOTROM: 174632 012601 MOV (SP)+,R1 ; Get entry address back 174634 042701 000001 BIC #1,R1 ; Ensure word aligned 174640 011102 MOV (R1),R2 ; Get magic number 174642 020227 000405 CMP R2,#&105 ; &o0405 - overlay 174646 103432 BCS EXEC_CODE ; &o0407 - normal 174650 020227 000411 CMP R2,#&109 ; &o0410 - read-only text 174654 103027 BCC EXEC_CODE ; &o0411 - seperated I&D 174656 005721 TST (R1)+ ; Step to next entry 174660 012103 MOV (R1)+,R3 ; Size of text 174662 012104 MOV (R1)+,R4 ; Size of initialised data 174664 060403 ADD R4,R3 ; Size of program 174666 012104 MOV (R1)+,R4 ; Size of uninitialised data 174670 013702 172764 MOV @#MEMBOT,R2 ; Destination address 174674 062701 000010 ADD #8,R1 ; Set past other fields to start of code 174700 174700 ; R1=source 174700 ; R2=dest 174700 ; R3=size of code+data 174700 ; R4=size to be zeroed 174700 174700 006203 ASR R3 ; Divide by two to get size in words 174702 EXEC_COPY: 174702 012122 MOV (R1)+,(R2)+ ; Copy program to MEMBOT 174704 005303 DEC R3 ; Decrement number of words to copy 174706 001375 BNE EXEC_COPY 174710 006204 ASR R4 ; Divide by two to get size in words 174712 001403 BEQ EXEC_ENTER ; No uninitialised data to clear 174714 EXEC_ZERO: 174714 005022 CLR (R2)+ ; Zero uninitialised data 174716 005304 DEC R4 ; Decrement number of words to clear 174720 001375 BNE EXEC_ZERO 174722 EXEC_ENTER: 174722 013701 172764 MOV @#MEMBOT,R1 ; Entry address 174726 ; Build an empty stack frame 174726 005046 CLR -(SP) ; argv[1]=0 174730 005046 CLR -(SP) ; argv[0]=0 174732 005046 CLR -(SP) ; argn=0 174734 174734 EXEC_CODE: 174734 ; r5=raw/rom+reset/oscli 174734 ; r1=entry address 174734 010146 MOV R1,-(SP) ; Stack entry address 174736 010500 MOV R5,R0 ; Get entry flags to R0 174740 012705 005674 MOV #&0BBC,R5 ; R5=&0BBC to indicate BBC EMTs available 174744 005004 CLR R4 ; Clear all other registers 174746 005003 CLR R3 174750 005002 CLR R2 174752 ; MOV #BANNER,R1 ; R1=> for no command line 174752 013701 172762 MOV @#LPTR,R1 ; R1=>command line 174756 006200 ASR R0 ; R0=0/1 for raw/header, Cy=RESET/OSCLI 174760 001405 BEQ EXEC_RAW ; Raw code, don't set program or change MEMTOP 174762 011637 172774 MOV (SP),@#PROG ; Code with a header, set entered code as current program 174766 100002 BPL EXEC_RAW ; Code in low memory, don't change MEMTOP 174770 011637 172766 MOV (SP),@#MEMTOP ; Code in high memory, put MEMTOP below code 174774 EXEC_RAW: 174774 000207 RTS PC ; Jump to code via RTS 174776 174776 EXEC_NOTLANG: 174776 ; ASR R5 174776 ; BCC EXEC_CLICOM ; Entered from RESET, drop into CLICOM 174776 ; JSR PC,INIT_HANDLES ; Connect to default error handler, Cy=SEC 174776 ; EMT 15 174776 ; EQUB 249,"This is not a language",0 174776 ; ALIGN 174776 ; 174776 EXEC_NOTPDP: 174776 006205 ASR R5 175000 103013 BCC EXEC_CLICOM ; Entered from RESET, drop into CLICOM 175002 004767 001622 JSR PC,INIT_HANDLES ; Connect to default error handler, Cy=SEC 175006 104017 EMT 15 175010 371 116 157 164 040 120 104 120 061 061 040 143 157 144 145 000 EQUB 249,"Not PDP11 code",0 175030 ALIGN 175030 175030 EXEC_CLICOM: 175030 000167 177050 JMP CLICOM ; Drop into Supervisor command prompt 175034 175034 175034 ; OSBYTE 175034 ; ====== 175034 ; On entry: R0,R1,R2=OSBYTE parameters 175034 ; On exit: R0 preserved 175034 ; If R0<&80, R1=returned value 175034 ; If R0>&7F, R1, R2, Carry=returned values 175034 ; 175034 ; Tube data: &04 X A -- X 175034 ; &06 X Y A -- Cy Y X 175034 ; 175034 BYTE_WAIT: 175034 012767 174004 175720 MOV #BANNER,LPTR ; Point LPTR=> 175042 000604 BR CLI_WAIT1 ; Jump to wait for ack. from OSCLI/OSBYTE 175044 _BYTE: 175044 010046 MOV R0,-(SP) ; Save R0 175046 105700 TSTB R0 175050 100413 BMI BYTE_HI ; Jump with high OSBYTEs 175052 012700 000004 MOV #4,R0 175056 004767 002000 JSR PC,SEND_CMD_R1 ; Send command and second parameter 175062 011600 MOV (SP),R0 ; Get first parameter from top of stack 175064 004767 002000 JSR PC,SEND_BYTE ; Send first parameter 175070 004767 002062 JSR PC,WAIT_BYTE ; Wait for response 175074 010001 MOV R0,R1 ; Pass to R1 175076 000462 BR BYTE_DONE 175100 ; MOV (SP)+,R0 ; Restore R0 175100 ; RTS PC 175100 175100 ; OSBYTE >&7F 175100 ; ----------- 175100 BYTE_HI: 175100 ; CMP R0,#&82 175100 ; BEQ MEM82 ; Fetch address high word 175100 ; CMP R0,#&83 175100 ; BEQ MEM83 ; Fetch low memory limit 175100 ; CMP R0,#&84 175100 ; BEQ MEM84 ; Fetch high memory limit 175100 ; 175100 020027 000202 CMP R0,#&82 175104 103404 BCS BYTE_HI1 ; Not a memory OSBYTE 175106 001445 BEQ MEM82 ; Fetch address high word 175110 020027 000205 CMP R0,#&85 175114 103444 BCS MEM83 ; Fetch low/high memory limit 175116 BYTE_HI1: 175116 012700 000006 MOV #6,R0 175122 004767 001734 JSR PC,SEND_CMD_R1 ; Send command and second parameter 175126 010200 MOV R2,R0 175130 004767 001734 JSR PC,SEND_BYTE ; Send third parameter 175134 012600 MOV (SP)+,R0 ; Get first parameter from stack 175136 004767 001726 JSR PC,SEND_BYTE ; Send first parameter 175142 020027 000235 CMP R0,#&9D ; Was it Fast BPut? 175146 001437 BEQ BYTE_DONE1 ; Don't wait for response 175150 020027 000216 CMP R0,#&8E ; Was it language startup? 175154 001727 BEQ BYTE_WAIT ; Wait for program startup 175156 010046 MOV R0,-(SP) ; Save R0 again 175160 004767 001772 JSR PC,WAIT_BYTE ; Wait for response 175164 062700 177600 ADD #&FF80,R0 ; Copy b7 into Carry 175170 004767 001762 JSR PC,WAIT_BYTE ; Wait for response 175174 042700 177400 BIC #&FF00,R0 ; Ensure 8-bit value 175200 010002 MOV R0,R2 ; Pass to R2 175202 000300 SWAB R0 175204 010001 MOV R0,R1 ; Pass to R1 as b8-b15 of result 175206 004767 001744 JSR PC,WAIT_BYTE ; Wait for response 175212 042700 177400 BIC #&FF00,R0 ; Ensure 8-bit value 175216 050001 BIS R0,R1 ; Merge with b8-b15 set from R2 175220 000411 BR BYTE_DONE 175222 175222 ; Read memory locations 175222 ; --------------------- 175222 MEM82: 175222 012700 000206 MOV #&86,R0 ; Point to ADDR+2 175226 MEM83: 175226 MEM84: 175226 006300 ASL R0 ; A=&0106,&0108,&010C 175230 016001 172356 MOV MEMBOT-&106(R0),R1 ; Fetch address value 175234 010102 MOV R1,R2 ; R2=R1 DIV 256 175236 000302 SWAB R2 175240 042702 177400 BIC #&FF00,R2 175244 BYTE_DONE: 175244 012600 MOV (SP)+,R0 ; Restore R0 175246 BYTE_DONE1: 175246 000207 RTS PC 175250 175250 175250 ; OSWORD 175250 ; ====== 175250 ; On entry: R0=OSWORD number 175250 ; R1=>control block 175250 ; 175250 _WORD: 175250 005700 TST R0 175252 001515 BEQ RDLINE ; OSWORD 0, jump to read line 175254 ; 175254 ; OSWORD <>&00 175254 ; ------------ 175254 ; Tube data: &08 function in_length block out_length -- block 175254 ; 175254 010346 MOV R3,-(SP) ; Save R3 175256 010246 MOV R2,-(SP) ; Save R2 175260 010046 MOV R0,-(SP) ; Save R0 175262 012700 000010 MOV #8,R0 175266 004767 001634 JSR PC,SEND_CMD ; Send command &08 - OSWORD 175272 011600 MOV (SP),R0 ; Get R0 back 175274 004767 001570 JSR PC,SEND_BYTE ; Send OSWORD number 175300 105700 TSTB R0 ; Check OSWORD number 175302 100003 BPL WORDLO ; <&80, calculate control block sizes 175304 112102 MOVB (R1)+,R2 ; Get transmit size from control block DMB: should be R1 175306 111103 MOVB (R1),R3 ; Get receive size from control block DMB: should be R1 175310 000414 BR WORDGO ; Jump to send OSWORD command 175312 WORDLO: 175312 012702 000020 MOV #&10,R2 ; OSWORD &15-&7F uses 16 bytes both ways 175316 012703 000020 MOV #&10,R3 175322 020027 000025 CMP R0,#&15 ; OSWORD &01-&7F use fixed control block sizes 175326 103005 BCC WORDGO ; OSWORD &15-&7F, jump to send OSWORD command 175330 060000 ADD R0,R0 ; Double R0 to index into table 175332 062700 175434 ADD #WORD_TABLE-2,R0 ; Point to table entry DMB: #WORD_TABLE 175336 112002 MOVB (R0)+,R2 ; Fetch send length 175340 111003 MOVB (R0),R3 ; Fetch receive length 175342 WORDGO: 175342 010200 MOV R2,R0 ; Get transmit block length 175344 004767 001520 JSR PC,SEND_BYTE ; Send transmit block length 175350 060201 ADD R2,R1 ; Point to past end of control block 175352 005302 DEC R2 ; Convert 0 to -1 175354 020227 000200 CMP R2,#&80 ; Check length of transmit block 175360 103005 BCC WORD_NOTX ; Transmit block=0 or >&80, send nothing 175362 WORD_TX: 175362 114100 MOVB -(R1),R0 ; Get byte from control block 175364 004767 001500 JSR PC,SEND_BYTE ; Send byte to Tube R2 175370 005302 DEC R2 175372 100373 BPL WORD_TX ; Loop to send control block 175374 WORD_NOTX: 175374 010300 MOV R3,R0 ; Get recive block length 175376 004767 001466 JSR PC,SEND_BYTE ; Send receive block length 175402 060301 ADD R3,R1 ; Point past end of control block 175404 005303 DEC R3 ; Convert 0 to -1 175406 020327 000200 CMP R3,#&80 ; Check length of received block 175412 103005 BCC WORD_NORX ; Receive block=0 or >&80, receive nothing 175414 WORD_RX: 175414 004767 001536 JSR PC,WAIT_BYTE ; Get byte from Tube R2 175420 110041 MOVB R0,-(R1) ; Store byte in control block 175422 005303 DEC R3 175424 100373 BPL WORD_RX ; Loop to receive control block 175426 WORD_NORX: 175426 012600 MOV (SP)+,R0 ; Restore registers 175430 012602 MOV (SP)+,R2 175432 012603 MOV (SP)+,R3 175434 000207 RTS PC 175436 ; 175436 ; Table of OSWORD control block lengths for &01-&14 175436 ; ------------------------------------------------- 175436 ; low byte=send length, high byte=recive length 175436 WORD_TABLE: 175436 002400 EQUW &0500 ; &01 =TIME 175440 000005 EQUW &0005 ; &02 TIME= 175442 002400 EQUW &0500 ; &03 =TIMER 175444 000005 EQUW &0005 ; &04 TIMER= 175446 002404 EQUW &0504 ; &05 =MEM 175450 000005 EQUW &0005 ; &06 MEM= 175452 000010 EQUW &0008 ; &07 SOUND 175454 000016 EQUW &000E ; &08 ENVELOPE 175456 002404 EQUW &0504 ; &09 =POINT 175460 004401 EQUW &0901 ; &0A Read bitmap 175462 002401 EQUW &0501 ; &0B Read palette 175464 000005 EQUW &0005 ; &0C Write palette 175466 004000 EQUW &0800 ; &0D Read graphics coords 175470 014420 EQUW &1910 ; &0E =TIME$ 175472 000040 EQUW &0020 ; &0F TIME$= 175474 000420 EQUW &0110 ; &10 Net_Tx 175476 006415 EQUW &0D0D ; &11 Net_Rx 175500 100000 EQUW &8000 ; &12 Net_Params 175502 004010 EQUW &0808 ; &13 Net_Info 175504 100200 EQUW &8080 ; &14 NetFS_Op 175506 175506 175506 ; Read a line of text 175506 ; ------------------- 175506 ; Tube data: &0A block -- &FF or &7F string &0D 175506 ; 175506 RDLINE: 175506 012700 000012 MOV #10,R0 175512 004767 001410 JSR PC,SEND_CMD ; Send command &0A - RDLINE 175516 062701 000002 ADD #2,R1 175522 012702 000003 MOV #3,R2 175526 004767 001274 JSR PC,SEND_BLK ; Send 3-byte control block 175532 012700 000007 MOV #7,R0 175536 004767 001326 JSR PC,SEND_BYTE ; Send &0700 175542 005000 CLR R0 175544 004767 001320 JSR PC,SEND_BYTE 175550 004767 001402 JSR PC,WAIT_BYTE ; Wait for response 175554 062700 177600 ADD #&FF80,R0 ; Copy b7 into Carry 175560 103413 BCS RD_DONE 175562 004767 176450 JSR PC,FETCHWORD2 ; Get address to store text, allowing for nonalignment 175566 005002 CLR R2 ; Clear count of received bytes 175570 RD_STR: 175570 004767 001362 JSR PC,WAIT_BYTE ; Wait for byte from Tube R2 175574 110021 MOVB R0,(R1)+ ; Store it 175576 005202 INC R2 ; Increment number of bytes 175600 020027 000015 CMP R0,#13 ; Check current byte 175604 001371 BNE RD_STR ; Loop until and Clear Carry 175606 005302 DEC R2 ; R2 is length of string 175610 RD_DONE: 175610 000207 RTS PC 175612 175612 175612 ; OSARGS - Read info on open file or filing system 175612 ; ================================================ 175612 ; On entry: R0=function 175612 ; R1=handle 175612 ; R2=>control block 175612 ; On exit: R0=returned value 175612 ; R1 preserved 175612 ; R2 preserved 175612 ; 175612 ; Tube Data: &0C handle block function -- result block 175612 ; 175612 _ARGS: 175612 010246 MOV R2,-(SP) ; Save control block pointer 175614 010146 MOV R1,-(SP) ; Save handle 175616 010046 MOV R0,-(SP) ; Save function 175620 012700 000014 MOV #&0C,R0 175624 004767 001232 JSR PC,SEND_CMD_R1 ; Send command and handle 175630 010201 MOV R2,R1 175632 012702 000004 MOV #4,R2 175636 004767 001164 JSR PC,SEND_BLK ; Send four-byte control block 175642 012600 MOV (SP)+,R0 175644 004767 001220 JSR PC,SEND_BYTE ; Send function 175650 004767 001302 JSR PC,WAIT_BYTE ; Wait for returned result 175654 010046 MOV R0,-(SP) ; Save result 175656 012702 000004 MOV #4,R2 ; Prepare to wait for 4-byte control block 175662 000463 BR FILE_DONE ; Wait for control block, restore and return 175664 175664 175664 ; OSFIND - Open or Close a file 175664 ; ============================= 175664 ; On entry: R0=function 175664 ; R1=handle or =>filename 175664 ; On exit: R0=zero or handle 175664 ; 175664 ; Tube data: &12 function string &0D -- handle 175664 ; &12 &00 handle -- &7F 175664 ; 175664 _FIND: 175664 010046 MOV R0,-(SP) ; Save R0 175666 012700 000022 MOV #&12,R0 175672 004767 001230 JSR PC,SEND_CMD ; Send command &12 - OSFIND 175676 012600 MOV (SP)+,R0 ; Get R0 back 175700 004767 001164 JSR PC,SEND_BYTE ; Send function 175704 005700 TST R0 ; Check function 175706 001006 BNE OPEN ; Jump to deal with OPEN 175710 ; CLOSE 175710 004767 001152 JSR PC,SEND_BYTE_R1 ; Send handle to Tube 175714 004767 001236 JSR PC,WAIT_BYTE ; Wait for acknowledgement 175720 005000 CLR R0 ; Zero R0 175722 000207 RTS PC 175724 OPEN: 175724 010146 MOV R1,-(SP) ; Save R1 175726 004767 001056 JSR PC,SEND_STR ; Send string at R1 175732 004767 001220 JSR PC,WAIT_BYTE ; Wait for returned handle 175736 012601 MOV (SP)+,R1 ; Restore R1 175740 000207 RTS PC 175742 175742 175742 ; OSFILE - Operate on whole files 175742 ; =============================== 175742 ; On entry: R0=function 175742 ; R1=>control block 175742 ; On exit: R0=result 175742 ; R1 preserved 175742 ; control block updated 175742 ; 175742 ; Tube data: &14 block string function -- result block 175742 ; 175742 _FILE: 175742 010246 MOV R2,-(SP) ; Save R2 175744 010146 MOV R1,-(SP) ; Save R1 175746 010046 MOV R0,-(SP) ; Save function 175750 012700 000024 MOV #&14,R0 175754 004767 001146 JSR PC,SEND_CMD ; Send command &14 - OSFILE 175760 062701 000002 ADD #2,R1 ; Point to control block contents 175764 012702 000020 MOV #16,R2 175770 004767 001032 JSR PC,SEND_BLK ; Send 16-byte control block 175774 004767 176236 JSR PC,FETCHWORD2 ; Get address of filename, allowing for nonalignment 176000 004767 001004 JSR PC,SEND_STR ; Send filename string 176004 012600 MOV (SP)+,R0 176006 004767 001056 JSR PC,SEND_BYTE ; Send function 176012 004767 001140 JSR PC,WAIT_BYTE ; Wait for returned result 176016 011601 MOV (SP),R1 ; Get control block pointer back 176020 010046 MOV R0,-(SP) ; Save result 176022 062701 000002 ADD #2,R1 ; Point to control block contents 176026 012702 000020 MOV #16,R2 ; Prepate to wait for 16-byte control block 176032 FILE_DONE: 176032 004767 001006 JSR PC,WAIT_BLK ; Wait for control block 176036 012600 MOV (SP)+,R0 ; Get result back 176040 012601 MOV (SP)+,R1 ; Get control block pointer back 176042 012602 MOV (SP)+,R2 ; Get R2 back 176044 000207 RTS PC 176046 176046 176046 ; OS_GBPB - Multiple byte read and write 176046 ; ===================================== 176046 ; On entry: R0=function 176046 ; R1=>control block 176046 ; On exit: R0=returned value 176046 ; control block updated 176046 ; 176046 ; Tube data: &16 block function -- block Carry result 176046 ; 176046 _GBPB: 176046 #ifndef NOCHNZERO 176046 TSTB (R1) ; Check handle 176046 BNE GBPB1 ; Non-zero handle 176046 TST R0 ; Check function 176046 BEQ GBPB1 ; Pass OSGBPB 0 to Tube 176046 CMP R0,#5 176046 BCS GBPB_RDWR ; Channel 0 via OSRDCH/OSWRCH 176046 #endif 176046 GBPB1: 176046 010246 MOV R2,-(SP) ; Save R2 176050 010046 MOV R0,-(SP) ; Save function 176052 012700 000026 MOV #&16,R0 176056 004767 001044 JSR PC,SEND_CMD ; Send command &16 - OSGBPB 176062 012702 000015 MOV #13,R2 176066 004767 000734 JSR PC,SEND_BLK ; Send 13-byte control block 176072 012600 MOV (SP)+,R0 176074 004767 000770 JSR PC,SEND_BYTE ; Send function 176100 012702 000015 MOV #13,R2 176104 004767 000734 JSR PC,WAIT_BLK ; Wait for 13-byte control block 176110 012602 MOV (SP)+,R2 ; Get R2 back 176112 000410 BR WAIT_CHAR ; Get Carry and result byte 176114 ; 176114 ; Read or write block of memory to/from OSWRCH/OSRDCH 176114 ; --------------------------------------------------- 176114 ; NB, only uses 16-bit address and count, b16-b31 ignored and not updated 176114 ; 176114 #ifndef NOCHNZERO 176114 GBPB_RDWR: 176114 MOV R2,-(SP) ; Save R2 176114 MOV R0,-(SP) ; Save function 176114 MOV R1,-(SP) ; Save pointer to control block 176114 INC R1 ; Point to Address 176114 JSR PC,FETCHWORD ; R1=Address, allowing for nonalignment 176114 MOV R1,R2 ; R2=Address 176114 MOV (SP)+,R1 ; Restore pointer to control block 176114 176114 GBPB_LP: 176114 CMP (SP),#3 176114 BCC GBPB_RD ; Function 3/4, read characters 176114 ; Function 1/2, write characters 176114 MOVB (R2)+,R0 ; Get character from memory 176114 JSR PC,_WRCH ; Write it 176114 BR GBPB_NEXT ; Jump to update and loop 176114 GBPB_RD: 176114 JSR PC,_RDCH ; Read character 176114 BCS GBPB_EXIT ; Carry set, exit 176114 MOVB R0,(R2)+ ; Store character 176114 GBPB_NEXT: 176114 TSTB 5(R1) ; Test byte low byte 176114 BNE GBPB_LO ; Count<>&xx00 176114 DECB 6(R1) ; Decrement count high byte 176114 GBPB_LO: 176114 DECB 5(R1) ; Decrement count low byte 176114 BNE GBPB_LP ; Loop until all done 176114 TSTB 6(R1) ; Test count high byte 176114 BNE GBPB_LP ; Loop until all done 176114 CLC ; Clear carry for OK 176114 GBPB_EXIT: 176114 MOVB R2,1(R1) 176114 SWAB R2 176114 MOVB R2,2(R1) ; Update address 176114 TST (SP)+ ; Drop function 176114 MOV (SP)+,R2 ; Restore R2 176114 MOV #0,R0 ; R0=0, function supported, don't affect Carry 176114 RTS PC 176114 #endif 176114 176114 176114 ; OSBGET - Get a byte from open file 176114 ; ================================== 176114 ; On entry: R1=handle 176114 ; On exit: R0=byte Read 176114 ; R1=preserved 176114 ; Cy set if EOF 176114 ; 176114 ; Tube data: &0E handle -- Carry byte 176114 ; 176114 _BGET: 176114 #ifndef NOCHNZERO 176114 TST R1 ; Check handle 176114 BEQ _RDCH ; BGET#0 calls OSRDCH 176114 #endif 176114 012700 000016 MOV #&0E,R0 176120 004767 000736 JSR PC,SEND_CMD_R1 ; Send command and handle 176124 000403 BR WAIT_CHAR ; Wait for Carry, Byte 176126 176126 176126 ; OSRDCH - Wait for character from input stream 176126 ; ============================================= 176126 ; On exit: R0=char, Cy=carry 176126 ; 176126 ; Tube data: &00 -- Carry Char 176126 ; 176126 _RDCH: 176126 005000 CLR R0 176130 004767 000772 JSR PC,SEND_CMD ; Send command &00 - OSRDCH 176134 WAIT_CHAR: 176134 004767 001016 JSR PC,WAIT_BYTE ; Get returned byte 176140 062700 177600 ADD #&FF80,R0 ; Copy b7 into carry 176144 ; Continue to fetch byte from Tube R2 176144 176144 176144 ; Wait for byte in Tube Register 1 to return in R0, preserving Carry 176144 ; ================================================================== 176144 WAIT_BYTE: 176144 ;;; if SERIAL fetch from serial input stream 176144 113700 177764 MOVB @#TUBE2S,R0 ; Read Tube R2 status 176150 100375 BPL WAIT_BYTE ; Loop until b7 set 176152 113700 177766 MOVB @#TUBE2,R0 ; Get byte from Tube R2 176156 000207 RTS PC 176160 176160 176160 ; OSBPUT - Put a byte to an open file 176160 ; =================================== 176160 ; On entry: R0=byte to write 176160 ; R1=handle 176160 ; On exit: R0=preserved 176160 ; R1=preserved 176160 ; 176160 ; Tube data: &10 handle byte -- &7F 176160 ; 176160 _BPUT: 176160 #ifndef NOCHNZERO 176160 TST R1 ; Check handle 176160 BEQ _WRCH ; BPUT#0 calls OSWRCH 176160 #endif 176160 010046 MOV R0,-(SP) ; Save R0 176162 012700 000020 MOV #&10,R0 176166 004767 000670 JSR PC,SEND_CMD_R1 ; Send command and handle 176172 011600 MOV (SP),R0 ; Get R0 back 176174 004767 000670 JSR PC,SEND_BYTE ; Send byte to Tube 176200 004767 177740 JSR PC,WAIT_BYTE ; Wait for acknowledgement 176204 012600 MOV (SP)+,R0 ; Restore R0 176206 000207 RTS PC 176210 176210 176210 ; OSASCI - Send ASCII character 176210 ; ============================= 176210 _ASCII: 176210 022700 000015 CMP #13,R0 ; If not , send raw character 176214 001006 BNE _WRCH ; If , fall through to send NEWL 176216 176216 176216 ; OSNEWL - Send LF/CR sequence 176216 ; ============================ 176216 _NEWL: 176216 012700 000012 MOV #10,R0 176222 004767 000004 JSR PC,_WRCH ; Output LF 176226 012700 000015 MOV #13,R0 ; Fall through into WRCH 176232 176232 176232 ; OSWRCH - Send character in R0 to Tube Register 1 176232 ; ================================================ 176232 _WRCH: 176232 000167 177774 JMP SENDBYTE ****** Undefined label 176236 176236 176236 ; TRAP handler 176236 ; ============ 176236 ; TRAP is used for Unix calls and is followed by a variable number of inline parameters, 176236 ; so it is impossible to simply do a null return. So, the safest option is to give the 176236 ; standard CoPro client 'unsupported' error. 176236 TRAP_HANDLER: 176236 104017 EMT 15 176240 377 102 141 144 000 EQUB 255,"Bad",0 176245 000 ALIGN 176246 176246 176246 ; EMT handler 176246 ; =========== 176246 ; On extry, R0-R5 contain any parameters 176246 ; PSW ignored 176246 ; On exit, R0-R5 contain any returned values 176246 ; C returns any returned value 176246 ; V set if error, R0=>error block 176246 ; 176246 EMT_HANDLER: 176246 042766 177760 000002 BIC #&FFF0,2(SP) ; Clear stacked flags 176254 013746 172740 MOV @#ERRV,-(SP) ; Save old ERR handler 176260 013746 172754 MOV @#EMTV,-(SP) ; Save old EMT SP 176264 010637 172754 MOV SP,@#EMTV ; Save current EMT SP 176270 012737 176334 172740 MOV #EMT_ERROR,@#ERRV ; Catch EMT errors 176276 005746 TST -(SP) ; Make space on stack 176300 010046 MOV R0,-(SP) ; Save R0 176302 016600 000010 MOV 8(SP),R0 ; Get return address 176306 014000 MOV -(R0),R0 ; Get EMT instruction 176310 042700 177400 BIC #&FF00,R0 ; Get EMT number 176314 ;CMP R0,#EMTMAX 176314 ;BCC EMT_IGNORE ; Out of range 176314 060000 ADD R0,R0 ; Index into dispatch table 176316 063700 172756 ADD @#EMTADDR,R0 ; Index into dispatch table 176322 011066 000002 MOV (R0),2(SP) ; Copy address to stack 176326 012600 MOV (SP)+,R0 ; Restore R0 176330 004736 JSR PC,@(SP)+ ; Jump to routine 176332 102005 BVC EMT_NOERROR ; V clear, jump to check Carry 176334 EMT_ERROR: 176334 013706 172754 MOV @#EMTV,SP ; Get saved EMT SP 176340 052766 000002 000006 BIS #2,6(SP) ; Set stacked V flag 176346 EMT_NOERROR: 176346 103003 BCC EMT_EXIT ; C clear, jump to exit 176350 052766 000001 000006 BIS #1,6(SP) ; Set stacked C flag 176356 EMT_EXIT: 176356 012637 172754 MOV (SP)+,@#EMTV ; Restore old EMT SP 176362 012637 172740 MOV (SP)+,@#ERRV ; Restore old error handler 176366 000002 RTI ; Return from EMT 176370 ;EMT_IGNORE: 176370 ;MOV (SP)+,R0 ; Restore R0 176370 ;TST (SP)+ ; Balance stack 176370 ;BR EMT_EXIT 176370 176370 176370 ; EMT 15 - Generate an error 176370 ; -------------------------- 176370 EMT15: 176370 ; v0.20a optimisation 176370 016600 000006 MOV 6(SP),R0 ; Get return address pointing to inline error block 176374 016666 000004 000006 MOV 4(SP),6(SP) ; Replace return address with mainline error handler 176402 000207 RTS PC ; Return to EMT handler, thence to error handler 176404 176404 176404 ; EMT 14 - Read/Write handlers, etc. 176404 ; ---------------------------------- 176404 ; On entry: R0=0..255 to claim EMTs 0..255 176404 ; R1=new routine address or 0 to read 176404 ; R0=&FFxx to set environment handlers 176404 ; R1=new handler address or 0 to read 176404 ; R2=new handler data address or 0 to read 176404 ; On exit: R0=preserved 176404 ; R1=old address 176404 ; R2=old handler address or preserved 176404 ; 176404 EMT14: 176404 ; So that EMT14 can change the ERRV we have to rewind out of the EMT handler and restore ERRV so that 176404 ; it can be changed. Otherwise, the EMT handler will just restore ERRV to whatever it was before. 176404 005726 TST (SP)+ ; Drop return to EMT handler 176406 012637 172754 MOV (SP)+,@#EMTV ; Restore old EMT SP 176412 012637 172740 MOV (SP)+,@#ERRV ; Restore mainline error handler 176416 010046 MOV R0,-(SP) ; Save R0 176420 100413 BMI EMT14_HANDLER ; Negative, set up handler 176422 020027 000400 CMP R0,#EMTMAX 176426 103033 BCC EMT14_QUIT ; Out of range 176430 060000 ADD R0,R0 ; Double R0 to offset into table 176432 063700 172756 ADD @#EMTADDR,R0 ; Index into EMT dispatch table 176436 011046 MOV (R0),-(SP) ; Get old address 176440 005701 TST R1 176442 001424 BEQ EMT14_READ ; Zero, just read 176444 010110 MOV R1,(R0) ; Store new address if non-zero 176446 000422 BR EMT14_READ 176450 176450 EMT14_HANDLER: 176450 005100 COM R0 176452 ; CMP R0,#HANDLEMAX 176452 020027 000012 CMP R0,#HANDLEMAX+WORKSPMAX/4 ; Allow access to workspace as well as handles 176456 103017 BCC EMT14_QUIT ; Out of range 176460 060000 ADD R0,R0 176462 060000 ADD R0,R0 ; Times four to offset into table 176464 062700 172730 ADD #HANDLERS,R0 ; Index into handlers 176470 011046 MOV (R0),-(SP) ; Save old handler address 176472 005701 TST R1 176474 001401 BEQ EMT14_HAND2 ; Just read old handler address 176476 010110 MOV R1,(R0) ; Store new handler address 176500 EMT14_HAND2: 176500 005720 TST (R0)+ ; DMB: Step to data address 176502 011046 MOV (R0),-(SP) ; Save old data address 176504 005702 TST R2 176506 001401 BEQ EMT14_HAND3 ; Just read old data address 176510 010210 MOV R2,(R0) ; Store new data address 176512 EMT14_HAND3: 176512 012602 MOV (SP)+,R2 ; Get old data 176514 EMT14_READ: 176514 012601 MOV (SP)+,R1 ; Get old address 176516 EMT14_QUIT: 176516 012600 MOV (SP)+,R0 ; Restore R0 176520 000002 RTI 176522 176522 ; EMT 13 - Misc control functions 176522 ; ------------------------------- 176522 ; On entry: R0=0 - Load BBC BASIC 176522 ; 1 - Set up new program environment - default environment handlers only 176522 ; 2 - Set up software environment - default environment handlers and EMTs 176522 ; 3 - Set up hardware environment - default environment handlers, EMTs, hardware vectors 176522 EMT13: 176522 005700 TST R0 176524 001404 BEQ EMTXX ; R0=0 - unsupported 176526 020027 000003 CMP R0,#3 ; R0=1 - set up new program environment - set up handlers 176532 103435 BCS INIT_HANDLES1 ; R0=2 - set up environment handlers, workspace, EMTs 176534 001403 BEQ INIT_ENV ; R0=3 - set up environment handlers, workspace, EMTs, hardware vectors 176536 176536 EMTXX: ; EMTs 16-255 176536 EVENT: ; Null event handler 176536 000207 RTS PC 176540 176540 ; EMT 0 - Exit current program 176540 ; ---------------------------- 176540 EMT0: 176540 000177 174164 JMP @EXITV ; Jump via exit handler 176544 176544 176544 ; Set up default system environment 176544 ; ================================= 176544 INIT_ENV: 176544 005000 CLR R0 176546 INIT_LP1: 176546 012720 000076 MOV #NULLIRQ,(R0)+ ; Set all hardware vectors to NULLIRQ 176552 005020 CLR (R0)+ ; Allow all interupts 176554 020027 000400 CMP R0,#&100 ; Hardware vectors at at &0000-&00FF 176560 001372 BNE INIT_LP1 176562 ; 176562 ; MOV #CLICOM,@#STACKVEC ; Could also catch Bad Stack vector 176562 ; ; There's no easy way to recover from a Bad Stack, so would have 176562 ; ; bomb out to somewhere safe. 176562 012737 176236 000034 MOV #TRAP_HANDLER,@#TRAPVEC ; Set up TRAP vector to give an error 176570 012737 176246 000030 MOV #EMT_HANDLER,@#EMTVEC ; Set up EMT vector 176576 ; CLR @#EMTVEC+2 ; EMT processor status - allow all interupts 176576 ; We now have R0.b0=0 from the CMP/BNE above 176576 176576 INIT_IRQ: 176576 ; On entry here, if R0.b0=0 initialise IRQ/NMIs, handlers and EMTs 176576 ; if R0.b0=1 initialise IRQ/NMIs, handlers only 176576 ; 176576 012737 000072 000200 MOV #NMI_ACK,@#NMIVEC+0 ; Set up NMI vector 176604 012737 000340 000202 MOV #&00E0,@#NMIVEC+2 ; NMI processor status - bar all interupts 176612 012737 177416 000204 MOV #IRQ,@#IRQVEC+0 ; Set up IRQ vector 176620 012737 000300 000206 MOV #&00C0,@#IRQVEC+2 ; IRQ processor status - bar all except NMIs 176626 ; 176626 INIT_HANDLES1: 176626 006000 ROR R0 ; Move b0 into Carry 176630 INIT_HANDLES: 176630 ; On entry here, if Cy=0 initialise handlers and EMTs 176630 ; if Cy=1 initialise handlers only 176630 ; 176630 012700 000014 MOV #HANDLEMAX*2,R0 ; R0=word count of handlers + workspace except ADDR/PROG 176634 012701 176676 MOV #HANDDEFAULT,R1 ; R1=> Default handlers and EMTs 176640 012702 172730 MOV #HANDLERS,R2 ; R2=> Start of handlers DMB 176644 103402 BCS INIT_HANDLES2 ; If Carry Set on entry, just do handlers+workspace 176646 062700 000030 ADD #16+WORKSPMAX/2,R0 ; Add core EMTs, ADDR/PROG, carry still clear 176652 INIT_HANDLES2: 176652 INIT_LP2: 176652 012122 MOV (R1)+,(R2)+ ; Set up initial settings 176654 005300 DEC R0 ; and EMT dispatch table, 176656 001375 BNE INIT_LP2 ; while preserving Carry 176660 103405 BCS INIT_DONE ; Carry was Set on entry, don't initialise EMTs 176662 012700 000360 MOV #EMTMAX-16,R0 ; Number of unused EMTs 176666 INIT_CLR: 176666 011122 MOV (R1),(R2)+ ; EMTs 16-255 do nothing 176670 005300 DEC R0 176672 001375 BNE INIT_CLR 176674 INIT_DONE: 176674 000207 RTS PC ; Return with R0=0, R1,R2 corrupted 176676 176676 ; Default settings and EMT table 176676 ; ============================== 176676 HANDDEFAULT: 176676 174104 EQUW EXITHAND ; &D8 - Default exit handler 176700 000042 EQUW VERSION ; &DA - Unused - Client version 176702 174226 EQUW ESCHAND ; &DC - Default escape handler 176704 172777 EQUW ESCFLG ; &DE - Default escape flag 176706 174200 EQUW ERRHAND ; &E0 - Default error handler 176710 172400 EQUW ERRBLK ; &E2 - Default error buffer 176712 176536 EQUW EVENT ; &E4 - Default event handler 176714 000000 EQUW 0 ; &E6 - Unused 176716 000076 EQUW USERIRQ ; &E8 - Default unknown IRQ handler 176720 000000 EQUW 0 ; &EA - Unused 176722 000000 EQUW 0 ; &EC - Holds old SP within EMT handler 176724 173000 EQUW EMTTABLE ; &EE - Default EMT dispatch table 176726 176726 000000 EQUW 0 ; &F0 - unused 176730 174004 EQUW BANNER ; &F2 - Line pointer 176732 000400 EQUW RAMSTART ; &F4 - Lowest user memory 176734 172400 EQUW RAMEND ; &F6 - Highest user memory 176736 174104 000000 EQUD CLICOM ; &F8 - Transfer address 176742 174104 EQUW CLICOM ; &FC - Default current program 176744 000 EQUB 0 ; &FE - Spare byte 176745 000 EQUB 0 ; &FF - Escape flag 176746 EMTDEFAULT: 176746 176540 EQUW EMT0 ; EMT 0 - QUIT 176750 174276 EQUW _CLI ; EMT 1 - OSCLI 176752 175044 EQUW _BYTE ; EMT 2 - OSBYTE 176754 175250 EQUW _WORD ; EMT 3 - OSWORD 176756 176232 EQUW _WRCH ; EMT 4 - OSWRCH 176760 176216 EQUW _NEWL ; EMT 5 - OSNEWL 176762 176126 EQUW _RDCH ; EMT 6 - OSRDCH 176764 175742 EQUW _FILE ; EMT 7 - OSFILE 176766 175612 EQUW _ARGS ; EMT 8 - OSARGS 176770 176114 EQUW _BGET ; EMT 9 - OSBGET 176772 176160 EQUW _BPUT ; EMT 10 - OSBPUT 176774 176046 EQUW _GBPB ; EMT 11 - OSGBPB 176776 175664 EQUW _FIND ; EMT 12 - OSFIND 177000 176522 EQUW EMT13 ; EMT 13 - System control 177002 176404 EQUW EMT14 ; EMT 14 - Set handlers 177004 176370 EQUW EMT15 ; EMT 15 - ERROR 177006 176536 EQUW EMTXX ; EMTs 16-255 - unused 177010 177010 177010 ; ***************** 177010 ; TUBE I/O ROUTINES 177010 ; ***************** 177010 177010 ; Send -string at R1 to Tube Register 2 177010 ; ========================================= 177010 SEND_STR: 177010 112100 MOVB (R1)+,R0 ; Get byte from R1, increment R1 177012 004767 000052 JSR PC,SEND_BYTE ; Send byte via Tube R2 177016 020027 000015 CMP R0,#13 ; Test current character 177022 001372 BNE SEND_STR ; Loop until sent 177024 000207 RTS PC 177026 177026 177026 ; Send block at R1 to Tube Register 2 177026 ; =================================== 177026 SEND_BLK: 177026 060201 ADD R2,R1 ; Add length of control block to R1 177030 SEND_BLKLP: 177030 114100 MOVB -(R1),R0 ; Decrement R1, Get byte from R1 177032 004767 000032 JSR PC,SEND_BYTE ; Send byte via Tube R2 177036 005302 DEC R2 ; Decrement count 177040 001373 BNE SEND_BLKLP ; Loop until all sent 177042 000207 RTS PC 177044 177044 177044 ; Wait for block at R1 from Tube Register 2 177044 ; ========================================= 177044 WAIT_BLK: 177044 060201 ADD R2,R1 ; Add length of control block to R1 177046 WAIT_BLKLP: 177046 004767 177072 JSR PC,WAIT_BYTE ; Wait for byte via Tube R2 177052 110041 MOVB R0,-(R1) ; Decrement R1, store byte to R1 177054 005302 DEC R2 ; Decrement count 177056 001373 BNE WAIT_BLKLP ; Loop until all received 177060 000207 RTS PC 177062 177062 177062 ; Send command in R0 followed by byte in R1 177062 ; ========================================= 177062 SEND_CMD_R1: 177062 004767 000040 JSR PC,SEND_CMD ; Send command 177066 177066 177066 ; Send byte in R1 to Tube Register 2 177066 ; ================================== 177066 SEND_BYTE_R1: 177066 010100 MOV R1,R0 ; Pass byte to R0 and fall through 177070 177070 177070 ; Tube Core I/O Routines 177070 ; ====================== 177070 ; Characters and commands are sent over the same single port 177070 ; Outward commands are escaped, and inward responses are escaped 177070 ; 177070 ; Outward 177070 ; x VDU x 177070 ; esc,esc VDU esc 177070 ; esc,n MOS function, control block follows 177070 ; 177070 ; Inward 177070 ; x char/byte x 177070 ; esc,esc char/byte esc 177070 ; esc,&00 BRK, error number+text+null follows 177070 ; esc,<&80 read returned control block set length 177070 ; esc,&8n Escape change, b0=new state 177070 ; esc,&9x,Y,X,A Event 177070 ; esc,&Ax reserved for networking 177070 ; esc,&Bx end transfer 177070 ; esc,&Cx,addr set address 177070 ; esc,&Dx,addr execute address 177070 ; esc,&Ex,addr start load from address 177070 ; esc,&Fx,addr start save from address 177070 ; All commands are data inward, except esc,&Fx which is data outward 177070 177070 177070 ; Send byte in A, escaping it if needed 177070 ; ===================================== 177070 SEND_BYTE: 177070 020027 177070 CMP R0,#esc ; Escape character? ****** Undefined label in destination 177074 001002 BNE SEND_DATA ; No, send raw 177076 004767 000000 JSR PC,SEND_DATA ; Double escape character 177102 SEND_DATA: 177102 010046 MOV R0,-(SP) ; Save byte 177104 SEND_WAIT: 177104 113700 177104 MOVB @#TXSTATUS,R0 ; Read Tube R4 status ****** Undefined label in source 177110 042700 177110 BIC #TXRDY,R0 ****** Undefined label in source 177114 001773 BEQ SEND_WAIT ; Loop until data can be sent 177116 012600 MOV (SP)+,R0 ; Get byte back 177120 110037 177120 MOVB R0,@#TXDATA ; Send data ****** Undefined label in destination 177124 000207 RTS PC 177126 177126 177126 ; Send an escaped command 177126 ; ======================= 177126 SEND_CMD: 177126 010046 MOV R0,-(SP) ; Save command byte 177130 012700 177130 MOV #esc,R0 ****** Undefined label in source 177134 004000 JSR SEND_DATA ; Send esc prefix ****** Missing , 177136 012600 MOV (SP)+,R0 177140 156700 177774 BISB DMA_TYPE,R0 ; Add personality bits ****** Undefined label in source 177144 BRA SEND_DATA ; Send command byte ****** Unknown opcode 177144 177144 177144 ; Check if a byte is waiting, and read it if there 177144 ; ================================================ 177144 BYTE_READ: 177144 113700 177144 MOVB @#RXSTATUS,R0 ****** Undefined label in source 177150 042700 177150 BIC #RXRDY,R0 ****** Undefined label in source 177154 001022 BNE WAIT_EXIT ; Nothing pending, return 177156 ; ; Continue into WaitByte 177156 177156 177156 ; Wait for a byte, decoding escaped data 177156 ; ====================================== 177156 ; On exit, R0 =byte 177156 ; F =preserved 177156 ; 177156 WAIT_BYTE: 177156 ??? PSHS CC ; Save flags ****** Unknown opcode 177156 WAIT_BYTELP: 177156 004767 000042 JSR PC,WAIT_DATA 177162 001017 BNE WAIT_BYTEOK ; Not esc, return 177164 004767 000034 JSR PC,WAIT_DATA ; Get another byte 177170 001414 BEQ WAIT_BYTEOK ; esc,esc, return 177172 010546 MOV R5,-(SP) 177174 010446 MOV R4,-(SP) 177176 010346 MOV R3,-(SP) 177200 010246 MOV R2,-(SP) 177202 010146 MOV R1,-(SP) ; Push all registers 177204 004767 000022 JSR PC,WAIT_COMMAND ; Decode escaped command 177210 010146 MOV R1,-(SP) 177212 010246 MOV R2,-(SP) 177214 010346 MOV R3,-(SP) 177216 010446 MOV R4,-(SP) 177220 010546 MOV R5,-(SP) ; Restore all registers 177222 BRA WAIT_BYTELP ****** Unknown opcode 177222 WAIT_BYTEOK: 177222 ??? PULS CC ; Pop flags ****** Unknown opcode 177222 WAIT_EXIT: 177222 000207 RTS PC 177224 177224 177224 ; Wait for data 177224 ; ============= 177224 ; On exit, A =byte 177224 ; F =Z byte=esc, NZ byte<>esc 177224 ; 177224 WAIT_DATA: 177224 LDA >RxSTATUS ****** Unknown opcode 177224 ANDA #RxRDY ****** Unknown opcode 177224 001777 BEQ WAIT_DATA ; Loop until data present 177226 LDA >RxDATA ; Fetch data ****** Unknown opcode 177226 020000 CMPA #esc ; Is it esc prefix? ****** Missing , 177230 000177 RTS ****** Missing register 177232 177232 177232 ; Decode escaped command 177232 ; ====================== 177232 ; On entry, A=command 177232 ; All registers can be trashed 177232 ; 177232 WAIT_COMMAND: 177232 005707 TSTA ****** Bad opcode suffix 177234 001405 BEQ WAIT_ERROR ; esc,&00 - error 177236 100411 BMI WAIT_TRANSFER ; esc,>&7F - data transfer 177240 177240 ; esc,1..127 - read a control block 177240 ; ================================= 177240 ; This depends on MOS calls storing control block address, 177240 ; which none of them do for this CPU. 177240 TFR A,B ; Move count to low byte of AB ****** Unknown opcode 177240 005007 CLRA ; Ensure AB is 8-bit value ****** Bad opcode suffix 177242 TFR D,Y ; Move count to Y ****** Unknown opcode 177242 LDX CTRL ; Point X to control block ****** Unknown opcode 177242 WAIT_LEN: 177242 004000 JSR WaitByte ; Wait for a byte ****** Missing , 177244 STA ,X+ ; Store the byte just read ****** Unknown opcode 177244 LEAY -1,Y ; Decrement count of bytes read ****** Unknown opcode 177244 001376 BNE WAIT_LEN ; Loop to read all bytes 177246 000177 RTS ; Return to WaitByte ****** Missing register 177250 177250 ; esc,&00 - error 177250 ; =============== 177250 WAIT_ERROR: 177250 LDS #ERRSTK ; Collapse stack ****** Unknown opcode 177250 LDX #ERRBLK ; Point to error buffer ****** Unknown opcode 177250 LDA #$3F ; SWI opcode ****** Unknown opcode 177250 STA ,X+ ; Store SWI opcode ****** Unknown opcode 177250 004000 JSR WaitByte ; Get error number ****** Missing , 177252 STA ,X+ ; Store error number ****** Unknown opcode 177252 FIRQ_R4LP: 177252 004000 JSR WaitByte ; Wait for byte of error string ****** Missing , 177254 STA ,X+ ; Store in error buffer ****** Unknown opcode 177254 001376 BNE FIRQ_R4LP ; Loop until terminating $00 received 177256 LDA ERRBLK+1 ****** Unknown opcode 177256 ORA ERRBLK+2 ; Check for error 0,"" ****** Unknown opcode 177256 LBEQ STARTUP ; Restart client ****** Unknown opcode 177256 LDX #ERRBLK+1 ; Point to error block after SWI opcode ****** Unknown opcode 177256 PSHS X ; Push error pointer onto stack ****** Unknown opcode 177256 000167 177774 JMP ERRJMP ; Jump to generate error ****** Undefined label 177262 177262 ; esc,&8n - Escape change 177262 ; ======================= 177262 WAIT_TRANSFER: 177262 020000 CMPA #$C0 ****** Missing , 177264 103021 BCC WAIT_START 177266 020000 CMPA #$A0 ****** Missing , 177270 103014 BCC WAIT_END 177272 020000 CMPA #$90 ****** Missing , 177274 103003 BCC WAIT_EVENT 177276 006007 RORA ****** Bad opcode suffix 177300 006007 RORA ; Move b0 into b7 ****** Bad opcode suffix 177302 STA >ESCFLG ; Store Escape flag ****** Unknown opcode 177302 000177 RTS ****** Missing register 177304 177304 ; esc,&9x - Event 177304 ; =============== 177304 WAIT_EVENT: 177304 004000 JSR WaitByte ; Get event Y parameter ****** Missing , 177306 TFR A,B ****** Unknown opcode 177306 005007 CLRA ****** Bad opcode suffix 177310 TFR D,Y ****** Unknown opcode 177310 004000 JSR WaitByte ; Get event X parameter ****** Missing , 177312 TFR A,B ****** Unknown opcode 177312 005007 CLRA ****** Bad opcode suffix 177314 TFR D,X ****** Unknown opcode 177314 004000 JSR WaitByte ; Get event A parameter ****** Missing , 177316 000167 177774 JMP [EVENTV] ; Dispatch event ****** Syntax error 177322 177322 ; esc,&Ax - Reserved 177322 ; ================== 177322 WAIT_END: 177322 020000 CMPA #$B0 ****** Missing , 177324 103736 BCS WAIT_EXIT ; &Ax - Return to WaitByte 177326 177326 ; esc,&Bx - End transfer 177326 ; ====================== 177326 LEAS 12,S ; Drop data from stack to fall ****** Unknown opcode 177326 ; ; out of WaitSave/WaitLoad loop 177326 WAIT_EXIT2: 177326 000177 RTS ; Return to WaitByte ****** Missing register 177330 177330 ; esc,&C0+ - Start transfer 177330 ; ========================= 177330 WAIT_START: 177330 PSHS A ; Save transfer type ****** Unknown opcode 177330 004000 JSR WaitByte ****** Missing , 177332 STA ADDRESS+0 ; Note - 6809 is big-endian ****** Unknown opcode 177332 004000 JSR WaitByte ; Get data address ****** Missing , 177334 STA ADDRESS+1 ****** Unknown opcode 177334 004000 JSR WaitByte ; Get data address ****** Missing , 177336 STA ADDRESS+2 ****** Unknown opcode 177336 004000 JSR WaitByte ; Get data address LSB ****** Missing , 177340 STA ADDRESS+3 ****** Unknown opcode 177340 LDX ADDRESS+2 ; Get transfer address ****** Unknown opcode 177340 PULS A ; Get transfer type back ****** Unknown opcode 177340 020000 CMPA #$D0 ****** Missing , 177342 103771 BCS WAIT_EXIT2 ; &Cx - set address 177344 020000 CMPA #$E0 ****** Missing , 177346 103405 BCS WAIT_CODE ; &Dx - enter code 177350 020000 CMPA #$F0 ****** Missing , 177352 103001 BCC WAIT_SAVE ; &Fx - save data 177354 WAIT_LOAD: 177354 004000 JSR WaitByte ; &Ex - load data ****** Missing , 177356 STA ,X+ ; Get byte, store it ****** Unknown opcode 177356 BRA WAIT_LOAD ; Loop until terminated ****** Unknown opcode 177356 WAIT_SAVE: 177356 LDA ,X+ ; Get byte ****** Unknown opcode 177356 004000 JSR SendByte ; Send it ****** Missing , 177360 004000 JSR BYTE_READ ; Poll input for termination ****** Missing , 177362 BRA WAIT_SAVE ; Loop until terminated ****** Unknown opcode 177362 WAIT_CODE: 177362 000167 177774 JMP ,X ; Jump directly to code ****** Too many operands 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 177366 ; Host->Client communication via interupts 177366 ; ======================================== 177366 Get_R1: 177366 113700 177760 MOVB @#TUBE1S,R0 ; Read Tube R1 status 177372 100375 BPL Get_R1 ; Loop until b7 set 177374 113700 177762 MOVB @#TUBE1,R0 ; Get byte from Tube R1 177400 000207 RTS PC 177402 177402 Get_R4: 177402 113700 177774 MOVB @#TUBE4S,R0 ; Read Tube R4 status 177406 100375 BPL Get_R4 ; Loop until b7 set 177410 113700 177776 MOVB @#TUBE4,R0 ; Get byte from Tube R4 177414 000207 RTS PC 177416 177416 177416 ; Interrupt handler 177416 ; ================ 177416 ; When Host sends a byte to R1 or R4 it generates a Client IRQ. 177416 ; Within the interupt handler PSW has been saved on the stack 177416 ; and further interrupts are disabled. 177416 ; 177416 IRQ: 177416 010046 MOV R0,-(SP) ; Save R0 177420 113700 177774 MOVB @#TUBE4S,R0 ; Read Tube R4 status 177424 100434 BMI IRQ_R4 ; If b7 set, R4 generated the interrupt 177426 113700 177760 MOVB @#TUBE1S,R0 ; Read Tube R1 status 177432 100403 BMI IRQ_R1 ; If b7 set, R1 generated the interrupt 177434 012600 MOV (SP)+,R0 ; Get R0 back 177436 000177 173306 JMP @USERIRQV ; DMB Something else generated the interrupt 177442 177442 ; Data present in Tube R1 generated an interrupt 177442 ; 177442 IRQ_R1: 177442 113700 177762 MOVB @#TUBE1,R0 ; Get byte from Tube R1 177446 100420 BMI IRQ_ESCAPE ; b7 set, change Escape state 177450 ; 177450 ; R1<&80 - Host event being passed to client 177450 ; Tube data: via R1: &00 Y X A 177450 ; 177450 010146 MOV R1,-(SP) ; Save R1 177452 010246 MOV R2,-(SP) ; Save R2 177454 004767 177706 JSR PC,Get_R1 ; Wait for byte via Tube R1 177460 010002 MOV R0,R2 ; Pass to R2 177462 004767 177700 JSR PC,Get_R1 ; Wait for byte via Tube R1 177466 010001 MOV R0,R1 ; Pass to R1 177470 004767 177672 JSR PC,Get_R1 ; Wait for byte via Tube R1 177474 004777 173244 JSR PC,@EVENTV ; DMB Call event vector 177500 012602 MOV (SP)+,R2 ; Restore R2 177502 NMI_DONE2: 177502 012601 MOV (SP)+,R1 ; Restore registers 177504 012600 MOV (SP)+,R0 177506 000002 RTI ; Return from interupt 177510 177510 ; R1>&7F - Host changing Escape state 177510 ; Tube data: via R1: flag, b7=1, b6=state 177510 ; 177510 IRQ_ESCAPE: 177510 004777 173220 JSR PC,@ESCV ; DMB Call Escape handler 177514 000526 BR NMI_DONE1 ; Restore and return from interrupt 177516 177516 ; Data present in Tube R4 generated an interupt 177516 ; 177516 IRQ_R4: 177516 113700 177776 MOVB @#TUBE4,R0 ; Get byte from Tube R4 177522 100023 BPL IRQ_DATA ; b7=0, jump to do data transfer 177524 177524 ; R4>&7F - Error occured 177524 ; Tube data: via R4: &FF, via R2: &00 err string &00 177524 ; 177524 010146 MOV R1,-(SP) ; Save R1 177526 004767 177424 JSR PC,WAIT_BYTE ; Wait for an initial byte from R2 177532 013701 172742 MOV @#ERRADDR,R1 ; Point to error buffer 177536 004767 177414 JSR PC,WAIT_BYTE 177542 110021 MOVB R0,(R1)+ ; Store error number 177544 IRQ_R4LP: 177544 004767 177406 JSR PC,WAIT_BYTE ; Wait for byte of error string 177550 110021 MOVB R0,(R1)+ ; Store in error buffer 177552 001374 BNE IRQ_R4LP ; Loop until terminating &00 received 177554 012601 MOV (SP)+,R1 ; Restore R1 177556 012600 MOV (SP)+,R0 ; Balance stack 177560 013700 172742 MOV @#ERRADDR,R0 ; Point to error block 177564 013716 172740 MOV @#ERRV,(SP) ; Replace return address with error handler 177570 000002 RTI ; Restore PSW and jump to error handler 177572 177572 ; R4<&80 - Data transfer 177572 ; Tube data: via R4: action ID address sync, via R3: data 177572 ; 177572 IRQ_DATA: 177572 ; R0=transfer type, (sp)=mainline R0 177572 ; 177572 010146 MOV R1,-(SP) ; Save R1 177574 010001 MOV R0,R1 ; Save transfer type in R2 177576 004767 177600 JSR PC,Get_R4 ; Wait for caller ID 177602 020127 000005 CMP R1,#5 ; Is transfer 'release'? 177606 001735 BEQ NMI_DONE2 ; Exit if 'release' 177610 004767 177566 JSR PC,Get_R4 ; Get data address byte 4 177614 110037 172773 MOVB R0,@#ADDR+3 177620 004767 177556 JSR PC,Get_R4 ; Get data address byte 3 177624 110037 172772 MOVB R0,@#ADDR+2 177630 004767 177546 JSR PC,Get_R4 ; Get data address byte 2 177634 110037 172771 MOVB R0,@#ADDR+1 177640 004767 177536 JSR PC,Get_R4 ; Get data address byte 1 177644 110037 172770 MOVB R0,@#ADDR+0 177650 113700 177772 MOVB @#TUBE3,R0 ; Clear Tube3 FIFO 177654 113700 177772 MOVB @#TUBE3,R0 177660 004767 177516 JSR PC,Get_R4 ; Get sync byte 177664 060101 ADD R1,R1 ; Index into NMI dispatch table 177666 016137 000100 000200 MOV NMIADDRS(R1),@#NMIVEC ; Set up NMI vector 177674 013700 172770 MOV @#ADDR,R0 ; Get transfer address 177700 020127 000014 CMP R1,#12 ; check transfer type 177704 103676 BCS NMI_DONE2 ; Jump to exit if not 256-byte transfers 177706 001412 BEQ NMI6 ; Jump with 256-byte write 177710 177710 ; Transfer 7 - Read 256 bytes from Host via R3 177710 ; -------------------------------------------- 177710 NMI7: 177710 012701 000400 MOV #256,R1 ; Prepare to transfer 256 bytes 177714 NMI7_LOOP: 177714 105737 177770 TSTB @#TUBE3S 177720 100375 BPL NMI7_LOOP ; Wait for Tube R3 ready 177722 113720 177772 MOVB @#TUBE3,(R0)+ ; Fetch byte from Tube R3 and store 177726 005301 DEC R1 ; Decrement count 177730 001371 BNE NMI7_LOOP ; Loop for 256 bytes 177732 000416 BR NMI_DONE 177734 177734 ; Transfer 6 - Send 256 bytes to Host via R3 177734 ; ------------------------------------------ 177734 NMI6: 177734 012701 000400 MOV #256,R1 ; Prepare to transfer 256 bytes 177740 NMI6_LOOP: 177740 105737 177770 TSTB @#TUBE3S 177744 100375 BPL NMI6_LOOP ; Wait for Tube R3 ready 177746 112037 177772 MOVB (R0)+,@#TUBE3 ; Fetch byte and send to Tube R3 177752 005301 DEC R1 ; Decrement count 177754 001371 BNE NMI6_LOOP ; Loop for 256 bytes 177756 NMI6_DONE: 177756 105737 177770 TSTB @#TUBE3S 177762 100375 BPL NMI6_DONE ; Wait for Tube R3 ready again 177764 105037 177772 CLRB @#TUBE3 ; Send final sync byte 177770 NMI_DONE: 177770 012601 MOV (SP)+,R1 ; Restore and return 177772 NMI_DONE1: 177772 010037 172770 MOV R0,@#ADDR ; Save updated transfer address 177776 012600 MOV (SP)+,R0 200000 000002 RTI 200002 200002 ; Transfer 3 - Read double bytes from host 200002 ; ---------------------------------------- 200002 NMI3: 200002 010046 MOV R0,-(SP) 200004 013700 172770 MOV @#ADDR,R0 ; Get transfer address 200010 113720 177772 MOVB @#TUBE3,(R0)+ ; Read two bytes 200014 113720 177772 MOVB @#TUBE3,(R0)+ 200020 000764 BR NMI_DONE1 200022 200022 ; Transfer 2 - Send double bytes to host 200022 ; -------------------------------------- 200022 NMI2: 200022 010046 MOV R0,-(SP) 200024 013700 172770 MOV @#ADDR,R0 ; Get transfer address 200030 112037 177772 MOVB (R0)+,@#TUBE3 ; Send two bytes 200034 112037 177772 MOVB (R0)+,@#TUBE3 200040 000754 BR NMI_DONE1 200042 200042 ; Transfer 1 - Read single byte from host 200042 ; --------------------------------------- 200042 NMI1: 200042 010046 MOV R0,-(SP) 200044 013700 172770 MOV @#ADDR,R0 ; Get transfer address 200050 113720 177772 MOVB @#TUBE3,(R0)+ ; Transfer byte from Tube 200054 000746 BR NMI_DONE1 200056 200056 ; Transfer 0 - Send single byte to Host 200056 ; ------------------------------------- 200056 NMI0: 200056 010046 MOV R0,-(SP) 200060 013700 172770 MOV @#ADDR,R0 ; Get transfer address 200064 112037 177772 MOVB (R0)+,@#TUBE3 ; Transfer byte to Tube 200070 000740 BR NMI_DONE1 200072 200072 ; Transfers 4,5,6,7 - Just acknowledge NMI 200072 ; ---------------------------------------- 200072 NMI_ACK: 200072 105037 177772 CLRB @#TUBE3 ; Store to Tube R3 to acknowledge NMI 200076 USERIRQ: ; Default unknown IRQ handler 200076 NULLIRQ: ; Default unused hardware vector handler 200076 000002 RTI 200100 200100 ; NMI transfer dispatch table 200100 ; --------------------------- 200100 NMIADDRS: 200100 000056 EQUW NMI0 ; Single byte to host 200102 000042 EQUW NMI1 ; Single byte from host 200104 000022 EQUW NMI2 ; Double byte to host 200106 000002 EQUW NMI3 ; Double byte from host 200110 000072 EQUW NMI_ACK ; Execute 200112 000072 EQUW NMI_ACK ; Release 200114 000072 EQUW NMI_ACK ; 256 bytes to host 200116 000072 EQUW NMI_ACK ; 256 bytes from host 200120 200120 200120 ; Spare space 200120 ; =========== 200120 072 EQUM TUBEIO-$ ; Spare space ****** Code overrun 177760 177760 177760 ; Tube I/O registers 177760 ; ================== 177760 000000 000000 000000 000000 000000 000000 000000 000000 EQUW 0,0,0,0,0,0,0,0 ; Tube registers 200000 Errors: 85