Google
 

Trailing-Edge - PDP-10 Archives - de-10-omona-v-mc9 - dteser.mac
There are 13 other files named dteser.mac in the archive. Click here to see a list.
TITLE DTESER - DTE20 INTERFACE ROUTINES V5241
SUBTTL E.SOCCI/EVS/EJW	22 AUG 78
	SEARCH F,S,DTEPRM

;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==015
; 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>
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VDTESR,5241
	SALL		;CLEAN MACRO EXPANSIONS
	ENTRY	DTESER
DTESER::
DEFINE DEAD10<PUSHJ P,DEDTEN>	;ONE DEAD10 FOR ALL DTESER, PUSHJ
				; TO IT SO WE KNOW WHICH FLAVOR
				; THEORY IS THAT UNLESS DUMP IS LOOKED
				; AT, ANY FURTHER DETAIL IS UNNEEDED;
				; THUS, I DON'T HAVE TO THINK UP
				; 20 OR SO NAMES FOR ALL THE DEAD10S IN
				; 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 THESE PROTOCOLS.
;
;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)
SUBTTL DTE20 INITIALIZATION ROUTINES


	XLIST			;DON'T PRINT LITERALS
	LIT
	LIST
	$LOW			;USED IN SYSINI
;ROUTINE TO INITIALIZE ALL DTES ON A CPU
; CALL WITH CPU NUMBER IN T1

DTEINI::SETZM	KLEEOF		;CLEAR EOF FLAG FOR KL ERROR PROCESSOR
	SETZM	KLNSTF


	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 EXISTS
	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
	AOJA	P1,DTEIN1	;LOOP ON

DTEIN2:	SKIPN	P2		;HAS A MASTER BEEN LOCATED AT ALL?
	DEAD10			;NO, BOO BOO
	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
	MOVE	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,ETDCDB(F)	;CDB ADDRESS IN T3
	MOVE	T3,.CPTOS##(T3)	;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,(JSR)	;THE RIGHT INSTRUCTION
	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
	PUSHJ	P,PEVEN8##	;GET GOOD PARITY, RID OF JUNK
	MOVEI	T1,DT.MTO(T3)	;STORE IN DTECMD
	PUSHJ	P,SPCMD		;DO THE COMMAND
T1POPJ:	POP	P,T1		;RESTORE T1
	POPJ	P,		;AND 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
	CAIN	T1,DT.ESP	;ENTERING SECONDARY PROTOCOL IS OK IF
				; NOT IN SECONDARY PROTOCOL
	JRST	SPCMD1		;SO DON'T CHECK
	PUSH	P,T1		;SAVE COMMAND
	MOVSI	T1,(ED.SPC)	;IS SECONDARY PROTOCOL RUNNING ON THIS DTE?
	TDNN	T1,ETDSTS(F)	;?
	JRST	T1POPJ		;DON'T USE TPOPJ IN CASE HISEG NOT SETUP
	POP	P,T1		;RESTORE THE COMMAND
SPCMD1:	SETZM	DTEFLG(T4)	;CLEAR DONE FLAG
	ADJSP	P,1		;RESERVE A PLACE ON THE STACK FOR THE
	CONI	PI,(P)		;PI STATUS
	CONO	PI,PIOFF##	;TURN OFF SO WE GET TO PUT COMMAND
				; IN AND RING DOORBELL, ENSURING THAT 11
				; WILL SEE SO A HIGHER LEVEL CAN CHECK DTEFLG
	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,PION##	;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 AND SETUP DTE CTL ADDRESS, EPT ADDRESS
	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

	MOVEI	U,TCONLN##	;SETUP LINE # FOR CTY
	SETZ	T1,		;GET READY TO TEST AND CLEAR FLAG
	EXCH	T1,DTEMTI(T4)	;CLEAR OUT DTEMTI AND GET ITS OLD VALUE IN T1
	JUMPE	T1,SPCODI	;JUMP IF NOT INPUT READY
	MOVE	T3,DTEF11(T4)	;WAS INPUT READY, GET CHAR IN T3
	PUSHJ	P,RECINT##	;AND CALL SCNSER
	PUSHJ	P,GTEPD		;SETUP F AND T4 AGAIN
	SETZ	T1,		;CLEAR T1 AGAIN TO CHECK FOR OUTPUT DONE
	MOVEI	U,TCONLN##	;SETUP CTY LINE NUMBER AGAIN

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	[POP P,T1	;DO THIS BY HAND IN CASE SYSINI NOT THERE
		 POPJ	P,]	;OUTPUT NEVER COMPLETE
	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
	PJRST	CPOPJ1##	;AND GIVE OUTPUT DONE RETURN


	XLIST			;DON'T PRINT LITERALS
	LIT
	LIST
	$HIGH			;BACK IN HISEG AGAIN
SUBTTL DTE. UUO

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


DTE.::	PUSHJ	P,SAVE2##
	HRR	M,T1		;ADDRESS OF PARAMETER BLOCK
	HLRZ	P1,T1		;GET FUNCTION CODE
IFN FTPRV,<
	MOVSI	T1,JP.POK	;DISALLOW UNLESS PRIVILEGED
	PUSHJ	P,PRVBIT##	;IS HE?
>
IFE FTPRV,<
	PUSHJ	P,PRVJ##	;CHECK FOR [1,2] OR JACCT
>
	  JRST	.+2		;IS
	JRST	DTUNPE		;ERROR, NO PRIVILEGES
	CAILE	P1,MXDTFN	;OUT OF RANGE?
	JRST	DTUFNE		;YES, FUNCTION NUMBER ERROR
	ROT	P1,-1		;/2, EVEN/ODD IN SIGN BIT
	MOVE	T1,DTUDSP(P1)	;GET ENTRY
	SKIPL	P1		;SKIP IF ODD
	MOVSS	T1		;EVEN, USE LH
	PJRST	(T1)		;DISPATCH
