Google
 

Trailing-Edge - PDP-10 Archives - BB-BT99T-BB_1990 - 10,7/mon/dteser.mac
There are 13 other files named dteser.mac in the archive. Click here to see a list.
TITLE DTESER - DTE20 INTERFACE ROUTINES V473
SUBTTL E.SOCCI/EVS/EJW/JBS/DRL/EGF/VJB/SSG	06-FEBRUARY-90

	SEARCH	F,S,NETPRM,DTEPRM,D36PAR,MACSYM
	T10SYM	;TO DEFEAT MACSYM
	$RELOC
	$HIGH


;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1976,1977,1978,1979,1980,1982,1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1976,1990>

XP VDTESR,473


;NOTE:
; IF ANY CHANGES ARE MADE TO DTEPRM THAT DTESER MUST HAVE, UPDATE
; THE FOLLOWING SYMBOL TO THE VERSION OF DTEPRM THAT MUST BE USED
	PRMMIN==73
; THIS WAY, ASSEMBLING THIS MODULE WITH WRONG VERSION OF DTEPRM FOR SOME REASON
; (LIKE FORGETTING TO ASSEMBLE IT) WILL CAUSE ASSEMBLY TO TERMINATE
; THIS SCHEME DOES NOT CAUSE EXTRA EDITING, SINCE ONLY FILES
; WHICH NEED THE CHANGES NEED PRMMIN TO BE UPDATED. MODULES
; THAT DO NOT NEED A NEW VERSION OF DTEPRM NEED NOT DEMAND IT.

IFL VDTPRM-PRMMIN,<PRINTX ?PLEASE USE LATEST VERSION OF DTEPRM
			PASS2
			END>
	SALL		;CLEAN MACRO EXPANSIONS
	ENTRY	DTESER
DTESER::

	PPCPI==SCNCHN##
	SPCPI==SCNCHN##	;***TEMPORARY
;DTESER IS THE ONE AND ONLY MODULE IN THE MONITOR WHICH DEALS
; WITH DTE20S DIRECTLY.  DTESER CONTAINS ROUTINES TO DRIVE BOTH
; PRIMARY (AS IT EXISTS IN THE RSX20 FRONT END) AND SECONDARY
; (AS IT EXISTS IN BOTH RSX20 AND KLDCP) PROTOCOLS.  SEE
; KLCOM.MEM FOR A DEFINITION OF THE QUEUED PROTCOL VERSION 1 AND
; QPRV2.MEM FOR THE CHANGES IN VERSION 2.
;
;DTESER NOW DEALS WITH BOTH VERSIONS OF THE DTE'S PROTOCOL.
; THE PROTYP FIELD (AS DEFINED IN QPRV2.MEM) CONTAINS THE PROTOCOL
; TYPE IN USE (THIS FIELD IS CALLED EC.PRT IN THE DTEPRM COMM AREA
; DEFINITIONS).  THE VALUE OF THIS FIELD IS 0 FOR THE OLD PROTOCOL
; AND 1 FOR THE NEW MCB (QPR V2) ONE.
;
;THE FOLLOWING COMMENTS DEAL WITH QPR V1.
;
;DTESER CONTAINS THE TO-11 QUEUE MECHANISM FOR THE PRIMARY PROTOCOL,
; THE DTE20 INTERRUPT SERVICE AND PROTOCOL MESSAGE HANDLER, AND
; PROTOCOL DEVICE SERVICE ROUTINES DEALING WITH OPERATION OF THE
; FRONT END (DATE/TIME, INITIAL MESSAGES, ETC).  THE CODE THAT
; DRIVES THE VARIOUS FRONT END DEVICES (NETWORK TTYS, LOCAL TTYS,
; FRONT END DEVICE, CTY) RESIDES MOSTLY IN INDIVIDUAL DEVICE DRIVER
; MODULES SEPARATE FROM DTESER.
;
;THESE DEVICE DRIVERS MUST OBEY THE FOLLOWING CONVENTIONS.
;
;TO-10 MESSAGE RECEIPT
;
;DTESER CALLS THE DRIVER WITH THE FOLLOWING ACS SET UP:
;	P1/10 CPU#,,DTE # (0-3)
;	P2/DEVICE,,FUNCTION
;	P3/LINE,,DATA OR COUNT (ALWAYS 8 BIT BYTES)
;	P4/BYTE POINTER
;	F/DTE CONTROL BLOCK ADDRESS (ETD)
;
; P3 AND P4 CONTAIN COUNT AND POINTER FOR LONG DIRECT AND INDIRECT
; TYPE MESSAGES.  ACS P1-P4 AND S ARE USED THROUGHOUT DTESER
; TO PASS THE ABOVE INFORMATION BETWEEN DTESER AND THE DRIVERS.
; THE USE OF THE FIELDS WITHING THESE ACS IS ALSO CONSISTENT.
; SEE THE COMMENT AT DTEQUE FOR A DESCRIPTION OF THE CONVENTION
; FOR THE CONTENTS OF P1-P4 AND S.
;
;THE DRIVER MAY USE ACS P3,P4 AND F BUT MUST PRESERVE P1 AND P2.
; IF THE DRIVER WISHES TO RESTORE THE CONTENTS OF F,
;	MOVE	F,P1
;	PUSHJ	P,GTETDS##
; WILL RESET F
;IF THE RECEIVED FUNCTION IS INDIRECT, THE DRIVER IS REQUIRED TO
; RETURN TO DTESER WITH AN 8 BIT BYTE COUNT AND BYTE POINTER IN P3 AND P4,
; RESPECTIVELY.  A NON-ZERO POST ADDRESS MUST BE SPECIFIED IN LH(S).
; THE DRIVER DOES NOT GET THE 16 BIT MODE BIT SET IN THE FUNCTION
; CODE ON INDIRECT MESSAGES, SINCE IT IS NOT KNOWN AT THAT POINT
; WHICH MODE THE 11 WILL SEND THE DATA. THE DRIVER IS
; THEREFORE RESPONSIBLE FOR KNOWING, BASED ON THE FUNCTION CODE
; AND/OR THE DEVICE, WHICH MODE THE DATA WILL BE COMING IN.
; IN GENERAL, BYTE STRINGS COME IN BYTE MODE AND WORD STRINGS
; COME IN WORD MODE.
;
;INDIRECT MESSAGES CAN BE RECEIVED PIECEMEAL BY THE DRIVERS.
; WHEN A FRAGMENT OF AN INDIRECT DATA PACKET IS RECEIVED BY DTESER,
; THE DRIVER'S POST ROUTINE IS CALLED. P3 CONTAINS THE NUMBER OF
; 8 BIT BYTES OF INDIRECT DATA AVAILABLE TO THE DRIVER
; AT THIS POINT, AND P4 CONTAINS THE ADDRESS OF THE LAST INDIRECT BYTE POINTER.
; EITHER THE DRIVER RETURNS
; C(P3)=0, WHICH INDICATES THAT THE DRIVER WANTS NO MORE DATA,
; OR THE DRIVER HAS SET UP LH(S) TO BE THE NEW POST ADDRESS,
; P3 THE NEW 8 BIT BYTE COUNT, AND P4 THE NEW BYTE POINTER.
; DTESER KEEPS TRACK OF HOW MANY BYTES ARE IN THE ENTIRE
; INDIRECT PACKET, AND ENSURES THAT THE DRIVER TAKES EXACTLY
; ALL OF THEM.
;
;TO-11
;
;THE DRIVER SETS UP S, P1-P4 WITH THE STANDARD INFORMATION.
; THE DRIVER MUST SAVE P1-P4 BEFORE USING THEM FOR THIS PURPOSE.
; LH(S) GETS THE POST ADDRESS, TO WHICH CONTROL IS PASSED
; UPON COMPLETION OF THE ENTIRE MESSAGE (AFTER DIRECT, OR ALL OF
; INDIRECT), AND RH(S) CAN BE USED BY THE DRIVER FOR STORED INFORMATION.
; IF THE DRIVER NEEDS TO REMEMBER MORE THAN 18 BITS WORTH OF INFORMATION,
; IT IS RECOMMENDED THAT A CHUNK OF CORE BE ALLOCATED AND THE ADDRESS
; OF THE CORE CAN BE REMEMBERED IN S.
; AT POST TIME, DTESER PUTS THE CPU AND DTE NUMBER IN P1,
; THE DEVICE CODE AND FUNCTION CODE IN P2, THE LINE NUMBER
; IN LH(P3) (THIS NUMBER SHOULD BE IGNORED
; FOR FUNCTIONS NOT CONTAINING A UNIQUE LINE NUMBER),
; AND IF THE TO-11 FUNCTION WAS INDIRECT, THE INDIRECT
;  8 BIT BYTE COUNT IN RH(P3), AND THE BYTE POINTER
; IN C(P4).
;ALL DRIVERS SHOULD BE PREPARED TO LOSE ACKS BECAUSE OF TEMPORARILY
; LEAVING PRIMARY PROTOCOL, AND TO RECOVER FROM THE LOST ACKS
; BY PROCESSING THE ACK ALL MESSAGE CORRECTLY.  EACH DRIVER WILL
; GET A SIMULATED ACK ALL MESSAGE FOR EACH DEVICE IN TABLE ACKTAB,
; AND IS RESPONSIBLE FOR SCANNING ALL UNITS ON THE PROTOCOL DEVICE
; TO ACKNOWLEDGE ANY THAT ARE WAITING FOR ACKS.  IT IS ALSO A GOOD
; IDEA TO CODE THE DRIVERS SUCH THAT A FREE ACK CAUSES NO DAMAGE.
;THE PURPOSE OF USING ACS P1-P4 IN A CONSISTENT MANNER WAS TO
; TRY TO KEEP ALL KNOWLEDGE OF PROTOCOL FORMATS IN DTESER.  HOWEVER,
; THE DRIVERS MUST STILL KNOW THE EXACT FORMAT OF LONG DIRECT AND
; INDIRECT MESSAGES FOR BOTH TO-10 AND TO-11 DIRECTIONS, SINCE
; THEY PROVIDE/ARE PROVIDED WITH BYTE POINTERS TO PROTOCOL SPECIFIC
; DATA. THE ALTERNATIVE TO THIS IS TO HAVE DTESER CALL/BE CALLED
; BY THE DRIVERS FOR ALL DATA IN INDIRECT AND LONG DIRECT MESSAGES.
; THIS WOULD MAKE DTESER SLOWER AND PREVENT THE DRIVERS FROM TAKING
; ADVANTAGE OF THE INDIRECT CAPABILITY (FILLING USER BUFFERS, FOR EXAMPLE)

;This module searches D36PAR for symbols, but does not use the LOAD
;and STOR functions they expect.  Thus we make the following checks to
;assure that the MOVEs in this module will be OK.

;The assignment under IFE FTDECNET is to allow the module to compile
;without searching D36PAR, which is under IFN FTDECNET.  Note that the
;code does not run this way that we should feature test out all the
;DECnet code.  That would require more testing, though.  The value
;400000 is intended to cause an IME if the DECnet code is exercised at
;the wrong time.


DEFINE CHKWRD(prefix,symbol),<
IFN prefix'symbol+1,<PRINTX ?prefix'symbol MUST BE A FULL-WORD FOR DTESER>
IFE FTDECNET,<prefix'.'symbol==400000>
>

	CHKWRD (MD,NXT)
	CHKWRD (MD,BYT)
	CHKWRD (MD,AUX)
	CHKWRD (MD,ALA)
SUBTTL DTE20 INITIALIZATION ROUTINES


;ROUTINE TO INITIALIZE ALL DTES ON A CPU
; CALL WITH CPU NUMBER IN T1

DTEINI::PUSH	P,P1		;SAVE P1 AND P2
	PUSH	P,P2		;FOR USE AS FLAGS
	HRLZ	P1,T1		;GET 10 NUMBER IN LH(P1), START WITH DTE
				; NUMBER EQUAL TO ZERO IN RH(P1)
	SETZ	P2,		;CLEAR MASTER 11 SEEN FLAG

DTEIN1:	MOVE	F,P1		;SETUP F WITH 10#,,DTE#
	PUSHJ	P,GETETD	;GET DTE CONTROL BLOCK ADDRESS IN F
	  JRST	DTEIN2		;RETURN, NO MORE BLOCKS LEFT.
	PUSHJ	P,DTEINA	;INITIALIZE ONE DTE
	MOVSI	T1,(ED.DTX)	;IF THIS DTE DOESN'T EXIST
	TDNE	T1,ETDSTS(F)	;THEN IT CANT BE MASTER
	SKIPE	P2		;SEEN A MASTER YET?
	AOJA	P1,DTEIN1	;YES, LOOP ON

;NOTE THAT RM BIT IS OFF FOR NON-EXISTANT DTES
	XCT	ETDCNI(F)	;CONI DTEN,T1
	TRNE	T1,RM		;RESTRICTED?
	AOJA	P1,DTEIN1	;YES.
	SETOM	P2		;NO, FLAG THAT THIS IS MASTER
	MOVSI	T1,(ED.DTM)
	IORM	T1,ETDSTS(F)	;FLAG THAT THIS IS MASTER IN ETD BLOCK
	LOAD.	T1,ED.CPN,(F)	;GET CPU NUMBER OF THIS DTE
	MOVEM	F,DTEMAS##(T1)	;REMEMBER MASTER DTE FOR THIS CPU
	MOVE	T2,.CPTTD##	;GET M'N'TTDN
	STOR.	T2,ED.ATN,(F)	;STORE NUMBER OF TERMINALS IN ETD
	AOJA	P1,DTEIN1	;LOOP ON

DTEIN2:	SKIPN	P2		;HAS A MASTER BEEN LOCATED AT ALL?
	STOPCD	.,STOP,DTEMDM,	;++NO MASTER DTE
	POP	P,P2		;YES, RESTORE P2 AND
	POP	P,P1		;P1 AND
	POPJ	P,		;RETURN
;HERE TO INITIALIZE A DTE, DTE CONTROL BLOCK ADDRESS IN F

DTEINA:	MOVEI	T1,CLRDTE+PILDEN+SPCPI
				;CLEAR DTE, TRY SETTING PI ASSIGNMENT
	XCT	ETDCNO(F)	;CONO DTEN,(T1)
	XCT	ETDCNI(F)	;CONI DTEN,T1
	MOVE	T2,T1		;GET COPY OF CONI WORD
	ANDI	T2,7		;JUST PI ASSIGNMENT
	CAIE	T2,SPCPI	;DID WE SET PI?
	POPJ	P,		;NO, DTE IS NON-EXISTANT

	MOVEI	T1,CLRDTE+PILDEN+0;RESET PI ASSIGNMENT TO ZERO
	XCT	ETDCNO(F)	;DO IT
	MOVX	T2,ED.CST	;GET STATUS CLEARING BITS
	ANDCAM	T2,ETDSTS(F)	;CLEAR OUT BITS TO BE CLEARED
	MOVSI	T2,(ED.DTX)	;YES. MARK AS EXISTANT
	IORM	T2,ETDSTS(F)	;DTE EXISTS. CLEAR OUT REST OF WORD
	LOAD.	T4,ED.DTN,(F)	;GET DTE NUMBER
	ASH	T4,3		;*^D8
	MOVE	T3,.CPEPT##	;GET EPT ADDRESS
	ADDI	T4,DTEHBG(T3)	;GET TO BEGINNING OF EPT REGION FOR THIS DTE
	MOVEI	T1,1(T4)	;MAKE BLT POINTER
	HRL	T1,T4
	SETZM	(T4)		;CLEAR FIRST WORD
	BLT	T1,DTEHBE-DTEHBG(T4);CLEAR HARDWARE LOCS
	MOVSI	T1,(XPCW)	;THE RIGHT INSTRUCTION TO CATCH A DOUBLE WORD PC

	HRRI	T1,ETDINT(F)	;GET INTERRUPT ADDRESS
	MOVEM	T1,DTEDII-DTEHBG(T4);SETUP INTERRUPT JSR
	POPJ	P,		;RETURN
SUBTTL SECONDARY PROTOCOL ROUTINES
	SPCTRY==50000		;NUMBER OF TIMES TO CHECK COMMAND COMPLETE


;ROUTINE TO TYPE 1 CHAR ON CTY (DATAO TTY,CHAR)
;CALL WITH:
;	T3= CHARACTER TO TYPE
;	PUSHJ	P,SPCTYO
;	RETURN HERE
;CALLERS RESPONSIBILITY TO WAIT FOR OUTPUT DONE.
;
SPCTYO::PUSH	P,T1		;SAVE T1
	ANDI	T3,377		;JUST CHAR AND PARITY
	MOVEI	T1,DT.MTO(T3)	;STORE IN DTECMD
	PUSHJ	P,SPCMD		;DO THE COMMAND
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
;ROUTINE TO GET DATE/TIME FROM -20F
;CALL WITH:
;	PUSHJ	P,SPCGDT
;	 NOT CAPABLE OR FAILED OR NOT VALID
;	SUCCEEDED, LOCxxx UPDATED

