Google
 

Trailing-Edge - PDP-10 Archives - tops10_704_monitoranf_bb-x140c-sb - 10,7/mon/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 V035
SUBTTL E. SOCCI/EVS/TL		9-JUN-87

	SEARCH	F,S,DTEPRM
	$RELOC
	$HIGH


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

.CPYRT<1976,1988>


XP VFEDSR,035

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

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

FEDSER::
SUBTTL DTE. UUO FRONT END DEVICE FUNCTIONS -- ASSIGN FED


;FUNCTION TO GET FRONT END DEVICE
; ADDR/CPU#,,DTE#
; ADDR+1/FED UNIT # OR -1 TO ASSIGN ANY FREE FED
;

FEDGET::PUSHJ	P,GETFEB	;GET FRONT END DEVICE BLOCK IN F FROM USER AREA
	  CAIA			;FAILED, SEE WHY
	JRST	FEDASG		;SUCCEEDED, ASSIGN THIS FED

	JUMPL	T1,CPOPJ##	;RETURN DTUDCE IF CPU DOESN'T EXIST
	MOVE	F,T1		;SAVE CPU#,,DTE#
	PUSHJ	P,GETWDU##	;FAILED, SEE WHAT USER SAID
	CAME	T1,[-1]		;REQUEST "ANY FREE FED"?
	 PJRST	DTUNXF##	;NO, FED DOES NOT EXIST
	PUSHJ	P,GETETD##	;FETCH DTE CONTROL BLOCK
	  PJRST	DTUNXF##	;?HUH
	LOAD.	F,ED.FED,(F)	;GET FIRST FEB ADDRESS ON THIS FE
FEDASW:	JUMPE	F,DTUNXF##	;RETURN ERROR IF FIND NONE
	LOAD.	T1,FE.JCH,(F)	;LOOK FOR FED OWNER
	JUMPN	T1,[LOAD. F,FE.LNK,(F)	;ALREADY OWNED, GET NEXT FEB
		    JRST  FEDASW]	;AND CHECK IT OUT
	LOAD.	T1,FE.UNI,(F)	;GET FED NUMBER OF THIS UNIT
	PUSHJ	P,STOTAC##	;RETURN FED NUMBER TO USER

FEDASG:	LOAD.	T1,FE.JCH,(F)	;GET JOB OWNING THE FRONT END DEVICE
	JUMPN	T1,DTUFDB##	;SOMEONE ALREADY HAS IT
	PUSHJ	P,FEDCLR	;CLEAR OUT THE BITS IN FEDSTS FIRST
	PUSHJ	P,FEDGTC	;ALLOCATE INPUT AND OUTPUT BUFFERS
	  POPJ	P,		;OOPS, COULDN'T DO IT
	PUSHJ	P,FEDSPT	;INITIALIZE POINTERS TO INPUT BUFFER
	MOVE	T1,.CPJCH##	;GET JCH OF NEW OWNER
	STOR.	T1,FE.JCH,(F)	;MARK FED IN USE AND AVAIL FOR INPUT
	JRST	CPOPJ1##	;RETURN
SUBTTL DTE. UUO FRONT END DEVICE FUNCTIONS -- RELEASE FED


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

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


SUBTTL RESET UUO SERVICE

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

IFE FTMP,< ;SINGLE PROCESSORS DON'T HAVE TO SAVE SO MUCH
FEDRST::PUSHJ	P,SAVE2##	;SAVE P1,P2
>  ;IFE FTMP
IFN FTMP,< ;MULTI-CPU SYSTEMS DO TRIPLE LOOPS
FEDRST::PUSHJ	P,SAVE3##	;SAVE P1,P2,P3
	MOVEI	P3,M.CPU##	;FOR EACH CPU
FEDRS4: > ;IFN FTMP
	MOVEI	P2,3		;SCAN 4 FRONT ENDS
FEDRS0:	MOVEI	P1,.FEMXU	;AND 4 FRONT END DEVICES
FEDRS1:	MOVE	F,P2		;GET CPU#,,DTE# IN F FOR GETETD
IFN FTMP,<
	HRLI	F,-1(P3)	;P3 IS 1 HIGHER THAN CPU NO.
> ;IFN FTMP
	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.JCH,(F)	;GET JOB OWNING IT
	CAMN	T1,.CPJCH##	;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