;DISPATCH TABLE FOR DTE. UUO

DTUDSP:	XWD	DTUCLR,DTUSTR	;(0,1)CLEAR A DTE, START A DTE
	XWD	DTUSTB,DTUSEB	;(2,3)SET TO-10 BYTE POINTER, SET TO-11 POINTER
	XWD	DTUGRW,DTUGMN	;(4,5)GET ROM WORD, GET MASTER DTE NUMBER
	XWD	DTUPRB,DTUGST	;(6,7)PRESS RELOAD BUTTON, GET STATUS
	XWD	DTUSRJ,FEDGET##	;(10,11)SET RELOAD JOB, GET FRONT END DEVICE
	XWD	FEDUIN##,FEDUOU##	;(12,13)FED INPUT, FED OUTPUT
	XWD	FEDUGS##,FEDUSS##	;(14,15)GET FED STATUS, SET FED STATUS
	XWD	FEDGIV##,DTURLC	;(16,17)RELEASE FED, RELEASE KLE CHUNKS
	XWD	DTURTM,DTUKLN	;(20,21)RESET KL ERROR TIMER, GET KLINIK LINE
	MXDTFN==<.-DTUDSP>*2-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 PRIMARY 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
;DTE. FUNCTION (#0) TO CLEAR A DTE
; ADDR/CPU#,,DTE#
; CAUSES DTE TO LEAVE PRIMARY PROTOCOL. ALSO CLEARS ED.RLD.

DTUCLR:	PUSHJ	P,DTUGTF	;GET CORRECT DTE CONTROL BLOCK IN F
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	DTECLR		;GO CLEAR OUT THE DTE

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

DTUSTR:	PUSHJ	P,DTUGTF	;GET DTE CONTROL BLOCK ADDR IN F
	MOVE	T1,ETDSTS(F)	;GET DTE STATUS
	TLNE	T1,(ED.PPC)	;ALREADY RUNNING PRIMARY PROTOCOL?
	JRST	DTUARP		;YES, GIVE AN ERROR RETURN
	TLNE	T1,(ED.DTM)	;IF MASTER,
	PUSHJ	P,ENTSPC	;GO INTO SECONDARY PROTOCOL FIRST
	PUSHJ	P,STXPPC	;START UP PRIMARY PROTOCOL
	  JRST	DTUSTE		;SOMETHING WENT WRONG, WE CAN'T START IT
	MOVE	T1,ETDSTS(F)	;GET DTE STATUS
	TLNE	T1,(ED.DTM)	;IF MASTER,
	PUSHJ	P,KPSSND	;SEND KLINIK PARAMETERS
	  JFCL			;NOT SERIOUS (OLD VERSION OF 20F)
	JRST	CPOPJ1##	;SIGNAL SUCCESSFUL START


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

DTUSTB:	PUSHJ	P,DTUGTF	;GET CORRECT DTE CONTROL BLOCK IN F
	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,DTUGTF	;GET CORRECT DTE CONTROL BLOCK IN F
	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:	PUSHJ	P,DTUGTF	;GET DTE CONTROL BLOCK ADDR IN F
	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:	PUSHJ	P,DTUGTF	;GET DTE CONTROL BLOCK ADDR IN F
	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#

	BOFTIM==^D200		;WAIT 200 MS, THEN TURN RELOAD BUTTON OFF
	DBCTIM==^D2		;WAIT 2 SECS FOR DOORBELL TO CLEAR
	DONTIM==^D1		;WAIT 1 MORE SEC BEFORE CLEARING TO-10 DONE AND TO-10 ERROR

	MAGICN==^O1365		;ROM HELLO BYTE COUNT


DTUPRB:	PUSHJ	P,DTUGTF	;GET DTE CONTROL BLOCK FROM USER ARG
	MOVE	T1,ETDSTS(F)	;GET STATUS
	TLNE	T1,(ED.PPC)	;RUNNING PRIMARY PROTOCOL?
	JRST	DTUARP		;YES, ERROR
	PUSHJ	P,SAVE3##	;SAVE SOME ACS FOR USE
	MOVEI	T1,SR11B	;SET 11 RELOAD BUTTON
	XCT	ETDCNO(F)	;

DTUPR2:	RDTIME	P1		;GET TIME BASE TIME
DTUPR3:	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	DTUPR3		;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,UPTIME##	;GET TIME TO WAIT FOR, LEAVE DOORBELL
				; BIT IN T1
DTUPR4:	MOVEI	T1,TO11DB	;SETUP IN CASE SLEEP CALLED
	XCT	ETDCSO(F)	;DOORBELL CLEAR?
	JRST	DTUPR5		;YES, WHAT WE WANTED
	CAMG	P1,UPTIME##	;TIME TO QUIT?
	JRST	DTUDEE		;YES, NO ELEVEN DOORBELL
	MOVEI	T1,1		;WAIT FOR 1 SEC
	PUSHJ	P,DTESLP	;GO SLEEP FOR 1 SEC
	JRST	DTUPR4		;WAIT STILL

DTUPR5:	MOVEI	T1,CLRDTE	;CLEAR ALL BITS
	XCT	ETDCNO(F)
	JRST	CPOPJ1##	;WE MADE IT.


;HERE TO SLEEP FOR N SECS.

DTESLP:	PUSH	P,F		;SAVE ETD ADDRESS
	SETZ	F,		;SO THAT RTEVM WON'T GET UPSET
	PUSHJ	P,SLEEP##	;GO SLEEP
	JRST	FPOPJ##		;RESTORE F AND RETURN
;DTE FUNCTION #7, GET STATUS WORD.

DTUGST:	PUSHJ	P,DTUGTF	;GET ETD BLOCK
	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.


;FUNCTION #17, RELEASE KLE CHUNKS
; USED BY DAEMON AFTER IT HAS WRITTEN THE KL ERROR DATA INTO ERROR.SYS

DTURLC:	PUSHJ	P,GETWDU##	;GET USER ARG (CPU#,,0)
	HLRZS	T1		;JUST CPU #
	JUMPN	T1,DTUDCE	;BAD CPU IF NON-ZERO
	AOS	(P)		;GIVE GOOD RETURN
	PJRST	KLEREL		;GO GIVE BLOCKS BACK AND RETURN


;HERE WHEN DAEMON CALLS TO RESET THE TIMER FOR THE KL ERROR DATA
; CORE. GIVES ERROR RETURN IF THE CORE IS NO LONGER AVAILABLE.

DTURTM:	PUSHJ	P,GETWDU##	;GET CPU#,,<DONT CARE>
	HLRZS	T1		;JUST CPU NUMBER
	JUMPN	T1,DTUDCE	;BAD NON-ZERO CPU SPEC
	MOVEI	T1,.KLETM+1	;RESET TIMER
	MOVEM	T1,KLETIM	;FIRST, THEN
	SKIPN	KLEADR		;MAKE SURE THE CORE IS REALLY THERE
	JRST	[SETZM	KLETIM
		 JRST	DTUTME]	;SORRY, IT'S NOT AVAILABLE
	JRST	CPOPJ1##	;OK, RETURN


;FUNCTION #21, GET DTE LINE NUMBER

DTUKLN:	PUSHJ	P,DTUGTF	;GET ETD BLOCK
	PJRST	TTDDLN##	;GO GET LINE NUMBER
;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#
	TLNE	T1,-1		;NON-ZERO CPU SPECIFIED?
	JRST	DTUGT1		;YES, BAD CPU NUMBER (TEMPORARY TILL SMP)
	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
	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
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
;	<OK RETURN>
;
; 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
	MOVE	T1,ETDSTS(F)	;GET STATUS WORD
	TLNE	T1,(ED.PPC)	;IS PRIMARY PROTOCOL DOWN OR
	TLNE	T1,(ED.RLD)	;IS THE RELOAD BIT SET?
	PJRST	FUPOPJ##	;YES, GIVE ERROR RETURN
	PUSHJ	P,GT2EFT	;GET TO-11 FUNCTION TYPE
	  DEAD10		;NOT LEGAL FUNCTION
	JRST	@DTQTYP(T1)	;DISPATCH TO PROPER ROUTINE
				; WHICH WILL CREATE PROPER HEADER
				; FOR FUNCTION

DTQTYP:	DTINDR
	DT16BT
	DTLINE
	DTLNGD
	DTLNDT
;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
	  PJRST	FUPOPJ##	;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
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
	  PJRST	FUPOPJ##	;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
	  PJRST	FUPOPJ##	;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 (XON,XOFF,ETC)

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
	  PJRST	FUPOPJ##	;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
	  PJRST	FUPOPJ##	;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


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,PIOFF##	;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
		 CONO	PI,PION## ;TURN PI BACK ON
		 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:	POP	P,F		;RESTORE F
	POP	P,U		;RESTORE U
	AOS	(P)		;GIVE GOOD RETURN
	PJRST	ONPOPJ##


;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,PIOFF##	;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,PION##	;OK TO MESS WITH QUEUE AGAIN
	JRST	DTESND		;GO SEND THIS MESSAGE

DTENX1:	CONO	PI,PION##	;OUT OF CRITICAL REGION
	MOVEI	T1,ED.EID	;MAKE TO-11 DTE SIDE IDLE
	STOR.	T1,ED.2ES,(F)	;PLACE IN TO-11 DTE STATE VAR
	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
	LOAD.	T2,EM.CNT,(T4)	;GET MESSAGE BYTE COUNT
	MOVEM	T4,@ETDEBP(F)	;PUT INTO TO-11 POINTER EPT LOCATION
	LOAD.	T4,ED.211,(F)	;GET TO-11 SECTION OF TO-10 AREA
	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 . . .
	DEAD10			;IS NOT, SOME CALLER MADE AN ERROR
	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 T1POPJ]	;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