SPCGDT::MOVE	T1,.CPSPF##	;GET OUR SECONDARY PROTOCOL FLAGS
	TRNE	T1,DF.GDT	;DOES THIS -20F SUPPORT DT.GDT?
	POPJ	P,		;NO, ERROR RETURN
	PUSHJ	P,GTEPT		;GET EPT OFFSET FOR CFE
	SETOM	.EPDTM##(T4)	;ASSUME FAILURE
	MOVE	T1,[.EPDTM##*1B19+DT.GDT]	;COMMAND FOR -20F
	PUSHJ	P,SPCMD		;BEG, GROVEL, AND WHINE
	SKIPLE	T1,.EPDTM##(T4)	;DID WE GET A VALID RESULT?
	TDNN	T1,[177777B19]	;YES, IS THE VALIDITY FLAG SET?
	POPJ	P,		;NO, WE FAILED
	ANDI	T1,177777	;GET YEAR
	MOVEM	T1,LOCYER##	;STORE IT
	LDB	T1,[POINT 8,.EPDTM##+1(T4),11]	;MONTH
	AOJ	T1,		;MAKE JAN = 1
	MOVEM	T1,LOCMON##	;STORE IT
	LDB	T1,[POINT 8,.EPDTM##+1(T4),19]	;DAY
	AOJ	T1,		;MAKE THE FIRST = 1
	MOVEM	T1,LOCDAY##	;STORE DAY
;	LDB	T1,[POINT 8,.EPDTM##+1(T4),27]	;DAY OF WEEK 0 = MONDAY
;	LDB	T1,[POINT 8,.EPDTM##+1(T4),35]	;DST FLAG
	LDB	T1,[POINT 16,.EPDTM##+2(T4),19]	;SECONDS SINCE MIDNIGHT /2
	LSH	T1,1		;SECONDS
	IDIVI	T1,^D60		;MAKE SECONDS INTO THIS MINUTE
	MOVEM	T2,LOCSEC##	;STORE SECOND
	IDIVI	T1,^D60		;EXTRACT HOUR AND MINUTE
	MOVEM	T1,LOCHOR##	;HOUR
	MOVEM	T2,LOCMIN##	;MINUTE
	JRST	CPOPJ1##	;DONE
;ROUTINE TO RETURN SECONDARY PROTOCOL FLAGS IN .CPSPF.
;PRESERVES ALL ACS

SPCGSF:	PUSHJ	P,SAVT##	;SAVE SOME ACS
	SETZ	T3,		;GET AN (EVEN PARITY) NULL
	PUSHJ	P,SPCTYO	;TYPE IT SO WE CAN GET THE DONE FLAG
	MOVE	T4,.CPEPT##	;GET ADDRESS OF EPT FOR THIS CPU
	SKIPN	T1,DTEMTD(T4)	;GET THE DONE FLAG (CONTAINS ^-NEW FEATURES)
	JRST	.-1		;WAIT FOR IT
	SETZM	DTEMTD(T4)	;GOT THE FEATURES MASK, CLEAR DONE
	MOVEM	T1,.CPSPF##	;SAVE FLAGS FOR LATER USE
	POPJ	P,		;RETURN
;ROUTINE TO SEND COMMAND OVER SECONDARY PROTOCOL
; CALL WITH COMMAND IN T1. RESPECTS ALL ACS BUT T1.
; SAVES/RESTORES STATE OF PI.PIA IN CASE OF ERRORS THAT TRAP THRU
; THE PAGE FAULT MECHANISM

SPCMD::	PUSHJ	P,SVEPTD	;SAVE F,T4 AND GET DTE CTL
				; ADDRESS, EPT ADDRESS OF THIS CPU
	PUSH	P,T1		;SAVE COMMAND
	CAIN	T1,DT.ESP	;ENTERING SECONDARY PROTOCOL IS OK IF
				; NOT IN SECONDARY PROTOCOL
	JRST	SPCMD1		;SO DON'T CHECK
	MOVSI	T1,(ED.SPC)	;IS SECONDARY PROTOCOL RUNNING ON THIS DTE?
	TDNN	T1,ETDSTS(F)	;?
	JRST	TPOPJ##		;NO
SPCMD1:	SETZM	DTEFLG(T4)	;CLEAR DONE FLAG
	CONI	PI,T1		;PI STATUS
	CONO	PI,PI.OFF	;NO, TURN OFF SO WE GET TO PUT COMMAND
				; IN AND RING DOORBELL, ENSURING THAT 11
				; WILL SEE SO A HIGHER LEVEL CAN CHECK DTEFLG
	EXCH	T1,(P)		;SAVE PI STATE, RESTORE COMMAND
	MOVEM	T1,DTECMD(T4)	;PUT COMMAND IN THE RIGHT WORD
	MOVEI	T1,TO11DB	;RING DOORBELL
	XCT	ETDCNO(F)
	POP	P,T1		;RESTORE FORMER PI STATUS
	TRNE	T1,PI.PIA	;WAS PI SYSTEM ON?
	CONO	PI,PI.ON	;YES, THEN TURN IT ON
	MOVE	T1,DTECMD(T4)	;GET COMMAND IN PROGRESS
	ANDI	T1,17B27	;JUST COMMAND, NOT DATA
	CAIN	T1,DT.MTO	;OUTPUT?
	POPJ	P,		;YES, OUTPUT COMMAND DOESNT SET DTEFLG
	MOVEI	T1,SPCTRY	;TRY THIS MANY TIMES
	SKIPN	DTEFLG(T4)	;COMMAND DONE YET?
	SOJG	T1,.-1		;NO, WAIT FOR A WHILE
	SKIPG	T1		;OK?
	PJSP	T1,DTERLD	;NO, SECONDARY PROTOCOL DEAD
	SETZM	DTECMD(T4)	;INDICATE SECONDARY PROTOCOL FREE NOW
	POPJ	P,		;RETURN
SPCINT::PUSHJ	P,SVEPTD	;SAVE F,T4 & SGET DTE CTL ADDR, EPT ADDR
	MOVEI	T1,CLRDTE	;CLEAR DOORBELL
	XCT	ETDCNO(F)	;UNDING
	MOVSI	T1,(ED.DTM)	;IS THIS THE MASTER DTE?
	TDNN	T1,ETDSTS(F)	;?
	POPJ	P,		;NO DISMISS INTERRUPT
	HRRZ	U,.CPCTN##	;POINT U TO CTY
	SKIPN	DINITF##	;SYSTEM INITIALIZING?
	SKIPN	LINTAB##(U)	;HAVE AN LDB ADDRESS?
	POPJ	P,		;ONCE TYPEIN/OUT HANDLED DIFFERENTLY
	SKIPN	T1,DTEMTI(T4)	;CHECK FOR INPUT READY
	JRST	SPCODI		;NO INPUT--CHECK FOR OUTPUT DONE
	MOVE	T3,DTEF11(T4)	;WAS INPUT READY, GET CHAR IN T3
	SETZM	DTEMTI(T4)	;CLEAR INTERLOCK SO CAN GET ANOTHER CHARACTER
	ANDI	T3,CK.CHR	;KEEP ONLY CHARACTER
	PUSHJ	P,RECINT##	;AND CALL SCNSER
	PUSHJ	P,GTEPD		;SETUP F AND T4 AGAIN
	SETZ	T1,		;CLEAR T1 AGAIN TO CHECK FOR OUTPUT DONE
	HRRZ	U,.CPCTN##	;POINT U TO CTY

SPCODI:	EXCH	T1,DTEMTD(T4)	;TEST AND CLEAR DTEMTD (T1 WAS ALREADY 0
				; IF THERE WAS NO INPUT READY)
	PJUMPN	T1,XMTINT##	;IF DTEMTD NON-ZERO, WE HAVE OUTPUT DONE
	POPJ	P,		;OTHERWISE DISMISS INTERRUPT
;ROUTINE USED TO WAIT UNTIL INPUT IS PRESENT ON THE CTY WHEN
; THE CTY IS BEING RUN UNDER SECONDARY PROTOCOL.
; SKIP RETURN IF INPUT READY, CHARACTER RETURNED IN T3.
; NON-SKIP IF INPUT NOT AVAILABLE.


SPCGTI::PUSHJ	P,SVEPTD	;SETUP F AND T4 WITH DTE AND EPT ADDRESSES
	MOVSI	T3,(ED.SPC)	;IS SECONDARY PROTOCOL RUNNING ON THIS DTE?
	TDNE	T3,ETDSTS(F)	;IF NOT, INPUT IS NEVER READY.
	SKIPN	DTEMTI(T4)	;INPUT READY?
	POPJ	P,		;NO, RETURN
	MOVE	T3,DTEF11(T4)	;YES, GET CHAR THEN
	SETZM	DTEMTI(T4)	;TELL 11 THAT IT CAN GIVE ANOTHER CHAR
	PJRST	CPOPJ1##	;GIVE SKIP RETURN WITH CHAR IN T3


;ROUTINE TO WAIT FOR SECONDARY PROTOCOL OUTPUT TO COMPLETE.
; USED IN ONCE ONLY OR WHENEVER INTERRUPT SYSTEM CANNOT BE RELIED
; UPON TO FLAG OUTPUT DONE.

SPCWTO::PUSHJ	P,SVEPTD	;SAVE F,T4 AND SETUP DTE, EPT ADDRESSES
	PUSH	P,T1		;SAVE T1
	MOVSI	T1,(ED.SPC)	;IS SECONDARY PROTOCOL RUNNING?
	TDNN	T1,ETDSTS(F)	;?
	JRST	TPOPJ##		;NO
	POP	P,T1		;RESTORE T1
	SKIPN	DTEMTD(T4)	;OUTPUT DONE YET?
	POPJ	P,		;NO, NON-SKIP RETURN
	SETZM	DTEMTD(T4)	;YES, CLEAR FLAG FOR NEXT TIME
	JRST	CPOPJ1##	;AND GIVE OUTPUT DONE RETURN
	SUBTTL	CAL11. UUO


; CAL11. UUO DISPATCH FOR RSX-20F AND MCB DTES
;
; CALLING SEQUENCE IS:
;	MOVE	AC,[XWD LENGTH,BLOCK]
;	CAL11.	AC,
;	  ERROR RETURN
;	OK RETURN
;
; BLOCK:	EXP	FUNCTION CODE
;	ARGUMENT (1) ...
;
;
; ENTER FROM COMDEV WITH P1 CONTAINING CPU#,,DTE# AND DTE BASE IN W
;
; COMDEV DOES THE DISPATCH BASED ON THE FOLLOWING TABLE.  THE HIGH
; ORDER BIT, IF SET, INDICATES THAT THE USER MUST HAVE THE "POKE" PRIV.

C1120F:
C11MCB:	XWD	400000,ECOD2##	;(0) DEPOSIT TO -11
	XWD	400000,ECOD2##	;(1) EXAMINE THE -11
	XWD	400000,ECOD2##	;(2) ERROR (IN DC76: QUE11)
	XWD	0,NAME11	;(3) RETURN NAME OF PGM IN 11
	XWD	0,DOWN11	;(4) IS PORT UP OR DOWN?
	XWD	400000,ECOD2##	;(5) SEND MESSAGE
	XWD	400000,ECOD2##	;(6) RECEIVE MESSAGE
	XWD	0,TYPE11	;(7) NODE & TYPE
MC1120==.-C1120F		;LENGTH OF 20F VECTOR
MC11MC==.-C11MCB		;LENGTH OF MCB VECTOR
;COME HERE TO RETURN THE NAME OF THE PDP-11 PROGRAM.
NAME11:	MOVE	F,P1		;COPY CPU#,,DTE#
	PUSHJ	P,GETETD	;FIND THE ETD
	  JRST	ECOD20##	;ILLEGAL PORT NUMBER
	MOVE	T1,ETDSTS(F)	;GET STATUS WORD
	TLNN	T1,(ED.DTX)	;DOES THIS FE REALLY EXIST?
	JRST	ECOD20##	;ILLEGAL PORT NUMBER
	MOVE	T1,DLXNMT##(W)	;PICK UP NAME
	PJRST	STOTC1##	;SKIP RETURN, GIVING  NAME


;COME HERE TO TELL THE STATUS OF THE PDP-11 PROGRAM.
DOWN11:	MOVE	F,P1		;COPY CPU#,,DTE#
	PUSHJ	P,GETETD	;FIND THE ETD
	  JRST	ECOD20##	;ILLEGAL PORT NUMBER
	MOVE	T1,ETDSTS(F)	;GET STATUS WORD
	TLNN	T1,(ED.DTX)	;DOES THIS FE REALLY EXIST?
	JRST	ECOD20##	;ILLEGAL PORT NUMBER
	TLNE	T1,(ED.PPC)	;PRIMARY PROTOCOL DOWN
	TLNE	T1,(ED.RLD)	; OR THE RELOAD BIT SET?
	TDZA	T1,T1		;SAY THE -11 IS DOWN
	MOVEI	T1,1		;INDICATE UP
	PJRST	STOTC1##	;SKIP RETURN


;HERE TO REPORT NODE & TYPE
TYPE11:	MOVE	F,P1		;COPY CPU#,,DTE#
	PUSHJ	P,GETETD	;FIND THE ETD
	  JRST	ECOD20##	;ILLEGAL PORT NUMBER
	MOVE	T1,ETDSTS(F)	;GET STATUS WORD
	TLNN	T1,(ED.DTX)	;DOES THIS FE REALLY EXIST?
	JRST	ECOD20##	;ILLEGAL PORT NUMBER
	HRRZ	T1,DLXTYP##(W)	;GET TYPE OF FRONT END
	CAIN	T1,.C1CFE	;RSX-20F?
	PJRST	STOTC1##	;NO NODE NUMBER, SO JUST RETURN
	SE1ENT			;DECNET STUFF IN NON-ZERO SECTION
	SKIPE	T2,ETDLBK(F)	;GET ADDRESS OF DLL BLOCK
	LOAD	T2,DLUID,(T2)	;GET ADDRESS OF ROUTER CONTROL BLOCK
	JUMPE	T2,TYP11A	;AVOID IME
	LOAD	T1,RCAJQ,(T2)	;GET ADJACENCY BLOCK ADDRESS
	JUMPE	T1,TYP11A	;JUMP IF NO ADJACENCY (NO NODE NUMBER)
	LOAD	T2,AJNAN,(T1)	;NOW GET THE NODE NUMBER
	LOAD	T1,AJNAA,(T1)	;AND NODE AREA
	LSH	T1,^D10		;POSITION IT
	IOR	T1,T2		;COMBINE IN T1
TYP11A:	HRL	T1,DLXTYP##(W)	;GET TYPE AGAIN
	MOVSS	T1		;MAKE IT NODE,,TYPE
	PJRST	STOTC1##	;AND RETURN
; ROUTINE TO SET THE CAL11. UUO DISPATCH VECTOR POINTER
;	MOVE	F, ETD
;	MOVE	T1, CAL11. DISPATCH ADDRESS
; CALL:	PUSHJ	P,C11VEC
;	RETURN			;ALWAYS
;
C11VEC:	PUSH	P,W		;SAVE W
	MOVE	W,ETDDLX(F)	;POINT TO THE BASE TABLE
	MOVEM	T1,DLXCAL##(W)	;SET ADDRESS
	JRST	WPOPJ##		;RESTORE W AND RETURN
SUBTTL	DTE FEK (GENERIC)

DFKDSP::CAIE	T1,FF.SEC	;SEE IF ONCE-A-SECOND CALL
	POPJ	P,		;NO--IGNORE WHAT WE DON'T CARE ABOUT
	POPJ	P,		;**** TEMP **** CHECK FOR DN60S HERE

;HERE TO SETUP FEK INFORMATION FOR A DTE
;CALL WITH ETD IN F AND LINE-USER IN T2
;RETURN CPOPJ WITH A VALID LINE-USER IN T2 ('NOBODY' OR UNCHANGED)

DFKSET::SKIPL	T2		;IN RANGE?
	CAILE	T2,DD.MAX	;BOTH WAYS?
DFKSE0:	SETZ	T2,		;NO, USE 'NOBODY'
	CAIE	T2,DD.NOB	;IF NOBODY
	CAIN	T2,DD.PRO	;OR PROGRAM
	JRST	DFKSE1		;IT'S ALWAYS OK
	MOVSI	T1,(ED.DTM)	;IS THIS THE MASTER DTE?
	TDNE	T1,ETDSTS(F)	;CHECK
	SETZ	T2,		;YES, USE 'NOBODY' AFTER ALL
DFKSE1:	MOVE	T1,ETDDLX(F)	;POINT TO DS'N'M'BS
	MOVE	T3,DLXFEK##(T1)	;AND TO THE FEK
	MOVSI	T4,^-7		;MASK FOR NON-CPU BITS IN LH
	ANDCAM	T4,FEKUNI(T3)	;CLEAN UP AFTER PREVIOUS USERS
	MOVEM	T2,ETDUSR(F)	;STORE NEW VALUE FOR THE CALLER
	CAIN	T2,DD.PRO	;IF PROGRAM MODE,
	HRLM	J,ETDUSR(F)	;REMEMBER WHICH USER
	JRST	@.+1(T2)	;SETUP THE FEK DATA
	IFIW	DFKUSR		;RSX20F
	IFIW	D8SUSR##	;ANF10
	IFIW	DFKMCB		;DECNET
	IFIW	DFKPRO		;PROGRAM
	IFIW	D6SUSR##	;IBM
REPEAT DD.MAX-DD.IBM,<IFIW DFKUSR> ;UNKNOWN ENTRIES?

DFKNAM::SIXBIT	|NOBODY|
	SIXBIT	|ANF10|
	SIXBIT	|DECNET|
	SIXBIT	|MAINT|
	SIXBIT	|DN60|
IFN DD.MAX-<.-DFKNAM>+1,<PRINTX ? DFKNAM IS WRONG>

DFKUSR::TDZA	T2,T2		;INDEX SHOULD BE RESET TO 'NOBODY'
DFKMCB:	SKIPA	T4,[.C1MCB]	;TYPE OF FE
DFKPRO:	MOVEI	T4,.C1CFE	;TYPE OF FE
	MOVEM	T4,DLXTYP##(T1)	;SET ITS TYPE
	MOVE	T4,ETDSTS(F)	;GET THE STATUS
	TLNE	T4,(ED.DTM)	;IF THE REAL CFE,
	SKIPA	T4,['RSX20F']	;SAY SO (NOT 'NOBODY')
	MOVE	T4,DFKNAM(T2)	;NO--GET TYPE NAME TO USE
	MOVEM	T4,DLXNMT##(T1)	;SET NAME
	MOVE	T4,[PUSHJ P,DFKDSP] ;GENERIC INSTRUCTION
	MOVEM	T4,FEKDSP(T3)	;SET UP ITS DISPATCH INFO
	MOVE	T4,[MC11MC,,C11MCB] ;GET MCB CAL11. INFO
IFN <C11MCB-C1120F>!<MC11MC-MC1120>,<
	CAIE	T2,DD.DEC	;IF A DECNET FE,
	MOVE	T4,[MC1120,,C1120F] ;ELSE USE RSX20F CAL11. INFO
> ;END CHECK FOR DIFFERING CAL11. VECTORS
	MOVEM	T4,DLXCAL##(T1)	;SET IT THAT WAY
	SKIPN	T2		;IF DFKUSR ENTRY,
	SETZM	ETDUSR(F)	;MAKE SURE ETD INFO IS RIGHT
	CAIE	T2,DD.DEC	;UNLESS DECNET,
	POPJ	P,		;NOW WE'RE DONE MESSING UP THE FEK

;Now that we know we are setting the user to DECNET, lets let DECnet
;know so that when the protocol comes up, ROUTER will be ready.

DFKSLD:	MOVX	T3,LILXC!FLD(LD.DTE,LIDEV) ;BUILD A LINE ID FOR THIS DTE
	LOAD.	T1,ED.CPN,(F)	;GET THE CPU#
	STOR	T1,LIKON,+T3	;SAVE AS KONTROLLER NUMBER
	LOAD.	T1,ED.DTN,(F)	;GET THE DTE#
	STOR	T1,LIUNI,+T3	;SAVE AS THE UNIT NUMBER
	MOVEI	T1,DI.ICB	;OPEN THIS CIRCUIT
	PUSHJ	P,CALUSR	;CALL THE DRIVER
	  PJRST	DFKSE0		;FAILURE--RESET TO 'NOBODY'
	MOVEI	T2,DD.DEC	;SUCCESS, RESTORE LINE USER
	POPJ	P,		;RETURN WITH TYPE ACTUALLY SET IN T2
SUBTTL DTE. UUO

;CALL TO DTE. UUO IS:
;	MOVE	AC,<FUNCTION,,ADDR>
;	DTE.	AC,
;	  <ERROR RETURN>
;	<OK RETURN>

UDTE::	PUSHJ	P,SAVE2##
	HRR	M,T1		;ADDRESS OF PARAMETER BLOCK
	HLRE	P1,T1		;GET FUNCTION CODE
	MOVSI	T1,JP.POK	;DISALLOW UNLESS PRIVILEGED
	PUSHJ	P,PRVBIT##	;IS HE?
	  SKIPA			;IS
	JRST	DTUNPE		;ERROR, NO PRIVILEGES
	CAML	P1,[EXP DTUCDS-DTUDSP]	;SKIP IF SMALLER THAN SMALLEST LEGAL
	CAILE	P1,MXDTFN	;OUT OF RANGE?
	JRST	DTUFNE		;YES, FUNCTION NUMBER ERROR
	MOVE	T1,DTUDSP(P1)	;GET FUNCTION AND FLAGS
	TXNN	T1,DF.OWN	;DO I HAVE TO BE OWNER??
	JRST	DTE.1		;NOPE, DON'T BOTHER CHECKING USER
	PUSHJ	P,DTUGTF	;YES, SET UP F FROM CPU,,DTE IN ARG BLK
	MOVE	T1,DTUDSP(P1)	;RESTORE FUNCTION AND FLAGS
	HRRZ	T2,ETDUSR(F)	;GET THE LINE'S USER
	CAIE	T2,DD.PRO	;IS IT PROGRAM MODE?
	JRST	DTE.1		;NO, ANYBODY MAY USE IT
	HLRZ	T2,ETDUSR(F)	;YES, GET THE JOB NUMBER
	CAME	J,T2		;IS IT THE SAME AS OUR CURRENT JOB
	JRST	DTUWRU		;ERROR: WRONG USER FOR FUNCTION

DTE.1:	TXNE	T1,DF.GTF	;SHOULD WE CALL DTUGTF??
	PUSHJ	P,DTUGTF	;YES, SET UP F FROM CPU,,DTE IN ARG BLK
	PUSHJ	P,@DTUDSP(P1)	;DISPATCH BY FUNCTION
	  SOS	(P)		;UUO FAIL RETURN
	SETZ	F,		;CLEAR F FOR UUOXIT
	JRST	CPOPJ1##	; AND RETURN
;DISPATCH TABLE FOR DTE. UUO

DEFINE	FUNCT(ADDR,FLAGS),<
	..TEMP==0
	IRP <FLAGS>,<..TEMP==..TEMP!DF.'FLAGS>
	EXP	..TEMP+ADDR
>

;THESE ARE THE FLAGS USED BY THE DTE. PROCESSORS

	DF.GTF==1B0		;CALL DTUGTF BEFORE CALLING PROCESSOR
	DF.OWN==1B1		;MUST BE OWNER OF THE LINE

DTUCDS:				;MIN LEGAL FUNCTION
DTUDSP:	FUNCT	DTUCLR,<GTF,OWN>	;(0)CLEAR A DTE
	FUNCT	DTUSTR,<GTF,OWN>	;(1)START A DTE
	FUNCT	DTUSTB,<GTF,OWN>	;(2)SET TO-10 BYTE POINTER
	FUNCT	DTUSEB,<GTF,OWN>	;(3)SET TO-11 POINTER
	FUNCT	DTUGRW,<GTF>		;(4)GET ROM WORD
	FUNCT	DTUGMN,<GTF>		;(5)GET MASTER DTE NUMBER
	FUNCT	DTUPRB,<GTF,OWN>	;(6)PRESS RELOAD BUTTON
	FUNCT	DTUGST,<GTF>		;(7)GET STATUS
	FUNCT	DTUSRJ			;(10)SET RELOAD JOB
	FUNCT	FEDGET##		;(11)GET FRONT END DEVICE
	FUNCT	FEDUIN##		;(12)FED INPUT
	FUNCT	FEDUOU##		;(13)FED OUTPUT
	FUNCT	FEDUGS##		;(14)GET FED STATUS
	FUNCT	FEDUSS##		;(15)SET FED STATUS
	FUNCT	FEDGIV##		;(16)RELEASE FED
	FUNCT	CPOPJ1##,<GTF>		;(17)RELEASE KLE CHUNKS
	FUNCT	DTUTME,<GTF>		;(20)RESET KL ERROR TIMER
	FUNCT	TTDDLN##,<GTF>		;(21)CONVERT TO TTY NUMBERS
	FUNCT	DTUSLU,<GTF,OWN>	;(22)SET LINE'S USER
	FUNCT	DTURLU,<GTF>		;(23)READ LINES USER
	FUNCT	DTULDS,<GTF,OWN>	;(24)LOAD SECONDARY BOOTSTRAP
	FUNCT	DTUDMP,<GTF,OWN>	;(25)DUMP
	FUNCT	DTUKLP,<GTF>		;(26)REPLACE KLINIK PARAMS
	FUNCT	DTUKPR,<GTF>		;(27)READ KLINIK PARAMS


	MXDTFN==.-DTUDSP-1	;MAXIMUM LEGAL FUNCTION

;ERROR CODES

	INTERN DTUBCE,DTUDOF,DTUFDB,DTUNXF,DTUFER,DTUNFC ;FRONT END DEVICE ERROR CODES
	INTERN	DTUCSM

	ERCODE	DTUNPE,DTENP%	;(1)NO PRIVILEGES
	ERCODE	DTUFNE,DTEUF%	;(2)FUNCTION NUMBER ERROR
	ERCODE	DTUDCE,DTEDC%	;(3)CPU OR DTE NUMBER ERROR
	ERCODE	DTUARP,DTEAP%	;(4)ALREADY RUNNING PROTOCOL
	ERCODE	DTUPTE,DTEPT%	;(5)POWER FAIL DIDNT COME UP
	ERCODE	DTUDEE,DTEDE%	;(6)DOORBELL DIDNT CLEAR
	ERCODE	DTUTEE,DTTTE%	;(7)TO-10 ERROR DURING BOOT SEQ.
	ERCODE	DTUDDE,DTEDD%	;(10)NO REPONSE FROM 11 AFTER BOOT SEQ.
	ERCODE	DTUILJ,DTEIJ%	;(11)ILLEGAL JOB NUMBER
	ERCODE	DTUBCE,DTEIB%	;(12)ILLEGAL BYTE COUNT
	ERCODE	DTUDOF,DTENI%	;(13)FRONT END DEVICE NOT INITED
	ERCODE	DTUFDB,DTEFB%	;(14)FRONT END DEVICE IN USE BY ANOTHER JOB
	ERCODE	DTUNXF,DTENF%	;(15)NON-EXISTANT FRONT END DEVICE
	ERCODE	DTUFER,DTEFE%	;(16)FATAL ERROR ON FRONT END DEVICE
	ERCODE	DTUSTE,DTESE%	;(17)ERROR STARTING PRIMARY PROTOCOL
	ERCODE	DTUNFC,DTENC%	;(20)NO FREE CORE FOR FED BUFFERS
	ERCODE	DTUTME,DTETE%	;(21)KL ERROR DATA TIMER EXPIRED
	ERCODE	DTUCSM,DTECM%	;(22)FEDSER WAS TOLD IT COULDN'T SEND A MESSAGE TO THE -11
	ERCODE	DTUIUN,DTEIU%	;(23)ILLEGAL USER NAME
	ERCODE	DTUWRU,DTEWU%	;(24)WRONG USER FOR FUNCTION
	ERCODE	DTUNEV,DTEEV%	;(25)NO EVM AVAILABLE FOR FUNCTION
	ERCODE	DTUIBP,DTEIP%	;(26)ILLEGAL BYTE POINTER
;DTE. FUNCTION (#0) TO CLEAR A DTE
; ADDR/CPU#,,DTE#
; CAUSES DTE TO LEAVE PRIMARY PROTOCOL. ALSO CLEARS ED.RLD.
;
; NOTE THAT THIS FUNCTION CAN BE DONE BY ANY PRIVILEGED PROGRAM
; EVEN IF HE IS NOT THE OWNER OF THE LINE.  ONCE THE DTE HAS BEEN
; HALTED (CLEARED), THE PROGRAM MAY SET THE USER OF THE LINE TO
; WHATEVER HE WANTS.

DTUCLR:	PUSHJ	P,DTECLR	;GO CLEAR OUT THE DTE
	PUSHJ	P,DFKSE0	;SET LINE'S USER TO NOBODY AND TELL THE FEK
	JRST	CPOPJ1##	;GIVE SKIP RETURN

;DTE. FUNCTION (#1) TO START PROTOCOL ON A DTE
; ADDR/CPU#,,DTE#

DTUSTR:	MOVE	T1,ETDSTS(F)	;GET DTE STATUS
	TLNE	T1,(ED.PPC)	;ALREADY RUNNING PRIMARY PROTOCOL?
	JRST	DTUARP		;YES, GIVE AN ERROR RETURN
	HRRZ	T2,ETDUSR(F)	;GET THE USER OF THE DTE
	CAIN	T2,DD.DEC	;IS IT DECNET?
	JRST	DTUSTM		;YES, GO INITIALIZE Q.P. V2
	TLNN	T1,(ED.DTM)	;IF NOT MASTER,
	CAIE	T2,DD.NOB	;AND UNKNOWN USER,
	TRNA			;(NO)
	JRST	DTUSTM		;THEN ACT LIKE IT'S AN MCB
	TLNE	T1,(ED.DTM)	;IF MASTER,
	PUSHJ	P,[PUSHJ P,ENTSPC ;GO INTO SECONDARY PROTOCOL FIRST
		  PUSHJ P,CLRDSN## ;FORGET DISK DRIVE SERIAL NUMBERS
		  PJRST TTDRLD##] ;AND RESTART -20F LINES
	MOVEI	T1,.M20F	;SPECIFY 20F TYPE PROTOCOL (MEANS ANF, TOO)
	LOAD.	T2,ED.211,(F)	;POINT TO TO-11 SECTION
	STOR.	T1,EC.PRT,(T2)	;STORE THE PROTOCOL TYPE
	LOAD.	T2,ED.210,(F)	;POINT TO TO-10 SECTION
	STOR.	T1,EC.PRT,(T2)	;STORE PROTOCOL TYPE HERE, ALSO
	PUSHJ	P,STXPPC	;START UP PRIMARY PROTOCOL
	  JRST	DTUSTE		;SOMETHING WENT WRONG, WE CAN'T START IT
	MOVE	T1,ETDSTS(F)	;DTE STATUS
	TLNE	T1,(ED.DTM)	;ARE WE TALKING TO MASTER?
	PUSHJ	P,KPSSND	;SEND KLINIK PARAMETERS
	  JFCL			;NOT SERIOUS (OLD VERSION OF 20F)
	JRST	CPOPJ1##	;SIGNAL SUCCESSFUL START

;HERE TO INITIALIZE QUEUED PROTOCOL VERSION 2.  USED WITH THE MCB.

DTUSTM:	PUSHJ	P,DTECLR	;CLEAR THE STATE
	MOVEI	T1,.MMCB	;USE MCB PROTOCOL TYPE
	LOAD.	T2,ED.211,(F)	;GET POINTER TO 11 REGION
	STOR.	T1,EC.PRT,(T2)	;STORE THE PROTOCOL TYPE
	LOAD.	T2,ED.210,(F)	;GET POINTER TO 10 REGION
	STOR.	T1,EC.PRT,(T2)	;STORE IT HERE, TOO
	PUSHJ	P,STXPPC	;START UP THE PROTOCOL
	  TRNA			;COULDN'T INITIALIZE
	JRST	CPOPJ1##	;RETURN SUCCESS
	PUSHJ	P,DTECLR	;WE COULDN'T INITIALIZE, SO LEAVE THE
				; DTE IN A DEAD STATE
	PJRST	DTUSTE		;SOMETHING WENT WRONG, WE CAN'T START IT


;DTE. FUNCTION (#2) TO SET TO-10 BYTE POINTER IN EPT
; ADDR/CPU#,,DTE#
; ADDR+1/<BYTE POINTER>

DTUSTB:	PUSHJ	P,DTUSXB	;GET EPT OFFSET IN T4 FOR PROPER DTE
	  POPJ	P,		;ERROR.
	MOVEM	T1,DTETBP(T4)	;STORE IN EPT PLACE
	JRST	CPOPJ1##	;UUO GETS SUCCESS RETURN
;DTE. FUNCTION (#3) TO SET TO-11 BYTE POINTER IN EPT
; ADDR/CPU#,,DTE#
; ADDR+1/<BYTE POINTER>

DTUSEB:	PUSHJ	P,DTUSXB	;GET EPT OFFSET
	  POPJ	P,		;ERROR
	MOVEM	T1,DTEEBP(T4)	;STORE
	JRST	CPOPJ1##	;UUO GETS SUCCESS RETURN

DTUSXB:	MOVSI	T2,(ED.PPC)	;RUNNING SOMETHING?
	TDNE	T2,ETDSTS(F)	;?
	PJRST	DTUARP		;YES, CANNOT SET ANY POINTERS
	PUSHJ	P,GETWD1##	;GET BYTE POINTER IN T1
	PUSHJ	P,GTEPT		;GET EPT ADDR FOR DTE'S CPU
	LOAD.	T2,ED.DTN,(F)	;GET DTE NUMBER
	ASH	T2,3		;*8
	ADD	T4,T2		;GET OFFSET FROM FIRST DTE
	JRST	CPOPJ1##	;GIVE GOOD RETURN


;DTE. FUNCTION (#4) TO GET 11 RELOAD ROM WORD
; ADDR/CPU#,,DTE#

DTUGRW:	LOAD.	T1,ED.211,(F)	;GET TO-11 SECTION FOR THIS DTE/11
	LOAD.	T1,EC.RLD,(T1)	;GET RELOAD WORD FOR THIS 11
	PJRST	STOTC1##	;PUT IN UUO AC AND GIVE GOOD RETURN


;DTE. FUNCTION (#5) TO GET NUMBER OF MASTER DTE ON A CPU
; ADDR/CPU#,,DTE#

DTUGMN:	HLRZS	T1		;GET JUST CPU NUMBER IN T1
	MOVE	F,DTEMAS##(T1)	;GET MASTER DTE CONTROL BLOCK ADDRESS
	LOAD.	T1,ED.DTN,(F)	;GET DTE NUMBER OF MASTER
	PJRST	STOTC1##	;STORE AND RETURN


;DTE FUNCTION (#6) TO PUSH 11 RELOAD BUTTON
; ADDR/CPU#,,DTE#

DTUPRB:	TLNE	T1,(ED.PPC)	;RUNNING PRIMARY PROTOCOL?
	JRST	DTUARP		;ALREADY RUNNING PROTOCOL
	PUSHJ	P,PRSRLD	;PRESS RELOAD BUTTON
	  JRST	DTUDEE		;NO ELEVEN DOORBELL BACK
	JRST	CPOPJ1##	;WE MADE IT.
;DTE FUNCTION #7, GET STATUS WORD.

DTUGST:	MOVE	T1,ETDSTS(F)	;GET STATUS WORD
	JRST	STOTC1##	;AND RETURN WITH IT.


;DTE FUNCTION #10, SET RELOAD JOB

DTUSRJ:	PUSHJ	P,GETWDU##	;GET JOB NUMBER
	CAMN	T1,[-1]		;SELF?
	MOVE	T1,J		;YES
	PUSHJ	P,LGLPRC##	;IS IT LEGAL?
	  JRST	DTUILJ		;NO, ILLEGAL JOB NUMBER
	MOVEM	T1,DTRJOB	;SET JOB NUMBER
	JRST	CPOPJ1##	;AND GIVE GOOD RETURN.
;DTE. FUNCTION (#22) TO SET LINES USER
; ADDR/	CPU#,,DTE#
; ADDR+1/ 'NAME' OF USER

DTUSLU:	MOVSI	T2,(ED.PPC!ED.SPC) ;BITS THAT MEAN WE'RE NOT HALTED
				; NOTE THAT WE DID NOT INCLUDE ED.MAI
				; BECAUSE WE GO FROM MAINT MODE TO
				; PPC WHEN WE SET LINE USER TO DECNET
	TDNE	T2,ETDSTS(F)	;ARE WE DOING ANYTHING?
	PJRST	DTUARP		;CANNOT SET - LINE IS RUNNING SOMETHING
	PUSHJ	P,GETWD1##	;GET THE NAME TO SET
	SETZ	T2,		;START WITH ZERO

DTUSL1:	PUSHJ	P,KONUSN##	;IDENTIFY USER NAME
	  JRST	DTUIUN		;ILLEGAL USER NAME
	PUSH	P,T2		;SAVE INTENDED USER
	PUSHJ	P,DFKSET	;SET-UP THE FEK INFO
	POP	P,T2		;RESTORE INTENDED LINE USER
	HRRZ	T1,ETDUSR(F)	;SEE WHAT GOT SET
	CAIE	T1,(T2)		;WAS IT THE SAME?
	JRST	DTUIUN		;GIVE ERROR IF DRIVER NOT LOADED
	CAIE	T2,DD.DEC	;SKIP RESET IF DECNET
	PUSHJ	P,DTECLR	;OTHERWISE JUST CLEAN THINGS UP
	PJRST	CPOPJ1##	; AND RETURN
;DTE FUNCTION (#23) TO READ LINE'S USER
; ADDR/ CPU#,,DTE#
; ADDR+1/ 'NAME' OF USER
; ADDR+2/ JOB NUMBER IF USER IS 'PROGRA'

DTURLU:	HRRZ	T1,ETDUSR(F)	;GET THE USER OF THE LINE FROM ETD BLOCK
	MOVE	T1,DTNAME##(T1)	; FROM THAT GET THE SIXBIT NAME
	PUSHJ	P,PUTWD1##	;GIVE THE USER NAME
	HLRZ	T1,ETDUSR(F)	;GET THE JOB NUMBER (ZERO IF NOT DD.PRO)
	AOS	(P)		;GIVE GOOD RETURN
	PJRST	PUTWD1##	;GIVE USER THE JOB NUMBER AND RETURN
;DTE FUNCTION (#24) TO LOAD SECONDARY BOOTSTRAP
; ADDR/ CPU#,,DTE#
; ADDR+1/ BP TO SECONDARY LOADER
; ADDR+2/ LENGTH OF LOADER IN BYTES

DTULDS:	PUSHJ	P,DTECLR	;CLEAR DTE
	MOVE	J,.CPJOB##	;ANF CAN CLOBBER J
	PUSHJ	P,PRSRLD	;PRESS RELOAD BUTTON
	  JRST	DTUDEE		;ROM RELOAD FAILURE
	MOVEI	T1,PI0ENB+PILDEN ;ENABLE TRANSFERING (PI 0)
	XCT	ETDCNO(F)	;DO THE CONO
	PUSHJ	P,GETWD1##	;GET NEXT WORD (BYTE POINTER)
	MOVE	P1,T1		;PRESERVE IT
	LDB	T1,[POINT 6,T1,11] ;GET BYTE SIZE
	CAIE	T1,^D16		;MAKE SURE BYTESIZE IS .LE. 16 BITS, OR ELSE WE
	  JRST	 DTUIBP		; MIGHT CLOBBER THE E-BUS
	PUSHJ	P,GETWD1##	;GET COUNT
	MOVE	P2,T1		;PRESEVE THIS ALSO

	DMOVE	T1,P1		;SET UP FOR CALL
	PUSHJ	P,DTUEBP	;MAP EVM FROM THIS BP AND COUNT
	  JRST	DTUNEV		;NO EVM LEFT, GIVE ERROR
	MOVEM	T3,@ETDEBP(F)	;STORE TO-11 BYTE POINTER
	PUSHJ	P,WAIT11	;WAIT FOR TO11DB
	  JRST	DTUDDE		;TIMED OUT, GIVE ERROR
	MOVEI	T1,TO11DB	;RING THE 11 DOORBELL TO
	XCT	ETDCNO(F)	; START THE LOAD
	JRST	CPOPJ1##	;RETURN NICELY
;DTE FUNCTION (#25) TO GET A DUMP FROM A PRE-LOADED DUMPER
; ADDR/ CPU#,,DTE#
; ADDR+1/ BP TO DUMP AREA
; ADDR+2/ NUMBER OF BYTES TO DUMP

DTUDMP:	PUSHJ	P,GETWD1##	;GET THE BP TO DUMP AREA
	MOVE	P1,T1		;SAVE DUMP AREA POINTER
	LDB	T1,[POINT 6,T1,11] ;GET BYTE SIZE
	CAIL	T1,^D16		;CHECK FOR A REASONABLE BYTE POINTER, ANYTHING
	CAILE	 T1,^D36	; LESS THAN 16 BITS JUST DOESN'T CUT IT, 'CAUSE
	  JRST	  DTUIBP	; WE ONLY DO BOOT TRANSFERS IN WORD MODE
	PUSHJ	P,GETWD1##	;GET COUNT OF BYTES TO BE DUMPED
	MOVE	P2,T1		;PRESERVE COUNT
	DMOVE	T1,P1		;SET UP FOR EVM CALL
	PUSHJ	P,DTUEBP	;MAP THE USERS DUMP BUFFER
	  JRST	DTUNEV		;NO EVM LEFT, GIVE ERROR
	MOVEI	T1,PI0ENB+PILDEN ;ENABLE TRANSFERING (PI 0)
	XCT	ETDCNO(F)	;DO THE CONO
	MOVE	T2,P2		;GET THE BYTE COUNT
	MOVE	T1,T3		;MOVE FOR DNDDMP
	PUSHJ	P,DNDDMP	;DO DUMP
	  JRST	DTUDDE		;DUMP TIMED OUT
	JRST	CPOPJ1##	;GIVE GOOD RETURN
;DTE. FUNCTION (#26) TO CHANGE KLINIK PARAMS ON A DTE
; ADDR/CPU#,,DTE#
;   +1/BC,,ADDR OF STRING
; STRING: BYTE(16)LEN,OPEN SSM(8)OPEN MM,YY,0,DD(16)CLOSE SSM(8)CLOSE MM,YY,
;	  0,DD,CONSOLE MODE,KL MODE,A,P,S,S,D,W
; WHERE: KL MODE = 0 DISABLED, = 1 REMOTE CTY, = -1 USER MODE
;	 CONSOLE MODE = 1 OPERATOR, 3 PROGRAMMER, 7 MAINTENANCE.
;	 LEN = # OF BYTES TO FOLLOW (MUST MATCH -20F)
;	 SSM IS SECONDS SINCE MIDNIGHT/2
;	AND EACH PAIR OF BYTES IN THE PASSWORD ARE REVERSED ("PASSWD" ABOVE)

DTUKLP:	MOVE	T1,ETDSTS(F)	;GET DTE STATUS
	TLNN	T1,(ED.PPC)	;PRIMARY PROTOCOL FUNNING?
	JRST	DTUARP		;NO
	TLNN	T1,(ED.DTM)	;IF NOT MASTER,
	JRST	DTUDCE		;INVALID CPU/DTE
	LOAD.	T2,ED.211,(F)	;POINT TO TO-11 SECTION
	LOAD.	T1,EC.PRT,(T2)	;LOAD THE PROTOCOL TYPE
	CAIE	T1,.M20F	;20F?
	JRST	DTUDCE		;NO, BAD
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	HLRZ	T2,T1		;GET BYTE COUNT
	CAIE	T2,KPSLEN	;MATCH WHAT WE EXPECT?
	JRST	DTUBCE		;NO, RETURN ERROR (ILLEGAL BYTE COUNT)
	HRRZS	T1		;ISOLATE ADDRESS ONLY
	MOVEI	T2,<<KPSLEN+3>/4>-1(T1)	;SET T2 := LAST WORD IN MESSAGE
	MOVE	P1,T1		;SAVE THIS
	PUSHJ	P,TRNGE##	;MAKE SURE ALL THE DATA IS IN CORE.
	HRR	M,P1		;GET ADDRESS OF FIRST WORD
	PUSHJ	P,GETWDU##	;READ IT FROM USER
	LDB	T1,[POINT 16,T1,15] ;GET LENGTH OF BLOCK
	CAIE	T1,KPSLEN-2	;BETTER BE DATA AREA - LEN(COUNT)
	JRST	DTUDCE		;SOMEONE WANTED TO TRASH -20F!
	MOVEI	T1,<<22+^D<36/8-1>>/4>+<SIZE(.KEHDL,36)> ;SIZE OF LOG ENTRY
				;+SIZE OF KLE HEADER IN -10 WDS
	PUSHJ	P,ALCSEB##	;ALLOCATE SOME CORE TO LOG THE EVENT
	  JRST	DTUNFC		;NO FREE CORE, ABORT
	PUSH	P,P1		;SAVE ADDRESS OF FIRST USER WORD
	LOAD.	P1,ED.DTN,(F)	;GET DTE #
	LOAD.	T2,ED.CPN,(F)	;GET CPU #
	HRL	P1,T2		;CPU#,,DTE#
	MOVSI	P2,.EMKLI	;DEVICE IS KLINIK EVENT
	MOVEI	P3,22		;UNIT 0,,BYTE COUNT
	PUSHJ	P,LOGSET	;SET UP LOG HEADER
	POP	P,T2		;GET USER ADDRESS BACK
	XSFM	T1		;GET PCS
	HRLI	T2,(T1)		;MAKE GLOBAL USER ADDRESS
	XMOVEI	T3,.CPKPB##	;GET DESTINATION (EXEC) ADDRESS
	MOVEI	T1,<KPSLEN+3>/4	;AND LENGTH OF TRANSFER
	XBLTUX	T1		;COPY TO CDB
	MOVE	T4,P4		;COPY BP TO DATA AREA
	MOVEI	T1,EM.ELR	;ERROR LOG REQUEST
	IDPB	T1,T4		;STORE IN MESSAGE
	MOVEI	T1,1		;SET KLINIK CODE
	LDB	T2,[POINT 8,.CPKPB##+3,32] ;NEW KLINIK MODE
	SKIPE	T2		;ENABLED (SOME FLAVOR)?
	TROA	T1,1*400	;YES, EVENT IS "SET"
	MOVEI	T1,377		;NO, EVENT IS "CLEAR"
	IDPB	T1,T4		;STORE THIS TOO
	MOVEI	T3,7		;NUMBER OF 16-BIT WORDS TO LOG
	MOVE	T2,[POINT 16,.CPKPB##,31-16] ;DON'T LOG COUNT OR PASSWD
CPYWND:	ILDB	T1,T2		;COPY A WORD OF WINDOW/MODE
	IDPB	T1,T4		;INTO LOG BUFFER
	SOJG	T3,CPYWND	;TILL ALL MOVED
	MOVEI	T2,-.KEDAT(P4)	;POINT BACK TO START OF KLE CHUNK
	PUSHJ	P,DVSLOG	;AND LOG THE EVENT (WILL EVENTUALLY FREE CORE)
	PUSHJ	P,KPSSND	;SEND KLINIK PARAMETERS
	  JFCL			;NOT SERIOUS (OLD VERSION OF 20F)
	JRST	CPOPJ1##	;SIGNAL SUCCESSFUL START
;DTE. FUNCTION (#27) TO READ KLINIK PARAMS ON A DTE
; ADDR/CPU#,,DTE#
;   +1/BC,,ADDR OF STRING
; STRING: BYTE(16)LEN,OPEN SSM(8)OPEN MM,YY,0,DD(16)CLOSE SSM(8)CLOSE MM,YY,
;	  0,DD,CONSOLE MODE,KL MODE
; WHERE: KL MODE = 0 DISABLED, = 1 REMOTE CTY, = -1 USER MODE
;	 CONSOLE MODE = 1 OPERATOR, 3 PROGRAMMER, 7 MAINTENANCE.
;	 LEN = # OF BYTES TO FOLLOW (MUST MATCH -20F)
;	 SSM IS SECONDS SINCE MIDNIGHT/2

DTUKPR:	MOVE	T1,ETDSTS(F)	;GET DTE STATUS
	TLNN	T1,(ED.DTM)	;IF NOT MASTER,
	JRST	DTUDCE		;INVALID CPU/DTE
	LOAD.	T2,ED.211,(F)	;POINT TO TO-11 SECTION
	LOAD.	T1,EC.PRT,(T2)	;LOAD THE PROTOCOL TYPE
	CAIE	T1,.M20F	;20F?
	JRST	DTUDCE		;NO, BAD
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	HLRZ	T2,T1		;GET BYTE COUNT
	CAIE	T2,KPSLEN-6	;MATCH WHAT WE EXPECT?
	JRST	DTUBCE		;NO, RETURN ERROR (ILLEGAL BYTE COUNT)
	HRRZS	P1,T1		;ISOLATE BUFFER ADDRESS AND SAVE
	MOVEI	T2,<<KPSLEN-6+3>/4>-1(T1) ;SET T2 := LAST WORD IN MESSAGE
	HRL	P1,T2		;SAVE LAST,,FIRST
	PUSHJ	P,TRNGE##	;MAKE SURE ALL THE DATA IS IN CORE.
IFE FTXMON,<
	HLRZ	T1,P1		;RETRIEVE LAST WORD (USER)
	HRLI	P1,.CPKPB##	;WHERE THE DATA COMES FROM
	EXCTXU	<BLT P1,(T1)>	;COPY TO USER
>
IFN FTXMON,<
	HLRZ	T1,P1		;RETRIEVE LAST WORD (USER)
	SUBI	T1,(P1)		;COUNT-1
	MOVEI	T1,1(T1)	;FIX TO REAL COUNT
	XSFM	T2		;GET PCS
	ANDI	T2,(SECMSK)	;ISOLATE SECTION
	MOVS	T3,T2		;GET IN PROPER HALFWORD
	HRRI	T3,(P1)		;FORM COMPLETE USER ADDRESS
	XMOVEI	T2,.CPKPB##	;WHERE THE DATA COMES FROM
	XBLTXU	T1,		;COPY TO THE USER
>
	JRST	CPOPJ1##	;OK
;HERE FOR THOSE FUNCTIONS THAT HAVE CPU#,,DTE# AS FIRST WORD OF BLOCK
; CALL IS:
;	PUSHJ	P,DTUGTF
;	<ONLY RETURN>
; RETURNS WITH DTE CONTROL BLOCK ADDRESS IN F SET UP FROM USER C(M),
; C(T1) = CPU#,,DTE# FOR USE BY FUNCTION SUBROUTINES.
; POPS CALLER'S PC OFF STACK AND POPJS IF DTE OR CPU NUMBER IS BAD.
; (BETTER NOT PUSH SOMETHING ON STACK AND THEN CALL DTUGTF.)
; THIS ROUTINE IS MEANT TO BE USED ONLY BY THE DTE UUO FUNCTION SUBROUTINES.


DTUGTF::PUSHJ	P,GETWDU##	;GET CPU#,,DTE#
	TRC	T1,-1		;ASKING FOR MASTER DTE?
	TRCN	T1,-1
IFN FTMP,<
	PUSHJ	P,CPLCK##	;YES, LOCKED ON THIS CPU?
	  CAIA
>
	HRL	T1,.CPCPN##	;YES, SUPPLY CPU NUMBER
	MOVE	W,T1		;SAVE CPU#,,DTE# FOR LATER
	MOVE	F,T1		;GET ARG IN F WHERE IT BELONGS
	PUSHJ	P,GETETD	;GET DTE CONTROL BLOCK ADDRESS IF ALL IS OK
	  JRST	DTUGT1		;GO GIVE ERROR
	MOVSI	T1,(ED.DTX)	;SEE IF THIS DTE REALLY EXISTS
	TDNN	T1,ETDSTS(F)	;DOES IT?
	JRST	DTUGT1		;NO, GIVE ERROR
IFN FTMP,<
	HLRZ	T1,W		;CPU NUMBER
	PUSHJ	P,ONCPUS##	;MAKE SURE WE'RE ON THE RIGHT CPU
	  JRST	DTUGT1
>
	LOAD.	T1,ED.DTN,(F)	;GET REAL DTE NUMBER IN CASE -1 WAS GIVEN
	HLL	T1,W		;PUT CPU NUMBER IN LH(T1)
	POPJ	P,		;EXIT

DTUGT1:	POP	P,(P)		;POP CALLER'S PC OFF STACK
	JRST	DTUDCE		;AND RETURN TO UPPER LEVEL, ABORT FUNCTION
;DTUEBP RETURN A BYTE POINTER TO EVM
; CALLED WITH:
;  T1/ BYTE POINTER TO USER ADDRESS SPACE
;  T2/ BYTE COUNT
; ON BEFORE RETURNING, PLACES ADDR OF ROUTINE TO GIVE BACK EVM ON STACK
;  AND SAVES EVA AND # OF PAGES TO RETURN.  T3 CONTAINS POINTER TO EVM
;  ON SKIP RETURN.  NON-SKIP RETURN GIVEN WHEN OUT OF EVM.  ALL POINTERS
;  GIVEN AND RETURNED ARE ILDB/IDPB POINTERS.
; USES T1-T4

DTUEBP:	PUSHJ	P,CHKBPT##	;RANGE CHECK IT
	  JRST	 UADERR##	;ADDRESS CHECK
	MOVSI	T3,NSHF!NSWP	;LOCK JOB IN CORE
	IORM	T3,JBTSTS##(J)	;SET STATUS WORD FOR JOB

	IBP	T1		;MAKE BYTE POINTER POINT TO FIRST REAL ADDRESS
	PUSH	P,T1		;SAVE BYTE POINTER FOR LATER
	LDB	T4,[POINT 6,T1,11] ;GET BYTE SIZE FROM BYTE POINTER
	MOVEI	T3,^D36		;GET BITS/WORD
	IDIV	T3,T4		;T3=BYTES/WORD
	IDIV	T2,T3		;T2=WORDS OF EVM REQUIRED
	HRRZ	T3,T1		;GET FIRST USER ADDRESS FOR GTEVBF
	MOVE	T1,T2		;SET UP BUFFER SIZE FOR GTEVBF

	PUSH	P,F		;SAVE ETD POINTER FOR LATER
	SETZ	F,		;MAKE SURE UUOCON KNOWS WE DON'T HAVE DDB HERE
	PUSHJ	P,GTEVBF##	;DO THE MAPPING
	  JRST	 DTUEB1		; GIVE THE ERROR RETURN (NO EVM LEFT)
	POP	P,F		;RESTORE ETD POINTER
	POP	P,T2		;GET COPY OF INCREMENTED BYTE POINTER
	HLL	T3,T2		;RESTORE P AND S FIELDS FROM INC'D USER BP
	EXCH	T1,0(P)		;T1=ADDR OF CALLER, 0(P)=AMOUNT OF EVM WE GOT
	PUSH	P,T3		;SAVE ADDRESS OF EVM
	SETO	T2,		;GET OFFSET FOR ABJBP
	ADJBP	T2,T3		;DECREMENT BYTE POINTER BY ONE
	MOVE	T3,T2		;PUT BP TO MAPPED EVM BACK WHERE IT BELONGS
	PUSHJ	P,1(T1)		;CALL THE CALLER WITH SKIP RETURN
	  CAIA			;NON SKIP RETURN
	AOS	-2(P)		;INDICATE SKIP RETURN
	POP	P,T2		;GET BACK EVA
	POP	P,T1		;AND THE NUMBER OF PAGES
	ANDI	T1,777		;GET USEFULL PART
	PUSH	P,F		;SAVE F FOR LATER USE
	SETZ	F,		;KEEP GIVEVM FROM LOOKING AT NON-EXISTANT DDB
	PUSHJ	P,GIVEVM##	;GIVE IT BACK
	MOVSI	T1,NSWP!NSHF	;NO SWAP, NO SHUFFLE
	ANDCAM	T1,JBTSTS##(J)	;CLEAR THEM (UNLOCK)
	JRST	FPOPJ##		;RETURN TO SENDER.

DTUEB1:	POP	P,F		;RESTORE ETD POINTER
	POP	P,T1		;AND T1
	POPJ	P,		;AND RETURN NO SKIP
SUBTTL	DTEDDB - PROTOTYPE DDB FOR THE DTE DEVICE

	DEFINE 	X(NAME<%1>,SIZE<1>),<NAME==:<%1==%1+SIZE>-SIZE>

	%1==DEVLLD		;INITIALIZE THE OFFSET

	X	DEVETD		;XWD ETD ADDRESS, INPUT MSG QUEUE
	X	DEVOBC		;COUNT OF OUTPUT BUFFERS OUTSTANDING
	X	DTEDBL,0	;LENGTH OF DTE DDB

;LAY OUT THE PROTOTYPE DDB

	DEFINE	X(OFFSET,EXPR),<
		RELOC	DTEDDB+OFFSET
		EXPR
	>

	$LOW			;HAS TO BE DIDDLED WITH

DTEDDB::X	DEVCHR,<XWD <6*HUNGST>+DVC2IO,<DTEMMS+3>/4+1> ; BUFFER SIZE
	X	DEVSER,<XWD 0,DTEUDS> ;DISPATCH THROUGH THIS
	X	DEVMOD,<XWD DVIN!DVOUT,1_BYTMOD>
	X	DEVSTA,<XWD DEPLEN!<.TYDTE*.TYEST>,DEPEVM> ;VARIABLE BUFFERS, NO EVM
	X	DEVCPU,<EXP 707B8> ;SET DEYPCL SO IT WILL RUN ON ANY CPU
	X	DTEDBL		;RESERVE SUFFICIENT ROOM

	$HIGH			;PURE AGAIN
	PURGE	X
SUBTTL	DTEUUO - DTE DEVICE'S ENTRY TO DTESER

;DISPATCH TABLE

	POPJ	P,		;(-5) DEVICE OFF LINE
	JRST	ECOD2##		;(-4) DEVOP. UUO
	JRST	REGSIZ##	;(-3) LENGTH CAN BE GOTTEN FROM DDB
	POPJ	P,		;(-2) ONCE INITIALIZATION
	JRST	DTEHNG		;(-1) HUNG DEVICE
DTEUDS:	JRST	DTEREL		;(0) RELEASE
	JRST	OUT##		;(1) CLOSE OUTPUT
	JRST	DTEOUT		;(2) OUTPUT
	JRST	DTEIN		;(3) INPUT
;TSTDTE - CALLED FROM DDBSRC IN UUOCON TO CHECK FOR THE DTE PHYSICAL DEVICE
; CALL:
;  T1/	DEVICE NAME
; RETURN:
;  CPOPJ			;ON ERROR (NOT DTE, ETC.)
;  CPOPJ1 			;F CONTAINING DDB ADDRESS ON SUCCESS

TSTDTE::HLRZ	T2,T1		;GET THE RH OF THE NAME
	CAIE	T2,'DTE'	;IS IT 'DTE'?
	POPJ	 P,		;NO, GIVE BAD RETURN
	HRLZ	T2,.USMUO	;UUO OP CODE
	IOR	T2,.USMUE	;EA-CALC
	TDZ	T2,[777,,UPHNLY] ;ONLY CALLI
	CAMN	T2,[FILOP.]	;FILOP?
	JRST	TSTDT1		;YES, ALLOW THAT
	HLRZS	T2		;OR OPEN
	CAIE	T2,(OPEN)
	JRST	 TSTER1		;NO, ONLY FILOP/OPEN MAY CREATE DDB
TSTDT1:	PUSHJ	P,SAVT##	;SAVE THE T'S
	PUSHJ	P,SAVE1##	; AND A PEA
	MOVE	P1,T1		;PRESERVE THE DEVICE NAME
	MOVSI	T1,JP.POK	;MAKE SURE THIS GUY IS REALLY
	PUSHJ	P,PRVBIT##	; A GOOD PERSON TO LET DO THIS
	  CAIA			;SEEMS OK
	JRST	TSTER1		;DON'T LET HIM

;CHECK FOR REAL DTE

	TRNE	P1,575454	;IS RH A GOOD NUMBER? (MUST BE 'DTE0NN')
	POPJ	P,		;ERROR
	LDB	F,[POINT 3,P1,29] ;GET CPU NUMBER
	MOVSS	F		;PUT IT IN THE LEFT HALF
	LDB	T1,[POINT 3,P1,35] ;GET DTE NUMBER
	HRR	F,T1		;CPU#,,DTE#
	PUSHJ	P,GETETD	;GET ETD BLOCK ADDRESS IN F
	  JRST	TSTER1		;CLEAR F AND RETURN
	MOVE	T1,ETDSTS(F)	;GET FLAGS INTO T1
	TXNE	T1,ED.DTX	;DOES THIS DTE EXIST??
	TXNE	T1,ED.DTM	;LETS ALSO MAKE SURE THAT
	JRST	TSTER1		; THIS ISN'T THE MASTER DTE
	TXNE	T1,ED.PPC	;IS PROTOCOL UP??
	JRST	TSTER1		; YES, CAN'T DO THIS
	PUSHJ	P,GETCPU	;AVOID ALL KINDS OF RACES
	  JRST	TSTER1		; CPU IS DOWN
	SKIPE	ETDDDB(F)	;DID SOMEONE OWN A DDB ALREADY?
	JRST	TSTER1		;YES, CAN'T OPEN IT AGAIN
; NOW WE CAN BUILD THE DDB

	MOVEI	T2,DTEDBL	;GET THE LENGTH OF THE DDB
	PUSHJ	P,GETWDS##	;ALLOCATE THAT MANY WORDS
	  JRST	TSTER1		;OOPS
	MOVSI	T2,DTEDDB	;GET PROTOTYPE DDB
	HRR	T2,T1		;COPY THE ADDRESS OF THE NEW ONE
	BLT	T2,DTEDBL-1(T1)	;INITIALIZE THE NEW ONE
	MOVEM	P1,DEVNAM(T1)	;STORE THE NAME IN THE DDB
	HRLM	F,DEVETD(T1)	;MAKE DDB POINT TO ETD BLOCK
	MOVEM	T1,ETDDDB(F)	;MAKE ETD POINT BACK TO DDB
	MOVEI	T2,DD.PRO	;WE ARE NOW
	MOVEM	T2,ETDUSR(F)	; IN PROGRAM MODE
	HRLM	J,ETDUSR(F)	;REMEMBER JOB NUMBER OF OWNER
	LOAD.	T2,ED.CPN,(F)	;GET CPU# OF THIS DTE
	LSH	T2,^D33		;GET CPU # IN 0-2
IFN FTMP,<
	ADDI	T2,PPCPI+INTL0## ;GET ADDR OF INTERLOCK WORD
>
	MOVEM	T2,DEVCPU(T1)	;STUFF IT
	DDBSRL			;LOCK THE DDB CHAIN WHILE WE PLAY
	HLLZ	T2,DEVSER+DTEDDB ;GET ADDR OF CHAIN FOLLOWING PROTOTYPE
	HLLM	T2,DEVSER(T1)	;INSTALL IT IN THE NEW DDB
	HRLM	T1,DEVSER+DTEDDB ;MAKE PROTOTYPE POINT TO NEW DB
	DDBSRU			;WE CAN NOW UNLOCK THE CHAIN
; SET UP TO DO I/O TO THE DTE DEVICE

	MOVX	T1,ED.TID	;GET TO-10 IDLE INDICATOR
	STOR.	T1,ED.2TS,(F)	;STUFF IT
IFN ED.TID-ED.EID, MOVX T1,ED.EID ;GET TO-11 IDLE INDICATOR
	STOR.	T1,ED.2ES,(F)	;MAKE THAT IDLE TOO
	MOVX	T1,ED.BFR+ED.MAI ;GET BUFFER READY BIT
	ANDCAM	T1,ETDSTS(F)	;RESET IT

	SKIPE	ETDIBK(F)	;IS A BUFFER ALLOCATED ALREADY?
	STOPCD	TSTERR,DEBUG,DTEIBA ;++ INPUT BUFFER ALREADY ALLOCATED
	MOVEI	T2,<DTEMMS+3>/4	;GET NUMBER OF WORDS NEEDED FOR BUFFER
	PUSHJ	P,GETWDS##	;GET IT FROM THE MONITOR
	  JRST	TSTERR		; NO MEMORY, GIVE UP
	STOR.	T1,ED.IBK,(F)	;STORE IT

	SKIPE	ETDOBK(F)	;IS A BUFFER ALLOCATED ALREADY?
	STOPCD	TSTERR,DEBUG,DTEOBA ;++ OUTPUT BUFFER ALREADY ALLOCATED
	MOVEI	T2,<DTEMMS+3>/4	;GET NUMBER OF WORDS NEEDED FOR BUFFER
	PUSHJ	P,GETWDS##	;GET IT FROM THE MONITOR
	  JRST	TSTERR		; NO MEMORY, GIVE UP
	STOR.	T1,ED.OBK,(F)	;STORE IT

	MOVX	T1,ED.MAI	;GET MAINTENANCE MODE BIT
	IORM	T1,ETDSTS(F)	;LET INTERRUPT LEVEL KNOW WHATS GOING ON
	MOVX	T1,PILDEN+PI0ENB+PPCPI ;GET BITS TO ENABLE THE DTE
	XCT	ETDCNO(F)	;TURN ON INTERRUPTS

	MOVEI	T2,DD.PRO	;PROGRAM MODE
	PUSHJ	P,DFKSET	;TELL THE FEK
	LOAD.	F,ED.DDB,(F)	;MAKE F POINT TO DDB
	JRST	CPOPJ1##	;GOOD RETURN

TSTERR:	PUSHJ	P,FREIOB	;RELEASE THE I/O BUFFERS
TSTER1:	SETZ	F,		;CLEAR F
	POPJ	P,		;GIVE BAD RETURN

FREIOB:	LOAD.	T2,ED.IBK,(F)	;ADDRESS OF INPUT BUFFER
	JUMPE	T2,FREIO1	;NO SUCH ANIMAL, TRY TO DEALLOCATE OUT BUFF
	MOVEI	T1,<DTEMMS+3>/4	;GET SIZE OF INPUT BUFFER
	PUSHJ	P,GIVWDS##	;DEALLOCATE THE MEMORY
	SETZ	T2,		;CLEAR ADDRESS
	STOR.	T2,ED.IBK,(F)	;SAVE IT
FREIO1:	LOAD.	T2,ED.OBK,(F)	;ADDRESS OF INPUT BUFFER
	JUMPE	T2,CPOPJ##	;NO SUCH ANIMAL, JUST RETURN
	MOVEI	T1,<DTEMMS+3>/4	;GET SIZE OF INPUT BUFFER
	PUSHJ	P,GIVWDS##	;DEALLOCATE THE MEMORY
	SETZ	T2,		;CLEAR ADDRESS
	STOR.	T2,ED.OBK,(F)	;SAVE IT
	POPJ	P,
;DTEREL - PROCESS THE "RELEASE" FUNCTION FOR OF THE DTE
; CALL:
;  F/ DDB ADDRESS
; RETURN:
;  CPOPJ			;ALWAYS

DTEREL:	PUSHJ	P,DTECKO	;CHECK TO MAKE SURE WE'RE OWNER
	  POPJ	 P,
	HLRZ	F,DEVETD(F)	;MAKE F POINT TO ETD
	PUSHJ	P,FREIOB	;AND RELEASE THE I/O BUFFERS
	PUSHJ	P,DFKSE0	;SET LINE-USER 'NOBODY' AND TELL THE FEK
	LOAD.	F,ED.DDB,(F)	;TURN IT BACK TO A DDB POINTER
	POPJ	P,		;AND RETURN
;ZAPDTE - DESTROY A DTE DDB
; CALLED BY RELEA9 IN UUOCON
; CALL:
;  F/ DDB ADDRESS
; RETURN:
;  CPOPJ			;ALWAYS

ZAPDTE::MOVEI	T1,DTEDDB	;MAKE T1 POINT TO PROTOTYPE DDB
	HLRZ	T2,DEVSER+DTEDDB ;T2 POINTS TO FIRST DDB WE WANT TO LOOK AT
	DDBSRL			;LOCK THE DDB CHAIN
ZAPDT2:	CAIN	T2,(F)		;IS THIS THE ONE?
	JRST	ZAPDT1		;YES, GO REMOVE IT
	MOVE	T1,T2		;FOLLOW THE CHAIN
	HLRZ	T2,DEVSER(T1)	;GET NEXT DDB
	JUMPN	T2,ZAPDT2	;JUMP BACK IF THERE IS MORE TO LOOK AT
	STOPCD	ZAPDT1,DEBUG,DTEDWA, ;++DDB WENT AWAY?

ZAPDT1:	HLLZ	T2,DEVSER(F)	;GET THE NEXT DDB
	HLLM	T2,DEVSER(T1)	;MAKE PREVIOUS DDB POINT TO NEXT DDB
	HLRZ	T1,DEVETD(F)	;GET ETD ADDRESS IN T1
	MOVX	T2,ED.MAI	;CLEAR MAINTENANCE MODE BIT SO THAT INTERRUPT
	ANDCAM	T2,ETDSTS(T1)	; LEVEL DOESN'T USE ETDDDB...
	SETZM	ETDDDB(T1)	;CLEAR PTR TO DDB
	DDBSRU			;UNLOCK THE CHAIN
	HRRZ	T2,F		;GET THE ADDR OF THE DDB
	MOVEI	T1,DTEDBL	; AND LENGTH
	PJRST	GIVWDS##	;GIVE BACK STORAGE AND RETURN
;DTEIN - CALLED TO PROCESS THE IN UUO FOR THE DTE DEVICE
; CALL:
;  F/ DDB ADDRESS
; RETURN:
;  CPOPJ			;ALWAYS

	T5==T4+1		;(W) EXTRA T FOR EXTEND INSTRUCTIONS
	T6==T5+1		;(M)  AND ANOTHER

IFN W-T5,<
IF1,<PRINTX ?DTESER assumes that ACs W and T5 are the same
     PRINTX ? because it knows that W is OK to trash>
>

IFN M-T6,<
IF1,<PRINTX ?DTESER assumes that ACs M and T6 are the same
     PRINTX ? because it knows that M is OK to trash>
>

DTEIN:	HLRZ	T2,DEVETD(F)	;GET ETD ADDRESS
	MOVEI	T1,PILDEN+PI0ENB+PPCPI
	XCT	ETDCNO(T2)	;ENABLE INTERRUPTS
	PUSHJ	P,SAVE2##	;SAVE THREE PEAS
	PUSHJ	P,DTECKM	;CHECK TO SEE IF IN CORRECT MODE

	SKIPA			;SKIP OVER INITIAL WAIT
DIWAIT:	PUSHJ	P,DIOWAI	; WAIT FOR -11 TO KICK US
	PUSHJ	P,DTEONL	;MAKE SURE DTE IS ON-LINE
	  POPJ	P,		;RETURN - ERROR BITS HAVE BEEN SET
	HLRZ	P2,DEVETD(F)	;GET ETD BLOCK ADDRESS
	MOVX	T2,ED.BFR	;GET BUFFER READY BIT
	TDNN	T2,ETDSTS(P2)	;IS THE BUFFER AVAILABLE???
	JRST	DIWAIT		; NO, WAIT FOR IT
	HRRZ	P1,DEVIAD(F)	;GET ADDRESS OF USERS INPUT BUFFER

;SET UP TO COPY DATA

	LOAD.	T4,ED.IBK,(P2)	;GET ADDR OF MONITORS INPUT BUFFER
	HRLI	T4,(POINT 8,)	;MAKE IT A BYTE POINTER
;	TLNN	S,IOBEG		;SKIP THIS IF WE ARE IN ROM DUMP MODE
	PUSHJ	P,GX2BYT	; GET FIRST TWO BYTES AS MSG LENGTH INTO T1
;	TLNE	S,IOBEG		;ARE WE IN ROM DUMP MODE?
;	MOVEI	T1,DTEMMS	; YES, TRANSFER THE WHOLE BUFFER
	EXCTXU	<HRRM T1,1(P1)>	;STORE BYTE COUNT FOR USER

	MOVE	T2,T4		;SET UP SOURCE BYTE POINTER

	EXCTUX	<HLRZ T4,(P1)>	;GET THE LENGTH OF THE INPUT BUFFER
	SUBI	T4,1		;MAKE IT THE ACTUAL LENGTH IN WORDS
	LSH	T4,2		; AND CONVERT THAT TO BYTES
	CAMGE	T4,T1		;MAKE SURE THAT THE DATA WILL FIT
	JRST	D.BKTL		; IF NOT, THEN GIVE THE ERROR "BLOCK TO LARGE"

	MOVSI	T5,(POINT 8,)	;MAKE A BYTE POINTER TO THE
	HRRI	T5,2(P1)	;USER'S INPUT BUFFER

	PXCT	1,[EXTEND T1,[EXP MOVSLJ,0]] ;AND COPY THE DATA
	  STOPCD	CPOPJ##,JOB,DTEMDS, ;++ MOVSLJ DIDN'T SKIP

;NOW RESET THE MONITOR'S INPUT BUFFER, AND ADVANCE THE USERS BUFFER

	MOVX	T1,ED.BFR	;GET BUFFER READY BIT
	ANDCAM	T1,ETDSTS(P2)	;CLEAR IT, 'CAUSE WE JUST READ THE BUFFER
	PUSHJ	P,ADVBFF##	;ADVANCE THE USER'S INPUT BUFFER
	  POPJ	P,		;IF WE'RE SUPPOSED TO STOP, RETURN TO UUOCON
	POPJ	P,		;YES, RETURN IMMEDIATELY, CAUSE MAINT MODE
				; WONT SAY ANYMORE TILL USER GIVES IT SOMETHING
;The following code, and all code controlled by IOBEG implements a new style
;of primary bootstrap for the DTE (in lieu of the .DTELS and .DTEDM DTE.
;functions.)  This operates as follows:  1) If IOBEG is set, and an IN uuo is
;done,one bufferful of 16 bit words is read over the DTE and given to the user.
;The user has the option of doing as many IN uuos as is necessary in order
;to dump the front end.  2) If IOBEG is set, and an OUT uuo is done, IOBEG
;gets cleared, and a bufferful of 16 bit words is copied from the user to
;location 0 of the front end, and then started.  This implies that the OUT
;uuo may only be done once in this mode.  It also implies that the code
;you load had better be able to speak the IN/OUT 8 bit protocol defined
;by DTEIN/DTEOUT (ie: the first two (swapped) bytes of each message is the
;count of the number of bytes that follow).
;
;Also note that this code is commented out, until I get a chance to implement
;it in NML (or DTELDR for that matter).

repeat 0,<
;FSTIO USES BM873 BOOT ROM TO DUMP THE FRONT END.  THIS IS CALLED ONLY WHEN NO
;OUT UUO'S HAVE BEEN PERFORMED.

FSTIO:	HRRZ	P1,DEVIAD(F)	;GET ADDRESS OF USERS INPUT BUFFER
	EXCTUX	<HLRZ T1,(P1)>	;GET THE LENGTH OF THE INPUT BUFFER
	SUBI	T1,1		;MAKE IT THE ACTUAL LENGTH IN WORDS
	LSH	T1,1		; AND CONVERT THAT TO 16 BIT BYTES
	CAILE	T1,DTEMMS/2	;IS BUFFER BIG ENOUGH?
	JRST	D.BKTL		; NO, BLOCK TOO LARGE ERROR
	MOVNS	T1		;NEGATE IT
	ANDI	T1,TO10BC	;MASK IT DOWN
	HLRZ	T2,DEVETD(F)	;GET ETD ADDR
	MOVX	T3,ED.TDB	;INDICATE WE ARE WAITING FOR DIRECT XFER
	STOR.	T3,ED.2TS,(T2)	; TO COMPLETE
	LOAD.	T3,ED.IBK,(T2)	;GET INPUT BUFFER ADDRESS
	HRLI	T3,(POINT 16,)	;MAKE IT A BYTE POINTER
	MOVEM	T3,@ETDTBP(T2)	;PUT IT IN THE EPT
	XCT	ETDDTO(T2)	;START THE XFER
	POPJ	P,		;AND RETURN
>; End of repeat 0
;MAIDBL RESPONDS TO DOORBELL INTERRUPTS FOR MAINTENANCE MODE

MAIDBL:	MOVEI	T1,CL11PT	;CLEAR THE DOORBELL
	XCT	ETDCNO(F)	;DO THE CONO
	MOVX	T1,ED.BFR	;GET BUFFER READY BIT
	TDNE	T1,ETDSTS(F)	;HAS UUO LEVEL READ THE BUFFER YET?
	JRST	MAIDER		; NO, SOMEBODY SCREWED UP...
	LOAD.	T1,ED.2TS,(F)	;GET TO-10 STATUS
	CAIE	T1,ED.TID	;ARE WE IDLE?
	JRST	MAIDER		; NO, MOP SCREWED UP...

;GET READY TO COPY THE MESSAGE LENGTH INTO THE BUFFER
	LOAD.	T1,ED.IBK,(F)	;GET ADDRESS OF INPUT BUFFER
	HRLI	T1,(POINT 8,)	;MAKE IT A BP
	MOVEM	T1,@ETDTBP(F)	;SAVE IT IN THE DTE CONTROL BLOCK
	MOVX	T1,ED.TIB	;INDICATE NEW STATE
	STOR.	T1,ED.2TS,(F)	;IN THE ETD BLOCK
	MOVEI	T1,-2&TO10BC	;START TRANSFER OF MESSAGE LENGTH (2 BYTES)
	XCT	ETDDTO(F)	;START THE XFER
	POPJ	P,		;AND RETURN

;HERE ON TO-10 XFER DONE WHILE IN MAINTENANCE MODE
MAIIDN:	MOVX	T1,CLTO10	;CLEAR TO-10 XFER DONE
	XCT	ETDCNO(F)	;TELL THE HARDWARE ABOUT IT
	LOAD.	T1,ED.2TS,(F)	;GET TO-10 STATE
	CAIN	T1,ED.TIB	;WERE WE WAITING FOR THE BYTE COUNT?
	JRST	MAIINP		; YES, GO START REAL XFER
	CAIN	T1,ED.TDB	;WERE WE WAITING FOR FINAL XFER TO COMPLETE?
	JRST	MAIITC		; YES, GO DO INPUT COMPLETE STUFF
	JRST	MAIDER		;NO TO EITHER...

;HERE WHEN WE HAVE THE BYTE COUNT FOR THE MOP MESSAGE.  START THE REAL XFER
MAIINP:	LOAD.	T4,ED.IBK,(F)	;GET ADDRESS OF INPUT BUFFER
	HRLI	T4,(POINT 8,)	;MAKE IT A BYTE POINTER
	PUSHJ	P,GX2BYT	;GET THE SIZE OF THE MESSAGE INTO T1

	JUMPE	T1,MAIDER	;ZERO LENGTH MESSAGE IS NO GOOD
	CAILE	T1,DTEMMS	;IS THE MESSAGE TOO BIG?
	JRST	MAIDER		; YES, DIE GRACEFULLY
	MOVNS	T1		;NEGATE THE LENGTH
	ANDI	T1,TO10BC	;REDUCE IT TO 12 BITS
	TXO	T1,TO10IB	;INTERRUPT 11 AFTER THIS XFER
	XCT	ETDDTO(F)	;START THE TRANSFER
	MOVEI	T1,ED.TDB	;INDICATE THAT WE ARE
	STOR.	T1,ED.2TS,(F)	; WAITING FOR BULK OF MESSAGE TO ARRIVE
	POPJ	P,		;AND RETURN

;HERE WHEN ALL OF MESSAGE HAS ARRIVED.  LET UUO LEVEL KNOW
MAIITC:	MOVX	T1,ED.TID	;INDICATE THAT THE TO-10 SIDE OF
	STOR.	T1,ED.2TS,(F)	; THE DTE IS NOW IDLE
	MOVX	T1,ED.BFR	;GET THE BUFFER IS READY BIT
	IORM	T1,ETDSTS(F)	;LET UUO LEVEL KNOW THAT BUFFER IS VALID

;HERE TO SIGNAL I/O DONE
MAIIOD:	MOVEI	T1,PSIIOD##	;SIGNAL I/O DONE
	LOAD.	F,ED.DDB,(F)	;MAKE F POINT TO DDB

;HERE TO SIGNAL UUO LEVEL THAT SOMETHING HAS HAPPENED
;CALL WITH F CONTAINING DDB POINTER

MAISGL:	PUSHJ	P,(T1)		;SIGNAL I/O DONE OR ERROR
	MOVE	T1,DEVAIO(F)	;GET NON-BLOCKING I/O BITS
	TRNE	T1,DEPAIO	;NON-BLOCKING I/O???
	POPJ	P,		; YES, WE CAN QUIT NOW
	LDB	T1,PJOBN##	;GET THE JOB NUMBER
	PJRST	EWAKE##		;GO WAKE UP THE JOB

;HERE WHEN WE GET TO-11 XFER DONE
MAIOTC:	MOVX	T1,CLTO11	;CLEAR TO-11 DONE
	XCT	ETDCNO(F)	;. . .

	LOAD.	T1,ED.2ES,(F)	;GET THE TO-11 STATE
	CAIE	T1,ED.EDB	;WAITING FOR TO-11 DONE?
	POPJ	P,		; NO, JUST RETURN

	MOVX	T1,ED.EID	;NEW STATE IS TO-11 IDLE
	STOR.	T1,ED.2ES,(F)	;LET UUO LEVEL KNOW THAT BUFFER IS AVAILABLE

	JRST	MAIIOD		;WAKE UP THE JOB
;DTEOUT - ROUTINE TO PROCESS THE OUTPUT UUO FOR THE DTE DEVICE
; CALL:
;  F/ DDB ADDRESS
; RETURN:
;  CPOPJ			;ALWAYS


DTEOUT:	PUSHJ	P,SAVE2##	;P1/ DEVOAD	P2/ DATA BUFFER ADDRESS
	TLO	S,IO		;INDICATE THAT WE ARE DOING OUTPUT
	IORM	S,DEVIOS(F)	;IN THE DDB ALSO
	PUSHJ	P,DTECKM	;CHECK FOR CORRECT MODE

	SKIPA			;SKIP OVER INITIAL WAIT
DOWAIT:	PUSHJ	P,DIOWAI	; WAIT FOR -11 TO GRONK US
DOLOOP:	PUSHJ	P,DTEONL	;MAKE SURE THAT WE ARE ONLINE
	  POPJ	P,		;IF NOT, RETURN (ERROR BITS ARE SET)
	HRRZ	P1,DEVOAD(F)	;GET USERS BUFFER ADDRESS
	HLRZ	P2,DEVETD(F)	;GET ETD ADDRESS
	LOAD.	T1,ED.2ES,(P2)	;GET TO-11 STATE
	CAIE	T1,ED.EID	;IS IT IDLE?
	 JRST	 DOWAIT		; NO, GO WAIT FOR XFER TO COMPLETE

;HERE TO COPY DATA FROM USER TO TO-11 MONITOR BUFFER

	EXCTUX	<HRRZ T1,1(P1)>	;GET THE NUMBER OF USER BYTES
	JUMPE	T1,ADVBFE##	;QUIT NOW IF BUFFER EMPTY
	CAILE	T1,DTEMMS	;MAKE SURE THAT THE NUMBER IS REALISTIC
	JRST	D.BKTL		;AND TELL THE USER "BLOCK TO LARGE"

	MOVSI	T2,(POINT 8,)	;START A BYTE POINTER
	HRRI	T2,2(P1)	;COMPLETE THE SOURCE BP

	MOVE	T4,T1		;DEST BYTE COUNT CAN BE SAME AS SOURCE

	LOAD.	T5,ED.OBK,(P2)	;GET OUTPUT BUFFER ADDRESS
	HRLI	T5,(POINT 8,)	;MAKE IT A BP
	MOVEM	T5,@ETDEBP(P2)	;SAVE IT IN THE DTE CONTROL BLOCK (TO-11 PTR)

	IDPB	T1,T5		;INSTALL LOW ORDER PART OF MESSAGE LENGTH
	LDB	T3,[POINT 8,T1,27] ;GET HIGH ORDER PART OF MESSAGE LENGTH
	IDPB	T3,T5		;INSTALL THAT TOO

	XCT	2,[EXTEND T1,[EXP MOVSLJ,0]] ;COPY THE DATA INTO THE MONITOR
	 PUSHJ	 P,DTEMDS	;++ MOVSLJ DIDN'T SKIP

	MOVX	T1,ED.EDB	;NEW STATE IS WAITING FOR TO-11 XFER
	STOR.	T1,ED.2ES,(P2)	;INSTALL IT

	MOVEI	T1,TO11DB	;GO RING THE PDP-11'S
	XCT	ETDCNO(P2)	; DOORBELL

	PUSHJ	P,ADVBFE##	;ADVANCE THE USER'S OUTPUT BUFFER
	  POPJ	P,		;IF NO MORE OUTPUT, RETURN TO UUOCON
	JRST	DOLOOP		;OTHERWISE TRY TO SEND MORE

	PURGE	T5		;WE'RE DONE WITH THE EXTEND INSTRUCTIONS
	SUBTTL	DTEHNG	Hung device code for the DTE device

;DTEHNG WILL SET AN ERROR BIT IN DEVIOS, SO THAT DIMOPW WILL KNOW WHEN TO
; GIVE UP.
; CALL:
;  F/  DDB ADDRESS
;  S/  DEVIOS
; RETURN:
;  CPOPJ1 ALWAYS

DTEHNG:	PUSHJ	P,D.DERR	;SET THE IODERR BIT IN DEVIOS
	JRST	CPOPJ1		;AND ALWAYS SKIP RETURN
;WAIT FOR -11 TO GRONK US.  IF DOING NON-BLOCKING I/O, JUST RETURN

DIOWAI:
repeat	0,<
	TLNE	S,IOBEG		;ARE WE IN ROM-DUMP MODE?
	 PUSHJ	 P,FSTIO	; YES, GO START UP TRANSFER
>
	MOVE	T1,DEVAIO(F)	;GET NON-BLOCKING I/O BITS
	TRNE	T1,DEPAIO	;DOING NON-BLOCKING I/O?
	JRST	TPOPJ##		; YES, POPJ PAST CALLER AND GET OUT OF HERE
	MOVEI	T1,EV.DTE	;OTHERWISE, GO INTO
	PJRST	ESLEEP##	; EVENT WAIT
;DTECKO - CHECK OWNERSHIP OF THE ETD BLOCK
; CALL:
;  F/ DDB ADDRESS
; RETURN:
;  CPOPJ			;ETD IS NOT IN PROGRAM MODE
;  CPOPJ1			;ETD IS IN PROGRAM MODE

DTECKO:	HLRZ	T1,DEVETD(F)	;GET THE ETD BLOCK POINTER
	HRRZ	T1,ETDUSR(T1)	;GET THE USER CODE
	CAIN	T1,DD.PRO	;IS IT A PROGRAM?
	AOS	(P)		;YES, SKIP RETURN
	POPJ	P,		;NO, BAD RETURN


;DTEONL - CHECK TO SEE IF THE DTE IS "ONLINE"
; CALL:
;  F/ DDB ADDRESS
; RETURN:
;  CPOPJ			;NOT OWNED OR OFFLINE (WITH ERROR BITS SET)
;  CPOPJ1			;DTE SEEMS TO BE READY FOR I/O

DTEONL: PUSHJ	P,DTECKO	;FIRST SEE IF WE OWN THE LINE
	  JRST	D.IMPM		; IF NOT, MUST BE IMPROPER MODE
	MOVE	S,DEVIOS(F)	;GET THE DEVICE STATUS
	TRNE	S,IOSSRM!IOSMRN	;IF EITHER ERROR IS LIT
	JRST	D.DERR		; RETURN TO USER WITH ERROR
	TRNE	S,IODERR!IODTER!IOIMPM!IOBKTL ;IF ANY ERROR LEFT
	POPJ	P,		; USER MUST CLEAR FIRST
	HLRZ	T2,DEVETD(F)	;GET THE POINTER TO ETD BLOCK
	TRNE	S,IOSMAI	;ARE WE TRYING MAINT MODE
	JRST	DTEON1		; YES, TRY SEE IF WE'RE IN THE MODE
	MOVSI	T1,(ED.PPC)	;SEE IF PRIMARY PROTOCOL IS WORKING
	TDNN	T1,ETDSTS(T2)	;ARE WE?
	JRST	D.DERR		;NO, DEVICE ERROR
	JRST	CPOPJ1##	;GIVE GOOD RETURN

DTEON1:	MOVSI	T1,(ED.MAI)	;CHECK FOR MAINT MODE
	TDNN	T1,ETDSTS(T2)	;ARE WE?
	JRST	D.DERR		;NO, DEVICE ERROR
	JRST	CPOPJ1##	;GOOD
;DTECKM - CHECK/SET THE MAINT/NORMAL MODE OF THE LINE
; CALL:
;  F/ DDB ADDRESS
; RETURN:
;  CPOPJ			;ALWAYS

DTECKM:	PUSHJ	P,DTECKO	;MAKE SURE WE OWN THE LINE
	  POPJ	P,		;WE DON'T, LOSE
	HLRZ	T2,DEVETD(F)	;GET ADDRESS OF ETD BLOCK
	MOVE	T1,ETDSTS(T2)	;GET THE ETD STATUS WORD
	MOVE	S,DEVIOS(F)	;GET THE DEVICE STATUS WORD
	TRNN	S,IOSMAI	;SEE IF WE ARE TRYING FOR MAINT MODE
	JRST	DTECK1		;NOPE, GO SEE ABOUT PRMARY PROTOCOL
	TLNE	T1,(ED.MAI)	;CHECK THE MODE OUT
	POPJ	P,		;WE'RE OK

	HLRZ	T2,DEVETD(F)	;GET THE ETD BLOCK ADDR IN T2
	MOVSI	T1,(ED.MAI)	;GET THE MAINTAINACE BIT
	IORM	T1,ETDSTS(T2)	;IDENTIFY OURSELVES AS DOING MAINT
	POPJ	P,		; RETURN READY TO TALK MOP

DTECK1:	TLNE	T1,(ED.PPC)	;ARE WE IN PRIMARY PROTCOL?
	POPJ	P,		;YUP, THATS OK
				;FOR RIGHT NOW THERE SHOULD BE NO
				;WAY TO GET INTO THIS MODE, SO WE
				;WILL JUST RETURN A DEVICE ERROR

D.IMPM:	MOVEI	S,IOIMPM	;SET IMPROPER MODE
	JRST	D.SET		;SET DEVIOS CORRECTLY

D.DERR:	MOVEI	S,IODERR	;GET THE DEVICE ERROR BIT
	JRST	D.SET		;SET IN DEVIOS

D.BKTL:	MOVEI	S,IOBKTL	;GET THE BLOCK TOO LARGE BIT
D.SET:	IORB	S,DEVIOS(F)	;SET THE APPROPRIATE BIT
	POPJ	P,		; AND RETURN
	SUBTTL	DTEMAI	INTERRUPT LEVEL CODE FOR MOP MODE XFERS

DTEMAI:	LOAD.	P1,ED.DDB,(F)	;GET POINTER TO DDB
	XCT	ETDCNI(F)	;GET CONI BITS INTO T1
	TXNE	T1,DEAD11!TO10ER!TO11ER ;-11 DIE, OR ANY XFER ERRORS?
	JRST	MAIDER		; YES, SAY SO
	TXNE	T1,TO10DN	;TO-10 XFER COMPLETE?
	JRST	MAIIDN		; YES, GO DO BUFFER CLEANUP
	TXNE	T1,TO10DB	;ANYBODY HOME?
	JRST	MAIDBL		; YES, GO START XFERS
	TXNE	T1,TO11DN	;TO-11 XFER DONE?
	JRST	MAIOTC		; YES, GO SIGNAL OUTPUT DONE
;	PJRST	DTICLR		;FREE INTERRUPTS, NO BITS...

MAIDER:	MOVEI	T1,PSIDWN##	;SIGNAL DEVICE OFF LINE
	LOAD.	F,ED.DDB,(F)	;GET BACK DDB POINTER
	PUSHJ	P,MAISGL	;WAKE UP THE JOB
	PUSHJ	P,D.DERR	;SET IO.DER FOR UUO LEVEL
	HLRZ	F,DEVETD(F)	;MAKE F POINT TO DTE AGAIN
	PJRST	DTICLR		;CLEAR THE DTE...
SUBTTL	DTEDSP - ENTRY VECTOR TO DTESER

;DTEDSP IS THE OUTSIDE WORLD'S ENTRY TO DTES IN Q'ED PROTOCOL V2.
; CALL:
;  T1/  FUNCTION CODE
;  T2/  CPU,,DTE (FOR FUNCTIONS DD.OPN AND DD.CET)
;  T2/  ETD BLOCK ADDRESS (FOR ALL OTHER FUNCTIONS)
;  T3/  FUNCTION SPECIFIC DATA
; RETURN:
;  CPOPJ			;ON FAILURE
;  CPOPJ1			;ON SUCCESS
;NOTE THAT THE FAIL RETURN IS ONLY GIVEN WHEN WE ARE CALLED FROM A
;DRIVER THAT DOES NOT CURRENTLY "OWN" THE LINE.

DTEDSP::PUSHJ	P,SAVE4##	;SAVE ALL PEAS
	CAIL	T1,0		;FIRST RANGE CHECK THE
	CAILE	T1,DD.MAX	; FUNCTION CODE
	 STOPCD(CPOPJ##,DEBUG,DTEIKF) ;++ILLEGAL KONTROLLER FUNCTION
	PUSH	P,F		;SAVE F FOR A FEW
	MOVE	F,T2		;SET UP F FOR GETETD AND FRIENDS
	PUSH	P,U		;SAVE U
	PUSH	P,J
	PUSHJ	P,@DTEDST(T1)	;AND DISPATCH ON THE FUNCTION CODE
	TRNA			;IF NO SKIP, DON'T INCREMENT RETURN PC
	AOS	-3(P)		;SKIPPED, INCREMENT THE PC
	POP	P,J
	POP	P,U
	POP	P,F		;RESTORE F
	POPJ	P,		; AND RETURN

DTEDST:	IFIW	DDFOPN		;0 = OPEN CIRCUIT (INITIALIZE PROTOCOL)
	IFIW	DDFCLS		;1 = CLOSE CIRCUIT (HALT PROTOCOL)
	IFIW	DDFQUE		;2 = QUEUE OUTPUT BUFFER
	IFIW	DDFPRB		;3 = POST RECEIVE BUFFER
	IFIW	DDFCET		;4 = CHECK EXISTANCE
IFN <.-DTEDST-DD.MAX-1>,<PRINTX ?Table DTEDST is incorrect>
;DDFOPN PERFORMS THE INITIALIZATION ON THE DTE
; CALL:
;  T3/  DNADLL CALLBACK ID
;  F/  CPU,,DTE
; RETURN:
;  CPOPJ ON ERROR
;  CPOPJ1 ON SUCCESS WITH T1/ ETD ADDRESS

DDFOPN:	PUSH	P,T3		;SAVE CALLBACK ID FOR A BIT
	PUSH	P,T4		;SAVE RECEIVE BUFFER ADDRESS
	S0PSHJ	GETETD		;GET ETD BLOCK
	  PJRST	TTPOPJ##	;NONE, RETURN
	POP	P,T4		;RESTORE RECEIVE BUFFER ADDRESS
	POP	P,T3		;AND CALLBACK ID
	MOVEM	T3,ETDLBK(F)	;SAVE CALLBACK ID FOR LATER USE
	HRRZ	T1,ETDUSR(F)	;GET LINE'S USER
	CAIE	T1,DD.DEC	;IS IT DECNET?
	POPJ	P,		;NO, RETURN NOW
	MOVEM	T4,ETDMBP(F)	;SAVE RECEIVE MESSAGE BLOCK POINTER
	PUSHJ	P,[PJSP	T1,DTERLD]	;GO RELOAD (OR RESTART PROTOCOL)
	MOVE	T1,F		;GET ETD BLOCK ADDRESS
	PJRST	CPOPJ1##	;AND RETURN


;DDFCLS WILL RESET THE DTE
; CALL:
;  F/  ETD BLOCK ADDRESS
; RETURN:
;  CPOPJ1			;ALWAYS

DDFCLS:	SKIPN	T1,F		;IF NEVER REALLY OPENED,
	JRST	CPOPJ1##	;SUCCEED VACUOUSLY (WITH NO BUFFER)
	PUSHJ	P,DTECLR	;RESET THE DTE
	MOVE	T1,ETDMBP(F)	;GET ANY ALLOCATED BUFFER
	SETZM	ETDMBP(F)	;CLEAR MEMORY
	SETZM	ETDLBK(F)	;...
	PJRST	CPOPJ1##	;AND RETURN
;DDFQUE QUEUE AN OUTPUT MESSAGE
; CALL:
;  F/  ETD BLOCK ADDRESS
;  T3/ MESSAGE BUFFER ADDRESS
; RETURN:
;  CPOPJ			;ON ERROR
;  CPOPJ1			;ON SUCCESS

DDFQUE:	JUMPE	F,CPOPJ##	;FAIL IF NOT INITIALIZED
	LOAD.	T4,ED.CPN,(F)	;GET THE CPU NUMBER WE NEED TO BE ON
	CAME	T4,.CPCPN	;ARE WE ON IT?
	 STOPCD	 .,STOP,DTECOW	;++CALLED FOR OUTPUT ON WRONG CPU
				;NO, GIVE A STOPCODE
				;(BEING ON THE CORRECT CPU IS THE
				; RESPONSIBILITY OF THE OWNER OF THE LINE)
	SETZB	P2,S		;ZERO SOME OF THESE FOR DTEQUE
	SKIPN	P3,T3		;SET UP POINTER TO MESSAGE BLOCK
	 STOPCD  DTERLD,DEBUG,DTEBMB ;++ BAD MESSAGE BLOCK POINTER
	PJRST	DTEQMC		;QUEUE IT OUT (PROPAGATE SUCCESS/FAILURE)


;DDFPRB POST RECEIVE BUFFER
; CALL:
;  F/  ETD BLOCK ADDRESS
;  T3/ MESSAGE BUFFER ADDRESS
; RETURN:
;  CPOPJ			;ON ERROR
;  CPOPJ1			;ON SUCCESS

DDFPRB:	JUMPE	F,CPOPJ##	;FAIL IF NOT INITIALIZED
	SKIPE	ETDMBP(F)	;ALREADY HAVE A RECEIVE BUFFER ALLOCATED?
	POPJ	P,		;ALREADY HAVE A BUFFER, REFUSE THIS ONE
	MOVEM	T3,ETDMBP(F)	;SAVE RECEIVE MESSAGE BLOCK POINTER
	PJRST	CPOPJ1##	;AND RETURN


;DDFCET - CHECK DTE EXISTANCE
; CALL:
;  F/  CPU,,DTE
;RETURN:
;  CPOPJ IF DTE DOESN'T EXIST
;  CPOPJ1 IF DTE EXISTS WITH T1/ ETD ADDRESS

DDFCET:	S0PSHJ	GETETD		;GET ADDRESS OF ETD BLOCK
	  POPJ	P,		;NONE, ERROR RETURN
	MOVE	T1,ETDSTS(F)	;GET STATUS BITS
	TXNE	T1,ED.DTX	;IF IT DOES NOT EXIST,
	TXNE	T1,ED.DTM	;OR IS THE MASTER,
	POPJ	P,		;TELL DNADLL IT'S NOT THERE
	MOVE	T1,F		;IT'S OK FOR DECNET TO USE (LATER),
	JRST	CPOPJ1##	;RETURN SUCCESS WITH ETD ADDRESS IN T1
;DNDDMP - RECEIVE MESSAGE FROM 11
; CALLED WITH:
;  T1/ BYTE POINTER TO WHERE IT GOES
;  T2/ COUNT OF BYTES TO TRANSFER
;	(TO10IB IS SET IN T2 TO INTERRUPT 11 AFTER XFER)
; RETURNS WITH MESSAGE AS PER T1
; USES T1,T2

	T10TIM==^D2		;2000 MS SOUNDS REASONABLE

DNDDMP:	PUSHJ	P,SAVE1##	;SAVE A PEA
	MOVE	P1,T2		;SAVE THE COUNT AND FLAG
	PUSHJ	P,RESPTR	;RESOLVE THE INDEXED BYTE POINTER
	MOVEM	T1,@ETDTBP(F)	;STORE TO-10 BYTE POINTER
	MOVEI	T1,CLTO10	;SET INTO PROPER STATE
	XCT	ETDCNO(F)	;DO CONO DTEN,(T1)
	MOVE	T1,P1		;GET COPY OF BYTE COUNT
	TRZ	T1,TO10IB	;ZAP BIT IF ON
	MOVNS	T1		;GET NEGATIVE COUNT
	ANDI	T1,TO10BC	;ONLY WANT THESE BITS
	TRNE	P1,TO10IB	;DID USER SET IT?
	TRO	T1,TO10IB	;YES, HE MUST HAVE WANTED IT
	XCT	ETDDTO(F)	;DATAO DTEN,T1
	MOVEI	P1,T10TIM	;TIME TO WAIT FOR TO-10
	IMUL	P1,TICSEC##	;CONVERT TO TICKS
	ADD	P1,SYSUPT##	;FIGURE OUT FUTURE TIME

DNDDM1:	MOVEI	T1,TO10DN!TO10ER ;CHECK FOR THESE
	XCT	ETDCSZ(F)	;CHECK IF DONE
	JRST	DNDDM2		;GO IT
	CAMG	P1,SYSUPT##	;DONE YET?
	POPJ	P,		;SIGNAL ERROR
	PUSHJ	P,SCDCHK##	;SEE ABOUT OTHERS
	JRST	DNDDM1		;LOOP

DNDDM2:	MOVEI	T1,TO10ER	;CHECK FOR ERROR
	XCT	ETDCSZ(F)	;LOOK
	POPJ	P,		;YES, GIVE BAD RETURN
	JRST	CPOPJ1##	;RETURN
;WAIT11 ROUTINE TO WAIT FOR ELEVEN TRANSFER
; CALL:
;  F/  ETD BLOCK ADDRESS
; RETURN:
;  CPOPJ			;WHEN TIMED OUT OR ERROR OCCURS
;  CPOPJ1			;ON SUCCESS
; USES T1

	LDSTIM==^D2		;LENGTH OF TIME TO WAIT FOR XFER

WAIT11:	PUSHJ	P,SAVE1##	;SAVE A PEA
	MOVEI	T1,CLTO11+TO11DB ;CLEAR TO-11 DONE, RING TO-11 DB
	XCT	ETDCNO(F)	;DO IT
	MOVEI	P1,LDSTIM	;TIME TO WAIT FOR LOAD (SECS)
	IMUL	P1,TICSEC##	;GET IT IN TICS
	ADD	P1,SYSUPT##	;TIME IN THE FUTURE

WAIT12:	MOVEI	T1,TO11DN!TO11ER ;LOOK FOR SOMETHING BACK
	XCT	ETDCSZ(F)	;CHECK FOR RETURN
	JRST	WAIT13		;GOT IT, CHECK OUT REASON
	CAMG	P1,SYSUPT##	;OVER OUR ALOTTED TIME
	POPJ	P,		;TO ELEVEN TIMED OUT
	PUSHJ	P,SCDCHK##	;SEE ABOUT ANYBODY ELSE
	JRST	WAIT12		;DO IT AGAIN

WAIT13:	MOVEI	T1,TO11ER	;CHECK IF IT WAS AN ERROR
	XCT	ETDCSO(F)	;WAS IT
	AOS	(P)		;MAKE IT A GOOD RETURN
	POPJ	P,		;BACK TO WHOEVER
SUBTTL DTE20 TO-11 QUEUE ROUTINES

;ROUTINE TO PLACE AN ENTRY INTO A DTE'S TO-11 QUEUE.
; CALL:
;	MOVE	S,[XWD POST ADDRESS,DEVICE DRIVER DATA]
;	MOVE	P1,[XWD 10 CPU#,DTE #]
;	MOVE	P2,[XWD DEVICE,FUNCTION]  (FUNCTION+EM.16B IF INDIRECT WORD MODE)
;	MOVE	P3,[XWD LINE,DATA]	;SOME FUNCTIONS DON'T USE DATA,
					; INDIRECT FUNCTIONS AND LONG DIRECT,
					; DATA IS COUNT
					;IF P4 HAS BYTE POINTER
;	MOVE P4,[BYTE POINTER TO DATA]	;IF LONG DIRECT OR INDIRECT
;	PUSHJ	P,DTEQUE	;
;	  <ERROR RETURN>	;COULD NOT SEND THE MESSAGE
;				; T1 = 0 IF NO FREE CORE
;				; T1 = -1 IF RELOAD BIT OR PRIMARY NOT UP
;				;  T2 = EDTSTS(F)
;	<OK RETURN>
;
;
; WHEN CALLED FOR A TRANSFER IN THE MCB PROTOCOL, THE TRANSFER MODE IS
; DETERMINED FROM THE BYTE SIZE IN THE BYTE POINTER STORED IN P4. ENTER
; THROUGH DTEQUF WHEN F ALREADY POINTS TO A GOOD ETD BLOCK.
;
; USES T1-T4

DTEQUE::PUSH	P,U		;SAVE U FOR HEADER ADDRESS
	PUSH	P,F		;SAVE F
	MOVE	F,P1		;PUT 10#,DTE# IN F FOR GTETDS
	PUSHJ	P,GTETDS	;SETUP F WITH DTE CONTROL BLOCK ADDRESS
	SETO	T1,		;ASSUME PROPER PROTOCOL NOT UP
	LOAD.	T2,ED.USR,(F)	;GET THE USER OF THIS LINE
	CAIE	T2,DD.ANF	;IS IT ANF?
	CAIN	T2,DD.NOB	; OR NOBODY (-20F)?
	JRST	DTEQU1		;YES TO EITHER
	CAIE	T2,DD.IBM	;OR THE DN60?
	JRST	FUPOPJ		;NO--GIVE ERROR RETURN
DTEQU1:
IFN FTMP,<
	LOAD.	T1,ED.CPN,(F)	;GET CPU NUMBER
	CAME	T1,.CPCPN##	;CALLED ON CORRECT CPU
	STOPCD	.,STOP,DTEWCN,DTEPDI, ;++WRONG CPU NUMBER
>
DTEQUF:	MOVE	T2,ETDSTS(F)	;GET STATUS WORD
	SETO	T1,		;ASSUME RELOAD BIT UP OR PRIMARY DOWN
	TLNE	T2,(ED.PPC)	;IS PRIMARY PROTOCOL DOWN OR
	TLNE	T2,(ED.RLD)	;IS THE RELOAD BIT SET?
	PJRST	FUPOPJ##	;YES, GIVE ERROR RETURN
	PUSHJ	P,GT2EFT	;GET TO-11 FUNCTION TYPE
	STOPCD	.,STOP,DTEEFI,DTEPDI, ;++ILLEGAL FUNCTION CODE
	PUSHJ	P,@DTQTYP(T1)	;DISPATCH TO PROPER ROUTINE
				; WHICH WILL CREATE PROPER HEADER
				; FOR FUNCTION
	  TDZA	T1,T1		;RETURN 0 BECAUSE OUT OF FREE CORE
	AOS	-2(P)		;GIVE GOOD RETURN
	PJRST	FUPOPJ##	;GIVE NO FREE CORE RETURN

DTQTYP:	DTINDR
	DT16BT
	DTLINE
	DTLNGD
	DTLNDT
	DTD60D
;FUNCTION DEPENDENT ROUTINES

;HERE IF DRIVER HAS RH(P3) 16 BIT BYTES TO BE COPIED INTO A MESSAGE


DTLNGD:	HRRZ	T2,P3		;GET COUNT
	PUSHJ	P,DTMHED	;GET HEADER, SET UP COMMON STUFF
	  POPJ	P,		;OUT OF CORE . . .
	HRLI	T4,(POINT 8,)	;EACH DATUM IS AN 8 BIT BYTE
	MOVE	T2,P4		;GET COPY OF POINTER
	HRRZ	T3,P3		;AND COUNT
	JUMPE	T3,DTEQU4	;IF NO DATA, SKIP THIS
DTLNG1:	ILDB	T1,T2		;GET DATA
	IDPB	T1,T4		;STORE IN MESSAGE
	SOJG	T3,DTLNG1	;LOOP FOR ALL BYTES
	JRST	DTEQU4		;DO QUEUE HEADER


;HERE IF THIS IS AN INDIRECT MESSAGE

DTINDR:	MOVEI	T2,2		;SIZE OF DATA NOT INCLUDING HEADER
	PUSHJ	P,DTMHED	;DO COMMON STUFF
	  POPJ	P,		;OUT OF CORE . . .
	HRLI	T4,(POINT 8,)	;MAKE T4 AN 8 BIT POINTER
	HLRZ	T1,P3		;P3 HAS LINE,,COUNT
	IDPB	T1,T4		;STORE LINE
	STOR.	T1,EQ.ELN,(U)	;ALSO PUT IN HEADER FOR POST TIME
	IDPB	P3,T4		;COUNT
	STOR.	P3,EQ.CNT,(U)	;INDIRECT MESSAGES NEED TO HAVE
				; COUNT AND POINTER REMEMBERED
	STOR.	P4,EQ.PTR,(U)	;NOW POINTER
	MOVSI	T1,(EQ.16B)	;IS DATA TO BE SENT IN 16 BIT MODE?
	TRNE	P2,EM.16B	;THATS INDICATED BY EM.16B IN FUNCTION ARG
	IORM	T1,ETQSTS(U)	;YES, SET THE BIT
	JRST	DTEQU4		;GO FINISH QUEUE HEADER

;HERE FOR THOSE FUNCTIONS WHICH HAVE 16 BIT DATA

DT16BT:	MOVEI	T2,2		;SIZE OF DATA NOT INCLUDING HEADER
	PUSHJ	P,DTMHED	;RETURN POINTER IN T4
	  POPJ	P,		;OUT OF CORE . . .
	IDPB	P3,T4		;STORE 16 BIT DATA IN MESSAGE
	MOVE	T1,P3		;NOW GET WHAT MAY BE A LINE NUMBER
	ANDI	T1,377		;JUST 8 BITS
	STOR.	T1,EQ.ELN,(U)	;IN CASE THIS IS A LINE NUMBER, POST
				; ROUTINE MAY LIKE TO SEE IT.
	JRST	DTEQU4		;FINISH UP
;HERE FOR THOSE FUNCTIONS WHICH HAVE LINE NUMBER ONLY

DTLINE:	MOVEI	T2,2		;SIZE OF DATA NOT INCLUDING HEADER
	PUSHJ	P,DTMHED	;GET 16 BIT BYTE POINTER IN T4
				; AND HEADER ADDRESS IN U
	  POPJ	P,		;OUT OF CORE . . .
	HLRZ	T1,P3		;GET LINE NUMBER PROVIDED
	HRLI	T4,(POINT 8,)	;GET 8 BIT BYTE POINTER
	IBP	T4		;SKIP OVER FIRST 8 BIT BYTE
	IDPB	T1,T4		;LINE NUMBER IS SECOND 8 BIT BYTE
	STOR.	T1,EQ.ELN,(U)	;REMEMBER FOR POST TIME
	JRST	DTEQU4		;GO FINISH UP

;HERE FOR THOSE FUNCTIONS WHICH HAVE LINE NUMBER AND DATA

DTLNDT:	MOVEI	T2,2		;SIZE OF DATA NOT INCLUDING HEADER
	PUSHJ	P,DTMHED	;POINTER IN T4
	  POPJ	P,		;OUT OF CORE . . .
	HRLI	T4,(POINT 8,)	;8 BIT POINTER INSTEAD
	HLRZ	T1,P3		;GET LINE NUMBER
	IDPB	T1,T4		;PUT IN MESSAGE
	STOR.	T1,EQ.ELN,(U)	;AND IN HEADER FOR POST REPORT OF LINE
	IDPB	P3,T4		;AND DATA
	JRST	DTEQU4		;GO FINISH UP

;HERE IF DN60 DIRECT OR DN60 DIRECT AND INDIRECT DATA (.EMD6D)

; CALL:	PUSHJ	P,DTLDST	;(RH) OF S MUST POINT TO A
;				; BLOCK WHICH CONTAINS AS THE
;				; (RH) OF THE FIRST WORD THE NUMBER
;				; OF 8-BIT DIRECT BYTES THAT ARE
;				; IN THE BLOCK.

DTD60D:	MOVE	T3,S		;GET HERE CAUSE CAN'T INDEX THRU S
	HRRZ	T2,(T3)		;GET COUNT OF 8-BIT BYTES IN THE BLOCK
	PUSHJ	P,DTMHED	;GO SETUP THE QUEUE HEADER AND
				; THE MESSAGE HEADER.
	  POPJ	P,		;WE ARE OUT OF FREE CORE
	HRLI	T4,(POINT 8,)	;MAKE IT A 8-BIT BYTE POINTER
	MOVE	T3,S		;GET HERE CAUSE CAN'T INDEX THRU S
	MOVE	T1,[POINT 8,1(T3)] ;POINT TO THE DATA
	HRRZ	T2,(T3)		;GET COUNT OF BYTES
	STOR.	P3,EQ.CNT,(U)	;INDIRECT MESSAGES NEED COUNT REMEMBERED
	STOR.	P4,EQ.PTR,(U)	;POINTER TO INDIRECT DATA
DTLDS1:	PUSH	P,T3		;SAVE T3
	ILDB	T3,T1		;GET A BYTE OF DIRECT DATA
	IDPB	T3,T4		;PUT IN THE MESSAGE HEADER
	POP	P,T3		;RESTORE T3
	SOJG	T2,DTLDS1	;ALL BYTES XFER'ED TO MSG HEADER?
;	PJRST	DTEQU4		;GO SEND THE MESSAGE
DTEQU4:	MOVE	T4,U		;GET QUEUE HEADER ADDRESS IN T4 FOR DTESND
	HLRZ	T1,S		;GET POST ADDRESS
	STOR.	T1,EQ.PST,(U)	;POST ADDRESS (OR ZERO IF NONE)
	STOR.	S,EQ.DRD,(U)	;AND STORE DRIVER'S DATA
	CONO	PI,PI.OFF	;TURN OFF PI AND TRY TO GET DTE
	LOAD.	T1,ED.2ES,(F)	;GET TO-11 STATE
	CAIN	T1,ED.EID	;IDLE?
	JRST	[MOVEI	T1,ED.EDB ;YES, MAKE IT BUSY FOR US
		 STOR.	T1,ED.2ES,(F) ;PUT IT IN STATE CODE FOR TO-11
		 PUSHJ	P,DTESND
		 JRST	DTEQU7]	;AND GO SEND THE MESSAGE, BYPASS QUEUE
				;PI STILL OFF TO INTERLOCK THE QUEUE
	LOAD.	T3,ED.LST,(F)	;GET OLD TAIL OF QUEUE
	JUMPE	T3,DTEQU5	;Q IS EMPTY, MAKE THIS BOTH FIRST AND LAST
	STOR.	T4,EQ.LNK,(T3)	;REPLACE 0 WITH NEW POINTER TO NEXT ENTRY IN Q
	JRST	DTEQU6		;REMEMBER NEW GUY AS LAST

DTEQU5:	STOR.	T4,ED.QUE,(F)	;QUEUE WAS EMPTY, SO THIS IS
				; FIRST AND LAST ENTRY
DTEQU6:	STOR.	T4,ED.LST,(F)	;NEW LAST ENTRY
DTEQU7:	CONO	PI,PI.ON	;GIVE GOOD RETURN
	JRST	CPOPJ1##
;HERE AFTER ALL TO-11 DONE(OR ERROR) PROCESSING IS DONE, ETD
; ETD ADDRESS IS IN F, DTE STILL MARKED AS BUSY.

DTENXT:	CONO	PI,PI.OFF	;IN CASE SOMEONE TRIES TO ADD OR
				; DELETE AN ENTRY TO QUEUE
	LOAD.	T4,ED.QUE,(F)	;GET NEXT QUEUE ENTRY
	JUMPE	T4,DTENX1	;NONE, FREE UP DTE
	MOVEI	T1,ED.EDB	;TO-11 STATE IS BUSY WITH DIRECT
	STOR.	T1,ED.2ES,(F)	; MESSAGE
	LOAD.	T1,EQ.LNK,(T4)	;GET NEXT ENTRY AND MAKE IT
	STOR.	T1,ED.QUE,(F)	;THE NEW HEAD OF THE QUEUE
	SKIPN	T1		;IF QUEUE IS NOW EMPTY,
	STOR.	T1,ED.LST,(F)	;THERE IS NO TAIL
	CONO	PI,PI.ON	;OK TO MESS WITH QUEUE AGAIN
	JRST	DTESND		;GO SEND THIS MESSAGE

DTENX1:	MOVEI	T1,ED.EID	;MAKE TO-11 DTE SIDE IDLE
	STOR.	T1,ED.2ES,(F)	;PLACE IN TO-11 DTE STATE VAR
	CONO	PI,PI.ON	;OUT OF CRITICAL REGION
	POPJ	P,		;DISMISS INTERRUPT

;HERE WITH DTE CONTROL BLOCK ADDRESS IN F, QUEUE ENTRY HEADER IN T4
; DTE ALREADY PUT INTO TO-11 DIRECT BUSY STATE BY CALLER


DTESND:	STOR.	T4,ED.CUR,(F)	;REMEMBER THIS QUEUE ENTRY FOR POST
				; PROCESSING
	ADD	T4,[POINT 8,SIZE(.EQLEN,36)];MAKE INTO BYTE POINTER FOR DTE
	MOVEM	T4,@ETDEBP(F)	;PUT INTO TO-11 POINTER EPT LOCATION
	LOAD.	T2,EM.CNT,(T4)	;GET MESSAGE BYTE COUNT
	LOAD.	T4,ED.211,(F)	;POINT TO TO-11 SECTION
	STOR.	T2,EC.QSZ,(T4)	;SET QSIZE UP
	MOVSI	T2,(EC.16B)	;SEND IN 8 BIT MODE
	ANDCAM	T2,ETCSTS(T4)
	LOAD.	T3,EC.11C,(T4)	;GET TO11IC
	ADDI	T3,1		;INCREMENT, LET IT OVERFLOW
	STOR.	T3,EC.11C,(T4)	;TRUNCATE, PUT IT BACK
	MOVEI	T1,TO11DB	;RING 11 DOORBELL
	XCT	ETDCNO(F)	;DONG
	POPJ	P,		;RETURN
;EACH FUNCTION DEPENDENT ROUTINE CALLS DTMHED WITH THE LENGTH OF
; DATA WITHOUT BASIC HEADER IN 8 BIT BYTES IN T2.
; RETURNS 16 BIT BYTE POINTER TO "FIRST WORD" IN MESSAGE (AFTER
; MESSAGE HEADER), AND QUEUE HEADER ADDRESS IN U
; SKIP RETURN IF ALL IS OK, NON-SKIP RETURN IF WE RAN OUT OF CORE

DTMHED:	TRNE	T2,1B35		;COUNT MUST BE EVEN . . .
	STOPCD	.,STOP,DTEDNE,DTEPDI, ;++COUNT NOT EVEN
	ADDI	T2,.EMHBL	;ADD ON NUMBER OF 8 BIT BYTES FOR BASIC HEADER
	PUSH	P,T2		;SAVE BYTE COUNT FOR MESSAGE COUNT
	ADDI	T2,^D3		;ROUND UP TO NEAREST WORD
	ASH	T2,-^D2		;/^D4 = WORDS NEEDED
	ADDI	T2,SIZE(.EQLEN,36);INCLUDE SIZE OF QUEUE HEADER
	PUSH	P,T2		;SAVE FOR GIVING CORE BACK
	PUSHJ	P,MESCOR	;GET C(T2) WORDS OF CONTIGUOUS CORE
	  JRST	[POP P,T1
		 JRST TPOPJ##]	;GIVE THE ERROR RETURN
	MOVE	U,T1		;SAVE ADDRESS OF QUEUE HEADER
	POP	P,T2		;RESTORE WORD COUNT
	STOR.	T2,EQ.SIZ,(U)	;PUT INTO QUEUE HEADER FOR DEALLOCATION
	MOVEI	T4,SIZE(.EQLEN,36)(U);SKIP QUEUE HEADER FOR NOW
	HRLI	T4,(POINT 16,)	;MAKE INTO BYTE POINTER

	POP	P,T2		;RESTORE PROVIDED BYTE COUNT
	IDPB	T2,T4		;SAVE MESSAGE BYTE COUNT

	IDPB	P2,T4		;STORE FUNCTION CODE
	HLRZ	T1,P2		;GET DEVICE CODE
	IDPB	T1,T4		;STORE MESSAGE PROTOCOL DEVICE CODE
	SETZ	T1,		;ZERO THE
	IDPB	T1,T4		;SPARE
	MOVEI	T4,SIZE(.EMHBL,36)+SIZE(.EQLEN,36)(U)
				;T4 POINTS TO FIRST WORD
	HRLI	T4,(POINT 16,)	;ASSUME 16 BIT POINTER NEEDED -
				; IF 8 BIT POINTER IS NEEDED, JUST
				; HRLI T4,(POINT 8,)
	JRST	CPOPJ1##	;SUCCESS RETURN
;HERE WHEN MESSAGE IS TO BE SENT IN MCB (QPR V2) PROTOCOL.

; P3 POINTS TO THE MESSAGE BLOCK

	T6==T4+2		;T6 HOLDS INDEX FOR AUX BYTE POINTER

DTEQMC:	SE1ENT			;MAKE THIS CODE RUN IN SECTION ONE
	MOVE	T2,ETDSTS(F)	;GET STATUS WORD
	TLNN	T2,(ED.RLD)	;RELOAD REQUESTED???
	TLNN	T2,(ED.PPC)	;IS PRIMARY PROTOCOL DOWN
	POPJ	P,		; YES, GIVE THE ERROR RETURN
	LOAD.	T2,ED.211,(F)	;GET POINTER TO TO-11 AREA
	LOAD.	T2,EC.PRT,(T2)	;GET PROTOCOL TYPE
	CAIE	T2,.MMCB	;RUNNING MCB PROTOCOL?
	POPJ	P,		; CAN'T QUEUE IT, GIVE ERROR RETURN

	DTEOFF			;TURN OFF INTERRUPTS WHILE QUEUING

	LOAD.	T1,ED.2ES,(F)	;GET THE TO-11 STATUS OF DTE
	CAIE	T1,ED.EID	;ARE WE BUSY?
	JRST	DTEQM3		; YES, JUST QUEUE UP THIS ONE
	PUSHJ	P,DTESMM	;SEND THE MESSAGE BLOCK
	DTEON			;TURN DTESER BACK ON
	JRST	CPOPJ1##	;AND GIVE SUCCESSFUL RETURN

DTEQM3:	SETZM	MB.NXT(P3)	;ZAPP NEXT MB POINTER IN CURRENT MB
	LOAD.	T1,ED.LST,(F)	;GET ADDRESS OF LAST QUEUED MB
	MOVEM	P3,MB.NXT(T1)	;MAKE US BE NEXT FOR THE PREVIOUS ENTRY
	STOR.	P3,ED.LST,(F)	;MAKE US BE THE NEW LAST
	DTEON			;TURN INTERRUPTS BACK ON
	PJRST	CPOPJ1##	;RETURN SUCCESS
;HERE TO INITIATE A SEND FOR QUEUED PROTOCOL VERSION 2.
;THIS ROUTINE WILL ALSO DECLARE THE DTE AS BEING BUSY

DTESMM:	STOR.	P3,ED.CUR,(F)	;STORE CUR PTR TO MESSAGE BLOCK FOR TO-11
				; DONE PROCESSING

	MOVE	T1,P3		;SET UP T1 TO POINT TO MESSAGE BLOCK
	SNCALL	(DNLENG##,MS.HGH) ;GET THE TOTAL LENGTH OF MESSAGE

	LOAD.	T4,ED.211,(F)	;POINT TO TO-11 SECTION
	STOR.	T1,EC.PSZ,(T4)	;STORE THE TOTAL COUNT IN PSIZE AND CSIZE
	STOR.	T1,EC.CSZ,(T4)	; SINCE WE DON'T BREAK UP XFERS

	MOVEI	T1,.TMBYT	;MAKE SURE THAT BYTE MODE TRANSFERS ARE DONE
	STOR.	T1,EC.TMD,(T4)	; BY SETTING IT IN TO-11 SECTION

	LOAD.	U,ED.OBK,(F)	;GET ADDRESS TO STUFF DATA IN
	PUSHJ	P,DTEQCM	;COPY DATA FROM POSSILBY EXTENDED SECTION
				;DTEQCM RETURNS BYTE PTR TO DATA IN U
	MOVEM	U,@ETDEBP(F)	;STORE THE BYTE POINTER IN EPT

	LOAD.	T4,ED.211,(F)	;POINT TO THE TO-11 SECTION
	LOAD.	T1,EC.QCT,(T4)	;GET QCOUNT
	AOJ	T1,		;INCREMENT, LET IT OVERFLOW
	STOR.	T1,EC.QCT,(T4)	;TRUNCATE AND PUT IT BACK

	MOVEI	T1,ED.EDB	;MAKE NEW STATE BE BUSY
	STOR.	T1,ED.2ES,(F)	;STORE IT
	MOVEI	T1,TO11DB	;SET UP TO RING 11 DOORBELL
	XCT	ETDCNO(F)	;RING
	POPJ	P,		;RETURN TO SENDER
;HERE WITH A TO11 DONE FOR MCB
; T4 IS SET UP WITH CURRENT MESSAGE BLOCK POINTER

DTEEDM:	LOAD.	T1,ED.2ES,(F)	;GET TO-11 STATE
	JRST	@.+1(T1)	;ED.2ES HAD BETTER BE 2 BITS WIDE
	CPOPJ			; ED.EID - FREE TO-11 DONE, JUST IGNORE
	DTEED2			; ED.EDB - WAITING FOR DIRECT XFER
	.+2			; ED.EIB - WE DON'T USE THIS STATE
	.+1			; NOBODY USES THIS STATE!
	STOPCD	DTERLD,DEBUG,DTEI1S ;++ILLEGAL TO-11 DONE STATE FOR QP2

DTEED2:	MOVEI	T1,ED.EID	;SET STATE TO IDLE, 'CAUSE WE REALLY ARE IDLE!
	STOR.	T1,ED.2ES,(F)	; IF DTESMM IS CALLED, IT WILL FIX STATE TO
				; REFLECT NON-IDLENESS

	SE1ENT			;RUN IN SECTION ONE
	SETZ	T1,		;GET A ZERO
	STOR.	T1,ED.CUR,(F)	;CLEAR CURRENT MB ENTRY

;HERE TO SEE IF THERE IS ANYTHING ON THE OUTPUT QUEUE TO TRANSFER.  WHEN
;THERE IS NOTHING LEFT, WE DECLARE THE DTE IDLE.

	LOAD.	T1,ED.QUE,(F)	;GET NEXT QUEUE ENTRY
	JUMPE	T1,DTENM1	;JUMP IF NO MORE TO DO

	MOVE	T2,MB.NXT(T1)	;GET THE NEXT ENTRY ON QUEUE
	STOR.	T2,ED.QUE,(F)	;MAKE HIM FIRST
	MOVEI	T3,ETDQUE-MB.NXT(F) ;IN CASE QUEUE IS EMPTY
	SKIPN	T2		;AND IF QUEUE IS NOW EMPTY
	 STOR.	 T3,ED.LST,(F)	; MAKE TAIL POINT TO BEGINNING

	PUSH	P,T4		;SAVE PTR TO FINISHED MB
	PUSH	P,P3		;SAVE P3 FOR USE WITH SMM
	MOVE	P3,T1		;SET UP MESSAGE BLOCK POINTER
	PUSHJ	P,DTESMM	;INITIATE TRANSFER OF MESSAGE BLOCK
	POP	P,P3		;RESTORE P3
	POP	P,T4		;RESTORE PTR TO FINISHED MB

;HERE WHEN WE JUST HAVE TO RETURN THE COMPLETED MESSAGE
DTENM1:	MOVEI	T1,DI.ODN	;GET "OUTPUT DONE" KONTROLLER FUNCT
	MOVE	T3,T4		;GET MB POINTER INTO CORRECT AC
	PJRST	CALUSR		;CALL DTE USER AND RETURN
;The following returns are only used for the non-gather read version of
;DTESER.  Eventually, when FTSEG is turned on (when the MCB supports
;it), this copying will be done by the DTE hardware.  A side effect of
;this copy is that we do not have to play with the page table to map
;extended section message blocks into section zero for DTE transfer.
;
;Here to copy the extended message block into somewhere in section zero.
;
;DTEQCM is used only for DECNET transfers.
;
;Call:	P3/ Full-word pointer to message block in extended section
;	U/  0,,pointer to DTE buffer in section 0/1
;Return:
;	U/  Byte pointer to beginning of data in DTE buffer

	T5==T4+1		;(W) NEED T5 & T6 FOR EXTEND INSTRs
	T6==T5+1		;(M) BYTE PTR (MD.AUX) USES THIS INDEX

DTEQCM:	PUSHJ	P,SAVE1##	;SAVE P1
	PUSH	P,T5		;WE NEED SIX
	PUSH	P,T6		; TEMP ACS FOR MOVSLJ

	SETZ	T4,		;WE'LL COLLECT BYTE COUNT HERE
	SKIPN	T5,MB.FMS(P3)	;GET PTR TO FIRST MSD
	  STOPCD .,STOP,DTENOD,	;++NO DATA
DTQCM0:	SKIPN	T3,MD.NXT(T5)	;REMEMBER ADDR OF LAST MSD IN T5
	  JRST	DTQCM1		;DON'T INCLUDE LAST MSD IN CHAIN
	ADD	T4,MD.BYT(T5)	;COUNT THIS MSD'S DATA
	MOVE	T5,T3		;MOVE TO NEXT MSD
	JRST	DTQCM0		;THERE IS A NEXT MSD, GO COUNT IT

DTQCM1:	MOVE	T6,MD.AUX(T5)	;INDEXED 8-BIT BYTE PTR TO BEG OF SOURCE
	TLNN	T6,700000	;IS IT 0410T6,,xxx?
	  ADD	T6,[400000,,1]	;YES, IT REALLY POINTS TO NEXT WORD
	HRRZ	T2,T6		;ISOLATE OFFSET FROM RH OF BYTE PTR
	ADD	T2,MD.ALA(T5)	; WHICH WAS INDEXED BY T6=MD.ALA
	MOVEI	T1,3(T4)	;GET BYTES BEFORE THIS MSD, ROUNDED UP
	ASH	T1,-2		;CALCULATE WORDS FOR ALL BUT LAST MSD
	XMOVEI	T3,(U)		;CALC SECTION 1 DEST PTR FOR XBLT
	ADD	T3,T1		;OFFSET TO ALLOW FOR HDRS LATER
	HRR	T6,T3		;SAVE LOCAL BYTE PTR TO BEG OF DEST
	MOVE	T1,MD.BYT(T5)	;GET COUNT OF BYTES IN MSD WE'RE COPYING
	ADDI	T1,3+3		;ROUND UP TO ALLOW FOR MISALIGNED BYTES
	ASH	T1,-2		;CALC # OF WORDS TO COPY
	EXTEND	T1,[XBLT]	;COPY FROM LAST MSD TO (U) IN SEC 1

	TLZ	T6,17		;GET RID OF INDEX FIELD IN LOCAL BYTE PTR
	MOVN	T5,T4		;NEGATE COUNT OF BYTES BEFORE BLT'D DATA
	ADJBP	T5,T6		;LOCAL BYTE PTR TO START OF MSG
	MOVE	U,T5		;RETURN LOCAL BYTE PTR TO CALLER
	TLO	T5,P1		;MOVSLJ NEEDS GLOBAL BPT IN T5
	MOVSI	P1,1		;MAKE P1 INDEX BPT IN T5 TO SECTION 1

	MOVE	T3,MB.FMS(P3)	;PICK UP PTR TO FIRST MSD
DTQCM2:	SKIPN	MD.NXT(T3)	;IS THIS THE LAST MSD?
	  JRST	DTQCM3		;YES, ALREADY BLT'D, DON'T MOVSLJ IT
	MOVE	T1,MD.BYT(T3)	;LENGTH OF DATA IN THIS MSD
	MOVE	T2,MD.AUX(T3)	;BYTE PTR TO BEG OF DATA
	MOVE	T6,MD.ALA(T3)	;BYTE PTR IN T2 IS INDEXED BY T6
	MOVE	T4,T1		;COPY SOURCE LENGTH TO DEST LENGTH
	EXTEND	T1,[MOVSLJ]	;COPY SECTION 3 DATA TO SECTION 1(0)
	  STOPCD .,STOP,DTECDF,	;++ COPY DATA FAILED
	SKIPN	T3,MD.NXT(T3)	;GET PTR TO NEXT MSD IN CHAIN
	  STOPCD .,STOP,DTENFP,	;++ NO FORWARD POINTER IN MSD
	JRST	DTQCM2		;GO COPY NEXT IF ITS NOT LAST

DTQCM3:	POP	P,T6		;RESTORE
	POP	P,T5		; ACS, AND
	POPJ	P,		; RETURN TO SENDER
;DTE2CM WILL COPY A MESSAGE FROM A SECTION ZERO, NON-SEGMENTED MESSAGE
;INTO A POSSIBLY EXTENDED SECTION MESSAGE BLOCK.

;CALLED WITH T1 POINTING TO SOURCE BLOCK AND T2 POINTING TO THE
;MESSAGE BLOCK.

DTE2CM:	PUSHJ	P,SAVE2##	;SAVE SOME PEAS
	DMOVE	P1,T1		;SAVE THE ARGUMENTS
	XMOVEI	T2,UD.MSD(P2)	;POINT TO THE USER DATA MSD
	MOVE	T3,MD.BYT(T2)	;GET LENGTH OF THE WHOLE MESSAGE
	ADDI	T3,3		;CONVERT TO
	LSH	T3,-2		; WORDS (ROUNDING UP)
	MOVE	T2,MD.ALA(T2)	;SET UP PTR TO POSSIBLY EXTENDED DEST BLK
	MOVE	T1,P1		;SET UP PTR TO SOURCE FOR DNCPYW
	SNCALL	(DNCPYW##,MS.HGH) ;COPY THE WORDS
	POPJ	P,		;AND RETURN
SUBTTL DTE20 INTERRUPT SERVICE

;HERE WITH ETD (DTE CONTROL BLOCK) ADDRESS IN F

DTEINT::MOVE	T1,ETDSTS(F)	;GET FLAGS INTO T1
	TXNE	T1,ED.PPC	;IS PRIMARY PROTOCOL RUNNING??
	JRST	DTEINN		; YES, GO HANDLE NORMAL INTERRUPT
	TXNE	T1,ED.SPC	;SECONDARY PROTOCOL??
	PJRST	SPCINT		; YES, DO SECONDARY PROTOCOL INTERRUPT
	TXNE	T1,ED.MAI	;ARE WE IN MAINTENANCE MODE?
	JRST	DTEMAI		; YES, GO DO SPECIAL STUFF
	TXNN	T1,ED.IPU	;DO WE WANT TO INDICATE PROTOCOL UP?
	JRST	DTICLR		; NO, JUST CLEAR DTE AND DISMISS
	PUSHJ	P,PPUINT	;YES, GIVE THE PROTOCOL UP INTERRUPT
				; TO THE USER OF THE LINE AND PROCESS NORMALLY

DTEINN:	XCT	ETDCNI(F)	;CONI DTEN,T1
	LOAD.	T4,ED.210,(F)	;YES, GET TO-10 SECTION OF 11'S AREA
	MOVE	T4,ETCSTS(T4)	;GET STATUS WORD FROM TO-10 SECTION
	TRNE	T1,DEAD11	;11 POWER FAIL?
	JRST	PWRF11		;YES
	TRNE	T1,TO11ER!TO10ER;IF EITHER A TO 10 OR A TO 11 ERROR
	PJSP	T1,DTERLD	; THEN RELOAD IT
	TRNE	T1,TO10DN	;TO-10 DONE? MUST CHECK BEFORE TO10DB
	JRST	DTE2XD		; SO WE FINISH MESSAGE BEFORE STARTING NEXT
	TRNE	T1,TO10DB	;TO-10 DOORBELL?
	JRST	DTERNG
	TRNE	T1,TO11DN	;TO-11 DONE?
	JRST	DTE2ED		;YES

;HERE WHEN WE CAN'T DETERMINE CAUSE OF INTERRUPT

DTICLR:	MOVEI	T1,CLRDTE	;CLEAR OUT DTE
	XCT	ETDCNO(F)	;ZAP
	POPJ	P,		;FREE INTERRUPT, DISMISS


PWRF11:	MOVEI	T1,PILDEN+0	;CLEAR PI ASSIGNMENT, SINCE A DEAD
				; -11 ON A DTE KEEPS SETTING THE BIT
	XCT	ETDCNO(F)	;ZAP
	JRST	DTICLR		;GO CLEAR OUT DTE AND RETURN
	SUBTTL	QUEUED PROTOCOL VERSION 1 DRIVERS - RECEIVER

;HERE ON TO-10 DOORBELL, ETD ADDRESS IN F, STATUS IN T4
;BOTH QP1 & QP2 COME HERE INITIALLY, QP2 BRANCHES OFF IN A MOMENT

DTERNG:	MOVEI	T1,CL11PT	;CLEAR DOORBELL
	XCT	ETDCNO(F)	;CONO DTEN,(T1)
	TLNE	T4,(EC.LOD)	;11 WANTS TO BE RELOADED?
	PJSP	T1,DTERLD	;RELOAD THE DTE
	LOAD.	T3,ED.210,(F)	;GET 11'S TO-10 ADDRESS
	LOAD.	T1,EC.PRT,(T3)	;GET PROTOCOL TYPE
	CAIN	T1,.MMCB	;ARE WE RUNNING QP2???
	JRST	DTERNM		; YES, GO DO THINGS DIFFERENTLY
	TRNE	T4,EC.IND	;IS THIS AN INDIRECT (OLD STYLE) MSG
	JRST	DTEIND		;YES, BETTER GO PROCESS IT
	LOAD.	T3,ED.211,(F)	;TO-11 SECTION OF 10'S AREA
	LOAD.	T2,EC.10C,(T3)	;GET LAST TO11IC COUNT
	LOAD.	T1,EC.10C,-ETCSTS+T4;GET THIS TO10IC COUNT FROM T4
	CAMN	T1,T2		;CHANGED?
	POPJ	P,		;NO, FREE DOORBELL. IGNORE.
	AOS	T2		;INCREMENT OLD COUNT
	ANDI	T2,377		; (MAY WRAP AROUND)
	CAME	T1,T2		;IS NEW COUNT 1 GREATER THAN OLD?
	PJSP	T1,DTERLD	;NO, SOMETHING'S WRONG
	MOVEI	T2,EC.2IT	;OK, SET TO-IT BIT BEFORE ACTUALLY
				; INCREMENTING QUEUE COUNT SO THAT
				; THE 11 CAN CHECK FOR LOST TO-10
				; DONE INTERRUPTS
	IORM	T2,ETCSTS(T3)	;SET THE BIT
	STOR.	T1,EC.10C,(T3)	;REMEMBER VALUE OF THIS TO10IC IN
				; TO-11 SECTION OF 10 COMM AREA
				;NO, MUST BE A DIRECT PACKET . . .

;HERE IF TO-10 TRANSFER IS DIRECT (MAY BE DIRECT PART OF INDIRECT MESSAGE)

	LOAD.	T1,ED.2TS,(F)	;GET TO-10 DTE STATE CODE
	CAIE	T1,ED.TID	;BETTER BE IDLE
	STOPCD	.,STOP,DTETNI,DTEPDI, ;++DTE NOT IDLE
	MOVEI	T1,ED.TDB	;MAKE TO-10 BUSY WITH DIRECT XFER
	STOR.	T1,ED.2TS,(F)	;PUT INTO DTE CONTROL BLOCK
	LOAD.	T4,ED.210,(F)	;GET ADDRESS OF TO-10 SECTION
	LOAD.	T2,EC.QSZ,(T4)	;GET QSIZE THAT 11 SET UP
	MOVEM	T2,ETDPKC(F)	;SAVE FOR CHECKING AT TO-10 DONE TIME
	PUSHJ	P,T10GTC	;ALLOCATE TO-10 BUFFER, RETURN ADDRESS IN T1
	STOPCD	.,STOP,DTENFC,DTEPDI, ;++NO FREE CORE
	HRLI	T1,(POINT 8,)	;MAKE INTO BYTE POINTER
	MOVEM	T1,@ETDTBP(F)	;PUT INTO EPT
	LOAD.	T3,ED.BSZ,(F)	;GET LENGTH OF THIS DTE'S BUFFER
	IMULI	T3,^D36/^D8	;IN EIGHT BIT BYTES
	MOVE	T1,ETDPKC(F)	;GET WHAT QSIZE SAID AGAIN
	CAMLE	T1,T3		;MAKE SURE QSIZE IS NOT GREATER
				; THAN THE BUFFER LENGTH
	STOPCD	.,STOP,DTEPTL,DTEPDI, ;++PACKET TOO LARGE
	MOVNS	T1		;GET NEGATIVE BYTE COUNT
	ANDI	T1,TO10BC	;JUST THE COUNT BITS FOR DATAO
	TRO	T1,TO10IB	;TAKING THE WHOLE PACKET AT ONCE,
				; SO INTERRUPT 11 WHEN XFER IS DONE
	XCT	ETDDTO(F)	;DATAO DTEN,T1
	POPJ	P,		;DONE
;HERE IF TO-10 PACKET IS THE INDIRECT PART OF AN INDIRECT MESSAGE

DTEIND:	LOAD.	T1,ED.2TS,(F)	;GET TO-10 DTE STATE
	CAIE	T1,ED.TWD	;WE SHOULD BE EXPECTING THIS DOORBELL
	PJSP	T1,DTERLD	;-11 IS CONFUSED
	MOVEI	T1,ED.TIB	;NOW WE'RE WAITING FOR TO-10 DONE
	STOR.	T1,ED.2TS,(F)	;FOR AN INDIRECT TRANSFER.
	LOAD.	T2,ED.211,(F)	;GET TO-11 SECTION ADDRESS
	MOVEI	T1,EC.2IT	;SET TO-10 XFER IN PROGRESS BIT FOR 11
	IORM	T1,ETCSTS(T2)	;POLLER.
	LOAD.	T4,ED.210,(F)	;TO-10 SECTION ADDRESS
	LOAD.	T2,EC.QSZ,(T4)	;NUMBER OF BYTES IN INDIRECT MESSAGE
	LOAD.	T1,ED.IBK,(F)	;GET COUNT SENT IN DIRECT PART OF THIS MESSAGE
	CAME	T1,T2		;MAKE SURE IT MATCHES QSIZE
	PJSP	T1,DTERLD	;IT DOESNT
				;IT DOES, LEAVE BYTES LEFT AT FULL COUNT
	LOAD.	T1,ED.ICT,(F)	;GET NUMBER OF BYTES DRIVER WANTS
	PJRST	DTEINX		;GO START FIRST INDIRECT FRAGMENT
				;C(T1)=# 8 BIT BYTES WANTED,
				; C(T2)=# BYTES LEFT (FULL COUNT NOW)
				; FOR DTEINX
;HERE ON TO-10 DONE INTERRUPT

DTE2XD:	MOVEI	T1,CLTO10	;GET READY TO CLEAR TO-10 DONE
	XCT	ETDCNO(F)	;CONO DTEN,(T1)
	LOAD.	T1,ED.2TS,(F)	;GET TO-10 DTE STATE
	LOAD.	T2,ED.210,(F)	;GET PTR TO TO10 AREA
	LOAD.	T2,EC.PRT,(T2)	;GET THE CURRENT PROTOCOL
	CAIN	T2,.MMCB	;ARE WE RUNNING 20F?
	JRST	DTE2XM		; DONE INTERRUPT FOR QP2
	CAIN	T1,ED.TDB	;EXPECTING TO-10 DONE FOR DIRECT XFER?
	JRST	DTE2X0		;YES, GO PROCESS IT
	CAIN	T1,ED.TIB	;NO, MAYBE INDIRECT?
	JRST	DTEXDI		;YES, GO HANDLE THAT
	PJSP	T1,DTERLD	;-11 IS CONFUSED

DTE2X0:	LOAD.	T4,ED.211,(F)	;GET TO-11 SECTION
	MOVEI	T1,EC.2IT	;CLEAR TO-10 XFER IN PROGRESS BIT
	ANDCAM	T1,ETCSTS(T4)	;FOR THE 11 POLLER
	LOAD.	T4,ED.BUF,(F)	;ADDRESS OF THE TO-10 DATA
	HRLI	T4,(POINT 8,)	;MAKE INTO BYTE POINTER
	STOR.	T4,ED.MSP,(F)	;THIS IS POINTER FOR CURRENT MESSAGE
	STOR.	T4,ED.NMP,(F)	;THIS LOC CONTAINS POINTER FOR NEXT MESSAGE IN PACKET

;THIS IS LOOP FOR EACH MESSAGE. T4 HAS BYTE POINTER TO NEXT MESSAGE

DTE2X1:	LOAD.	P1,ED.DTN,(F)	;SET RH(P1) TO BE DTE NUMBER
	HRL	P1,.CPCPN##	;CPU NUMBER
	PUSHJ	P,GX2BYT	;BYTES IN HEADER COME SWAPPED, SO
				; CALL GX2BYT FOR COUNT
	TRNN	T1,1B35		;IS COUNT ODD
	CAMLE	T1,ETDPKC(F)	;OR IS 11 LIEING ABOUT SIZE OF THIS MESSAGE?
	PJSP	T1,DTERLD	;COUNT NOT EVEN OR BAD SIZE
				; (INDIVIDUAL MESSAGE SIZE CANNOT
				; EXCEED SIZE OF ENTIRE PACKET)
	MOVN	T2,T1		;GET MINUS COUNT IN T2
	ADDB	T2,ETDPKC(F)	;PKC HAS COUNT LEFT
	MOVE	T2,T1		;GET COUNT IN T2 AGAIN
	ADJBP	T2,ETDNMP(F)	;T4 HAS CURRENT MESSAGE POINTER,
				; T2 GETS NEXT MESSAGE POINTER
	STOR.	T2,ED.NMP,(F)	;SAVE
	SUBI	T1,.EMHBL	;ACCOUNT FOR LENGTH OF HEADER UP TO
				; BUT NOT INCLUDING FIRST WORD
	SKIPGE	T1		;COUNT TOO SMALL??
	PJSP	T1,DTERLD	;YES
	MOVE	U,T1		;FROM NOW ON, U HAS COUNT FOR CURRENT MESSAGE
	PUSHJ	P,GX2BYT	;16 BIT FUNCTION BYTE
	HRRZ	P2,T1		;RH(P2) ALWAYS HAS FUNCTION CODE
	PUSHJ	P,GX2BYT	;16 BIT DEVICE CODE
	HRL	P2,T1		;LH(P2) ALWAYS GETS DEVICE CODE
	PUSHJ	P,GX2BYT	;EAT UP SPARE. NOW WE'VE TAKEN .EMHBL BYTES
	PUSH	P,T4		;SAVE BYTE POINTER
	PUSHJ	P,GT2XFT	;GET TO-10 FUNCTION TYPE IN T1
	  PJSP	T1,[POP P,T4
		JRST DTERLD]
	POP	P,T4		;RESTORE BYTE POINTER

DTE2X2:	PUSHJ	P,@D2XTAB(T1)	;CALL FUNCTION DEPENDENT ROUTINE
				; TO SETUP P3,P4
	PUSH	P,U		;SAVE U AROUND CALL TO FUNCTION ROUTINE
	PUSH	P,F		;SAVE ETD ADDRESS
	PUSHJ	P,DODSP		;DO A PJRST TO CORRECT DRIVER ROUTINE
	POP	P,F		;RESTORE ETD
	POP	P,U		;GET U BACK AGAIN
	TRNE	P2,EM.IND	;WAS THE MESSAGE JUST RECEIVED THE
				; DIRECT PART OF AN INDIRECT MESSAGE?
	JRST	DTE2X3		;YES, THIS IS DIRECT PART OF INDIRECT
	SKIPG	ETDPKC(F)	;ANYTHING LEFT?
	JRST	DTETID		;NO, MAKE DTE IDLE NOW

	LOAD.	T4,ED.NMP,(F)	;NO, GET OLD NEXT MESSAGE POINTER
	JRST	DTE2X1		;GO DO NEXT MESSAGE
; HERE ON DIRECT PART OF INDIRECT MESSAGE

DTE2X3:	HLRZ	T1,S		;ITS EITHER THIS OR DONT USE STOR. IN NEXT INSTRUCTION
	STOR.	T1,ED.IPS,(F)	;SAVE INITIAL ADDRESS TO TRANSFER
				; TO AFTER FIRST FRAGMENT OF INDIRECT
				; MESSAGE COMES
	MOVEI	T1,ED.TWD	;WAITING FOR TO-10 DOORBELL TO SIGNAL START OF
	STOR.	T1,ED.2TS,(F)	;TO-10 INDIRECT PACKET XFER
	STOR.	P3,ED.ICT,(F)	;SAVE INITIAL BYTE COUNT (8 BIT BYTES)
	MOVEM	P4,@ETDTBP(F)	;PUT BYTE POINTER IN EPT NOW
	STOR.	P4,ED.MSP,(F)	;REMEMBER ORIGINAL POINTER TO PASS
				; BACK TO DRIVER ON TO-10 DONE FOR
				; INDIRECT PACKET
	SKIPE	ETDPKC(F)	;ANY MORE MESSAGES LEFT IN PACKET?
	PJSP	T1,DTERLD	;NO, 11 MUST HAVE LIED
	POPJ	P,		;RETURN, AWAITING DOORBELL
;HERE WHEN RECEIVE DONE INTERRUPT WHILE WAITING FOR INDIRECT PART OF INDIRECT
;MESSAGE

DTEXDI:	LOAD.	T1,ED.2TS,(F)	;GET TO-10 DTE STATE
	CAIE	T1,ED.TIB	;WERE WE EXPECTING TO-10 DONE FOR INDIRECT?
	STOPCD	.,STOP,DTENIS,DTEPDI, ;++DTE IN WRONG STATE
				;YES, LEAVE IN THAT STATE UNTIL ALL
				; INDIRECT FRAGMENTS HAVE BEEN
				; RECEIVED BY THE 10
	LOAD.	T2,ED.IPS,(F)	;GET TO-10 INDIRECT POST ADDRESS
	SKIPN	T2		;BETTER BE ONE
	STOPCD	.,STOP,DTEIPA,DTEPDI, ;++NO POST ADDRESS
	LOAD.	P1,ED.DTN,(F)	;GET DTE NUMBER IN P1
	HRL	P1,.CPCPN##	;CPU NUMBER TO THE LEFT HALF
	LOAD.	P2,ED.XFN,(F)	;TO-10 FUNCTION
	LOAD.	T1,ED.XDV,(F)	;DEVICE THAT WAS SENT
	HRL	P2,T1		;GOES IN LH(P2)
	LOAD.	P3,ED.IBK,(F)	;GET NUMBER OF BYTES NOW AVAILABLE TO
				; DRIVER
	LOAD.	T1,ED.XLN,(F)	;TO-10 LINE
	HRL	P3,T1		;LINE,,8 BIT BYTES LEFT IN P3
	LOAD.	P4,ED.MSP,(F)	;GET ORIGINAL POINTER FOR CORE DEALLOCATION
	PUSH	P,F		;SAVE ETD ADDRESS
	PUSHJ	P,(T2)		;CALL DRIVER TO SAY INDIRECT FRAGMENT DONE
	POP	P,F		;RESTORE ETD ADDRESS
	TRNN	P3,-1		;IF DESIRED NEW COUNT = 0,
	JRST	DTEXD1		; MAKE SURE DRIVER ISNT EXPECTING ANY MORE
	HLRZ	T1,S		;GET POST ADDRESS FROM STANDARD AC
	STOR.	T1,ED.IPS,(F)	;NEW TO-10 INDIRECT POST ADDRESS
	LOAD.	T2,ED.IBK,(F)	;GET NUMBER OF BYTES LEFT IN T2
	HRRZ	T1,P3		;GET COUNT DRIVER WANTS IN T1
	MOVEM	P4,@ETDTBP(F)	;STORE NEW POINTER
	STOR.	P4,ED.MSP,(F)	;ALSO STORE IN ETD SO NEXT CALL TO DRIVER
				; CAN PASS THIS POINTER BACK

;HERE AFTER INITIAL TO-10 DOORBELL SIGNALLING THE START OF INDIRECT
; FRAGMENT TRANSFER. T1 HAS CURRENT DESIRED COUNT, T2 HAS NUMBER
; OF BYTES LEFT IN PACKET BEFORE NEXT TRANSFER STARTS.

DTEINX:	SUB	T2,T1		;GET NEW NUMBER OF BYTES LEFT IN PACKET IN T2
	STOR.	T2,ED.IBK,(F)	;SAVE FOR NEXT TIME
	SKIPGE	T2		;DRIVER EATING TOO MUCH?
	STOPCD	.,STOP,DTEARD,DTEPDI, ;++RUNAWAY DRIVER
	LOAD.	T3,ED.210,(F)	;GET TO-10 SECTION ADDRESS
	MOVE	T3,ETCSTS(T3)	;GET TO-10 STATUS WORD FROM IT
	TLNE	T3,(EC.16B)	;IS THIS INDIRECT DATA 16 BITS?
	ASH	T1,-1		;YES, TURN 8 BIT COUNT INTO 16 BIT COUNT
	MOVNS	T1		;SETUP MINUS BYTE COUNT
	ANDI	T1,TO10BC	;JUST THESE BITS
	SKIPG	T2		;TAKING IT ALL?
	TRO	T1,TO10IB	;YES, INTERRUPT 11 AFTER THIS XFER
	XCT	ETDDTO(F)	;DATAO DTEN,(T1)
	POPJ	P,		;TRANSFER IS GOING NOW.
;HERE IF DRIVER DOESNT WANT ANYMORE INDIRECT DATA

DTEXD1:	LOAD.	T1,ED.IBK,(F)	;GET NUMBER OF BYTES LEFT IN PACKET
	SKIPE	T1		;SKIP IF DRIVER HAS TAKEN ENOUGH
	STOPCD	.,STOP,DTEDNH,DTEPDI, ;++DRIVER NOT HUNGRY
	LOAD.	T2,ED.211,(F)	;GET TO-11 SECTION
	MOVEI	T1,EC.2IT	;CLEAR TO-10 XFER IN PROGRESS AFTER LAST FRAG
	ANDCAM	T1,ETCSTS(T2)	;FROM 1 TO ZERO

;HERE TO PUT TO-10 SIDE OF DTE IDLE
; RELEASE THE TO-10 BUFFER IF ITS THERE.

DTETID:	MOVEI	T1,ED.TID	;MARK TO-10 DTE AS IDLE
	STOR.	T1,ED.2TS,(F)	;ZAP
	PJRST	T10RLC		;RELEASE TO-10 BUFFER AND RETURN
	SUBTTL	QUEUED PROTOCOL VERSION 2 DRIVERS - RECEIVER

;HERE TO HANDLE DOORBELL FOR QP2

; **** NOTE WELL ****  !PROTOCOL VIOLATION!
;
; IN THE FOLLOWING CODE, THE CPQCNT FIELD IS USED EXCLUSIVLY WHEN DEALING WITH
; A TO-10 TRANSFER.  THIS MEANS THAT WE INSPECT CPQCNT (EC.CPQ) FROM THE TO-10
; AREA, AND (AFTER VERIFICATION) COPY IT INTO CPQCNT IN THE TO-11 AREA.  NOTE
; THAT THESE BYTES ARE BEING HANDLED IDENTICALLY TO THE QP1 DOORBELL PROCEDURE.

DTERNM:	TXNE	T4,EC.INI	;DOES HE WANT TO INITIALIZE PROTOCOL???
	PJSP	T1,DTERLD	; YES, LET UUO LEVEL TAKE CARE OF THAT
	LOAD.	T3,ED.211,(F)	;GET ADDRESS OF TO-11 AREA
	LOAD.	T1,EC.CPQ,-ETCSTS+T4 ;GET HIS QCOUNT
	LOAD.	T2,EC.CPQ,(T3)	;AND MY COPY OF HIS QCOUNT (CPQCNT)
	CAMN	T1,T2		;ARE THEY DIFFERENT???
	POPJ	P,		; NO, FREE DOORBELL, IGNORE
	AOJ	T2,		;INCREMENT MY COPY (CPQCNT)
	ANDI	T2,377		;REDUCE IT TO 8 BITS (FOR WRAPAROUND)
	CAME	T1,T2		;DID WE DIFFER BY EXACTLY ONE??
	PJSP	T1,DTERLD	; NOPE, I BET HE WENT CRAZY
	MOVEI	T1,EC.RCV	;YES. GET TO-11 RECEIVE BIT
	IORM	T1,ETCSTS(T3)	;LET -11 KNOW THAT I RECEIVED HIS DOORBELL
	STOR.	T2,EC.CPQ,(T3)	;SAVE THE LATEST COPY OF HIS QCOUNT

	LOAD.	T4,ED.210,(F)	;GET TO-10 ADDRESS
	LOAD.	T1,EC.TMD,(T4)	;GET TRANSFER MODE FROM TO-10 BLOCK
	SKIPE	T1		;IS IT BYTE MODE?  (ONLY ONE WE SUPPORT)
	 STOPCD	 .+1,DEBUG,DTEITM	;++ILLEGAL TO-10 TRANSFER MODE IN QP2

	LOAD.	T1,ED.2TS,(F)	;GET TO-10 TRANSFER STATE
	JRST	@.+1(T1)	;THIS TABLE ASSUMES ED.2TS IS A 2 BIT FIELD
	EXP	DTERN1		;ED.TID WE ARE IDLE, GET BUFFERS FOR A NEW XFER
	EXP	DTEBST		;ED.TDB, WAITING FOR XFER TO COMPLETE -- BAD
	EXP	DTERN2		;ED.TWD, WAITING FOR NEXT PART OF SCATTER READ
	EXP	DTEBST		;ED.TIB, WAITING FOR SCATTER READ XFER TO COMPLETE
DTEBST:	STOPCD	DTERLD,DEBUG,DTEITS ;++ILLEGAL TO-10 TRANSFER STATE
;HERE WHEN WE ARE STARTING A NEW XFER	(ED.2TS = ED.TID)

DTERN1:	SE1ENT			;RUN THIS IN SECTION ONE
	LOAD.	T3,EC.PSZ,(T4)	;GET THE WHOLE MESSAGE SIZE
	STOR.	T3,ED.RMN,(F)	;SAVE THIS STARTING COUNT

	SKIPN	T1,ETDMBP(F)	;GET THE MESSAGE BLOCK POINTER
	POPJ	P,		;NONE, PROBABLY BEING TURNED OFF

	XMOVEI	T2,UD.MSD(T1)	;LOAD POINTER TO USER DATA MSD
	MOVEM	T2,MB.FMS(T1)	;STORE POINTER TO FIRST MSD IN MSG
	MOVEM	T3,MD.BYT(T2)	;STORE XFER SIZE AS MSG BYTE COUNT

	LOAD.	T1,ED.IBK,(F)	;POINT TO BLOCK USED FOR INPUT
	HRLI	T1,(POINT 8,)	;FINISH UP THE BYTE POINTER
	MOVEM	T1,@ETDTBP(F)	;PUT IT IN TABLE

; HERE FOR EACH SEGMENT OF A SCATTER WRITE (INBOUND) TRANSFER

DTERN2:	LOAD.	T1,EC.PSZ,(T4)	;GET MESSAGE SIZE
	LOAD.	T2,EC.CSZ,(T4)	;GET SIZE OF THIS TRANSFER, WHICH COULD BE
				; DIFFERENT FROM MESSAGE SIZE IF SENDER IS
				; DOING A SCATTER WRITE
	CAMLE	T2,T1		;REASONABLE TRANSFER?
	 STOPCD	 DTERLD,DEBUG,DTEBTC ;++BAD TRANSFER COUNT(S)
	MOVEI	T3,ED.TDB	;ASSUME WAITING FOR LAST XFER
	CAME	T2,T1		;CSIZE AND PSIZE EQUAL???
	MOVEI	T3,ED.TIB	; NO, TELL DONE INTERRUPT NOT TO CALL KONTROLLER
	STOR.	T3,ED.2TS,(F)	;STORE THE NEW TO-10 STATUS

	MOVN	T1,T2		;GET THE NEGATIVE OF CSIZE
	ANDI	T1,TO10BC	;MASK OUT ALL BUT 12 BITS
	TRO	T1,TO10IB	;ALWAYS INTERRUPT 11
	XCT	ETDDTO(F)	;START THE TRANSFER
	POPJ	P,		;AND RETURN
;HERE WITH TO-10 DONE FOR QP2

DTE2XM:	LOAD.	T3,ED.211,(F)	;GET PTR TO MY -11 AREA
	MOVEI	T1,EC.RCV	;GET THE "RECEIVED DOORBELL" BIT
	ANDCAM	T1,ETCSTS(T3)	;TURN IT OFF, SO -11 KNOWS I GOT DONE INTERRUPT

	LOAD.	T1,ED.2TS,(F)	;GET TO-10 STATE
	JRST	@.+1(T1)	;THIS TABLE ASSUMES ED.2TS IS A 2 BIT FIELD
	EXP	DTEBS2		;ED.TID, WE ARE IDLE (AND WE JUST GOT A DONE INT!?!?)
	EXP	DTE2X4		;ED.TDB, WAITING FOR XFER TO COMPLETE
	EXP	DTEBS2		;ED.TWD, WAITING FOR NEXT PART OF SCATTER READ
	EXP	DTE2X5		;ED.TIB, WAITING FOR SCATTER READ XFER TO COMPLETE
DTEBS2:	PJSP	T1,DTERLD	;ILLEGAL, RELOAD THE DTE
;	STOPCD	DTERLD,DEBUG,DTEIDS ;++ILLEGAL TO-10 DONE STATE

; HERE WHEN WE ARE COMPLETELY DONE WITH A TO-10 TRANSFER.  TELL THE KNOTROLLER

DTE2X4:	SE1ENT			;RUN THIS IN SECTION ONE
	SKIPN	T2,ETDMBP(F)	;GET MESSAGE BLOCK POINTER
	JRST	DTE2X6		;NONE, DRIVER MUST BE SHUTTING US DOWN

	LOAD.	T1,ED.IBK,(F)	;POINT TO THE INPUT BLOCK
	PUSHJ	P,DTE2CM	;DO THE COPY
	MOVEI	T1,DI.INC	;INPUT COMPLETE IS TYPE
	MOVE	T3,ETDMBP(F)	;GET THE POINTER TO MESSAGE BLOCK
	SETZM	ETDMBP(F)	;CLEAR PREVIOUS MESSAGE ADDRESS
	PUSHJ	P,CALUSR	;CALL DTE USER MODULE
DTE2X6:	MOVEI	T1,ED.TID	;NOW SAY THAT
	STOR.	T1,ED.2TS,(F)	; DTE IS IDLE
	POPJ	P,		;RETURN

;HERE WHEN WE JUST RECEIVED PART OF A SCATTER TO-10 XFER.  JUST WAIT FOR NEXT
;DOORBELL

DTE2X5:	MOVEI	T1,ED.TWD	;WE ARE WAITING FOR DOORBELL FOR NEXT CHUNK
	STOR.	T1,ED.2TS,(F)	; DTE IS IDLE
	POPJ	P,		;RETURN
	SUBTTL	DTE20 INTERRUPT SERVICE

;ROUTINES TO DO DISPATCH FOR INCOMING TO-10 FUNCTIONS
; PJRSTS TO APPROPRIATE PLACE IN DEVICE DRIVER
; CALL WITH C(P2) = DEVICE,,FUNCTION
; DEVICE CODE IS RANGE CHECKED, AND A SPECIAL "EAT" DISPATCH
; TABLE, DESIGNED TO GRACEFULLY THROW AWAY MESSAGES, IS USED
; FOR UNKNOWN DEVICES.  THIS WAY, RSX20 CAN TALK ABOUT LINE
; PRINTERS AND WE WONT CARE.
; THIS IS A SEPARATE ROUTINE BECAUSE IT DOES SOME FOOLING AROUND
; LOOKING FOR SPECIAL DEVICES, AND CHECKING TO SEE IF THE FUNCTION
; IS LEGAL FOR ALL DEVICES, IN WHICH CASE A SEPARATE DISPATCH TABLE
; MUST BE USED.
; RETURN TO CALLER AFTER DISPATCH

DODSP:	PUSHJ	P,DSTDSP	;SETUP T1, T2 FOR DISPATCH
	PUSHJ	P,ISALL		;SKIP IF FN IS LEGAL FOR ALL DEVICES
	  PJRST	@DEVTAB(T2)	;DISPATCH ACCORDING TO FUNCTION, DEVICE
	PJRST	@ALLDSP(T1)	;THIS IS SPECIAL FUNCTION. IGNORE DEVICE FIELD.


;HERE TO DISPATCH ON A NEGATIVE (DTESER INTERNAL) FUNCTION
; CODE

DNDSP:	PUSH	P,T1		;SAVE THE CODE (18 BIT NEG)
	PUSHJ	P,DSTDSP	;SETUP T2 AS IDX INTO DEVTAB
	POP	P,T1		;RESTORE
	PJRST	@DEVTAB(T2)	;DISPATCH AND RETURN

;HERE TO DISPATCH FROM DEVTAB EVEN FOR GLOBAL FUNCTION CODES

DSDSP:	PUSHJ	P,DSTDSP	;SETUP T1,T2 FOR DISPATCH
	PJRST	@DEVTAB(T2)	;DISPATCH

;ENTER HERE WITH C(P2) = DEV,,FN
; EXIT WITH FUNCTION CODE IN T1, INDEX INTO DEVTAB IN T2.
; RETURN WITH C(T2) = 0 IF DEVICE IS UNKNOWN, CAUSING DISPATCH
; THROUGH DEVTAB TO USE EATDSP.

DSTDSP:	HRRZ	T1,P2		;GET FUNCTION FROM P2
	ANDI	T1,FNCMSK	;JUST THE NUMBER
	HLRZ	T2,P2		;GET DEVICE CODE
	CAIG	T2,MAXDEV	;OUT OF RANGE?
	POPJ	P,		;NO, RETURN
	MOVEI	T4,0		;YES, SEE IF ITS ONE OF THE SPECIALS
	MOVE	T3,T2		;SAVE ORIGINAL FUNCTION FOR CHECKING
DSTDS1:	SKIPN	T2,SPDVTB(T4)	;GET ENTRY IN TABLE
	POPJ	P,		;RETURN 0 (GUARANTEED TO BE EATDSP)
				; IF END OF TABLE
	CAME	T2,T3		;MATCH?
	AOJA	T4,DSTDS1	;NO, KEEP LOOKING
	MOVNI	T2,1(T4)	;GET NEGATIVE INDEX INTO DEVTAB

	POPJ	P,		;RETURN WITH T1, T2 SETUP
;TEMPORARILY DEFINED TO BE IGNORED . . .

	CLKDSP==EATDSP
	DL1DSP==EATDSP
	DH1DSP==EATDSP
	KLIDSP==EATDSP
	KLEDSP==EATDSP
	KLCDSP==EATDSP

;MASTER DISPATCH TABLES. FUNCTION CODE WILL BE IN T1.
; POSITIVE OFFSETS IN DEVTAB MUST AGREE WITH PROTOCOL DEVICE CODE
; DEFINITIONS (SEE DTEPRM).
; NEGATIVE OFFSETS TO DEVTAB MUST CORRESPOND TO POSITIVE ENTRIES
; IN SPDVTB, AND THEY INDICATE SPECIAL DEVICES.

	@KLIDSP(T1)		;GET KLINIK STATUS
	@KLEDSP(T1)		;GET FROM THE 11
	@KLCDSP(T1)		;KL CPU (WHY RELOAD)
DEVTAB:	@EATDSP(T1)		;GUARANTEED TO BE EATDSP
	@CT0DSP##(T1)		;CTY
	@DL1DSP(T1)		;DL11 #1
	@DH1DSP(T1)		;DH11
	@DLSDSP##(T1)		;DATA LINE SCANNER (DLS)
	@DLPDSP##(T1)		;LPT
	@FCRDSP##(T1)		;CDR
	@CLKDSP(T1)		;CLOCK
	@FEDDSP##(T1)		;FRONT END DEVICE
IFN FTNET,<
	@NCLDSP##(T1)		;NCL DEVICE (DN87S)
>
IFE FTNET,<
	@EATDSP(T1)
>
	@D6SDDS##(T1)		;DN60 DEVICE

	MAXDEV==.-DEVTAB-1	;MAXIMUM DEVICE NUMBER ALLOWED
IFN .EMMXD-MAXDEV,<PRINTX DEVTAB AND DTEPRM DO NOT AGREE>

;TABLE TO SEARCH FOR DEVICES OUT OF ORDER FROM ABOVE
; MUST BE IN REVERSE ORDER OF THE NEGATIVE ENTRIES IN DEVTAB

SPDVTB:	.EMCPU			;KL10 CPU (WHY RELOAD)
	.EMKLE			;KLERR
	.EMKLI			;KLINIK
	Z			;TABLE MUST END WITH A ZERO
;DISPATCH TABLE FOR FUNCTIONS THAT ARE LEGAL FOR ALL DEVICES
; NOTE NEGATIVE DISPATCH ENTRIES ARE NOT NEEDED, SINCE
; GENERIC FUNCTIONS DO NOT NEED THEM

ALLDSP:	DTEFNC			;(??) GENERATE DUMMY TABLE ENTRIES
	DTEFNC	(2TI,TAKCTN)	;(02) TAKE CTY-DLS CORRESPONDENCE
	DTEFNC	(HDS,TAKDVS)	;(07) TAKE DEVICE STATUS
	DTEFNC	(RDT,TAKRDT)	;(11) REQUEST FOR DATE/TIME
	DTEFNC	(RBI,TAKROM)	;(24) TAKE 11 ROM WORD
	DTEFNC	(AKA,TAKAAL)	;(25) ACK ALL
	DTEFNC	(KPS,KLCKPS)	;(33) TAKE KLINIK PARAMETERS
	DTEFNC	(DSN,TAKRPN)	;(40) TAKE DRIVE SERIAL NUMBERS

IF2, IFN .-ALLDSP-<MAXFNC+1>,PRINTX ? ALLDSP table is not the same length as FNCTAB
;ROUTINE TO RANGE CHECK A PROTOCOL FUNCTION CODE
; CALL WITH FUNCTION CODE, EM.IND ON IF APPLICABLE
; IN RH(P2) (USUAL PLACE)
; RETURN INTERNAL FUNCTION TYPE IN RH(T1), SOME BITS IN LH(T1)
; CALL AT GT2XFT TO FIND TO-10 FUNCTION TYPE
; CALL AT GT2EFT TO FIND TO-11 FUNCTION TYPE
; GIVES ERROR RETURN IF FUNCTION NOT LEGAL FOR SOME REASON
; GIVES SKIP RETURN IF OK, WITH FUNCTION TYPE IN RH(T1), BITS IN LH(T1)

	FNCMSK==77777

GT2XFT:	SKIPA	T4,[LGL2X]	;CHECK LEGAL FOR TO-10 BIT
GT2EFT:	MOVSI	T4,(LGL2E)	;CHECK LEGAL FOR TO-11 BIT
GTXXFT:	HRRZ	T1,P2		;GET FUNCTION CODE
	ANDI	T1,FNCMSK	;JUST THE CODE
	CAILE	T1,MAXFNC	;OUT OF RANGE?
	POPJ	P,		;YES, ERROR RETURN
	MOVE	T2,FNCTAB(T1)	;GET FUNCTION ENTRY FOR REST OF ROUTINE
	TDNN	T4,T2		;LEGAL FOR SAID DIRECTION?
	POPJ	P,		;NO, GIVE ERROR RETURN
	TRNE	P2,EM.16B	;IS 16 BIT MODE ON?
				; (NEVER IS FOR TO-10, 11 CANT SET IT)
	TLNE 	T2,(LGL16)	;YES, IS IT LEGAL FOR THIS FN?
	JRST	.+2		;YES.
	POPJ	P,		;NO, ERROR RETURN
	LDB	T1,[POINT 3,T2,35];GET TO-10 FUNCTION TYPE,
				;ASSUMING TEN FUNCTION
	TLNE	T4,(LGL2E)	;REALLY CALLED FOR TO-11?
	LDB	T1,[POINT 3,T2,32];YES, GET TO-11
	MOVE	T3,[CAIN T1,TINDR]
				;SETUP FOR DIRECT
	TRNE	P2,EM.IND	;IS THIS INDIRECT?
	CAIN	T1,TD60D	;DN60 DATA?
	JRST	GTXXF1		;YES, DON'T CARE
	HRLI	T3,(CAIE T1,)	;YES, SETUP FOR INDIRECT
	XCT	T3		;SKIP IF DIRECT/INDIRECT MODE IS SET CORRECTLY
	POPJ	P,		;NO, ITS NOT
GTXXF1:	HLL	T1,T2		;GET FLAG BITS IN LH(T1)
				;FUNCTION TYPE IS IN RH(T1)
	JRST	CPOPJ1##	;SUCCESS.
;ROUTINE TO CHECK TO SEE IF THE FUNCTION CODE IN RH(P2) IS
; LEGAL FOR ALL DEVICES (USE SPECIAL DISPATCH TABLE)
; CALL WITH FUNCTION CODE, EM.IND IN RH(P2) (USUAL PLACE)
; DEAD10 IF NOT A LEGAL FUNCTION (SHOULD HAVE BEEN CHECKED ALREADY)
; ERROR RETURN IF JUST ORDINARY FUNCTION
; SUCCESS RETURN IF FUNCTION IS LEGAL FOR ALL DEVICES
; SAVES ALL ACS

ISALL:	PUSHJ	P,SAVT##	;SAVE ALL T ACS
	PUSHJ	P,GT2XFT	;GET FUNCTION TYPE - INTERESTED IN LH BITS
	STOPCD	.,STOP,DTEPCI,DTEPDI, ;++FUNCTION CODE ILLEGAL
	TLNE	T1,(LGLAL)	;LEGAL FOR ALL DEVICES?
	AOS	(P)		;YES, GIVE SKIP RETURN
	POPJ	P,		;TO SKIP OR NOT TO SKIP
;TABLE INDICATING INTERNAL FUNCTION TYPE AND OTHER INFO
; TO-11 TYPE IN BITS 30-32, TO-10 TYPE IN BITS 33-35

	LGL2X==1B0		;LEGAL TO-10 FUNCTION
	LGL2E==1B1		;LEGAL TO-11 FUNCTION
	LGLAL==1B2		;LEGAL FOR ALL DEVICES (USE SPECIAL DISPATCH TABLE)
	LGL16==1B3		;LEGAL 16 BIT INDIRECT (COULD BE 8 BIT TOO)

;INTERNAL FUNCTION TYPES.  THERE ARE TWO TABLES, DTQTAB AND D2XTAB, THAT
; DEPEND ON THE TYPES BEING DEFINED IN THE FOLLOWING ORDER.

	TINDR==0		;INDIRECT
	T16BT==1		;16 BITS OF DATA
	TLINE==2		;LINE NUMBER
	TLNGD==3		;LONG DIRECT (LINE, DATA, LINE, DATA . . .)
	TLNDT==4		;ONE LINE, ONE DATUM
	TD60D==5		;DN60 DATA

FNCTAB:	0				;(0)ILLEGAL FUNCTION
	LGL2E+<T16BT>B32		;(1)TO-11 INITIAL MESSAGE
	LGLAL+LGL2X+<TLINE>B35 		;(2)TAKE CTY-DLS CORRESPONDENCE
	LGL16+LGL2E+LGL2X+<TINDR>B32+<TINDR>B35 ;(3)STRING DATA
	LGL2E+LGL2X+<TLNGD>B32+<TLNGD>B35 ;(4)TAKE CHARACTER DATA
	LGL2E+LGL2X+<TLNDT>B32+<TLNDT>B35 ;(5)REQUEST FOR DEVICE STATUS
	0				;(6)UNUSED
	LGLAL+LGL16+LGL2E+LGL2X+<TINDR>B32+<TINDR>B35 ;(7)HERE IS DEVICE STATUS
	0				;(10)UNUSED
	LGLAL+LGL2E+LGL2X+<T16BT>B32+<T16BT>B35 ;(11)REQUEST DATE/TIME
	LGL16+LGL2E+LGL2X+<TINDR>B32+<TINDR>B35 ;(12)HERE IS DATE/TIME
	LGL2E+<TLINE>B32		;(13)FLUSH TTY LINE OUTPUT
	LGL2E+<TINDR>B32		;(14)SEND ALL
	LGL2E+LGL2X+<TLINE>B32+<TLNGD>B35 ;(15)DATASET CONNECTED
	LGL2E+LGL2X+<TLINE>B32+<TLNGD>B35 ;(16)DATASET HUNG UP
	LGL2E+LGL2X+<TLNGD>B32+<TLNGD>B35 ;(17)DEVICE ACKNOWLEDGE
	LGL2E+<TLINE>B32		;(20)XON
	LGL2E+<TLINE>B32		;(21)XOFF
	LGL16+LGL2E+LGL2X+<TINDR>B32+<TINDR>B35 ;(22)HERE IS LINE SPEED
	LGL2E+LGL2X+<TLNGD>B32+<TLNGD>B35 ;(23)HERE IS LINE ALLOCATIONS
	LGLAL+LGL2X+<T16BT>B35		;(24)HERE IS 11 ROM WORD
	LGLAL+LGL2E+LGL2X+<T16BT>B32+<T16BT>B35	;(25)ACK ALL
	LGL2E+<TLNDT>B32		;(26)DEVICE ON/OFF
	LGL2E+<T16BT>B32		;(27)ENABLE/DISABLE REMOTES (DATASETS)
	LGL16+LGL2E+<TINDR>B32		;(30)LOAD LP RAM
	LGL16+LGL2E+<TINDR>B32		;(31)LOAD LP VFU
	LGL2E+LGL2X+<TD60D>B32+<TD60D>B35 ;(32)DN60 DATA
	LGLAL+LGL16+LGL2E+LGL2X+<TINDR>B32+<TINDR>B35 ;(33)KLINIK PARAMETERS
	LGL2E+<TLNDT>B32		;(34)ENABLE/DISABLE AUTO-XOFF
	LGL2E+<TLNGD>B32		;(35)BREAKTHROUGH CHAR DATA
	LGL2E+<T16BT>B32		;(36)DEBUGGING MODE ON
	LGL2E+<T16BT>B32		;(37)DEBUGGING MODE OFF
	LGLAL+LGL16+LGL2X+<TINDR>B35	;(40)HERE ARE DRIVE SERIAL NUMBERS
	LGL2E+<TLINE>B32		;(41)ENABLE EIGHT BIT TTY
	LGL2E+<TLINE>B32		;(42)DISABLE EIGHT BIT TTY
	MAXFNC==.-FNCTAB-1	;MAXIMUM FUNCTION CODE FOR RANGE CHECK

;TABLE FOR DISPATCH ON TO-10 MESSAGES ACCORDING TO INTERNAL FUNCTION TYPE

D2XTAB:	TKINDR			;INDIRECT
	TK16BT			;16 BIT DATUM
	TKLINE			;JUST LINE NUMBER
	TKLNGD			;LONG DIRECT
	TKLNDT			;LINE-DATUM
	TKD60D			;DN60 DATA
;ROUTINES TO HANDLE THE VARIOUS TYPES OF FUNCTIONS

;HERE IF FUNCTION IS INDIRECT

TKINDR:	HLRZ	T1,P2		;GET DEVICE
	STOR.	T1,ED.XDV,(F)	;STORE IN DTE BLOCK SO DRIVER CAN BE
				; TOLD WHAT'S WHAT
	STOR.	P2,ED.XFN,(F)	;STOR.E FUNCTION TOO
	ILDB	P3,T4		;GET COUNT FOR INDIRECT PART
	STOR.	P3,ED.IBK,(F)	;STORE IN ETD FOR COMPARE AGAINST QSIZE
				; AT DOORBELL TIME
	ILDB	T1,T4		;GET LINE NUMBER
	STOR.	T1,ED.XLN,(F)	;REMEMBER THIS FOR INDIRECT PART
	HRL	P3,T1		;C(P3)=LINE,,COUNT
	JRST	TKEXT1

;HERE FOR FUNCTIONS WHICH HAVE 16 BITS OF DATA

TK16BT:	PUSHJ	P,GX2BYT	;GET 16 BIT BYTE (SWAP BYTES)
	MOVE	P3,T1		;C(P3)=DATA
	JRST	TKEXT1

;HERE FOR FUNCTIONS CONTAINING JUST LINE NUMBER

TKLINE:	ILDB	T1,T4		;GET LINE NUMBER
	HRLZ	P3,T1		;C(P3)=LINE,,0
	SUBI	U,1
	JRST	TKEXT2

;HERE FOR LINE NUMBER,DATA FUNCTIONS
TKLNDT:	ILDB	P3,T4		;GET DATA IN P3
	ILDB	T1,T4		;GET LINE NUMBER
	HRL	P3,T1		;LINE
TKEXT1:	SUBI	U,2		;TOOK 2 8 BIT BYTES
TKEXT2:	SETZ	P4,		;NO BYTE POINTER
	POPJ	P,		;RETURN

;HERE FOR LONG DIRECT MESSAGES

TKLNGD:	HRRZ	P3,U		;THIS IS HOW LONG DATA IS
	MOVE	P4,T4		;SETUP 8 BIT BYTE POINTER FOR DRIVER
	POPJ	P,		;RETURN, HAVEN'T TAKEN ANY BYTES

;HERE FOR DN60 TYPE DATA
;
TKD60D:	MOVE	P4,T4		; AND THE POINTER
	TRNN	P2,EM.IND	;INDIRECT?
	  POPJ	P,		;DIRECT, SO RETURN NOW
	STOR.	P2,ED.XFN,(F)	;STORE THE FUNCTION
	MOVEI	T1,4		;NUMBER OF BYTES TO PASS OVER
	ADJBP	T1,T4		;POINTER TO THE COUNT
	MOVE	T4,T1		;POINTER HERE FOR GX2BYT
	PUSHJ	P,GX2BYT	;GET COUNT FROM THE DIRECT PORTION
	STOR.	T1,ED.IBK,(F)	;REMEMBER FOR INDIRECT PART
	MOVE	P3,T1		;RETURN INDIRECT COUNT TO DRIVER
				; IN P3
	POPJ	P,		;
;EATING SERVICE

;THIS IS A "DEVICE DRIVER" FOR UNKNOWN DEVICES.
; USING THE EATDSP TABLE ENSURES THAT A MESSAGE FROM THE 11
; IS EATEN IN A WAY TO MAKE THE 11 HAPPY, BUT WILL BE IGNORED
; BY THE 10.
;THESE ROUTINES SHOULD BE USED BY DEVICE DRIVERS FOR THROWING AWAY
; UNKNOWN MESSAGES.

	IFIW	CPOPJ##		;(-1) LOST TO-10 INDIRECT MESSAGE
EATDSP::DTEFNC			;(??) GENERATE DUMMY TABLE ENTRIES

EATMSG::PUSHJ	P,GT2XFT	;GET THE TO-10 FUNCTION TYPE
	STOPCD	.,STOP,DTEFNG,DTEPDI ;++ILLEGAL FUNCTION CODE
	PJRST	@EATTAB(T1)	;DISPATCH

EATTAB:	EATIND			;INDIRECT
	CPOPJ##			;16 BIT
	CPOPJ##			;LINE NUMBER
	CPOPJ##			;LONG DIRECT
	CPOPJ##			;LINE-DATA
	EATIND			;DN60 DATA - COULD BE INDIRECT


;ROUTINE TO EAT AN INDIRECT MESSAGE. (ALL OTHERS CAN BE IGNORED)

EATIND::MOVSI	S,CPOPJ##	;POST ADDRESS (P3 WILL BE ZERO AT POST TIME)
				;LEAVE LINE,,COUNT IN P3
	PJRST	TKEXT2		;ZERO BYTE POINTER SO DATA GOES NOWHERE
				; LET DTESER XFER THE INDIRECT DATA
;HERE ON TO-11 DONE. ETD ADDRESS IN F

DTE2ED:	MOVEI	T1,CLTO11	;CLEAR TO11 DONE
	XCT	ETDCNO(F)	;GONE.
	LOAD.	T4,ED.CUR,(F)	;GET RELEVANT QUEUE ENTRY
	LOAD.	T2,ED.211,(F)	;GET PTR TO COMM REGION
	LOAD.	T3,EC.PRT,(T2)	;GET PROTOCOL TYPE
	CAIN	T3,.MMCB	;IS IT MCB?
	JRST	DTEEDM		;PROCESS FOR MCB
	LOAD.	T1,ED.2ES,(F)	;GET TO-11 DTE STATE
	CAIN	T1,ED.EDB	;WERE WE WAITING FOR TO-11 DONE
	JRST	DTEEDD		;YES, SEE IF WE HAVE TO SEND INDIRECT DATA
	CAIE	T1,ED.EIB	;WAS TO-11 INDIRECT GOING?
	PJSP	T1,DTERLD	;SOMEONE FIDDLING WITH SWITCHES OR DTELDR
DTEEDI:	MOVE	T1,[EC.IND!EC.16B] ;CLEAR OUT SPECIAL INDIRECT BITS NOW
	LOAD.	T2,ED.211,(F)	;WHERE TO CLEAR THEM FROM
	ANDCAM	T1,ETCSTS(T2)	;ZAP EM
	JRST	DTEED1		;CONTINUE ON
DTEEDD:	LOAD.	T1,EQ.CNT,(T4)	;GET INDIRECT COUNT, IF ANY
	JUMPN	T1,DTESID	;IF COUNT IS NON-ZERO, SEND INDIRECT DATA NOW
DTEED1:	PUSH	P,T4		;SAVE CURRENT QUEUE ENTRY
	SETZ	T4,		;THERE IS NO MORE
	STOR.	T4,ED.CUR,(F)	;A CURRENT MESSAGE (UNTIL DTENXT)
	PUSHJ	P,DTENXT	;START UP DTE EARLY
	POP	P,T4		;RESTORE FORMER CURRENT MESSAGE QUEUE HEADER

;HERE TO POST A TO-11 MESSAGE. CALLED BY PUSHJ FROM DTECLR TO
; FAKE UP A POST WHEN A DTE IS CLEARED SO DRIVERS DONT HANG UP.
; DRIVERS ARE BEING LIED TO ABOUT SUCCESSFUL COMPLETION OF MESSAGE.
; HOWEVER, SHOULD BE NO DIFFERENT THAN IF 11 GOT MESSAGE AND THEN DIED.

DTEPST:	PUSHJ	P,SAVE4##	;SAVE P1-P4 FOR ARG PASSING
	LOAD.	T3,EQ.PST,(T4)	;GET POST ADDRESS
	JUMPE	T3,DTEPS1	;IF NO POST ADDRESS, SKIP SETUP
	PUSH	P,T4		;SAVE QUEUE HEADER ADDRESS AGAIN
	LOAD.	P1,ED.DTN,(F)	;C(P1)=CPU#,,DTE#
	HRL	P1,.CPCPN##	;INSERT CPU NUMBER
	ADDI	T4,SIZE(.EQLEN,36) ;POINT TO THE TO-11 MESSAGE ITSELF
	LOAD.	P2,EM.FNC,(T4)	;GET FUNCTION IN RH P2
	LOAD.	T1,EM.DEV,(T4)	;DEVICE GOES IN LH OF
	HRL	P2,T1		;P2
	SUBI	T4,SIZE(.EQLEN,36) ;POINT TO Q HEADER AGAIN
	LOAD.	T1,EQ.ELN,(T4)	;GET POSSIBLE TO-11 LINE NUMBER
	HRLZ	P3,T1		;PUT INTO LH(P3) FOR DRIVER
	LOAD.	P4,EQ.PTR,(T4)	;PASS POINTER BACK TO DRIVER
	LOAD.	T1,EQ.CNT,(T4)	;GET INDIRECT COUNT HE GAVE
	HRR	P3,T1		;RETURN IT FROM WHENCE IT CAME
	MOVSI	T1,(EQ.16B)	;WAS IT 16 BIT MODE?
	TDNE	T1,ETQSTS(T4)	;??
	TRO	P2,EM.16B	;YES, MAY AS WELL TELL HIM IN CASE IT WAS USEFUL
	LOAD.	S,EQ.DRD,(T4)	;DRIVER'S SPECIAL DATA (DDB OR SOMETHING)
	PUSH	P,F		;SAVE ETD ADDRESS
	PUSHJ	P,(T3)		;CALL DRIVER'S POST ROUTINE
	POP	P,F		;RESTORE ETD ADDRESS
	POP	P,T2		;RESTORE QUEUE ADDRESS INTO T2
	JRST	DTEPS2		;AND GIVE CORE BACK
DTEPS1:	MOVE	T2,T4		;GET ADDRESS IN T2 FOR GIVMES
DTEPS2:	LOAD.	T1,EQ.SIZ,(T2)	;GET TOTAL SIZE OF CORE BLOCK
	PJRST	GIVMES		;CALL GIVMES WITH ADDRESS IN T2,
;HERE IF TO-11 DONE FOR DIRECT PART OF INDIRECT MESSAGE
; WITH QUEUE HEADER ADDRESS IN T4

DTESID:	LOAD.	T3,ED.211,(F)	;GET TO-11 SECTION ADDRESS
	LOAD.	T1,EQ.PTR,(T4)	;GET INDIRECT POINTER DRIVER GAVE
	MOVEM	T1,@ETDEBP(F)	;PUT IN TO-11 POINTER WORD IN EPT
	LOAD.	T1,EQ.CNT,(T4)	;INDIRECT DATA COUNT
	STOR.	T1,EC.QSZ,(T3)	;SET UP QSIZE FOR INDIRECT PACKET
	MOVEI	T1,ED.EIB	;CHANGE STATE OF DTE TO EXPECTING TO-11
				; DONE FOR INDIRECT SO THAT DRIVER GETS CALLED
	STOR.	T1,ED.2ES,(F)	; (SEE ABOVE CODE)
	MOVE	T2,ETCSTS(T3)	;GET STATUS WORD FROM TO-11 SECTION
	TRO	T2,EC.IND	;INDIRECT BIT, SO 11 KNOWS WHAT BELL IS FOR
	MOVSI	T1,(EQ.16B)	;IS THE INDIRECT DATA TO BE SENT IN
	TDNE	T1,ETQSTS(T4)	; WORD MODE?
	TLO	T2,(EC.16B)	;YES, SET THE BIT FOR COMM AREA
	MOVEM	T2,ETCSTS(T3)	;SET STATUS ALL AT ONCE
	MOVEI	T1,TO11DB	;RING 11 DOORBELL NOW
	XCT	ETDCNO(F)	;DONG
	POPJ	P,		;RETURN
SUBTTL GENERAL MESSAGE PROCESSOR

TAKCTN:	HLRZ	T1,P3		;GET LINE # OF CTY
	STOR.	T1,ED.CTN,(F)	;STORE IN DTE CONTROL BLOCK
	HRLM	T1,.CPCTN##	;AND IN CDB
	POPJ	P,		;RETURN


;ACK ALL SERVICE

;THIS ROUTINE WILL DO INDIVIDUAL ACK ALL MESSAGES FOR ALL
; DEVICES IN ACKTAB

TAKAAL:	MOVSI	T4,-ACKTBL	;AOBJN POINTER TO ACKTAB
TAKAA1:	HRL	P2,ACKTAB(T4)	;GET DEVICE
	PUSH	P,T4		;SAVE AOBJN POINTER
	PUSH	P,F		;SAVE ETD ADDRESS
	PUSHJ	P,DSDSP		;DO THE ACK FOR A SINGLE DEVICE
				; (CALL SPECIAL ROUTINE THAT WILL DO DISPATCH
				; THROUGH SPECIFIC DEVICE'S DISPATCH TABLE)
	POP	P,F		;RESTORE ETD ADDRESS
	POP	P,T4		;GET POINTER BACK
	AOBJN	T4,TAKAA1	;AND CONTINUE
	POPJ	P,		;DONE


;TABLE OF DEVICES THAT NEED ACK ALL. THESE DEVICES MUST
; BE NON-SPECIAL, SINCE TAKAAL DOES DISPATCH BY HAND AND DOES NOT
; DO SEARCH OF SPECIAL DEVICE TABLE.
ACKTAB:	.EMDLS			;DLS
	.EMLPT			;LPT
	.EMFED			;FRONT END DEVICE

	ACKTBL==.-ACKTAB	;LENGTH


;TAKE 11 ROM WORD, FOR RELOADING

TAKROM:	LOAD.	T1,ED.211,(F)	;GET TO-11 SECTION ADDRESS
	STOR.	P3,EC.RLD,(T1)	;PUT INTO COMM REGION
	POPJ	P,		;RETURN
;DATE/TIME SERVICE

;HERE FROM COMCON TO SET DATE/TIME FOR ALL APPROPRIATE FRONT
; ENDS WHEN EITHER DATE OR DAYTIME SET COMMANDS ARE DONE.
; PRESENTLY ONLY THE MASTER -11 IS GIVEN THE DATE AND TIME.

COMSDT::MOVEI	T1,.C0CDB##	;GET ADDRESS OF FIRST CDB
	MOVSI	T2,F20SDT##	;GET BIT TO TELL TTDINT TO SET DATE/TIME
COMSD1:	IORM	T2,.CP20F##-.CPCDB##(T1) ;SET BIT FOR THIS CPU
	HLRZ	T1,.CPCDB##-.CPCDB##(T1) ;STEP TO NEXT CDB
	JUMPN	T1,COMSD1	;LOOP FOR ALL CPU'S
	POPJ	P,		;RETURN


;HERE FROM TTDINT WHEN THE DATE/TIME IS ACTUALLY TO BE
; SET.  COMSDT DOESN'T DO THE WORK DIRECTLY BECAUSE
; WE WANT TO TELL THE -11 ON EACH CPU IN THE SYSTEM
; OF THE CHANGE

DTEDTM::PUSHJ	P,SAVE4##	;SAVE P1-P4 NOW
	PUSHJ	P,SVEPTD	;GET MASTER ETD ADDRESS
	LOAD.	P1,ED.DTN,(F)	;GET DTE NUMBER IN P1
	HRL	P1,.CPCPN##	; AND CPU # OF THIS CPU
	PJRST	DTESD0		;GO DO IT
;HERE TO PROCESS REQUEST FOR DATE/TIME, OR TO SEND DATE/TIME
; JUST FOR THE HECK OF IT.  C(P1) = CPU#,,DTE#. P2-P4 SETUP BY THIS ROUTINE
; BEFORE CALL TO DTEQUE.


TAKRDT:
DTESDT:	PUSHJ	P,SAVE4##	;STILL USE DATA FROM P1-P4,
				; BUT RESTORE AFTER WE'RE DONE

;HERE IF P1-P4 ALREADY SAVED

DTESD0:	MOVEI	T2,SIZE(.EMDTS,36) ;GET SIZE OF INDIRECT CORE, IN 36 BITS
	PUSHJ	P,MESCOR	;GET THE CORE
	  POPJ	P,		;LOSE. DON'T CRASH THE TEN, THOUGH.
	MOVE	P4,T1		;SAVE ADDRESS OF INDIRECT MESSAGE
	MOVSI	T2,(POINT 16,(P4)) ;POINTER TO FILL MESSAGE
	MOVEI	T1,177777	;FIRST BYTE SAYS VALID DATE/TIME
	IDPB	T1,T2		;PUT IT IN THE INDIRECT MESSAGE
	MOVE	T1,LOCYER##	;NEXT BYTE IS THE YEAR
	IDPB	T1,T2
	MOVE	T2,[POINT 8,1(P4)] ;NEXT FEW ARE 8 BIT BYTES
	MOVE	T1,LOCMON##	;GET MONTH
	SOS	T1		;RSX-20 EXPECTS JANUARY TO BE 0
	IDPB	T1,T2		;STORE
	MOVE	T1,LOCDAY##	;AND DAY
	SOS	T1		;RSX-20 EXPECTS 1ST OF THE MONTH TO BE ZEROTH
	IDPB	T1,T2		;STORE THAT TOO
	HLRZ	T3,DATE##	;GET UNIVERSAL DATE
	IDIVI	T3,7		;GET DAY OF WEEK IN T4
	ADDI	T4,2		;RSX'S MONDAY = 0, WHILE WED. = 0 FOR UDT
	CAIL	T4,7		;OVERFLOW?
	SUBI	T4,7		;YES, DROP BACK 7
	IDPB	T4,T2		;STORE DAY OF WEEK, MONDAY = 0
	MOVE	T2,[POINT 16,2(P4)]	;NEXT WORD. ONE 16 BIT BYTE IN HERE.
	MOVE	T3,TIME##	;GET TICS SINCE MIDNIGHT
	IDIV	T3,TICSEC##	;CONVERT TO SECONDS SINCE MIDNITE
	ASH	T3,-1		;/2 SO IT WILL FIT
	IDPB	T3,T2		;STORE THAT

;NOW MESSAGE PACKET IS COMPLETE, SEND IT

	HRLI	P4,(POINT 16,)	;16 BIT BYTE POINTER
	MOVEI	P3,.EMDTS	;SIZE OF MESSAGE, IN 8 BIT BYTES
	MOVE	P2,[.EMCLK,,EM.16B+EM.IND+.EMHDT]	;HERE IS DATE/TIME
	MOVSI	S,DTESD1	;PLACE TO GO TO WHEN DONE
	S0PSHJ	DTEQUE		;GO SEND IT
	  JFCL			;IGNORE AN ERROR
	POPJ	P,		;RETURN


;HERE WHEN DATE/TIME MESSAGE IS SENT, GIVE BACK CORE

DTESD1:	MOVEI	T1,SIZE(.EMDTS,36) ;WORDS TO GIVE BACK
	HRRZ	T2,P4		;GET ADDRESS BACK FROM POINTER
	PJRST	GIVMES		;RETURN CORE.
SUBTTL -- KLINIK PARAMETER STATUS SAVING

;HERE ON DIRECT PART OF THE KLINIK PARAMETER MESSAGE

KLCKPS:	MOVSI	S,KPSRCV	;POST KLINIK PARAMETER SAVE ADDRESS
	MOVEI	P3,KPSLEN	;LENGTH OF PARAMETER MESSAGE
	MOVE	P4,KPSPTR	;POINTER TO SAVE AREA
	POPJ	P,		; AND RETURN


;HERE ON RECEIPT OF THE INDIRECT PORTION OF THE PARAMETER MESSAGE

KPSRCV:	MOVEI	P3,0		;INDICATE ALL EXPECTED DATA RECEIVED
	POPJ	P,		; AND RETURN


;HERE TO SEND THE PARAMETERS BACK TO THE -11

KPSSND:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	LOAD.	P1,ED.DTN,(F)	;MASTER DTE NUMBER
	HRL	P1,.CPCPN##	;ON THIS CPU
	MOVEI	P2,EM.16B+EM.IND+.EMKPS
	MOVEI	P3,KPSLEN	;MESSAGE LENGTH IN 8-BIT BYTES
	MOVE	P4,KPSPTR	;POINTER TO THE DATA
	MOVEI	S,'FOO'		;DON'T CARE ABOUT POST
	S0JRST	DTEQUE		;SEND MESSAGE

KPSPTR:	POINT	16,.CPKPB##	;POINTER TO SAVE AREA
SUBTTL -- DRIVE SERIAL NUMBER RECEIPT

;HERE ON DIRECT PART OF THE DRIVE SERIAL MESSAGE

TAKRPN:	MOVSI	S,DSNRCV	;POST DRIVE SERIAL SAVE ADDRESS
	MOVEI	P3,^D<8*2>	;LENGTH OF DRIVE SERIAL MESSAGE
	MOVE	P4,DSNPTR	;POINTER TO SAVE AREA
	POPJ	P,		; AND RETURN


;HERE ON RECEIPT OF THE INDIRECT PORTION OF THE DRIVE SERIAL MESSAGE

DSNRCV:	MOVEI	P3,0		;INDICATE ALL EXPECTED DATA RECEIVED
	PJRST	NEWDSN##	;TELL FILSER NEW SERIAL NUMBERS ARRIVED


;ROUTINE TO RETURN UNIT NUMBER OF BOOT DEVICE ON SPECIFIED CPU.
;CALL:
;	T1/ CPU NUMBER
;RETURN:
;	<ERROR>
;	<SUCCESS>, T1/ UNIT NUMBER PLUS 1B0 IF BOOTED FROM DISK

DTEGBU::PUSH	P,F		;DTESER STEPS ON F
	HRLO	F,T1		;PUT IN FORM DTESER UNDERSTANDS
	PUSHJ	P,GETETD	;GET ADDRESS OF DTE CONTROL BLOCK
	  JRST	FPOPJ##		;ERROR
	LOAD.	T1,ED.211,(F)	;GET TO-11 SECTION FOR THIS DTE/11
	LOAD.	T2,EC.RLD,(T1)	;GET RELOAD WORD FOR THIS 11
	LDB	T1,[POINT 3,T2,27] ;GET BOOT UNIT
	TRNE	T2,1B28		;BOOTED FROM DISK?
	TLO	T1,(1B0)	;YES, SET BIT
	JRST	FPOPJ1##	;SKIP RETURN

DSNPTR::POINT	16,.CPDSN##	;POINT TO DRIVE SERIAL NUMBER FOR THIS CPU
SUBTTL KL ERROR STATUS COLLECTING

;HERE ON RECEIPT OF STATUS MESSAGE

TAKDVS:	HRRZ	T1,P3		;GET COUNT OF 8 BIT BYTES
	ADDI	T1,^D36/^D8-1	;ROUND UP TO A 36 BIT WORD'S WORTH
	ASH	T1,-2		;TURN INTO 36 BIT WORDS
	ADDI	T1,SIZE(.KEHDL,36) ;ADD IN SIZE OF OUR HEADER
	PUSHJ	P,ALCSEB##	;GET THE CORE
	  JRST	EATMSG		;CAN'T, FORGET IT
LOGSET:	MOVE	P4,T1		;GET ADDRESS IN P4, USE FOR POINTER LATER
	XMOVEI	T2,DVSTBL	;POINT TO OUR TRANSFER TABLE
	PUSHJ	P,XFRSEB##	;INITIALIZE THE SYSTEM ERROR BLOCK
	  JFCL			;CAN'T FAIL HERE
	MOVEM	P1,.KEDTE(P4)	;SET CPU,,DTE
	HLRZ	T1,P2		;GET DEVICE CODE
	HLL	T1,P3		;MAKE UNIT,,DEV
	MOVEM	T1,.KEDEV(P4)	;STASH
	HRRZ	T1,P3		;GET 8 BIT COUNT AGAIN
	MOVEM	T1,.KECNT(P4)	;SAVE FOR SPEAR
	ADDI	T1,^D36/8-1	;ROUND UP FOR BYTE-TO-WORD CONVERSION
	ASH	T1,-2		;CONVERT TO WORDS
	MOVNS	T1		;NEGATE
	HRLZS	T1		;MAKE AOBJN POINTER
	SKIPE	T1		;IF THERE IS ANYTHING,
	HRRI	T1,.KEDAT-.KEBEG ;MAKE A RELATIVE POINTER
	MOVEM	T1,.KEPTR(P4)	;STORE FOR SPEAR
;	SETZ	T1,		;ZERO FIRST WORD SO DAEMON CAN SEE
;	STOR.	T1,KE.1WD,(P4)	;IF TRANSFER EVER MADE IT (AT LEAST ONE BIT
;				; SHOULD BE ON IN THE GENERAL STATUS BYTE)
	SETZM	.KEDAT(P4)	;QUICKER VERSION OF ABOVE
	ADDI	P4,.KEDAT	;POINT TO FIRST WORD WITH DATA
	HRLI	P4,(POINT 16)	;MAKE BYTE POINTER
	MOVSI	S,DVSDON	;ADDRESS TO GO WHEN XFER IS DONE
	POPJ	P,		;RETURN AND START XFER
;HERE WHEN STATUS MESSAGE IS IN, GIVE TO DRIVER AND THEN LOG IT IF APPROPRIATE

DVSDON:	PUSH	P,P4		;SAVE POINTER TO STATUS MESSAGE
	MOVE	T2,P4		;COPY BYTE POINTER FOR PEEK-AHEAD
	ILDB	T2,T2		;GET GENERAL STATUS BYTE
	PUSH	P,F		;SAVE ETD ADDRESS
	TRNN	T2,EM.CFG	;IS THIS REALLY CONFIGURATION INFO
	PUSHJ	P,DSDSP		;NO, REAL STATUS, HAND DATA TO DRIVER
	POP	P,F		;RESTORE ETD ADDRESS
	POP	P,T2		;RESTORE POINTER
	SETZ	P3,		;WE ARE DONE WITH ALL THE DATA
	MOVEI	T2,-.KEDAT(T2)	;POINT BACK TO CHUNK PROPER
	LOAD.	T1,KE.1WD,(T2)	;GET GENERAL STATUS BYTE
	TRNN	T1,EM.ELR	;ERROR LOGGING REQUEST
	JRST	DVSGIV		;NO, RETURN CHUNK TO FREE CORE
DVSLOG:	PUSH	P,T2		;SAVE THE ADDRESS
	LOAD.	T1,KE.DEV,(T2)	;GET DEVICE TYPE
	CAIN	T1,.EMKLI	;IF KLINIK PARAMETER CHANGE,
	PUSHJ	P,DVSWTO	;TRY TO NOTIFY ORION
	POP	P,T1		;RESTORE ADDRESS IN A BETTER AC
	PJRST	QUESEB##	;SEND IT TO DAEMON AND RETURN

DVSTBL:	SEBTBL	(.ERKLE,DVSTBE,) ;KL ERROR CHUNKS REQUEST
	SETO			;(R00) JOB NUMBER
	SETZ			;(R01) DIRECTORY
	SETZ			;(R02) FRONT END SOFTWARE VERSION
	SETZ			;(R03) SIXBIT NAME OF PROGRAM (NONE)
DVSTBE:!			;END OF STATIC TRANSFER DATA
;SUBROUTINE TO FORMAT A WTO MESSAGE FOR ORION, CALLED FROM DVSLOG

DVSWTO:	MOVEI	T1,OPM.SO	;SEND TO ORION (ONLY)
	PUSHJ	P,OPRMSG##	;WE WANT AN OPERATOR MESSAGE
	  POPJ	P,		;NO CORE OR NO ORION--PUNT
	PUSHJ	P,SAVE1##	;GET A BETTER AC
	MOVE	P1,T2		;SAVE START OF OUR BLOCK
	MOVE	P4,[POINT 16,.KEDAT(P1),15] ;GET ROVING DATA POINTER AS WELL
	MOVE	T2,.CPLOG##	;OUR CPU NAME
	PUSHJ	P,PRNAME##	;START THE MESSAGE HEADER
	PUSHJ	P,INLMES##	;ADD TEXT
	  ASCIZ	/ KLINIK Status Change/
	PUSHJ	P,OPRHDR##	;BIND IT OFF AS THE HEADER AND PREPARE FOR TEXT
	ILDB	T1,P4		;GET EVENT CODE WORD
	MOVE	T2,T1		;COPY CODE,TYPE
	LSH	T2,-8		;CODE
	ANDI	T1,377		;TYPE
	CAIN	T1,377		;CLEAR?
	JRST	KLEKWC		;(-1) WINDOW CLOSED
	CAILE	T1,0		;IF .LE. ZERO
	CAILE	T1,7		;OR .GT. MAX
	PJRST	OPRMSQ##	;INVALID FORMAT, FORGET IT
	PJRST	@.(T1)		;DISPATCH IT
	IFIW	KLEKOW		;(1) OPEN WINDOW
	IFIW	KLEKLR		;(2) LINE RANG
	IFIW	KLEKLD		;(3) LINE DISCONNECT
	IFIW	KLEKLC		;(4) LINE CONNECT
	IFIW	KLEKBP		;(5) BAD PASSWORD
	IFIW	KLEKLF		;(6) LOGIN FAILED
	IFIW	KLEKAR		;(7) ACTIVE ON REBOOT

KLEKOW:	PUSHJ	P,INLMES##	;WINDOW OPENED
	  ASCIZ	/Access window opened
Window opened on /
	PUSHJ	P,KLEKDT	;TYPE DATE/TIME
	PUSHJ	P,INLMES##	;DELIMIT
	  ASCIZ	/
Window closes on /
	PUSHJ	P,KLEKDT	;TYPE DATE/TIME
	PUSHJ	P,INLMES##	;MORE FORMATTING
	  ASCIZ	/
KLINIK mode: /
	ILDB	T1,P4		;FETCH CSL,MODE
	MOVE	T2,T1		;SAVE CSL
	ANDI	T1,377		;GET MODE
	CAIN	T1,377		;USER MODE?
	  JRST	[PJSP T1,KLEKST	;YES, DONE AFTER THIS STRING
		 ASCIZ /USER/]
	PUSHJ	P,INLMES##	;NOPE
	  ASCIZ	/REMOTE	Console mode: /
	MOVE	T1,T2		;GET CSL,MODE
	LSH	T1,-8		;ONLY CSL
	IDIVI	T1,3		;XLATE (1,3,7) TO (0,1,2)
KLEKLM:	MOVE	T1,[[ASCIZ /OPERATOR/]
		    [ASCIZ /PROGRAMMER/]
		    [ASCIZ /MAINTENANCE/]](T1)
	PJRST	KLEKST		;TYPE AND SEND MESSAGE

KLEKLR:	PUSHJ	P,INLMES##	;WHAT HAPPENED
	  ASCIZ	/Dataset rang - /
	MOVEI	T1,[ASCIZ /???/] ;IN CASE OF JUNK
	CAIN	T2,1		;ACCEPTED?
	MOVEI	T1,[ASCIZ /Accepted/]
	CAIN	T2,377		;REJECTED?
	MOVEI	T1,[ASCIZ /Window closed/]
	PJRST	KLEKST		;TYPE AND SEND MESSAGE

KLEKLD:	PUSHJ	P,INLMES##	;SAY WHAT HAPPENED
	  ASCIZ	/Dataset disconnected /
	MOVEI	T1,[ASCIZ /???/] ;IN CASE OF JUNK
	CAIN	T2,1		;INTENTIONAL?
	MOVEI	T1,[ASCIZ /from CTY or Timeout/]
	CAIN	T2,377		;LINE DROP?
	MOVEI	T1,[ASCIZ /due to carrier loss/]
	PJRST	KLEKST		;TYPE AND SEND

KLEKLC:	PUSHJ	P,INLMES##	;WHAT HAPPENED
	  ASCIZ	/Remote user connected in /
KLEKC0:	MOVE	T1,T2		;GET EVENT CODE
	CAIN	T1,377		;IS IT USER?
	JRST	[PJSP	T1,KLEKC1	;YES
		 ASCIZ	/USER/]
	SOSL	T1,T2		;RANGE CHECK
	CAILE	T1,2		;OPR, PRG, MNT
	SKIPA	T1,[[ASCIZ /???/]] ;FAILS
	XCT	KLEKLM		;GET ADDRESS OF MODE
	PUSH	P,T1		;SAVE
	PUSHJ	P,INLMES##	;INTRODUCE IT
	  ASCIZ	/REMOTE /
	POP	P,T1		;RESTORE ADDRESS OF MODE STRING
KLEKC1:	PUSHJ	P,CONMES##	;TYPE IT
	PJSP	T1,KLEKST	;TYPE THIS AND SEND IT
	ASCIZ	/ mode/

KLEKBP:	PUSHJ	P,INLMES##	;WHAT HAPPENED
	  ASCIZ	/Bad password #/
	MOVE	T1,T2		;GET NUMBER
	PUSHJ	P,PRTDIG##	;TYPE IT
	PJSP	T1,KLEKST	;DON'T TYPE WHAT WAS TRIED
	ASCIZ	/ entered/	;JUST TYPE THIS AND SEND IT

KLEKLF:	PUSHJ	P,INLMES##	;WHAT HAPPENED
	  ASCIZ	/Remote access failed - /
	MOVE	T1,T2		;HOW MANY PASSWORDS
	PUSHJ	P,PRTDIG##	;SAY
	PJSP	T1,KLEKST	;TYPE REMAINDER AND SEND
	ASCIZ	/ passwords attempted/

KLEKAR:	PUSHJ	P,INLMES##	;WHAT HAPPENED
	  ASCIZ	/Active during reload in /
	JRST	KLEKC0		;GO TYPE CODE AND ISSUE MESSAGE

KLEKWC:	MOVEI	T1,[ASCIZ /Access window closed/]
	;PJRST	KLEKST

KLEKST:	PUSHJ	P,CONMES##	;TYPE THE FINAL STRING
	PJRST	PCRLF##		;ADD A CRLF AND LET CORETURN SEND THE MESSAGE
;SUBROUTINE TO FORMAT A DATE FROM 20F

KLEKDT:	ILDB	T1,P4		;FETCH THE TIME (IN SEC/2)
	PUSH	P,T1		;SAVE IT
	ILDB	T1,P4		;GET MON,YR
	PUSH	P,T1		;SAVE
	ILDB	T1,P4		;GET 0,DAY
	ANDI	T1,377		;MAKE SURE JUST DAY
	PUSHJ	P,PRT2##	;TYPE DAY
	MOVE	T1,(P)		;MONTH,YR
	LSH	T1,-8		;MONTH
	SKIPLE	T1		;BETTER BE LEGAL
	CAILE	T1,^D12
	SKIPA	T1,["???"]	;NO--GET JUNK
	MOVE	T1,MONTAB##-1(T1) ;YES--GET MONTH NAME
	DMOVE	T2,DAMESS##	;GET A COPY OF THE STRING (SMP PROBLEM?)
	PUSH	P,T2		;SAVE FIRST PART
	PUSH	P,T3		;AND SECOND
	DPB	T1,[POINT 7*3,-1(P),34-7] ;SET OUR MONTH IN STRING
	MOVEI	T1,-1(P)	;POINT TO IT
	PUSHJ	P,CONMES##	;TYPE IT
	ADJSP	P,-2		;TRIM OFF THE STRING
	POP	P,T1		;GET YEAR
	ANDI	T1,377		;JUST YEAR
	PUSHJ	P,PRT2##	;TYPE END OF DATE
	PUSHJ	P,INLMES##	;SEPARATE FROM TIME
	  ASCIZ	/ at /
	POP	P,T1		;RESTORE TIME
	LSH	T1,1		;MAKE SECONDS
	IMUL	T1,TICSEC##	;THEN JIFFIES
	PJRST	PRTIM##		;PRINT THE TIME AND RETURN
;SUBROUTINE TO ACTUALLY DEALLOCATE THE CORE, CALLED FROM DVSDON

DVSGIV:	MOVE	T1,.KECNT(T2)	;GET SIZE OF KLE DATA IN THIS ONE
	ADDI	T1,^D36/^D8-1	;ROUND UP
	ASH	T1,-2		;MAKE IT 36 BIT WORDS
	ADDI	T1,.KEDAT	;DEALLOCATE HEADER TOO
	PJRST	GIVMES		;CALL WITH ADDR IN T2, COUNT IN T1
SUBTTL PROTOCOL CONTROL

;ROUTINE TO ENTER SECONDARY PROTOCOL FOR THE FIRST TIME
; USES T ACS.

ENTSPC::PUSHJ	P,SVEPTD	;SAVE F,T4 AND SETUP DTE & EPT ADDRESSES
	CONI	PI,T2		;GET CURRENT PI STATE
	PUSH	P,T2		;SAVE FOR LATER
	CONO	PI,PI.OFF	;TURN OFF IN CASE STUFF RUNNING
	MOVSI	T2,(ED.PPC)	;GET READY TO CLEAR PRIMARY PROTOCOL BIT
	ANDCAM	T2,ETDSTS(F)	;CLEAR BIT. NOW INTERRUPTS WILL GO
				; THRU SECONDARY INTERRUPT ROUTINE
	LOAD.	T2,ED.211,(F)
	MOVSI	T1,(EC.PWF)	;CLEAR POWER FAIL BIT
	ANDCAM	T1,ETCSTS(T2)	; SO 11 WILL BELIEVE WE ARE OK
	MOVEI	T1,PILDEN+SPCPI	;SETUP NEW PI ASSIGNMENT
	XCT	ETDCNO(F)	;DO IT
	SKIPN	DTEEPW(T4)	;WERE WE IN PRIMARY PROTOCOL?
	JRST	ENTSP1		;NO, CAUSE NO EXTRA DOORBELLS
	MOVEI	T1,TO11DB	;WAIT FOR ALL DOORBELLS TO THE -11 TO CLEAR
	MOVEI	T2,SPCTRY	;TIME TO WAIT
	XCT	ETDCSZ(F)	;CLEAR YET?
	SOJG	T2,.-1		;NO, TRY FOR A WHILE
	SKIPG	T2		;DID WE MAKE IT?
	PJSP	T1,[POP P,T2	;GO KILL -11
		    TRNE T2,PI.PIA ;BUT FIRST, RESTORE PI
		    CONO PI,PI.ON ;BACK ON
		    PJRST DTERLD] ;AND TELL DTELDR
	SETZM	DTEEPW(T4)	;IN CASE PRIMARY PROTOCOL WAS RUNNING
	MOVEI	T1,TO11DB	;RING 11'S DOORBELL SO IT
	XCT	ETDCNO(F)	;CAN SEE WHATS HAPPENED
ENTSP1:	MOVEI	T1,DT.ESP	;ENTER SECONDARY PROTOCOL COMMAND
	PUSHJ	P,SPCMD		;DO THE COMMAND
	MOVSI	T1,(ED.SPC)	;SET SECONDARY PROTOCOL BIT
	IORM	T1,ETDSTS(F)	;IN DTE STATUS WORD
	POP	P,T2		;GET PREVIOS PI STATE
	TRNE	T2,PI.PIA	;WERE THEY ON BEFORE
	CONO	PI,PI.ON	;TURN ON PI SYSTEM AND
	PUSHJ	P,SPCGSF	;GET SECONDARY PROTOCOL FLAGS INTO .CPSPF
	POPJ	P,		;RETURN
REPEAT 0,<
;ROUTINE TO START PRIMARY PROTOCOL ON ANY DTE. CALL WITH
; DTE NUMBER (0-3) IN T1.

STRPPC::PUSH	P,F		;SAVE F AND
	PUSH	P,T4		;T4
	HRRZ	F,T1		;GET DTE NUMBER IN RH(F)
	MOVE	T1,.CPCPN##	;GET CPU NUMBER
	HRL	F,T1		;IN LH OF F
	PUSHJ	P,GTETDS	;GET DTE CONTROL BLOCK IN F
	AOS	-2(P)		;ASSUME GOOD RETURN
	PUSHJ	P,STXPPC	;DO COMMON STUFF
	  SOS	-2(P)		;NOT
	POP	P,T4		;RESTORE T4
	PJRST	FPOPJ##		;F AND RETURN
> ;END OF REPEAT 0
;HERE TO STOP AN 11 FROM RUNNING PRIMARY PROTOCOL. LEAVES
; 11 WAITING TO ENTER A PROTOCOL (PRIMARY, SECONDARY).
; CALL WITH DTE CONTROL BLOCK ADDRESS IN F.

LEVPPC:	PUSHJ	P,SAVE1##	;WE'LL USE P1 BELOW TO PASS A PARAMETER
	PUSHJ	P,GTEPT		;HAVE ETD ALREADY, GET EPT
	LOAD.	T1,ED.DTN,(F)	;GET DTE NUMBER
	LSH	T1,3		;*8
	ADD	T4,T1		;PLUS EPT IS OFFSET FROM DTE0 VECTOR
	MOVSI	T1,(ED.PPC)	;CLEAR PRIMARY PROTOCOL BIT
	ANDCAM	T1,ETDSTS(F)
	SETZM	DTEEPW(T4)	;NOW STOP 11 FROM LOOKING AT VALID EXAMINE BIT
	MOVEI	T1,TO11DB	;MAKE 11 NOTICE BY RINGING DOORBELL
	XCT	ETDCNO(F)	;DONG
	PUSHJ	P,SSEC0##	;USE SECTION 0 CAUSE OF INDIRECTION IN DTEFEK
	LOAD.	P1,ED.DTN,(F)	;GET DTE # OF THIS FRONT END
	LOAD.	T1,ED.CPN,(F)	;GET CPU #
	HRLI	P1,(T1)		;P1 IS NOW STANDARD DATA (CPU,,DTE)
	SKIPN	T2,@DTEFEK##(T1) ;SEE IF A FEK THERE
	POPJ	P,		;NO GET OUT NOW
	MOVEI	T1,FF.DWN	;GET THE "FEK DIED" FUNCTION CODE
	XCT	FEKDSP(T2)	;  AND TELL SOMEONE THEY LOST AN 11
	POPJ	P,		;RETURN
;STAPPC	ROUTINE TO START PRIMARY PROTOCOL ON ALL DTE'S.
;  DTEINI MUST BE CALLED FIRST.
;  THIS ROUTINE FIRST STARTS PRIMARY PROTOCOL ON DTE'S 3-0, THEN REQUESTS
;  DATE AND TIME FROM THE MASTER.
;RETURNS NON-SKIP ALWAYS

STAPPC::SETZM	.CPTMF##	;RESET TICKS SINCE LAST KEEP ALIVE UPDATE
	MOVSI	T1,(ST%NPP)	;SEE IF ONCE PREVENTED THIS (/NOPPC)
	TDNE	T1,CNFST2##	;...
	POPJ	P,		;YES, KEEPA YOUR HANDS OFFA DEM DTES
	PUSHJ	P,SVEPTD	;SAVE F, T4 ETC.
	MOVEI	F,3		;GET NUMBER OF LAST (POSSIBLE) DTE
	HRL	F,.CPCPN##	;GET CPU NUMBER IN LEFT HALF.
STAPP1:	PUSH	P,F		;SAVE "XWD CPU,DTE"
	PUSHJ	P,GETETD	;FIND DTE BLOCK
	  JRST	STAPP2		;NON-EXISTANT
	MOVE	P1,(P)		;DTE NUMBER
	MOVX	T1,ED.SAL	;THIS CALL IS FROM START ALL
	IORM	T1,ETDSTS(F)	;TELL STXPPC
	PUSHJ	P,DTECLR	;CLEAR OUT ANY OLD QUEUES
	HLRZ	T1,(P)		;GET CPU #
	CAME	F,DTEMAS##(T1)	;DON'T DO CFE YET
	PUSHJ	P,STXPPC	;START PRIMARY PROTOCOL
	  JFCL			;  WE DON'T CARE IF WE CAN'T
STAPP2:	MOVX	T1,ED.SAL	;START-ALL FLAG
	ANDCAM	T1,ETDSTS(F)	;MAKE SURE IT'S CLEAR FOR OTHER CALLERS
	POP	P,F		;GET "XWD CPU,DTE" BACK
	TRNE	F,-1		;IF WE HAVEN'T GOTTEN DOWN TO "ZERO"
	SOJA	F,STAPP1	;  DECREMENT TO THE NEXT ONE AND START THAT.

;NOW REQUEST DATE AND TIME FROM THE MASTER.

	PUSHJ	P,GTEPD		;GET F := ETD ADDRESS OF THE MASTER
	PUSHJ	P,DFKSE0	;SET LINE-USER TYPE FOR RSX20F
	MOVX	T1,ED.SAL	;FROM START-ALL FLAG
	IORM	T1,ETDSTS(F)	;LIGHT IT FOR THIS CALL
	PUSHJ	P,STXPPC	;START PRIMARY ON MASTER NOW
	  JFCL			;SHOULD NEVER FAIL
	MOVX	T1,ED.SAL	;START-ALL FLAG
	ANDCAM	T1,ETDSTS(F)	;LEAVE IT CLEAR FOR DTELDR
	POPJ	P,		;ALL DONE.  ALL DTE'S STARTED, MASTER TICKLED.
;STXPPC -- ROUTINE TO START PRIMARY PROTOCOL ON ANY DTE, ETD ADDRESS IN F
;
; NOTE: T4 IS SETUP TO BE OFFSET TO THE SPECIFIC DTE'S HARDWARE VECTOR
; MINUS ADDRESS OF FIRST VECTOR, SO DTE VECTOR IS ADDRESSED AS
; DTE???(T4), WHERE DTE??? IS THE LOCATION OF THE FIRST DTE'S VECTOR
; LOCATION
; SKIP RETURN IF SEEMED TO GET INTO PRIMARY PROTOCOL
; NON-SKIP IF NOT

STXPPC:	PUSHJ	P,SAVE4##	;SAVE P1-P4 FOR CALL TO DTEQUE
STXPP0:	PUSHJ	P,GTEPT		;GET EPT, F ALREADY SET UP
	SETZ	S,		;NO DRIVER DATA OR POST ADDRESS
	LOAD.	P1,ED.DTN,(F)	;GET DTE NUMBER IN RH(P1)
	LOAD.	T1,ED.CPN,(F)	;PUT CPU NUMBER IN LH(P1)
	HRL	P1,T1
	MOVEI	T1,PILDEN+PI0ENB+0 ;MAKE SURE THIS DTE DOESNT INTERRUPT
	XCT	ETDCNO(F)
	LOAD.	T1,ED.DTN,(F)	;GET DTE NUMBER
	LSH	T1,3		;*8
	ADD	T4,T1		;GET OFFSET TO THIS DTE'S HARDWARE VECTOR
	SETZM	ETDKAN(F)	;RESET KEEP-ALIVE HUNG COUNTER
				; FOR THIS DTE
	MOVE	T1,ETDSTS(F)	;GET SOME BITS
	MOVE	T2,ETDUSR(F)	;AND THE LINE USER
	TLNE	T1,(ED.DTM)	;IF NOT THE MASTER,
	JRST	STXPP4		;MASTER--JUST USE WHAT'S BEEN SET
	CAIE	T2,DD.NOB	;AND WE DON'T KNOW THE USER,
	CAIN	T2,DD.DEC	;OR IT'S AN MCB
	TRNA			;THEN MAKE SURE OF QP2
	JRST	STXPP4		;(NO--JUST USE WHAT'S BEEN SET)
	LOAD.	T3,ED.210,(F)	;YES--GET 11'S TO-10 ADDRESS
	LOAD.	T2,ED.211,(F)	;AND OUR TO-11 ADDRESS
	MOVEI	T1,.MMCB	;AND THE MCB PROTOCOL TYPE
	STOR.	T1,EC.PRT,(T2)	;SET IN TO-11 SECTION
	STOR.	T1,EC.PRT,(T3)	;AND IN TO-10 SECTION
STXPP4:	LOAD.	T3,ED.210,(F)	;GET 11'S TO-10 SECTION ADDRESS
	LOAD.	T2,EC.PRT,(T3)	;GET PROTOCOL TYPE
	SETZ	T1,		;AT LEAST CLEAR THE QUEUE COUNTS
	CAIE	T2,.MMCB	;IS IT MCB TYPE?
	MOVSI	T1,(EC.VEX!EC.QIU) ;NO, VALID EXAMINE, Q PROTOCOL IN USE
	MOVEM	T1,ETCSTS(T3)	;INITIALIZE STATUS WORD
				;(ZEROES QUEUE COUNTS TOO)
	LOAD.	T3,ED.211,(F)	;GET TO-11 SECTION ADDRESS
	MOVEM	T1,ETCSTS(T3)	;DO SAME FOR TO-11 SECTION STATUS
	CAIE	T2,.MMCB	;ARE WE RUNNING MCB PROTOCOL?
	JRST	STXPP1		;NO, SKIP THIS STUFF

	MOVEI	T1,CLRDTE	;RESET DTE
	XCT	ETDCNO(F)	;DO IT
	SETZM	DTEEPW(T4)	;CLEAR VALID EXAMINE
	SETZM	DTETBP(T4)	; AND BYTE POINTERS IN CASE
	SETZM	DTEEBP(T4)	; . . .
	MOVEI	T1,TO11DB	;RING 11'S DOORBELL TO TELL HIM
	XCT	ETDCNO(F)	;RING

STXPP1:	PUSH	P,T4		;SAVE T4
	LOAD.	T3,ED.10A,(F)	;POINT TO 10'S COMM AREA
	LOAD.	T4,ED.11A,(F)	;POINT TO 11'S COMM AREA

	SETZ	T1,		;INITIALIZE VERSION TYPES
	CAIE	T2,.M20F	;OLD STYLE?
	MOVEI	T1,.CVMCB	;NO, USE MCB COMM REGION VERSION
	STOR.	T1,EC.CVR,(T3)	;STORE IT IN COMM REGION VERSION FIELD
	STOR.	T1,EC.CVR,(T4)	;DO IT FOR TO-11 ALSO

	CAIE	T2,.M20F	;OLD STYLE?
	MOVEI	T1,.PVMCB	;NO, USE MCB'S PROTCOL VERSION
	STOR.	T1,EC.PVR,(T3)	;STORE IN TO-10 FIELD
	STOR.	T1,EC.PVR,(T4)	;STORE IN TO-11 FIELD

	LOAD.	T2,ED.PNE,(F)	;11 PROTOCOL PROCESSOR NUMBER
	MOVNI	T3,1(T2)	;GET OFFSET RELATIVE TO BEGINNING
				; OF COMM REGION
	MOVEI	T1,ETCRGN##(T3)	;GET ACTUAL ADDRESS THAT THIS 11
				; WANTS TO BEGIN WINDOW AT
	POP	P,T4		;GET BACK EPT POINTER
	MOVEM	T1,DTEERW(T4)	;THIS IS EXAMINE RELOCATION WORD
	LOAD.	T1,ED.11A,(F)	;GET ADDRESS OF THIS 11'S AREA

	SETZM	ETCKAC(T1)	;START WITH ZERO FOR ITS KEEP ALIVE
	SETZM	ETDKAR(F)	;AND 10'S REMEMBRANCE OF IT

	MOVEM	T1,DTEDRW(T4)	;DEPOSIT RELOCATION WORD
				;HERE COMES THE TRICKY PART . . .
	LOAD.	T2,EC.OSZ,(T1)	;GET SIZE OF 11'S SECTION OF 11'S AREA
	CAIN	T2,ETOSIZ	;DOES THIS ALLOW THE -11 TO TALK TO US?
	ADDI	T2,ET2SIZ	;NO--FIX IT
	ASH	T2,3		;CONVERT SIZE OF OWNERS SECTION TO WORDS
	MOVEM	T2,DTEDPW(T4)	;THAT'S THE DEPOSIT PROTECTION
				;***OFF BY ONE??***
				;EXAMINE PROTECTION WORD IS LAST
	LOAD.	T2,ED.PNE,(F)	;GET PROTOCOL PROCESSOR NUMBER
				; (ASSUME HEADER IS SET UP WITH ALL OF THEM, AND INCREASING
	MOVEI	T1,ETCSIZ##+1(T2);SIZE OF ENTIRE REGION
	MOVEM	T1,DTEEPW(T4)	;NOW 11 WILL THINK Q PROTOCOL IS IN EFFECT
	MOVEI	T1,ED.EID	;MAKE TO-11 DTE STATE IDLE
	STOR.	T1,ED.2ES,(F)
	PUSHJ	P,DTETID	;MAKE TO-10 SIDE OF DTE IDLE

	LOAD.	T1,ED.CUR,(F)	;DON'T LET CORE DISAPPEAR
	SKIPE	T1
	STOPCD	.,STOP,DTEQEF,DTEPDI, ;++QUEUE ENTRY FULL
	LOAD.	T1,ED.QUE,(F)	;DON'T LET CORE DISAPPEAR
	SKIPE	T1
	STOPCD	.,STOP,DTETQP,DTEPDI, ;++FOUND QUEUE POINT

	MOVSI	T1,(ED.DTM)	;IS THIS THE MASTER?
	TDNN	T1,ETDSTS(F)	;?
	JRST	STXPP2		;NO, JUST RING DOORBELL

	MOVE	T1,[MC1120,,C1120F] ;POINT TO CAL11. UUO VECTOR
	PUSHJ	P,C11VEC	;SET UP BASE TABLE
	PUSHJ	P,SPCGSF	;GET FLAGS INTO .CPSPF
	MOVEI	T1,DT.LSP!DT.RST;LEAVE SECONDARY PROTOCOL, RESET COMM REGION
	PUSHJ	P,SPCMD		;DO IT
	MOVSI	T1,(ED.SPC!ED.PPP) ;TURN OFF SECONDARY PROTOCOL BIT IF IT WAS ON
	ANDCAM	T1,ETDSTS(F)	;TURN OFF JUST BEFORE ENABLING PI ASSIGNMENT
	MOVSI	T1,(ED.PPC)	;SET PRIMARY PROTOCOL BIT SO
				; INTERRUPTS WILL GO TO RIGHT PLACE
	IORM	T1,ETDSTS(F)	;PUT INTO STATUS
	SKIPE	T1,.CPTMF##	;SEE IF CLOCK TICKED?
	MOVEI	T1,1		;MAINTAIN NON-ZERO FLAG
	MOVEM	T1,.CPTMF##	;RESET TICKS SINCE LAST KEEP ALIVE UPDATE
	MOVEI	T1,PI0ENB+PILDEN+PPCPI	;SETUP PI STATUS PROPERLY
	XCT	ETDCNO(F)	;DO CONO DTEX,(T1)
	MOVEI	P2,.EM2EI	;TO-11 INITIAL MESSAGE FUNCTION
				;DEVICE CODE DOESNT MATTER
	LOAD.	P3,ED.ATN,(F)	;GET NUMBER OF ASYNCHRONOUS TTY LINES ON THIS 11
	MOVSI	T1,(ST.CYC)	;GET 50HZ BIT
	TDNE	T1,STATES##	;IS IT 50HZ?
	TRO	P3,EM.50C	;YES, TELL 11
	SETZ	P4,		;NO POINTER
	S0PSHJ	DTEQUE		;SEND THE MESSAGE
	  POPJ	P,		;NO GOOD, GIVE ERROR RETURN
	PUSHJ	P,DTESDT	;SEND DATE/TIME TO -11
	SETZB	P3,S		;CLEAR JUNK
	MOVE	P2,[XWD .EMCLK,.EMRDT] ;REQUEST DATE AND TIME
	MOVX	T1,ED.SAL	;START-ALL FLAG
	TDNE	T1,ETDSTS(F)	;ONLY SEND THIS IF SET
	S0PSHJ	DTEQUE		;SEND THIS MESSAGE (S, P1 & P4 STILL SETUP)
	  JFCL			;SHOULDN'T FAIL
	MOVE	P2,DEBUGF##	;GET DEBUG BIT
	LSH	P2,-^D35	;RIGHT-JUSTIFIED
	DPB	P2,[POINT 1,ETDSTS(F),^L<ED.DBG>] ;SAVE FE DEBUG MODE
	MOVN	P2,P2		;STUPID FUNCTIONS WERE ASSIGNED BACKWARDS
	MOVEI	P2,.EMDBF(P2)	;GET FUNCTION TO PERFORM
	S0PSHJ	DTEQUE		;SET/CLEAR FE DEBUG MODE AS PER DEBUGF
	  POPJ	P,		;SIGH....
	JRST	CPOPJ1##	;AND GIVE SKIP RETURN
STXPP2:	LOAD.	T3,ED.211,(F)	;POINT TO 11 REGION
	LOAD.	T2,EC.PRT,(T3)	;GET PROTOCOL TYPE
	CAIN	T2,.MMCB	;IS IT THE MCB PROTOCOL?
	JRST	STXQP2		;START IT UP
	MOVSI	T1,(ED.PPC)	;SET PRIMARY PROTOCOL FLAG
	IORM	T1,ETDSTS(F)
	MOVEI	T1,TO11DB+PI0ENB+PILDEN+PPCPI
				;RING DOORBELL, ASSIGN PI STUFF
	XCT	ETDCNO(F)	;RING 11 DOORBELL FOR RESTRICTED 11
	HLRZ	T1,P1		;ISOLATE CPU #
	SKIPN	T2,@DTEFEK##(T1)	;SEE IF A FEK FOR THIS DTE
	RETSKP			;IF NO FEK, GET OUT NOW
	MOVEI	T1,FF.UP	;GET THE "11 UP" FUNCTION CODE
	XCT	FEKDSP(T2)	;TELL SOMEONE HIS 11 IS THERE
	RETSKP			;GIVE GOOD RETURN

STXPP3:	LOAD.	T2,ED.11A,(F)	;GET 11'S AREA HEADER ADDRESS
	LOAD.	T1,EC.CVR,(T2)	;GET COMM. REGION VERSION
	JUMPN	T1,DTECLR	;FAIL IF -11 DIDN'T CLEAR IT
	LOAD.	T2,EC.PVR,(T2)	;OK--GET LINE-USER TYPE INDEX
	PUSHJ	P,DFKSET	;SETUP FOR OUR PREFERRED STYLE
	JUMPE	T2,DTECLR	;FAIL IF WE DIDN'T REALLY SET A TYPE
	MOVEI	T1,.M20F	;PROTOCOL TYPE FOR NON-MCB
	LOAD.	T2,ED.211,(F)	;GET TO-11 ADDRESS
	STOR.	T1,EC.PRT,(T2)	;MAKE SURE WE KNOW IT'S NOT AN MCB
	MOVEI	T1,CLRDTE+PILDEN+0 ;BITS TO SILENCE A DTE
	XCT	ETDCNO(F)	;QUIET THE -11 BEFORE WE TRY AGAIN
	JRST	STXPP0		;AND THEN TRY IT AGAIN
;STXQP2 -- ROUTINE TO START QUEUED PROTOCOL V. 2 ON A DTE

	MCINI1==^D5		;WAIT THIS LONG ON FIRST PASS
	MCINI2==^D3		;NOT AS LONG FOR SECOND

STXQP2:	MOVE	T1,[MC11MC,,C11MCB] ;POINT TO CAL11. UUO VECTOR
	PUSHJ	P,C11VEC	;SET UP BASE TABLE
	MOVEI	T1,<ETOSIZ+ET2SIZ>*10 ;GET SIZE OF DEPOSIT WINDOW
	MOVEM	T1,DTEDPW(T4)	; AND STORE IT IN EPT

	LOAD.	T2,ED.11A,(F)	;GET POINTER TO 11 OWNING SECTION
	LOAD.	T3,ED.10A,(F)	; AND 10'S
	MOVEI	T1,2		;MCB IS ALWAYS SIZE TWO (MAGIC)
	STOR.	T1,EC.OSZ,(T2)	;STORE IT
	STOR.	T1,EC.OSZ,(T3)

	LOAD.	T3,ED.211,(F)	;PTR TO TO11 REGION
	LOAD.	T4,ED.210,(F)	;PTR TO TO10 REGION

	SETZM	ETCQSZ(T3)	;ZERO THESE TWO DYNAMIC WORDS
	SETZM	ETCQSZ(T4)

	MOVSI	T1,(EC.INI!EC.VEX) ;SET INI AND VEX (VALID EXAMINE)
	MOVEM	T1,ETCSTS(T3)	;LIGHT THEM
	MOVEI	T1,PILDEN+PI0ENB+TO11DB ;ENABLE DTE AND RING 11'S DOORBELL
	XCT	ETDCNO(F)	;DO IT

	MOVEI	P2,MCINI1	;TIME TO WAIT
	PUSHJ	P,WAITDB	;WAIT FOR IT
	  POPJ	P,		;ERROR - INITIALIZATION FAILURE
	MOVE	T2,ETCSTS(T4)	;GET THE STATUS WORD
	TLNN	T2,(EC.INI)	;DID HE SET THE INI BIT?
	POPJ	P,		;GIVE FAILURE RETURN
	MOVEI	T1,CL11PT	;CLEAR TO-10DB
	XCT	ETDCNO(F)	;DO IT
	LOAD.	T1,EC.PRT,(T4)	;GET DESIRED PROTOCOL TYPE
	CAIN	T1,.M20F	;IS IT BACK TO RSX20F (ANF/DN60)?
	JRST	STXPP3		;YES--GO FIX IT UP
	PUSH	P,T3		;SAVE A REGISTER
	PUSH	P,T4		;OR TWO
	MOVEI	T2,DD.DEC	;LINE-USER OF DECNET
	CAME	T2,ETDUSR(F)	;IF WE DIDN'T KNOW BEFORE,
	PUSHJ	P,DFKSET	;WE DO NOW
	POP	P,T4		;RESTORE TO-10 POINTER
	POP	P,T3		;AND TO-11 POINTER
	JUMPE	T2,DTECLR	;FAIL IF CAN'T SET LINE-USER OF 'DECNET'
	MOVX	T1,ED.SAL	;START-ALL BIT
	TDNE	T1,ETDSTS(F)	;WAS IT?
	PJRST	DTECLR		;YES--WAIT FOR NML TO START AN MCB
	MOVSI	T1,(EC.INI)	;THIS IS THE INI BIT
	ANDCAM	T1,ETCSTS(T3)	;CLEAR IT
	MOVEI	T1,TO11DB	;TO-11 DOORBELL
	XCT	ETDCNO(F)	;RING IT

	MOVEI	P2,MCINI2	;LENGTH OF TIME TO WAIT
	PUSHJ	P,WAITDB	;WAIT FOR IT
	  POPJ	P,		;ERROR - INITIALIZATION FAILURE
	MOVE	T2,ETCSTS(T4)	;GET THE STATUS WORD
	TLNE	T2,(EC.INI)	;WAS THIS LIT?
	POPJ	P,		;GIVE FAILURE RETURN
	MOVSI	T1,(ED.MAI!ED.PPP) ;WE ARE OUT OF MAINT MODE
	ANDCAM	T1,ETDSTS(F)	;SHOW THIS
	MOVSI	T1,(ED.IPU)	;ALSO INDICATE THAT WHEN WE GET THE
	IORM	T1,ETDSTS(F)	; INTERRUPT FOR THIS DTE, WE HAVE TO
				; GIVE LINE'S USER A PROTOCOL UP
	MOVEI	T1,ETDQUE-MB.NXT(F) ;GET PSEUDO MB ADDRESS SO THAT NEXT STOR.
	STOR.	T1,ED.LST,(F)	; TO ED.LST WILL SET UP ED.QUE
;If we are not doing gather reads, we will get a piece of free core to
; use for doing the transfer in section zero.  When the message block is
; ready to be transfered, it is copied into this block from a possibly
; extended section.

	LOAD.	T1,ED.OBK,(F)	;GET PTR TO OUTPUT BLOCK
	JUMPN	T1,STXQP3	;JUMP IF WE ALREADY HAVE ONE
	MOVEI	T2,UBLSIZ	;WE NEED BLOCKS THIS BIG
	ADDI	T2,SIZE(.EQLEN,36) ;LITTLE ROOM FOR THE HEADER
	PUSH	P,T2		;SAVE THIS SIZE
	PUSHJ	P,MESCOR	;GET A PIECE OF BIG
	  JRST	TPOPJ##		;FIX STACK AND RETURN
	STOR.	T1,ED.OBK,(F)	;STORE THE POINTER TO IT
	POP	P,T2		;RESTORE THE SIZE
	STOR.	T2,EQ.SIZ,(T1)	;SAVE IT
STXQP3:
	LOAD.	T1,ED.IBK,(F)	;GET PTR TO INPUT BLOCK
	JUMPN	T1,STXQP4	;JUMP IF WE ALREADY HAVE ONE
	MOVEI	T2,UBLSIZ	;MAXIMUM SIZE BLOCK FOR INPUT
	ADDI	T2,SIZE(.EQLEN,36) ;LITTLE ROOM FOR THE HEADER
	PUSH	P,T2		;SAVE THIS SIZE
	PUSHJ	P,MESCOR	;GET A PIECE OF BIG
	  JRST	TPOPJ##		;FIX STACK AND RETURN
	STOR.	T1,ED.IBK,(F)	;STORE THE POINTER TO IT
	POP	P,T2		;RESTORE THE SIZE
	STOR.	T2,EQ.SIZ,(T1)	;SAVE IT
STXQP4:

;Here we start the DTE and set ourselves up for interrupts.
;All setup code must be done before this.

	MOVEI	T1,PI0ENB+PILDEN+PPCPI ;SET PI STATE
	XCT	ETDCNO(F)	;DO CONO DTEX,(T1)
	JRST	CPOPJ1##	;GIVE GOOD RETURN
;PPUINT IS CALLED FROM DTEINT ON THE FIRST DTE INTERRUPT AFTER STXQP2
;HAS FINISHED SETTING UP FOR PRIMARY PROTOCOL.  IT WILL CALL THE USER OF
;THE LINE TO INDICATE THAT THE PROTOCOL IS UP.

PPUINT:	MOVSI	T1,(ED.IPU)	;TURN OFF "GIVE PROTOCOL UP INTERRUPT"
	ANDCAM	T1,ETDSTS(F)
	MOVSI	T1,(ED.PPC)	;WE CAN NOW SAY WE ARE IN PRIMARY PROTOCOL
	IORM	T1,ETDSTS(F)	;TURN IT ON
	MOVSI	T1,(ED.LLS)	;GET LINE STATE REPORTED FLAG
	TDNE	T1,ETDSTS(F)	;WAS LAST LINE STATE REPORTED AS UP?
	POPJ	P,		;YES, RETURN
	IORM	T1,ETDSTS(F)	;MARK LAST STATE REPORTED AS UP
	MOVEI	T1,DI.LSC	;SIGNAL A PROTOCOL UP RIGHT AWAY
	MOVEI	T3,LS.ON	;NEW LINE STATE OF ON
	PJRST	CALUSR		;CALL DTE USER AND RETURN
;ROUTINE TO TEMPORARILY LEAVE PRIMARY PROTOCOL AND ENTER SECONDARY
; PROTOCOL ON THE MASTER 11 OF CALLING CPU.  WORKS LIKE P AC SAVE
; ROUTINES, IN THAT PUSHJ TO SAVPPC WILL CAUSE SECONDARY PROTOCOL
; TO RUN, AND WHEN CALLING ROUTINE DOES A POPJ, PRIMARY PROTOCOL
; IS RESTORED.  USED IN PARITY SCAN ROUTINES, DIE, AND ANYWHERE
; ELSE THAT NEEDS SECONDARY PROTOCOL TEMPORARILY.
; NOTE THAT THE MASTER DTE'S PI ASSIGNMENT IS CLEARED SO THAT
; THE INTERRUPT SYSTEM IS NOT USED.  THEREFORE THE CALLER IS RESPONSIBLE
; TO WAIT FOR EVENTS THAT WOULD OTHERWISE GIVE INTERRUPTS (TRANSMIT DONE, ETC.)
; IF PI ASSIGNMENT WAS LEFT ON, INTERRUPT SERVICE MIGHT STEAL SECONDARY
; PROTOCOL DONE FLAG FROM ORIGINAL LEVEL.
;
; IF SECONDARY PROTOCOL IS ALREADY RUNNING, THIS ROUTINE IS A NO-OP.
; RESPECTS ALL ACS EXCEPT T1,T2,T3

SVPPC::	EXCH	F,(P)		;SAVE OLD C(F) ON STACK GET CALLING PC
	PUSH	P,T4		;SAVE T4
	MOVE	T3,F		;SAVE CALLING PC IN T3
	PUSHJ	P,GTEPD		;GET ETD ADDRESS IN F, EPT IN T4
	LOAD.	T2,ED.DTN,(F)	;COMPUTE OFFSET TO THE PROPER DTE
	ASH	T2,3		;*8
	ADD	T4,T2		;ADD TO EPT ADDRESS
	MOVSI	T2,(ED.PPC)	;IS THERE ANYTHING TO SAVE?
	TDNN	T2,ETDSTS(F)	;SKIP IF SO
	JRST	SVPP2		;NOT, QUIT RIGHT NOW
	PUSH	P,DTEEPW(T4)	;SAVE EXAMINE PROTECTION WORD
	PUSHJ	P,ENTSPC	;ENTER SECONDARY PROTOCOL
	MOVEI	T1,PILDEN+0	;CLEAR OUT PI ASSIGNMENT
	XCT	ETDCNO(F)	;CONO DTEN,(T1)
	MOVSI	T4,F20LPP##	;LOST PROTOCOL
	IORM	T4,.CP20F##	;LIGHT FOR TTDINT
	MOVE	T4,-1(P)	;GET OLD CONTENTS OF T4
	MOVE	F,-2(P)		; AND OLD CONTENTS OF F
	PUSHJ	P,(T3)		;CALL THE CALLER
	  CAIA			;NON-SKIP RETURN
	AOS	-3(P)		;SKIP RETURN
	PUSHJ	P,GTEPD		;SETUP F AND T4 AGAIN. NO NEED TO SAVE
	POP	P,DTEEPW(T4)	;RESTORE OLD EXAMINE PROTECTION WORD
	MOVEI	T1,PILDEN+0	;TURN OFF DTE FOR A WHILE
	XCT	ETDCNO(F)	;DO IT
	MOVEI	T1,DT.LSP	;ENTER PRIMARY PROTOCOL, NO RESET
	PUSHJ	P,SPCMD		;LEAVE
	MOVSI	T1,(ED.PPC)	;MARK PRIMARY PROTOCOL NOW
	IORM	T1,ETDSTS(F)
	MOVSI	T1,(ED.SPC)	;AND TURN OFF SECONDARY
	ANDCAM	T1,ETDSTS(F)
	MOVEI	T1,PILDEN+PI0ENB+PPCPI;PRIMARY PI ASSIGNMENT
	XCT	ETDCNO(F)	;DO IT
SVPP1:	POP	P,T4		;T4
	PJRST	FPOPJ##		;RESTORE F
				; AND RETURN WITH OLD PROTOCOL RUNNING
SVPP2:	PUSHJ	P,ENTSPC	;ENTER SECONDARY PROTOCOL JUST IN CASE
	POP	P,T4
	POP	P,F		;RESTORE F, T4
	JRST	(T3)		;AND RETURN TO CALLER'S PC IMMEDIATELY
;ROUTINE TO CAUSE THE MASTER -11 TO RELOAD THE -10
;THIS IS INTENDED TO BE CALLED PRIOR TO EXECUTING A HALT INSTRUCTION
;OR WHEN THE BOOTSTRAP IS NOT AVAILABLE FOR RELOADING THE MONITOR.
;CALL:	PUSHJ	P,LOAD10
;
; *** RETURNS IN PRIMARY PROTOCOL ***

LOAD10::PUSHJ	P,SVEPTD	;SAVE F, T4, AND SETUP DTE & EPT ADDRESSES
	SKIPE	DTEEPW(T4)	;ALREADY IN PRIMARY PORTOCOL?
	SKIPN	T1,ETDKAR(F)	;GET SAVED EXAMINE PROTECTION WORD
	JRST	LOAD1A		;ALREADY IN PP OR NO SAVED EPW
	MOVEM	T1,DTEEPW(T4)	;TURN ON VALID EXAMINE
	MOVEI	T1,DT.LSP	;BIT TO LEAVE SECONDAY PROTOCOL (ENTER PRIMARY)
	SETZM	DTEFLG(T4)	;CLEAR DONE FLAG
	MOVEM	T1,DTECMD(T4)	;STUFF COMMAND WHERE -20F WILL FIND IT
	MOVEI	T1,TO11DB	;DOORBELL
	XCT	ETDCNO(F)	;TELL -20F TO ENTER PRIMARY PROTOCOL
LOAD1A:	MOVX	T1,EC.LOD	;GET THE LOAD BIT
	IORM	T1,ETCSTS(F)	;SET FOR THE -11 TO READ
	MOVEI	T1,TO11DB	;DOORBELL
	XCT	ETDCNO(F)	;REQUEST A DUMP/LOAD SEQUENCE
	POPJ	P,		;RETURN
;LOOP OVER EACH DTE AND CALL A SUBROUTINE
;CALL:	MOVE	T1, SUBROUTINE ADDRESS
;	PUSHJ	P,DTEAPP

DTEAPP::PUSHJ	P,SSEC0##	;RUN IN SECTION ZERO
	PUSHJ	P,SAVE1##	;SAVE P1
	PUSH	P,F		;SAVE F
	PUSH	P,T1		;SAVE SUBROUTINE ADDRESS
	MOVSI	P1,-4		;AOBJN POINTER
DTEAP1:	HRLZ	F,.CPCPN##	;CPU NUMBER
	HRR	F,P1		;DTE NUMBER
	PUSHJ	P,GETETD	;FIND ETD BLOCK
	  SKIPA			;NOT THERE
	PUSHJ	P,@(P)		;CALL SUBROUTINE
	  JFCL			;IGNORE ERRORS
	AOBJN	P1,DTEAP1	;LOOP FOR ALL DTES
	POP	P,(P)		;PHASE STACK
	POP	P,F		;RESTORE F
	POPJ	P,		;RETURN
;ROUTINE TO INITIATE A PROTOCOL PAUSE
;CALL WITH THE PI SYSTEM OFF TO PREVENT SOME NASTY RACES
;
;NOTE THAT THE -11 WILL KEEP A TIMER RUNNING ON US, AND WILL CAUSE A
;RELOAD 30 SECONDS AFTER WE ENTER PROTOCOL PAUSE.

DTESPP::SKIPE	DINITF##	;SYSTEM STARTUP?
	POPJ	P,		;THIS IS A NOOP
	MOVEI	T1,SETPP	;ROUTINE TO EXECUTE
	PJRST	DTEAPP		;SET PROTOCOL PAUSE

SETPP:	MOVSI	T1,(ED.PPC)	;ONLY DO THIS IF ACTUALLY IN PRIMARY PROTOCOL
	TDNN	T1,ETDSTS(F)
	POPJ	P,		;NOT IN PRIMARY PROTOCOL, THIS IS A NO-OP
	LOAD.	T4,ED.DTN,(F)	;GET DTE NUMBER
	ASH	T4,3		;TIMES 8
	ADD	T4,.CPEPT##	;INDEX INTO THE EPT
	SETZM	DTECMD(T4)	;ENSURE THAT -20F DOESN'T SEE "ENTER SECONDARY"
	MOVE	T1,DTEEPW(T4)	;COPY OLD PROTOCOL STATUS
	LOAD.	T2,ED.DTN,(F)	;GET DTE # OF THIS FRONT END
	MOVEM	T1,.CPEPW##(T2)	;SAVE FOR LATER
	SETZM	DTEEPW(T4)	;INITIATE A PROTOCOL PAUSE
	MOVEI	T1,TO11DB	;SET DOORBELL TO GET -11'S ATTN
	SKIPE	.CPEPW##(T2)	; ... UNLESS IT'S IGNORING US ALREADY
	XCT	ETDCNO(F)	;TELL IT TO IGNORE US FOR A WHILE
	MOVX	T1,ED.PPP	;PROTOCOL-PAUSE STATUS BIT
	IORM	T1,ETDSTS(F)	;REMEMBER FOR LATER
	POPJ	P,		;RETURN PREVIOUS STATE


;ROUTINE TO TERMINATE PROTOCOL PAUSE

DTERPP::SKIPE	DINITF##	;SYSTEM STARTUP?
	POPJ	P,		;THIS IS A NOOP
	MOVEI	T1,CLRPP	;ROUTINE TO EXECUTE
	PJRST	DTEAPP		;CLEAR PROTOCOL PAUSE

CLRPP:	MOVX	T1,ED.PPP	;PROTOCOL-PAUSE STATUS BIT
	TDNN	T1,ETDSTS(F)	;DID WE SET IT?
	POPJ	P,		;NO--NO NEED TO CLEAR IT
	ANDCAM	T1,ETDSTS(F)	;YES--CLEAR IT OUT
	LOAD.	T4,ED.DTN,(F)	;GET DTE NUMBER
	ASH	T4,3		;TIMES 8
	ADD	T4,.CPEPT##	;INDEX INTO THE EPT
	LOAD.	T2,ED.DTN,(F)	;GET DTE # OF THIS FRONT END
	MOVE	T1,.CPEPW##(T2)	;GET OLD EPW
	MOVEM	T1,DTEEPW(T4)	;RESTORE PRIMARY PROTOCOL
	MOVEI	T1,TO11DB	;TELL -11 WE'RE BACK
	SKIPE	DTEEPW(T4)	; ... UNLESS WE'RE NOT (SNH)
	XCT	ETDCNO(F)	;RING THE 'OLE BELL
	POPJ	P,		;DONE
;ROUTINE TO CHECK TO SEE IF MASTER IS RUNNING PRIMARY PROTOCOL
; CALL IS
;	PUSHJ	P,SKPMPP##	;SKIP IF MASTER RUNNING PRIMARY PROTOCOL
;	  <NOT>
;	<IS>

SKPMPP::PUSHJ	P,SVEPTD	;SAVE F,T4 & GET MASTER DTE'S CTL BLOCK ADDRESS
	MOVSI	T4,(ED.PPC)	;DON'T NEED EPT ADDRESS, USE SAVED T4
	TDNE	T4,ETDSTS(F)	;IS IT PRIMARY?
	AOS	(P)		;YES
	POPJ	P,		;RETURN THE RIGHT WAY


;ROUTINE TO CHECK TO SEE IF THE MASTER IS OK.
; CALL IS:
;	PUSHJ	P,SKPMRN
;	 <NOT - AT LEAST MARKED AS NEEDING RELOADING>
;	<IS>

SKPMRN::PUSHJ	P,SVEPTD	;SAVE F,T4; GET MASTER CTL BLOCK ADDRESS
	MOVSI	T4,(ED.RLD)	;GET NEEDS RELOADING BIT
	TDNN	T4,ETDSTS(F)	;DOES IT?
	AOS	(P)		;NO, GIVE SKIP RETURN
	POPJ	P,		;RETURN
SUBTTL ONCE PER SECOND ACTIVITIES

DTESEC::PUSH	P,F		;SAVE FOR DTE CONTROL BLOCK
	HRLZ	T4,.CPCPN##	;START WITH FIRST DTE ON THIS CPU
DTESC1:	MOVE	F,T4		;GET NEXT DTE # '' CPU #
	PUSHJ	P,GETETD	;GET DTE CONTROL BLOCK ADDRESS
	  JRST	FPOPJ##		;DONE

	MOVE	T1,ETDSTS(F)	;GET STATUS OF DTE
	TLNN	T1,(ED.PPC)	;RUNNING PRIMARY PROTOCOL?
	AOJA	T4,DTESC1	;NO, DON'T BOTHER WITH THE REST

	LOAD.	T2,ED.10A,(F)	;GET ADDRESS OF 10'S COMM AREA
	TLNE	T1,(ED.DTM)	;IS THIS THE MASTER DTE?
	AOS	ETCKAC(T2)	;YES, INCREMENT THIS CPU'S KEEP ALIVE
				; ONLY ONCE PER CALL TO THIS ROUTINE.
				; NOTE THAT WE INCREMENT KEEP ALIVE
				; EVEN IF -11 IS SICK IF ITS RUNNING
				; PRIMARY PROTOCOL. THIS IS IN CASE
				; THE -11 IS STILL WELL ENOUGH TO LOOK

	TLNE	T1,(ED.RLD)	;IS THIS -11 SICK?
	AOJA	T4,DTESC1	;YES, DON'T OVERWRITE THE LAST CRASH PC
				; WITH PC FROM HERE
	LOAD.	T2,ED.11A,(F)	;GET ADDRESS OF 11'S COMM AREA
	MOVE	T3,ETCKAC(T2)	;GET 11'S KEEP ALIVE COUNT
	CAME	T3,ETDKAR(F)	;DIFFERENT THAN OUR COPY?
	JRST	[SETZM	ETDKAN(F)	;YES, RESET THE HUNG COUNTER
		 MOVEM	T3,ETDKAR(F) ;REMEMBER NEW LAST VALUE
		 AOJA	T4,DTESC1] ;AND GO TO NEXT DTE

	AOS	T1,ETDKAN(F)	;NO, GET HUNG COUNTER VALUE
	CAIG	T1,.EDKAE	;HAS IT PASSED MAXIMUM VALUE?
	AOJA	T4,DTESC1	;NOT YET, GO TO NEXT DTE
	PUSH	P,T4		;SAVE WHERE WE WERE
	MOVEI	T1,.+1		;SET T1 UP TO BE PC
	PUSHJ	P,DTERLD	;RELOAD THIS DTE
	POP	P,T4		;RESTORE DTE NUMBER
	AOJA	T4,DTESC1	;LOOP
SUBTTL CORE ALLOCATION

;CALL MESCOR WITH NUMBER OF WORDS DESIRED IN T2
; IF CANT ALLOCATE CORE, RETURN CPOPJ WITH SIZE OF BIGGEST HOLE IN ??
; RETURN CPOPJ1 WITH ADDRESS OF CORE IN T1
; CORE IS CLEARED.
; SEE GETWDS IN CORE1

MESCOR:	PUSH	P,T2		;SAVE ARG FOR BLT
	PUSHJ	P,GETWDS##	;GET SOME CORE
	  JRST	TPOPJ##		;THROW AWAY SAVED ARG AND RETURN
	POP	P,T2		;RESTORE NUMBER OF WORDS
	HRL	T3,T1		;ADDRESS OF CORE IN LH(T3)
	HRRI	T3,1(T1)	;ADDRESS + 1 IN RH(T3)
	MOVE	T4,T1		;COPY OF ADDRESS
	ADDI	T4,-1(T2)	;LAST ADDRESS TO CLEAR
	SETZM	(T1)		;CLEAR FIRST WORD
	BLT	T3,(T4)		;CLEAR THE REST
	JRST	CPOPJ1##	;RETURN CPOPJ1 WITH ADDRESS IN T1


;CALL GIVMES WITH ADDRESS OF CORE IN T2, SIZE IN T1
; ALWAYS RETURNS CPOPJ
GIVMES==GIVWDS##		;DITTO


;ROUTINE TO ALLOCATE TO-10 DTE BUFFER USING ED.BSZ, STORE ADDRESS
; OF BUFFER IN ED.BUF, RETURN THE ADDRESS IN T1.
; CALL WITH ETD ADDRESS IN F, NUMBER OF 8 WORD BYTES TO ALLOCATE IN T2.
; STOPCODE IF
; A TO-10 DTE BUFFER IS ALREADY ALLOCATED.  SKIP RETURN
; IF SUCCESSFUL, NON-SKIP IF WE RAN OUT OF CORE.

T10GTC:	MOVSI	T1,(ED.TBA)	;GET TO-10 DTE BUFFER IS ALLOCATED BIT
	TDNE	T1,ETDBUF(F)	;IS IT THERE?
	STOPCD	.,STOP,DTEBAA,DTEPDI, ;++BUFFER ALREADY THERE
	IORM	T1,ETDBUF(F)	;NO, ITS GOING TO BE
	ADDI	T2,^D36/^D8-1	;ROUND UP TO NEXT WHOLE 36 BIT WORD
	ASH	T2,-2		;/4 = NUMBER OF 36 BIT WORDS
	STOR.	T2,ED.BSZ,(F)	;REMEMBER TO-10 BUFFER SIZE
	PUSHJ	P,GETWDS##	;GET THAT MUCH
	  POPJ	P,		;LOSE
	STOR.	T1,ED.BUF,(F)	;REMEMBER WHERE IT IS
	JRST	CPOPJ1##	;AND SUCCEED
;ROUTINE TO RELEASE TO-10 DTE BUFFER. CALL WITH ETD ADDRESS IN F.
; ALWAYS GIVES NON-SKIP RETURN. OK TO CALL IF TO-10 DTE BUFFER DOESNT
; EXIST.

T10RLC:	MOVSI	T1,(ED.TBA)	;GET TO-10 BUFFER ALLOCATED BIT
	TDNN	T1,ETDBUF(F)	;DOES IT EXIST?
	POPJ	P,		;NO, NO WORK TO DO
	ANDCAM	T1,ETDBUF(F)	;YES, SAY ITS GONE NOW
	LOAD.	T1,ED.BSZ,(F)	;GET SIZE TO DEALLOCATE
	LOAD.	T2,ED.BUF,(F)	;AND ADDRESS
	PJRST	GIVWDS##	;GOODBY.
SUBTTL CPU REMOVAL CODE FOR DTESER

; THIS ROUTINE WILL CLEAR OUT ALL THE DTES ON A GIVEN CPU.  IT CAN BE CALLED ON
; ANY CPU FOR ANY CPU.  ITS MAIN PURPOSE IS TO RELEASE ALL CHUNKS OF CORE
; WHICH HAVE BEEN ALLOCATED TO THOSE DTES.  THIS INCLUDES QUEUED UP OUTPUT
; BUFFERS, SECTION ZERO TRANSFER BUFFERS, AND ANYTHING ELSE THAT TAKES UP
; LOTS OF SPACE.
;
; CALL:	MOVx	T1,CPU#
;	PUSHJ	P,KILDTE##

KILDTE::
	PUSHJ	P,SAVE1##		;SAVE A P
	PUSH	P,F			;SAVE F
	HRLZ	P1,T1			;SAVE CPU,,DTE#
KILDT1:	TRNE	P1,777774		;DID WE OVERFLOW?
	 PJRST	 FPOPJ##		; YES, RETURN NOW
	MOVE	F,P1			;GET CPU,,DTE INTO F
	PUSHJ	P,GETETD		;GET ADDRESS OF ETD
	 AOJA	 P1,KILDT1		; NON-EXISTANT
	LOAD.	T2,ED.211,(F)		;GET THE TO-11 SECTION
	LOAD.	T2,EC.PRT,(T2)		;GET THE PROTOCOL TYPE
	CAIN	T2,.MMCB		;TALKING DECNET?
	PUSHJ	P,DTECLK		;KILL THE DTE
	AOJA	P1,KILDT1		;NEXT DTE PLEASE
SUBTTL 11 DUMP AND RELOAD CONTROL

;ROUTINE TO CLEAR OUT A DTE REGARDLESS OF WHAT ITS DOING
; CALL WITH DTE CONTROL BLOCK ADDRESS IN F
; GIVES PHONEY POSTS TO ALL DRIVERS WHICH HAD PENDING TO-11
; MESSAGES, WHICH SHOULD BE THE SAME AS THOSE MESSAGES ACTUALLY GETTING
; TO THE 11 JUST BEFORE IT DIES.
; ALL TO-11 MESSAGE CORE IS DEALLOCATED, DTE STATE IS CLEARED,
; 11 IS TAKEN OUT OF PRIMARY PROTOCOL IF IT IS THERE.  PRESENCE OF
; TO-10 MESSAGES ARE IGNORED.

DTECLR::PUSHJ	P,SSEC0##	;MAY BE CALLED BY DECnet IN NON-ZERO SECTION

	LOAD.	T1,ED.CPN,(F)	;GET THE CPU NUMBER OF THIS DTE
	CAME	T1,.CPCPN##	;ARE WE ON THE CORRECT CPU?
	 STOPCD	 CPOPJ,DEBUG,DTEDWC ;++DTECLR CALLED ON WRONG CPU
	MOVSI	T1,(ED.PPC)	;IF RUNNING PRIMARY PROTOCOL,
	TDNE	T1,ETDSTS(F)	;
	PUSHJ	P,LEVPPC	;LEAVE PRIMARY PROTOCOL ON THIS DTE/11
	PUSHJ	P,GTEPT		;MAKE SURE OF EPT ADDRESS
	LOAD.	T1,ED.DTN,(F)	;DTE NUMBER FOR THIS FE
	ASH	T1,3		;8-WORD BLOCKS
	ADD	T4,T1		;ADDRESS OF THIS DTE'S VARIABLES
	SETZM	DTEEPW(T4)	;MAKE SURE HE KNOW'S HE'S DEAD
	MOVEI	T1,CLRDTE+PILDEN+0 ;CLEAR THIS DTE AND ZERO PI ASSIGNMENT
	XCT	ETDCNO(F)

DTECLK:
; HERE TO CLEAR DTE FROM ANY CPU.  AFTER THIS POINT, THERE SHOULD BE NO I/O
; INSTRUCTIONS OR ANY REFERENCES TO PER-CPU DATA BASES (SUCH AS .CPxxx).

	MOVEI	T1,0		;CLEAR CAL11. VECTOR
	MOVSI	T2,(ED.DTM)	;GET MASTER DTE BIT
	TDNE	T2,ETDSTS(F)	;IS THE THE MASTER DTE?
	PUSHJ	P,C11VEC	;YES--ZAP CAL11. VECTOR
	LOAD.	T2,ED.211,(F)	;POINT TO THE TO-11 SECTION
	LOAD.	T2,EC.PRT,(T2)	;GET THE PROTOCOL TYPE
	MOVSI	T1,(ED.RLD)	;CLEAR RELOAD BIT
	ANDCAB	T1,ETDSTS(F)	;SINCE THIS 11 IS NOW QUIET.
	CAIN	T2,.MMCB	;RUNNING THE MCB?
	PJRST	DTECLM		;YUP, CLEAN OUT THE MESS
	TLNE	T1,(ED.DTM)	;IF THE MASTER
	PUSHJ	P,[PUSHJ P,CLRDSN## ;FORGET DISK DRIVE SERIAL NUMBERS
		   PJRST TTDRLD##] ;RESTART -20F LINES
	LOAD.	T4,ED.CUR,(F)	;GET CURRENT TO-11 MESSAGE
	SKIPE	T4		;SKIP IF NONE
	PUSHJ	P,DTEPST	;CALL DRIVER AND DEALLOCATE CORE
	SETZ	T4,		;CLEAR OUT CURRENT ENTRY
	STOR.	T4,ED.CUR,(F)	;CLEAR
DTECL1:	LOAD.	T4,ED.QUE,(F)	;GET NEXT QUEUE ENTRY
	JUMPE	T4,DTECL2	;GO FINISH UP, ALL CORE DEALLOCATED
	LOAD.	T1,EQ.LNK,(T4)	;GET NEXT ITEM IN QUEUE
	STOR.	T1,ED.QUE,(F)	;MAKE THIS NEW FIRST ITEM
	PUSHJ	P,DTEPST	;GO CALL DRIVER, DEALLOCATE CORE FOR
				; THIS MESSAGE
	JRST	DTECL1		;LOOP FOR ALL MESSAGES IN QUEUE

DTECL2:	STOR.	T4,ED.LST,(F)	;CLEAR OUT PLACE TO PUT NEW QUEUE ENTRIES

	LOAD.	T1,ED.2TS,(F)	;GET TO-10 DTE STATUS
	CAIGE	T1,ED.TWD	;NEED TO NOTIFY A DRIVER OF LOST
				; TO-10 INDIRECT DATA?
	JRST	DTECL3		;NO

	PUSHJ	P,SAVE4##	;YES, SAVE P1-P4 FOR CALL TO DRIVER
	LOAD.	P1,ED.DTN,(F)	;GET DTE NUMBER
	LOAD.	T1,ED.CPN,(F)	;AND CPU NUMBER
	HRL	P1,T1		;IN P1
	LOAD.	P2,ED.XFN,(F)	;GET CURRENT TO-10 FUNCTION
	LOAD.	T1,ED.XDV,(F)	;AND DEVICE
	HRL	P2,T1		;IN P2
	LOAD.	T1,ED.XLN,(F)	;GET LINE
	HRLZ	P3,T1		;LINE,,0 LEFT
	LOAD.	P4,ED.MSP,(F)	;AND NOW THE IMPORTANT DATA, THE POINTER
				; WITH WHICH THE DRIVER DEALLOCATED THE  CORE
	PUSH	P,F		;SAVE F
	MOVEI	T1,.EMXML	;THE INTERNAL FUNCTION FOR THIS SITUATION
	PUSHJ	P,DNDSP		;DO NEGATIVE DISPATCH
	POP	P,F		;RESTORE F

DTECL3:	PUSHJ	P,DTETID	;MAKE TO-10 DTE SIDE IDLE
	MOVEI	T1,ED.EID	;MAKE TO-11 DTE SIDE IDLE
	STOR.	T1,ED.2ES,(F)

				;COMM REGION WILL BE RESET THE NEXT
				; TIME PRIMARY PROTOCOL IS ENTERED
	POPJ	P,		;RETURN
;HERE TO DO CLEARING PROCESSING FOR QUEUED PROTOCOL VERSION 2 (MCB).

DTECLM:	MOVEI	T1,0		;CLEAR CAL11.
	PUSHJ	P,C11VEC	; VECTOR ADDRESS
	MOVX	T1,ED.EID	;GET TO-11 IDLE STATE INDICATOR
	STOR.	T1,ED.2ES,(F)	;MAKE TO-11 SIDE IDLE
	MOVX	T1,ED.TID	;GET TO-10 IDLE STATE INDICATOR
	STOR.	T1,ED.2TS,(F)	;MAKE TO-10 SIDE IDLE
	SE1ENT			;QPV2 CODE RUNS IN SECTION ONE

	MOVEI	T1,.M20F	;RESET PROTOCOL TYPE TO 20F (ALSO ANF)
	LOAD.	T2,ED.211,(F)	;GET POINTER TO TO-11 SECTION
	STOR.	T1,EC.PRT,(T2)	;SET 11'S PROTOCOL TYPE
	LOAD.	T2,ED.210,(F)	;GET POINTER TO TO-10 SECTION
	STOR.	T1,EC.PRT,(T2)	;SET 10'S PROTOCOL TYPE

	MOVSI	T1,(ED.LLS)	;GET LINE STATE REPORTED FLAG
	TDNN	T1,ETDSTS(F)	;WAS LAST LINE STATE REPORTED AS DOWN?
	JRST	DTECM4		;YES, DON'T REPORT AGAIN
	ANDCAM	T1,ETDSTS(F)	;MARK LAST STATE REPORTED AS DOWN
	MOVEI	T1,DI.LSC	;SIGNAL A PROTOCOL DOWN RIGHT AWAY
	MOVEI	T3,LS.OFF	;NEW LINE STATE OF OFF
	PUSHJ	P,CALUSR	;CALL DTE USER

DTECM4:	SETZ	T2,		;GET A ZERO
	EXCH	T2,ETDIBK(F)	;GET INPUT BUFFER ADDRESS
	JUMPE	T2,DTECM2	;IF NO INPUT BUFFER, SKIP THIS
	MOVX	T1,UBLSIZ+SIZE(.EQLEN,36) ;GET INPUT BUFFER SIZE
	PUSHJ	P,GIVWDS##	;GIVE BACK THE MEMORY

DTECM2:	SETZ	T2,		;GET A ZERO
	EXCH	T2,ETDOBK(F)	;GET OUTPUT BUFFER ADDRESS
	JUMPE	T2,DTECM3	;IF NO OUTPUT BUFFER, SKIP THIS
	MOVX	T1,UBLSIZ+SIZE(.EQLEN,36) ;GET OUTPUT BUFFER SIZE
	PUSHJ	P,GIVWDS##	;GIVE BACK THE MEMORY

DTECM3:	LOAD.	T3,ED.CUR,(F)	;GET THE CURRENT MESSAGE POINTER
	SKIPE	T3		;IS ONE THERE?
	PUSHJ	P,DTECMR	;NO, GIVE THE OUTPUT INCOMPLETE
	SETZ	T3,
	STOR.	T3,ED.CUR,(F)	;ZERO OUT THE ENTRY

DTECM1:	LOAD.	T3,ED.QUE,(F)	;GET NEXT QUEUE ENTRY
	JUMPE	T3,CPOPJ##	;WE'RE ALL DONE NOW IF NONE LEFT
	MOVE	T1,MB.NXT(T3)	;GET POINTER TO NEXT MESSAGE
	STOR.	T1,ED.QUE,(F)	;STORE IT AS NEW FIRST ITEM
	PUSHJ	P,DTECMR	;GIVE THE MESSAGE BACK TO DRIVER (RTR)
	JRST	DTECM1		;CLEAN OUT THE NEXT ONE


;HERE TO PRETEND OUTPUT DONE TO DRIVER (DNADLL) WHICH WILL DISCARD
;THE MESSAGE IN THE CORRECT MANNER.  CALLED WITH T3 POINTING TO THE
;MESSAGE.

DTECMR:	MOVEI	T1,DI.ODN	;GET "OUTPUT DONE" KONTROLLER FUNCT
	SKIPN	T3		;HAVE A MESSAGE BLOCK?
	STOPCD	.,STOP,DTENOM,	;++ NO MESSAGE BLOCK
	PJRST	CALUSR		;CALL DTE DRIVER AND RETURN
;HERE TO INFORM THE 11 ON A POWER FAILURE

DTEPWF::PUSHJ	P,GTEPD
	LOAD.	T2,ED.211,(F)
	MOVSI	T1,(EC.PWF)
	IORM	T1,ETCSTS(T2)
	MOVEI	T1,TO11DB
	XCT	ETDCNO(F)
	POPJ	P,

;HERE WHEN POWER IS RESTORED

DTEPFC::PUSHJ	P,GTEPD
	SETZM	DTEEPW(T4)
	PUSHJ	P,ENTSPC
	PUSHJ	P,STAPPC
	POPJ	P,
;PRSRLD - PRESS 11 RELOAD BUTTON
; SKIP RETURN ON SUCCESS, OTHERWISE INDICATES WE NEVER SAW 11 DOORBELL

	BOFTIM==^D200		;WAIT 200 MS, THEN TURN RELOAD BUTTON OFF
	DBCTIM==^D2		;WAIT 2 SECS FOR DOORBELL TO CLEAR
	MAGICN==^O1365		;ROM HELLO BYTE COUNT

PRSRLD:	PUSHJ	P,SAVE3##	;SAVE SOME ACS FOR USE
	MOVEI	T1,SR11B	;SET 11 RELOAD BUTTON
	XCT	ETDCNO(F)	;DO IT

PRSRL2:	RDTIME	P1		;GET TIME BASE TIME
PRSRL3:	RDTIME	T1		;GET TIME NOW
	DSUB	T1,P1		;GET TIME DIFFERENCE
	ASHC	T1,<TB.LTP-^D35>;ACCOUNT FOR UNUSED BITS
	CAIGE	T2,BOFTIM*^D1000;WAITED THE TIME?
	JRST	PRSRL3		;NO, WAIT SOME MORE
	MOVEI	T1,CR11B	;YES, GET YOUR FINGER OFF THE BUTTON
	XCT	ETDCNO(F)	;NOW.

;HERE TO SAY HELLO TO THE ROM

	SETZM	@ETDTBP(F)	;MAKE SURE SETTING BYTE COUNT XFERS NOTHING
	MOVEI	T1,MAGICN	;GET MAGIC HELLO NUMBER
	XCT	ETDDTO(F)	;HELLO, ROM
	MOVEI	T1,TO11DB	;RING THE DOORBELL
	XCT	ETDCNO(F)
	MOVEI	P1,DBCTIM	;GET MS TO WAIT FOR DOORBELL FOR
	IMUL	P1,TICSEC##	;TICS
	ADD	P1,SYSUPT##	;GET TIME TO WAIT FOR, LEAVE DOORBELL
				; BIT IN T1

PRSRL4:	MOVEI	T1,TO11DB	;SETUP IN CASE SLEEP CALLED
	XCT	ETDCSO(F)	;DOORBELL CLEAR?
	JRST	PRSRL5		;YES, WHAT WE WANTED
	CAMG	P1,SYSUPT##	;TIME TO QUIT?
	POPJ	P,		;ELEVEN MUST HAVE TIMED OUT
	MOVEI	T1,1		;WAIT FOR 1 SEC
	PUSHJ	P,SLEEPF##	;GO SLEEP FOR 1 SEC
	JRST	PRSRL4		;WAIT STILL

PRSRL5:	MOVEI	T1,CLRDTE	;CLEAR ALL BITS
	XCT	ETDCNO(F)
	JRST	CPOPJ1##	;GIVE GOOD RETURN
;WAITDB -- ROUTINE TO WAIT FOR TO-10 DOORBELL, CALL WITH P2 CONTAINING THE
; WAIT TIME IN SECONDS.  OBVIOUSLY P2 MUST BE SAVED FROM DESTRUCTION.

WAITDB:	IMUL	P2,TICSEC##	;CONVERT TO TICS
	ADD	P2,SYSUPT##	;TIME IN FUTURE

WAITD1:	MOVEI	T1,TO10DB	;WAIT FOR TO-10 DOORBELL
	XCT	ETDCSZ(F)	;CONSZ DTEN,(T1)
	JRST	CPOPJ1##	;GOT IT
	CAMG	P2,SYSUPT##	;TIMED OUT YET?
	POPJ	P,		;YUP, GIVE BAD NEWS
	PUSHJ	P,UUOLVL##	;CAN WE CALL SCDCHK?
	  JRST	WAITD1		;NO--JUST LOOP AT STARTUP TIME
	PUSHJ	P,SCDCHK##	;CHECK OTHER GUYS
	JRST	WAITD1		;CHECK AGAIN
;CALUSR -- ROUTINE TO CALL DECnet
;CALL WITH F POINTING TO ETD BLOCK

CALUSR:	PUSHJ	P,SAVR##	;DECnet USES R AS A TRASH AC
	LOAD.	T2,ED.USR,(F)	;GET THE LINE'S USER
	CAIE	T2,DD.DEC	;IS IT DECnet ???
	STOPCD	CPOPJ##,DEBUG,DTEIUD ;++ILLEGAL USER FOR DTE
	MOVE	T2,ETDLBK(F)	;GET LINE BLOCK ADDRESS
	PJRST	DTIPPI##	;PASS IT OFF TO DNADLL
;RESPTR - RESOLVE A POSSIBLY EXTENDED INDEXED BYTE POINTER FOR USE
; WITH TO-11 AND TO-10 BYTE POINTERS.
;
;IF THE INDEX TURNS OUT TO BE AN EXTENDED POINTER, IT MUST BE MAPPED INTO
;SECTION ZERO SO IT CAN BE SENT ACROSS THE DTE.
;
;CALLED WITH T1 CONTAINING THE UNRESOLVED BYTE POINTER, RETURNS WITH
; T1 CONTAINING THE RESOLVED POINTER.

RESPTR:	LDB	T2,[POINT 4,T1,17] ;GET THE INDEX FIELD OF THE BYTE POINTER
	JUMPE	T2,CPOPJ	;UNINDEXED, JUST RETURN
	CAIE	T2,T6		;ARE WE INDEXING BY T6 (THE DECNET INDEX)
	STOPCD	.,STOP,DTEIDX,	;++ BAD INDEX IN BYTE POINTER
	TLZ	T1,37		;MASK OUT THE INDEX AND INDIRECT BITS
	MOVE	T3,(T2)		;DO THE INDIRECTION NOW
	TLNE	T3,-1		;EXTENDED SECTION?
	PUSHJ	P,RESPT1	;YES, DO THE MAPPING AND RETURN
	ADDI	T1,(T3)		;ADD THE OFFSET TO THE BYTE POINTER
	POPJ	P,		; AND RETURN

;HERE WE HAVE TO MAP THE NON-ZERO SECTION MESSAGE BLOCK.

RESPT1:
;	SE1ENT			;GO INTO SECTION ONE FOR A WHILE

;*** FILL IN THIS SPACE ***

	POPJ	P,		;RETURN WITH T1 CONTAINING BYTE POINTER
;HERE WHEN AN 11 IS DEAD TO INDICATE IT SHOULD BE RELOADED.
; CALL WITH DTE CONTROL BLOCK ADDRESS IN F
;INSTEAD OF BEING CALLED BY PJRST, DO PJSP T1, INSTEAD TO SAVE PC
;SOMEPLACE FOR DEBUGGING PURPOSES.

DTERLD::MOVEM	T1,ETDLCP(F)	;SAVE LAST -11 CRASH PC
	LOAD.	T1,ED.CPN,(F)	;GET THE CPU NUMBER FOR THIS DTE
	CAME	T1,.CPCPN	;ARE WE RUNNING ON THE CORRECT CPU?
	 STOPCD	 CPOPJ,DEBUG,DTERWC ;++DTERLD CALLED ON WRONG CPU
	MOVEI	T1,PILDEN+0	;ZERO PI ASSIGNMENT SO SICK 11 WON'T
	XCT	ETDCNO(F)	; KILL US WITH ZILLIONS OF INTERRUPTS
	MOVSI	T1,(ED.RLD)	;SET RELOAD BIT
	IORM	T1,ETDSTS(F)	;SO PROGRAM THAT RELOADS CAN SEE
	MOVE	T1,ETDUSR(F)	;GET THE USER OF THE LINE
	CAIN	T1,DD.DEC	;IF IT'S DECNET
	JRST	DECRLD		; GO TELL DECNET ABOUT IT
	CONSZ	PI,PI.PIA	;DON'T CALL WAKJOB IF PI'S ARE OFF
	SKIPN	T1,DTRJOB	;SKIP IF RELOAD JOB EXISTS
	POPJ	P,		;NO, RETURN
	PJRST	WAKJOB##	;WAKE IT UP, IT WILL SEE THE BIT
				; (CAN'T GET HERE IF FROM SYSINI)

DECRLD:	SE1ENT			;DECNET WANTS TO BE IN SECTION 1
	MOVSI	T1,(ED.LLS)	;GET LINE STATE REPORTED FLAG
	TDNN	T1,ETDSTS(F)	;WAS LAST LINE STATE REPORTED AS DOWN?
	POPJ	P,		;YES, RETURN
	ANDCAM	T1,ETDSTS(F)	;MARK LAST STATE REPORTED AS DOWN
	MOVEI	T1,DI.LSC	;SIGNAL A PROTOCOL DOWN RIGHT AWAY
	MOVEI	T3,LS.OFF	;NEW LINE STATE OF OFF
	PJRST	CALUSR		;CALL DTE USER AND RETURN
SUBTTL MISCELLANEOUS UTILITY ROUTINES

	LIST

;ROUTINE TO SETUP DTE CONTROL BLOCK ADDRESS IN F,
; AND STOP IF CPU,,DTE SPEC IS NOT LEGAL.
; CALLED WITH LH(F) EQUAL TO CPU NUMBER (0-CPUN), RH(F) EQUAL TO DTE NUMBER
; (0-DTE'N10'N)

GTETDS::HRRE	T1,F		;GET DTE NUMBER
	AOSE	T1		;DO NOT ALLOW MASTER TO BE ASKED FOR BY -1
	PUSHJ	P,GETETD	;GET DTE CONTROL BLOCK ADDRESS
	STOPCD	.,STOP,DTEBDN	;++BAD DEVICE NUMBER
	POPJ	P,		;OK, RETURN


;ROUTINE TO GET DTE CONTROL BLOCK ADDRESS IN F, SKIP IF SUCESSFUL.
; CALLED BY GTETDS, DTUGTF (UUO ROUTINE), DTESEC (FOR SCANNING
; THROUGH DTE CONTROL BLOCKS).
; CALL WITH CPU#,,DTE# IN F. IF MASTER DTE IS DESIRED, CALL WITH
; CPU#,,-1 IN F.  GIVES NON-SKIP RETURN IF CPU OR DTE NUMBER IS BAD,
; OTHERWISE SKIP RETURN WITH DTE CONTROL BLOCK ADDRESS IN F.


GETETD::HLRZ	T1,F		;GET CPU NUMBER
	CAIL	T1,M.CPU##	;IN RANGE?
	POPJ	P,		;NO, GIVE ERROR INDICATION
	HRRZ	T3,F		;JUST DTE NUMBER
	CAIN	T3,-1		;DOES CALLER WANT MASTER ETD?
	JRST	GTETD1		;YES, PUT C(T2) IN F AND GIVE GOOD RETURN
	CAIL	T3,4		;IS DESIRED DTE NUMBER LESS THAN NUMBER OF DTES?
	POPJ	P,		;NO, GIVE ERROR RETURN
	HLRZ	T1,F		;RESTORE CPU NUMBER
	SKIPA	F,@ETDTAB##(T1)	;YES, ALL IS OK, FETCH PROPER ETD ADDRESS
GTETD1:	MOVE	F,DTEMAS##(T1)	;GET MASTER DTE CONTROL BLOCK ADDR IN F
	JRST	CPOPJ1##	;RETURN SUCCESS
;ROUTINE TO GET TWO EIGHT BIT BYTES FROM A MESSAGE, SWAP THEM, AND
; RETURN THEM AS A 16 BIT BYTE IN T1. USES T4 FOR BYTE POINTER.
; USES ACS T1,T2

GX2BYT::ILDB	T1,T4		;GET FIRST BYTE
	ILDB	T2,T4		;GET SECOND BYTE
	LSH	T2,^D8		;MAKE SECOND BYTE FIRST BYTE
	IOR	T1,T2		;PUT INTO T1 AND
	POPJ	P,		;RETURN WITH 16 BIT BYTE


;HERE DURING STOPCD PROCESSING TO TYPE DTE THAT
; CAUSES THE STOPCODE.  F CONTAINS ETD ADDRESS.

DTEPDI::PUSHJ	P,INLMES##
	ASCIZ	/DTE /
	LOAD.	T1,ED.DTN,(F)	;GET DTE NUMBER
IFN FTMP,<
	PUSHJ	P,PRTDI8##	;OUTPUT DTE NUMBER
	PUSHJ	P,INLMES##
	ASCIZ	/ on CPU /
	LOAD.	T1,ED.CPN,(F)	;GET CPU NUMBER
>
	PJRST	PRTDI8##	;OUTPUT AND RETURN


;GETCPU PLACES A JOB ON THE CORRECT CPU DEPENDING UPON F (POINTER TO THE
;ETD REGION).  ONLY CALLED FROM UUO LEVEL!

IFE FTMP,<GETCPU==CPOPJ1##>

IFN FTMP,<
GETCPU:
	PUSHJ	P,SSEC0##	;MUST CALL THIS IN SECTION 0
	LOAD.	T1,ED.CPN,(F)	;GET THE CPU NUMBER FROM THE ETD BLOCK
	PJRST	ONCPUS##	;RUN ON THAT ONE, SKIPPING IF DOABLE
>;IFN FTMP

;ROUTINE TO SAVE F AND T4, AND SETUP F WITH DTE CONTROL BLOCK
; ADDRESS OF MASTER DTE ON CALLING CPU, T4 TO EPT ADDRESS OF
; CALLING CPU. SMASHES T1

SVEPTD::EXCH	F,(P)		;GET CALLING PC, SAVE F
	PUSH	P,T4		;SAVE T4
	PUSH	P,F		;SAVE CALLING PC ON STACK
	PUSH	P,T1		;SAVE T1 AROUND CALL
	PUSHJ	P,GTEPD		;SETUP DESIRED F AND T4
	POP	P,T1		;RESTORE T1
	ADJSP	P,-1		;ADJUST STACK POINTER BACK
	PUSHJ	P,@1(P)		;CALL CALLER
	  CAIA			;NON-SKIP
	AOS	-2(P)		;ADJUST FOR SKIP RETURN
	POP	P,T4		;RESTORE T4
	POP	P,F		;AND F
	POPJ	P,		;AND GO BACK TO META-CALLER


;ROUTINE TO SETUP T4 AND F TO BE EPT ADDRESS AND DTE CONTROL BLOCK ADDRESS
; OF MASTER DTE ON CALLING CPU.  SMASHES T1,F,T4
; ENTER AT GTEPT WITH DTE CONTROL BLOCK ADDRESS
; TO GET JUST EPT OFFSET OF DTE'S CPU.

GTEPD:	MOVE	T1,.CPCPN##	;GET CPU NUMBER OF CALLING CPU
	MOVE	F,DTEMAS##(T1)	;GET DTE CONTROL BLOCK OF MASTER DTE
GTEPT:	MOVE	T4,.CPEPT##	;NOW GET EPT ADDRESS OF CALLING CPU
	POPJ	P,		;DONE.
	$LOW
DTRJOB::Z			;JOB TO WAKE ON 11 RELOAD
	$LIT
DTEEND:	END