Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - fedser.mac
There are 6 other files named fedser.mac in the archive. Click here to see a list.
TITLE FEDSER - FRONT END DEVICE SERVICE ROUTINES V20
SUBTTL E. SOCCI/EVS			01 FEB 77
	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==10
; 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
;***COPYRIGHT 1976,1977, DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VFEDSR,20

	SALL		;CLEAN MACRO EXPANSIONS
	ENTRY	FEDSER

FEDSER::
SUBTTL DTE. UUO FRONT END DEVICE FUNCTIONS


;FUNCTION TO GET FRONT END DEVICE
; ADDR/CPU#,,DTE#
; ADDR+1/FED UNIT #
;

FEDGET::PUSHJ	P,GETFEB	;GET FRONT END DEVICE BLOCK IN F FROM USER AREA
	  JRST	DTUNXF##	;FRONT END DEVICE DOES NOT EXIST
	CONO	PI,PIOFF##	;DISALLOW INTERFERENCE
	LOAD.	T1,FE.JOB,(F)	;GET JOB OWNING THE FRONT END DEVICE
	JUMPN	T1,[CONO PI,PION## ;SOMEONE ALREADY HAS IT
		    JRST DTUFDB##] ;FRONT END DEVICE BUSY ERROR
	PUSHJ	P,FEDCLR	;CLEAR OUT THE BITS IN FEDSTS FIRST
	STOR.	J,FE.JOB,(F)	;STORE OUR JOB NUMBER
	PUSHJ	P,FEDGTC	;ALLOCATE INPUT AND OUTPUT BUFFERS
	  POPJ	P,		;OOPS, COULDN'T DO IT
				; WAIT FOR EVENTUAL RELEASE
	JRST	CPOPJ1##	;RETURN

;FUNCTION TO RETURN A FRONT END DEVICE

FEDGIV::PUSHJ	P,GETFEB	;GET FRONT END DEVICE BLOCK IN F
	  JRST	DTUNXF##	;DOESN'T EXIST
	JSP	T4,FEJCHK	;MAKE SURE WE OWN IT
	PUSHJ	P,FEDCLR	;CLEAR OUT THE FRONT END DEVICE
	JRST	CPOPJ1##	;AND RETURN

;HERE FROM RESET. CHECK TO SEE IF THE JOB OWNS A FRONT END DEVICE,
; AND GIVE IT UP IF SO.

FEDRST::PUSHJ	P,SAVE2##	;SAVE P1,P2
	MOVEI	P2,3		;SCAN 4 FRONT ENDS
FEDRS0:	MOVEI	P1,3		;AND 4 FRONT END DEVICES
FEDRS1:	MOVE	F,P2		;GET CPU#,,DTE# IN F FOR GETETD
	PUSHJ	P,GETETD##	;GET DTE CONTROL BLOCK ADDR FOR GETFE0
	  JRST	FEDRS3		;THIS FRONT END DOESN'T EXIST
	MOVE	T1,P1		;GET UNIT NUMBER IN T1
	PUSHJ	P,GETFE0	;GET THAT FRONT END BLOCK
	  JRST	FEDRS2		;DOESN'T EXIST
	LOAD.	T1,FE.JOB,(F)	;GET JOB OWNING IT
	CAMN	J,T1		;SAME AS THIS JOB?
	PUSHJ	P,FEDCLR	;YES, RELEASE THIS FRONT END DEVICE
FEDRS2:	SOJGE	P1,FEDRS1	;DO NEXT FRONT END DEVICE ON THIS FE
FEDRS3:	SOJGE	P2,FEDRS0	;DO NEXT FRONT END
	POPJ	P,		;DONE
;ROUTINE TO DO ACTUAL RELEASE OF FRONT END DEVICE. CALLED FROM DTE.
; UUO, RESET UUO. CALL WITH FRONT END DEVICE BLOCK IN F.

FEDCLR:	SETZ	T1,		;CLEAR OUT JOB NUMBER
	STOR.	T1,FE.JOB,(F)	;IN FED BLOCK
	MOVE	T1,[FE.CLR]	;BITS TO CLEAR IN STATUS
	ANDCAM	T1,FEDSTS(F)	;CLEAR THEM
	PJRST	FEDRLC		;RELEASE BUFFER CORE AND RETURN
SUBTTL FRONT END DEVICE INPUT ROUTINES


FEDUIN::PUSHJ	P,SAVE4##
	PUSHJ	P,GETFEB	;GET FRONT END BLOCK ADDRESS IN F
	  JRST	DTUNXF##	;DOES NOT EXIST
	JSP	T4,FEJCHK	;MAKE SURE WE OWN THE FRONT END DEVICE IN QUESTION

	PUSHJ	P,GETWD1##	;GET BYTE COUNT,,ADDRESS
	HRRI	M,-1(T1)	;POINT TO WORD BEFORE THE ADDRESS
	HLRZ	P3,T1		;GET COUNT IN P3
	JUMPE	P3,DTUBCE##	;IF ZERO, ERROR IN BYTE COUNT
IFN FTVM,<
	MOVE	T2,P3		;GET 16 BIT BYTE COUNT
	ASH	T2,-1		;TURN INTO 36 BIT WORD COUNT
	ADDI	T2,(T1)		;C(T2) NOW HAS LAST ADDRESS
	PUSHJ	P,TRNGE##	;MAKE SURE ITS ALL IN CORE
>;END IFN FTVM
	MOVSI	T1,(FE.EOF)	;CLEAR END OF FILE FLAG
	ANDCAM	T1,FEDSTS(F)
	SETZ	P1,		;CLEAR COUNT OF BYTES GIVEN TO USER

FEDUI1:	MOVE	T3,FEDPPT(F)	;GET PUT POINTER
	CAMN	T3,FEDTPT(F)	;SEE IF SAME AS TAKE
	JRST	FEDUI2		;THEY ARE, NEED MORE DATA
	ILDB	T2,FEDTPT(F)	;GET A BYTE
	TRNN	P1,1		;GOES IN LH?
	JRST	[HRLZ	T1,T2	;YES
		 JRST	.+2]
	HRR	T1,T2		;NO, PUT IN RH WITH THE OTHER BYTE
	AOS	P1		;ONE MORE BYTE FOR USER
	TRNN	P1,1		;BACK TO A LH BYTE?
	PUSHJ	P,PUTWD1##	;YES, GIVE 2 BYTES TO THE USER
	CAMGE	P1,P3		;ITS NOT, HAVE WE GIVEN USER ALL HE ASKED FOR?
	JRST	FEDUI1		;NO, KEEP GIVING
	TRNE	P1,1		;YES, STILL KEEPING A LH BYTE IN T1?
	PUSHJ	P,PUTWD1##	;YES, STORE THE ODD BYTE
	JRST	CPOPJ1##	;RETURN TO USER WITH THE DATA IN HIS BUFFER.
FEDUI2:	PUSH	P,T1		;SAVE POSSIBLE BYTE IN LH(T1)
	CONO	PI,PIOFF##	;MUST TURN OFF PI SO WE DON'T GET INPUT
				; DATA FOR FED WHILE UPDATING PUT POINTER
	PUSHJ	P,FEDSPT	;SETUP THE POINTERS AND FREE COUNT
	CONO	PI,PION##	;TURN PI BACK ON.
				; NOTE THAT FRONT END CAN NOW SEND DATA,
				; BEFORE WE SEND ACK THUS WE SEND ACK
				; WHEN LESS THAN WHOLE BUFFER IS AVAILABLE.
				; TO GET AROUND THIS, BUFFER SIZE IS TWICE
				; ALLOCATION
	PUSH	P,P1		;SAVE COUNT OF BYTES GIVEN TO USER
	PUSH	P,P3		;AND COUNT USER WANTS
	LOAD.	P1,FE.DTN,(F)	;GET DTE NUMBER OF THIS FE DEVICE
	LOAD.	T1,FE.UNI,(F)	;GET FRONT END UNIT NUMBER
	LSH	T1,^D35-^D15	;POSITION LINE NUMBER IN 1ST 16 BIT BYTE
	PUSH	P,T1		;SAVE IT SOMEWHERE
	MOVEI	P4,(P)		;GET ADDRESS OF DATA TO PUT INTO MSG IN P4
	HRLI	P4,(POINT 8,)	;MAKE INTO 8 BIT BYTE POINTER
	MOVEI	P3,2		;2 8 BIT BYTES TO COPY FOR LONG DIRECT MSG
	MOVE	P2,[.EMFED,,.EMACK] ;ACK TO FRONT END DEVICE
	MOVSI	S,CPOPJ##	;POST ADDRESS,,DATA
	PUSHJ	P,DTEQUE##	;ASK FOR DATA
	JRST	[ADJSP P,-4	;POP ALL THAT STUFF OFF STACK
		 JRST DTUCSM##]	;AND GIVE CAN'T SEND -11 MESSAGE ERROR
	POP	P,T1		;TAKE TEMPORARY PART OF MSG OFF STACK
	POP	P,P3		;AND USER'S SUPPLIED BYTE COUNT
	POP	P,P1		;AND COUNT GIVEN TO USER SO FAR
	PUSHJ	P,FEDWTI	;WAIT FOR THE BUFFER
	  JRST	FEDUI6		;OOPS, FATAL ERROR.
	POP	P,T1		;RESTORE POSSIBLE LH BYTE
	JRST	FEDUI1		;REJOIN LOOP AS IF BUFFER WAS INFINITE

FEDUI6:	POP	P,T1		;GET JUNK OFF STACK
	JRST	DTUFER##	;GO GIVE FATAL ERROR


;ROUTINE TO WAIT FOR FRONT END DEVICE INPUT BUFFER TO BECOME
; AVAILABLE. RETURNS CPOPJ1 IF IT IS, CPOPJ IF A FATAL ERROR
; HAS OCCURED IN THE FED.

FEDWTI:	MOVSI	T1,(FE.FER)	;HAS AN ERROR OCCURED?
	TDNE	T1,FEDSTS(F)
	POPJ	P,		;YES, GIVE THE ERROR RETURN.
	MOVE	T1,FEDTPT(F)	;GET TAKE POINTER
	CAME	T1,FEDPPT(F)	;NEED TO WAIT?
	JRST	CPOPJ1##	;NO, WE HAVE MORE DATA
	MOVEI	T1,EV.FEI	;FRONT END INPUT WAIT
	PUSHJ	P,ESLEEP##	;GO INTO EVENT WAIT, WAKE UP WHEN DATA IS READY
	JRST	FEDWTI		;MAKE SURE ALL IS OK

;HERE TO TAKE STRING DATA FOR A FRONT END DEVICE. P1-P4 SETUP BY
; DTESER TO BE THE STANDARD THINGS (SEE DTESER).

FEDTKD:	PUSHJ	P,FDIGET	;GET FED CONTROL BLOCK ADDRESS IN F
	LOAD.	T1,FE.JOB,(F)	;GET CONTROLLING JOB NUMBER
	JUMPE	T1,EATMSG##	;IF NONE, JUST EAT UP THE DATA
	HRRZ	T2,P3		;GET 8 BIT BYTE COUNT IN T2
				; IT HAD BETTER BE EVEN
	TRNE	T2,1		;BYTE COUNT EVEN? (SHOULD BE 16 BIT BYTES)
	JRST	FEDTKE		;NO, GIVE ERROR
	ASH	T2,-1		;CONVERT TO 16 BIT BYTE COUNT
	CAMLE	T2,FEDFBI(F)	;ENOUGH ROOM? (HAD BETTER BE OR ELSE
				; FRONT END IS PROBABLY SENDING TOO MUCH)
	JRST	FEDTKE		;YES TO EITHER, GIVE FATAL ERROR TO UUO
	MOVN	T3,T2		;GET COPY OF LENGTH OF MESSAGE
	ADDM	T3,FEDFBI(F)	;UPDATE COUNT OF FREE BYTES IN BUFFER
	MOVSI	S,FEDTDD	;THE POST PLACE
	MOVE	P4,FEDPPT(F)	;GET POINTER TO STORE DATA WITH
	ADJBP	T2,P4		;PUT POINTER TO NEXT PLACE TO STORE DATA
	MOVEM	T2,FEDPPT(F)
	POPJ	P,		;RETURN TO DTESER, WHO WILL DO INDIRECT
				; XFER.

;HERE IF THERE WAS A PROBLEM, GIVE UUO FATAL ERROR RETURN WHEN IT
; NEXT LOOKS.
FEDTKE:	MOVSI	T1,(FE.FER)	;YES TO EITHER, GIVE FATAL ERROR TO UUO
	IORM	T1,FEDSTS(F)	;SET BIT
	PUSHJ	P,FEDWKJ	;WAKE UP CORRECT JOB IF WAITING
	PJRST	EATMSG##	;EAT REMAINING DATA AND RETURN

;HERE WHEN DATA TRANSFER TO THE TO-10 BUFFER IS COMPLETE.

FEDTDD:	PUSHJ	P,FDIGET	;GET FED BLOCK FROM C(P2), C(P3)
				;FALL INTO FEDWKJ



;HERE TO REMOVE A JOB FROM EVENT WAIT ASSOCIATED WITH A FRONT END DEVICE IF IT
; EXISTS. CALL WITH FRONT END DEVICE BLOCK ADDRESS IN F.
; ALWAYS RETURNS CPOPJ.


FEDWKJ:	LOAD.	T1,FE.JOB,(F)	;GET JOB NUMBER OWNING THIS
	JUMPE	T1,CPOPJ##	;DO NOTHING IF THERE IS NONE
	PJRST	EWAKE##		;THERE IS ONE, WAKE THE JOB UP IF ITS WAITING FOR SOMETHING
SUBTTL FRONT END DEVICE OUTPUT ROUTINES


;HERE FROM DTESER ON FRONT END DEVICE OUTPUT FUNCTION OF DTE. UUO

FEDUOU::PUSHJ	P,SAVE4##	;WE WILL BE CALLING DTEQUE
	PUSHJ	P,GETFEB	;SETUP FED BLOCK ADDRESS IN F FROM USER ARGS
	  JRST	DTUNXF##	;NON-GOOD
	MOVE	P1,T1		;GETFEB RETURNS CPU#,,DTE# IN T1
				; SO SAVE IN P1 FOR MAKING MESSAGE LATER
	JSP	T4,FEJCHK	;DOES THIS GUY HAVE THE RIGHT?
				; IF NOT, GO AWAY AND GIVE HIM UUO ERROR RETURN


FEDUO1:	PUSHJ	P,GETWD1##	;GET BYTE COUNT,,ADDRESS
	HLRZ	P3,T1		;GET 16 BIT BYTE COUNT IN P3
	HRRI	M,-1(T1)	;ADDRESS-1 IN RH(M) FOR GETWD1
	JUMPE	P3,DTUBCE##	;ZERO IS ERROR
IFN FTVM,<
	MOVE	T2,P3		;GET 16 BIT COUNT
	ASH	T2,-1		;MAKE 36 BIT COUNT
	ADDI	T2,(T1)		;MAKE IT LAST ADDRESS
	PUSHJ	P,TRNGE##	;MAKE SURE ALL PAGES ARE THERE
>;END IFN FTVM

FEDUO2:	PUSHJ	P,FEDWTO	;WAIT FOR OUTPUT BUFFER TO BE OURS
	  JRST	DTUFER##	;SOMETHING HAPPENED . . .
	MOVE	P4,FEDOBF(F)	;ADDRESS TO PUT BYTES
	HRLI	P4,(POINT 16,)	;MAKE INTO A POINTER
	MOVE	P2,P3		;GET COPY OF COUNT FOR LOOP
	CAILE	P2,.FEOSZ	;IS COUNT BIGGER THAN A BUFFER?
				; (/2 BECAUSE BUFFER SIZE IS TWICE ALLOCATION)
	MOVEI	P2,.FEOSZ	;YES, JUST DO A BUFFER FULL NOW - 
	PUSH	P,P2		;SAVE COUNT OF DATA TO SEND OUT NOW

FEDUO3:	PUSHJ	P,GETWD1##	;GET 2 BYTES FROM USER
	HLRZ	T2,T1		;GET FIRST BYTE
	IDPB	T2,P4		;PUT INTO FED BUFFER
	SOJLE	P2,FEDU3A	;JUMP IF FINISHED
	IDPB	T1,P4		;PUT SECOND ONE INTO FED OUTPUT BUFFER
	SOJG	P2,FEDUO3	;LOOP UNTIL USER DATA EXHAUSTED

FEDU3A:	EXCH	P3,(P)		;SAVE TOTAL COUNT, GET COUNT FOR THIS OUTPUT
	ASH	P3,1		;MAKE THIS # 8 BIT BYTES FOR DTESER
	LOAD.	T1,FE.UNI,(F)	;GET UNIT NUMBER OF THIS FRONT END DEVICE
	HRL	P3,T1		;UNIT,,COUNT
	MOVE	P4,FEDOBF(F)	;GET ADDRESS OF BUFFER
	HRLI	P4,(POINT 16,)	;MAKE IT BYTE POINTER
	MOVE	P2,[.EMFED,,EM.16B+EM.IND+.EMSTR] ;DEVICE,,FN
				;P1 WAS SETUP AT VERY BEGINNING
	MOVSI	S,CPOPJ##	;NO POST, WAIT FOR THE ACK THATS COMING
	MOVSI	T1,(FE.OAE)	;GIVE UP THE BUFFER, MAKING THE NEXT UUO BLOCK
	IORM	T1,FEDSTS(F)	;
	PUSHJ	P,DTEQUE##	;SEND THE DATA TO THE -11
	  JRST	[POP P,P3	;GET P3 BACK OFF STACK
		 JRST DTUCSM##]	;CAN'T SEND -11 MESSAGE
	POP	P,P3		;RESTORE COUNT OF BYTES LEFT TO BE DONE
	SUBI	P3,.FEOSZ	;WE'VE JUST DONE LESS THAN OR EQUAL TO A
				; WHOLE BUFFER - ANY BYTES LEFT TO DO?
	JUMPG	P3,FEDUO2	;YES, GO DO THEM
	JRST	CPOPJ1##	;NO, RETURN TO USER RIGHT AWAY, LETTING HIM
				; FILL ANOTHER BUFFER


;ROUTINE TO WAIT FOR OUTPUT BUFFER TO FREE UP
; SKIP RETURN WHEN OUTPUT BUFFER IS READY, NON-SKIP IF FATAL ERROR FLAG
; IS UP.

FEDWTO:	MOVSI	T1,(FE.FER)	;CHECK FOR FATAL ERROR
	TDNE	T1,FEDSTS(F)	;?
	PJRST	DTUFER##	;YEAH, GOODBYE.
	MOVSI	T1,(FE.OAE)	;CAN WE STUFF OUTPUT BUFFER WITH DATA?
	TDNN	T1,FEDSTS(F)	;?
	JRST	CPOPJ1##	;YES, GIVE SKIP RETURN
	MOVEI	T1,EV.FEO	;NO, GO INTO OUTPUT WAIT
	PUSHJ	P,ESLEEP##	;ZZZZ
	JRST	FEDWTO		;MAKE SURE EVERYTHING IS OK
;HERE WHEN THE 11 CAN ACCEPT MORE DATA FOR A FRONT END DEVICE
; (ACK)

FEDACK:	ILDB	T1,P4		;GET LINE NUMBER
	IBP	P4		;ADVANCE PAST BLANK BYTE
	SUBI	P3,2		;REMEMBER WE'VE TAKEN 2 BYTES
	PUSHJ	P,FDIGT0	;GET FED BLOCK ADDRESS IN F
	MOVSI	T1,(FE.OAE)	;MAKE OUTPUT BUFFER AVAILABLE TO UUO AGAIN
	ANDCAM	T1,FEDSTS(F)
	PUSHJ	P,FEDWKJ	;AND WAKE UP THE JOB IF ITS SLEEPING
	JUMPN	P3,FEDACK	;LOOP IF MORE ACKS ARE IN THIS MESSAGE
	POPJ	P,		;ALL DONE


;HERE ON ACK ALL - IF SOMEONE IS USING A FRONT END DEVICE, GIVE HIM
; AN ERROR

FEDAAL:	LOAD.	F,ED.FED,(F)	;GET FIRST FRONT END DEVICE ADDRESS
FEDAA1:	JUMPE	F,CPOPJ##	;DONE
	LOAD.	T1,FE.JOB,(F)	;GET JOB #, IF ANY
	JUMPE	T1,FEDAA2	;NO JOB OWNS IT, GET NEXT FED ON THIS FE
	MOVSI	T1,(FE.FER)	;SOMEONE IS USING, GIVE HIM THE FINGER
	IORM	T1,FEDSTS(F)	;
	PUSHJ	P,FEDWKJ		;RUDE AWAKENING
FEDAA2:	LOAD.	F,FE.LNK,(F)	;GET NEXT ADDRESS
	JRST	FEDAA1		;AND LOOP FOR ALL FRONT END DEVICES ON THIS DTE


SUBTTL FRONT END DEVICE STATUS HANDLING

;HERE ON DTE. UUO THAT OBTAINS STATUS
;ADDR/CPU#,,DTE#
;ADDR+1/FE DEVICE #
; USER GETS STATUS OF FRONT END DEVICE RETURNED IN HIS AC.


FEDUGS::PUSHJ	P,GETFEB	;GET FED BLOCK FROM USER ARGS
	  JRST	DTUNXF##	;SORRY
	JSP	T4,FEJCHK	;MAKE SURE HE OWNS THE FE DEVICE
	MOVE	T2,FEDSTS(F)	;GET STATUS WORD
	SETZ	T1,		;PREPARE RESULT

	TLNE	T2,(FE.EOF)	;EOF?
	TRO	T1,EM.EOF	;YES
	TLNE	T2,(FE.FER)	;FATAL ERROR?
	TRO	T1,EM.FER	;YES
	JRST	STOTC1##	;RETURN RESULT IN T1


;HERE FOR DTE. UUO FUNCTION TO SET FRONT END DEVICE STATUS
;ADDR/CPU#,,DTE#
;ADDR+1/FE DEVICE #
;ADDR+2/STATUS

FEDUSS::PUSHJ	P,SAVE4##	;WE WILL BE CALLING DTEQUE
	PUSHJ	P,GETFEB	;GET FRONT END DEVICE BLOCK, AS USUAL
	  JRST	DTUNXF##
	JSP	T4,FEJCHK	;MAKE SURE HE OWNS THE FE DEVICE
	PUSHJ	P,GETWD1##	;GET THE STATUS SETTING DESIRED
	DPB	T1,[POINT 16,FEDSOB(F),15] ;PUT INTO THE MESSAGE
	MOVEI	P4,FEDSOB(F)	;GET ADDRESS OF INDIRECT DATA
	HRLI	P4,(POINT 16,)	;MAKE INTO A BYTE POINTER
	LOAD.	T1,FE.UNI,(F)	;GET UNIT NUMBER OF FRONT END DEVICE
	HRL	P3,T1		;SETUP UNIT # IN LH(P3)
	HRRI	P3,.FESMS*2	;# 8 BIT BYTES IN THE INDIRECT MESSAGE
	MOVE	P2,[.EMFED,,EM.16B+EM.IND+.EMHDS] ;HERE IS DEVICE STATUS, 16 BIT STYLE
	LOAD.	P1,FE.DTN,(F)	;GET DTE #
	LOAD.	T1,FE.CPN,(F)	;CPU #
	HRL	P1,T1		;CPU#,,DTE# IN P1
	MOVSI	S,CPOPJ##	;FORGET ABOUT POST
	PUSHJ	P,DTEQUE##	;SEND THE STATUS
	  JRST	DTUCSM##	;CAN'T SEND -11 MESSAGE
	JRST	CPOPJ1##	;RETURN
;HERE TO TAKE STATUS OF A FRONT END DEVICE FROM THE -11


FEDTKS:	PUSHJ	P,FDIGET	;GET FED BLOCK IN F
	MOVSI	S,FEDTK1	;CONTINUE FROM HERE WHEN DATA IS IN
	HRRI	P3,.FESMS*2	;# 8 BIT BYTES WE WANT (THROW AWAY REST)
	MOVEI	P4,FEDSIB(F)	;ADDRESS TO TRANSFER STATUS TO
	HRLI	P4,(POINT 16,)
	POPJ	P,		;MAKE DTESER START UP THE FIRST FRAGMENT


;HERE WHEN FIRST PART OF STATUS IS IN. IGNORE THE REST OF THE DATA,
; UPDATE STATUS IN FED BLOCK.

FEDTK1:	PUSHJ	P,FDIGET	;SETUP FED BLOCK ADDR FROM C(P2), C(P3)
	LDB	T1,[POINT 16,FEDSIB(F),15] ;GET GOOD INFO
	MOVSI	T2,(FE.EOF)	;EOF BIT WILL BE SET OR CLEARED
	TRNE	T1,EM.EOF	;EOF BIT ON?
	IORM	T2,FEDSTS(F)	;YES, SET EOF IN THE BLOCK
	MOVSI	T2,(FE.FER)	;DO SAME FOR FATAL ERROR BIT
	TRNE	T1,EM.FER	;FATAL ERROR?
	IORM	T2,FEDSTS(F)	;YES, SET THE FATAL ERROR BIT IN STATUS
	PJRST	EATMSG##	;EAT UP REMAINING INDIRECT DATA
;ROUTINE TO GET FRONT END DEVICE BLOCK IN F FROM USER
; ARGUMENTS TO DTE. UUO
; USER ADDR+1/CPU#,,DTE#
; USER ADDR+2/FE DEVICE UNIT #
; SKIP RETURN IF OK, NON-SKIP IF SOMETHING WAS WRONG
; WITH CPU#,,DTE# IN T1

GETFEB:	PUSHJ	P,DTUGTF##	;CHECK AND GET CPU#,,DTE# IN T1
	PUSH	P,T1		;SAVE CPU#,,DTE#
	PUSHJ	P,GETWD1##	;GET FE DEVICE UNIT #
	CAILE	T1,.FEMXU	;LEGAL UNIT NUMBER?
	JRST	TPOPJ##		;NO, ERROR RETURN
	PUSHJ	P,GETFE0	;YES, GO GET THE BLOCK
	  JRST	TPOPJ##		;DOESN'T EXIST
	JRST	TPOPJ1##	;RETURN WITH CPU#,,DTE# IN T1

;THIS ROUTINE IS FOR DRIVER INTERRUPT LEVEL TO GET THE FED ADDRESS IN F.
; CALL WITH CPU#,,DTE# IN P1, FED UNIT NUMBER IN LH(P3)
; ALWAYS RETURNS CPOPJ, IF FED DOESNT EXIST, STOPCD.

FDIGET:	HLRZ	T1,P3		;GET FED UNIT


;ENTER HERE WITH UNIT # IN T1, CPU#,,DTE# IN P1

FDIGT0:	MOVE	F,P1		;GET CPU#,,DTE# IN F
	PUSH	P,T1		;SAVE FED UNIT NUMBER
	PUSHJ	P,GTETDS##	;GET DTE CONTROL BLOCK ADDR OR DIE
	POP	P,T1		;RESTORE FED UNIT NUMBER
	PUSHJ	P,GETFE0	;GET THE BLOCK OR
	  STOPCD .,STOP,NFB,	;++NO FRONT END DEVICE BLOCK
	SALL
	POPJ	P,		;OK, RETURN



;HERE WITH FED UNIT NUMBER IN T1, DTE CONTROL BLOCK ADDR IN F
; RETURN CPOPJ1 WITH FED BLOCK ADDRESS IN F, OR CPOPJ IF ERROR.

GETFE0:	LOAD.	F,ED.FED,(F)	;GET FIRST FEB ADDRESS ON THIS FRONT EN
GETFE1:	JUMPE	F,CPOPJ##	;END OF CHAIN, GIVE ERROR RETURN
	LOAD.	T3,FE.UNI,(F)	;GET UNIT NUMBER OF THIS FE DEVICE
	CAMN	T1,T3		;THIS THE ONE?
	JRST	CPOPJ1##	;YES, RETURN WITH FEB ADDRESS IN F
	LOAD.	F,FE.LNK,(F)	;NO, GET NEXT ADDRESS
	JRST	GETFE1		;AND KEEP LOOKING



SUBTTL CORE ALLOCATION

;ROUTINE TO SETUP INPUT AND OUTPUT BUFFERS FOR FED. CALLED
; WHEN JOB GETS FED. CALL WITH C(F) = FED BLOCK. NON-SKIP
; WITH CORRECT ERROR CODE IN T1 IF NO CORE AVAILABLE, SKIP
; RETURN IF ALL OK.

FEDGTC:	MOVEI	T2,<.FEISZ+<^D36/^D16-1>>/<^D36/^D16>
				;GET NUMBER OF WORDS IN FED BUFFER, ROUNDED UP
	PUSHJ	P,GETWDS##	;GET THAT MANY FOR INPUT BUFFER
	  PJRST	DTUNFC##	;NO FREE CORE, GIVE ERROR RETURN
	MOVEM	T1,FEDIBF(F)	;OK, SAVE ADDRESS
	MOVEI	T2,<.FEOSZ+<^D36/^D16-1>>/<^D36/^D16>
				;GET NUMBER OF WORDS IN FED BUFFER, ROUNDED UP
	PUSHJ	P,GETWDS##	;GET CORE FOR OUTPUT BUFFER NOW
	  PJRST	DTUNFC##	;LOSE
	MOVEM	T1,FEDOBF(F)	;SAVE THAT TOO
	JRST	CPOPJ1##	;OK RETURN


;ROUTINE TO GIVE BACK FED BUFFER CORE. ALWAYS NON-SKIP RETURN.
; IGNORE IF NO BUFFERS TO GIVE BACK.

FEDRLC:	MOVEI	T1,<.FEISZ+<^D36/^D16-1>>/<^D36/^D16>
				;GET NUMBER OF WORDS IN FED BUFFER, ROUNDED UP
	SKIPE	T2,FEDIBF(F)	;GET ADDRESS
	PUSHJ	P,GIVWDS##	;GIVE BACK THE INPUT BUFFER
	SETZM	FEDIBF(F)	;OK, NO MORE INPUT BUFFER
	MOVEI	T1,<.FEOSZ+<^D36/^D16-1>>/<^D36/^D16>
				;GET NUMBER OF WORDS IN FED BUFFER, ROUNDED UP
	SKIPE	T2,FEDOBF(F)	;GET ADDRESS
	PUSHJ	P,GIVWDS##	;GET RID OF OUTPUT BUFFER
	SETZM	FEDOBF(F)	;SAY NO MORE BUFFER
	POPJ	P,		;RETURN
SUBTTL UTILITY ROUTINES


;ROUTINE TO CHECK TO SEE IF A JOB OWNS A FRONT END DEVICE, RETURN
; TO NEXT LEVEL IF NOT.  CALL:
;	MOVE	J,<JOB>
;	MOVE	F,<FED BLOCK ADDRESS>
;	JSP	T4,FEJCHK
;	<RETURN IF JOB OWNS FRONT END DEVICE>


FEJCHK:	LOAD.	T1,FE.JOB,(F)
	CAME	J,T1		;DOES JOB OWN THIS FRONT END DEVICE?
	JRST	DTUDOF##	;NO, GIVE ERROR (AND POPJ BACK TO UPPER LEVEL)
	JRST	(T4)		;YES, RETURN TO CALLER


;ROUTINE TO SETUP PUT AND TAKE POINTERS, AND FREE BYTES IN
; FED INPUT BUFFER. CALLED AT FED INITIALIZATION TIME AFTER
; BUFFERS HAVE BEEN ALLOCATED, AND JUST BEFORE AN ACK IS SENT TO
; THE -11. CALL WITH FED BLOCK ADDRESS IN F


FEDSPT:	MOVE	T1,FEDIBF(F)	;SETUP INITIAL INPUT BUFFER POINTER
	HRLI	T1,(POINT 16,)	;MAKE IT A POINTER
	MOVEM	T1,FEDTPT(F)	;SETUP TAKE POINTER
	MOVEM	T1,FEDPPT(F)	;AND PUT POINTER
	MOVEI	T1,.FEISZ	;SETUP NUMBER OF BYTES IN BUFFER FREE
	MOVEM	T1,FEDFBI(F)	;FREE BYTES IN INPUT BUFFER
	POPJ	P,		;RETURN
SUBTTL INTERRUPT LEVEL ROUTINES


;PROTOCOL FUNCTION DISPATCH TABLE

	CPOPJ##			;(-1)INTERNAL FUNCTION FOR TO-10 MESSAGE RUINED
FEDDSP::EATMSG##		;(0)
	EATMSG##		;(1)
	EATMSG##		;(2)
	FEDTKD			;(3)HERE IS STRING DATA
	EATMSG##		;(4)
	EATMSG##		;(5)
	EATMSG##		;(6)
	FEDTKS			;(7)HERE IS DEVICE STATUS
	EATMSG##		;(10)
	EATMSG##		;(11)
	EATMSG##		;(12)
	EATMSG##		;(13)
	EATMSG##		;(14)
	EATMSG##		;(15)
	EATMSG##		;(16)
	FEDACK			;(17)ACK
	EATMSG##		;(20)
	EATMSG##		;(21)
	EATMSG##		;(22)
	EATMSG##		;(23)
	EATMSG##		;(24)
	FEDAAL			;(25)ACK ALL
	EATMSG##		;(26)
	END