SUBTTL DTE20 INTERRUPT SERVICE


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

DTEINT::MOVSI	T1,(ED.SPC)	;CHECK TO SEE IF SECONDARY PROTOCOL
	TDNE	T1,ETDSTS(F)	;IS RUNNING
	PJRST	SPCINT		;YES, DO SECONDARY PROTOCOL INTERRUPT
	MOVSI	T1,(ED.PPC)	;NOT SECONDARY, SEE IF PRIMARY IS RUNNING
	TDNN	T1,ETDSTS(F)	;IS IT?
	JRST	DTICLR		;NO, JUST CLEAR DTE AND DISMISS
	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
	XCT	ETDCNI(F)	;CONI DTEN,T1
	TRNE	T1,DEAD11	;11 POWER FAIL?
	JRST	PWRF11		;YES
	TRNE	T1,TO11DN	;TO-11 DONE?
	JRST	DTE2ED		;YES
	TRNE	T1,TO10DN	;TO-10 DONE? MUST CHECK BEFORE TO10DB
	JRST	DTE2XD		; SO WE FINISH A MESSAGE BEFORE STARTING A NEW ONE
	TRNE	T1,TO10DB	;TO-10 DOORBELL?
	JRST	DTERNG
	TRNE	T1,TO11ER
	JRST	DTE2EE
	TRNE	T1,TO10ER
	JRST	DTE2XE
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
;HERE ON TO-10 DOORBELL, ETD ADDRESS IN F, STATUS IN T4

