.SBTTL XDTE10 - driver for a DECsystem-10 through a DTE-20 ; This module replaces the DL10 module in the DN60 front-end ; program to use the DTE-20 on a 1090 configuration rather ; than the DTE-20 on the 2040 or the DL10 on a 1070. ; ; Note that the hardware is the same for TOPS-10 and TOPS-20, but ; the TOPS-10 version is driven by D60SER/D6SINT, which interface ; to the TOPS-10 DTESER module for the DN60. The TOPS-20 version ; is driven by the TOPS-20 module FESRV which interfaces to ; DTESRV. FESRV was enhanced for the DN60 project, but ; is not special-purpose as D60SER/D6SINT is. ; ; This module conditionally assembles to interface to FESRV on ; TOPS-20 by setting the switch FTFEDV to a nonzero value. ; ; XDTE10.P11 is a replacement for the old HDTE10.P11 to use the ;common protocol module XTENCM and its standard interface. .REPT 0 Things still to do, loose ends: o separate common code for XDTE10 and XDTE20 (and perhaps XDMC20) o move DLGONE to driver o change DLACKF to be .WORD 0 o move DTE save code to TRPINT .ENDR;.REPT 0 .REPT 0 COPYRIGHT (c) 1982,1981,1980, 1979 DIGITAL EQUIPMENT CORPORATION, maynard, mass. THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED. THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. .ENDR;.REPT 0 VDTE10=033 ;XDTE10 edit number VEDIT=VEDIT+VDTE10 ;DN60 total edit number .REPT 0 Revision History Edit Who Date What 5(31) KR 13-Oct-80 Strip out all common code, implement standard interface This new module is (very) loosely based on 4(30) of HDTE10. 5(32) RLS 28-JAN-81 Insert FTFEDV condtional code to create a TOPS-20/FESRV protocol driver. Primary difference is that the DN60 header comes as an indirect message and any data comes as a separate FE header,indirect transfer pair. Also, each indirect part must be explicitly ack'd. 5(33) RLS 12-JUN-81 Insert FTP5 conditional code to create TOPS-20 release 5 protocol. Primary differences are an expanded header(up to 8 words) and the exclusive use of direct mode transfers. The response header includes a 2 word device status and a 2 word line status. TENTSK may elect to return no data on a read dta fcn - handled by setting the queue size to zero and ringing the 10 doorbell. Similarly the deposit fcn doesn't even return a header...no header returned => no data returned. .ENDR;.REPT 0 .REPT 0 This section contains the DTE-20 driver and the queued protocol interface conforming to the RSX-20F specifications for communication between the PDP-11 and DECsystem-10. This module contains device-dependent code for talking to the TOPS-10 modules D60SER/D6SINT and DTESER. It calls a common protocol module, XTENCM.P11, via the standard interface, namely calling either WAKTEN to wake up the DL10/DTE task if the -10 has had some sort of error, or WAKFNC to provide a function and wake up the task if it has work to do. The following symbols defined in this module are referred to by the rest of the DN60 code: DLSTCS routine to store stopcode value DSPDLT once/tick timer code DSPDLS once/second timer code INITDL initialize -10 interface hardware DLRESP send back response to -10 BLECHI block transfer of input data BLECHO block transfer of output data BYTCHI byte transfer of input data BYTCHO byte transfer of output data DT10DS two word device status - FTP5 DT10LS two word line status - FTP5 The following symbols defined elsewhere are used by this module: T.HDR displacement of header in DL10/DTE task block T.FN function code T.RES result code T.DEV device number T.LIN line number T.LNG (word) length of data WAKTEN routine to wake DL10/DTE task WAKFNC routine to give a function to DL10/DTE task and wake it TENSLP routine to put DL10/DTE task to sleep waiting for EBTENI DLGONE cell set to -1 when -10 interface is dead, 0 when it is alive note, driver alone can set or clear it This module implements the DN60-DTE interaction as a single state machine, pieces of which are executed at both interrupt and non-interrupt level. The subroutine NXTPRT does the next part of the state machine; it has one of six interrupt conditions (I..xxx) set in cell INTCND. Each state examines interrupt conditions in a fixed order, and decides upon a new state to enter. The interrupt conditions are generated by both the DTE hardware and the DN60 software; the hardware conditions are to-10 done interrupt, to-11 done interrupt and doorbell interrupt. The interrupt handler generates another condition, TGHA doorbell, if valid examine is not on in the status word from the -10 on a doorbell. The remaining two interrupt conditions are 1) response ready (generated by DLRESP which the common module calls when it has finished building the reply to a request) and 2) TGHA timer expired, which means the once a second code has decremented the TGHA timer to zero. .ENDR;.REPT 0 .SBTTL Symbol definitions ;Parameters .IIF NDF,FTP5,FTP5=0 ;default to version 4 rpotocol .IIF NE,FTP5,FTFEDV=0 ;if version 5 protocol, can't have 4 .IIF NDF,FTFEDV,FTFEDV=0 ;default to no FE device interface .IIF NE,FTFEDV,MAXDAT=376 ;FE device will only xfer small amount .IIF NDF,MAXDAT,MAXDAT=^D5*CHDATL ;max data transferred in a single request .IIF NDF,TGHMAX,TGHMAX=5. ;max number of seconds to wait for TGHA .IIF NDF,DLYPRM,DLYPRM=0 ;make no DTE delay default ;Define more mnemonic interrupt bits I..10D=TS.XNT ;-10 done I..11D=TS.ETD ;-11 done I..DBL=TS.XEE ;-11 doorbell I..TGH=TS.MPE ;TGHA doorbell (software bit) I..RSP=TS.EPE ;DLRESP (software bit) I..TMO=TS.XER ;TGHA timer expire (software bit) ;(The hardware error bits used to define the software interrupt conditions ;are guaranteed never to be on during the state machine, as the interrupt ;code traps them before dispatching to the state machine.) ;DN60 function definitions DF.RED=1. ;READ DATA INTO THE PDP-10 DF.WRT=2. ;WRITE DATA FROM THE PDP-10 DF.RDS=3. ;READ DEVICE STATUS DF.WDC=4. ;WRITE DEVICE COMMAND DF.RLS=5. ;READ LINE STATUS DF.WLC=6. ;WRITE LINE COMMAND DF.RPS=7. ;READ PORT STATUS DF.WPC=8. ;WRITE PORT COMMAND DF.EXA=9. ;examine function DF.DEP=10. ;deposit function DF.MAX=DF.DEP ;max fcn code ;NOTE: Even valued functions have indirect data from the ten and odd valued ; functions do not(they send indirect data to the ten). This fact is used ; in FE device service to determine whether anything follows the FEH from ; the ten. Non-FE service just tests the indirect data flag in DT11FN. ;The driver needs to know DF.EXA and DF.DEP, since it fulfills them at interrupt ;level instead of dispatching to the task. .SBTTL DTE20 HARDWARE BITS TE.BRL= 5 ;(?)DTE bus request level TE.LVL= PR.TEN ;PROCESSOR LEVEL FOR DTE20 INTERRUPTS TE.VEC=774 ;VECTOR FOR DTE20 INTERRUPTS TE.DYC=0 ;DELAY COUNTER TE.XW3=2 ;DEPOSIT OR EXAMINE WORD 3 TE.XW2=4 ;DEPOSIT OR EXAMINE WORD 2 TE.XW1=6 ;DEPOSIT OR EXAMINE WORD 1 TE.XA1=10 ;TEN ADDRESS WORD 1 TS.DEP=B12 ;DEPOSIT TS.POF=B11 ;EXAMINE/DEPOSIT PROTECT OFF TS.PEX=B15 ;PHYSICAL EXAMINE TE.XA2=12 ;TEN ADDRESS WORD 2 TE.XBC=14 ;TO-10 BYTE COUNT (?) TE.EBC=16 ;TO-11 BYTE COUNT TS.IFB=B15 ;I FLIPFLOP BIT TS.ZST=B14 ;ZSTOP TS.EBM=B13 ;TO 11 BYTE MODE TE.XAD=20 ;TO-10 PDP-11 MEMORY ADDRESS TE.EAD=22 ;TO-11 PDP-11 MEMORY ADDRESS TE.XDT=24 ;TO-10 PDP-11 DATA WORD TE.EDT=26 ;TO-11 PDP-11 DATA WORD TE.DG1=30 ;DIAGNOSTIC WORD 1 TE.DG2=32 ;DIAGNOSTIC WORD 2 TS.RST=B6 ;RESET DTE20 TE.STW=34 ;STATUS WORD TS.XNT=B15 ;TO-10 NORMAL TERMINATION TS.XTS=B14 ;TO-10 NORMAL TERMINATION STATUS TS.XER=B13 ;TO-10 ERROR TERMINATION (AND STATUS) TS.XEC=B12 ;CLEAR TO-10 ERROR TERMINATION TS.XEE=B11 ;10 REQUESTED -11 INTERRUPT TS.RES=B11 ;REQUEST -11 STATUS TS.EIS=B10 ;10 REQUESTS 11 INTERRUPT STATUS TS.MPE=B9 ;11 MEMORY PARITY ERROR TS.EEX=B8 ;11 REQUESTED 10 INTERRUPT TS.ETD=B7 ;TO-11 TRANSFER DONE TS.ENT=B6 ;TO-11 NORMAL TERMINATION TS.EEE=B5 ;11 INTERRUPT ENABLE TS.EPE=B4 ;E-BUS PARITY ERROR TS.RM=B3 ;RESTRICTED MODE TS.DEI=B3 ;DISABLE -11 INTERRUPT TS.XDN=B2 ;DEPOSIT/EXAMINE DONE TS.EET=B1 ;TO-11 ERROR TERMINATION (AND STATUS) TS.IEN=B0 ;INTERRUPTS ENABLED TS.CET=B0 ;CLEAR TO-11 ERROR TERMINATION TE.DG3=36 ;STATUS WORD 3 TS.TBM=B0 ;TO TEN BYTE MODE .SBTTL RSX-20F queued protocol definitions ;THIS DEFINES THE DEVICE QUEUE POINTERS AND FUNCTION CODES ; FOR THE RSX-20F QUEUED PROTOCOL. ; DEVICE QUEUE POINTERS DLDCTY =1 ;DEVICE CODE FOR CTY DLDL11 =2 ;DEVICE CODE FOR DL11 DLDH11 =3 ;DEVICE CODE FOR DH11 (1) DLDDLS =4 ;DEVICE CODE FOR DATA LINE SCANNER (1) DLDLPT =5 ;DEVICE CODE FOR LPT DLDCDR =6 ;DEVICE CODE FOR CDR DLDCLK =7 ;DEVICE CODE FOR CLOCK DLDPFE =10 ;PSEUDO DEVICE FOR FE DLDDAS =12 ;DN61 DEVICE CODE DLDCPU =200 ;PSEUDO DEVICE PDP10 CPU DLDKLE =201 ;KL ERROR PSEUDO DEVICE ; TO ELEVEN QUEUE ENTRY ; FUNCTION CODE DEFINITIONS DTFRQD =1 ;REQUEST DEVICES DTFHAD =2 ;HERE ARE DEVICES DTFSTR =3 ;STRING DATA DTFLNC =4 ;LINE/CHARACTER DATA DTFRDS =5 ;RETURN DEVICE STATUS DTFSDS =6 ;SET DEVICE STATUS DTFHDS =7 ;HERE IS DEVICE STATUS DTFDES =10 ;DEVICE ERROR STATUS DTFRTD =11 ;RETURN TIME OF DAY DTFHTD =12 ;HERE IS TIME OF DAY DTFFOD =13 ;FLUSH OUTPUT DEVICE QUEUE DTFSNA =14 ;SEND ALL DTFTDU =15 ;DEVICE DIAL UP DTFTHU =16 ;DEVICE HANG UP DTFSAK =17 ;ACKNOWLEDGE DEVICE DONE DTFXOF =20 ;X-OFF (TTY ONLY) DTFXON =21 ;X-ON (TTY ONLY) DTFSTS =22 ;SET TTY SPEED DTFSLA =23 ;set line allocation DTFBTP =24 ;11 REBOOT WORD DTFAKA =25 ;ACK ALL DTFSPT =26 ;START/STOP LINE DTFEDR =27 ;ENABLE/DISABLE REMOTES DTFLDR =30 ;LOAD LP RAM DTFLDV =31 ;LOAD LP VFU DTFDAS =32 ;DN60 FUNCTION DATA DTFFNM =33 ;1 GREATER THAN MAX FUNCTION .SBTTL DTE20 COMMUNICATION AREA OFFSETTS (WORD NAMES) ;The comm region consists of a circular list of blocks - one for each processor ;communicating with each other. Each block is composed of a base area which has ;some info about the "owning" processor and a series of "TO" blocks, one for ;each processor to which the owning processor communicates. In theory, the size ;of each area may vary but only in 8 36-bit word units. ;A processor sends status info to another processor by setting the data in ;his owned "TO" block for that processor and,similarly, reads info for himself ; from that processor by looking at that processor's "TO" block for himself. ;The 11 addresses data in the comm region relative to an address space that ;is individually relocated for the particular dte through which the 11 examines ;the 10's memory. Immediately preceeding the comm region is a series of single ;words, one for each connected processor. The relative address zero points at ;the particular word associated with the processor who is looking at 10 memory. ;This word contains the processor's own identifying number and the offset, ;relative to the beginning of the comm region, of the processor's own area. ;The beginning of the comm region is located in the processor's address space ; at +1. Thus the address of the processor's own area is ;located at "offset"++1. ;The 11 examines/deposits 36 bit words in 10 memory - these are formatted in ;the 11 as three consective 16 bit words: ; word 0 - low order 4 bits - 10 word bits 0-3 ; word 1 - 10 word bits 4-19 ; word 2 - 10 word bits 20-35 ;11's processor word - relative address 0 ; xam word 1 ;must be zero ; xam word 2 ; high byte ;processor number for me ; low byte ; unused ; xam word 3 ; offset to my area relative to beg of ; comm region ;processor's own area ; base block offsets PBPID=0 ;PROCESSOR IDENTIFICATION WORD ; XAM WORD 1 PB.TEN=10 ;this processor is a 10 PB.VER=7 ;mask for comm version number ; xam word 2 ; high byte = protocol version being used ; low byte PB.NPR=370 ;mask for number of processors in this area PB.SIZ=7 ;mask for size of base area(in 8 word units) ; xam word 3 ; word = processor name PBPNA=1 ;POINTER TO COMM AREA OF NEXT PROCESSOR (CIRC LIST) PBCPS=2 ;CLOCK CPS COUNT PBTOD=3 ;TIME OF DAY PBDAT=4 ;DATE PBPW1=5 ;keepalive count PBPW2=6 ;PROCESSOR STATUS WORD2 PBPW3=7 ;PROCESSOR STATUS WORD3 PBPW4=10 ;PROCESSOR STATUS WORD4 PBPW5=11 ;PROCESSOR STATUS WORD5 PBPW6=12 ;PROCESSOR STATUS WORD6 PBPW7=13 ;PROCESSOR STATUS WORD7 PBPW10=14 ;PROCESSOR STATUS WORD10 PBPW11=15 ;PROCESSOR STATUS WORD11 PBPW12=16 ;PROCESSOR STATUS WORD12 PBPW13=17 ;PROCESSOR STATUS WORD13 PBASIZ=20 ;size of base area = offset to 1st TO block ; TO block offsets TOPID=0 ;FOR PROCESSOR IDENTIFICATON WORD ; xam word 1 TO.TEN=10 ;this connection is to a 10 TO.DTE=4 ;a DTE connects these two processors TO.DTN=3 ;mask for the DTE number ; xam word 2 ; high byte unused ; low byte TO.PRO=370 ;mask for protocol in use: 0=RSX20F(TOPS-20 version 4 ; 1=MCB ; 2=DN60(TOPS-20 version 5) TO.SIZ=7 ;mask for size of this TO block ; xam word 3 ; word = processor number that this block is "TO" TOPCA=1 ;POINTER TO COMM AREA OF THE PROCESSOR ASSOC WITH THIS BLOCK ; xam word 1 - unused ; xam wrod 2 - unused ; xam word 3 ; word = offset to "TO" processor's own area relative to beginning of comm region TOSTAT=2 ;COMMUNICATION STATUS WORD ; xam word 1 TO.PFL=10 ;power fail indicator TO.REL=4 ;reload 11 indicator TO.INI=2 ;MCB,DN60 protocol initializing flag TO.VEX=1 ;valid examine flag - guaranteed to be set ; xam word 2 TO.QP=100 ;queued protocol in use TO.FWD=4 ;do a word mode xfer(16 bit) TO.IND=2 ;indirect transfer TO.IT=1 ;xfer in progress from me to him ; xam word 3 ; high byte = 10 queue count ; low byte = 11 queue count TOXFSZ=3 ;queue size word ; xam word 1 - unused ; xam word 2 - unused ; xam word 3 ; word(12 bits) = numbers of bytes in this transfer ;remaining 4 words are not relavent to the 11 .SBTTL Macro definitions ;Macros to disable and enable interrupts from the dte .MACRO DTEOFF MOV #TS.DEI,TE.STW(R5) ;disable dte interrupts .ENDM .MACRO OFFDTE MOV DTEBAD,-(SP) ADD #TE.STW,(SP) MOV #TS.DEI,@(SP)+ ;disable dte interrupts .ENDM .MACRO DTEON MOV #TS.EEE,TE.STW(R5) ;enable dte interrupts .ENDM .MACRO ONDTE MOV DTEBAD,-(SP) ADD #TE.STW,(SP) MOV #TS.EEE,@(SP)+ ;enable dte interrupts .ENDM ;Macro to declare next state in state machine ;Call NXTINT to define following code as next state ;or NXTINT #name to define "name" as next state ;or NXTINT cell to define contents of cell as next state .MACRO NXTINT ADR,?TAG .IF B, MOV #TAG,NXTPC GOBACK TAG: .IFF;.IF B, MOV ADR,NXTPC .ENDC;.IF B, .ENDM NXTINT ;Macro to go back to state dispatch level .MACRO GOBACK .IF NE,DTBUG JMP NXTCN1 ;try to schedule another condition .IFF;.IF NE,DTBUG JMP NXTCND .ENDC;.IF NE,DTBUG .ENDM GOBACK ;Macro to define state entry block for a state -- must be used at state entry point ;Contains the interrupt bits that cause 11err state, the bits that cause ;10err state, followed by pairs of masks and dispatch addresses (terminated ;by a zero word). .MACRO INTTYP ERR11,ERR10,ARG,?TAG STBDSP=. E10DSP=.-STBDSP .WORD ERR10 ;means -10 has done protocol wrong and ; should be considered down STBDSP=.-STBDSP .IRP DISP, DSPENT DISP ;generate bit mask, dispatch address .ENDR;.IRP DISP, .WORD 0 TAG: .ENDM INTTYP ;Macro to define dispatch entries within state entry block .MACRO DSPENT BITS,ADR .WORD BITS,ADR .ENDM DSPENT ;Macro for call that only stores PC (i.e. is really a JMP) .MACRO XCALL ADR CALL ADR .ENDM XCALL ;Macro to test carry and XCALL an error routine if set .MACRO IFCRY WHERE,?TAG BCC TAG XCALL WHERE TAG: .ENDM IFCRY ;Macro to test equal and XCALL an error routine if not set .MACRO IFNE WHERE,?TAG BEQ TAG XCALL WHERE TAG: .ENDM IFNE .MACRO IFEQ WHERE,?TAG BNE TAG XCALL WHERE TAG: .ENDM IFEQ ;Macro to do DTE examine ;Call EXAM disp for examine,dest to examine and copy to dest ; EXAM disp for examine,, to examine and leave in TE.XW1-3 .MACRO EXAM LOWADR,DEST,TAG,?TAG1 CLR TE.XA1(R5) ;set examine EVA, protectin off, bits 13-19 0 MOV LOWADR,TE.XA2(R5) ;set low order address, start examine CALL DLWEDN ;wait for examine done to set BCC TAG1 CLR TE.XA1(R5) ;set examine EVA, protectin off, bits 13-19 0 MOV LOWADR,TE.XA2(R5) ;set low order address, start examine CALL DLWEDN ;wait for examine done to set BCS TAG ;is timeout, don't store value TAG1: .IF NB, MOV TE.XW1(R5),DEST ;store first word of result (KL bits 0-3 ; right justified) MOV TE.XW2(R5),DEST+2 ;store bits 4-19 MOV TE.XW3(R5),DEST+4 ;store bits 20-35 .ENDC;.IF NB, .IIF NE,FTRACE, MFPS -(SP) TRACE TRCDTE, .IIF NE,FTRACE, MTPS (SP)+ .ENDM EXAM ;Macro to do DTE deposit ;Call DEPO disp for deposit,source to copy source and deposit ; DEPO disp for deposit,, to use contents of TE.XW1-3 .MACRO DEPO LOWADR,SRC,TAG,?TAG1 .IF NB, MOV SRC,TE.XW1(R5) ;get first word (KL bits 0-3) MOV SRC+2,TE.XW2(R5) ;get second word (bits 4-19) MOV SRC+4,TE.XW3(R5) ;get third word (bits 20-35) .ENDC;.IF NB, TRACE TRCDTE, MOV #TS.DEP,TE.XA1(R5) ;set deposit EVA, protection on, bits 13-19 0 MOV LOWADR,TE.XA2(R5) ;move low order address and start deposit CALL DLWEDN ;wait for done flag BCC TAG1 MOV #TS.DEP,TE.XA1(R5) ;set deposit EVA, protection on, bits 13-19 0 MOV LOWADR,TE.XA2(R5) ;move low order address and start deposit CALL DLWEDN ;wait for done flag BCS TAG ;carry will be set if -10 times out TAG1: .ENDM DEPO .SBTTL Data storage ; THE DTE DATA BASE. DTIDBL: .WORD 0 ;KEEP DOORBELL INTERRUPT COUNT HERE DTIXDN: .WORD 0 ;KEEP TEN DONE INTERRUPT COUNT HERE DTIEDN: .WORD 0 ;ELEVEN DONE INTERRUPT COUNT HERE DTEPCA: .WORD 0 ;ADDRESS OF PRIV OFFSET TABLE ENTRY DTPSTA: .WORD 0 ;OUR DTE20 STATUS WORD AND DTEBAD: .WORD 0 ; DTE ADDRESS (INITTED AT STARTUP) DTEDTO: .WORD 0 ;DEPOSIT/EXAMINE TIMEOUT ;ALSO USED FOR STORING ;INTERRUPT VECTOR LOCATION ;IN CHK11.P11 MODULE DLACKF: .WORD 0 ;NON-ZERO WHEN IN PRIMARY PROTOCOL DTQSTA: ;ZEROED AT STARTUP DT11ST: .BYTE 0 ;STATE OF TO-11 MECHANISM DT10ST: .BYTE 0 ;AND OF TO-10 DT10AK: .WORD 0 ;IF NON-ZERO, ED DATA EXPECTED AND MUST BE ACKED DTPTCT: .WORD 0 ;COUNT OF MESSGES PUNTED ; POINTERS TO COMMUNICATIONS AREA DLCMBS: .WORD 0 ;BASE OF COMMUNICATION AREA DLMYPN: .WORD 0 ;MY PROCESSOR NUMBER DLDPOF: .WORD 0 ;DEPOSIT OFFSET FROM EXAMINE ; PROCESSOR IDENTIFICATION TABLE ; DTPIDT FORMAT: ; 5 WORDS/ENTRY ; 16 ENTRYS IN THE TABLE ONE FOR EACH PROCESSOR IN COMMUNICATION ; COMMUNICATION NUMBERS ARE LIMITED TO THE RANGE 0-15. ; (PROCESSOR 0) DTPIDT: ADDRESS OF DTE20 TO ACCESS THIS PROCESSOR DTENM=0 ; (PROCESOR 0) ADDRESS TO COMMUNICATE TO PROCESSOR 0 DTEMYN =2 ; (PROCESSOR 0) ADDRESS TO COMMUNICATE TO PROCESSOR 0 (WRITE) DTDMYN =4 ; (PROCESSOR 0) ADDRESS FROM GENERAL DTEHSG =6 ; (PROCESSOR 0) ADDRESS FROM SPECIFIC DTEHSM =10 ; (PROCESSOR 1) ADDRESS OF DTE20 TO USE TO ACCESS THIS PROCESSOR ; ........... DTPIDT: .NLIST .REPT 16.*5. .WORD 0 .ENDR .LIST DTXTM3: .WORD 0 ;EXAMINE WORD 3 (TEMP STORAGE) TO BE DTXTM2: .WORD 0 ;EXAMINE WORD 2 -USED ONLY BECAUSE EXAMINE DTXTM1: .WORD 0 ;EXAMINE WORD 1 - OR DEPOSIT ; MAY FAIL AND ; MUST BE REDONE DTSTT: .WORD 0 ;TO 10 STATUS .WORD 0 .WORD 0 DTQCNT =DTSTT+4 ;BOTH OF BELOW DT10QC =DTSTT+4 ;TO 10 QUEUE COUNT DT11QC =DTSTT+5 ;TO 11 QUEUE COUNT DTKPLV: .WORD 0 ;last successful 11 keep alive NXKPLV: .WORD 0 ;next time we really want to do one .IF NE,DEBUG DTESAV: .NLIST .REPT 20 ;FOR SAVING DTE20 REGISTERS .WORD 0 .ENDR .LIST .ENDC ;.IF NE,DEBUG ;Queued protocol header input buffer DT11HD: .IF EQ,FTP5 .WORD 0 ;count of bytes in this message DT11FN: .WORD 0 ;queued protocol function code DT11DV: .WORD 0 ;queued protocol device number .WORD 0 ;unused .IF NE,FTFEDV DT11UC: .WORD 0 ;FE#,,BYTE COUNT TO FOLLOW .ENDC ;DEFINED ONLY FOR FE DEVICES .ENDC ;.IF EQ,FTP5 D11HDL=.-DT11HD ;length of to 11 direct header DT11DF: .WORD 0 ;DN60 function code DT11AD: .WORD 0 ;address (exam/depo) or DN60 line,,dev DT11DT: .WORD 0 ;data (deposit) or length of indirect msg .IF NE,FTP5 DT11A3: .WORD 0 ;arg3 - unused DT11A4: .WORD 0 ;arg4 - unused DT11A5: .WORD 0 ;arg5 - unused DT11A6: .WORD 0 ;arg6 - unused DT11A7: .WORD 0 ;arg7 - unused .ENDC ;IF NE,FTP5 D11DFL=.-DT11DF ;length of to 11 DN60 header .IF NE,FTFEDV DTACKR: .WORD 0 ;ack flag - nonzero => ack must be sent ; THIS HEADER IS FOR SENDING "ACK" TO THE TEN ; EACH TIME 11 RECEIVED INDIRECT DATA. DTAKHD: .WORD 0 ;NO OF BYTES IN THIS HEADER DTAKFN: .WORD 0 ;ACK FUNCTION CODE DTAKDV: .WORD 0 ;FE DEVICE CODE .WORD 0 ;unused DTAKUC: .WORD 0 ;HAS FE# RIGHT JUSTIFIED .ENDC ;.IF NE,FTFEDV ;Queued protocol header output buffer .IF NE,FTP5 RSPSIZ: .WORD 0 ;size of response header .ENDC ;IF NE,FTP5 DT10HD: .IF EQ,FTP5 .WORD 0 ;count of bytes in this message DT10FN: .WORD 0 ;queued protocol function code (must be 32) DT10DV: .WORD 0 ;queued protocol device number (must be DLDDAS) .WORD 0 ;unused .IF NE,FTFEDV ;DEFINED ONLY FOR FE DEVICES DT10UC: .WORD 0 ;FE#,,BYTE COUNT TO FOLLOW .ENDC ;NE FTFEDV .ENDC ;.IF EQ,FTP5 D10HDL=.-DT10HD ;length of to ten direct header DT10DF: .WORD 0 ;DN60 function code DT10AD: .WORD 0 ;address (exam/depo) or DN60 line,,dev DT10DT: .WORD 0 ;data (deposit) or length of indirect msg .IF NE,FTP5 DT10A3: .WORD 0 ;return val3 - unused DT10DS: .WORD 0,0 ;device status DT10LS: .WORD 0,0 ;line status .ENDC ;IF NE,FTP5 D10DFL=.-DT10DF ;length of to ten dn60 header ;Queued protocol comm-region status TCSTFX: .BLKW 3 ;status word from -10 ;Queued protocol data buffers (indirect part) INBUF: ;input data buffer OUTBUF: ;output data buffer .BLKB MAXDAT ;Buffer control cells (used by BLECHI, BLECHO, BYTCHI, BYTCHO) OUTPTR: .WORD 0 ;current output pointer OUTCTR: .WORD 0 ;bytes left to go till output overflow INPPTR: .WORD 0 ;current input pointer INPCTR: .WORD 0 ;bytes left to go till input runs out ;TGHA Control cells TGHCNT: .WORD 0 ;0 means TGHA not running, > 0 means seconds ; before TGHA timer expires ;State machine dispatch information NXTPC: .WORD 0 ;next state address TNXTPC: .WORD 0 ;copy of NXTPC while TGHA is running .IF NE,DTBUG WITHIN: .WORD 0 ;indicate we are within the state machine .ENDC;.IF NE,DTBUG ;State machine interrupt conditions INTCND: .WORD 0 ;interrupt conditions active at current ; entry into state machine ;State machine stack .IIF NDF,STKLEN,STKLEN=40. ;default number of words of stack INTGW: .WORD 0 ;guard word for overwriting stack .BLKW STKLEN ;body of stack INTSTK: ;address for start of stack + 2 STATSP: .WORD 0 ;current state machine stack pointer INTSP: .WORD 0 ;current caller (of state machine) stack pointer ;-10 link state information ;DLGONE: .WORD 0 ;0 when talking, -1 when down ;actually defined elsewhere PROTER: .WORD 0 ;when DLGONE = -1, 0=ten down, 1=protocol ; error ;Debugging information .IF NE,DTBUG LSTTWC: .BLKW STKLEN ;copy of stack for last caller of TENDWN SAVSTK: .WORD 0 ;tag for start of saved stack and pointer ; save area LSTINT: .WORD 0 ;interrupt conditions on last running of state ; machine INTFLG: .WORD 0 ;flag that we are within DTE interrupt .ENDC;.IF NE,DTBUG .SBTTL DTE initialization INITDL: ;initialize DTE communications SAVE ;save standard hardware register PIOFF MOV DTEBAD,R5 ;get hardware address TST DLACKF ;are we in primary protocol? BEQ 14$ ;no, just try to start it MOV #50,R2 ;number of tries MOV #TS.RST,TE.DG2(R5) ;yes, reset DTE-20 10$: CALL CHKTEN ;check on -10's health BCS 14$ ;dead, go try to start it up again SOB R2,10$ ;keep trying till count exhausted .IF NE,DTBUG INC #0 .ENDC;.IF NE,DTBUG 99$: PION RESTOR ;restore registers RETURN 14$: CLR DLACKF ;indicate out of primary protocol MOV #TS.EEX,TE.STW(R5) ;ring -10 doorbell to wake it up MOV #50,R2 ;times to try 15$: CALL CHKTEN ;see if up now BCC 19$ ;yes, mark it up SOB R2,15$ ;keep trying .IF NE,DTBUG INC #0 .ENDC;.IF NE,DTBUG BR 99$ ;give up if takes too long 19$: TRACE TRCPRO, MOV #-1,DLACKF ;mark primary protocol runnning CLR DLGONE ;mark -10 up CALL DLINDB ;setup DTE block(s) BCS 21$ ;if error, die CALL INISTA ;initialize state machine BR 99$ ;return 21$: ;here because -10 looked up but was ; really down CLR DLACKF ;flag primary protocol not running MOV #-6,DLGONE ;note ten is down BR 99$ ; and exit .SBTTL Stopcode processing DLSTCS: ;here on stopcode to ask -10 to reload us TST DLGONE ;see if -10 alive BNE 99$ ;no, no chance at asking him to reload either .IF NE,DTBUG TST STPFLG ;have we been here once? BEQ 5$ ;no, continue HALT ;just die 5$: MOV #-1,STPFLG .ENDC;.IF NE,DTBUG SAVE MOV DTEBAD,R5 MOV DTEPCA,R3 PIOFF CALL SAVDTE ;save DTE registers on stopcode BIS #TO.REL,DTSTT ;set reload bit CALL SETSTS ;send status to -10 BCS 90$ MOV #TS.EEX,TE.STW(R5) ;and ring -10 doorbell 90$: PION RESTOR 99$: RETURN .IIF NE,DTBUG,STPFLG: .WORD 0 .SBTTL DTE-20 interrupt .REPT 0 This routine runs a single-valued state machine (instead of one for input and one for output as the old code did) at interrupt level; any incorrect interrupt causes the driver to inform the common code that the -10 is down. The events that may trigger a change of state are: 1) receipt of a normal doorbell interrupt (i.e. with valid examine set) 2) receipt of a to-11 done interrupt 3) receipt of a to-10 done interrupt 4) receipt of a TGHA doorbell interrupt (i.e. with valid examine not set) 5) call to DLRESP by DL10/DTE task to send a response back to the -10 6) TGHA timer expiration The major states and their processing (in parenthesis) and state transitions (F: means failure, S: means success) are: idle between transactions 4=>(set TGHA flag and timer)wfg-idle 1=>(setup to read header)F:wfg-wfeh,S:wfeh 2,3=>-10 error 5,6=>-11 error wfeh waiting to read header 4=>(set TGHA flag and timer)wfg-wfeh 2=>(test for indirect function)S:wfeb,F:(check for examine/deposit)F:(wake DL10/DTE task)wftsk, S:(build answer header, ring -10 doorbell, send header)F:wsth,S:wfth 1,3=>-10 error 5,6=>-11 error wfeb waiting for indirect 4=>(set TGHA flag and timer)wfg-wfeb doorbell 1=>(setup to read data)F:wfg-wfeb,S:wfed 2,3=>-10 error 5,6=>-11 error wfed waiting to read data 4=>(set TGHA flag and timer)wfg-wfed 2=>(wake DL10/DTE task)wftsk 1,3=>-10 error 5,6=>-11 error wftsk waiting for common 4=>(set TGHA flag and timer)wfg-wftsk module to respond 1,2,3=>-10 error 5=>(ring -10 doorbell, send header)F:wsth,S:wfth 6=>-11 error wsth waiting to send -10 4=>ignore doorbell again 1=>(abort response)wfeh 6=>(ring -10 doorbell, send header)F:-10 down,S:wfth 2,3=>-10 error 5=>-11 error wfth waiting for -10 done 4=>(set TGHA flag and timer)wfg-wfth for header 3=>(check for indirect)F:idle,S:(ring -10 doorbell, send data)F:wstd,S:wftd 1=>(check for indirect)F:wfeh,S:-10 error 2=>-10 error 5,6=>-11 error wstd trying to resend -10 4=>ignore doorbell for data 1=>(abort response)wfeh 6=>(ring -10 doorbell, send data)F:-10 down,S:wftd 2,3=>-10 error 5=>-11 error wftd waiting for -10 done 4=>(set TGHA flag and timer)wfg-wftd for data 3=>idle 1=>(abort response)wfeh 2=>-10 error 5,6=>-11 error wfg-xx waiting for TGHA 1,2,3=>(clear TGHA flag and timer;pass interrupt on)xx 4=>ignore 6=>(clear TGHA flag and timer;check for valid examine) F:-10 down,S:xx 5=>-11 error -10 err illegal protocol (set DLGONE to -1, wake DL10/DTE task)idle -10 dwn -10 not responding (set DLGONE to -1, wake DL10/DTE task)idle -11 err logic error in FE trap .ENDR;.REPT 0 DT.INT: INTSKD SAVE ;save a couple of registers CLKOFF ;turn off clock so it won't screw us MOV DTEBAD,R5 ;copy base address into standard register DTEOFF MTPS #PR.TEN*40 ;set ten interface priority level .IF NE,DTBUG TST INTFLG ;are we already within interrupt? BEQ 2$ ;no, continue MOV TE.STW(R5),#0 ;yes, remember current status STOPCD DTE ; and die 2$: MOV #-1,INTFLG .ENDC;.IF NE,DTBUG MOV DTEPCA,R3 ;get DTE table address MOV TE.STW(R5),R0 ;get interrupt bits TRACE TRCDTE,R0 .IF NE,DTBUG MOV R0,LSTINT ;save last interrupt .ENDC;.IF NE,DTBUG BIT #TS.XER!TS.MPE!TS.EPE!TS.EET,R0;check for hard errors BNE 20$ ;yes, mark -10 down BIT #TS.ETD!TS.XNT!TS.XEE,R0;check useful bits .IF NE,DTBUG BNE 1$ ;if some on, skip following INC #0 ;count how often it happens MOV R0,#0 ;and record status bits BR 99$ ;ignore interrupt 1$: .IFF;.IF NE,DTBUG BEQ 99$ ;exit if none on .ENDC;.IF NE,DTBUG MOV R0,INTCND ;store interrupt conditions BIC #^C,INTCND;only leave on ones we handle BIT #I..DBL,R0 ;is it a doorbell? BEQ 10$ ;no, just do normal dispatch CALL GETSTS ;get status word from -10 BCS 9$ ;if no examine done, -10 is down TST TCSTFX ;check valid examine BNE 10$ ;yup, do normal dispatch 9$: BIC #I..DBL,INTCND ;no, call this TGHA doorbell BIS #I..TGH,INTCND ; instead of normal doorbell 10$: CALL CLRINT ;clear hardware interrupt conditions CALL NXTPRT ;do next part of state machine 99$: MTPS #BR7 ;allow us to get out of here DTEON RESTOR ;restore registers .IIF NE,DTBUG, CLR INTFLG ;no longer within interrupt CLKON ;turn the clock back on RTI ;dismiss interrupt 20$: CALL DTEDWN ;mark -10 down BR 99$ ; and dismiss interrupt DTEDWN: ;subroutine to declare -10 down when ;not in state machine TRACE TRCPRO,<(SP),NXTPC,JIFCLK> .IF NE,DEBUG BIT #TRCTER,TRCHLT BEQ 1$ STOPCD TER 1$: .ENDC;.IF NE,DEBUG CALL INISTA ;initialize state machine CLR PROTER ;not due to protocol error MOV #-1,DLGONE ;mark it down CALL WAKTEN ;wake up DTE/DL10 task RETURN ;exit CLRINT: ;subroutine to clear hardware conditions SAVE R0 10$: BEQ 99$ ;if equal, all hardware bits cleared BIT #I..11D,R0 ;to -11 done? BEQ 20$ ;no, try another MOV #TS.ENT,TE.STW(R5) ;clear to -11 done BIC #I..11D,R0 ;clear flag bit BEQ 99$ ;for speed 20$: BIT #I..10D,R0 ;to -10 done? BEQ 30$ ;no, try next MOV #TS.XTS,TE.STW(R5) ;yes, clear it BIC #I..10D,R0 BEQ 99$ 30$: BIT #I..DBL,R0 ;doorbell? BEQ 99$ ;no, finished MOV #TS.EIS,TE.STW(R5) ;clear condition BIC #I..DBL,R0 99$: RESTOR R0 RETURN .SBTTL dispatch for state machine NXTPRT: ;subroutine to execute next part of ; state machine code TRACE TRCDTE,<(SP),PS> .IF NE,DTBUG TST WITHIN BEQ 1$ STOPCD 1$: .ENDC;.IF NE,DTBUG SAVE ;save caller regs MOV SP,INTSP ; and stack pointer MOV STATSP,SP ;get state machine stack pointer RESTOR ;restore state machine's regs MOV (SP)+,NXTPC ;get entry point to state machine TRACE TRCPRO, .IF NE,DTBUG CMP #INTSTK,SP ;make sure we are at appropriate point BEQ 77$ STOPCD 77$: MOV #-1,WITHIN .ENDC;.IF NE,DTBUG NXTCND: CALL FNDCND ;find an active condition BCC ERRCHK ;if none, check for illegal interrupts NXTCN0: TRACE TRCDTE, JMP @CNDHLD ;handle condition .IF NE,DTBUG NXTCN1: ;return here from state TRACE TRCDTE,NXTPC .IF NE,DEBUG CMP #INTSTK,SP BEQ 78$ STOPCD 78$: .ENDC;.IF NE,DEBUG BR NXTCND ; and go look for another .ENDC;.IF NE,DTBUG ERRCHK: ;here to see if error condition TST INTCND ;any more interrupt conditions BEQ DISMIS ;no, we are done CALL PRTCHK ;go check for protocol error interrupts IFCRY S.10ER ;if error, declare -10 down XCALL S.11ER ;must be -11 logic error DISMIS: ;when condition is finished, come here TRACE TRCPRO, SAVE ;save new state and registers MOV SP,STATSP ;save stack pointer for state machine MOV INTSP,SP ;restore caller's stack pointer RESTOR ;restore caller's registers DISM0: ;here to exit from TENDWN .IF NE,DTBUG TST INTCND BEQ 5$ INC #0 5$: CLR WITHIN .ENDC;.IF NE,DTBUG CLR INTCND ;make sure no unfinished business left RETURN ;return to caller of NXTPRT FNDCND: ;find active condition SAVE ;need a couple of registers MOV NXTPC,R0 ;get pointer to current state block ADD #STBDSP,R0 ;point to dispatch part 10$: MOV (R0)+,R1 ;get bit(s) to dispatch on BEQ 30$ ;if none, return carry clear BIT R1,INTCND ;a condition met? BEQ 20$ ;no, advance to next MOV (R0)+,CNDHLD ;yes, save dispatch address BIC R1,INTCND ;mark conditions satisfied MOV R1,CNDINT ;save last conditions (in case state ; machine wants to know) RESTOR ;restore regs SEC ;indicate we got something RETURN 20$: MOV (R0)+,R1 ;advance past dispatch address BR 10$ ;try next entry 30$: RESTOR ;restore regs CLC RETURN CNDHLD: .WORD 0 ;dispatch address for condition CNDINT: .WORD 0 ;conditions this dispatch PRTCHK: SAVE R0 ;save a register MOV #E10DSP,R0 ;displacement of -10 protocol error mask ADD NXTPC,R0 ;get address of mask bits CLC ;assume no error conditions BIT (R0),INTCND ;check mask against conditions BEQ 99$ ;exit if none match SEC ;flag error 99$: RESTOR R0 RETURN .SBTTL State machine .IF NE,FTP5 .ENABL LSB S.INI0: ;initial protocol start exchange INTTYP ,,<,> 5$: CALL TGHWAI 10$: BIT #TO.INI,TCSTFX ;check if 10 is initializing BNE 15$ GOBACK 15$: S.IN00: BIS #TO.INI,DTSTT ;yes - we are too CALL SETSTS ;tell him we agree BCC 20$ CALL TGHWAI BR 15$ 20$: MOV #TS.EEX,TE.STW(R5) ;ring -10 doorbell to wake it up NXTINT ;now he must agree that we agree .DSABL LSB S.INI1: ; we are agreeing that we are both starting INTTYP ,,<,> 5$: CALL TGHWAI 10$: BIT #TO.INI,TCSTFX ;does he agree that we agree with him? BNE S.IN00 ;no - then we don't agree about startup 15$: BIC #TO.INI,DTSTT ;yes - tell him we agree that he agrees that we agree CALL SETSTS BCC 20$ CALL TGHWAI BR 15$ 20$: MOV #TS.EEX,TE.STW(R5) ;ring -10 doorbell to wake it up NXTINT #S.IDLE ;and we are started GOBACK .ENDC ;.IF NE,FTP5 S.11ER: STOPCD S11 ;-11 logic error S.10ER: MOV #-1,PROTER ;indicate protocol error XC: XCALL TENDWN ;flag -10 down S.10DW: CLR PROTER ;no protocol error BR XC ;flag it down .ENABL LSB TGHSTD: CALL TGHWAI 99$: GOBACK S.IDLE: ;initial state (between messages) INTTYP ,,<,> 10$: S.IDL0: BIT #TO.IND,TCSTFX+2 ;doorbell for indirect? IFNE S.10ER ;yes, -10 goofed S.IDL1: CMPB DT10QC,TCSTFX+4 ;compare our queue count with -10's BEQ 99$ ;if same, ignore 20$: CALL SETHDR ;setup to read header BCC 30$ CALL TGHWAI BR 20$ 30$: NXTINT .DSABL LSB S.WFEH: ;waiting for -11 done of header .IF NE,FTFEDV SAWFEH: ;substate: waiting for FEH for DN60 header .ENDC ; .IF NE,FTFEDV INTTYP ,,<,> 10$: MOV #DT11HD,R0 ;point to correct header CALL SWPHDR ;swap header bytes .IF EQ,FTP5 TRACB TRCPRO,DT11HD,D11HDL/2 ;trace the FEH header .IFF TRACB TRCPRO,DT11DF,D11DFL/2 ;trace the DN60 header .ENDC ;.IF EQ,FTP5 CALL VALHDR ;check constant header info .IF NE,FTFEDV BCC 19$ .IIF NE,DTBUG, INC #0 ;count these for the hell of it 12$: NXTINT #S.IDLE ;if illegal header - ignore it! GOBACK .IFF IFCRY S.10ER ;illegal header .ENDC ; .IF NE,FTFEDV 19$: .IF NE,FTFEDV CMPB DT11FN,#DTFSAK ;check for unexpected ack BEQ 12$ ;20 sends another after transaction complete 15$: CALL GETSTS ;try to get status BCS 30$ ;if -10 timeout, declare it dead TST TCSTFX ;check for valid examine BNE 20$ ;no, assume TGHA running 30$: CALL TGHWAI ;go into TGHA wait BR 19$ ;if timeout and -10 is up, read status again 20$: ;here for indirect - the DN60 header NXTINT SAWFEB: ;wait for indirect doorbell - DN60 header INTTYP ,,<,> 10$: BIT #TO.IND,TCSTFX+2 ;indirect doorbell? BNE 20$ ;yes, continue INC #0 ;count how often this happens BIS I..DBL,INTCND ;dummy up interrupt condition NXTINT #S.IDLE ;change state immediately GOBACK ; and go to it 20$: CALL INPHD ;setup to read data BCC 25$ CALL TGHWAI BR 20$ 25$: NXTINT SAWFED: ;wait for -11 done for indirect data - DN60 header INTTYP ,,<,> 10$: MOV #DT11HD,R0 ;point at to-11 header CALL SWPHDF ;swap the bytes .ENDC ; .IF NE,FTFEDV .IF EQ,FTP5 TRACB TRCPRO,DT11DF,D11DFL/2 ;trace the DN60 header .ENDC ;.IF EQ,FTP5 .IF EQ,FTFEDV CALL GETSTS ;try to get status BCS 30$ ;if -10 timeout, declare it dead TST TCSTFX ;check for valid examine BNE 21$ ;no, assume TGHA running CALL TGHWAI ;go into TGHA wait BR 19$ ;if timeout and -10 is up, read status again 30$: XCALL TENDWN ;declare -10 down .ENDC ;.IF EQ,FTFEDV ;(never returns) 21$: MOVB DT11DF,R1 ;get DN60 function code CMPB #DF.EXA,R1 ;is it examine BEQ 80$ ;yes, special case CMPB #DF.DEP,R1 ;is it deposit? BEQ 80$ ;yes, special case .IF NE,FTFEDV+FTP5 BIT #1,DT11DF ;check DN60 function code for indirect dat BEQ 20$ ;even function codes are writes from ten to eleven .IFF TST DT11FN ;is it indirect function? BMI 20$ ;yes, go bring in data .ENDC ;.IF NE,FTFEDV+FTP5 .IIF NE,FTFEDV, CALL DTSACK ;send ack with FEH for response CLR INPCTR ;no input data CALL WKTSK ;wake up DL10/DTE task NXTINT #S.WFTK ;declare next interrupt 99$: GOBACK 80$: CALL DLTEXM ;build examine/deposit response .IF NE,FTP5 MOV #DT10HD,R0 ;point to the right header CALL SWPHDF ;swap DN60 header for ten .ENDC ;.IF NE,FTP5 .IIF NE,FTFEDV, CALL DTSACK ;send ack with FEH for response 81$: CALL SNDHDR ;try to send it to -10 BCS 75$ ;if error ringing ten, try to repeat .IF NE,FTP5 TST RSPSIZ ;if response size is zero BNE 70$ JMP SFAKDN ;there won't be any to 10 done 70$: .ENDC ;IF NE,FTP5 NXTINT #S.WFTH ;declare next interrupt GOBACK 75$: NXTINT #S.WSTH ;next state is trying to send header CALL TGHWAI ;but put ourselves into TGHA wait first BR 81$ ;go try again to send 20$: ;here if indirect data coming .IF NE,FTFEDV CALL DTSAK ;send ack and wait for indirect data BR 81$ ;go try again to send SBWFEB: ;waiting for doorbell for FEH for data INTTYP ,,<,> 10$: BIT #TO.IND,TCSTFX+2 ;doorbell for indirect? IFNE S.10ER ;yes, -10 goofed CMPB DT10QC,TCSTFX+4 ;compare our queue count with -10's BEQ 11$ ;if same, ignore CALL SETHDR ;setup to read header BCC 15$ 11$: GOBACK ;don't leave state if it fails 15$: NXTINT SBWFEH: ;substate: waiting for FEH for DN60 data INTTYP ,,<,> 10$: MOV #DT11HD,R0 ;point to correct header CALL SWPHDR ;swap header bytes TRACB TRCPRO,DT11HD,D11HDL/2 ;trace the FEH header CALL VALHDR ;check constant header info BCC 19$ .IIF NE,DTBUG, INC #0 ;count these for the hell of it 12$: NXTINT #S.IDLE ;if illegal header - ignore it! GOBACK 19$: CMPB DT11FN,#DTFSAK ;check for unexpected ack BNE 15$ .IIF NE,DTBUG, INC #0 ;count these for the hell of it BR 12$ ;have seen this happen here, followed ;by a non-fe header. seemed to be ;associated with tgha event. 15$: CALL GETSTS ;try to get status BCS 30$ ;if -10 timeout, declare it dead TST TCSTFX ;check for valid examine BNE 20$ ;no, assume TGHA running 30$: CALL TGHWAI ;go into TGHA wait BR 19$ ;if timeout and -10 is up, read status again 20$: ;here for indirect - the DN60 data .ENDC ; .IF NE,FTFEDV NXTINT #S.WFEB GOBACK S.WFEB: ;wait for indirect doorbell INTTYP ,,<,> 10$: BIT #TO.IND,TCSTFX+2 ;indirect doorbell? .IF NE,FTP5 BEQ 20$ ;no, continue .IFF BNE 20$ ;yes, continue .ENDC ;IF NE,FTP5 INC #0 ;count how often this happens BIS I..DBL,INTCND ;dummy up interrupt condition NXTINT #S.IDLE ;change state immediately GOBACK ; and go to it 20$: CALL SETDAT ;setup to read data BCC 21$ CALL TGHWAI BR 20$ 21$: NXTINT S.WFED: ;wait for -11 done for indirect data INTTYP ,,<,> 10$: .IF NE,FTFEDV BIT #1,DT11DF ;CHECK FOR WRITE FUNCTION BNE 11$ ;for some mysterious reason write commands have to get their data from the ; indirect header byte count(WRITE DATA only but do it for all for consistency) CLR DT11DT ;get length of msg MOVB DT11UC,DT11DT ;from FEH of indirect msg .ENDC ; .IF NE,FTFEDV 11$: MOV DT11DT,INPCTR ;get length of input data CMP INPCTR,#MAXDAT ;limit to buffer size BLE 12$ MOV #MAXDAT,INPCTR 12$: CALL WKTSK ;wake up task .IIF NE,FTFEDV, CALL DTSACK ;set up ack of data read to go back with ;FEH of response NXTINT S.WFTK: ;wait for task to respond INTTYP 0,,<,> 10$: .IF NE,FTP5 MOV #DT10HD,R0 ;point to the right header CALL SWPHDF ;swap DN60 header for ten .ENDC ;.IF NE,FTP5 CALL SNDHDR ;try to send header BCC 20$ ;it went, go finish up NXTINT #S.WSTH ;declare next state CALL TGHWAI ;but as a TGHA state BR 10$ ;try again 20$: NXTINT ;success, we are in a new state S.WFTH: ;waiting for to -10 done on header INTTYP ,,<,,> 10$: BIT #TO.IND,TCSTFX+2 ;doorbell for indirect? IFNE S.10ER ;yes, -10 error CALL ABTXMT ;abort transmit in progress .IIF NE,FTFEDV, CLR DTACKR ;clear ack flag JMP S.IDL1 ;and wait for header from -10 20$: SFAKDN: ;here when no to 10 done will happen .IF NE,FTFEDV TST DTACKR ;trace ack header if acking indirect data BEQ 21$ TRACB TRCPRO,DTAKHD,D10HDL/2 ;length 21$: MOV DTACKR,R0 ;check for ack only BEQ 25$ ;no ack at all CLR DTACKR ;done with ack header CMP R0,#D10HDL ;ack - check if FEH of response with it BGT 25$ ;yes - go send the indirect data NXTINT #SBWFEB ;no, just ack => expecting indirect data from 10 GOBACK 25$: TRACB TRCPRO,DT10DF,D10DFL/2 ;trace DN60 header returned MOV #DT10HD,R0 ;point to the right header CALL SWPHDF ;swap DN60 header for ten 26$: CALL OUTHD ;send DN60 header to ten BCC 40$ NXTINT #S.WSTD CALL TGHWAI BR 26$ 40$: NXTINT SAWFTD: ; waiting for to-10 done on DN60 header INTTYP ,,<,,> 10$: CALL ABTXMT ;abort transmit CLR DTACKR ;clear ack flag JMP S.IDL0 ;next state 20$: BIC #TO.IND!TO.FWD,DTSTT+2 ;clear indirect in progress and byte mode NXTINT ;now wait for ack of indirect part sent SAWFAK: ;waiting for ack header INTTYP ,,<,> 10$: BIT #TO.IND,TCSTFX+2 ;doorbell for indirect? IFNE S.10ER ;yes, -10 goofed CMPB DT10QC,TCSTFX+4 ;compare our queue count with -10's BNE 15$ ;if same, ignore GOBACK 15$: CALL SETHDR ;setup to read header BCC 20$ ;don't leave state if it fails CALL TGHWAI BR 15$ 20$: NXTINT SBWFAK: ;waiting for -11 done of ack header INTTYP ,,<,> 10$: MOV #DT11HD,R0 ;point to correct header CALL SWPHDR ;swap header bytes TRACB TRCPRO,DT11HD,D11HDL/2 ;trace the FEH header CALL VALHDR ;check constant header info BCC 19$ .IIF NE,DTBUG, INC #0 ;count these for the hell of it NXTINT #S.IDLE ;if illegal header - ignore it! GOBACK 19$: CMPB DT11FN,#DTFSAK ;check for expected ack BEQ 15$ CALL S.10ER ;ten is confused 15$: ;now time to think about sending response data ;NOTE: DN60 header has been swapped at this point MOV DT10DT,R0 ;any data to go back ? BEQ 20$ ;no - done with transaction CMPB #DF.EXA,DT10DF+1 ;maybe - check if it was examine/deposit response BEQ 20$ ;yes - data is in DN60 header CMPB #DF.DEP,DT10DF+1 BEQ 20$ ;yes - no data to return BITB #1,DT10DF+1 ;check for write function BNE 30$ ;no - data returns to 10 ;yes - no data is returned to 10 20$: NXTINT #S.IDLE ;done - fall back to ground state(exhausted) GOBACK 30$: SWAB R0 ;FE service can only handle a byte?? MOVB R0,DT10UC ;set no. bytes to follow CALL SNDHDR ;try to send header BCC 40$ ;it went, go finish up NXTINT #S.WSTH ;declare next state CALL TGHWAI ;but as a TGHA state BR 30$ ;try again 40$: NXTINT ;success, we are in a new state SAWFTH: ;waiting for to -10 done on header for data INTTYP ,,<,,> 10$: BIT #TO.IND,TCSTFX+2 ;doorbell for indirect? IFNE S.10ER ;yes, -10 error CALL ABTXMT ;abort transmit in progress JMP S.IDL1 ;and wait for header from -10 20$: TRACB TRCPRO,DT10HD,D10HDL/2 .ENDC ;.IF NE,FTFEDV .IF NE,FTP5 CMPB DT10DF+1,#DF.EXA ;check for examine/deposit BEQ 25$ ;examine CMPB DT10DF+1,#DF.DEP BEQ 25$ ;deposit BITB #1,DT10DF+1 ;check for read data type function BNE 30$ ;yes - have to respond ;no - header is sufficient .IFF TST DT10FN ;check for indirect function BMI 30$ ;yes, continue it .ENDC ;IF NE,FTP5 25$: BIC #TO.IND!TO.FWD,DTSTT+2 ;clear byte mode (and indirect for the hell of it) NXTINT #S.IDLE ;next stop is idle GOBACK 30$: CALL SNDDAT ;send data BCC 40$ ;continue if it worked NXTINT #S.WSTD CALL TGHWAI BR 30$ 40$: NXTINT S.WFTD: ;waiting for to -10 done on data INTTYP ,,<,,> 10$: CALL ABTXMT ;abort transmit .IIF NE,FTFEDV, CLR DTACKR ;clear ack flag JMP S.IDL0 ;next state 20$: BIC #TO.IND!TO.FWD,DTSTT+2 ;clear indirect in progress and byte mode .IF NE,FTFEDV NXTINT ;now wait for ack of indirect part sent SCWFAK: ;waiting for ack header INTTYP ,,<,> 10$: BIT #TO.IND,TCSTFX+2 ;doorbell for indirect? IFNE S.10ER ;yes, -10 goofed CMPB DT10QC,TCSTFX+4 ;compare our queue count with -10's BNE 15$ ;if same, ignore GOBACK 15$: CALL SETHDR ;setup to read header BCC 20$ ;don't leave state if it fails CALL TGHWAI BR 15$ 20$: NXTINT SDWFAK: ;waiting for -11 done of ack header INTTYP ,,<,> 10$: MOV #DT11HD,R0 ;point to correct header CALL SWPHDR ;swap header bytes TRACB TRCPRO,DT11HD,D11HDL/2 ;trace the FEH header CALL VALHDR ;check constant header info BCC 19$ .IIF NE,DTBUG, INC #0 ;count these for the hell of it NXTINT #S.IDLE ;if illegal header - ignore it! GOBACK 19$: CMPB DT11FN,#DTFSAK ;check for expected ack BEQ 15$ CALL S.10ER ;ten is confused 15$: .ENDC ;.IF NE,FTFEDV ;transaction complete - at last!! NXTINT #S.IDLE GOBACK S.WSTH: ;waiting to send header INTTYP ,,<,,> 20$: CALL ABTXMT JMP S.IDL0 10$: GOBACK 30$: CALL SNDHDR BCC 31$ CALL TGHWAI BR 30$ 31$: .IF NE,FTP5 TST RSPSIZ ;check if to 10 done will happen BNE 35$ JMP SFAKDN ;no - fake it 35$: .ENDC ;IF NE,FTP5 NXTINT #S.WFTH GOBACK S.WSTD: ;waiting to send data INTTYP ,,<,,> 20$: CALL ABTXMT JMP S.IDL0 10$: GOBACK 30$: NXTINT #S.IDLE GOBACK .SBTTL Subroutines for state machine TGHWAI: ;subroutine to wait for TGHA pause to ; finish TRACE TRCDTE!TRCPRO,<(SP),NXTPC,JIFCLK> ;trace caller and state coming from ;Call only at top level stack in state machine ; This subroutine can only be called from the state machine; it assumes ; 10 will have turned off DTE for up to TGHMAX seconds. The TGHA state ends ; when: 1) the timer expires and -10 still doesn't have valid examine. This ; means the -10 is down, and results in a call to S.10DW. 2) the timer expires ; and the -10 is alive. This returns to the caller of TGHWAI. 3) another ; interrupt condition occurs while timing. This immediately terminates the ; TGHA state, and returns to the beginning of the state TGHWAI was called in ; with the interrupt condition set. .IF NE,DTBUG TST TGHCNT ;are we already in TGHA? BEQ 5$ ;no, skip it STOPCD RTC ;recursive TGHA call! 5$: .ENDC;.IF NE,DTBUG MOV (SP)+,TGHRET ;save return address MOV NXTPC,TNXTPC ;save current state MOV #TGHMAX,TGHCNT ;set timeout counter NXTINT ; and go into new state WAITGH: INTTYP 0,0,<,,,,,> 10$: BIS #I..DBL,INTCND ;re-iterate interrupt condition 11$: NXTINT TNXTPC ;force chance of state 99$: GOBACK ;go do it 20$: BIS #I..11D,INTCND ;re-iterate condition BR 11$ 30$: BIS #I..10D,INTCND BR 11$ 40$: BIS #I..RSP,INTCND BR 11$ 50$: NXTINT TNXTPC ;restore original state JMP @TGHRET ;return to caller TGHRET: .WORD 0 ;caller return for TGHWAI WKTSK: ;subroutine to wake TENTSK ;The caller must set up INPCTR with the number of data bytes read MOV DT11DT,OUTCTR ;maximum to transfer is requested amount CMP OUTCTR,#MAXDAT ;check for buffer overflow BLE 5$ ;no, use it MOV #MAXDAT,OUTCTR ;yes, cut down to our buffer size 5$: MOV #OUTBUF,OUTPTR ; and where to start MOV #INBUF,INPPTR ;when input starts CALL CPYHDR ;copy header from input to output area MOV #DT11DF,R0 ;point to DN60 part of header CALL WAKFNC ;wake up task SETSKD TCDLDR ;force scheduling pass RETURN INISTA: ;subroutine to initialize state machine SAVE R5 MOV SP,R5 ;copy stack pointer MOV #INTSTK,SP ;reset stack pointer to state machine stack .IF EQ,FTP5 SAVE #S.IDLE ;start idling .IFF SAVE #S.INI0 ;startup exchange required .ENDC ;.IF EQ,FTP5 SAVE <#0,#0,#0,DTEPCA,#0,DTEBAD>;initialize state regs and return MOV SP,STATSP ;save state machine stack pointer MOV #S.IDLE,NXTPC ;save current (and next) state CLR TGHCNT ;assume TGHA not running CLR INTCND ;make sure nothing left over .IIF NE,FTFEDV, CLR DTACKR ;clear ack flag .IIF NE,DTBUG, CLR WITHIN MOV R5,SP ;restore old stack pointer RESTOR R5 ;and register RETURN ;return to caller TENDWN: ;subroutine for state machine to declare ; -10 down .IF NE,DTBUG CALL STKSAV ;save state machine stack .ENDC;.IF NE,DTBUG .IF NE,DEBUG BIT #TRCTER,TRCHLT BEQ 1$ STOPCD TER 1$: .ENDC;.IF NE,DEBUG CALL WAKTEN ;wake up DTE/DL10 task MOV INTSP,SP ;restore caller's stack pointer CALL INISTA ;initialize state machine MOV #-1,DLGONE ;mark it down RESTOR ;restore caller's registers JMP DISM0 ;exit .SBTTL Software-generated interrupt conditions DLRESP: ;send response to -10 ;NOTE: this code is called from DL10/DTE task to return the data ;length and result code and to initiate their return to the -10. ;It corresponds to the interrupt condition I..RSP in the state machine. MOVB R0,DT10DF+1 ;save result code MOV R1,DT10DT ;and copy length TRACE TRCTEN!TRCPRO, ;trace the results .IF EQ,FTP5 .IF EQ,FTFEDV TST R1 BEQ 6$ ;if 0, leave indirect function bit clear BIT #1,DT10DF ;was it a write function? BEQ 6$ ;yes, never have data to send BIS #100000,DT10FN ;else set indirect function bit .ENDC ; .IF EQ,FTFEDV .ENDC ;.IF EQ,FTP5 6$: CLKOFF ;flush the clock OFFDTE ;disable dte interrupts BIS #I..RSP,INTCND ;set the interrupt condition CALL NXTPRT ;do next part of state machine PIOFF ;protect from clenches ONDTE ;allow dte interrupts CLKON ;also crocks PION ;unclench RETURN TGHEXP: ;called from once per second code ; when timer for TGHA expires PIOFF ;no interrupts CALL GETSTS ;read status word BCS 10$ ;if it timed out, -10 is dead CMP NXTPC,#WAITGH ;make sure we are waiting for TGHA BEQ 4$ ;yup, continue XCALL S.11ER ;die 4$: .IF NE,DTBUG TST INTCND ;make sure no left-over interrupt conditions BEQ 5$ STOPCD INZ 5$: .ENDC;.IF NE,DTBUG CLR TGHCNT ;no longer timing tgha MOV #I..TMO,INTCND CALL NXTPRT 10$: PION RETURN .SBTTL Timer entry points DSPDLT: ;tick timer TST DLGONE BNE 99$ TST TGHCNT ;is TGHA timer running? BEQ 99$ ;no, retire MOV DTEBAD,R5 ;point to hardware DTEOFF MOV DTEPCA,R3 ;get DTE block pointer CALL CHKTEN ;check if ten is healthy BCS 98$ ;if not - wait for tgha interval CALL TGHEXP ;try TGHA expiration for size 98$: DTEON 99$: CLC RETURN DSPDLS: ;second timer TRACE TRCDTE, TST DLGONE BEQ 1$ DEC DLGONE ;count it down RETURN 1$: SAVE ;save standard hardware register MOV DTEBAD,R5 ;point to hardware DTEOFF MOV DTEPCA,R3 ;get DTE block pointer TST TGHCNT ;is TGHA timer running? BEQ 50$ ;no, test -10 DEC TGHCNT ;decrement timer BNE 99$ ;if not up, we are done 70$: CALL DTEDWN ;if not, declare -10 down 99$: DTEON RESTOR RETURN 50$: ;here if -10 needs to be up CALL CHKTEN ;check that it is BCC 60$ MOV #I..TGH,INTCND ;no - set tgha state CALL NXTPRT BR 99$ 60$: CALL CRAML0 ;cram keepalive BCC 99$ CALL CRAML0 BR 99$ ;ignore error CRAMLV: MFPS -(SP) ;preserve condition codes over this fcn CMP JIFCLK,NXKPLV ;do this at odd times if not done recently BLO 10$ CALL CRAML0 10$: MTPS (SP)+ RETURN CRAML0: CLR TE.XW1(R5) CLR TE.XW2(R5) MOV JIFCLK,TE.XW3(R5) ;the count to -20 MOV #TS.DEP,TE.XA1(R5) ;set deposit flag MOV #PBPW1,TE.XA2(R5) ;start xfer CALL DLWEDN ;wait for exam/dep BCS 10$ MOV JIFCLK,DTKPLV ;save last successful keepalive MOV DTKPLV,NXKPLV ADD #JIFSEC,NXKPLV ;next time it becomes urgent to do it TRACE TRCDTE,JIFCLK ;trace last successful keepalive CLC 10$: RETURN .ENABL LSB CHKTEN: CALL DTECHK BCC 5$ CALL DTECHK BCS 9$ ;branch if -10 down 5$: TST TE.XW3(R5) ;check for processor number BEQ 9$ ;ten not up yet if zero TRACE TRCDTE,<(SP),JIFCLK,TE.XW1(R5),TE.XW2(R5),TE.XW3(R5)> CHKSUC: CLC RETURN 9$: TRACE TRCDTE,<(SP),JIFCLK> CHKFAL: 10$: SEC RETURN .DSABL LSB DTECHK: CLR TE.XA1(R5) ;look at DTEXAM: CLR TE.XA2(R5) ; out comm region header entry JMP DLWEDN ;wait for examine done .SBTTL DTE subroutines ;Turn on the DTE-20 and setup DTE table ; ; THIS ROUTINE WILL SET UP THE TABLES NECESSARY TO ; INITIALIZE THE COMMUNICATIONS BETWEEN THE PDP-10 ; AND THE PDP-11. ; ; CALL: CALL DLINDB ; ; ON RETURN: ; C = 0: R0 = 1 TO INDICATE SUCCESS ; C = 1: ERROR ; ; NOTE THAT THIS ROUTINE USES R5 IN A NON-STANDARD WAY. ; THIS IS BECAUSE IT WAS TAKEN FROM THE DN87S CODE AND ; WE WOULD PREFER NOT TO HAVE TO RE-WRITE IT TO MAKE IT ; CONFORM TO THE DN60 CODING CONVENTIONS. ; DLINDB: MOV R5,-(SP) CLR -(SP) CLR -(SP) MOV DTEBAD,R0 ;FIND THE COMMON DTE-20 CLR R1 ;SET UP TO FIND PROCESSOR NUMBER CLR R2 ;START TRANSFER OF ABS WORD 0 OF EPT (MY PROCESSOR NUMBER MOV #DTXTM3,R3 ;SET UP ADDRESS TO STORE WORDS CLR R4 CALL DLSWED ;WAIT FOR EXAMINE/DEPOSIT BCS 11$ ;E BOX STOP MOV @R3,R4 ;YES --FIND OFFSET TO MY R/W AREA MOVB @#DTXTM2+1,R2 ;FIND THE PROCESSOR NUMBER ; PROCESSOR NUMBER TO LOW ORDER BITS BIC #177760,R2 ;MASK OFF JUNK(0.-15. LEGAL) MOV R2,DLMYPN ;SAVE PROCESSOR NUMBER INC R2 ;FIND COMMUNICATIONS VIRTUAL 2 MOV R2,DLCMBS ;SAVE BASE OF COMMUNICATIONS AREA ADD R4,R2 ;ADD OFFSET TO BASE OF COMM AREA MOV R2,DLDPOF ;SET CORRECT OFFSETT TRACE TRCDTE, CALL DLSWED ;WAIT FOR TRANSFER BCC 12$ 11$: JMP DLINDR 12$: TRACE TRCDTE, MOV @#DTXTM2,R5 ;PICK UP THE NUMBER OF 8 TM BLOCKS BIC #177770,R5 ;FIND THE NUMBER OF 8 WORD BLOCKS IN MY AREA BEQ 33$ ;die if none SUB #2,R5 ;ACCOUNT FOR MY GENERAL SECTION .IIF NE,FTP5,INC R5 ;faker BGT 34$ ;MCB uses 2 blocks,FE service 3 33$: STOPCD DTE 34$: MOV R2,2(SP) MOV R5,0(SP) ;SAVE COUNT OF BLOCKS DLIND1: ADD #PBASIZ,2(SP) ;LOOK AT A COMMUNICATIONS AREA TO ANOTHER PROCESSOR MOV 2(SP),R2 CLR R4 CALL DLSWED ;WAIT FOR TRANSFER BCC 77$ ; E BOX STOPPED 11$: JMP DLINDR 77$: TRACE TRCDTE, MOV @R3,R4 ;FIND PROCESSOR NUMBER MOV #DTPIDT,R5 ;SET INITIAL POINTER BIC #177770,R4 ;MASK OFF JUNK BEQ 13$ ;YES -- CONTINUE 12$: ADD #5*2,R5 ;NO -- LOOK AT NEXT ENTRY SOB R4,12$ ;TRY UNTIL ALL DONE 13$: TRACE TRCDTE, MOV @#DTXTM2,R4 ;FIND NUMBER OF 8 WORD BLOCS BIC #177770,R4 ;MASK OFF POSSIBLE GARBAGE SUB R4,@SP ;UPDATE COUNT OF BLOCKS CLR @R5 ;SET UP TO CLEAR TABLE IF NO DTE MOV @#DTXTM1,R4 ;PICK UP DTE NUMBER TRACE TRCDTE, BIT #TO.DTE,R4 ;DTE HERE? BEQ 15$ ;NO -- DON'T ENTER IN TABLE SWAB R4 ;MAKE MOD 40 (8) ROR R4 ROR R4 ROR R4 BIC #177637,R4 ;MASKOFF JUNK ADD #174400,R4 ;POINT TO FIRST BLOCK OF DTE'S CMP R4,DTEBAD ;PRIMARY DTE? BNE 14$ ;NO -- DON'T SET TABLE POINTER MOV R5,DTEPCA ;SAVE TABLE OFFSET TRACE TRCDTE, 14$: MOV R4,@R5 ;SET DTE ADDRESS IN TABLE MOV #DLYPRM,@R4 ;SET UP DELAY COUNTER MOV #TS.EEE,TE.STW(R4) ;YES -- ENABLE INTERRUPT ON IT 15$: MOV R2,DTEMYN(R5) ;SET THE ADDRESS OF EXAMINE MY AREA FOR N ; MAKE ADDRESS OF THE ADDRESS OF DEPOSIT MY AREA FOR N MOV R2,DTDMYN(R5) ;STORE IT SUB DLDPOF,DTDMYN(R5) ;RESTORE SUBRESS FOR EXAMINE OF THIS BLOCK TRACE TRCDTE, ADD #TOPCA,R2 ;READ POINTER TO HIS COMM AREA CLR R4 CALL DLSWED ;WAIT FOR EXAMINE/DEPOSIT BCS DLINDR ;E BOX STOPPED MOV @R3,R2 ;FIND THE EXAMINE ADDRESS ADD DLCMBS,R2 ;ADD OFFSET TO COMMON AREA MOV R2,DTEHSG(R5) ;SET DTEHSG ADDRESS IN TABLE - ptr to his base area ADD #PBASIZ,R2 ;POINT TO HIS FIRST TABLE FOR OTHER PROCESSORS TRACE TRCDTE, 17$: CLR R4 CALL DLSWED ;WAIT FOR EXAMINE/DEPOSIT BCS DLINDR TRACE TRCDTE, CMPB DLMYPN,@R3 ;SAME PROCESSOR NUMBER? BEQ 19$ ;YES -- FOUND MY ENTRY MOV @#DTXTM2,R4 ;NO -- FIND NEXT ENTRY IN LIST BIC #177770,R4 ;IT IS IN 8 WORD INCREMENTS ;;++KR-FIX FOR TOPS-20 MONITOR PROBLEM BNE 20$ ;;++KR-NON ZERO IS GOOD INC R4 ;;++KR-MAKE IT NON ZERO 20$: ;;++KR-END FIX ASL R4 ;SO IT MUST BE SHIFTED LEFT 3 BITS ASL R4 ; ASL R4 ; ADD R4,R2 ;READ NEXT BLOCK BR 17$ ;AND TRY AGAIN 19$: TRACE TRCDTE,R2 MOV R2,DTEHSM(R5) ;STORE DTEHSM ADDRESS - 10'S TO me area offset MOV @SP,R5 ;DONE ALL BLOCKS?? BLE 96$ JMP DLIND1 ;NO -- TRY NEXT BLOCK 96$: MOV #-1,TENALV ;let all know it has happened at least once CLR DTQCNT ;RESET PROTOCOL COUNTERS CLR DTQSTA ;INIT STATE MECHANISM, CLEAR CARRY DLINDR: MOV (SP)+,R5 ;RESTORE STACK MOV (SP)+,R5 MOV (SP)+,R5 RETURN ; THIS SUBROUTINE STARTS A DEPOSIT/EXAMINE SEQUENCE AND WAITS FOR ; ITS COMPLETION. IT CHECKS TO SEE IF THE BOOTSTRAP ; PROTOCOL IS NECESSARY BY CHECKING THE EXAMINE VALID BIT ; AFTER EVERY EXAMINE/DEPOSIT. IT IS NOT NECESSARY TO ; CHECK MORE THAN ANY ONE RANDOM EXAMINE VAILD BIT ; BECAUSE IF ONE IS 0 THEN THE PROCESSOR HAS ; TO REVERT TO THE BOOTSTRAP PROTOCOL. ; ; CALL: CALL DLSWED ; ; R0 -- ADDRESS OF DTE-20 ; R1 -- HIGH ORDER EXAMINE/DEPOSIT ADDRESS WORD (FOR TE.XA1) ; R2 -- LOW ORDER EXAMINE/DEPOSIT ADDRESS WORD (FOR TE.XA2) ; R3 -- ADDRESS TO XFER 3 WORD BLOCK TO OR FROM ; ; ON RETURN: ; ; C = 0: SUCCESS, NO REGISTERS ALTERED. ; C = 1: ERROR. DLSWED: MOV R3,-(SP) ;SAVE REGISTERS SAVE R5 MOV R0,R5 BIT #TS.DEP,R1 ;CHECK FOR DEPOSIT BNE 12$ ;YES -- GO TO DEPOSIT PART OF SUB CALL 30$ BCC 10$ CALL 30$ BCS 14$ ;COMPLAIN ABOUT E BOX STOPPED 10$: MOV TE.XW3(R0),(R3)+ ;STORE THE WORD XFERED MOV TE.XW2(R0),(R3)+ MOV TE.XW1(R0),(R3)+ .IF NE,DTBUG CALL TRCIT .ENDC;.IF NE,DTBUG 11$: TST R4 ;PRIV EXAMINE/DEP? BNE 14$ ;YES -- DON'T DO CHECKS CLR TE.XA1(R0) ;SEE IF WE CAN READ ANYTHING CLR TE.XA2(R0) ;START TRANSFER CALL DLWEDN ;WAIT FOR XFER BCC 9$ CLR TE.XA2(R0) ;START TRANSFER CALL DLWEDN ;WAIT FOR XFER BCS 14$ ;E BOX STOPPED 9$: TST TE.XW3(R0) ;VALID? BNE 14$ ;YES -- PROCEED BR 13$ ; NO - JUST SET CARRY AND RETURN ; HERE TO DO AN EXAMINE. 12$: MOV (R3)+,TE.XW3(R0) ;TRANSFER TO 10 MOV (R3)+,TE.XW2(R0) ;SET UP WORD IN DTE MOV (R3)+,TE.XW1(R0) .IF NE,DTBUG CALL TRCIT .ENDC;.IF NE,DTBUG CALL 30$ BCC 11$ ;GO TO COMMON EXAMINE VALID BIT CHECK CALL 30$ BCC 11$ ;GO TO COMMON EXAMINE VALID BIT CHECK ; HERE IF THE 'EXAMINE VALID' BIT IS OFF. GIVE AN ERROR RETURN. 13$: .IF NE,DTBUG STOPCD DBG ;-10 STOPPED UNEXPECTEDLY .ENDC;.IF NE,DTBUG SEC 14$: RESTOR R5 MOV (SP)+,R3 ;RESTORE R3 RETURN ;RETURN TO CALLER 30$: MOV R1,TE.XA1(R0) ;SET UP ADDRESS OF XFER IN DTE MOV R2,TE.XA2(R0) ;START XFER JMP DLWEDN ;WAIT FOR EXAMINE/DEPOSIT .IF NE,DTBUG TRCIT: TRACE TRCDTE,<-2(R3),-4(R3),-6(R3)> RETURN .ENDC;.IF NE,DTBUG ; R3/DPTIDT block for this processor GETSTS: ;subroutine to read comm region status word TRACE TRCDTE,(SP) SAVE R2 MOV #TOSTAT,R2 ;calculate offset of status word from ; beginning of to- section ADD DTEHSM(R3),R2 ;add in comm region offset of the ; to- section for me in KL's area EXAM R2,TCSTFX,69$ ;examine it 69$: RESTOR R2 RETURN ;return, carry will be set if timeout SETSTS: ;subroutine to write comm region status word TRACE TRCDTE,<(SP)> SAVE R2 MOV #TOSTAT,R2 ;get displacement of status within to- section ADD DTDMYN(R3),R2 ;convert to deposit offset DEPO R2,DTSTT,20$ ;store status 20$: RESTOR R2 RETURN SETQSZ: ;subroutine to store queued protocol ;R0/ transfer size CLR TE.XW1(R5) ;zero high CLR TE.XW2(R5) ; order bits of -10 word MOV R0,TE.XW3(R5) ;put size of transfer in low word TRACE TRCDTE,R0 MOV #TOXFSZ,R0 ;get offset of queue size ADD DTDMYN(R3),R0 ;make into deposit offset DEPO R0,,69$ ;deposit queue size 69$: RETURN ABTXMT: ;here to abort transmit already started INC #0 ;count how many times we are in this situation ATRACE <(SP),INTCND> ;trace these always RETURN ;can't do it, DTE20 doesn't have a way ;to cut down byte count. SETHDR: ;setup to read header .IF NE,FTP5 MOV #DT11HD,R1 ;get address of where to put it GETDAT: .ENDC ;.IF NE,FTP5 BIS #TO.IT,DTSTT+2 ;set queue in progress bit in status to -10 INCB DT10QC ;increment our counter CMPB TCSTFX+4,DT10QC ;see if we match BEQ 10$ ;ok, continue .IF NE,DTBUG MOVB DT10QC,#0 MOVB TCSTFX+4,#0 .ENDC;.IF NE,DTBUG DECB DT10QC SEC 99$: RETURN 10$: CALL SETSTS ;write status BCS 99$ ;return on error CALL GETQSZ ;get the xfer size BCS 99$ .IF NE,FTP5 CMP R0,#MAXDAT ;is it too big? BLE 11$ ;no, continue MOV #MAXDAT,R0 ;yes, cut it down INC #0 ;count how often this happens 11$: .ENDC ;.IF NE,FTP5 TST R0 ;check size BNE 20$ .IF NE,FTFEDV MOV #D11HDL,R0 ;else use default size .IFF MOV #D11HDL+D11DFL,R0 ;else use default size .ENDC ; .IF NE,FTFEDV 20$: CALL CRAMLV ;cram keepalive .IF EQ,FTP5 MOV #DT11HD,R1 ;get address of where to put it .ENDC ;.IF EQ,FTP5 CALL DTSTRT ;start input BIC #TO.IT,DTSTT+2 ;clear TOIT bit to indicate not indirect CALL SETSTS ;set status RETURN ;return to caller .IF NE,FTFEDV INPHD: ;get DN60 header - indirect data CALL GETQSZ ;extract queue size word from dte BCC 5$ RETURN ;return failure 5$: CMP R0,#D11DFL ;check max length dn60 header BLE 10$ MOV #D11DFL,R0 ;use only this much INC #0 ;count these 10$: MOV #DT11DF,R1 ;where to read the dn60 header BR INPDAT ;do it .ENDC ; .IF NE,FTFEDV SETDAT: ;subroutine to setup to read indirect data .IF NE,FTP5 MOV #INBUF,R1 ;address to put it BR GETDAT ;go get it .IFF CALL GETQSZ ;extract queue size from dte BCC 5$ RETURN ;return failure 5$: CMP R0,#MAXDAT ;is it too big? BLE 10$ ;no, continue MOV #MAXDAT,R0 ;yes, cut it down INC #0 ;count how often this happens 10$: MOV #INBUF,R1 ;address to put it INPDAT: CALL DTSTRT ;start input, R0/bytes to read, R1/buffer BIS #TO.IT,DTSTT+2 ;set TOIT bit to indicate indirect in progress CALL SETSTS ;deposit status 10$: RETURN .ENDC ;.IF NE,FTP5 GETQSZ: ;extract queue size word from dte CLR R0 SAVE R2 MOV #TOXFSZ,R2 ADD DTEHSM(R3),R2 EXAM R2,,69$ MOV TE.XW3(R5),R0 ;get it into proper register 69$: RESTOR R2 RETURN DTSTRT: ;subroutine to start to-11 transfer ;R0 = byte count ;R1 = address to read to ;TCSTFX must have status word after last doorbell NEG R0 ;make byte count negative and set carry BIC #170000,R0 ;clear status bits at top of count word RORB R0 ;divide negative byte count by two BIT #TO.FWD,TCSTFX+2 ;was this supposed to be word mode? BNE 10$ ;yes, skip setting byte flag ROLB R0 ;restore original negative byte count BIS #TS.EBM,R0 ;set byte mode 10$: BIS #TS.IFB,R0 ;set to interrupt both on done MOV R1,TE.EAD(R5) ;set address MOV R0,TE.EBC(R5) ; and count (which starts transfer) CLC ;make sure this sucs RETURN SNDHDR: ;subroutine to start sending header to -10 .IF NE,FTFEDV MOV DTACKR,R0 ;check if ack needed BEQ 10$ ;no - just header MOV #DTAKHD,R1 ;yes - R0/size, get ack ptr .IF NE,FTRACE CMP R0,#D10HDL BLE 5$ TRACB TRCPRO,DTAKHD,D10HDL BR 20$ 5$: .ENDC ;.IF NE,FTRACE TRACB TRCPRO,DTAKHD,D10HDL/2 BR 20$ .ENDC ;.IF NE,FTFEDV 10$: .IF EQ,FTP5 MOV #DT10HD,R1 ;point to start address MOV (R1),R0 ;get size of header .IF EQ,FTFEDV TRACB TRCPRO,DT10DF,D10DFL/2 .IFF TRACB TRCPRO,DT10HD,D10HDL/2 ;trace the FEH header .ENDC; .IF EQ,FTFEDV .IFF MOV #DT10DF,R1 ;point to DN60 header MOV RSPSIZ,R0 ;and it's this big TRACB TRCPRO,DT10DF,</2> ;trace the DN60 header .ENDC ;.IF EQ,FTP5 20$: MOV R1,TE.XAD(R5) ;set up -10 address CALL SETQSZ ;send queue size BCS 99$ MOV #TS.TBM,TE.DG3(R5) ;set byte mode (always for header) INCB DT11QC ;increment queue count BIC #TO.IT,DTSTT+2 ;clear TOIT bit to indicate not indirect CALL SETSTS ;deposit status word BCS 98$ CALL CRAMLV ;cram keepalive MOV #TS.EEX,TE.STW(R5) ;ring -10 doorbell 99$: RETURN 98$: DECB DT11QC SEC RETURN ;THIS SUBROUTINE HAS TWO ENTRY POINTS . DTSACK TO SEND ; AN ACK + FEH TO THE TEN AND DTSAK FOR SENDING THE ; ACK ALONE TO THE TEN TO ACKNOWLEDGE RECEIPT OF DATA. .IF NE,FTFEDV DTSACK: MOV #D10HDL*2,R0 ;SEND ACK + FEH TOGETHER BR DTSAC ;SET UP ACK HEADER DTSAK: MOV #D10HDL,R0 ;SEND ONLY THE ACK TO-TEN DTSAC: MOV R0,DTACKR ;set ack flag with length of msg MOV #D10HDL,DTAKHD ;LENGTH OF HEADER MOV #DTFSAK,DTAKFN ;ACK FUNCTION MOV #DLDPFE,DTAKDV ;FE DEVICE CLR DTAKUC ;CLEAR BEFORE PUTTING FE# MOVB DT11UC+1,DTAKUC ;FE# RIGHT JUSTIFIED RETURN .ENDC ;.IF NE,FTFEDV .IF NE,FTFEDV OUTHD: MOV #D10DFL,R0 ;output DN60 header MOV #DT10DF,R1 BR OUTDAT .ENDC ; .IF NE,FTFEDV SNDDAT: ;subroutine to start sending indirect data .IF NE,FTFEDV CLR R0 ;get no. bytes we said we would send BISB DT10UC,R0 .IFF MOV DT10DT,R0 ;get size ready for deposit .IF NE,FTP5 SWAB R0 ;previously swapped BNE 5$ ;check for zero length xfer INC R0 ;yes - xfer 1 fake byte ; DN60 header indicates truth 5$: .ENDC ;IF NE,FTP5 .ENDC ; .IF NE,FTFEDV MOV #OUTBUF,R1 ;get big buffer ptr OUTDAT: ;output data ;R0/bytes to send ;R1/buffer ptr CALL SETQSZ ;set queued protocol transfer size BCS 99$ MOV R1,TE.XAD(R5) ;set output address .IF NE,FTP5 BIC #TO.IND,DTSTT+2 ;all version 5 xfers are direct INCB DT11QC ;increment queue count BIC #TO.IT,DTSTT+2 ;clear TOIT bit to indicate not indirect .IFF BIS #TO.IND,DTSTT+2 ;say we are doing indirect transfer .ENDC ;IF NE,FTP5 MOV #TS.TBM,TE.DG3(R5) ;set byte mode in hardware CALL SETSTS ;deposit status .IF NE,FTP5 BCS 98$ .IFF BCS 99$ .ENDC ;.IF NE,FTP5 CALL CRAMLV ;cram keepalive MOV #TS.EEX,TE.STW(R5) ;ring -10 doorbell 99$: RETURN .IF NE,FTP5 98$: DECB DT11QC SEC RETURN .ENDC ;.IF NE,FTP5 ;DLWEDN ;subroutine to wait for examine/deposit done ; THIS SUBROUTINE WAITS FOR EXAMINE/DEPOSIT TRANSFERS AND ; CHECKS TO SEE THAT E BOX HAS NOT STOPPED. ; CALL: CALL DLWEDN ; R5 -- ADDRESS OF DTE-20 ; ON RETURN: ; C = 0: SUCCESS ; C = 1: ERROR .ENABL LSB DLWEDN: MOV #3000,DTEDTO ;SET UP TIMEOUT FOR TS.XDNE 11$: BIT #TS.XDN,TE.STW(R5) ;WAIT FOR TRANSFER TO COMPLETE BNE 12$ ;DONE DEC DTEDTO ;TIMEOUT? BNE 11$ ;NO -- CONTINUE WAITING ATRACE <(SP),TE.STW(R5)>;trace this if anything is traced EXMFAL: SEC ;YES, ERROR. RETURN ; HERE WHEN THE TRANSFER IS COMPLETE. 12$: BIT #TS.EPE,TE.STW(R5) ;CHECK FOR E BUS PARITY ERROR BNE 13$ ;WE HAVE E-BUS PARITY TRACE TRCDTE,TE.STW(R5) EXMSUC: CLC ;CLEAR CC-C RETURN ; WE HAVE AN E-BUS PARITY ERROR. CALL THIS A FATAL ERROR. 13$: STOPCD DTE20 ;E-BUS PARITY ERROR .DSABL LSB SAVDTE: ;subroutine to save DTE registers SAVE ;save registers MOV DTEBAD,R5 ;point to DTE MOV #-1,DTEMSK ;assume all registers NXM MOV #DTERGS,R2 ;point to table SAVE NXMGO MOV #10$,NXMGO MOV #100000,R3 ;mask bit for first register 5$: MOV @R5,(R2) ;save register (or cause NXM) BIC R3,DTEMSK ;clear its bit 6$: ADD #2,R5 ;point to next register ADD #2,R2 ;don't use auto-increment because ; it is unpredictable around NXM CLC ROR R3 ;shift bit BNE 5$ ; until shifted away RESTOR NXMGO RESTOR ;restore registers RETURN 10$: ;here on NXM MOV #70707,@R2 ;save distinctive pattern for NXM BR 6$ ; and continue DTEMSK: .WORD 0 ;B15=reg 0,B14=reg 1, etc. DTERGS: .BLKW 20 ;copy sixteen words of DTE .SBTTL Examine/Deposit functions ;The examine and deposit requests are handled completely at interrupt level, ;so that we can examine a DN60 that is looping at task level. DLTEXM: ;subroutine to do examine/deposit CALL CPYHDR ;setup output header .IIF NE,FTP5, MOV #6,RSPSIZ ;default examine response size CMPB DT10DF,#DF.DEP ;is this a deposit function? BNE 10$ ;no, default length OK .IF EQ,FTP5 MOV #D10HDL+2,DT10HD ;yes, deposit data is only 1st word of DN60 header .IFF MOV #2,RSPSIZ ;send only the 1st word of the DN60 header .ENDC ;.IF EQ,FTP5 10$: SAVE NXMGO ;save previous NXM trap MOV #50$,NXMGO ;where to go on NXM CMPB DT11DF,#DF.DEP ;is it deposit? BEQ 20$ ;yes, go do it MOV @DT11AD,DT10DT ;pick up word or NXM 11$: RESTOR NXMGO ;put back old NXM trap MOVB #1,DT10DF+1 ;put success result code RETURN ;return to caller 20$: MOV DT11DT,@DT11AD ;store data or get NXM BR 11$ ;success, return OK 50$: ;here if examine/deposit NXM RESTOR NXMGO ;restore old NXM trap MOVB #3,DT10DF+1 ;set reject code for result RETURN ; and exit .SBTTL General subroutines SWPHDR: ;routine to swap header pointed to by R0 .IF EQ,FTP5 SWAB DT11HD-DT11HD(R0) ;swap first word (queued protocol length) SWAB DT11FN-DT11HD(R0) ;swap queud protocol function SWAB DT11DV-DT11HD(R0) ;swap queued protocol device code .IF NE,FTFEDV SWAB DT11UC-DT11HD(R0) ;swap fe#,bytes RETURN .ENDC ; .IF NE,FTFEDV .ENDC ;.IF EQ,FTP5 SWPHDF: SWAB DT11DF-DT11HD(R0) ;swap DN60 function,,result SWAB DT11AD-DT11HD(R0) ;swap address for dep/exam, or line,,dev SWAB DT11DT-DT11HD(R0) ;swap dep data or indirect length .IF NE,FTP5 SWAB DT11A3-DT11HD(R0) ;swap remaining args SWAB DT11A4-DT11HD(R0) ;swap remaining args SWAB DT11A5-DT11HD(R0) ;swap remaining args SWAB DT11A6-DT11HD(R0) ;swap remaining args SWAB DT11A7-DT11HD(R0) ;swap remaining args .ENDC ;IF NE,FTP5 RETURN ;exit VALHDR: ;validate fe header pointed to by R0 .IF EQ,FTP5 .IF NE,FTFEDV CMP DT11DV-DT11HD(R0),#DLDPFE;make sure device is DN60 device BNE 10$ ;if not, return error CMPB DT11FN-DT11HD(R0),#DTFSAK ;check for ack FEH BEQ 99$ ;yes - valid header, no indirect coming TST DT11FN-DT11HD(R0) ;check if indirect BPL 10$ ;this is not so pretty good CMPB DT11FN-DT11HD(R0),#DTFSTR;make sure function is string data BEQ 99$ ;if so, all is kosher ;if not, this header is to be ignored! ;unbelievable !!!! .IFF CMPB DT11FN-DT11HD(R0),#DTFDAS;make sure function is DN60 BNE 10$ ;if not, return error CMP DT11DV-DT11HD(R0),#DLDDAS;make sure device is DN60 device BEQ 99$ ;if so, don't set error .ENDC ; .IF NE,FTFEDV 10$: SEC RETURN .ENDC ;.IF EQ,FTP5 99$: CLC RETURN CPYHDR: ;subroutine to copy input to output header .IF EQ,FTP5 .IF NE,FTFEDV MOV #D10HDL,DT10HD ;size of output header .IFF MOV #D10HDL+D10DFL,DT10HD ;size of output header .ENDC ; .IF NE,FTFEDV MOV DT11DV,DT10DV ;copy queued protocol device MOV DT11FN,DT10FN ;copy queued protocol function .IF NE,FTFEDV BIS #100000,DT10FN ;set indirect bit MOVB DT11UC+1,DT10UC+1 ;xfer the FE # MOVB #D10DFL,DT10UC ;set the bytes to follow to DN60 header size .IFF BIC #100000,DT10FN ;clear indirect bit .ENDC ; .IF NE,FTFEDV .IFF MOV #D11DFL,RSPSIZ ;set response header size .ENDC ;.IF EQ,FTP5 CPYDFL: MOV DT11DF,DT10DF ;copy DN60 function MOV DT11AD,DT10AD ;copy address or line,,dev CLR DT10DT ;clear data transferred .IF NE,FTP5 CLR DT10A3 ;precleen response header CLR DT10DS CLR DT10DS+2 CLR DT10LS CLR DT10LS+2 .ENDC ;IF NE,FTP5 RETURN ;done .SBTTL Interface to read/write data part of message .REPT 0 This interface consists of 4 routines, BLECHI and BLECHO to read and write blocks of data, and BYTCHI and BYTCHO to read and write a single byte. The first two have a byte count in R0 and an address in R1, the latter two simply transfer the single byte to/from R0. .ENDR;.REPT 0 BLECHI: ;block transfer in TRACE TRCTEN,<(SP),TCXLT(R5),R0,INPCTR> CLR -(SP) ;assume 0 bytecount returned CMP R0,INPCTR ;see if request too big BLE 10$ ;no, assumption right so branch SUB INPCTR,R0 ;yes, calculate returned bytecount MOV R0,(SP) ;save it for later MOV INPCTR,R0 ;change request to amount we have 10$: SAVE R2 ;save source address register MOV INPPTR,R2 ;get source address SUB R0,INPCTR ;update input count CLC ;ensure carry bit clear BIT #1,R2 ;source address odd? BNE 20$ ;yes, go check for match BIT #1,R1 ;destination address even too? BNE 50$ ;no, go do byte moves for mismatch 30$: ROR R0 ;divide by two to get words BEQ 32$ ;if none, go check for extra byte 31$: MOV (R2)+,(R1)+ ;copy word SOB R0,31$ ;loop till count exhausted 32$: BCC 33$ ;if original count was not odd, go finish MOVB (R2)+,(R1)+ ;else copy odd byte CLC 33$: MOV R2,INPPTR ;update input pointer RESTOR ;restore work register and set count remaining ;plus condition codes RETURN 20$: BIT #1,R1 ;is destination address odd BEQ 50$ ;no, go process mismatch MOVB (R2)+,(R1)+ ;copy preceding odd byte SOB R0,30$ ;update count and jump into loop if more BR 33$ ;just exit if that was all 50$: MOVB (R2)+,(R1)+ ;copy one byte SOB R0,50$ ;repeat till count exhausted BR 33$ ;go finish up BLECHO: ;block transfer out TRACE TRCTEN,<(SP),TCXLT(R5),R0,R1> CLR -(SP) ;assume 0 bytecount returned CMP R0,OUTCTR ;see if request too big BLE 10$ ;no, assumption right so branch SUB OUTCTR,R0 ;yes, calculate returned bytecount MOV R0,(SP) ;save it for later MOV OUTCTR,R0 ;change request to amount we have 10$: SAVE R2 ;save destination address register MOV OUTPTR,R2 ;get destination address SUB R0,OUTCTR ;update remaining output count CLC ;ensure carry bit clear BIT #1,R2 ;destination address odd? BNE 20$ ;yes, go check for match BIT #1,R1 ;source address even too? BNE 50$ ;no, go do byte moves for mismatch 30$: ROR R0 ;divide by two to get words BEQ 32$ ;if none, go check for extra byte 31$: MOV (R1)+,(R2)+ ;copy word SOB R0,31$ ;loop till count exhausted 32$: BCC 33$ ;if original count was not odd, go finish MOVB (R1)+,(R2)+ ;else copy odd byte CLC 33$: MOV R2,OUTPTR ;update output pointer RESTOR ;restore work register and set count remaining ;plus condition codes RETURN 20$: BIT #1,R1 ;is source address odd BEQ 50$ ;no, go process mismatch MOVB (R1)+,(R2)+ ;copy preceding odd byte SOB R0,30$ ;update count and jump into loop if more BR 33$ ;just exit if that was all 50$: MOVB (R1)+,(R2)+ ;copy one byte SOB R0,50$ ;repeat till count exhausted BR 33$ ;go finish up BYTCHI: ;input one byte TST INPCTR BGT 10$ CLC SEZ RETURN 10$: DEC INPCTR CLR R0 BISB @INPPTR,R0 INC INPPTR TRACE TRCTEN,<(SP),TCXLT(R5),R0> CLRC CZ RETURN BYTCHO: ;output one byte TRACE TRCTEN,<(SP),TCXLT(R5),R0> TST OUTCTR ;any room? BGT 10$ ;yes, continue CLC SEZ RETURN 10$: DEC OUTCTR MOVB R0,@OUTPTR INC OUTPTR CLRC CZ RETURN .IF NE,DTBUG .SBTTL Debugging subroutines STKSAV: ;subroutine to save state machine stack SAVE ;save some registers MOV #SAVSTK,R1 ;point to source MOV #INTSTK,R0 ;address of source MOV #STKLEN,R2 ;get count 10$: MOV -(R0),-(R1) ;push onto save stack SOB R2,10$ ;copy whole stack MOV SP,R2 ;copy current pointer SUB #INTSTK,R2 ;displacement ADD #SAVSTK,R2 ; into saved stack MOV R2,SAVSTK ;save stack pointer 20$: RESTOR RETURN .ENDC;.IF NE,DTBUG