IFN FTMP,<
	SOJG	P3,FEDRS4	;LOOP FOR NEXT CPU
> ;IFN FTMP
	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:	MOVSI	T1,(FE.MIP)	;IS A MESSAGE IN PROGRESS AT INTERRUPT LEVEL
	SYSPIF			;CONSISTENCY (NOT NESC. ON OWNING CPU)
	TDNN	T1,FEDSTS(F)	;??		(SO PI.OFF IS NOT SUFFICIENT)
	  JRST	FEDCLN		;NO, CLEAN OUT THE FED
	SYSPIN			;WAIT
	MOVEI	T1,EV.FEI	;YES, WAIT FOR MESSAGE TO FINISH COMING IN
	PUSHJ	P,ESLEEP##	;SO WE DON'T RELEASE THE CORE IT WILL WRITE
	JRST	FEDCLR		;SEE IF SAFE YET

FEDCLN:	SETZ	T1,		;CLEAR OUT JOB NUMBER
	STOR.	T1,FE.JCH,(F)	;IN FED BLOCK
	SYSPIN			;INTERRUPT CODE WON'T TOUCH NOW.
	MOVE	T1,[FE.CLR]	;BITS TO CLEAR IN STATUS
	ANDCAM	T1,FEDSTS(F)	;CLEAR THEM
	PJRST	FEDRLC		;RELEASE BUFFER CORE AND RETURN
SUBTTL  DTE. UUO FRONT END DEVICE FUNCTIONS -- FED DEVICE INPUT


;FUNCTION TO DO INPUT FROM FRONT END DEVICE
; ADDR/CPU#,,DTE#
; ADDR+1/FED UNIT #
; ADDR+2/#16-BIT BYTES TO READ,,BUFFER ADDRESS

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 THIS FRONT END DEVICE

	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
	MOVE	T2,P3		;GET 16 BIT BYTE COUNT
	ASH	T2,-1		;TURN INTO 36 BIT WORD COUNT
	TLZ	T1,-1		;C(T1) NOW HAS FIRST ADDRESS
	ADDI	T2,(T1)		;C(T2) NOW HAS LAST ADDRESS
	PUSHJ	P,TRNGE##	;MAKE SURE ITS ALL IN CORE
	MOVSI	T1,(FE.EOF)	;CLEAR END OF FILE FLAG
	ANDCAM	T1,FEDSTS(F)
	SETZ	P1,		;CLEAR COUNT OF BYTES GIVEN TO USER

FEDUI1:	PUSHJ	P,FEDUIB	;GET NEXT INPUT BYTE
	  POPJ	P,		;ERROR, RETURN IT
	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		;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.
;READ NEXT (16-BIT) BYTE FROM -11
;RETURNS BYTE IN T2, MUST PRESERVE T1, P1, P3, & M
;RETURN:	CPOPJ IF ERROR (ERROR ALREADY SET)
;		CPOPJ1 WITH DATA

FEDUIB:	SKIPG	FEDTCT(F)	;IF NO DATA AVAILABLE
	  JRST	FEDUB2		;GET SOME MORE
	ILDB	T2,FEDTPT(F)	;GET A BYTE
	SOS	FEDTCT(F)	;THERE IS ONE LESS BYTE AVAILABLE NOW
	JRST	CPOPJ1##	;DONE

FEDUB2:	PUSH	P,T1		;SAVE POSSIBLE BYTE IN LH(T1)
	SYSPIF			;MUST TURN OFF PI SO WE DON'T GET INPUT
				; DATA FOR FED WHILE UPDATING PUT POINTER
	SKIPG	FEDTCT(F)	;OF COURSE, THE DTE COULD HAVE DELIVERED DATA
	  JRST	FEDUB3		;SINCE WE LOOKED.  JUMP IF IT DID NOT.
	SYSPIN			;IT DID, MUST CONSUME THAT DATA FIRST
	POP	P,T1		;RESTORE POSSIBLE BYTE IN LH
	JRST	FEDUIB		;GO TAKE DATA THAT SNUCK IN