DTERNG:	MOVEI	T1,CL11PT	;CLEAR DOORBELL
	XCT	ETDCNO(F)	;CONO DTEN,(T1)
	TLNE	T4,(EC.LOD)	;11 WANTS TO BE RELOADED?
	PJSP	T1,DTERLD	;YES, DO IT
	TRNE	T4,EC.IND	;IS THIS THE INDIRECT PORTION OF A MESSAGE?
	JRST	DTEIND		;YES, GO HANDLE 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
	DEAD10			;DTE IN WRONG STATE
	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
	  DEAD10		;NO FREE CORE, LOSE
	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
	DEAD10			;PACKET TO 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
	DEAD10			;NO, DTE IS IN WRONG STATE
	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.IBL,(F)	;GET COUNT SENT IN DIRECT PART OF THIS MESS^GE
	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)
	PUSHJ	P,SAVE4##	;SAVE P1-P4 FOR ARG PASSING TO DRIVER
	LOAD.	T1,ED.2TS,(F)	;GET TO-10 DTE STATE
	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
	DEAD10			;DTE WAS IN WRONG STATE

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
	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	;ILLEGAL FUNCTION
		PJRST	DTERLD]	;FIX STACK AND RELOAD
	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


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
DTEXDI:	LOAD.	T1,ED.2TS,(F)	;GET TO-10 DTE STATE
	CAIE	T1,ED.TIB	;WERE WE EXPECTING TO-10 DONE FOR INDIRECT?
	DEAD10			;NO, DTE WAS 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
	DEAD10			;NOT
	LOAD.	P1,ED.DTN,(F)	;GET DTE NUMBER IN P1
	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.IBL,(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.IBL,(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.IBL,(F)	;SAVE FOR NEXT TIME
	SKIPGE	T2		;DRIVER EATING TOO MUCH?
	DEAD10			;YES, ERROR
	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.IBL,(F)	;GET NUMBER OF BYTES LEFT IN PACKET
	SKIPE	T1		;SKIP IF DRIVER HAS TAKEN ENOUGH
	DEAD10			;DRIVER TOOK LESS INDIRECT DATA THAN
				; THE 11 WAS TRYING TO SEND
	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
;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 S 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 . . .

	KLIDSP==ALLDSP
	CLKDSP==EATDSP
	DL1DSP==EATDSP
	DH1DSP==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)		;KLINIK
	@KLEDSP(T1)		;GE 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)
>
	@EATDSP(T1)		;DAS60 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:	EATMSG			;(0)
	EATMSG			;(1)
	TAKCTN			;(2)TAKE CTY-DLS CORRESPONDENCE
	EATMSG			;(3)
	EATMSG			;(4)
	EATMSG			;(5)
	EATMSG			;(6)
	KLNSTS			;(7)
	EATMSG			;(10)
	TAKRDT			;(11)REQUEST FOR DATE/TIME
	EATMSG			;(12)
	EATMSG			;(13)
	EATMSG			;(14)
	EATMSG			;(15)
	EATMSG			;(16)
	EATMSG			;(17)
	EATMSG			;(20)
	EATMSG			;(21)
	EATMSG			;(22)
	EATMSG			;(23)
	TAKROM			;(24)TAKE 11 ROM WORD
	TAKAAL			;(25)ACK ALL
	EATMSG			;(26)
	EATMSG			;(27)
	EATMSG			;(30)
	EATMSG			;(31)
	EATMSG			;(32)
	EATMSG			;(33)

;TEMPORARY DEFINITIONS

;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?
	HRLI	T3,(CAIE T1,)	;YES, SETUP FOR INDIRECT
	XCT	T3		;SKIP IF DIRECT/INDIRECT MODE IS SET CORRECTLY
	POPJ	P,		;NO, ITS NOT
	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
	  DEAD10		;FUNCTION NO GOOD AT ALL . . .
	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



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+<TLINE>B32+<TLINE>B35 ;(5)REQUEST FOR DEVICE STATUS
	0				;(6)UNUSED
	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+<T16BT>B32		;(13)FLUSH TTY LINE OUTPUT
	LGL2E+<TINDR>B32		;(14)SEND ALL
	LGL2X+<TLNGD>B35		;(15)DATASET CONNECTED
	LGL2E+LGL2X+<TLNDT>B32+<TLNGD>B35 ;(16)DATASET HUNG UP
	LGL2E+LGL2X+<TLNGD>B32+<TLNGD>B35 ;(17)DEVICE ACKNOWLEDGE
	LGL2E+<T16BT>B32		;(20)XON
	LGL2E+<T16BT>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
	0				;(32) UNUSED
	LGL16+LGL2E+LGL2X+<TINDR>B32+<TINDR>B35 ;(33)KLINIK PARAMETERS

	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
;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.IBL,(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
;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.

	CPOPJ##			;(-1)LOST TO-10 INDIRECT MESSAGE
EATDSP::EATMSG			;(0)
	EATMSG			;(1)
	EATMSG			;(2)
	EATMSG			;(3)
	EATMSG			;(4)
	EATMSG			;(5)
	EATMSG			;(6)
	EATMSG			;(7)
	EATMSG			;(10)
	EATMSG			;(11)
	EATMSG			;(12)
	EATMSG			;(13)
	EATMSG			;(14)
	EATMSG			;(15)
	EATMSG			;(16)
	EATMSG			;(17)
	EATMSG			;(20)
	EATMSG			;(21)
	EATMSG			;(22)
	EATMSG			;(23)
	EATMSG			;(24)
	EATMSG			;(25)
	EATMSG			;(26)
	EATMSG			;(27)
	EATMSG			;(30)
	EATMSG			;(31)


EATMSG::PUSHJ	P,GT2XFT	;GET THE TO-10 FUNCTION TYPE
	  DEAD10		;FN ALREADY PASS CHECK, MUST HAVE DROPPED
				; THE BALL SOMEWHERE
	PJRST	@EATTAB(T1)	;DISPATCH

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


;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.	T1,ED.2ES,(F)	;GET TO-11 DTE STATE
	CAIN	T1,ED.EDB	;WERE WE WAITING FOR TO-11 DIRECT
				; OR INDIRECT DONE?
	JRST	DTEEDD		;YES, SEE IF WE HAVE TO SEND INDIRECT DATA
	CAIN	T1,ED.EIB	;WAS TO-11 INDIRECT GOING?
	JRST	DTEEDI		;YES, DON'T CHECK INDIRECT COUNT ANYMORE
	PJSP	T1,DTERLD	;SOMEONE FIDDLING

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#
	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 SO
				; HE CAN DEALLOCATE CORE
	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)
	PUSHJ	P,(T3)		;CALL DRIVER'S POST ROUTINE
	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,
				; COUNT IN T1

;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
	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		;SCNSER WIPES OUT F
	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
	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:	.EMCTY			;DO ACKS FOR CTY AND
	.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::PUSHJ	P,SAVE4		;SAVE P1-P4 NOW
	PUSHJ	P,SVEPTD	;GET MASTER ETD ADDRESS
	LOAD.	P1,ED.DTN,(F)	;GET DTE NUMBER IN P1
	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
	MOVE	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
	PUSHJ	P,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

KPSLEN==26			;LENGTH OF PARAMETER SAVE MESSAGE

;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
	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
	PJRST	DTEQUE		;SEND MESSAGE

KPSPTR:	POINT	16,KPSBUF	;POINTER TO SAVE AREA
	$LOW

KPSBUF:	BLOCK	<KPSLEN+3>/4

	$HIGH
SUBTTL KL ERROR STATUS COLLECTING


;KL ERROR INFORMATION IS SENT BY THE MASTER -11 AFTER IT
; RELOADS THE -10. THE DATA COMES AS EITHER ONE OR TWO RECORDS, BUT
; BOTH THESE RECORDS ARE TOO LARGE TO COME OVER AS A SINGLE
; INDIRECT PACKET.  THIS CODE COLLECTS THE FRAGMENTS OF THE RECORDS
; IN FREE CORE AND CALLS DAEMON TO LOOK AT THEM WHEN THE LAST
; PACKET (THE ONE WITH EM.EOF SET) COMES OVER. DAEMON WILL ISSUE
; A DTE. UUO FUNCTION TO RELEASE ALL THE CORE AT ONCE WHEN IT IS
; FINISHED WRITING THE ENTRIES INTO ERROR.SYS. IF DAEMON DOES NOT
; RELEASE THE CORE IN A SPECIFIED AMOUNT OF TIME AFTER THE LAST
; STATUS MESSAGE COMES IN  (SYMBOL
; .KETIM IN DTEPRM, IN MINUTES), THE MONITOR WILL RELEASE THE
; FREE CORE ITSELF, AND DAEMON WILL WRITE A NULL ENTRY INTO
; ERROR.SYS IF IT FINALLY GETS AROUND TO SERVICING THE ERROR LOG
; REQUEST. IF THE -11 QUITS BEFORE SENDING THE LAST MESSAGE,
; THE CORE WILL DISAPPEAR AFTER THE TIMEOUT INTERVAL ALSO.
; IF THE -11 COMES BACK UP AFTER A CRASH BEFORE SENDING THE
; FINAL MESSAGE, THE ACK ALL SERVICE CALL WILL RELEASE THE CORE
; IN THE HOPES THAT THE -11 WILL SEND THE STUFF OVER AGAIN.



;DISPATCH TABLE FOR KLE DEVICE


	KLEREL			;(-1)TO-10 INDIRECT MESSAGE LOST
KLCDSP:
KLEDSP:	EATMSG			;(0)
	EATMSG			;(1)
	EATMSG			;(2)
	EATMSG			;(3)
	EATMSG			;(4)
	EATMSG			;(5)
	EATMSG			;(6)
	KLESTS			;(7)HERE IS DEVICE STATUS
	EATMSG			;(10)
	EATMSG			;(11)
	EATMSG			;(12)
	EATMSG			;(13)
	EATMSG			;(14)
	EATMSG			;(15)
	EATMSG			;(16)
	EATMSG			;(17)
	EATMSG			;(20)
	EATMSG			;(21)
	EATMSG			;(22)
	EATMSG			;(23)
	EATMSG			;(24)
	KLEAAL			;(25)ACK ALL
	EATMSG			;(26)
	EATMSG			;(27)
	EATMSG			;(30)
	EATMSG			;(31)
	EATMSG			;(32)
	KLCKPS			;(33) KLINIK PARAMETER STATUS MESSAGE


;LOCATIONS USED TO KEEP TRACK OF WHERE WE ARE:

	$LOW
KLEEOF:	0		;NON-ZERO IF ALL CHUNKS ARE IN. CLEARED BY KLEREL
KLETIM::0		;SOSN DONE ON THIS LOCATION EVERY MINUTE TO
			; MAKE SURE CHUNKS DON'T STAY ALLOCATED FOREVER
			; IN THE CASE THAT DAEMON IS SICK, WRONG VERSION, ETC.
KLEADR:	0		;LH = ADDRESS OF LAST CHUNK
KLNSTF:	0		;KLINIK STATUS FLAG
			; RH = ADDRESS OF FIRST CHUNK
	$HIGH