FEDUB3:	MOVSI	T1,(FE.MIP)	;IS A MESSAGE ON ITS WAY IN
	TDNN	T1,FEDSTS(F)	;(AT INTERRUPT LEVEL)?
	  PUSHJ	P,FEDSPT	;NO, MAKE THE NEXT ONE START AT TOP OF BUFFER
	SYSPIN			;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
	PUSHJ	P,FEDSAK	;SINCE WE EXPECT TO BLOCK, SEND AN ACK TO GET
	  PJRST	TPOPJ##		;MORE DATA FROM THE -11. (RETURN IF ERROR)
	PUSHJ	P,FEDWTI	;WAIT FOR THE BUFFER
	  JRST	FEDUB4		;OOPS, FATAL ERROR.
	POP	P,T1		;RESTORE POSSIBLE LH BYTE
	JRST	FEDUIB		;GO FETCH THE NEW DATA

FEDUB4:	POP	P,T1		;GET JUNK OFF STACK
	JRST	DTUFER##	;GO GIVE FATAL ERROR
;ROUTINE TO SEND AN ACK TO -20F
;-20F DOESN'T REALLY CARE HOW MANY ACKS IT GETS.  IT WILL BLOCK FOR AN
;ACK WHEN SENDING DEVICE DATA (BUT NOT FUNCTION REPLYS).  MORE COMPLICATED
;SCHEMES COULD BE MORE EFFICIENT, BUT SUFFER SYNCHRONIZATION PROBLEMS.
;
;CALLED BY FEDUIB, MUST PRESERVE SAME ACS

FEDSAK:	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.CPN,(F)	;CPU #
	HRL	P1,T1		;CPU#,,DTE# IN P1
	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
	JRST	CPOPJ1##	;DONE
;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.  (11-RELOAD, DATA OVERRUN)