;HERE ON RECEIPT OF STATUS MESSAGE

KLNSTS:	SETOM	KLNSTF		;KLINIK STATUS FLAG
KLESTS:	MOVEI	T1,.KLETM+1	;RESET FREE CORE WATCH TIMER EVERY
	MOVEM	T1,KLETIM	;TIME A STATUS MESSAGE COMES IN SO
				; THAT DAEMON WILL HAVE THAT MUCH
				; TIME FROM LAST MESSAGE.
	HRRZ	T2,P3		;GET COUNT OF 8 BIT BYTES
	ADDI	T2,^D36/^D8-1	;ROUND UP TO A 36 BIT WORD'S WORTH
	ASH	T2,-2		;TURN INTO 36 BIT WORDS
	ADDI	T2,SIZE(.KEHDL,36) ;ADD IN SIZE OF HEADER
	PUSHJ	P,MESCOR	;GET THE CORE
	  JRST	EATMSG		;CAN'T, FORGET IT
	MOVE	P4,T1		;GET ADDRESS IN P4, USE FOR POINTER LATER
	HLRZ	T1,P1		;GET CPU NUMBER
	STOR.	T1,KE.CPU,(P4)	;REMEMBER IT
	HRRZ	T1,P1		;GET DTE NUMBER
	STOR.	T1,KE.DTE,(P4)	;THAT TOO
	HLRZ	T1,P2		;GET DEVICE CODE
	STOR.	T1,KE.DEV,(P4)	;STASH
	HLRZ	T1,P3		;GET LINE NUMBER
	STOR.	T1,KE.LIN,(P4)	;STORE THAT TOO
	HRRZ	T1,P3		;GET 8 BIT COUNT AGAIN
	STOR.	T1,KE.CNT,(P4)	;SAVE FOR DAEMON
	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)
	CONO	PI,PIOFF##	;LINK UP THIS BLOCK ALONE
	HLRZ	T1,KLEADR	;GET POSSIBLE LAST ADDRESS
	JUMPE	T1,KLEST1	;JUMP IF NEED TO MAKE NEW CHAIN
	STOR.	P4,KE.LNK,(T1)	;NO, LAST ENTRY POINTS TO THIS ONE
	HRLM	P4,KLEADR	;THIS IS NEW LINKING PLACE
	JRST	KLEST2		;GO TURN PI BACK ON
KLEST1:	HRRM	P4,KLEADR	;SETUP NEW FIRST AND
	HRLM	P4,KLEADR	;LAST ADDRESS
KLEST2:	CONO	PI,PION##	;TURN PI BACK ON
	ADDI	P4,SIZE(.KEHDL,36) ;POINT TO FIRST WORD WITH DATA
	HRLI	P4,(POINT 16,)	;MAKE BYTE POINTER
	MOVSI	S,KLESDN	;ADDRESS TO GO WHEN XFER IS DONE
	POPJ	P,		;RETURN AND START XFER


;HERE WHEN DATA IS IN. CHECK GENERAL STATUS TO SEE IF EOF, IF SO
; CALL DAEMON


KLESDN:	SUBI	P4,SIZE(.KEHDL,36) ;SO REFERENCE TO KE.1WD WILL WORK
	LOAD.	T1,KE.1WD,(P4)	;GET STATUS BYTE
	TRNN	T1,EM.EOF	;TIME TO CALL DAEMON?
	SKIPE	KLNSTF		;KLINIK STATUS?  TIME TO CALL
	CAIA
	POPJ	P,		;NO, JUST LET THIS CHUNK LIE AROUND
	AOS	KLEEOF		;EOF HAS BEEN SEEN, CALL OFF THE ACK ALL
				; ROUTINE
	MOVEI	T1,.ERKLE	;CODE FOR DAEMON
	HRL	T1,KLEADR	;ADDRESS TO LOOK AT FOR DATA
	PJRST	DAEEIM##	;BLAME IT ON JOB 0


;HERE ON ACK ALL. IF CORE EXISTS AND EOF HAS NOT BEEN SENT, RELEASE
; THE CORE SO THAT THE ERROR INFO DOESN'T REPEAT

KLEAAL:	MOVEI	T1,-1		;SETUP TO CHECK FOR EXISTANCE OF ERROR DATA
	TDNE	T1,KLEADR	;IS THERE A CHAIN AND
	SKIPE	KLEEOF		;IS IT UNFINISHED?
	POPJ	P,		;NO
	PJRST	KLEREL		;YES, DO NOT LEAVE UNFINISHED CHAIN



;ROUTINE TO RELEASE THE KLERR CHUNKS. CALLED 5 MINUTES AFTER DAEMON IS
; CALLED, OR ON DTE. UUO FUNCTION THAT DAEMON DOES.

KLEREL::PUSHJ	P,SAVE1##	;SAVE P1 TO REMEMBER NEXT CHUNK ADDRESS
	HRRZ	P1,KLEADR	;GET START OF LIST
KLERE1:	JUMPE	P1,KLERE2	;JUMP IF NO MORE TO RELEASE
	MOVE	T2,P1		;GET ADDRESS INTO T2 FOR GIVMES
	LOAD.	P1,KE.LNK,(T2)	;GET NEXT CHUNK TO DEALLOCATE
	LOAD.	T1,KE.CNT,(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,SIZE(.KEHDL,36) ;DEALLOCATE HEADER TOO
	PUSHJ	P,GIVMES	;CALL WITH ADDR IN T2, COUNT IN T1
	JRST	KLERE1		;GO FOR MORE TO DEALLOCATE
KLERE2:	SETZM	KLEADR		;CLEAR LAST,,FIRST ADDRESSES
	SETZM	KLNSTF		;CLEAR KLINIK STATUS FLAG
	SETZM	KLEEOF		;NO MORE END OF FILE
	POPJ	P,		;RETURN
SUBTTL PROTOCOL CONTROL

	XLIST		;DON'T PRINT LITERALS
	LIT
	LIST
	$LOW

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

ENTSPC::PUSHJ	P,SVEPTD	;SAVE F,T4 AND SETUP DTE & EPT ADDRESSES
	MOVSI	T2,(ED.PPC)	;GET READY TO CLEAR PRIMARY PROTOCOL BIT
	CONO	PI,PIOFF##	;IN CASE STUFF IS RUNNING
	ANDCAM	T2,ETDSTS(F)	;CLEAR BIT. NOW INTERRUPTS WILL GO
				; THRU SECONDARY INTERRUPT ROUTINE
	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,DTERLD	;NO, GO KILL -11
	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
	CONO	PI,PION##	;TURN ON PI SYSTEM AND
	POPJ	P,		;RETURN. (DON'T USE ONPOPJ BECAUSE
				; ITS NOT AROUND EARLY ENOUGH)


	XLIST		;DON'T PRINT LITERALS
	LIT
	LIST
	$HIGH

;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)
	PUSHJ	P,GTCPUN	;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
;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
IFN FTNET,<
	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)
	PUSHJ	P,NCLDWN##	;TELL NCL IT MAY HAVE LOST A NODE
>	;IFN FTNET
	POPJ	P,		;RETURN
;STMPPC -- ROUTINE TO START PRIMARY PROTOCOL ON MASTER DTE
; FOR THE FIRST TIME.
; CALLED FAIRLY EARLY IN THE MONITOR INITIALIZATION SO THAT THE DATE AND TIME CAN
; BE OBTAINED FROM THE 11 INSTEAD OF FROM THE OPERATOR THROUGH THE
; ONCE ONLY DIALOG QUESTIONS. DTEINI MUST BE CALLED FIRST.
;
;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

STMPPC::PUSHJ	P,SVEPTD	;SAVE F,T4 AND GET DTE,EPT ADDRESSES
	PUSHJ	P,STXPP1	;CALL COMMON CODE
	  POPJ	P,		;TOUGH LUCK, GIVE ERROR RETURN
	LOAD.	P1,ED.DTN,(F)	;GET DTE NUMBER
	LOAD.	T1,ED.CPN,(F)	;AND CPU NUMBER
	HRL	P1,T1		;SETUP CPU#,,DTE# IN P1
	MOVE	P2,[.EMCLK,,.EMRDT] ;REQUEST TIME AND DATE
				; SO THAT -11 WILL SEND US CPU AND KLERR INFORMATION
				; AND LINE SPEEDS (LINE SPEEDS IGNORED)
	SETZB	P3,P4		;CLEAR OUT UNUSED ACS
	SETZ	S,		;NO POST ADDRESS
	PJRST	DTEQUE		;GIVE ERROR RETURN IF DTEQUE GIVES ONE,
				; OTHERWISE DTEQUE GIVES SKIP RETURN



STXPPC:	PUSHJ	P,GTEPT		;GET EPT, F ALREADY SET UP

STXPP1:	PUSHJ	P,SAVE4##	;SAVE P1-P4 FOR CALL TO DTEQUE
	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
	LOAD.	T3,ED.210,(F)	;GET 11'S TO-10 SECTION ADDRESS
	MOVSI	T2,(EC.VEX!EC.QIU);VALID EXAMINE, Q PROTOCOL IN USE
	MOVEM	T2,ETCSTS(T3)	;INITIALIZE STATUS WORD
				;(ZEROES QUEUE COUNTS TOO)
	LOAD.	T3,ED.211,(F)	;DO SAME FOR 10'S TO-11 AREA
	MOVEM	T2,ETCSTS(T3)	;..
	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
	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
	ASH	T2,3		;CONVERT SIZE OF OWNERS SECTION TO WORDS
	MOVEM	T2,DTEDPW(T4)	;THAT'S THE DEPOSIT RELOCATION
				;***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 THING 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
	DEAD10			;***TEMPORARY***
	LOAD.	T1,ED.QUE,(F)	;DON'T LET CORE DISAPPEAR
	SKIPE	T1
	DEAD10			;***TEMPORARY***
	MOVSI	T1,(ED.DTM)	;IS THIS THE MASTER?
	TDNN	T1,ETDSTS(F)	;?
	JRST	STXPP2		;NO, JUST RING DOORBELL
	MOVEI	T1,DT.LSP!DT.RST;LEAVE SECONDARY PROTOCOL, RESET COMM REGION
	PUSHJ	P,SPCMD		;DO IT
	MOVSI	T1,(ED.SPC)	;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
	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
	PUSHJ	P,DTEQUE	;SEND THE MESSAGE
	  POPJ	P,		;NO GOOD, GIVE ERROR RETURN
	PUSHJ	P,DTESDT	;SEND DATE/TIME TO -11
	JRST	CPOPJ1##	;AND GIVE SKIP RETURN
STXPP2:	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
IFN FTNET,<
	PUSHJ	P,NCLUP##	;TELL NCL IT MAY HAVE GOTTEN A NEW NODE
>
	JRST	CPOPJ1##	;GIVE GOOD 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)
	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:	POP	P,T4
	POP	P,F		;RESTORE F, T4
	JRST	(T3)		;AND RETURN TO CALLER'S PC IMMEDIATELY
;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
SUBTTL ONCE PER SECOND ACTIVITIES