FEDWTI:	MOVSI	T1,(FE.FER)	;HAS AN ERROR OCCURED?
	TDNE	T1,FEDSTS(F)
	  POPJ	P,		;YES, GIVE THE ERROR RETURN.
	SKIPLE	FEDTCT(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 AT INTERRUPT LEVEL 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.JCH,(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

	HRLM	T2,FEDFBI(F)	;SAVE MESSAGE LENGTH FOR POST ROUTINE

	MOVE	P4,FEDPPT(F)	;GET POINTER TO STORE DATA WITH

	ADJBP	T2,P4		;COMPUTE POINTER TO NEXT PLACE TO STORE DATA
	MOVEM	T2,FEDPPT(F)	;UPDATE FOR NEXT MESSAGE

	MOVSI	S,FEDTDD	;THE POST PLACE

	MOVSI	T1,(FE.MIP)	;MESSAGE WILL NOW COME IN
	IORM	T1,FEDSTS(F)	;SO MAKE SURE BUFFER POINTERS AREN'T RESET
	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 AT INTERRUPT LEVEL WHEN WE CRASH THE -11 WHILE WAITING FOR INDIRECT DONE
;DTESER ACS ARE SETUP.

FEDLMG:	PUSHJ	P,FDIGET	;GET FED BLOCK FROM C(P2), C(P3)
	MOVSI	T1,(FE.FER)	;FLAG FATAL ERROR STATUS
	IORM	T1,FEDSTS(F)	;SO USER WAKES UP NOW
	PJRST	FEDTD1		;CLEAR MESSAGE IN PROGRESS

;HERE AT INTERRUPT LEVEL WHEN DATA TRANSFER TO THE TO-10 BUFFER IS COMPLETE.
;DTESER ACS ARE SETUP.

FEDTDD:	PUSHJ	P,FDIGET	;GET FED BLOCK FROM C(P2), C(P3)
	HLRZ	T1,FEDFBI(F)	;FETCH LENGTH OF THIS MESSAGE
	ADDM	T1,FEDTCT(F)	;MAKE DATA AVAILABLE TO USER
FEDTD1:	HRRES	FEDFBI(F)	;RESTORE BYTES AVAIL FOR NEXT MESSAGE
	MOVSI	T1,(FE.MIP)	;MESSAGE IS NO LONGER IN PROGRESS
	ANDCAM	T1,FEDSTS(F)	;SO ALLOW BUFFER SWITCHING
				;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.JCH,(F)	;GET JOB NUMBER OWNING THIS
	JUMPE	T1,CPOPJ##	;DO NOTHING IF THERE IS NONE
	PUSHJ	P,CTXEWK##	;THERE IS ONE, WAKE THE JOB UP IF IT'S WAITING
	  JFCL			;IT DOESN'T MATTER IF CTX IS NOW GONE
	POPJ	P,		;JOB IS AS AWAKE AS IT'LL GET
SUBTTL  DTE. UUO FRONT END DEVICE FUNCTIONS -- FED DEVICE OUTPUT


;FUNCTION TO DO OUTPUT TO FRONT END DEVICE
; ADDR/CPU#,,DTE#
; ADDR+1/FED UNIT #
; ADDR+2/#16-BIT BYTES TO WRITE,,BUFFER ADDRESS

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


	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
	MOVE	T2,P3		;GET 16 BIT COUNT
	ASH	T2,-1		;MAKE 36 BIT COUNT
	TLZ	T1,-1		;FIRST ADDRESS
	ADDI	T2,(T1)		;MAKE IT LAST ADDRESS
	PUSHJ	P,TRNGE##	;MAKE SURE ALL PAGES ARE THERE
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?
	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 IT'S SLEEPING
	JUMPN	P3,FEDACK	;LOOP IF MORE ACKS ARE IN THIS MESSAGE
	POPJ	P,		;ALL DONE
SUBTTL DTESER ACK ALL SERVICE


;HERE ON ACK ALL - IF SOMEONE IS USING A FRONT END DEVICE, GIVE HIM
; AN ERROR, AS THE FE HAS JUST RELOADED.

FEDAAL:	LOAD.	F,ED.FED,(F)	;GET FIRST FRONT END DEVICE ADDRESS
FEDAA1:	JUMPE	F,CPOPJ##	;DONE
	LOAD.	T1,FE.JCH,(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  DTE. UUO FRONT END DEVICE FUNCTIONS -- GET FED DEVICE STATUS


;FUNCTION TO GET STATUS FROM FRONT END DEVICE
; ADDR/CPU#,,DTE#
; ADDR+1/FED UNIT #
; 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 AT INTERRUPT LEVEL TO TAKE STATUS OF A FRONT END DEVICE FROM THE -11
;	(DTESER HAS ALREADY RECEIVED IT)
;DTESER ACS ARE SETUP.

FEDTKS:	PUSHJ	P,FDIGET	;GET FED BLOCK IN F
	ILDB	T1,P4		;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
SUBTTL  DTE. UUO FRONT END DEVICE FUNCTIONS -- SET FED DEVICE STATUS


;FUNCTION TO SET FRONT END DEVICE STATUS
; ADDR/CPU#,,DTE#
; ADDR+1/FED UNIT #
; ADDR+2/NEW STATUS (16 BITS)

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
SUBTTL DTE. UUO INTERFACE - READ USER ARGUMENT BLOCK

;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
; IN ANY CASE WITH CPU#,,DTE# IN T1 (OR -1 IF INVALID)

GETFEB:	PUSH	P,[-1]		;ASSUME CPU OR DTE IS INVALID
	PUSHJ	P,[PUSHJ P,DTUGTF##	;CHECK AND GET CPU#,,DTE# IN T1
		   JRST  CPOPJ1##]	;SKIP FOR SUCCESS
	  JRST	TPOPJ##		;RETURN BAD CPU/DTE ERROR
	MOVEM	T1,(P)		;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
SUBTTL FEB SEARCH ROUTINES


;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 END
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/DEALLOCATION

;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	[PUSHJ	P,FEDRC1 ;NO FREE CORE, RELEASE INPUT 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,<.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
FEDRC1:	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
	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:
;	ASSUMES JOB IS CURRENT (.CPJCH)
;	MOVE	F,<FED BLOCK ADDRESS>
;	JSP	T4,FEJCHK
;	<RETURN IF JOB OWNS FRONT END DEVICE>


FEJCHK:	LOAD.	T1,FE.JCH,(F)
	CAME	T1,.CPJCH##	;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
	SETZM	FEDTCT(F)	;NO DATA AVAILABLE TO USER
	POPJ	P,		;RETURN
SUBTTL DTESER FUNCTION DISPATCH TABLE FOR THIS DRIVER


	IFIW	FEDLMG		;(-1) LOST TO-10 INDIRECT MESSAGE
FEDDSP::DTEFNC			;(??) GENERATE DUMMY TABLE ENTRIES
	DTEFNC	(STR,FEDTKD)	;(03) HERE IS STRING DATA
	DTEFNC	(HDS,FEDTKS)	;(07) HERE IS DEVICE STATUS
	DTEFNC	(ACK,FEDACK)	;(17) ACK
	DTEFNC	(AKA,FEDAAL)	;(25) ACK ALL

	END