DTESEC::MOVE	T1,UPTIME##	;GET UPTIME (COUNT ON IT BEING INCREMENTED
				; AT APR CLOCK LEVEL)
	CAMGE	T1,DTSTIM	;TIME TO TO ONCE A SECOND STUFF?
	POPJ	P,		;NO, RETURN DOING NOTHING
	ADD	T1,TICSEC##	;GET WHAT UPTIME SHOULD BE NEXT TIME
	MOVEM	T1,DTSTIM	;REMEMBER
				;(THE ABOVE CODE IS MADE NECESSARY
				; BY THE CASE WHERE MANY SECONDS ARE LOST
				; DURING PARITY ERROR SWEEP. DTESEC
				; WILL GET CALLED ONCE A TICK UNTIL
				; ALL THE MISSED TICKS ARE COMPENSATED FOR)

	PUSH	P,F		;SAVE FOR DTE CONTROL BLOCK
	MOVEI	T4,0		;START WITH FIRST DTE
DTESC1:	MOVE	F,T4		;GET NEXT DTE # (CPU # ALWAYS ZERO)
				;***SMP***
	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

	$LOW
DTSTIM:	BLOCK	1		;UPTIME AT NEXT SECOND FOR DTESEC
	$HIGH
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?
	DEAD10			;YES, SOMEONE GOOFED
	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 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:	MOVSI	T1,(ED.PPC)	;IF RUNNING PRIMARY PROTOCOL,
	TDNE	T1,ETDSTS(F)	;
	PUSHJ	P,LEVPPC	;LEAVE PRIMARY PROTOCOL ON THIS DTE/11
	MOVEI	T1,CLRDTE+PILDEN+0 ;CLEAR THIS DTE AND ZERO PI ASSIGNMENT
	XCT	ETDCNO(F)
	MOVSI	T1,(ED.RLD)	;CLEAR RELOAD BIT
	ANDCAM	T1,ETDSTS(F)	;SINCE THIS 11 IS NOW QUIET.
	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 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.

	$LOW			;SYSINI USES SPCMD BEFORE HISEG SETUP

DTERLD::MOVEM	T1,DTELCP	;SAVE LAST -11 CRASH PC
	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
	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)

;HERE FROM COMMON DURING POWER FAILURE

DTEPWF::PUSHJ	P,GTEPD		;FIND COMM REGION
	LOAD.	T2,ED.211,(F)	;FIND CFE'S AREA
	MOVSI	T1,(EC.PWF)	;"OUR POWER FAILED"
	IORM	T1,ETCSTS(T2)	;LIGHT IT BEFORE LIGHTS OUT
	MOVEI	T1,TO11DB
	XCT	ETDCNO(F)	;TELL -11
	POPJ	P,
	$HIGH
SUBTTL MISCELLANEOUS UTILITY ROUTINES

	$LOW	
	XLIST			;DON'T PRINT LITERALS
	LIT
	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
	  DEAD10		;SORRY, BAD SPECIFICATION
	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,CPUN##	;IN RANGE?
	POPJ	P,		;NO, GIVE ERROR INDICATION
	PUSHJ	P,GTCPUD	;GET CPU DATA BLOCK IN T2
	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
	CAML	T3,.CPDTN##(T2)	;IS DESIRED DTE NUMBER LESS THAN NUMBER OF DTES?
	POPJ	P,		;NO, GIVE ERROR RETURN
	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
	AOS	(P)		;AND SUCCEED (CALLED BY SYSINI, NEED THE
				; AOS HERE)
	POPJ	P,		;RETURN

	XLIST		;DON'T PRINT LITERALS
	LIT
	LIST
	$HIGH
;ROUTINE TO GET TWO EIGHT BIT BYTES FROM A MESSAGE, SWAP THEM, AND
; RETURN THEM AS A 16 BIT BYTE. USES ETDMSP(F) 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
;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
	$LOW
	XLIST		;DON'T PRINT LITERALS
	LIT
	LIST
			;USED DURING SYSINI

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:	PUSHJ	P,GTCPUN	;GET CPU NUMBER OF CALLING CPU
	MOVE	F,DTEMAS##(T1)	;GET DTE CONTROL BLOCK OF MASTER DTE
GTEPT:	MOVE	T4,ETDCDB(F)	;GET CDB ADDRESS
	MOVE	T4,.CPTOS##(T4)	;NOW GET EPT ADDRESS OF CALLING CPU
	POPJ	P,		;DONE.

;ROUTINE TO RETURN CPU NUMBER OF CALLING CPU IN T1

GTCPUN:	SETZ	T1,		;ASSUME CPU0
	SKPCPU(0)		;IS IT?
	MOVEI	T1,1		;NO, ITS CPU1
				;***SMP!***
	POPJ	P,		;EASILY DONE FOR NOW

;ROUTINE TO GET CPU DATA BLOCK FOR CPU WHOSE NUMBER IS IN T1
; RETURNS THE CPU NUMBER IN T1, CPU DATA BLOCK ADDRESS IN T2

GTCPUD:	MOVEI	T2,.C0CDB##	;ASSUME CPU0
	SKIPE	T1		;IS IT? (***SMP***)
IFN FTMS,<
	MOVEI	T2,.C1CDB##	;YES, GET CPU1'S CDB
>;END IFN FTMS

IFE FTMS,<
	DEAD10			;ONLY ONE
>;END IFE FTMS

	POPJ	P,		;RETURN
	$HIGH
	XLIST		;DON'T PRINT LITERALS
	LIT
	LIST

DTE2EE:
DTE2XE:
	STOPCD	.,HALT,TXE,	;TO 10/11 ERROR


DEDTEN:	STOPCD(.,STOP,D10)	;++DEAD 10

	$LOW
DTELCP::0			;LAST PC ON AN -11 RELOAD
DTRJOB:	Z			;JOB TO WAKE ON 11 RELOAD
	$LIT
DTEEND:	END