Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - uuocon.mac
There are 20 other files named uuocon.mac in the archive. Click here to see a list.
TITLE	UUOCON - UUO HANDLER AND UUO+IO ROUTINES - V1132
SUBTTL /CHW/TL/RCC/CMF/PH/GDR/DAL/EVS/TW/JMF/DRT	22 MAR 77
	SEARCH	F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VUUOCN,1132
		;THIS MACRO PUTS VERSION NO. IN STORAGE MAP AND GLOB

UUOCON::ENTRY	UUOCON		;ALWAYS LOAD UUOCON(IF LIB SEARCH)

IFNDEF MAXCAL,<XP MAXCAL,56>
			;DEFINE HIGHEST CALLI UUO WHICH HAS
			; CORRESPONDING CALL UUO

;       	TABLE OF CONTENTS FOR UUOCON
;
;
;    1. UUO DISPATCH ROUTINE
;    2. CALL & CALLI UUO'S
;    3. EXIT & SETPOV UUO'S
;    4. RESET & APRENB UUO'S
;    5. MISC. ACCOUNTING UUOS (JOBNO,JOBTIM,DATE & MSTIME)
;    6. SLEEP SERVICE FOR SLEEP UUO, DTA, MTA AND SCNSER
;    7. PEEK UUO
;    8. POKE. UUO
;    9. CALLS TO SEGCON FOR SETUWP AND REMAP
;   10. TRIVIAL UUOS (LIGHTS, TIMER AND SWITCH)
;   11. DEVCHR AND DEVSIZ UUO'S
;   12. GETPPN AND DEVPPN UUO'S (ALSO RTZER)
;   13. IONDX.  UUO
;   14. SUBROUTINE TO FIND A DDB GIVEN ITS IO INDEX
;   15. MVBFH. UUO -- MOVE BUFFER HEADERS
;   16. DEVSTS, DEVLNM, DEVRST, AND DEVURS UUO'S
;   17. SETDDT, WAIT AND GETLIN CALLI'S ; WAIT2 AND GETPPL
;   18. LOGIN, LOGOUT AND ATTACH UUO'S
;   19. GETTAB UUO
;   20. SETNAM & CNGPPN UUO'S
;   21. DEVNAM UUO
;   22. REAL-TIME AND HIBWAKE FEATURE
;   23. DAEMON UUO'S AND ROUTINES
;   24. CLOSE UUO
;   25. INBUF & OUTBUF UUO'S
;   26. OPEN & INIT UUO'S
;   27. COMMON PART OF LOOKUP AND ENTER
;   28. COMMON PART OF RENAME, USETI/O, UGETF AND UTPCLR
;   29. COMMON PART OF INPUT AND OUTPUT UUO'S
;   30. RELEASE UUO
;   31. STATUS SETTING AND GETTING UUO'S
;   32. ROUTINES TO ADVANCE BUFFERS
;   33. DUMP MODE COMMAND LIST PROCESSING ROUTINES
;   34. DDB SCAN LOGIC
;   35. BUFFER RING BUILDER & CLEARER
;   36. RANDOM SUBROUTINES FOR I/O

;THE CALL UUO ROUTINES AND THE IO UUO ROUTINES
;SOME UUO DO DISPATCH TO OTHER ROUTINES OUTSIDE OF UUOCON
;SYSTEM UUOS(40-77) FIRST SAVE THE USERS ACS IN RELATIVE LOC 0-17
;THEN THE FOLLOWING ACS ARE LOADED UP BEFORE DISPATCHING:
;	P	;PUSHDOWN LIST IN CURRENT JOB DATA AREA
;	R	;CURRENT JOB RELOCATION IN RH,PROTECTION IN LH
;	M	;THE CONTENTS OF LOC 40 WITH R IN INDEX FIELD
;		;SO THAT RELOCATION CAN BE DONE FOR PICKING UP ARGUMENTS
		; EXCEPT THAT ON A CALL OR CALLI UUO, THE ADDRESS IS
		; MODIFIED TO BE THE AC OF THE UUO,FOR
		; PICKING UP ARGUMENTS.
;	F	;ADR. OF DEVICE DATA BLOCK
;	S	;DEVICE IO STATUS WORD
;	T1	;(CALLI) CONTENTS OF AC
;	T4	;ADR. OF DEVICE SERVICE ROUT. DISPATCH TABLE
;	P1	;THE USER IO CHANNEL(AC FIELD) OF UUO
		;LH BIT 0=1 (PHONLY) IF ONLY PHYSICAL DEVICE WANTED
		; IE NO LOGICAL NAME SEARCH

;RETURN IS PUSHED ON END OF PD LIST
;THEN IF CALL WAS FROM USER MODE, THE UUO ROUTINE IS CALLED
;WITH A PUSHJ, SO THAT ALL UUO ROUTINE RETURN WITH A POPJ P,
;WHICH WILL RETURN CONTROL TO UUOCON WHICH WILL RESTORE USERS
;ACS AND RETURN TO HIM
;IF THE CALL IS FROM EXEC MODE, THE UUO ROUTINE IS CALLED
;BY DOING JUST A JRST,  WHEN THE UUO ROUTINE RETURNS WITH
;A POPJ, IT WILL RETURN TO THE EXEC WITHOUT RESTORING
;ANY ACS
; CONTROL MAY ALWAYS BE RETURNED BY EXECUTING A
;	POPJ P,
; WHICH WILL RESTORE THE ACS, APR BITS, AND RETURN.
; THE UUO HANDLER IS PURE IF THE FOLLOWING RESTRICTIONS ARE OBSERVED.
; RESTRICTIONS: UUOS CANNOT BE CALLED BY INTERRUPT SERVICE ROUTINES.

;ALL UUO'S SHOULD PRESERVE THE PRESERVED AC'S P1-P4
	SUBTTL	UUO DISPATCH ROUTINE

;HERE FROM COMMON WITH ACS SAVED IF KA10. NO NEED TO SAVE ACS
; ON A KI10 SINCE THE MONITOR USES AC BLOCK 0 AND THE USER USES
; AC BLOCK 1.
UUOSY1::MOVE	M,MPTRAP##	;GET THE UUO INTO AC(M)
				; (CHECK THIS BEFORE PUSHING ON STACK WHICH WOULD
				; DESTROY VALUABLE INFO IN CRASH IF FROM EXEC MODE)
	MOVE	J,JOB##		;SET UP J IN CASE UUOERR
				; (GIVRES EXPECTS J SET UP)
	TLNN	M,740000	;SYSTEM UUO?
	JRST	UUOERR##	;NO, 0-37 ARE ILLEGAL, PRINT ERROR
	PUSH	P,UUO0##	;SAVE RETURN ON PUSH DOWN LIST
IFN FTMS,<	PUSHJ	P,MSTUUO##	;SET THIS JOB TO RUN ON MASTER ONLY DURING UUO
>				; (ALREADY CHECKED FOR ILLEGAL UUO).
IFN FTKA10,<
	MOVEI	P4,.C0CDB##	;CPU0'S CDB
>
				;UUOS FROM SLAVE ENTER HERE AFTER RESCHEDULED ON MASTER
MPUUO::	PUSHJ	P,FNDPDS##	;FIND JOB'S PDB
IFN FTACCT,<
	AOS	.PDUUC##(W)	;COUNT THE UUO
>
	TLO	M,R		;SET FOR RELOCATION
	LDB	T2,[POINT 9,M,8];PICK UP UUO OP CODE
	CAIL	T2,100		;ILLEGAL INSTRUCTION?
	JRST	ILLINS##	;YES, STOP JOB AND PRINT ERROR
	LDB	P1,PUUOAC##	;SETUP USER DEVICE CHANNEL NUMBER
IFN FTVM,<
	SKIPE	F,USRJDA##(P1)	;GET ADRESS OF DEVICE DATA BLOCK
>
IFE FTVM,<
	MOVEI	F,.CPJDA##(P4)	;ADDRESS OF CHANNEL TABLE ON THIS CPU
	ADDI	F,(P1)		;PLUS THE CHANNEL NUMBER
	SKIPE	F,(F)		;IS THE A DDB?
>
IFN FTVM,<
	CAMLE	P1,USRHCU##
>
IFE FTVM,<
	CAMLE	P1,.CPHCU##(P4)	;IS IT LESS THAN OR EQUAL TO HIGHEST
				; USER IO CHANNEL IN USE FOR CURRENT JOB?
>
	JRST	NOCHAN		;CHANNEL NOT ASSIGNED
DISP3:	MOVE	S,DEVIOS(F)
	MOVE	T4,DEVSER(F)	;SETUP IO SERVICE DISPATCH
				; TABLE ADDRESS
	CAIL	T2,LNGUUO	;LONG DISPATCH TABLE UUO?
	JRST	DISP1		;YES
DISP0:	ROT	T2,-1		;DIVIDE UUO OPCODE BY 2, SAVE REMAINDER
	MOVE	U,UUOTAB-20(T2);GET DISPATCH TABLE ENTRY
IFN FTVM!FTMS,<
	MOVE	T1,M		;ADR INTO T1 FOR UUOCHK
	MOVE	T3,CHKTAB-20(T2);GET CHECK-BITS FOR THE UUO
>
DISP2:	JUMPL	T2,DISP2A	;WAS UUO ODD?
	MOVS	U,U		;NO, USE LH OF DISPATCH ENTRY
	MOVSS	T3
DISP2A:
IFN FTVM,<
	TRNE	T3,UU.MSK	;CHECK ARGUMENTS FOR VALIDITY?
	PUSHJ	P,UUOCHK##	;YES (DONT ALLOW PAGE FAULT IN UUO PROCESSING)
>
	MOVE	T2,(P)		;UUO FROM SYSTEM?
	TLNN	T2,(XC.USR)
	JRST	(U)		;YES
IFN FTPI,<
	PUSHJ	P,ANYUUO##	;CALL PSISER SINCE THIS IS A FUNNY
				; CONDITION
;***NOTE: THIS ROUTINE SKIPS TO ABORT THE UUO. IT MUST BE PRIOR TO THE
; PUSHJ P,(U) SO IT WILL SKIP INTO UUOXIT
>
;DISPATCH TO UUO ROUTINE
;THE FOLLOWING CODE IS EXECUTED ON ALL RETURN TO USER PROGRAMS
;BUT IS NEVER EXECUTED ON RETURNS FROM EXEC UUOS(SAVGET)

	PUSHJ	P,(U)		;NO, FROM USER. ALL
				; UUO ROUTINES RETURN WITH POPJ
	  JRST	USRXIT		;NO SKIP RETURN TO USER
USRXT1:
IFE FTVM,<
	AOS	JOBPD1##(R)
>
IFN FTVM,<
	PUSHJ	P,INCPD1##
>
USRXIT::
IFN FTNET,<
	JUMPE	F,UUONET	;NO DDB
	HRRZ	T1,DEVSER(F)	;GET NETWORK DDB BIT
	CAIE	T1,NETDSP##	;IS IT
	JRST	UUONET		;NO, IGNORE
	MOVEI	T1,ASSCON!ASSPRG  ;IS THE DDB ASSIGNED OR INITED
	TDNN	T1,DEVMOD(F)	;CHECK
	PUSHJ	P,ZAPNET##	;NO, REMOVE THE DDB
UUONET:
>	;END FTNET
IFN FTMS,<
	SKPCPU	(0)		;ON CPU0?
	JRST	USPXIT##	;NO, SEE IF CPU1 JOB SHOULD BE STOPPED
>
IFE FTVM,<
	SKIPE	T2,USREPL##	;DOES THIS USER HAVE EXEC CORE FOR EXTENDED PD LIST?
				; (POSSIBLE IF PDL OV DURING UUO)
	PUSHJ	P,GIVEPL##	;YES, GIVE IT BACK (SEE CORE1)
>	;END IFE FTVM
	MOVSI	T1,37		;GET MASK OF IR+IND FIELDS
	IORM	T1,MPTRAP##	;OR INTO 40 SO UUO WATCHERS SEE IT
	MOVE	J,JOB##		;CURRENT JOB NUMBER
IFN FTMS,<	PUSHJ	P,DPXST##	;CLEAR BIT SP.NR1 SO CAN'T START JOB ON CPU0
				; IF CPU0 NOT IN JOB'S CPU SPECIFICATION
	SKIPN	.C1PUC##	;ARE THERE SLAVE UUO PENDING
	PUSHJ	P,UXITMP##	;OR IS THIS JOB UNRUNABLE ON MASTER CPU
	  JRST	USRXT2		;YES, GO DO A RESCHEDULE
>

	MOVE	T1,JBTSTS##(J)	;JOB STATUS WORD
	TDNN	T1,[XWD STOPIO!CNTRLC,JS.DEP!JS.MPE] ;IS MONITOR TRYING TO STOP THIS USERS
				; IO OR IS HE TRYING TO STOP HIS JOB
				; (BY TYPING ^C WHILE HE WAS IN MONITOR)?
				; OR HAD ERROR AND IS IN DAEMON ERROR PAUSE?
				; OR MEM PAR ERR (WHILE IN MONITOR BUT BAD ADR
				; PROVED TO BE IN USER MODE)
	SKIPE	TIMEF##		;NO. HAS CLOCK TICKED WHILE IN MONITOR?
	JRST	USRXT2		;YES, GO CALL SCHEDULER
	SKIPE	.C0RTF##	;NO, SHOULD WE DO A HIGH PRIORITY RESCHEDULE
				; ONLY SET FOR CPU0 UNTIL RTTRP UUOS CAN BE HANDLED ON CPU1
;------ NOTE - 'UUODON' MUST LABEL THE PC STORED BY THIS PUSHJ
;USED FOR CONTROL C INTERCEPT TO DETECT USER STOPPED ON THIS CALL TO SCHED
USRXT2:	PUSHJ	P,USCHD1##	;YES, GO CALL SCHEDULER
UUODON::			; SAVE CURRENT JOB NO (J)
;----------------		; NOTE: USCHD1 POPS PUSHJ PC INTO JOBPC
				; WHEN RESCHEDULING JOB
;HERE TO RETURN TO USER - CHECK IF USER TRAP PENDING

USRRET::
IFN <FTKI10!FTKL10>&FTSET,<
	MOVEI	T1,JS.ABP	;EXEC MODE ADDRESS BREAK BIT
	TDNE	T1,JBTST2##(J)	;DID ONE OCCUR DURING THIS UUO?
	PUSHJ	P,EXCABK##	;YES, GO PROCESS IT
>
IFN FTPI,<
	XCT	NOPISK##	;SKIP IF NO INTERRUPTS BECAUSE USER
				; IS NOT ENABLED FOR SOFTWARE INTERRUPTS.
	XCT	@JBTPIA##(J)	;EXECUTE THE USER'S PENDING TRAP
				; INSTRUCTION.
UUOPSI::			;PSI EXPECTS THIS TO BE THE PC STORED BY
				; PUSHJ XCT ABOVE.
	XCT	NOPISK##
	XCT	@JBTPIA##(J)
> ;END FTPI
	MOVE	T1,JBTSTS##(J)	;STATUS WORD FOR CURRENT USER
				; ON THIS CPU
	TRNN	T1,UTRP		;SEE IF TRAP PENDING
	JRST	USRXNT		;NO--PROCEED BELOW
;HERE WHEN TRAP SET UP WHILE JOB WAS DOING A UUO.
;TYPE OF TRAP IS IN .JBFDV:
;	-1 IF .JBINT TRAP (E.G., ^C)
;	0,,ADDR	IF START AT ADDR (E.G., .DDT)

	MOVE	T2,(P)		;GET RETURN PC
IFN	FTCCIN,<
	SKIPGE	T4,JOBFDV##(R)	;GET NEW PC
	JRST	USRXJI		;NO--GO DO .JBINT
>
IFE FTCCIN,<
	MOVE	T4,JOBFDV##(R)	;GET NEW PC
>
	MOVEM	T2,JOBOPC##(R)	;STORE INTERRUPTED PC
	HRRM	T4,(P)		;STORE NEW PC
IFN FTCCIN,<
	JRST	USRXCT		;AND GO FINISH INTERRUPT
USRXJI:	MOVEI	T4,0		;CLEAR BITS
	PUSHJ	P,CHKINT##	;SEE IF INT BLOCK OK
	  JRST	USRXCT		;NO--JUST CLEAR TRAP
	PUSHJ	P,DOINT##	;YES--SWITCH PC
>

USRXCT:	MOVEI	T1,UTRP		;CLEAR
	ANDCAM	T1,JBTSTS##(J)	;  TRAP FLAG
;HERE TO RESTORE USER HARDWARE STATE AND JUMP TO USER
USRXNT:
IFN FTMS,<	SKPCPU	(0)		;MASTER?
	JRST	USPRET##	;NO, GO EXIT TO USER FROM SLAVE DEPENDENT CODE
>
	JRST	UMPRET##	;YES, GO EXIT TO USER FROM MASTER DEPENDENT CODE
NOCHAN:
IFN FTVM,<
	SKIPL	USRHCU##	;SAVE/SET IN PROGRESS?
	CAMG	P1,USRHCU##	;NO, MAKE SURE LEGAL CHANNEL
>
IFE FTVM,<
	SKIPL	.CPHCU##(P4)	;SAVE/GET IN PROGRESS (F POINTS TO DDB)
	CAMG	P1,.CPHCU##(P4)	;NO, USER CHANNEL NO. GREATER THAN HIGHEST INITED
>
	SKIPA			;DON'T ZERO F - IT POINTS TO A DDB
	MOVEI	F,0		;INDICATE NO DDB
	MOVSI	T3,(XC.USR)
	CAIE	T2,70		;YES,IS IT CLOSE OR RELEASE?
	CAIN	T2,71		;CLOSE AND RELEASE ALWAYS LEGAL
				; EVEN THOUGH NO DEVICE ASSIGNED
	JRST	NOOP		;YES, DO NO-OP FOR EXEC OR USER
	TDNE	T3,(P)		;UUO FROM USER?
				;IF FROM EXEC, PROBABLY SAVGET
				; WHICH SETS USRCHN NEG. IN LH
	CAIGE	T2,IOUUO	;YES, IS THIS AN IO UUO?
	JRST	DISP3		;NO, GO DISPATCH
	JRST	IOIERR##	;NO, PRINT IO TO UNASSIGNED CHANNEL
				; AND STOP JOB

NOOP:	TDNE	T3,(P)		;YES,IS UUO FROM USER?
	JRST	USRXIT		;YES, RETURN TO HIM (RESTORE ACS)
	POPJ	P,		;NO, RETURN TO EXEC (DO NOT RESTORE ACS)
DISP1:	MOVE	T1,DEVMOD(F)	;LONG DISPATCH TABLE UUO
IFN FTSPL,<
	SKIPL	DEVSPL(F)	;LONG DISPATCH TABLE IF SPOOLED
>
	TLNE	T1,DVLNG	;DOES THIS DEVICE HAVE A LONG
				; DISPATCH TABLE?
	JRST	DISP0		;YES, DISPATCH
	CAIGE	T2,76		;NO, IS UUO LOOKUP OR ENTER?
	JRST	USRXIT		;NO, RETURN TO USER
	HRRI	T1,DVIN		;YES, TEST IF DEVICE LEGAL
	CAIN	T2,77		;LOOKUP?
	HRRI	T1,DVOUT	;NO, TEST FOR OUTPUT DEVICE (ENTER)
	TLNE	T1,(T1)		;IF LOOKUP, TEST FOR INPUT DEVICE (DVIN)
	JRST	USRXT1		;DEVICE AND FUNCTION AGREE, SKIP RETURN
	PUSHJ	P,GETWD1##	;NOT AGREE, GET E+1
	HRRI	T1,0		;ERROR CODE 0, FILE-NOT-FOUND SHOULD NOT MESS UP UPDATES
	PUSHJ	P,PUTWDU##	;PUT BACK IN E+1
	JRST	USRXIT		;AN NON SKIP RETURN TO USER
;TABLE OF UUO DISPATCH ADDRESSES
;IN FORMAT:
;	XWD 40,41
;	XWD 42,43
;	.
;	XWD 76,77



	XALL
UUOTAB:	UCALL,,UINIT		;(40,41)CALL,INIT
	UUOERR##,,UUOERR##	;(42,43)FIVE UUOS FOR EACH INSTALLATION
	UUOERR##,,UUOERR##	;(44,45)TO DEFINE AS THEY SEE FIT
	UUOERR##,,UCALLI	;(46,47),CALLI
	UOPEN,,TTYUUO##		;(50,51)OPEN, TTCALL
	UUOERR##,,UUOERR##	;(52,53)
	UUOERR##,,URENAM	;(54,55),RENAME
XP IOUUO,55			;LOWEST IO UUO(RENAME)
	TIN,,TOUT		;(56,57)IN,OUT
	SETIOS,,USTATO		;(60,61)SETSTS,STATO
	USTATS,,USTATZ		;(62,63)GETSTS,STATZ
	UINBF,,UOUTBF		;(64,65)INBUF,OUTBUF
	UIN,,UOUT		;(66,67)INPUT,OUTPUT
	CLOSE1,,RELEA1		;(70,71)CLOSE,RELEASE
XP LNGUUO,72			;LOWEST LING DISPATCH TABLE UUO
	UMTAPE,,UDGF		;(72,73)MTAPE,GETF
	UDSI,,UDSO		;(74,75)SETI,SETO
	UDLK,,UDEN		;(76,77)LOOKUP,ENTER

;UUOS 42, 43, 44, 45, AND 46 ARE FOR CUSTOMERS TO DEFINE AS THEY PLEASE
;UUOS 40, 41 AND 47 THROUGH 77 ARE DEFINED BY DIGITAL
;UUOS 51,52,53 AND 54 ARE RESERVED FOR EXPANSION BY DIGITAL

IFN FTVM!FTMS,<
;TABLE OF CHECK-BITS FOR UUOS
CHKTAB::UU.EA,,3		;CALL,INIT
	0,,0			;42,43
	0,,0			;44,45
	0,,UU.CP1		;46,CALLI
	UU.EA+3,,UU.EA		;OPEN,TTCALL
	0,,0			;52,53
	0,,UU.LER		;54,RENAME
	0,,0			;IN,OUT
	0,,UU.CP1		;SETSTS,STATO
	UU.CP1,,UU.CP1		;GETSTS,STATZ
	0,,0			;INBUF,OUTBUF
	0,,0			;INPUT,,OUTPUT
	0,,0			;CLOSE,,RELEASE
	0,,0			;MTAPE,UGETF
	0,,0			;USETI,USETO
	UU.LER,,UU.LER		;LOOKUP,ENTER
>
	SUBTTL	CALL & CALLI UUO'S

; CALLING SEQUENCE
;	CALL D,[SIXBIT/NAME/]
; WHERE NAME IS THE NAME OF A SYSTEM ROUTINE.
; IF NO SYSTEM ROUTINE WITH THE SPECIFIED NAME IF FOUND, THIS ROUTINE
; EXITS TO UUOERR.
;CONTENTS OF USER AC PLACED IN AC T1,UUO SET TO POINT
;TO USER AC, R IN LH.
;J SET TO JOB NUMBER
UCALL:	PUSHJ	P,GETWDU##	;SET T1 FROM CONTENTS OF EFFECTIVE ADDRESS OF
				; UUO FROM EITHER HIGH OR LOW SEG
				; DO NOT RETURN IF ERROR
				; SET J TO CURRENT JOB NO.
	MOVNI	T2,UCLLEN+CCLLEN  ;LENGTH OF TABLE
	CAME	T1,CCLTAB+UCLLEN+CCLLEN(T2)  ;SEARCH SYSTEM ROUTINE NAME TABLE
	AOJL	T2,.-1
	HRRI	T2,UCLLEN(T2)
	JUMPGE	T2,CPOPJ##	;IF NOT FOUND, NO. OF UUO
	HRRM	T2,M		;STORE INDEX IN UUO, JUST AS IF USER HAD DONE CALLI UUO
;FALL INTO CALLI ON NEXT PAGE
;CALL UUO FALLS IN HERE
;CALLI UUO	-	CALL IMMEDIATE
;CALLI D,E
;WHERE E IS RELATIVE INDEX IN CALL TABLE
UCALLI::MOVE	T1,T2		;SAVE USER/EXEC BIT
	HRRE	T2,M		;GET CALLI NUMBER(POS.=DIGITAL,NEG.=CUSTOMER DEFINED)
IFN FTPHYO,<
	JUMPL	T2,UCALL1	;IF ARGUMENT IS POSITIVE,
	TRZE	T2,UPHNLY	;IS BIT 19=1?
	HRLI	P1,PHONLY	;YES, PHYSICAL DEVICES ONLY
	JRST	UCALL2
UCALL1:	TRON	T2,UPHNLY	;ARGUMENT NEG, IS BIT 19=0?
	HRLI	P1,PHONLY	;YES, PHYSICAL ONLY
>	;END CONDITIONAL ON FTPHYO
UCALL2:	CAML	T2,MCCLEN	;MORE NEGATIVE THAN MOST NEGATIVE CUSTOMER DEFINED UUO?
	CAIL	T2,UCILEN	;MORE POSITIVE THAN HIGHEST DIGITAL DEFINED CALLI?
	POPJ	P,		;YES, RETURN TO USER TREAT AS NO-OP SO
				; PROGRAMS AHEAD OF MONITOR WILL STILL
				; RUN WITHOUT ERROR MESSAGE
	TLNE	T1,(XC.USR)	;NO, UUO WAS FROM MONITOR?
	POP	P,(P)		;NO, REMOVE RETURN
	HRR	M,P1		;UUO AC FIELD
	PUSHJ	P,GTWST2##	;PICK UP CONTENTS OF USER AC
	ROT	T2,-1		;DIVIDE BY 2 AND SAVE REMAINDER
	MOVE	U,UCLJMP(T2)	;GET DISPATCH TABLE ENTRY
IFN FTVM,<
	MOVE	T3,CHKTBC(T2)	;GET CHECK-BITS
>
	JRST	DISP2		;AND GO DISPATCH
;CALL UUO DISPATCH TABLE
;NEW UUO'S MUST BE ADDED AT END SINCE CALLI DEPENDS ON
;POSITION IN TABLE, CUSTOMERS SHOULD ADD UUO'S IN CNAMES MACRO SO CALLI ADDRESS
;WILL BE NEGATIVE.  IN THIS WAY BOTH DIGITAL AND ITS CUSTOMERS CAN ADD UUO'S
;WITHOUT CONFLICT, DIGITAL GOING POSITIVE, CUSTOMERS GOING NEGATIVE.
; (ALSO, TOWARD TOP OF PAGE)



DEFINE CNAMES <
IFN FTPATT,<
X	CPOPJ,CPOPJ##                   ;(-3) PLACE FOR CUSTOMERS
                                        ;    TO PATCH UUOS
X	CPOPJ,CPOPJ##                   ;(-2) 
>
X	LIGHTS,LIGHTS,UU.CP1            ;(-1) SET LIGHTS (EXAMPLE
                                        ;    OF CUSTOMER DEFINED
                                        ;    UUO)
>

DEFINE NAMES,<
X	RESET,RESET                     ;(0)RESET IO
X	DDTIN,DDTIN##,UU.EA+25          ;(1)EXT-GET DDT CHAR.
X	SETDDT,SETDDT,UU.CP1            ;(2)SETDDT LOC IN PROTECTED
                                        ;    JOB DATA
X	DDTOUT,DDTOUT##,UU.EA+25        ;(3)EXT:SEND DDT CHAR.
X	DEVCHR,DVCHR                    ;(4)DEVICE CHARACTISTICS
X	DDTGT,CPOPJ##,UU.CP1            ;(5)GET DDT MODE
X	GETCHR,DVCHR                    ;(6)DEVICE CHAR.(DIFF. NAME)
X	DDTRL,CPOPJ##,UU.CP1            ;(7)RELEASE DDT MODE
X	WAIT,WAIT                       ;(10)WAIT TILL DEVICE INACTIVE
X	CORE,CORUUO##                   ;(11)CORE UUO
X	EXIT,EXIT                       ;(12)EXIT
X	UTPCLR,UTPCLR                   ;(13)CLEAR DEC TAPE DIRECTORY
                                        ;    
X	DATE,DATE,UU.CP1                ;(14)GET DATE
X	LOGIN,LOGIN,UU.MEA              ;(15)LOGIN
X	APRENB,APRENB                   ;(16)ENABLE APR FOR TRAPPING
X	LOGOUT,LOGOUT                   ;(17)LOGOUT
X	SWITCH,SWITCH,UU.CP1            ;(20)RETURN DATA SWITCHES
X	REASSI,REASSI##                 ;(21)REASSIGN DEVICE TO ANOTHER
                                        ;    JOB
X	TIMER,TIMER,UU.CP1              ;(22)RETURN JIFFY CLOCK TIME
X	MSTIME,MSTIME,UU.CP1            ;(23)RETURN TIME OF DAY IN
                                        ;    MS


;CONTINUED ON NEXT PAGE
X	GETPPN,GETPPN,UU.CP1            ;(24)RETURN PROJECT-PROGRAMMER
                                        ;    NUMBER
X	TRPSET,TRPSET,UU.LEA            ;(25)SET PI TRAP LOC, AND
                                        ;    USER IO
X	TRPJEN,UUOERR##                 ;(26)DISMISS INTERRUPT TO
                                        ;    EXEC MODE(SUPERCEDED
                                        ;    BY UJEN)
X	RUNTIM,JOBTIM                   ;(27)RETURN TOTAL JOB RUNNING
                                        ;    TIME
X	PJOB,JOBNO,UU.CP1               ;(30)RETURN JOB NUMBER
X	SLEEP,SLEEP                     ;(31)SLEEP FOR N SECONDS,
                                        ;    THEN RETURN TO USER
X	SETPOV,SETPOV,UU.CP1            ;(32)SET PUSH DOWN OVERFLOW
                                        ;    TRAP
X	PEEK,UPEEK,UU.CP1               ;(33)TO PEEK AT CERTAIN MONITOR
                                        ;    PARAMETERS
X	GETLIN,GETLN,UU.CP1             ;(34) GET TTY LINE NUMBER
X	RUN,URUN##,UU.EA+6              ;(35) RUN DEV:FILE
X	SETUWP,SETUWP                   ;(36) SET OR CLEAR USER MODE
                                        ;    WRITE PROTECT
X	REMAP,REMAP                     ;(37) REMAP TOP OF LOW SEGMENT
                                        ;    INTO HIGH SEG
X	GETSEG,UGTSEG##,UU.EA+6         ;(40) GET SHARABLE HIGH SEG
X	GETTAB,GETTAB,UU.CP1            ;(41) GET EXEC ADDRESS OF
                                        ;    A JOB TABLE
X	SPY,USPY##                      ;(42) SET HIGH SEG TO BE
                                        ;    PHYSICAL CORE
X	SETNAM,SETNAM,UU.CP1            ;(43) SETNAME OF THIS PROGRAM
                                        ;LAST CALLI IN 4.50
X	TMPCOR,TMPUUO##,UU.EA           ;(44) TEMPORARY FILE STORAGE
                                        ;    UUO (CCL)
X	DSKCHR,DSKCHR##,UU.LEA          ;(45) DISK CHARACTERISTICS
                                        ;LAST CALLI IN 4.72
X	SYSSTR,SYSTUU##                 ;(46) RETURN NEXT STR IN
                                        ;    SYSTEM
X	JOBSTR,JOBSTR##,UU.LEA          ;(47) RETURN NEXT STR IN
                                        ;    JOB
X	STRUUO,STRUUO##,UU.LEA          ;(50) VARIOUS FUNCTION FOR
                                        ;    STRS
X	SYSPHY,SYSPHY##,UU.CP1          ;(51) RETURN ALL PHYSICAL
                                        ;    DEVS AND UNITS IN SYSTEM
X	FRECHN,CPOPJ##,UU.CP1           ;(52) RETURN 1ST FREE USER
                                        ;    CHAN IN AC, STARTING
                                        ;    FROM C(AC)
X	DEVTYP,DVTYP                    ;(53) EXTENDED DEVICE CHARACTERISTICS
                                        ;    AND BUFFER SIZE


;CONTINUED ON NEXT PAGE
X	DEVSTS,DEVST                    ;(54) DEVSTS
X	DEVPPN,DEVPPU	            ;(55) RETURN PPN FOR DEVICE
X	SEEK,UUOSEK##                   ;(56) SEEK
                                        ;LAST CALLI IN 5.01
X	RTTRP,RTTRP##,UU.EA+4           ;(57) REAL TIME TRAP
X	LOCK,LOKJOB##                   ;(60) LOCK JOB IN CORE
X	JOBSTS,UJBSTS##,UU.CP1          ;(61) RETURN STATUS OF JOB
                                        ;    AND ITS PTY
X	LOCATE,LOCATE##,UU.CP1          ;(62) FOR REMOTE COMM
X	WHERE,WHERE##	                ;(63) FOR REMOTE COMM
X	DEVNAM,UDEVNM                   ;(64) GET PHYSICAL DEVICE
                                        ;    NAME
X	CTLJOB,CTLJOB##,UU.CP1          ;(65) FIND CONTROLLER OF
                                        ;    THIS JOB (IF BY PTY)
X	GOBSTR,GOBSTR##,UU.LEA          ;(66) GENERALIZED JOBSTR
                                        ;    (ANY JOB'S SEARCH LIST)
                                        ;LAST CALLI IN 5.02
X	FOO,CPOPJ##,                    ;(67) FOO
X	FOO,CPOPJ##,                    ;(70) FOO
X	HPQ,HPQ##,UU.CP1                ;(71) HIGH PRIORITY QUEUE
                                        ;    UUO
IFN FTHIBWAKE,<
X	HIBER,HIBUUO                    ;(72) HIBERNATE UUO
>
IFE FTHIBWAKE,<
X	HIBER,CPOPJ##,UU.CP1            ;(72) NOP
>
X	WAKE,WAKUUO                     ;(73) WAKE UUO
X	CHGPPN,CHGPPN,UU.CP1            ;(74) CHANGE PPN
X	SETUUO,SETUUO##,UU.CP1          ;(75) SET
X	DEVGEN,DEVGEN                   ;(76) DEVICE GENERIC NUMBER
                                        ;    UUO
X	OTHUSR,GETPPL,UU.CP1            ;(77) SEE IF OTHER USER'S
                                        ;    WITH SAME PPN AS CALLING
                                        ;    JOB
X	CHKACC,ACCCHK##,UU.EA+3         ;(100) ACCESS-ALLOWED UUO
X	DEVSIZ,DVSIZ	             ;(101) RETURN BUFFER SIZE
X	DAEMON,CALDAE,UU.LEA            ;(102) CALL DAEMON
X	JOBPEK,JOBPEK,UU.EA+2           ;(103) READ/WRITE ANOTHER
                                        ;    JOB'S CORE
X	ATTACH,UATTAC                   ;(104) ATTACH OR DETACH JOBS.
X	DAEFIN,DAEFIN,UU.LEA            ;(105) DAEMON FINISHED -
                                        ;    RESTART USER JOB
X	FRCUUO,FRCUUO,UU.LEA            ;(106) FORCE COMMAND FOR
                                        ;    JOB
X	DEVLNM,DEVLNM                   ;(107) SET DEVICE LOGICAL
                                        ;    NAME
                                        ;LAST CALLI IN 5.03


;CONTINUED ON NEXT PAGE
X	PATH.,PTHUUO##,UU.LEA           ;(110) TEST/SET FULL PATHS
                                        ;    TO FILES
X	METER.,METER##,UU.LEA           ;(111)PERFORMANCE METERING
X	MTCHR.,MTACHR##			;(112)GET MAGTAPE CHARACTERISTICS
X	JBSET.,JBSET.##,UU.EA+2         ;(113)JOB SETUUO
X	POKE.,POKE,UU.EA+3              ;(114)CHANGE MONITOR
X	TRMNO.,TRMNO##                  ;(115)TERMINAL NUMBER FOR
                                        ;    JOB
X	TRMOP.,TRMOP##,UU.LEA           ;(116)TERMINAL OPERATIONS
                                        ;    UUO
X	RESDV.,RESDV                    ;(117)RESET DEVICE OR CHANNEL
X	UNLOK.,UNLOK.##                 ;(120)UNLOCK A LOCKED JOB
                                        ;LAST CALLI IN 5.04
X	DISK.,DSKUUO##,UU.EA            ;(121)RANDOM DISK FUNCTIONS
X	DVRST.,DEVRST                   ;(122)RESTRICT DEVICE TO
                                        ;    OPER ONLY
X	DVURS.,DEVURS                   ;(123)UNRESTRICT DEVICE
                                        ;LAST CALLI IN 5.05 & 5.06
IFN     FTXTC,<
X	XTTSK.,XTUUO##,UU.LEA           ;(124)DA28C DEPENDENT FUNCTIONS
>
IFE     FTXTC,<
X	XTTSK.,CPOPJ##                  ;(124)DA28C DEPENDENT FUNCTIONS
>
X	CAL11.,CALL11##,UU.LEA          ;(125)MULTI-FUNCTION CALLI
                                        ;    FOR THE PDP-11
X	MTAID.,MTARID##                 ;(126)FOR MTA ERROR REPORTING
IFN FT5UUO,<
X	IONDX.,UIONDX	            ;(127)RETURN IO INDEX
>
IFE FT5UUO,<
X	IONDX.,CPOPJ##                  ;(127)NOT IMPLEMENTED
>
X	CNECT.,CONECT##,UU.EA+1         ;(130)CONNECT A DEVICE TO
                                        ;    AN MPX CHAN
X	MVHDR.,MOVHDR                   ;(131)MOVE BUFFER HEADER
X	ERLST.,ERLST##,UU.EA+2          ;(132)ERROR LIST
X	SENSE.,SENSE##,UU.LEA           ;(133)SENSE
X	CLRST.,CLRST##,UU.LEA           ;(134)CLEAR STATUS


;CONTINUED ON NEXT PAGE
X	PIINI.,PIINI##,UU.EA            ;(135)INITIALIZE SOFTWARE
                                        ;    INTERRUPT SYSTEM
X	PISYS.,PISYS##                  ;(136)MANIPULATE SOFT. INTERRUPT
                                        ;    SYSTEM
X	DEBRK.,DEBRK##                  ;(137)DISMISS A SOFTWARE
                                        ;    INTERRUPT
X	PISAV.,PISAVE##,UU.LEA+UU.CP1   ;(140)SAVE THE PI SYSTEM
X	PIRST.,PIRST##,UU.EA+UU.CAC     ;(141)RESTORE THE PI SYSTEM
X	IPCFR.,UIPCFR##,UU.EA+4         ;(142) IPCF READ
X	IPCFS.,UIPCFS##,UU.EA+4         ;(143) IPCF SEND
X	IPCFQ.,UIPCFQ##,UU.EA+4         ;(144) IPCF QUERY
IFN FTVM,<
X	PAGE.,UPAGE.##,UU.CP1           ;(145) PAGING UUOS
>
IFE FTVM,<
X	PAGE.,CPOPJ##,UU.CP1
>
X	SUSET.,USUSET##                 ;(146) SUPER USETI/O
X	COMPT.,CPOPJ##                  ;(147) CALL TO COMPATABILITY
                                        ;    PACKAGES
                                        ;LAST CALLI IN 5.07/6.01
IFN FTNSCHED,<
X	SCHED.,SCHED.##                 ;(150) SCHEDULING UUO
>;END IFN FTNSCHED
IFE FTNSCHED,<
X	SCHED.,CPOPJ##
>;END IFE FTNSCHED

X	ENQ.,ENQ##                      ;(151) ENQUEUE
X	DEQ.,DEQ##                      ;(152) DEQUEUE
X	ENQC.,ENQC##                    ;(153) ENQ CONTROLLER


;CONTINUED ON NEXT PAGE
X	TAPOP.,UTAPOP##,UU.LEA          ;(154) TAPOP. UUO (SEE TAPSER)
IFE FT5UUO,<
X	FILOP.,CPOPJ##                  ;(155) UNDEFINED
>
IFN FT5UUO,<
X	FILOP.,FILOP,UU.LEA             ;(155) FILOP. UUO
>
X	CAL78.,CALL78##                 ;(156) FOR DAS78
X	NODE.,NODE.U##                  ;(157) RESERVED FOR NETWORKS
X	ERRPT.,ERRPT.##			;(160) ERROR REPORTING UUO FOR DAEMON
IFE FTGALAXY,<
X	ALLOC.,CPOPJ##			;(161) UNDEFINED
>
IFN FTGALAXY,<
X	ALLOC.,ALLOC,UU.LEA		;(161) ALLOC. UUO
>
X	PERF.,UPERF.			;(162) PERFORMANCE ANALYSIS UUO
IFN FTDHIA,<
X	DIAG.,DIAUUO##			;(163) DIAGNOSTIC UUO
>
IFE FTDHIA,<
X	DIAG.,CPOPJ##			;(163) UNDEFINED
>
IFE FT5UUO,<
X	DVPHY.,CPOPJ##			;(164) UNDEFINED
>
IFN FT5UUO,<
X	DVPHY.,DVPHY.			;(164) DVPHY.UUO
>
IFN FT5UUO,<
X	GTNTN.,GTNTN			;(165) GET THE NETWORK TTY NUMBER
X	GTXTN.,GTXTN			;(166) GET THE -10 TTY NAME
>
IFE FT5UUO,<
X	GTNTN.,CPOPJ##			;(165) NOT IMPLEMENTED
X	GTXTN.,CPOPJ##			;(166) NOT IMPLEMENTED
>
IFN FTACCT,<
X	ACCT.,ACCT			;(167) ACCOUNTING UUO
>
IFE FTACCT,<
X	ACCT.,CPOPJ##			;(167) NOT IMPLEMENTED
>
IFN FTKL10,<
X	DTE.,DTE.##			;(170) DTE. UUO
>;END IFN FTKL10
IFN FTKA10!FTKI10,<
X	DTE.,CPOPJ##			;(170) NOT IMPLEMENTED
>;END IFN FTKA10!FTKI10
IFN FT5UUO,<
X	DEVOP.,DEVOP,UU.LEA		;(171) DEVOP. UUO
>
IFE FTGALAXY,<
X	SPPRM.,CPOPJ##			;(172) NOT IMPLEMENTED
>	;END IFE FTGALAXY

IFN FTGALAXY,<
X	SPPRM.,SPPRM,UU.LEA		;(172) SPPRM. UUO
>	;END IFN FTGALAXY



;***ADD NEW CALLI'S ABOVE THIS LINE *****
IFN FTPATT,<
X	CPOPJ,CPOPJ##   ;2 SPARE UUO'S FOR PATCHING - DIGITAL ONLY
X	CPOPJ,CPOPJ##   ;ALWAYS ADD NEW UUO'S ABOVE THESE
>
                                ;CUSTOMERS SHOULD ADD UUO'S ABOVE
                                ;IN CNAMES MACRO RATHER THAN NAMES MACRO
                                ; SO THAT THEIR CALLI INDICES WILL
                                ; BE NEGATIVE
>
;GENERATE SIXBIT TABLE OF UUO NAMES

DEFINE X (A,B,C) <
	<EXP SIXBIT /A/>
>

;GENERATE CUSTOMER CALL/CALLI UUO'S

MCCLEN::EXP	-CCLLEN
CCLTAB:	CNAMES
CCLLEN==.-CCLTAB	;LENGTH OF CUSTOMER DEFINED CALL/CALLI UUO'S
			;(MINIMUM CALLI NUMBER, TOO)

;GENERATE DIGITAL UUO'S

DEFINE X (A,B,C)  <
	IFL	.-UCLTAB-MAXCAL,<EXP SIXBIT /A/>
>

UCLTAB:	NAMES
XP	UCLLEN,.-UCLTAB		;DEFINE LENGTH OF DIGITAL UUO TABLE
DEFINE X (A,B,C)
<	ZZ==ZZ+1
	DEFINE	XX (D)		;DEFINE XX IN CASE ODD NUMBER OF CUSTOMER UUO'S
<	XWD CPOPJ##,D
>>
ZZ==0
;COUNT NUMBER OF CUSTOMER DEFINED UUO'S
	CNAMES

;GENERATE HALF WORD UUO DISPATCH TABLE

DEFINE X (A,B,C)
<	IFE ZZ&1,
<	DEFINE XX (D)
<
	XWD	B,D
>>
	IFN	ZZ&1,
<
	XX	B
>
ZZ==ZZ+1
>
;GENERATE CUSTOMER TABLE

CUSTAB:	CNAMES

ZZ==0

;GENERATE DIGITAL TABLE

UCLJMP:	NAMES

	IFN	ZZ&1,<XX CPOPJ##>	;GEN. LAST WORD IF ODD NUMBER OF UUOS
UCILEN==:<.-UCLJMP>*2		;MAX DIGITAL CALLI INDEX
IFN FTVM!FTMS,<
	DEFINE	X(A,B,C)
<	ZZ==ZZ+1
>
	DEFINE	XX(D)		;DEFINE XX IN CASE ODD NO. OF CUST. CALLI'S
<	XWD	0,D
>
ZZ==0
;COUNT NUMBER OF CUSTOMER CALLI'S
	CNAMES
DEFINE X (A,B,C)
<IFE ZZ&1,
<DEFINE XX (D)
<
	XWD	C,D
>>
	IFN	ZZ&1,
<
	XX	C
>
ZZ==ZZ+1
>
	CNAMES
ZZ==0
CHKTBC::NAMES

IFN ZZ&1,< XX 0>
>
	SUBTTL	EXIT & SETPOV UUO'S


;EXIT UUO ROUTINE
;CALL:	CALL FIELD, [SIXBIT/EXIT/]
;IF FIELD - 0, PRINT EXIT ^C.  CONT WILL NOT WORK

EXIT:
IFN FTLOGIN,<
	MOVSI	T1,JLOG
	TDNN	T1,JBTSTS##(J)	;IS THIS JOB LOGGED IN?
	  JRST	LOGOUT		;NO, GO DESTROY JOB
>
	JUMPN	P1,MONRET	;AC FIELD NON-ZERO?
	PUSHJ	P,IORELS	;NO, RELEASE ALL DEVICES
	PUSHJ	P,RESET		;AFTER CLOSING OUT FILES, RELEASE RT DEV
				;UNLOCK JOB, RESET APR
	PUSHJ	P,TTYFUW##	;FIND TTY FOR CURRENT JOB
				; SET J TO JOB NO.,U TO OUTPUT BYTE POINTER
				; F TO TTY DDB
	JSP	T1,PHOLD##	;MOVE "EXIT" TO OUTPUT BUFFER
				; AND STOP JOB, AND START TTY, CONT WILL NOT WORK
	ASCIZ	/
EXIT/

;	CALL 1,[SIXBIT/EXIT/] - RETURN TTY TO MONITOR MODE,
;	STOP JOB, BUT DO NOT RELEASE DEVICES
;TYPE . WITH NO CRLF, ALLOW CONT COMMAND TO RETURN AFTER UUO


MONRET:	PUSHJ	P,TTYFUW##	;FIND TTY FOR CURRENT JOB
	PUSHJ	P,PRRSP3##	;PRINT [XXX], CRLF, DOT
	PUSHJ	P,TTYSTC##	;PUT TTY INTO COMMAND MODE
	PUSHJ	P,STOP1C##	;START TTY IN MONITOR MODE AND STOP JOB, BUT ALLOW
				; CONTINUE TO WORK (RETURN CONTROL AFTER EXIT UUO)
	JRST	USCHED##	;CALL SCHEDULER WHICH WILL SET CURRENT JOB
				; WITH RUN BIT OFF AND WILL STOP JOB


;SETPOV - SET PUSH DOWN OVERFLOW TRAP
;CALL	MOVE AC,ADR. OF TRAP ON PD OVF
;	CALL AC,[SIXBIT /SETPOV/]


SETPOV:	MOVEM	T1,JOBAPR##(R)
	MOVEI	T1,1B19
	JRST	APRENB		;SET TRAP LOC.

	SUBTTL	RESET & APRENB UUO'S


RESET::
IFN FTKL10,<
	PUSHJ	P,CPUCDB##	;P4=THIS CPUS CDB
	PUSHJ	P,HAVPMR##	;HAVE PERFORMANCE METER?
	  CAIA			;NO, DON'T GIVE IT UP
	PUSHJ	P,RELPMR##	;YES, GIVE IT BACK.

	PUSHJ	P,FEDRST##	;RELEASE FRONT END DEVICE
>;END IFN FTKL10
	PUSHJ	P,TTYRES##	;NORMALIZE CONTROLLING TTY, IF ANY
IFN FTHIBWAK,<			;HIBERNATE-WAKE FEATURE?
IFN FTHPQ,<			;HIGH PRIORITY QUEUE FEATURE?
	LDB	T2,HPQSPT##	;CONSOLE COMMAND HPQ SETTING
>
	HRLOI	T1,HPQMSK##	;MASK OUT LH BITS LEAVE RH SAME
				; (REAL TIME DEVICE COUNT)
	ANDM	T1,JBTRTD##(J)	;CLEAR ALL BUT CONSOLE COMMAND HPQ
IFN FTHPQ,<			;HIGH PRIORITY QUEUE
	DPB	T2,HPQPNT##	;RESTORE CONSOLE COMMAND AS OPERATING QUEUE
>				;END FTHPQ
>				;END FTHIBWAK
IFN FTNET,<
				;THIS CALL MUST PRECEED THE CALL TO UNLOCK BELOW
	PUSHJ	P,NETCTC##	;ALSO CALL NETSER ON CONTROL ^C
>;END FTNET
IFN FTLOCK,<
	PUSHJ	P,UNLOCK##	;TURN OFF NSHF AND NSWP AND RETURN CORE
	>
IFN FTTRPSET,<
	SETZM	STOPTS##	;MAKE SURE SCHEDULING ALLOWED
				; IN CASE THIS FOLLOWS A TRPSET UUO
				;(IF STOPTS IS NON-ZERO, THIS MUST BE
				; THE JOB THAT STOPPED TIME SHARING)
IFN FTMS,<	CAMN	J,.C1STS##	;IS THIS THE SLAVE JOB DOING A TRPSET
	SETZM	.C1STS##	;YES, CLEAR HIS STOP TIME SHARING FLAG
	PUSHJ	P,CRESET##	;RESET UUO SET CPU SPECIFICATION
>
>
IFN FT2REL,<
	PUSHJ	P,HRESET##	;FLAG USER AS HAVING UWP ON FOR HIGH SEG
				; AND DO DATAO TO SET UWP ON
>
	PUSHJ	P,FNDPDS##	;FIND THE JOB PDB
	HRRZ	T2,.PDSCX##(W)	;ADDRESS OF JOB'S SAVED CONTEXT
	MOVEI	T1,NWSCTX	;NUMBER OF WORDS OF SAVED CONTEXT
	SKIPE	T2		;HAS THE JOB'S CONTEXT BEEN SAVED?
	PUSHJ	P,GIVWDS##	;YES, RETURN SPACE TO MONITOR FREE CORE
	HLLZS	.PDSCX##(W)	;INDICATE NO SAVED CONTEXT
IFN FTSET,<
	PUSHJ	P,CLRBRK##	;CLEAR ADDRESS BREAK IF SET BY UUO
>
IFN FTPI,<
	PUSHJ	P,CLRPSI##	;RESET SOFTWARE INTERRUPT STATUS
>
IFN FTEQDQ,<
	PUSHJ	P,ENQRST##	;CLEAR ALL LOCKS
>
IFN FTIPCF,<
	PUSHJ	P,IPCFRS##	;SIGNAL RESET TO SYS:INFO
>
	MOVEI	T1,RELEA5	;RELEASE ALL DEVICES
	PUSHJ	P,IOALL		; WITHOUT WAITING
IFN FTWATCH,<
	HRRZS	JBTPC##(J)	;NOT IN IOWAIT NOW (FOR ^T'ERS)
>
	PUSHJ	P,SETUSR	;CLEAR USERS JOB DATA AREA

IFE FTVM,<
	SKIPE	T2,USREPL##	;JOB HAVE EXTENDED PD LIST IN EXEC?
	PUSHJ	P,GIVEPL##	;YES. RETURN IT
>	;END IFE FTVM
	MOVSI	T1,777777-USRMOD  ;CLEAR ALL UUO PC FLAGS IN LH, EXCEPT USER MODE
	ANDCAM	T1,JOBPD1##(R)	;LEAVE USER MODE OFF TOO, IF EXEC DOING CALL RESET
				; FALL INTO APRENB WITH RH T1=0
				; SO THAT ALL APR INTERRUPTS WILL BE DISABLED
;ROUTINE TO SET UP APR FOR USER TRAPPING
;CALL:	CALL AC,[SIXBIT /APRENB/]
;WITH FOLLOWING APR CONSO FLAG BITS
;TO INDICATE WHICH APR CONDITIONS SHOULD
;TRAP TO USER WHEN TRAP OCCURS FROM USER MODE
;1B18	;DO NOT DISABLE SELECTED CONDITIONS (EXCEPT CLOCK) SEE APRINT

;1B19	;PUSHDOWN OVERFLOW
;1B22	;ILLEGAL MEMORY
;1B23	;NON-EXISTENT MEMORY
;1B26	;CLOCK
;1B29	;FLOATING POINT OVERFLOW
;1B32	;ARITH. OVERFLOW


APRENB::
	HRRM	T1,JOBENB##(R)	;SET RH TO CONSO BITS IN JOB DATA AREA
				; USED EVERY TIME IS STARTED UP

	JRST	SETAPR##	;GO ENABLE/DISABLE APR FOR FOV AND HR OV
				; ALSO SET APR CONSO INSTR. FOR PROPER FLAGS
				; AND RETURN TO USER
	SUBTTL	MISC. ACCOUNTING UUOS (JOBNO,JOBTIM,DATE & MSTIME)

;RETURN JOB NUMBER FOR THIS JOB

JOBNO:	SKIPA	T1,J		;JOB NUMBER
				; SKIP AND STORE T1 IS USER AC

;RETURN THE DATE TO THE USER


DATE:	MOVE	T1,THSDAT##
	JRST	STOTAC##

;RETURN JOB RUNNING TIME IN MILLISECONDS
JOBTIM:IFN FTTIME,<
	PUSHJ	P,JOBTMM	;GET JOBS RUN TIME
	PJRST	STOTAC##	; AND STORE IT

;THIS CODE DEPENDS UPON RTUPS BEING AN INTEGRAL MULTIPLE OF ^D100000

JOBTMM::MOVEI	T3,RTUPS3##	;ASSUME MILLISECOND RESOLUTION
	TLZE	T1,(1B0)	;IF SIGN BIT = 1
	MOVEI	T3,RTUPS5##	; RETURN 10 USEC. RESOLUTION
	IMUL	T3,TICSEC##
	PUSH	P,T3		;SAVE FOR LATER DIV
	PUSHJ	P,LGLPR1##	;SKIP IF LEGAL JOB NUMBER (0 IS OK)
	  JRST	JOBTM3
IFE FTPDBS,< ;IF PDBS ARE ALWAYS IN CORE THIS IS EASY
	SKIPN	T1
	SKIPA	T1,J
	MOVE	J,T1		;J PROCESS # IN QUESTION
	PUSHJ	P,FNDPDB##	;FIND THE PDB
	  JRST	JOBTM3		;IF NONE RETURN ZERO
> ;END FTPDBS
IFN FTPDBS,< ;IF PDBS ARE ON THE DISK
	MOVE	T2,T1		;T2 HOLDS THE PROCESS NUMBER
	MOVE	T3,PDIOWD##	;T3 IS THE IOWD
	PUSHJ	P,SCWAIT##	;GET THE SC RESOURCE
	PUSHJ	P,REDPDB##	;PUT THE PDB IN THE BUFFER
	MOVEI	W,PDBUFF##	;POINT TO PDB
> ;END FTPDBS
	PUSHJ	P,CPUJOB##	;SET UP J FROM JOB
IFN FTEMRT,<
	MOVEI	T1,ST%EMR	;EBOX MBOX ROUTINE?
	TDNN	T1,CNFST2##	;?
	JRST	JOBTM1		;NO, COMPUTE RUNTIME NORMAL WAY
				;YES,
	.MOVE	T1,.PDMB2##(W)	;GET REMAINDER FROM MBOX JIFFY CALCULATION
	MULI	T1,RTUPS##	;COMPUTE LEFTOVER*RTUPS/MBOX TICKS PER JIFFY
	DIV	T1,.CPMBJ##(P4)	;LEAVE IN T1
	.MOVE	T3,.PDEB2##(W)	;SAME FOR EBOX TICKS
	MULI	T3,RTUPS
	DIV	T3,.CPEBJ##(P4)
	ADD	T3,T1		;RESULT CANNOT BE GREATER THAN 2*RTUPS,
				; WHICH FITS IN 36 BITS
	.MOVE	T1,.PDEBT##(W)	;GET EBOX TICKS
	.ADD	T1,.PDMBT##(W)	;COMPUTE EBOX/MBOX HIGH ORDER RUNTIME
	MULI	T1,RTUPS##	;CONVERT TO HIGH PRECISION UNITS
	ADD	T2,T3		;ADD LOW ORDER PART FROM T3
	JRST	JOBTM2		;GO JOIN COMMON CODE AGAIN
JOBTM1:>;END FTEMRT
	.MOVE	T1,.PDTTM##(W)	;TOTAL JOB RUNNING TIME
	MULI	T1,RTUPS##	;EXPAND TO FULL PRECISION
	.ADD	T2,.PDTT2##(W)	;ADD JIFFY FRACTION
JOBTM2:	TLZE	T2,(1B0)	; DOUBLE PRECISION
	AOS	T1
	POP	P,T3
	DIV	T1,T3
IFN FTPDBS,< ;IF WE GOT THE SC RESOURCE ABOVE
	PUSHJ	P,SCFREE##	;RETURN THE RESOURCE
> ;END FTPDBS
	POPJ	P,
JOBTM3:	SETZM	(P)		;RETURN ZERO
	JRST	TPOPJ##
>
IFE FTTIME,<
	JRST	RTZER		;RETURN ZERO IF NO TIMMING COM.
>

;RETURN TIME OF DAY IN MILLISECONDS


MSTIME:	MOVE	T1,TIME##	;USE APR CLOCK BECAUSE IT HAS BETTER LONG
				; TERM ACCURACY
	IMULI	T1,^D1000	;CONVERT TO MILLISECONDS
	IDIV	T1,TICSEC##
	JRST	STOTAC##
	SUBTTL	SLEEP SERVICE FOR SLEEP UUO, DTA, MTA AND SCNSER.

;PUT JOB TO SLEEP FOR NSECONDS
;CALL	CALL AC,[SIXBIT /SLEEP/]
;AC=XWD LOC,N   N=NUMBER OF SECONDS TO SLEEP
;IF LH(AC)NON-0, SLEEP ONLY IF LOC THROUGH LOG+17
; MATCHES THE CURRENT JOBSTS ON THAT CHAN, OR IS 0


SLEEP::
IFN FTSLEEP,<
	MOVSI	T2,(JS.SLP)	;SET SLEEP BIT
	IORM	T2,JBTST2##(J)	;..
	IMUL	T1,TICSEC##	;CONVERT TO TICKS
	ANDI	T1,7777
MSLEEP:	TRNN	T1,7777		;0 TIME?(CHECK ONLY 12 BITS)
	MOVEI	T1,1		;YES. SLEEP 1 JIFFY
IFN FTSWAP,<
	PUSH	P,W		;SAVE W FOR DTASRN WHERE IT POINTS
				; TO CONTROLER DATA BLOCK
	PUSHJ	P,FNPDBS##	;FIND THE PDB OR STOP
	.LDB	T2,PDYIPT##	;GET PROTECT TIME
	CAIGE	T2,(T1)		;SLEEPING LONGER THAN PROTECT TIME?
	PUSHJ	P,CLRIPT##	;YES. CLEAR PROTECT TIME
	POP	P,W
>
	PUSH	P,T1		;SAVE SLEEP TIME
	HRLI	T1,WAKEJ##	;ADR. IN RUNCSS WHEN JOB WAKES UP
	MOVEI	T2,CLKR
	TDNE	T2,JBTSTS##(J)	;DOES THIS JOB HAVE A CLOCK QUEUE
				; REQUEST IN CLOCK QUEUE?
	JRST	XSLEEP		;YES, DO NOT PUT ANOTHER ONE IN
SSLEEP:	CONO	PI,PIOFF##
	IDPB	T1,CLOCK##
	IDPB	J,CLOCK##
	CONO	PI,PION##
	JRST	SLPNAP		;SET JOB STATUS WORD SO JOB WILL NOT RUN
XSLEEP:	MOVE	T2,T1		;TIME TO SLEEP
	MOVE	T1,J		;JOB NUMBER
	PUSHJ	P,CLKCHG##	;FIX UP THE CLOCK REQUEST
	  JRST	SSLEEP		;NO, ENTRY FOUND IN THE CLOCK QUEUE
				; SO MAKE ONE NOW

SLPNAP:	POP	P,T1		;RESTORE SLEEP TIME
	PUSHJ	P,SAVE4##	;SETSLP USES 16,17
	MOVEI	T2,JIFSEC##	;GET SECONDS WORTH OF JIFFIES
	CAILE	T2,(T1)		;SLEEPING LONGER THAN A SECOND?
	JRST	SETNAP##	;NO, JUST GIVE THIS JOB A NAP
	JRST	SETSLP##	;YES, PUT THIS JOB TO SLEEP
>;END IFN FTSLEEP
IFE FTSLEEP,<	POPJ P,	;RETURN IMMEDIATELY IF NOT A FEATURE>
	SUBTTL	PEEK UUO

;PEEK INTO MONITOR UUO
;CALL	MOVEI	AC,<MONITOR ADDRESS>
;	CALL	AC,[SIXBIT .PEEK.]


IFN FTPEEKSPY,<			;PEEK AND SPY
UPEEK:	JUMPL	T1,RTZER	;RETURN 0 IF NEGATIVE ARGUMENT
	MOVE	T2,T1		;SAVE ARG
IFE FTPRV,<
IFN FTLOGIN,<
	HLRZ	T1,JBTPPN##(J)	;GET USER'S PROJECT NUMBER
	CAIN	T1,1		;SKIP IF SYSTEM ADMINISTRATOR
				;DON'T ALLOW REGULAR USERS TO DO THIS
				; NOTE PATCH TO JFCL IF OK
>
	CAMLE	T2,SYSSIZ##	;SKIP IF ASKING FOR LEGAL VALUE
>
IFN FTPRV,<	MOVSI	T1,PVSPYA	;SEE IF USER MAY SPY ON ALL CORE
	PUSHJ	P,PRVBIT##	;..
	  JRST PEEKOK		;YES.  OK
	MOVSI	T1,PVSPYM	;NO.  MAY HE SPY ON MONITOR?
	PUSHJ	P,PRVBIT##	;..
	  JRST PEEK1		;YES
	JRST	RTZER		;NO.  ERROR, RETURN 0.

PEEK1:	CAMGE	T2,SYSSIZ##	;IS HE ASKING FOR LEGAL VALUE?
PEEKOK:
	CAML	T2,MEMSIZ##	;..
>
	JRST	PEEKHI		;NO.  FAILURE.  RETURN 0
GOPEEK:	MOVE	T1,0(T2)	;YES.  GET WORD
	JRST	STOTAC##	;RETURN IT TO USER IN AC.
IFN FT2SEGMON,<
PEEKHI:	MOVE	T3,SYSLEN##	;SIZE OF HISEG
	CAIL	T2,MONORG	;IS THIS IN THE
	CAILE	T2,MONORG(T3)	; HISEG
	JRST	RTZER		; NO
	JRST	GOPEEK		; YES
>	;END FT2SEGMON

>	;END IFN FTPEEKSPY
	SUBTTL	POKE. UUO
;POKE. -- PRIVILEGED UUO TO ALTER THE MONITOR
;CALL:	MOVE	AC,[3,,BLOCK]
;	POKE.	AC,
;	ERROR
;	OK
;ERROR RETURN WITH AC UNCHANGED IF NOT IMPLEMENTED
;	AC=0 IF NOT PRIVILEGED
;	AC=1 IF BAD MATCH
;	AC=2 IF BAD ADDRESS
;
;BLOCK:	LOCATION
;   +1	OLD VALUE
;   +2	NEW VALUE
	IFN	FTPOKE,<
POKE:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVE	P1,T1		;SAVE ARGUMENT
	MOVSI	T1,JP.POK	;CHECK FOR POKE
	PUSHJ	P,PRVBIT##	;  PRIVILEGES
	  CAIA
	JRST	RTZER		;NO--BOMB USER
	HRR	M,P1		;POINT TO BLOCK
	PUSHJ	P,GETWDU##	;GET LOCATION
IFN FT2SEGMON,<
	MOVE	T2,SYSLEN##
	CAIL	T1,MONORG
	CAILE	T1,MONORG(T2)
	CAIA
>	JRST	POKE0
	CAILE	T1,17		;CHECK ADDRESS
	CAML	T1,MEMSIZ##	;  SEE IF LEGAL
	PJRST	ECOD2##		;NO--BOMB USER WITH ERROR 2
POKE0:	MOVE	P1,T1		;SAVE ADDRESS
	MOVE	P2,T1
	PUSHJ	P,GETWD1##	;GET USER'S IDEA OF
				;  OLD CONTENTS
	MOVE	T4,T1		;SAVE IT
	PUSHJ	P,GETWD1##	;GET NEW VALUE
IFN FT2SEGMON,<
	MOVE	T2,SYSLEN##
	CAIL	P1,MONORG
	CAILE	P1,MONORG(T2)
	JRST	POKE1
	MOVE	T2,P1
	LSHC	T2,W2PLSH##-1
	TLNN	T3,400000
	TDOA	T2,[POINT 18,.EPPM##,17]
	TDO	T2,[POINT 18,.EPPM##,35]
	LDB	T2,T2
	TRO	T2,PM.WRT
	HRRM	T2,.UPMP+.MTEMP
	MOVEI	T2,.TEMP/1000
	DPB	T2,[POINT 9,P1,26]
	CLRPGT	(0,.TEMP)
>
POKE1:	CONO	PI,PIOFF##	;TO BE SAFE
	CAME	T4,(P1)		;COMPARE OLD VALUE
	JRST	POKE.1		;FAIL--BOMB USER
	MOVEM	T1,(P1)		;WIN--STORE
	CONO	PI,PION##	;TURN ON SYSTEM
	AOS	LASPUC##	;INCREMENT COUNT OF NO. OF POKE UUOS
	HRLM	J,LASPUC##	;ALSO STORE JOB NO WHICH POKED LAST
	MOVEM	P2,LASPOK##	;SAVE LOCATION CHANGED TOO (LEAVE ROOM FOR 22 BIT ADR)
				; USEFUL IN CASE OF CRASH CAUSED BY POKE
	JRST	CPOPJ1##	;SKIP RETURN

POKE.1:	CONO	PI,PION##	;TURN ON SYSTEM
	PJRST	ECOD1##		;RETURN CODE 1
>
IFE FTPOKE,<POKE==CPOPJ##>
SUBTTL PERF. MUUO

;THE PERF. MUUO IS INTENDED TO BE A GENERAL PURPOSE CALL
; TO EXECUTE SYSTEM PERFORMANCE MEASURING FUNCTIONS.  THESE FUNCTIONS
; INCLUDE HANDLING OF THE KL10 PERFORMANCE METER.  THE METER IS
; CONSIDERED A RESOURCE WHICH CAN BE USED ONLY BY ONE PROCESS AT A TIME.
;
;CALL TO THE PERF. MUUO:
;
;	MOVE	AC,[XWD N,ADDR]		;COUNT OF FUNCTIONS, ADDRESS
;	PERF.	AC,			;OR CALLI AC,***
;	  <ERROR RETURN>		;ERROR CODE RETURNED IN AC
;	<SUCCESSFUL RETURN>
;
;ADDR:	XWD	FUNCTION,BLOCK
;	XWD	FUNCTION,BLOCK
;		.
;		.
;		.			;N FUNCTIONS
;
;THE LOCATION BLOCK ALWAYS CONTAINS COUNT OF THE NUMBER OF
; WORDS FOLLOWING IN THE BLOCK.  THE REST OF THE
; BLOCK IS FUNCTION SPECIFIC.
;
;THE MAIN LOOP OF THE PERF. UUO IS RESPONSIBLE FOR SETTING UP
; P2 FROM THE ITEM COUNT AT LOCATION BLOCK, CHECKING AND DISPATCHING
; FROM THE FUNCTION NUMBERS PROVIDED, AND SETTING UP THE RIGHT HALF
; OF AC M TO POINT TO BLOCK OF THE CURRENT FUNCTION IT IS EXECUTING.
; IT EXPECTS P1 TO BE PRESERVED BY THE FUNCTION EXECUTION ROUTINES, SINCE
; P1 IS USED AS AN AOBJN POINTER TO THE LIST OF FUNCTIONS TO BE EXECUTED.
;
;THE FUNCTION EXECUTION ROUTINES USE ACS T1-T4, AND A SPECIAL ARGUMENT
; GETTER THAT THEY CALL USES P2 TO DETERMINE IF THE ARGUMENTS IN BLOCK
; ARE EXHAUSTED OR NOT.  THE ROUTINES THAT HANDLE THE KL10 PERFORMANCE
; METER TAKE ADVANTAGE OF THE FACT THAT ZERO IS ALWAYS DONT CARE BY
; SIMPLY RETURNING ZERO IF THE ARGUMENT IS NOT PRESENT.

;INTERN THE ERROR RETURNS SO THE MODULES CAN CALL THEM

	INTERN	PREICT,PRENXC,PREIPM,PREMNS,PREMIU,PREMAS,PREBJN
	INTERN	PREMNR,PREFNI,PREBFN,PREMBP


UPERF.::PUSHJ	P,SAVE2##	;P1 AND P2 WILL BE USED
	MOVE	P1,T1		;SAVE C(AC)
	PUSHJ	P,PRVJ		;PRIVS?
	  CAIA			;YES
	JRST	PREMBP		;**MUST BE PRIVILEGED**
	HLRE	T1,P1		;GET POSITIVE COUNT IN T1
	JUMPLE	T1,CPOPJ1##	;FINISHED IF .LE. ZERO
	MOVNS	T1		;MAKE AOBJN POINTER
	HRL	P1,T1		;PUT -COUNT IN LH OF P1, AOBJN POINTER

UPERF1:	HRR	M,P1		;GET NEXT FUNCTION
	PUSHJ	P,GETWDU##	;GET FUNCTION,,BLOCK
	HRR	M,T1		;PUT ADDRESS OF BLOCK IN M
	HLRZ	T4,T1		;SAVE FUNCTION NUMBER IN T4
	PUSHJ	P,GETWDU##	;GET COUNT OF ITEMS IN BLOCK
				;M NOW POINTS TO BLOCK FOR FUNCTION ROUTINE
	MOVE	P2,T1		;SAVE COUNT IN P2 WHERE IT BELONGS
	ROT	T4,-1		;TAKE INTO ACCOUNT DISPATCH TABLE IS 1/2 WORDS
	MOVE	T3,UPRFDS(T4)	;GET ENTRY
	SKIPL	T4		;SKIP IF ITS THE ODD ENTRY
	MOVSS	T3		;NOT, ITS THE EVEN
	PUSHJ	P,(T3)		;DISPATCH TO PROPER ROUTINE
	  POPJ	P,		;ROUTINE GAVE ERROR RETURN, STOP UUO
	AOBJN	P1,UPERF1	;OK SO FAR, DO MORE FUNCTIONS IF ANY LEFT
	JRST	CPOPJ1##	;EVERYTHING IS BEAUTIFUL (IN ITS OWN WAY)

;DISPATCH TABLE
; HERE WE MUST EITHER EXTERN THE ADDRESS OF THE FUNCTION ROUTINE,
; OR DEFINE THE FUNCTION TO JUMP TO THE ERROR ROUTINE
; THAT INDICATES UNIMPLEMENTED FUNCTION.


IFN FTKL10,<
	EXTERN CPOPJ,PMRSET,PMRSTR,PMRRED,PMRSTP,PMRREL
>;END IFN FTKL10

IFE FTKL10,<
	PMRSET==PREFNI
	PMRSTR==PREFNI
	PMRRED==PREFNI
	PMRSTP==PREFNI
	PMRREL==PREFNI
>;END IFN FTKL10


UPRFDS:	XWD	CPOPJ##,PMRSET	;(0,1)
	XWD	PMRSTR,PMRRED	;(2,3)
	XWD	PMRSTP,PMRREL	;(4,5)

	PRFMAX==<.-UPRFDS>*2-1	;MAXIMUM FUNCTION NUMBER
				;NOTE THAT IF LAST WORD IN DISPATCH
				;TABLE HAS ONLY ONE FUNCTION,
				;THE OTHER SLOT MUST HAVE PREFNI IN IT.
;ERROR RETURNS - USE SYSTEM ERCODE MACRO

	PRFBC%==1
	PRFNC%==2
	PRFIM%==3
	PRFNS%==4
	PRFMB%==5
	PRFAS%==6
	PRFBJ%==7
	PRFMS%==10
	PRFUF%==11
	PRFBF%==12
	PRFNP%==13

	ERCODE	PREICT,PRFBC%	;IMPROPER CPU TYPE
	ERCODE	PRENXC,PRFNC%	;NON-EXISTANT CPU
	ERCODE	PREIPM,PRFIM%	;IMPROPER MODE
	ERCODE	PREMNS,PRFNS%	;METER NOT SETUP
	ERCODE	PREMIU,PRFMB%	;METER BUSY
	ERCODE	PREMAS,PRFAS%	;METER ALREADY STARTED
	ERCODE	PREBJN,PRFBJ%	;BAD JOB NUMBER
	ERCODE	PREMNR,PRFMS%	;METER NOT RUNNING
	ERCODE	PREFNI,PRFUF%	;UNIMPLEMENTED FUNCTION
	ERCODE	PREBFN,PRFBF%	;BAD FUNCTION NUMBER
	ERCODE	PREMBP,PRFNP%	;NO PRIVILEGES

	SUBTTL	CALLS TO SEGCON FOR SETUWP AND REMAP

;SET OR CLEAR USER MODE WRITE PROTECT BIT IN HIGH SEG FOR THIS USER ONLY
;CALL:	MOVEI AC,0 OR 1
;	CALL AC,[SIXBIT /SETUWP/] OR CALLI AC,34
;	ERROR - MACHINE OR MONITOR CANNOT HANDLE TWO REG, OR TRYING TO CLEAR
;			;UWP OF A SHARABLE SEG(AC=1 ON RETURN)
;	OK RETURN - AC CONTAINS PREVIOUS SETTING( OR JOB HAS NO HIGH SEG)

IFN FT2REL,<
SETUWP=USTUWP##			;GO TO ROUTINE IN SEGCON
				;IF FT2REL=0, SETUWP DOES RTZER
>


;UUO TO REMAP TOP PART OF LOW SEGMENT INTO HIGH SEGMENT
;PREVIOUS HIGH SEG(IF ANY) IS KILLED AND A NEW SEGMENT NUMBER IS ASSIGNED
;TO THIS JOB. REMAP IS USED BY LOADER AND GET
;CALL:	MOVEI AC,NEW HIGHEST USER ADR IN LOW SEG(EXEC ORS IN 1777)
;	CALL AC,[SIXBIT /REMAP/] OR CALLI AC,35
;	ERROR RETURN, MACHINE OR EXEC CANNOT HANDLE 2 REG OR DESIRED ADR
;			;GREATER THAN OLD LOW SEG
;	OK RETURN, LOW SEG ABOVE ARG NOW THE HIGH SEG

IFN FT2REL,<
REMAP=UREMAP##			;CORE1 MODULE IN SEGCON
>
IFE FT2REL,<
REMAP=CPOPJ##			;ERROR RETURN TO USER(CPOPJ IS AN EXTERN)
>
	SUBTTL	TRIVIAL UUOS (LIGHTS, TIMER AND SWITCH)

;SET LIGHTS ON CONSOLE FROM USER PROGRAM

;CALL AC,[SIXBIT /DATAO/] OR CALLI AC,-1

;THIS IS AN EXAMPLE OF A USER DEFINED UUO WITH A NEGATIVE CALLI ARG.

LIGHTS:
IFN FTKI10!FTKA10,<
	DATAO	PI,T1		;SENT USER'S AC TO CONSOLE LIGHTS
>;END IFN FTKA10!FTKI10
	POPJ	P,		;RETURN TO HIM

;RETURN TIME OF DAY IN JIFFIES (60THS,50THS OR MS)


TIMER:	SKIPA	T1,TIME##	;FALL INTO STOTAC

;RETURN DATA SWITCHES


SWITCH:
IFN FTKA10!FTKI10,<
	DATAI	APR,T1		;GET 36 BIT SWITCHES
>
IFN FTKL10,<
	SETZ	T1,		;RETURN ZERO ON KL10
>
	JRST	STOTAC##	;GO STORE VALUE
IFN FT5UUO,<
SUBTTL DVPHY. UUO
;THE DVPHY. UUO RETURNS THE PHYSICAL NAMES OF ALL THE DEVICES OF A
; CERTAIN TYPE OR OPTIONALLY, THE PHYSICAL NAMES OF ALL THE DEVICES
; ON THE SYSTEM (EXCLUDING PTYS, TTYS, MPXS, AND DSK).
;CALLING SEQUENCE:
;	MOVE	AC,[N,,ADDR]	;COUNT,,ARGUMENT
;	DVPHY. 	AC,		;OR CALLI AC,164
;	<ERROR RETURN>
;	<NORMAL RETURN>
;
;WHERE
;ADDR:	DEVICE TYPE OR -1 IF ALL DEVICES
;+1	0 FOR FIRST CALL, PREVIOUS DEVICE NAME ON SUBSEQUENT CALLS
;NEXT PHYSICAL DEVICE NAME IS RETURNED IN ADDR+1 OR 0 IF LAST
; DEVICE IN THE SYSTEM OF THAT TYPE.

DVPHY.:	PUSHJ	P,SAVE1##	;SAVE P1
	HRR	M,T1		;ADR OF ARG BLOCK
	HLRE	T1,T1		;LENGTH OF BLOCK
	MOVMS	T1		;MAKE SURE IT'S POSITIVE
	CAIGE	T1,2		;ENOUGH ARGS?
	JRST	DPEIAL		;INVALID ARG LIST
	PUSHJ	P,GETWDU##	;GET DEVICE TYPE
	CAILE	T1,TYPMAX	;LEGAL?
	JRST	DPENDT		;NO SUCH DEVICE TYPE
	CAME	T1,[-1]		;WANT EVERYTHING?
	JUMPL	T1,DPENDT	;NO, NO DEVICE IF NEGATIVE
	MOVE	P1,T1		;SAVE ARGUMENT
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	JUMPGE	P1,DVPHY2	;GO IF DONT WANT EVERYTHING
	HLRZ	F,DEVLST##	;ALL, START AT START OF DEVS
	JUMPE	T1,DVPHY1	;GO IF FIRST CALL
	PUSHJ	P,DEVPHY	;NOT FIRST, FIND THIS DEVICE
	  JRST	DPENPD		;NOT THERE
	HLRZ	F,DEVSER(F)	;POINT AT NEXT DEVICE ON CHAIN
DVPHY1:	PUSHJ	P,NOTPTD	;FIND NEXT DEVICE
	  JRST	DVPHY4		;NO MORE, RETURN A ZERO
	JRST	DVPHY6		;WON, STORE T1 AND SKIP RETURN
DVPHY2:	JUMPN	T1,DVPHY3	;GO IF NOT 1ST CALL
	MOVE	T1,P1		;AND HERE I GOT CONFUSED
	PUSHJ	P,DVSDVT
	  JRST	DPENDT
	JRST	DVPHY5
DVPHY3:	PUSHJ	P,DEVPHY
	  JRST	DPENPD
	HLRZ	F,DEVSER(F)
	LDB	T1,PDVTYP##
	CAIE	T1,.TYDSK/.TYEST
	CAME	T1,P1
DVPHY4:	TDZA	T1,T1
DVPHY5:	MOVE	T1,DEVNAM(F)
DVPHY6:	AOS	(P)
	PJRST	PUTWDU##
;SUBROUTINE TO SEARCH FOR A DEVICE TYPE
;CALLING SEQUENCE:
;	MOVEI	T1,DEVICE TYPE
;	PUSHJ	P,DVSDVT
;RETURNS CPOPJ IF NOT FOUND. CPOPJ1 IF FOUND, F POINTS AT THE FIRST
; DDB IN THE DEVICE CHAIN WHICH IS THAT DEVICE TYPE,

DVSDVT:	HLRZ	F,DEVLST##
DVSDV1:	LDB	T2,PDVTYP##
	CAMN	T1,T2
	JRST	CPOPJ1##
	HLRZ	F,DEVSER(F)
	JUMPE	F,CPOPJ##
	JRST	DVSDV1

;SUBROUTINE TO SEARCH FOR THE NEXT DEVICE WHICH IS NOT A PTY, TTY,
; OR DSK.
;CALLING SEQUENCE:
;	MOVE	F,PLACE TO START ON THE DDB CHAIN
;	PUSHJ	P,NOTPTD
;RETURNS CPOPJ IF NO MORE DEVICES, CPOPJ1 WITH F POINTING AT THE
; DDB IF A DEVICE WHICH IS NOT A PTY, TTY, OR DSK IS FOUND, T1= DEVICE
; NAME.

NOTPTD:	MOVEI	T1,NOTTTL
	LDB	T2,PDVTYP##
NOTPT1:	CAIE	T2,@NOTTBL-1(T1)
	SOJG	T1,NOTPT1
	JUMPLE	T1,NOTPT3
NOTPT2:	HLRZ	F,DEVSER(F)
	JUMPE	F,CPOPJ##
	JRST	NOTPTD
NOTPT3:	SKIPE	T1,DEVNAM(F)
	JRST	CPOPJ1##
	JRST	NOTPT2

NOTTBL:	XWD	ZERO5,.TYPTY/.TYEST
	XWD	ZERO5,.TYTTY/.TYEST
	XWD	ZERO5,.TYDSK/.TYEST
	XWD	ZERO5,.TYMPX/.TYEST
	XWD	ZERO5,TYPMAX+1
NOTTTL==.-NOTTBL
;DVPHY. ERROR CODES
DVPIA%==1	;INVALID ARGUMENT LIST
DVPIT%==2	;INVALID DEVICE TYPE
DVPNP%==3	;NO SUCH PHYSICAL DEVICE
DVPNT%==4	;NO SUCH DEVICE TYPE

ERCODE DPEIAL,DVPIA%	;INVALID ARGUMENT LIST
ERCODE DPEIDT,DVPIT%	;INVALID DEVICE TYPE
ERCODE DPENPD,DVPNP%	;NO SUCH PHYSICAL DEVICE
ERCODE DPENDT,DVPNT%	;NO SUCH DEVICE TYPE
>	;END OF IFN FT5UUO
	SUBTTL	DEVCHR AND DEVSIZ UUO'S

;RETURN DEVICE CHARACTERISTICS


IFN FTSPL, <
DVCH0:
IFN	FTPHYO,<
	TLOE	P1,PHONLY	;ALREADY HAVE REAL DEVICE ?
	JRST	DVCH1		;YES, GET DEVMOD
>
	MOVE	T1,DEVNAM(F)	;NO, GET NAME USER SUPPLIED
	HRRZ	P2,DEVMOD(F)	;DEVMOD FOR SPOOLED DEVICE
	TRZ	P2,-1-<ASSCON!ASSPRG>	;SAVE ASSCON AND ASSPRG
	JRST	DVCH3		;SKIP OVER SAVE AND CLEARING P2
DVCHR:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	SETZ	P2,		;FIRST CALL - ZERO P2
DVCH3:
>
IFE FTSPL, <
DVCHR:
>
IFE FT5UUO,<
	PUSHJ	P,DEVSRC	;SEARCH FOR DEVICE
>
IFN FT5UUO,<
	PUSHJ	P,DVCNSG	;SEARCH FOR DEVICE
>
	  JRST RTZER		;NOT A DEVICE, RETURN ZERO
IFN FTNUL,<
	SETZ	T3,
	CAMN	T1,[SIXBIT /NUL/]  ;NUL DEVICE?
	MOVEI	T3,-1-TTYATC	;YES, LH WILL BE CHANGED
>
IFN FTSPL, <
	SKIPE	DEVCHR(F)	;IF NOT A FAKE DDB,
	SKIPL	DEVSPL(F)	;IF A SPOOLED DEVICE,
DVCH1:	SKIPA	T1,DEVMOD(F)
	JRST	DVCH0		; GO GET DEVMOD FOR REAL DEVICE
>
IFE FTSPL,<
DVCH1:	MOVE	T1,DEVMOD(F)	;REAL DEVICE FOUND, RETURN DEVMOD
>
IFN FTSPL,<
	PUSHJ	P,CHKSPL	;DEVICE SPOOLED?
	  TRZA	T1,ASSCON!ASSPRG  ;YES, IGNORE WHAT REAL DEV IS DOING
	JRST	DVCH2		;NO
	IOR	T1,P2		; AND SET ASSCON, ASSPRG FROM SPOOLED DDB
	TLO	T1,DVAVAL	;YES, SET AVAILABLE-BIT
DVCH2:
>
	LDB	T2,PJOBN##	;GET JOB NO.  USING DEVICE
	CAME	T2,JOB##	;DOES CURRENT USER ALREADY HAVE IT?
	TRNN	T1,ASSCON+ASSPRG	;NO, IS IT ASSIGNED?
	TLO	T1,DVAVAL	;NO, BUT HE CAN GET IT.
IFN FTNUL,<
	TLO	T1,(T3)		;SET LH = -1 IF NUL:
>
	PUSHJ	P,TTYKLQ##	;DISCARD TTY DDB IF NOT IN USE
	JRST	STOTAC##

;SUBROUTINE TO DETERMINE IF CHARACTERISTICS OF DDB IN F SHOULD BE
; REPLACED BY THOSE OF THE SPOOLED DEVICE.
;CALL IS
;	MOVE	F,DDB-ADR
;	PUSHJ	P,CHKSPL
;	SPOOLED RETURN
;	NOT SPOOLED RETURN
;SPOOLED BIT FOR DEVICE (DEYSPL) RETURNED IN T2; OTHER ACS PRESERVED
IFN FTSPL,<	;IF SPOOLING
CHKSPL:	LDB	T2,DEYSPL##	;GET SPOOL BIT FOR DEVICE
	SKIPN	DEVCHR(F)	; "FAKE" (TABLE) DDB?
	POPJ	P,		;YES
	TDNN	T2,JBTSPL##(J)	;NO. JOB SPOOLING DEVICE?
	  JRST	CPOPJ1##	;NO
	PUSH	P,T1		;MAYBE. SAVE T1
	PUSH	P,T2		; AND T2
	MOVE	T1,DEVMOD(F)	;GET DEVMOD
	LDB	T2,PJOBN##	;AND JOB OWNING DEVICE
	TRNE	T1,ASSCON!ASSPRG  ;DEVICE ASSIGNED OR INITED?
	CAME	T2,JOB##	;YES, TO US?
	  SOS	-2(P)		;NO, SPOOLED RETURN
	POP	P,T2		;RESTORE T2
	JRST	TPOPJ1##	;RESTORE T1 AND EXIT SKIP/NO-SKIP
>	;END FTSPL

IFN FT5UUO,<
;RETURN DEVICE TYPE (AND OTHER PROPERTIES)
DVTYP:	AOS	(P)		;SKIP-RETURN SINCE UUO IS IMPLIEMENTED
	PUSHJ	P,DVCHR		;GET DEVICE CHARACTERISTICS
	JUMPE	T1,CPOPJ##	;NO SUCH DEV - RETURN 0
IFN FTSPL,<
	PUSHJ	P,CHKSPL	;SEE IF DEVICE IS SPOOLED
	  TLOA	T2,.TYSPL!DVAVAL	;YES, SPOOL+AVAILABLE
>	;END CONDITIONAL ON FTSPL

DVTY1:	SETZ	T2,		;NO
	MOVE	T3,T2		;SAVE DEVCHR WORD
	TLZ	T1,-1-DVIN-DVOUT-DVTTY-DVAVAL;SAVE CERTAIN BITS
	OR	T1,T2		;+SPOOL+AVAILABLE
	LDB	T2,DEYTYP##	;GET TYPE+VAR BUFFER SIZE
IFN FTSPL,<
	SKIPN	DEVCHR(F)	;FROM TABLE?
	HLRZ	T2,SPLBIT##(F)	;YES, GET TYPE-NUMBER
>
	TRZE	T2,DERLEN	;VARIABLE BUFFER SIZE?
	TLNE	T1,.TYSPL	;YES, BEING SPOOLED?
	JRST	.+2		;YES
	TLO	T1,.TYVAR	;UNSPOOLED, VARIABLE DEV
	HRR	T1,T2		;GET TYPE INTO T1
IFN FTNUL,<
	SKIPN	T2		;IF A DISK,
	JUMPL	T3,DVTY2	; IF "DVDIRIN" IS ON ITS NUL:
>
IFN FTTSK!FTRDX,<
	CAIE	T2,.TYRDA/.TYEST  ;IS IT A RDA
	CAIN	T2,.TYTSK/.TYEST  ;IS IT A TASK
	TLOA	T1,.TYINT	;YES, SET INTERACTIVE MODE
>
	CAIG	T2,.TYDTA/.TYEST  ;DSK OR DTA?
	TLO	T1,.TYMAN	;YES - LOOKUP/ENTER MANDATORY
DVTY2:	LDB	T2,PJOBN##	;OWNER OF DEVICE
IFN FTSPL,<
	SKIPE	DEVCHR(F)	;NO OWNER IF SPOOLED
>
	DPB	T2,[POINT 9,T1,26]	;IN BITS 18-26
IFN FTMSGSER,<
	TLO	T1,TY.MPX	;ASSUME OK
	PUSHJ	P,LGLMPX##	;IS IT OK?
	  TLZ	T1,TY.MPX	;NO--CLEAR BIT
>
	SKIPGE	DEVCHR(F)	;IS THIS A LOWER CASE LPT?
	TLO	T1,TY.LL	;YES
	MOVSI	T2,DVCMDA	;IS THIS AN
	TDNE	T2,DEVCHR(F)	;MDA DEVICE?
	TLO	T1,TY.MDA	;YES
	PJRST	STOTAC##	;RETURN TO USER

;STILL IN FT5UUO CONDITIONAL
;RETURN BUFFER SIZE, STANDARD NO OF BUFFERS
;CALL:	MOVE AC,LOC OF (2 WORRD) OPEN BLOCK
;CALLI AC,DVSIZ
;NOT IMPLEMENTED RETURN
;AC=XWD NO OF BUFS,BUF SIZE

DVSIZ:	PUSHJ	P,SAVE1##	;SAVE P1
	PUSH	P,M		;SAVE M
	HRR	M,T1		;GET LOC OF OPEN-BLOCK
	PUSHJ	P,GETWDU##	;GET MODE
	MOVE	P1,T1		;SAVE IT
	PUSHJ	P,GETWD1##	;GET DEVICE
	PUSHJ	P,DVCNSG	;FIND ITS DDB
	  TDZA	T1,T1		;NOT A DEVICE
	SKIPA	M,P1		;FOUND - SET M=MODE
	SOJA	T1,SIZRET	;NOT A DEV - RETURN AC=-1
	MOVEI	T2,1		;SET FOR MODE TEST
	ANDI	P1,17		;GET MODE ALONE
	LSH	T2,(P1)		;POSITION THE BIT
	MOVNI	T1,2		;IF MODE IS ILLEGAL,
	CAIL	P1,SD		;TEST FOR DUMP MODE
	TDZA	T1,T1		;IT IS, RETURN AC=0
	TDNN	T2,DEVMOD(F)	; RETURN AC=-2
	PJRST	SIZRET
IFN FTSPL,<
	PUSHJ	P,CHKSPL	;SPOOLED DEVICE?
	  MOVEI	F,DSKDDB##	;YES, SET FOR A DISK
>	;END CONDITIONAL ON FTSPL

	MOVE	T4,DEVSER(F)	;LOC OF DISPATCH TABLE
	PUSHJ	P,DSZ(T4)	;GET BUFFER SIZE
	PUSHJ	P,DFTNB		;FIND DEFAULT NUMBER OF BUFS
	HRL	T1,T2		;RETURN IN LH(T1)
	ADDI	T1,2		;BUMP SIZE BY 2 HOUSEKEEPING WORDS
SIZRET:	POP	P,M		;RESTORE LOC OF AC
	PJRST	STOTC1##	;STOTAC, THEN SKIP-RETURN
>	;END CONDITIONAL ON FT5UUO
IFE FT5UUO,<
DVTYP==CPOPJ##
DVSIZ==CPOPJ##
>

;SUBROUTINE TO SET T1=LENGTH OF A NON-VARIABLE BUFFER
REGSIZ::LDB	T1,PBUFSZ##	;NORMAL SIZE
	POPJ	P,		;RETURN 
;DEVGEN -- RETURN RANGE AND STATION OF GENERIC DEVICES
;CALL:	MOVE	AC,SIXBIT NAME OF DEVICE
;	CALLI	AC,DEVGEN
;RETURNS CPOPJ IF UNIMPLEMENTED OR IF NO SUCH DEVICE (AC UNCHANGED)
;RETURNS CPOPJ1 IF DEVICE FOUND WITH AC AS FOLLOWS:
;	BITS 0-8: LOWEST DEVICE NUMBER MATCHING GENERIC NAME
;	    9-17: HIGHEST DEVICE NUMBER MATCHING
;	   18-35: STATION NUMBER OF DEVICE
;IN PARTICULAR, DEPENDING ON THE TYPE OF NAME SPECIFIED, THE
;FOLLOWING RESULTS:
;	(1) SPECIFIC (E.G. LPT153)
;		LOW=HIGH=UNIT NUMBER (153)
;	(2) STATION GENERIC (E.G. LPTS3)
;		LOW=LOWEST DEVICE AT STATION OF THAT TYPE
;		HIGH=HIGHEST
;	(3) GLOBAL GENERIC (E.G. LPT)
;		IF DEVICE AT JOB'S STATION, SAME AS STATION GENERIC
;		IF NO DEVICE AT JOB'S STATION, SAME AS STATION GENERIC
;		AT THE CENTRAL STATION

DEVGEN==CPOPJ##			;THIS UUO NOT SUPPORTED NOW
REPEAT 0,<
DEVGEN:	PUSHJ	P,DEVSRC	;SEE IF SPECIFIC NAME
	  JRST	DEVGN1		;NO--TRY GENERIC
IFN FTSPL,<
	SKIPL	DEVSPL(F)	;SPOOLED DISK?
	JRST	DEVGN0		;NO
	MOVE	T1,DEVNAM(F)	;YES. NAME USER INITED
	JRST	DEVGEN		;DO THE UUO ON REAL DEVICE
DEVGN0:>
	LDB	T1,PDVSTA##	;GET STATION NUMBER
	LDB	T2,PUNIT	;GET UNIT NUMBER
	MOVE	T3,T2		;SET OTHER UNIT THE SAME

DEVGNX:	HRL	T1,T3		;STORE HIGH UNIT
	DPB	T2,[POINT 9,T1,8]	;STORE LOW UNIT
	PJRST	STOTC1##	;SKIP RETURN WITH T1 AS ANSWER
;HERE WHEN NOT A SPECIFIC UNIT

DEVGN1:	MOVEI	T3,0		;TAKE ANY DEVICE
	PUSHJ	P,DVASRC	;TRY GENERIC SEARCH
	  POPJ	P,		;FAILED--RETURN TO USER
	LDB	T2,PUNIT	;SAVE LOWEST UNIT
	LDB	T1,PDVSTA##	;GET STATION NUMBER

;LOOP OVER DDB CHAIN GETTING REST OF UNITS

	PUSHJ	P,SAVE1##	;SAVE P1

DEVGNL:	HLLZ	T4,DEVNAM(F)	;GET GENERIC NAME
	LDB	T3,PUNIT	;SAVE HIGH UNIT IN CASE LAST ONE
	HLRZ	F,DEVSER(F)	;MOVE TO NEXT UNIT
	JUMPE	F,DEVGNX	;RETURN RESULT IF END OF CHAIN
	LDB	P1,PDVSTA##	;GET THIS DEVICE'S LOCATION
	CAME	P1,T1		;IS IT THE SAME AS WE WANT?
	JRST	DEVGNX		;NO--RETURN RESULT TO USER
	HLLZ	P1,DEVNAM(F)	;YES--GET IT'S GENERIC NAME
	CAMN	P1,T4		;SEE IF IT MATCHES OUR REQUEST
	JRST	DEVGNL		;YES--LOOP ONWARDS
	JRST	DEVGNX		;NO--ALL DONE, RETURN RESULT
>;END OF REPEAT ZERO
	SUBTTL	GETPPN AND DEVPPN UUO'S (ALSO RTZER)


;RETURN PROJECT-PROGRAMMER NUMBER IN AC

GETPPN:
IFN FTLOGIN,<
	MOVSI	T1,JACCT
	TDNE	T1,JBTSTS##(J)	;LOGIN OR LOGOUT CUSP RUNNING ?
	JRST	GETPPL		;YES, SPECIAL PROJ,R NUMBER CHANGE.
	MOVE	T1,JBTPPN##(J)	;NO, RETURN PROJECT-PROGRAMMER NO. OF THIS JOB.
	JRST	STOTAC##
>



RTZER1::AOSA	(P)		;RETURN 0 AND SKIP RETURN
RTZERP:	POP	P,T1		;POP STACK & RETURN 0
IFE FT2REL, <
SETUWP:				;SETUWP RETURNS 0
>
IFE FT2SEGMON,<
PEEKHI:
>
IFE FTPEEKSPY,<
UPEEK:
>
RTZER::	TDZA	T1,T1		;RETURN 0. TO USER AC
RTM1::	SETOM	T1		;RETURN -1
	JRST	STOTAC##	;AS SPECIFIED IN AC FIELD OF HIS UUO


IFN FTDISK,<IFN FT5UUO,<
DEVPPU:	PUSHJ	P,DVCNSG	;FIND DDB
	  JRST RTZER		;NOT A DEVICE - RETURN 0
	PUSHJ	P,CURPPX##
	MOVSI	T2,DVDSK
	TDNN	T2,DEVMOD(F)	;IS DEVICE A DISK?
	JRST	STOTAC##	;NO, ERROR RETURN
	JRST	STOTC1##	;STORE ANSWER AND RETURN
>>
IFE FT5UUO,<
DEVPPU:	POPJ 	P,
>
	SUBTTL	IONDX.  UUO
IFN FT5UUO,<
;CALLI TO CONVERT CHANNEL # OR DEVICE NAME TO I/O INDEX
;CALL WITH:
;	MOVE	AC,DEVICE NAME OR CHANNEL #
;	IONDX.	AC,	OR CALLI 127
;	ERROR RETURN
;	GOOD RETURN UNIVERSAL I/O INDEX IN AC
UIONDX::PUSHJ	P,IONDX		;FIND THE IO INDEX
	  JRST	STOTAC##	;STORE ERROR CODE
	JRST	STOTC1##	;STORE IO INDEX

;SUBROUTINE TO FIND IO INDEX. SAME AS UIONDX EXCEPT USER'S AC IS LEFT
;	ALONE
IONDX::	PUSHJ	P,DVCNSG	;FIND A DDB
	  PJRST	ZPOPJ		;RETURN 0 IF NO SUCH DEVICE
IONDF::	FRAME	<NDXARG,NDXNAM>
	MOVEM	T1,NDXARG
	MOVE	T1,DEVNAM(F)
	MOVEM	T1,NDXNAM
	PUSHJ	P,TTYKLQ##	;KILL OFF DDB IF DDB
				; NOT NEEDED
	MOVE	T1,NDXNAM	;GET DEVICE NAME IN T1
	PUSHJ	P,TTYALL##	;SET UP U VIA SIXBIT NAME
	  JRST	DEVUDX		;TRY HARDER IF NOT A TTY
	LDB	T1,LDPLNO##	;GET LINE NUMBER
	ADDI	T1,.UXTRM	;CONVERT TO I/O INDEX
	PJRST	CPOPJ1##	;STORE IN AC AND SKIP
DEVUDX:	LDB	T1,PDVTYP##	;GET THE DEVICE TYPE
	MOVE	T3,T1
	LSH	T1,9		;ALLOW FOR UNIT NUMBER
	LDB	T2,PUNIT##	;PICK UP UNIT NUMBER
IFN FTRDX,<
	CAIN	T3,.TYRDA/.TYEST	;RDX DEVICE
	ANDI	T2,7			;YES, ONLY LOW ORDER 3 BITS
>;END FTRDX
	IOR	T1,T2		;SQUISH TOGETHER
	JUMPE	T1,DSKUDX	;IF RESULT=0 WE HAVE A DISK AND WANT TO DO
				; SOME SPECIAL THINGS.
	LDB	T2,PDVSTA##
	LSH	T2,3
	CAIE	T3,.TYTTY/.TYEST
	CAIN	T3,.TYPTY/.TYEST
	SKIPA
	IOR	T1,T2
IFN FTRDX,<
	CAIN	T3,.TYRDA/.TYEST	;RDX DEVICE
	JRST	DEVUD1			;YES
>;END FTRDX
	CAIE	T3,.TYMTA/.TYEST;IS THIS A MAG TAPE
	CAIN	T3,.TYDTA/.TYEST; OR A DEC TAPE?
	SKIPA			;YES--SEE IF THIS IS 2ND CONTROL
	PJRST	CPOPJ1##	;GOOD RETURN
DEVUD1:	LDB	T2,[POINT 6,DEVNAM(F),17] ;GET THIRD LETTER
	SUBI	T2,'  A'
	LSH	T2,^D15
	ADD	T1,T2
	JRST	CPOPJ1##	;GOOD RETURN

DSKUDX:	MOVE	T1,NDXARG
	MOVN	T3,USRHCU##	;NEGATIVE # OF CHANNELS IN USE
	HRLZI	T3,-1(T3)	;PUT IN LEFT HALF
DSUDX1:	HRRZ	T2,USRJDA##(T3)	;GET DDB ADRESS
	CAIE	T2,0(F)		;DVCNSG FIND THIS DDB?
	CAMN	T1,DEVNAM(T2)	;DID WE FIND A CHAN FOR THIS DDB?
	SKIPA	T1,T3		;YES--COPY CHAN # AND EXIT
	AOBJN	T3,DSUDX1	;NO--KEEP LOOKING
	TLZ	T1,-1		;MAKE SURE LH=0
	JUMPL	T3,CPOPJ1##	;GIVE GOOD RETURN IF FOUND
>;END IFN FT5UUO


ZPOPJ:	TDZA	T1,T1		;SET T1 = 0
M1POPJ:	MOVNI	T1,1		;SET T1 = -1
	POPJ	P,0		;RETURN
	SUBTTL	SUBROUTINE TO FIND A DDB GIVEN ITS IO INDEX

IFN FT5UUO,<
;SUBROUTINE TO FIND A DDB GIVEN ITS UNIVERSAL IO INDEX
;CALL WITH:
;	MOVE	T1,IO-INDEX
;	PUSHJ	P,UDXDDB
;	  BAD UDX OR NO SUCH DEVICE
;	HERE WITH F POINTING TO THE DDB
;
;NOTE: THIS ROUTINE IS NOT VERY FAST. DO NOT CALL IT UNLESS
;  THERE IS NO OTHER WAY TO SETUP F. IN PARTICULAR, DO NOT
;  CALL UDXDDB ON IN OR OUT UUOS.
;
UDXDDB::TLNE	T1,-1		;IS LH=0
	POPJ	P,0		;NO--INSTANT LOOSER
	CAIGE	T1,20		;0 TO 20 ARE I/O CHANNELS
	PJRST	DVCNSG		;GO SEE IF OPEN -- SKIP RETURN IF YES
	CAIGE	T1,1000		;20 THRU 777 ARE RESERVED
	POPJ	P,0		; SO THEY ALL FAIL
	LDB	T2,[POINT 3,T1,20] ;GET CONTROLLER NUMBER

	PUSH	P,T2
	CAIN	T2,2		;MATCH SPECIAL CODE FOR TTY?
	JRST	[TRNE	T1,577000	;IS THIS A POSSIBLE TTY
		 JRST	UDXDB1		;NO, CONTINUE
		 TRZN	T1,.UXTRM	; CHECK FOR A TTY
		 JRST	T2POPJ##	;NO EXIT
		 SETZM	(P)		;YES
		 PUSH	P,[SIXBIT .TTY.]  ;ELSE ASSUME TTY #
	MOVEI	 T2,.TYPTY/.TYEST	;SET T2 IN CASE VIRTUAL TTY
		 JRST	UDXDB2]	;AND GO LOOK FOR IT
UDXDB1:	LDB	T2,[POINT 6,T1,26] ;PICK UP DEVICE TYPE
	CAILE	T2,TYPMAX	;SKIP IF NOT TOO BIG
	JRST	T2POPJ##	;TOO BIG--BOMB OUT
	PUSH	P,TYPTAB(T2)	;ELSE SAVE GENERIC NAME
UDXDB2:	ANDI	T1,777		;JUST UNIT NUMBER
	CAIN	T1,777		;GENERIC ONLY?
	JRST	UDXDB4		;YES--GO DO GENERIC THING
	MOVE	T3,-1(P)	;GET BACK CONTROLLER NUMBER
	JUMPE	T3,UDXDB3
	ADDI	T3,'A'		;CONVERT TO LETTER
	DPB	T3,[POINT 6,(P),17] ;STORE IN DEVICE NAME
UDXDB3:	PUSH	P,T2
	PUSHJ	P,CVTSBT	;CONVERT UNIT NUMBER TO SIXBIT
	POP	P,T2
	CAIN	T2,.TYPTY/.TYEST	;NO LEADING O'S FOR PTY
	JRST	UDXDB4
	TLNN	T1,77		;3 DIGITS?
	JRST	[LSH T1,-6	;NO, SHIFT ONE DIGIT
		 TLO T1,(20B5)	;INSERT A LEADING SIXBIT 0
		 JRST .-1]
UDXDB4:	HLRM	T1,(P)		;STORE NUMBER
	POP	P,T1		;PUT INTO T1 FOR DEVSRG
	POP	P,T2
	PJRST	DEVSRG		;GO LOOK FOR THE DDB
	DEFINE	TYPES(X),<
	 IRP X,<
	  <SIXBIT \X\>
	>>

TYPTAB:	TYPES	<DSK,DTA,MTA,TTY,PTR,PTP,DIS,LPT,CDR>
	TYPES	<CDP,PTY,PLT,EPA,MPX,PAR,PCR,PAP,LPC,PCP,WTY,TSK>
	TYPES	<XXI,RDA,MCR>
>;END FT5UUO
	SUBTTL	GTNTN./GTXTN. UUO'S FOR TTY NAMES

IFN FT5UUO,<
;CALLI 165 (GTNTN) RETURN THE PHYSICAL NODE NUMBER AND TTY NUMBER
;CALL WITH:
;	MOVE	AC,[SIXBIT /TTYNNN/]
;	GTNTN.	AC,
;RETURN	CPOPJ			;TTY DOES NOT EXIST / NOT CONNECTED
;AC=XWD NODE NUMBER,LINE NUMBER
;ERRORS:
;	0:	NO SUCH DEVICE
;	1:	NOT A TTY
;	2:	TTY NOT CONNECTED
GTNTN:	PUSHJ	P,DVCNSG	;GET THE DDB
	  PJRST	ECOD0##		;NO SUCH DEVICE
	MOVSI	T2,DVTTY	;GET THE TTY BIT
	TDNN	T2,DEVMOD(F)	;IS IT?
	PJRST	ECOD1##		;NOPE
IFN FTNET,<
	MOVE	U,DDBLDB##(F)	;GET THE LDB
	MOVEI	T1,LDRREM##	;GET THE REMOTE BIT
	TDNN	T1,LDBDCH##(U)	;NETWORK TTY?
	JRST	GTNTN1		;NO, LOCAL TTY
	HLRZ	T2,LDBREM##(U)	;IS THE TTY CONNECTED?
	PJUMPE	T2,ECOD2##	;NOPE, TELL USER
	LDB	T1,LDPRLN##	;GET THE REMOTE LINE NUMBER
	HLL	T1,NDBNNM##(T2)	;INSERT THE NODE NUMBER
	PJRST	STOTC1##	;EXIT
GTNTN1:
>	;END IFN FTNET
	LDB	T1,LDPLNO##	;GET THE LINE NUMBER
IFN FTNET,<
	HRL	T1,JBTLOC##	;GET THE LOCAL NODE NUMBER
>
	PJRST	STOTC1##	;RETURN THE NODE,,LINE

;CALLI 166 (GTXTN) RETURN THE -10'S TTY NUMBER GIVER NODE AND LINE
;CALL WITH:
;	MOVE	AC,[XWD NODE,LINE]
;	GTXTN	AC,
;RETURN CPOPJ			;TTY/NODE DO NOT EXITS/NOT CONNECTED
;	CPOPJ1			;AC=SIXBIT /TTYNNN/
;ERRORS:
;	0:	UNKNOWN NETWORK TTY
;	1:	NO SUCH LOCAL TTY

GTXTN:	HLRZ	T2,T1		;GET THE NODE NUMBER
IFN FTNET,<
	CAME	T2,JBTLOC##	;LOCAL NODE?
>
	SKIPN	T2		;ZERO IS ALSO THE LOCAL NODE
	JRST	GTXTN4		;LOCAL NODE
IFE FTNET,<
	PJRST	ECOD0##		;NOT LOCAL RETURN ZERO
>
IFN FTNET,<
	SKIPN	T4,NETRTY##	;GET THE REMOTE PORTION OF THE SYSTEM'S TTYS
	JRST	ECOD0##		;NO REMOTE TTYS, RETURN ZERO
GTXTN1:	MOVE	U,LINTAB##(T4)	;GET THE LDB POINTER
	HLRZ	T3,LDBREM##(U)	;GET THE NDB POINTER
	HLRZ	T3,NDBNNM##(T3)	;GET THE NODE NUMBER
	JUMPE	T3,GTXTN2	;NOT CONNECTED
	CAIE	T3,(T2)		;ON THIS NODE?
	JRST	GTXTN2		;NO
	LDB	T3,LDPRLN##	;GET THE REMOTE LINE NUMBER
	CAIE	T3,(T1)		;IS THIS THE LINE?
GTXTN2:	AOBJN	T4,GTXTN1	;NO, CONTINUE THRU LINTAB
	JUMPGE	T4,ECOD0##	;NOT CONNECTED OR ILLEGAL

GTXTN3:	LDB	T1,LDPLNO##	;GET THE -10 LINE NUMBER
				;RESTORE U
	JRST	GTXTN5		;CONVERT AND EXIT
>	;END IFN FTNET

GTXTN4:	ANDI	T1,-1		;MAX NUMBER
	CAILE	T1,TCONLN##	;IN RANGE?
	JRST	ECOD1##		;NO, NOT A LEGAL TTY
IFN FTNET,<
	MOVE	T2,LINTAB##(T1)	;GET THE LDB POINTER
	MOVEI	T3,LDRREM##	;GET NETWORK LINE BIT
	TDNE	T3,LDBDCH##(T2)	;IS IT A NETWORK TTY?
	JRST	ECOD1##		;YES, ILLEGAL DEVICE
>	;END IFN FTNET
GTXTN5:	PUSHJ	P,CVTSBT	;NO, CONVERT TO SIXBIT
	HLRZ	T1,T1		;RIGHT HALF
	HRLI	T1,'TTY'	;INSERT TTY NAME
	PJRST	STOTC1##	;EXIT THE UUO
>	;END FT5UUO
	SUBTTL	MVBFH. UUO -- MOVE BUFFER HEADERS

IFN FT5UUO,<
;SUBROUTINE TO MOVE BUFFER HEADERS
;CALL WITH:
;	MOVE	AC,CHANNEL-NUMBER
;	MOVE	AC+1,[NEW-OUTPUT,,NEW-INPUT]
;	MVBFH.	AC,
;	  ERROR RETURN
;	GOOD RETURN
MOVHDR:	PUSHJ	P,SAVE1##	;SAVE UCHAN
	HRRZ	P1,T1		;COPY CHANNEL NUMBER
	LDB	T1,PUUOAC##	;GET AC #
	HRRI	M,1(T1)		;PLUS 1
	PUSHJ	P,GETWDU##	;PICK UP THE WORD
	CAMG	P1,USRHCU##	;SKIP IF CHANNEL # TOO BIG
	SKIPN	F,USRJDA##(P1)	;SKIP IF CHANNEL INITED
	JRST	ECOD1##		;ERROR -- BAD CHANNEL NUMBER
	PUSH	P,T1		;SAVE ARG
	HLRZ	T2,T1		;GET OUTPUT BUFFER ADDRESS
	JUMPE	T2,MVBFH1	;JUMPE IF NO CHANGE
	HRLM	T2,DEVBUF(F)	;STORE NEW ADDRESS
	TLON	F,OBUFB		;TEST AND SET "OUTPUT BUFFER EXISTS" FLAG
	PUSHJ	P,UINITZ	;NEW BUFFER
MVBFH1:	HRRZ	T2,(P)		;GET INPUT POINTER
	JUMPE	T2,MVBFH2	;JUMP IF NO CHANGE
	HRRM	T2,DEVBUF(F)	;SAVE NEW ADDRESS
	TLON	F,IBUFB		;FLAG WE HAVE INPUT BUFFER
	PUSHJ	P,UINITZ	;NEW BUFFER
MVBFH2:	MOVEM	F,USRJDA##(P1)	;SAVE UPDATED FLAGS
	JRST	TPOPJ1##	;GOOD RETURN
> ;END FT5UUO
IFE FT5UUO,<	MOVHDR==CPOPJ##	>
	SUBTTL	DEVSTS, DEVLNM, DEVRST, AND DEVURS UUO'S

IFN FT5UUO,<
;DEVICE STATUS CONI RETRIEVAL CALLI UUO
;     CALL AC,[SIXBIT/DEVSTS/]
;                 OR
;    CALLI AC,54

;             WHERE AC CONTAINS THE CHANNEL NUMBER OF THE
;		INIT'ED DEVICE....
;		OR DEVICE NAME
;		THE CONI STATUS WORD IN THE DDB (DEVSTS)
;		IS RETURNED IN AC 
DEVST:	PUSHJ	P,DVCNSG	;SEARCH FOR DEVICE OR CHANNEL
	  JRST RTZER			;RETURN 0 IF NOT THERE
	MOVE	T1,DEVSTS(F)	;GET DEVICE STATUS WORD
	JRST	STOTC1##	;USER, RETURNING T1 IN AC
IFN FTREAS,<
;CALLI TO SET LOGICAL NAME
;	MOVE AC,SIXBIT/DEVICE NAME/OR CHAN. NO.
;	MOVE AC+1,SIXBIT/LOGICAL NAME/
;	DEVLNM AC,
;	  ERROR RETURN	;AC=-1 IF NON-EX DEV. OR CHAN;-2 IF LOGICAL NAME IN USE
;	NORMAL RETURN
DEVLNM:	PUSHJ	P,DVCNSG	;FIND DDB FOR THIS DEVICE
	  PJRST RTM1		;CAN'T--ERROR RET. WITH AC=-1
	LDB	T2,PJOBN##
	MOVE	T1,DEVMOD(F)	;DEVICE INITED OR ASSIGNED?
	CAMN	T2,J		;MY DEVICE
	TRNN	T1,ASSCON!ASSPRG
	JRST	DEVLN3		;NO, RETURN -3
	PUSHJ	P,SAVE1##	;SAVE P1
	PUSHJ	P,GETWD1##	;GET LOGICAL NAME
	MOVE	P1,F		;SAVE DDB ADDR.
	PUSHJ	P,DEVLG		;IS ALREADY USED?
	  JRST DEVLN1		;NO--
	CAME	F,P1		;YES--SAME DEVICE?
	SOJA	M,DEVLN2	;NO--ERROR RET -2
DEVLN1:
IFN FTDISK,<
	CAIN	P1,DSKDDB##	;DON'T CHANGE PROTYPE DSK DDB
	JRST	CPOPJ1##
>
	MOVEM	T1,DEVLOG(P1)	;YES--SET LOGICAL NAME
	MOVE	F,P1		;RESTORE F FOR ASSCHK AND SETDVL
	PUSHJ	P,SETDVL	;BE SURE LOG. NAME TABLE IS OK.
	SKIPN	DEVLOG(F)	;CLEARING LOGICAL NAME?
	PUSHJ	P,ASSCK1##	;YES, SEE IF WE CAN RECLAIM SPACE
	JRST	CPOPJ1##	; AND GIVE GOOD RETURN

DEVLN3:	SKIPA	T1,[-3]
DEVLN2:	MOVNI	T1,2		;RETURN -2 IN USER AC
	PJRST	STOTAC##
>	;IFN FTREAS
IFE FTREAS,<DEVLNM==CPOPJ##>
>	;END CONDITIONAL ON FT5UUO
IFE FT5UUO,<
DEVLNM==CPOPJ##
DEVST==CPOPJ##
>
IFN FT5UUO,<

;CALLI'S TO SET AND CLEAR THE RESTRICTED
;ASSIGNMENT BIT (DEPRAS) IN DEVSTA.  LIMITED
;TO [1,2] OR JACCT SET.
;	MOVE AC,[SIXBIT /DEVICE NAME/] OR CHANEL NO.
;	DEVRST. AC,	;TO RESTRICT DEVICE
;	DEVURS. AC,	;TO UNRESTRICT DEVICE
;	ERROR RETURN	;NOT PRIVILEDGED, OR NON-EXISTANT DEVICE
;	NORMAL RETURN

DEVRST:	PUSHJ	P,PRVJ##	;SKIP IF NOT PRIVILEDGED
	  PUSHJ	P,DVCNSG	;SEARCH FOR DDB AND SKIP IF FOUND
	  POPJ	P,		;ERROR (NON-SKIP) RETURN
	MOVSI	T1,DVDSK
IFN FTSPL,<
	SKIPE	DEVCHR(F)
>
	TDNE	T1,DEVMOD(F)	;IS IT A DISK?
	POPJ	P,		;YES, DON'T RESTRICT DISKS
	MOVSI	T1,DEPRAS	;GET RESTRICTED ASSIGNMENT BIT
	IORM	T1,DEVSTA(F)	;SET BIT IN DDB
	PJRST	CPOPJ1##	;AND SKIP RETURN

DEVURS:	PUSHJ	P,PRVJ##	;SKIP IF NOTPRIVILEDGED
	  PUSHJ	P,DVCNSG	;SEARCH FOR DDB AND SKIP IF FOUND
	  POPJ	P,		;ERROR (NON-SKIP) RETURN
	MOVSI	T1,DEPRAS	;GET RESTRICTED ASSIGNMENT BIT
	ANDCAM	T1,DEVSTA(F)	;CLEAR THE BIT IN DDB
	PJRST	CPOPJ1##	;AND SKIP RETURN
>	;END FT5UUO
IFE FT5UUO,<
DEVRST==CPOPJ##
DEVURS==CPOPJ##
>
	SUBTTL	SETDDT, WAIT AND GETLIN CALLI'S ; WAIT2 AND GETPPL


SETDDT:	MOVEM	T1,JOBDDT##(R)	;SET BOTH USRDDT & JOBDDT IN JOB DATA AREA IN CASE
IFE FTVM,<
	MOVEM	T1,.CPDDT##(P4)	;LOCATION IN PROTECTED JOB DATA AREA
>
IFN FTVM,<
	MOVEM	T1,USRDDT##	; USER LOOKS AT JOBDDT BEFORE RESCHEDULING OCCURS
>
	POPJ	P,		;RETURN TO USER

IFN	FTLOGIN, <
GETPPL:	MOVE	T1,JBTPPN##(J)	; AND GET OLD NUMBERS.
	MOVE	T2,HIGHJB##	;CHECK FOR OTHER USERS UNDER SAME PP NUMBER.
PPNLUP:	CAIN	T2,(J)		;IS NEXT JOB TO BE LOOKED AT CURRENT JOB ?
	SOJLE	T2,STOTAC##	;YES, FINISHED SCANNING ALL JOBS ?
	CAMN	T1,JBTPPN##(T2)	;NO, ANOTHER USER UNDER SAME PROJ,R NUMBER ?
	JRST	STOTC1##	;YES, SKIP RETURN TO USER (LOGIN OR LOGOUT)
	SOJG	T2,PPNLUP	;NO, KEEP LOOKING
	JRST	STOTAC##	;NO OTHER JOBS, GIVE NORMAL RETURN
>
IFE	FTLOGIN,<
GETPPL==CPOPJ##>

GETLN:	PUSHJ	P,TTYFND##	;FIND USER'S TTY DATA BLOCK.
	MOVE	T1,DEVNAM(F)	;GET DEVICE NAME IN SIXBIT
	JRST	STOTAC##	;RETURN IT TO USER.
;WAIT FOR IO TO BECOME INACTIVE ON CHANNEL AC


WAIT:	JUMPE	F,CPOPJ##	;CHANNEL ASSIGNED?
;	JRST	WAIT2		;WAIT TILL INACTIVE BEFORE
				; RETURNING TO USER.
;ROUTINE TO ENSURE THAT ALL OUTPUT BUFFERS HAVE BEEN WRITTEN

WAIT2:	TRNE	S,IOCON		;DISCONTINUOUS MODE?
	PJRST	WAIT1##		;YES, JUST WAIT
WAIT2X:	PUSHJ	P,WAIT1##	;NO, WAIT TILL INACTIVE
	HLRZ	U,DEVBUF(F)	;L(BUF)
	JUMPE	U,CPOPJ##	;NONE-RETURN
	LDB	T1,PIOMOD##
	CAIGE	T1,SD		;BUF MODE?
	TLNN	F,OUTBFB+OUTPB	;YES, ANY BUFFERS?
	POPJ	P,		;NO
IFN FTMSGSER,<
	LDB	T1,PDVTYP##	;DEVICE TYPE
	CAIN	T1,.TYMPX/.TYEST;MPX?
	PJRST	MPXWAT##	;YES, WAIT MPX STYLE
>
IFN FTKA10,<
	HRLI	U,R
>
	HRRZ	T1,U
	PUSHJ	P,UADRCK	;ADDRESS CHECK THE HEADER
	TLNE	S,IO		;RETURN IF OUTPUT WASN'T LAST
	EXCTUX	<SKIPG @U>	;YES, VIRGIN RING?
	POPJ	P,		;YES, RETURN
	PUSH	P,DEVAIO(F)
	MOVEI	T1,DEPAIO!DEPOND;NON-BLOCKING BIT AND OUTPUT NOT DONE BIT
	ANDCAM	T1,DEVAIO(F)	;MAKE SURE THAT THIS WAITS UNTIL BUFFERS ARE OUT
				;FALL INTO WAIT2A
WAIT2A:	HRR	U,DEVOAD(F)
	HRRZ	T1,U
	JUMPE	T1,WAIT2B	;RETURN IF REALLY NO OUTPUTS
	PUSHJ	P,UADRCK	;ADDRESS CHECK THE BUFFER ITSELF
	EXCTUX	<SKIPL @U>	;BUFFER HAVE DATA?
	JRST	WAIT2B		;NO, DONE
IFN FTVM,<
	PUSHJ	P,BRNGE##	;MAKE SURE ENTIRE DEVOAD BUFFER IS IN CORE
>
	TRZ	S,760000	;YES, CLEAR ERROR BITS
	PUSH	P,U
	PUSH	P,M
	PUSHJ	P,CALOUT	;CRANK UP THE DEVICE
	POP	P,M
	POP	P,U
	PUSHJ	P,WAIT1##
	TRNE	S,760000	;ERRORS ENCOUNTERED?
	JRST	WAIT2B		;YES, GIVE UP
	MOVSI	T1,DEPSIE	;STOP ON ERROR BIT
	TDNE	T1,DEVJOB(F)	;IS IT ON?
	TRNN	S,IOTEND	;AND END OF TAPE?
	JRST	WAIT2A		;NO, RESTART IO IF NOT ALL BUFS DONE
WAIT2B:	HRRZ	T4,DEVSER(F)	;YES, RESTORE T4 = DISPATCH ADR
	POP	P,T1
	ANDI	T1,DEPAIO+DEPOND
	IORM	T1,DEVAIO(F)
	POPJ	P,		;AND RETURN
IFN FTLOGIN&FTACCT,<

	SUBTTL	ACCT. UUO - ACCOUNTING UUO

;UUO TO PERFORM ACCOUNTING FUNCTIONS
;CALLING SEQUENCE:
;	MOVE	AC,[FUNCTION,,ADDRESS]
;	ACCT.	AC,
;	  ERROR RETURN
;	NORMAL RETURN

ACCT:	HLRZ	U,T1		;FUNCTION
	CAILE	U,NLACCT	;DEFINED?
	JRST	ACTIAL		;NO, ILLEGAL
	HRR	M,T1		;ADDRESS OF ARGUMENT BLOCK
	PUSHJ	P,GETWRD##	;GET LENGTH OF ARGUMENT BLOCK
	  JRST	ACTADC		;ADDRES CHECK
	JRST	@ACTTBL(U)	;DISPATCH

ACTTBL:	ACTCAS
	ACTRAS
NLACCT==.-ACTTBL-1

;HERE TO CHANGE THE ACCOUNT STRING
ACTCAS:	MOVEI	T2,ACTSTL##	;LENGTH OF ACCOUNT STRING
	JUMPE	T2,CPOPJ##	;NOT IMPLEMENTED IF LENGTH EQUALS ZERO
	MOVSI	T2,JACCT	;IS HE?
	TDNN	T2,JBTSTS##(J)	;NO, ERROR
	JRST	ACTNPV		;NO, ERROR
	CAIE	T1,1		;ARGUMENT LIST MUST CONTAIN EXACTLY ONE WORD
	JRST	ACTIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,GETWR1##	;GET BYTE POINTER TO ACCOUNT STRING
	  JRST	ACTADC		;ADDRESS CHECK
	PUSHJ	P,CKSTR		;MAKE SURE THE STRING IS LEGAL AND IN CORE
	  JRST	ACTADC		;ADDRESS CHECK
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVSI	P1,MACTSL##	;MINUS THE MAXIMUM LENGTH OF AN ACCOUNTING STRING
	HRRI	P1,.PDACS##(W)	;WHERE TO STORE ACCOUNT STRING
	HRRI	M,-1(T1)	;ADDRESS OF NEW ACCOUNT STRING
ACTCA1:	PUSHJ	P,GETWD1##	;GET NEXT WORD
	MOVEM	T1,(P1)		; AND STORE IT IN THE PDB
	AOBJN	P1,ACTCA1	;LOOP OVER ENTIRE STRING
	LDB	T1,LSTBAS##	;LAST BYTE IN THE ACCOUNT STRING
	MOVEI	T2,0		;LAST BYTE MUST BE ZERO
	DPB	T2,LSTBAS##	;ZAP
	JUMPN	T1,ACTTLS	;ERROR IF LAST BYTE ISN'T ZERO
	JRST	CPOPJ1##	;GOOD RETURN
;HERE TO READ THE ACCOUNT STRING
ACTRAS:	MOVEI	T2,ACTSTL##	;LENGTH OF THE ACCOUNT STRING
	JUMPE	T2,CPOPJ##	;NOT IMPLEMENTED IF ZERO
	CAIE	T1,2		;ARGUMENT LIST MUST BE EXACTLY TWO WORDS LONG
	JRST	ACTIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,GETWR1##	;GET JOB NUMBER
	  JRST	ACTADC		;ADDRESS CHECK
	CAME	T1,[-1]		;MINUS ONE MEANS CURRENT JOB
	MOVE	J,T1		;TARGET JOB NUMBER
	PUSHJ	P,FNDPDB##	;FIND JOB'S PDB
	  JRST	ACTNSJ		;NO SUCH JOB
	PUSHJ	P,GETWR1##	;GET ADDRESS WHERE A.S. SHOULD BE STORED
	  JRST	ACTADC		;ADDRESS CHECK
	HRRI	M,ACTSTL##(T1)	;LAST ADDRESS WHERE A.S. TO BE STORED
	PUSHJ	P,GETWRD##	;CHECK LEGALITY
	  JRST	ACTADC		;BAD ADDRESS
	HRRI	M,MACTSL##-1(M)	;SET TO STORE ACCOUNT STRING
	MOVSI	T2,MACTSL##	;NEGATIVE LENGTH
	HRRI	T2,.PDACS##(W)	;ADDRESS OF THE ACCOUNT STRING
ACTRA1:	MOVE	T1,(T2)		;WORD FROM ACCOUNT STRING
	PUSHJ	P,PUTWD1##	;STORE IT FOR THE PROGRAM
	AOBJN	T2,ACTRA1	;LOOP OVER THE ENTIRE ACCOUNT STRING
	JRST	CPOPJ1##	;GOOD RETURN

;ACCT. ERROR CODES
ERCODE	ACTTLS,1		;STRING TO LONG
ERCODE	ACTADC,2		;ADDRESS CHECK
ERCODE	ACTIAL,3		;ILLEGAL ARGUMENT LIST
ERCODE	ACTNSJ,4		;NO SUCH JOB
ERCODE	ACTNPV,5		;NOT PRIVILEGED
>
	SUBTTL	LOGIN, LOGOUT AND ATTACH UUO'S

;LOGIN UUO USED ONLY BY LOGIN AND LOGOUT CUSPS
;CALL:	CALL AC,[SIXBIT /LOGIN/]
;WHERE AC CONTAINS XWD -NO. OF ENTRIES,LOCATION
;WHICH IS A LIST OF JOB STATISTICS TO BE STORED IN MONITOR
;RETURNS TO UUO +1 IF SUCCESSFUL AND THAT LOC DOES NOT CONTAIN A HALT


IFN FTLOGIN,<

LOGIN:	MOVSI	T2,JLOG		;IS USER ALREADY LOGGED IN?
	TDNE	T2,JBTSTS##(J)
	POPJ	P,		;YES, NO-OP
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	HLRE	P1,T1		;NO, -NO. OF WORDS
	HRR	M,T1		;FIRST REL. LOC.
	MOVE	P2,[XWD -LOGTOP,LOGTAB]	;SET FOR LOOP
LOGIN1:	MOVEI	T1,0		;ASSUME 0
	AOSG	P1		;FINISHED HIS COUNT?
	PUSHJ	P,GTWST2##	;NO, GET NEXT WORD FROM USER AREA
	MOVEM	T1,@(P2)	;STORE WORD OR 0
	ADDI	M,1		;GET NEXT ITEM
	AOBJN	P2,LOGIN1	;FINISHED NO. OF MONITOR TABLES?
	PUSHJ	P,SETLOG##	;SET JLOG, INCREMEN LOGNUM, BATNUM
IFN FTGALAXY,<
	PUSHJ	P,QSRLGI##
>	;END IFN FTGALAXY

	MOVSI	T2,JACCT	;RESET THIS BIT TO INDICATE LOG-IN IS
	HRRI	T2,JS.XO	; AND CLEAR EXECUTE ONLY
	ANDCAM	T2,JBTSTS##(J)	; NOW COMPLETE AND ^C IS AGAIN PERMITTED.
	HRRZ	M,JOBPD1##(R)	;LOCATION OF UUO IN USER AREA
	PUSHJ	P,GETWDU##	;GET NEXT INSTR FROM USER AREA
	LSH	T1,-30		;LOOK AT TOP 12 BITS
	CAIE	T1,<HALT>B<35+24> ;HALT?
	POPJ	P,0		;NO. RETURN TO USER.
LOGIN2:	PUSHJ	P,IORELS	;RELEASE ALL DEVICES
	PUSHJ	P,TTYFUW##	;FIND TTY AND PRINT ^C
	JRST	HOLD##
;STILL IN FTLOGIN CONDITIONAL
;TABLE OF POINTERS TO TABLES(STORED WITH JOB NUMBER AS INDEX)
;TO MAKE LOGIN SET MORE TABLES IN MONITOR, JUST ADD TABLE NAMES AT END


LOGTAB:	XWD	J,JBTPPN##	;PROJECT-PROGRAMMER NUMBER
IFN FTPRV,<
	XWD	J,JBTPRV##	;JOB PRIVILEGE BITS
>
IFE FTPRV,<
IFN FTUNAME!FTCNO,<
;KEEP THESE IF ANY ENTRIES FOLLOW
	EXP	S		;STORE IN AC S, SINCE PRIVILEGE TABLE DOES NOT EXIST
>>


IFN FTUNAME,<
	XWD	W,.PDNM1##	;1ST HALF OF USER'S NAME
	XWD	W,.PDNM2##	;2ND HALF OF USER'S NAME
>
IFE FTUNAME,<
IFN FTCNO,<
;KEEP THESE IF ANY ENTRIES FOLLOW
	EXP	S
	EXP	S
>>
IFN FTCNO,<
	XWD	W,.PDCNO##	;CHARGE NUMBER THIS JOB
>
IFE FTCNO,<
REPEAT 0,<
;KEEP THESE IF ANY ENTRIES FOLLOW
	EXP	S
>>
LOGTOP==.-LOGTAB	;NO. OF TABLES TO BE SET
>	;END CONDITIONAL ON FTLOGIN
;LOGOUT UUO



LOGOUT:	PUSHJ	P,TTYFNU##
IFN FTLOGIN,<
	MOVE	T1,JBTSTS##(J)	;JOB STATUS
	TLNN	T1,JLOG		;LOGGED IN?
	JRST	JOBKL##		;NO
	TLNN	T1,JACCT	;ONLY A REAL, LIVE
				;JACCTED LOGOUT
	JRST	EXIT		;IS ALLOWED TO DO THIS
	MOVE	T1,JBTPRG##(J)	;FOR EVERYBODY WLSE,
	CAME	T1,[SIXBIT .LOGOUT.]  ;TREAT JUST LIKE EXIT
	JRST	EXIT
>
	JRST	JOBKL##

IFE FTLOGIN,<

LOGIN=CPOPJ##	;CANT DO A LOGIN UUO
>
;ATTACH UUO - PRIVILEGED, FOR DAEMON, ATTACH COMMAND.
IFE FTATTACH,<UATTAC==CPOPJ##>
IFN FTATTACH,<
UATTAC:	PUSHJ	P,SAVE1##	;SAVE P1
	HLLZ	P1,T1		;P1=FLAGS
	PUSH	P,T1		;SAVE ARG XWD LINE, JOB
IFN FTLOGIN,<	PUSHJ	P,PRVJ##	;IS THIS A PRIVILEGED JOB?
	 SKIPA T1,0(P)		;YES. RESTORE ARGUMENT.
	JRST	UATAC5		;NO. GO
>
	TRNE	T1,400000	;NEGATIVE JOB ARGUMENT?
	JRST	UATC1A		;YES, MIGHT BE LINE CHANGE
	TRNE	T1,-1		;ZERO ARGUMENT?
	JRST	UATAC1		;NO. WANTS ATTACH.
	HLRZ	T1,0(P)		;YES. WANTS DETACH DONE
	TRZ	T1,600000	;CLEAR FLAGS
	CAIE	T1,177777	;DETATCH SELF?
	JRST	UATAC2		;NO.
	PUSHJ	P,TTYSRC##	;FIND DDB VIA J
	 JRST TPOPJ##		;SHOULDN'T FAIL, NO DDB THIS JOB?
UATAC3:	PUSHJ	P,TTYDET##	;DETACH VIA F
	SKIPE	LDBBKC##(U)	;ANY BREAK CHARACTERS INPUT?
	PUSHJ	P,COMSET##	;YES, ASSUME COMMAND TYPED
	JRST	TPOPJ1##	;GIVE USER OK RETURN
UATAC2:	CAIL	T1,TTPLEN##	;LEGAL LINE NUMBER?
	JRST	TPOPJ##		;NO. GIVE FAIL RETURN.
	HRRZ	U, LINTAB##(T1)	;YES. GET THE LDB ADDRESS
	HRRZ	F,LDBDDB##(U)	;GET LINKED DDB, IF ANY
	JUMPE	F,TPOPJ1##	;ALREADY DETACHED. GIVE OK RETURN
	JRST	UATAC3		;GO DETACH JOB.
UATAC1:	HRRZS	T1		;JOB NUMBER OF JOB BEING ATTACHED TO
	PUSHJ	P,LGLPRC##	;IS IT A LEGAL JOB NUMBER?
	JRST	TPOPJ##		;NO, FAIL RETURN
	SKIPA	T1,(P)		;YES, RESTORE JOB NUMBER
UATC1A:	HRR	T1,J		;NEGATIVE JOB ARGUMENT MEANS SELF
	HRRZ	F,TTYTAB##(T1)	;DDB OF JOB DESIRED
	JUMPE	F,TPOPJ##	;IF NONE, FAIL RETURN
	MOVSI	U,600000	;FLAG BITS TO CLEAR
	ANDCAM	U,0(P)		;ZAP!
	HLRZ	U,0(P)		;GET LINE NUMBER REQUESTED
	CAIL	U,TTPLEN##	;IS IT LEGAL?
	JRST	TPOPJ##		;NO. FAIL RETURN.
	PUSHJ	P,PTYDET##	;DETACH VIA F
	HLRZ	U,0(P)		;GET LINE NUMBER
	HRRZ	U,LINTAB##(U)	;GET LDB ADDRESS
	LDB	J,PJOBN##	;GET JOB NUMBER
	MOVE	T1,(P)		;RESTORE ARGUMENT
	TRNN	T1,400000	;JOB ATTACH ?
	JRST	UATC1B		;YES
	HRRM	J,(P)		;NO. USE J.
UATC1B:	PUSHJ	P,TTYATT##	;DO THE ATTACH.
	 JRST TPOPJ##		;FAIL RETURN (SHOULDN'T HAPPEN)
	JUMPGE	P1,UATAC4	;JUMP IF SET TO MONITOR LEVEL FLAG NOT SET
	PUSHJ	P,CNCMOD##	;SET TO MONITOR LEVEL
	JRST	TPOPJ1##
UATAC4:	MOVSI	T1,LDLCOM##
	TLNE	P1,200000	;SKIP IF TO SET USER LEVEL
	ANDCAM	T1,LDBDCH##(U)	;CLEAR MONITOR LEVEL BIT
	TDNE	T1,LDBDCH##(U)	;SKIP IF AT USER LEVEL
	JRST	TPOPJ1##	;NO, OK RETURN NOW
	LDB	T1,PJBSTS##
	CAIE	T1,TIOWQ##
	JRST	TPOPJ1##
	MOVE	T1,DEVIOS(F)
	TLNE	T1,IOW
	PUSHJ	P,TTWAKE##
	JRST	TPOPJ1##	;OK RETURN.
IFN FTLOGIN,<

UATAC5:	MOVE	T1,(P)		;DET STILL ALOWED (SOMETIMES)
	TRNE	T1,-1		;DOES HE WANT A DET?
	PJRST	TPOPJ##		;NO, RETURN
	PUSHJ	P,TTYSRC##	;YES, SET UP 4
	  PJRST	TPOPJ##		;SHOULD NEVER FAIL
	HLRZ	T1,(P)		;GET TTY NUMBER HE WANTED DET'D
	CAIN	T1,-1		;IS IT -1? (DEFAULT FOR SELF)
	JRST	UATAC6		;YES, CHECK USER MODE
	TRZ	T1,600000	;GET RID OF FLAGS
	LDB	P1,LDPLNO##	;GET REAL TTY NUMBER
	CAME	T1,P1		;SAME?
	PJRST	TPOPJ##		;NO, RETURN
UATAC6:	MOVSI	T1,LDLCOM##	;MONITOR COMMAND LEVEL BIT
	MOVSI	P1,(JB.LBT)	;GET BATCH BIT
	TDNN	P1,JBTLIM(J)	;IS THIS A BATCH JOB?
	TDNE	T1,LDBDCH##(U)	;IS HIS TTY AT USER LEVEL?
	PJRST	TPOPJ##		;NO, RETURN
	JRST	UATAC3		;YES, NOW DET HIM.

>	;END FTLOGIN CONDITIONAL

>	;END FTATTACH CONDITIONAL
	SUBTTL	GETTAB UUO
;UUO TO RETURN CONTENTS OF A MONITOR JOB TABLE ENTRY
;CALL:	HRROI AC, MONITOR JOB TABLE NUMBER (NEG. TABLES FOR CUSTOMER)
;	HRLI AC, JOB NUMBER (OPTIONAL) LH .EQ. -1 MEANS CURRENT JOB
;	LH .EQ. -2 MEANS JOB'S HIGH-SEGMENT
;	CALL AC, [SIXBIT /GETTAB/] OR CALLI AC,41
;	ERROR RETURN AC PRESERVED IF LH OR RH TOO BIG OR
				; AC=-1 IF NOT PRIVILIGED TO GET INFO
;	NORMAL RETURN - AC=0 IF TABLE IS UNDEFINED
IFN FTGETTAB,<
GETTAB:	HLRZ	T2,T1		;GET USER SUPPLIED JOB NUMBER
	HRRE	T3,T1		;GET TABLE NUMBER IN T3
	CAIGE	T3,GTTBLN	;IS TABLE NUMBER LEGAL?
	CAMGE	T3,MINTBB	; (NEGATIVE NUMBERS LEGAL FOR CUSTOMER'S TABLES)
	POPJ	P,		;NO. ERROR RETURN, AC UNCHANGED
	CAIN	T3,GTSELF	;IS THIS A GETTAB IMMEDIATELY?
	JRST	GETIMT		;YES--GO HANDLE SPECIALLY
	CAIGE	T2,-2		;DID HE SUPPLY ONE?
	MOVE	J,T2		;YES, USE IT
IFN FT2REL,<IFN FT5UUO,<
	SKIPE	TWOREG##	;SEE IF HIGH-SEGS
	CAIE	T2,-2		;YES--SEE IF REQUESTING HI-SEG
	JRST	GETTB1		;NO--SKIP AHEAD
	SKIPG	J,JBTSGN##(J)	;YES--SEE IF HE HAS A HI-SEG
	POPJ	P,		;ERROR IF NO HI-SEG
	TLZ	J,-1
GETTB1:>>
;AT THIS POINT T3=TABLE NUMBER AND J=INDEX
	LDB	T1,[POINT 3,NUMTAB(T3),11] ;GET CODE
	JUMPE	T1,CPOPJ##	;JUMP IF UNDEFINED
	MOVEI	T2,0		;ASSUME 0 MAX
	CAIE	T1,GT.JOB	;JOB TABLE?
	CAIN	T1,GT.PDB	; OR PDB POINTER?
	MOVEI	T2,JOBMAX##	;YES--SETUP MAXIMUM
	CAIN	T1,GT.SEG	;JOBN+SEGN LONG?
	MOVEI	T2,JBTMAX##	;YES--SETUP MAXIMUM
	CAIN	T1,GT.ITM	;SPECIAL TABLE
	LDB	T2,[POINT 9,NUMTAB(T3),8] ;GET MAXIMUM
	JUMPE	T2,RTZER1	;IF T2=0 NUMTAB IS WRONG
	CAMLE	J,T2		;SKIP IF VALID INDEX
	POPJ	P,0		;INDEX IS TOO BIG
	CAIE	T1,GT.PDB	;IS DATA IN PDB?
	JRST	GETTBX		;NO--GET FROM TABLE
	MOVE	T2,J		;COPY INDEX INTO RIGHT AC
	HRRZ	T3,NUMTAB(T3)	;INDEX INTO PDB
	PUSHJ	P,PDBWRD##	;GET WORD FROM PDB
	JRST	STOTC1##	;STORE AS ANSWER
GETTBX:	MOVE	T1,@NUMTAB(T3)	;GET WORD
	JRST	STOTC1##	;SKIP RETURN T1 IN HIS AC
GETIMT:	HRRE	J,T2		;GET TABLE NUMBER INDEX
	JUMPGE	J,GETTB1	;NON-NEGATIVE, DO NORMALLY
	CAMGE	J,MINTBB	;IS IT IN RANGE?
	POPJ	P,		;NO--GIVE ERROR RETURN
	JRST	GETTBX		;YES--RETURN VALUE
;THE MONITOR JOB TABLE NUMBERS:
	$LOW			;MUST BE IN LOW SEG FOR GETTAB IMMEDIATE

;MACRO TO DEFINE A GETTAB TABLE
;THIS MACRO HAS 3 ARGUMENTS:
; FT    - FEATURE TESTS FOR WHICH TABLE EXISTS
; TYPE  - ONE OF:
;	  "J" - JOB TABLE
;	  "S"- JOB TABLE WITH JOBN + SEGN ENTRIES
;	  "I" - RANDOM TABLE
;	  "P" - DATA IN PDB
; TBL   - ADDRESS OF TABLE (OR INDEX INTO PDB)
; MAX   - MAXIMUM FOR RANDOM TABLES SHIFTED LEFT 9 BITS
;

DEFINE	GT(FT,TYPE,TBL,MAX),<
IFIDN <TYPE>,<J>,<
IFE FT,< JOBMXL##+<GT.JOB>B29,,ZERO>
IFN FT,< JOBMXL##+<GT.JOB>B29+J,,TBL>
>
IFIDN <TYPE>,<S>,<
IFE FT,< JBTMXL##+<GT.SEG>B29,,ZERO>
IFN FT,< JBTMXL##+<GT.SEG>B29+J,,TBL>
>
IFIDN <TYPE>,<P>,<
IFE FT,< JOBMXL##+<GT.JOB>B29,,ZERO>
IFN FT,< JOBMXL##+<GT.PDB>B29+W,,TBL>
>
IFIDN <TYPE>,<I>,<
IFE FT,< ZERO>
IFN FT,< MAX+<GT.ITM>B29+J,,TBL>
>
>
	SALL
GTBSTT:				;CUSTOMER TABLES GO HERE
NUMTAB::GT	1,S,JBTSTS##		;(000) JOB STATUS TABLE
MINTAB==GTBSTT-NUMTAB
	GT	1,S,JBTADR##		;(001) SIZE,,ADDRESS
	GT	FTLOGIN,S,JBTPPN##	;(002) PPN
	GT	1,S,JBTPRG##		;(003) PROGRAM NAME
	GT	FTTIME,P,.PDTTM##	;(004) RUNTIME IN JIFFIES
	GT	FTKCT,P,.PDKCT##	;(005) KCT COUNT
	GT	FTPRV,J,JBTPRV##	;(006) PRIVILEGE BITS
	GT	FTSWAP,S,JBTSWP##	;(007) LOCATION ON DISK
	GT	1,J,TTYTAB##		;(010) TTY DDB POINTERS
	GT	1,I,CNFTBL##,CNFMXL##	;(011) CONFIGURATION DATA
	GT	1,I,NSWTBL##,NSWMXL##	;(012) NON-SWAPPING DATA
	GT	FTSWAP,I,SWPTBL##,SWPMXL## ;(013) SWAPPING DATA
	GT	FT2REL,J,JBTSGN##	;(014) HIGH SEG #
	GT	FTDISK,I,ODPTBL##,ODPMXL## ;(015) ONCE ONLY DISK PARAMETERS
	GT	FTDISK,I,LVDTBL##,LVDMXL## ;(016) LEVEL-D TABLE
	GT	FTDSTT,J,JBTRCT##	;(017) DISK READS
	GT	FTDSTT,J,JBTWCT##	;(020) DISK WRITES
	EXP	ZERO			;(021) UNUSED
	EXP	ZERO			;(022) UNUSED
GTSELF==.-NUMTAB			;TABLE # OF NUMTAB
	GT	1,I,NUMTAB,<<GTTBLN-1>B26> ;(023) THIS TABLE
	GT	FT2REL,S,JBTDEV##	;(024) DEVICE OR FSN
	GT	1,I,STSTBL##,STSMXL##	;(025) STATE CODES
	GT	FTNET,J,JBTLOC##	;(026) JOB LOCATION
	GT	1,I,CORTAB##,CTBMXL##	;(027) KA10 CORE TABLE
	GT	1,I,COMTAB##,COMMXL##	;(030) MONITOR COMMANDS*
	GT	FTUNAM,P,.PDNM1##	;(031) USER NAME (0FIRST)
	GT	FTUNAM,P,.PDNM2##	;(032) USER NAME (0LAST)
	GT	FTCNO,P,.PDCNO##	;(033) CHARGE NUMBER
	GT	FTTMP,I,JBTTMP##,ITMTMP## ;(034) TMPCOR POINTERS
	GT	FTWATC,J,JBTWCH##	;(035) WATCH BITS
	GT	FTSPL,J,JBTSPL##	;(036) SPOOL TABLE
	GT	FTRTTR!FTHPQ!FTHIBW,I,JBTRTD##,ITMRTD## ;(037) REAL TIME
	GT	FTTLIM,J,JBTLIM##	;(040) CORE AND TIME LIMITS
	GT	FTSWAP,I,QQQTAB##,QQQMXL## ;(041) QUEUE HEADERS
	GT	FTSWAP,J,JBTQ##		;(042) JOBS IN QUEUES
	GT	FTSET,I,COMTB2##,COMMX2## ;(043) SET COMMANDS
	GT	1,I,APRSTS##,LENSTS##	;(044) CRASH TABLE
	GT	FTSWAP,I,ISCAN##,ISTMXL## ;(045) SWAP-IN LIST
	GT	FTSWAP,I,OSCAN##,OSTMXL## ;(046) SWAP-OUT LIST
	GT	FTSWAP,I,SSCAN##,SSTMXL## ;(047) SCHEDULER LIST
	GT	FTRSP,J,JBTRSP##	;(050) TIME USER BEGAN TO WAIT
	GT	1,I,SYSTBL##,SYSMXL## 	;(051) SYSTEM WIDE DATA
	GT	FTWHY,I,CRSHAC##,17000	;(052) WHY RELOAD COMMENT
	GT	FTRSP,J,JBTRQT##	;(053) TIME IN RUN QUEUES
	GT	FTMS,I,JBTSPS##,ITMSPS##  ;(054) SECOND CPU STATUS
;CONTINUED ON NEXT PAGE
	GT	1,I,.C0CDB##,ITMC0C##	;(055) CPU0 CDB CONSTANTS
	GT	1,I,.C0VBG##,ITMC0V##	;(056) CPU0 CDB VARIABLES
	GT	1,I,.C1CDB##,ITMC1C##	;(057)
	GT	1,I,.C1VBG##,ITMC1V##	;(060)
	GT	1,I,.C2CDB##,ITMC2C##	;(061)
	GT	1,I,.C2VBG##,ITMC2V##	;(062)
	GT	1,I,.C3CDB##,ITMC3C##	;(063)
	GT	1,I,.C3VBG##,ITMC3V##	;(064)
	GT	1,I,.C4CDB##,ITMC4C##	;(065)
	GT	1,I,.C4VBG##,ITMC4V##	;(066)
	GT	1,I,.C5CDB##,ITMC5C##	;(067)
	GT	1,I,.C5VBG##,ITMC5V##	;(070)
	GT	1,I,FETTBL,FETMXL	;(071) FEATURE TABLE
	GT	FTDISK,I,SDVTBL##,SDVMXL## ;(072) ERSATZ DEVICE NAMES
	GT	FTRSP,I,.GTSCN##,SCNMXL## ;(073) SCNSER DATA
	GT	FTTALK,I,SNDTMP##,SNDMXL## ;(074) LAST SEND ALL
	GT	1,I,TTCWDT##,TTCMXL##	;(075) SET TTY NAMES*
	GT	FTIPCF,I,PIDTAB##,MIDMXL##	;(076) PROCESS ID TABLE
	GT	FTIPCF,I,IPCTAB##,IPCMXL## ;(077) IPCF MISC. DATA
IFN FTKA10,<
	EXP	ZERO			;(100)NOT IN KA10
>
IFN FTKL10!FTKI10,<
	GT	1,S,JBTUPM##		;(100)POINTER TO USER PAGE MAP
>
	GT	FTWATCH,I,WATTAB##,WTCMXL## ;(101) WATCH COMMANDS*
	GT	FTVM,P,.PDCVL##		;(102) CURRENT VM LIMITS
	GT	FTVM,P,.PDMVL##		;(103) MAX VM LIMITS
	GT	FTIPCF,P,.PDIPA##	;(104) IPCF STATISTICS
	GT	FTIPCF,P,.PDIPC##	;(105) IPCF POINTERS
	GT	FTIPCF,P,.PDIPI##	;(106) THIS JOB'S [SYSTEM]INFO
	GT	FTIPCF,P,.PDIPQ##	;(107) FLAGS AND QUOTAS
	GT	FTHSLN,P,.PDDVL##	;(110) POINTER TO DEVICE LOG NAME TABLE
	GT	FTKI10!FTKL10,P,.PDABS##  ;(111) ADDRESS BREAK SETTING
	EXP	ZERO			;(112) RESERVED
	GT	FTVM,I,.GTVM##,GTVMXL##	;(113) VM DATA
	GT	FTVM,J,JBTVRT##		;(114) PAGING RATES
	GT	1,I,.GTSST##,SSDMXL##	;(115) SCHEDULER STATISTICS
	GT	FTNSCH,I,.GTDCF##,DCFMXL## ;(116) DESIRED CHAN USE FRACTION
	GT	1,J,JBTST2##		;(117)SECOND JOB STATUS WORD
	GT	FTNSCH,J,JBTSCD##	;(120) TYPES AND CLASS WORD
	GT	FTNSCH,I,CLSSTS##,CLSMXL## ;(121) QUOTAS BY CLASS
	GT	FTNSCH,I,CLSQTA##,CLSMXL## ;(122) QUOTAS BY CLASS IN JIFFIES
	GT	FTNSCH,I,CLSRTM##,CLSMXL## ;(123) RUNTIME BY CLASS SINCE STARTUP
	GT	FTNSCH,I,SQQTAB##,CLSMXL## ;(124) SUBQUEUE HEADERS
	GT	FTNSCH,J,JBTSQ##	;(125) SUB QUEUE WORD FOR JOB 
;CONTINUED ON NEXT PAGE
	GT	FTIPCF,I,.GTSID##,SIDMXL## ;(126) SPECIAL PIDS
	GT	FTEQDQ,I,.EQTAB##,ENQMXL## ;(127) ENQ/DEQ STATISTICS
	GT	1,J,JBTJLT##		;(130) JOB LOGIN TIME
	GT	FTKL10&FTEMRT,P,.PDEBT##  ;(131) # JIFFIES OF EBOX TIME FOR JOB
	GT	FTKL10&FTEMRT,P,.PDEB2##  ;(132) REMAINDER MOD RTUPS OF JIFFIES OF EBOX TIME FOR JOB
	GT	FTKL10&FTEMRT,P,.PDMBT##  ;(133) # JIFFIES SPENT DOING MEMORY REFERENCES FOR JOB
	GT	FTKL10&FTEMRT,P,.PDMB2##  ;(134) REMAINDER MOD RTUPS OF A MBOX JIFFIES FOR JOB
	GT	FTFDAE,P,.PDSTR##	;(135) DEVICE PROGRAM WAS RUN FROM
	GT	FTFDAE,P,.PDDIR##	;(136) DIRECTORY PROGRAM WAS RUN FROM
	GT	FTFDAE,P,.PDNAM##	;(137) PROGRAM NAME
	GT	FTSET,P,.PDDFL##	;(140) USER'S DEFAULTS
	GT	FTNET&FTCMSR,I,NETGTT##,.NTMXL## ;(141) NETSER PERFORMANCE MEASUREMENTS
	GT	FTPSCD,I,SCDPER##,%PERLN## ;(142) PERFORMANCE TABLE
	GT	FTVM&FTACCT&FTKCT,P,.PDVKC## ;(143)JOB'S VIRTUAL KCT
	GT	FTACCT,P,.PDUUC##	;(144)JOB'S UUO COUNT

;INSERT NEW TABLES ABOVE HERE
GTTBLN=.-NUMTAB			;LENGTH OF TABLE
IFN FTPATT,<
	Z			;FOR PATCHING
	Z
>
ZERO:	0			;IN LOWSEG FOR SPY'ERS
	$HIGH			;BACK TO THE HIGH SEGMENT
>	;END FTGETTAB CONDITIONAL

IFE FTGETTAB,<GETTAB=CPOPJ##>
MINTBB:	MINTAB
	DEFINE	FTBITS(FET),<
	.X==0
	.Y==0
	.Z==0
IRP FET<
IFGE .Y-21,<PRINTX ? FET CANT BE INSERTED>
IFN	FT'FET,<.X==.X!1_.Y>
	.Z==.Z!1_.Y
	F.'FET==1_.Y
	.Y==.Y+1>
	XWD .Z,.X>
	FT1==-1			;FORCE ON (NAME=1)
	FT0==0			;FORCE OFF (NAME=0)
;TABLE OF BITS FOR MONITOR FEATURES
;ALWAYS ADD NEW FEATURES AT END OF LIST
;AND ATTEMPT TO INCLUDE IN MOST APPROPRIATE LIST
	$LOW
FETTBL:
;(0) LIST OF MONITOR NON-I/O FEATURES WHICH DIRECTLY IMPACT CUSPS
	FTBITS<2REL,GETTAB,DAEMON,PRV,SPL,JCON,POKE,PEEK,PTYUUO,CCIN,IPCF,PI,GALAXY,EQDQ,MIC,MLOG,MDA>
;(1) REAL-TIME AND SCHEDULING FEATURES
	FTBITS<HPQ,HIBWAK,SLEEP,RTTRAP,TRPSET,LOCK,RTC,SHFL,SWAP,VM,NSCHED,PSCD,CMSR>
;(2) COMMAND FEATURES
	FTBITS<ATTACH,TALK,EXAM,REAS,FINI,WATCH,SEDA,BCOM,VERS,SET,QCOM,CCLX,CCL,MONL,MOFF,EXE,PJOB>
;(3) ACCOUNTING FEATURES
	FTBITS<TIME,KCT,UNAME,CNO,TLIM,FDAE,EMRT,ACCT>
;(4) NON I/O FEATURES NOT RELATED TO DEBUGGING
	FTBITS<MEMP,MS,EL,2SWP,BOOT,KII,1,METR,KI10,PDBS,22BI,KA10,KL10,MEMN>
;(5) NON I/O DEBUGGING FEATURES
	FTBITS<CHECK,MONP,RCHK,HALT,TRAC,PATT,WHY,RSP,2SEG>
;(6) DISK UUO FEATURES (THIS WORD IS FULL)
	FTBITS<MOUN,SFD,PHYO,5UUO,STR,DQTA,DSUP,DSEK,DRDR,GSRC,AIR,APLB,DPRI,LIB,NUL,DSIM,DHIA>
;(7) DISK "INVISIBLE" FEATURES (THIS WORD IS FULL)
	FTBITS<DOPT,DBAD,DHNG,DSTT,DALC,DSMC,DMRB,DETS,DUFC,DBBK,SWPE,FFRE,DISK,LOGIN,CBDB,2ATB,SLCK>
;(10) SCANNER, RP04 FEATURES
	FTBITS<HDPX,GPO2,630H,MODM,SCNR,SCLC,DIAL,TPAG,TBLK,CAFE,2741,TYPE,TVP,D10H,RDX,RP04>
;(11) OTHER PERIPHERALS (THIS WORD IS FULL)
	FTBITS<TMP,MTSE,CDRS,OPRE,LPTR,NET,CTY1,CRTR,CPTR,HSLN,MSGS,XTC,DAS7,TSK,TLAB,TAPOP,RDBA>
;(12) OTHER PERIPERALS (SECOND WORD)
	FTBITS<DX10>
;(13) DISK "INVISIBLE" FEATURES (SECOND WORD)
	FTBITS<DUAL>
;(14) DISK UUO FEATURES (SECOND WORD)
	FTBITS<PSTR>
	FETMXL=<.-FETTBL-1>B26
	$HIGH
	SUBTTL	SETNAM & CNGPPN UUO'S

;UUO TO SET CURRENT PROGRAM NAME
;	MOVE AC,[SIXBIT /NAME/]
;	ALWAYS RETURN


SETNAM:	MOVEM	T1,JBTPRG##(J)	;STORE PROGRAM NAME FOR SYSTAT AND SYSDPY
IFN FTTLIM, <	MOVSI	T2,(JB.LSY)	;CLEAR "GOT FROM SYS:" FLAG
	ANDCAM	T2,JBTLIM##(J)	;  INDICATES LOADER IS DONE
>
	MOVSI	T2,JACCT	;ALWAYS CLEAR JACCT
	ANDCAM	T2,JBTSTS##(J)
	MOVEI	T2,JS.RUU!JS.XO!JS.XOR ;CLEAR EXECUTE ONLY SO CAN SAVE
IFN FTKI10!FTKL10,<
	MOVE	T3,JBTSGN##(J)	;HI SEG CHARACTERISTICS FOR THIS JOB
	MOVE	T4,JOBPD1##(R)	;UUO PC
	TLNE	T3,GTSSEG	;HE SEG CONCEALED?
	TLNN	T4,(IC.LIP)	;UUO DONE FROM A PUBLIC PAGE?
>
	ANDCAM	T2,JBTSTS##(J)	; A PROGRAM LOADED BY XO LOADER
				; ALWAYS CLEAR JACCT WITH JS.XO
IFN FTVM,<
	MOVSI	T2,(UP.GET)	;CLEAR GET IN PROGRESS FLAG
	ANDCAM	T2,.UPMP+.UPBTS
>
IFN FTKI10!FTKL10,<
	PUSHJ	P,MAPHGH##	;REDO THE MAP IN CASE CONCEALED
	MOVE	T1,JBTPRG##(J)	;RESTORE NAME
>
IFN FTWATCH&FTVERSION,<
	JUMPE	T1,CPOPJ##	;IF TO 0, DONT TYPE OUT
	PUSHJ	P,VERWAT##	;SEE IF WATCHING (IF SO, ONLY ON CPU0)
	  POPJ	P,		;NO--JUST RETURN
	PUSHJ	P,INLMES##	;TYPE:
	ASCIZ	/:/
	PUSHJ	P,VERBTH##	;TYPE NAME AND VERSION
	PJRST	PRRBKC##	;TYPE RIGHT BRACKET <CRLF>
>
IFE FTWATCH&FTVERSION,<
	POPJ	P,
>

;UUO TO CHANGE PROJECT, PROGRAMMER NUMBER, FOR LOGIN ONLY
;	MOVE AC,NEW PPN
;	CALLI AC,CHGPPN
;	NOT IMPLEMENTED
;	OK


IFN FTLOGIN,<
CHGPPN:	MOVSI	T2,JLOG		;LOGGED IN BIT
	TDNE	T2,JBTSTS##(J)	;SKIP IF JOB NOT LOGGED IN
	POPJ	P,		;NO GOOD IF IT IS
	MOVEM	T1,JBTPPN##(J)	;OK, CHANGE PPN
	JRST	CPOPJ1##	;AND GIVE OK RETURN
>	;END CONDITIONAL ON FTLOGIN
IFE FTLOGIN,<CHGPPN==CPOPJ##>

	SUBTTL	DEVNAM UUO


IFN FT5UUO,<
;DEVNAM UUO (CALLI 64)
;OPERATES IN TWO MODES:
;MODE 1:C(AC) HAVE AN INIT'ED CHANNEL NUMBER
;DEVNAM RETURNS SIXBIT DEVICE NAME IN DEVNAM IN AC
;MODE 2: C(AC) ASSUMED TO HAVE SIXBIT LOGICAL DEVICE NAME
;IF ARE GREATER THAN 17.  PHYSICAL NAME RETURNED IN AC.


UDEVNM:	PUSHJ	P,DVCNSG	;SEARCH FOR CHANNEL OR DEVICE
	  JRST RTZER		;NONE--RETURN ERROR AS 0
IFN FTDISK,<
	TLZ	F,-1
	CAIE	F,DSKDDB##	;T1 IS MORE SPECIFIC THAN 'DSK'
>
	MOVE	T1,DEVNAM(F)	;GET PHYSICAL NAME
	JRST	STOTC1##	;PUT IN AC AND RETURN

>	;END CONDITIONAL ON FT5UUO
IFE FT5UUO,<
UDEVNM==CPOPJ##
>
	SUBTTL	REAL-TIME AND HIBWAKE FEATURE

;UUO TO SET JOB TO USE IO IN USER MODE
;AND TO SET PI INTERRUPT LOCATION IN LOWER CORE(WORKS ONLY ON P-10'S -SEE NEXT PAGE)
;CALL:	CALL AC,[SIXBIT /TRPSET/]
;	ERROR RETURN, USER NOT ALLOWED TO DO IO IN USER MODE
;	OK RETURN

;WHERE RH(AC)=REL ADR. OF 1 INSTRUCTION TO BE MOVED INTO
;THE MONITOR PI TRAP LOCATION(40-57) AS SPECIFIED BY LH(AC)
;RELOCATION OF JOB IS ADDED TO RH OF INSTRUCTION AS IT IS MOVED.
;ALSO THE RELOCATION IS ADDED TO THE RH OF WORD IN USER AREA SPECIFIED BY
;RH OF USER INSTRUCTION IN CASE IT IS A BLKO/BLKI POINTER
;THE USER MUST RESET EVERY TRPSET CALL IF BLKI/BLKO POINTER 
;AND SHOULD SET RH TO 0 IF JSR PC WORD
;THE APR IS ALSO SET SO USER MAY DO IO IN USER MODE
;TO SET USER MODE IO WITHOUT SETTING LOWER CORE, C(AC)=0
;STOP TIME SHARING ONLY IF AC IS NON-ZERO(IE RUN ONLY JOB 1)


IFN FTTRPSET,<
TRPSET::
IFE FTPRV,<
	CAIE	J,1		;IS THIS JOB 1 (REQUIRED IF NO PRIVILEG BITS)
	POPJ	P,		;NO.  ERROR RETURN
>
IFN FTPRV,<	MOVE	T2,JBTPRV##(J)	;IS JOB PRIVILEGED TO DO TRPSET UUO?
	TLNN	T2,PVTRPS	;PVTRPS IS SPECIFIED IN ACCT.SYS AND SETUP BY LOGIN
	POPJ	P,		;NO, ERROR RETURN
>
	MOVEI	P4,.C0CDB##	;ASSUME JOB IS ON CPU0
	SETZM	.CPSTS##(P4)	;CLEAR THE STOP TIME SHARING FLAG
IFE FTMS<
	JUMPE	T1,TRPST1	;IS AC 0?(DO NOT SET PI LOC IF YES)>
IFN FTMS<JUMPE T1,TRPST0>
	HLRZ	T2,T1		;NO, SET LOWER CORE
	CAIL	T2,40		;IS IT LEGAL LOWER CORE ADR.?
	CAIL	T2,60
	POPJ	P,		;NO, ERROR RETURN
IFN FTKI10!FTKL10,<
IFN FTLOCK,<
	PUSHJ	P,LOKEVC##	;IF KI10, JOB MUST BE LOCKED IN EVM
				; IS IT?
>
	  POPJ	P,		;NO, ERROR RETURN
>
IFN FTMS,<			;DUAL CPU FEATURE?
TRPST0:	PUSHJ	P,CPUTRP##	;GO SEE IF USER CAN DO TRPSET UUO ON DUAL CPU
	  POPJ	P,		;ERROR RETURN, SET TO RUN ON CPU1 ONLY
				; BUT NOT LOCKED IN CORE
				;SET TO RUN ON CPU0 OR CPU1, T4=CDB
				; FOR CPU HE IS ALLOWED TO RUN ON
>
IFN FTMS!FTKI10!FTKL10,<
	PUSHJ	P,GETTAC##	;RESTORE USER'S AC ARGUMENT TO T1
	JUMPE	T1,TRPST1
>
	MOVEM	J,.CPSTS##(P4)	;SET STOP TIME SHARING FLAG, SO NO OTHER JOBS
				; JOBS WILL RUN AND NO CORE SHUFFLING
	HRLI	T1,R		;YES, SET TO RELOCATE
	MOVE	T1,@T1		;GET THE INSTR.
	ADDI	T1,(R)		;ADD RELOCATION SO WILL POINTER TO USER AREA
	HRRZ	U,R		;USER RELOCATION
	ADDM	U,(T1)		;ALSO ADD RELOCATION TO WORD POINTED TO BY INSTR
				; IN CASE IT IS A BLKI/BLKO POINTER WORD
				; USER SHOULD RESET RH OF POINTER IF BLKI/BLKO INSTR
				; OR CLEAR PC LOC IF JSR INSTR
	ADD	T2,.CPTOS##(P4)	;ADD IN TRAP OFFSET VALUE FOR THIS CPU
	EXCH	T1,(T2)		;AND STORE IN MONITOR TRAP LOC.
TRPST1:	AOS	(P)		;OK RETURN
	MOVSI	T2,(XC.UIO)	;SET USER IO PC FLAG
	IORM	T2,JOBPD1##(R)	;IN UUO RETURN PC
	JRST	STOTAC##	;RETURN PREVIOUS CONTENTS OF PI LOC.

>	;END CONDITIONAL ON FTTRPSET
IFE FTTRPSET,<
TRPSET==:CPOPJ##
>

;ROUTINE TO DISMISS INTERRUPT  FOR JOB DOING USER IO
;WHEN PC IS IN EXEC MODE
;NOTE  THE TRPJEN UUO HAS BEEN ELIMINATED
;BECAUSE UUO HANDLER CANNOT BE INTERRUPTED AND REENTERED
;INSTEAD INTERRUPTS IN USER MODE ARE DISMISSED
;BY USING OP CODE 100 (UJEN) WHICH
;TRAPS TO EXEC 61 INSTEAD OF 41 ON P-10'S
;UJEN IS A NO-OP ON P-6'S AND SO THIS FACILTY IS GOOD ON P-10'S ONLY
;CALL:	RESTORE ALL EXEC ACS
;		UJEN ADR	;UJEN=100
;		WHERE ADR CONTAINS PC STORED BY INTERRUPT JSR
;		SEE UUO HANDLER (UUO2) FOR CODE


;RTTRP UUO

;LOCK UUO

;HPQ UUO
;	HIBERNATE/WAKE UUOS
;SIGN BIT OF UUO AC ARG=1 IF JOB
; WANT TO BE SWAPPED OUT IMMEDIATELY

IFN FTHIBWAK,<

HIBUUO:
IFE FTVM,<
	AOS	JOBPD1##(R)	;GIVE SKIP RETURN
>
IFN FTVM,<
	PUSHJ	P,INCPD1##
>
IFN FTPI,<
	XCT	NOPISK##	;SKIP IF USER NOT ENABLED FOR TRAPS
	SKIPL	JBTPIA##(J)	;GET ADDRESS OF PI TABLE
	JRST	HIBPSI		;NOT ENABLED
	MOVSI	T2,(JFCL)	;ARE WE WAITING FOR A UUO TO HAPPEN
	CAME	T2,@JBTPIA##(J)	; ..
	POPJ	P,		;YES--THIS WAS THE UUO
HIBPSI:				;NOT WAITING
>
	PUSHJ	P,HIBER		;DO THE UUO
	  POPJ	P,
	POPJ	P,
HIBER::	PUSHJ	P,SAVE1##	;SAVE P1
	HLRZ	T2,T1		;GET THE PROTECTION BITS
	DPB	T2,HIBPRT##	;STORE PROTECTION CODE IN LEFT HALF OF JBTRTD(J)
IFN FTIPCF,<
	MOVSI	T3,IPCACE##	;CLEAR IPC ACTIVITY ENABLE
	ANDCAM	T3,JBTRTD##(J)
	TRNE	T2,IPCUUB##	;USER WANT IPC ACTIVITY?
	IORM	T3,JBTRTD##(J)	;YES, DO SO
>
	MOVSI	P1,TTILCE##	;TTY CHARACTER OR LINE MODE BIT
	TDNE	P1,JBTRTD##(J)	;IS JOB GOING INTO CHARACTER MODE?
	PUSHJ	P,HIBTTY##	;YES, GO SET UP LINE CHARACTERISTICS
	MOVSI	T2,WAKEB##	;CHECK IF JOB HAS BEEN AWAKENED
	MOVEI	P1,SLPQ##	;PREPARE TO PUT JOB IN SLEEP QUEUE
	CONO	PI,PIOFF##	;GUARD AGAINST WAKEUP AT INTERRUPT LEVEL
	TDNN	T2,JBTRTD##(J)	;HAS THIS JOB BEEN WOKEN
	JRST	HIBER1		;NO, THEN PUT IT TO SLEEP
	ANDCAM	T2,JBTRTD##(J)	;CLEAR THE WAKE BIT
	CONO	PI,PION##	;RESTORE THE PI STATUS
	JRST	CPOPJ1##	;GIVE A SKIP RETURN TO THE USER
HIBER1:	DPB	P1,PJBSTS##	;STORE THE SLEEP CODE IN JBTSTS WORD
	CONO	PI,PION##	;RESTORE PI SYSTEM
IFN FTSWAP,<
	JUMPGE	T1,HIBER2	;DOES JOB WANT TO BE SWAPPED OUT IMMEDIATELY?
				; (HBRSWP SET)
	PUSHJ	P,ZERIPT##	;YES, MARK HIM AS SWAPPABLE.
	PUSHJ	P,GETWDU##	;PICKUP. ARGUMENT OF UUO AGAIN
>
;MORE
HIBER2:	AOS	(P)		;GIVE SKIP RETURN WHEN JOB WAKES UP
	HRRZS	T1		;GET THE SLEEP TIME IN MILLISEC
	JUMPE	T1,HIBER3	;IF NO SLEEP TIME, DONT ENTER CLOCK REQUEST
	IMUL	T1,TICSEC##	;CONVERT TO JIFFIES
	IDIVI	T1,^D1000	;   FROM MILLISECONDS
	SKIPE	T2		;IS THIS AN EVEN NUMBER OF JIFFIES
	AOS	T1		;NO, ALWAYS ROUND UP TO NEXT JIFFY
	CAILE	T1,7777		;WAS THIS A VERY LARGE NUMBER
	MOVEI	T1,7777		;YES, THEN SLEEP THE MAXIMUM TIME
	JRST	MSLEEP		;GO ENTER SLEEP TIME IN CLOCK REQUEST QUEUE
IFN FTSWAP,<
HIBER3:	PUSHJ	P,FNPDBS##	;GET THE PDB ADDRESS
	PUSHJ	P,CLRIPT##	;CLEAR IN-CORE PROTECT TIME
	PJRST	WSCHED##	;GO RESCHEDULE>
IFE FTSWAP,<HIBER3==WSCHED##>
;HERE ON A WAKE UUO
WAKUUO:

;HERE FROM RTTRP AT INTERRUPT LEVEL
WAKEUP::JUMPLE	T1,WAKEME	;WAKE UP CURRENT JOB ON NEG ARGUMENT
	PUSHJ	P,LGLPR1##	;IS THIS AN UNREASONABLE REQUEST?
	  POPJ	P,		;YES, GIVE AN ERROR RETURN
IFN FTLOGI,<	PUSHJ	P,PRVJ##	;DOES THIS JOB HAVE SPECIAL PRIVELEGES?
	  JRST	WAKOK1		;YES, WAKE THE JOB UP ALWAYS
>
	EXCH	T1,J		;SET UP TO TAKE THE JOB OUT OF SLPQ
	LDB	T2,HIBPRT##	;GET PROTECTION CODE
	TRNE	T2,4		;ONLY-ME PROTECTION?
	JRST	ONLYME		;YES, MAKE SURE THIS IS RIGHT JOB
IFN  FTLOGIN,<
	TRNE	T2,1		;ALL PROJECTS OK?
	JSP	T3,CHPRJ	;NO, CHECK THIS PROJECT NUMBER
	TRNE	T2,2		;ALL PROGRAMMERS OK?
	JSP	T3,CHPRG	;NO, CHECK THIS PROGRAMMER NUMBER
>	;END FTLOGIN
	JRST	WAKEOK		;GO WAKE THE JOB UP
WAKEME:	SKIPA	T1,J
WAKOK1:	EXCH	J,T1		;SET UP J PROPERLY
WAKEOK:
	MOVSI	T2,(JS.SLP)	;JOB DID SLEEP UUO BIT
	TDNE	T2,JBTST2(J)	;SLEEP OR HIBER?
	JRST	SETWAK		;SLEEP, JUST SET WAKE BIT
IFN FTPI,<
	XCT	OKSGNL##	;JOB SET UP FOR INTERRUPTS?
	  JRST	WAKEIT		;NO
	MOVE	T2,JBTPIA##(J)
	MOVEM	T1,PITWJB##(T2)	;YES, SAVE JOB NUMBER
	MOVE	T3,T1
	SIGNAL	C$WAKE		;SIGNAL WAKEUP
	 EXCTUU	<MOVEM	T3,IBKISW##(M)>
>
WAKEIT:
	MOVEI	T1,RNQ##	;PREPARE TO PUT JOB IN THE RUN QUEUE
	CONO	PI,PIOFF##	;GUARD AGAINST HIGHER PI ACTIVITY
	LDB	T2,PJBSTS##	;GET CURRENT QUEUE CODE
	CAIE	T2,SLPQ##	;IS THE JOB IN THE SLEEP QUEUE
	JRST	NOTSLP		;NO, THEN DONT WAKE THE JOB UP
IFN FTPSCD,<
	AOS	REQWK##		;COUNT A WAKE
>
WAKOKE::DPB	T1,PJBSTS##	;PUT THE JOB IN THE RUN QUEUE
	CONO	PI,PION##	;TURN THE PI BACK ON
	PUSHJ	P,SETR2##	;SET A SCHEDULER REQUEST
WAKOKA:
IFN FTHPQ,<
	LDB	T1,HPQPNT##	;GET CURRENT RUNQUE
	JUMPE	T1,CPOPJ1##	;IF IT IS TS QUEUE THEN DONT SCHEDULE
	MOVSI	T2,SWP		;PREPARE TO CHECK IF JOB IS ON DISK
	CONO	PI,PIOFF##	;GUARD AGAINST HIGH PI WAKE UP
	SETOM	.C0CKF##	;FLAG THE SCHEDULER FOR CPU0
	SKIPN	.C0RTF##	;IS THERE A FORCED SCHEDULE TO BE DONE
	SETOM	.C0RTF##	;NO, MARK  ONE IS IN PROGRESS FOR CPU0
	TDNN	T2,JBTSTS##(J)	;IS THIS JOB SWAPPED OUT
	  JRST	WAKOK3		;NO. PROCEED.
	SKIPG	T2,.C0RTF##	;ANYONE IN .C0RTF?
	  JRST	WAKOK2		;NO. PUT OUR NUMBER IN IT.
	LDB	T3,HPQPT2##	;YES. GET HIS HPQ NUMBER
	CAMLE	T1,T3		;IS HE AHEAD OF US?
WAKOK2:	HRRZM	J,.C0RTF	;NO. PUT OUR NUMBER IN.
WAKOK3:	CONO	PI,PICLK##	;CAUSE AN INTERRUPT ON PI 7
>
	JRST	CPOPJ1##	;GIVE SKIP RETURN
	;WAKJOB IS A ROUTINE WHICH CAN BE CALLED FROM ANY INTERRUPT LEVEL
	;TO WAKE UP A HIBERNATING JOB.  THE CALLING SEQUENCE IS:
	;	MOVE T1,JOBNUM		;T1 = # OF JOB TO BE WOKEN
	;	PUSHJ P,WAKJOB		;WAKE UP JOB
	;	RETURN ALWAYS
	;WAKJOB SAVES ALL ACS EXCEPT T1, T2


WAKJOB::PUSH	P,J		;SAVE J
	MOVE	J,T1
	PUSHJ	P,WAKEIT	;GO WAKE JOB
	  PJRST	JPOPJ##		;ALWAYS SKIP RETURNS
	PJRST	JPOPJ##		;RESTORE J AND RETURN


;WAKEJB SAME AS WAKJOB EXCEPT J=JOB#

WAKEJB::PUSHJ	P,WAKEIT
	  POPJ	P,
	POPJ	P,
NOTSLP:	CAIE	T2,NAPQ##	;NOT SLEEP, IS IT A NAP?
	JRST	NOTNAP		;NO, SET WAKE BIT
	DPB	T1,PJBSTS##	;ITS A NAP, CLEAR WAIT STATE
	CONO	PI,PION##	;TURN ON PIS AGAIN
	JRST	WAKOKA		;AND RETURN AFTER CHECKING FOR HPQ STUFF
SETWAK:	CONO	PI,PIOFF##	;GUARD AGAINST PI LEVEL ACTIVITY
NOTNAP:	MOVSI	T2,WAKEB##	;SET WAKEUP BIT INSTEAD
	IORM	T2,JBTRTD##(J)	;SET WAKE UP BIT
	CONO	PI,PION##	;DONT RESCHEDULE
	JRST	CPOPJ1##	;SKIP RETURN TO CALLER

ONLYME:	CAME	T1,J		;IS THIS JOB ME
	POPJ	P,		;NO, GIVE ERROR RETURN
	JRST	WAKEOK		;YES, GO WAKE THE JOB UP

	IFN  FTLOGIN,<CHPRJ:	HLLZ	T4,JBTPPN##(T1)	;GET OBJECT JOB'S PROJECT NUMBER
	XOR	T4,JBTPPN##(J)	;COMPARE WITH THIS JOB'S PROJECT
	MOVSS	T4		;RESULT TO RH
	JRST	CHPRG1		;TEST

CHPRG:	HRRZ	T4,JBTPPN##(T1)	;GET OBJECT JOB'S PROGRAMMER NUMBER
	XOR	T4,JBTPPN##(J)	;COMPARE WITH THIS JOB'S PROGRAMMER
CHPRG1:	TRNE	T4,-1		;SKIP IF EXACT MATCH
	POPJ	P,		;NO, GIVE ERROR RETURN
	JRST	(T3)		;OK, KEEP GOING
>	;END FTLOGIN
>	;END FTHIBWAK

IFE FTHIBWAK,<HIBER:
WAKUUO::
WAKJOB::
WAKEUP::POPJ	P,
>
	SUBTTL	DAEMON UUO'S AND ROUTINES

IFN FTDAEM,<
;UUO TO REQUEST SERVICE BY DAEMON
;CALL	MOVE AC,[XWD +LENGTH,ADDR OF ARG LIST]
;	 (FIRST ARG = FUNCTION CODE--SEE DAEMON FOR LEGAL FUNCTIONS)
;	CALLI AC,102
;	  ERROR RETURN
;	OKAY RETURN


CALDAE:	PUSH	P,T1		;SAVE USER ARG AC
	PUSHJ	P,STDAEM##	;IS DAEMON RUNNING?
	  JRST	TPOPJ##		;NO, ERROR RETURN TO USER-HIS AC UNCHANGED
	POP	P,T2		;T2=USER'S AC
	HRR	M,T2		;ADR. OF FIRST ARG IN USER AREA
	PUSHJ	P,GETWDU##	;GET FIRST WORD = FUNCTION
				; LEAVE IN T1 FOR DAEMON TO FINE IN DUMP ACS.
	MOVEI	T3,JDCQ##	;MAKE JOB UNRUNABLE
	DPB	T3,PJBSTS##	;BY PUTTING IT IN DAEMON WAIT STATE
	PUSHJ	P,WSCHED##	;CALL SCHEDULER
				;DAEMON WILL FIND T1 IN DUMP ACS FOR FUNCTION
				; IT WILL RETURN ERROR CODE IN FUMP T1 AND 0/NON-0
				; FLAG IN T1+1 IF SKIP/NON-SKIP RETURN
	JUMPE	T2,STOTC1##	;SKIP RETURN IF OK
	JRST	STOTAC##	;ERROR RETURN - STORE RETURN IN AC IN ANY CASE

;STILL IN FTDAEM CONDITIONAL
;UUO TO READ OR WRITE ANOTHER JOB'S CORE
;CALL	MOVEI	AC,ADDR OF 2 WORD ARGUMENT LIST
;	CALLI	AC,JOBPEK
;	  ERROR RETURN
;	OK RETURN
;FIRST ARG LH=FLAGS AND JOB NUMBER
;BIT 0=0 IF READ, 1 IF WRITE
;RH=NUMBER OF WORDS TO TRANSFER
;SECOND ARG=XWD SOURCE ADDR, DESTINATION ADDR


JOBPEK:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSHJ	P,PRUSET	;REQUIRES PRIVILEGES
	  POPJ	P,		;NOT PRIVILEGED
	HLRZ	P1,T1		;RH P1=JOB NUMBER
	TRZ	P1,600000	;CLEAR FLAGS
	HLL	P1,T1		;LH P1=FLAGS
	HRRZ	P2,T1		;P2=LENGTH OF TRANSFER
	HRRZ	T1,P1		;T1=JOB NUMBER
	PUSHJ	P,LGLPRC##	;SKIP IF LEGAL JOB NUMBER
	  POPJ	P,		;NO, REFUSE TO DO IT
	NOSCHEDULE
IFN FTVM,<
	MOVSI	T2,SWP		;JOB ON ITS WAY OUT OR IN?
	TDNE	T2,JBTSTS##(T1)	;LOSE IF SO
	JRST	JOBPKX		;RETURN IF SWP=1
>
	MOVM	T2,FINISH##	;T2 = JOB IN TRANSIT
	SKIPE	JBTADR##(P1)	;SKIP IF JOB SWAPPED
	CAIN	T2,(P1)		;SKIP IF ALL IN CORE
	JRST	JOBPKX		;NOT IN CORE
	CAILE	P2,1000		;SKIP IF UNDER MAX
	MOVEI	P2,1000
	PUSHJ	P,GETWD1##	;GET XWD SOURCE, DESTINATION
IFN FTVM,<
	PUSH	P,T1		;SAVE T1
	TLNE	P1,400000	;SKIP IF READ
	HLRZS	T1		;ADDR IN USER'S JOB
	HRRZS	T2,T1		;. .
	ADDI	T2,-1(P2)	;HIGHEST ADDRESS IN USER'S JOB
	PUSHJ	P,TRNGE##	;SEE IF PROCEEDING WILL CAUSE A PAGE FAULT
	CAIE	J,(P1)		;JOB PEK ON SELF?
	JRST	JOBPK2		;NO, PROCEED
	MOVE	T1,(P)		;GET XWD BACK
	TLNN	P1,400000	;SKIP IF WRITE
	HLRZS	T1		;ADDR IN USER'S JOB
	HRRZS	T2,T1		; ...
	ADDI	T2,-1(P2)	;HIGHEST ADDR IN JOB
	PUSHJ	P,TRNGE##	;CHECK IT
JOBPK2:	POP	P,T1		;RESTORE XWD
>
;STILL IN FTDAEM CONDITIONAL
;HERE TO CHECK IF SOURCE ADDR IS FROM HIGH SEGMENT

	MOVE	P3,R		;P3=JBTADR FOR THIS JOB
	MOVE	T4,JBTADR##(P1)	;T4=JBTADR FOR USER'S JOB
	TLNE	P1,400000	;SKIP IF READ, NOT IF WRITE
	EXCH	T4,P3		;T4=SOURCE JBTADR, P3=DESTINATION JBTADR
	HLRZ	T3,T4		;T3=SIZE OF SOURCE LOW SEGMENT
	HLRZ	T2,T1		;T2=SOURCE ADDRESS
IFN	FT2REL,<
	CAMGE	T2,T3		;SKIP IF SOURCE ADDR GT LOW SEGMENT SIZE
	JRST	JOBPK1		;SOURCE ADDRESS IS IN LOW SEGMENT
	MOVE	T4,JBTSGN##(P1)	;HIGH SEGMENT NUMBER FOR USER'S JOB
	TLNE	P1,400000	;SKIP IF READ, NOT IF WRITE
	MOVE	T4,JBTSGN##(J)	;HIGH SEGMENT NUMBER FOR THIS JOB
	JUMPE	T4,JOBPKX	;EXIT IF SOURCE JOB HAS NO HIGH SEGMENT
	CAIGE	T3,400000	;SKIP IF LOW SEGMENT GT 400000 LOCATIONS
	MOVEI	T3,400000	;NO, T3=OFFSET FOR HIGH SEGMENT
IFN FTKI10!FTKL10,<
	JUMPL	T4,JOBPK0	;GO IF A SPY SEG.
	LDB	T3,[POINT 9,JBTUPM##(T4),8]  ;HIGH SEG ORIGIN PAGE #
	LSH	T3,P2WLSH##	;VIRTUAL ADDRESS OF HIGH SEG.
JOBPK0:>
	SUB	T2,T3		;T2=ADDRESS IN SEGMENT FOR TRANSFER
	JUMPL	T2,JOBPKX	;ILLEGAL ADR IF NEGATIVE
	HRL	T1,T2		;ADDRESS IN SEGMENT BACK TO ACTUAL ADDRESS
	SKIPL	T4		;SKIP IF SPY SEG
	SKIPA	T4,JBTADR##(T4)	;T4=JBTADR FOR SOURCE SEGMENT
	HRLZS	T4		;T4=XWD LENGTH, START ADDR OF SPYSEG
	HLRZ	T3,T4		;T3=SIZE OF SOURCE SEGMENT
>
;HERE TO CHECK IF SOURCE ADDRESS FITS IN SOURCE SEGMENT
JOBPK1:	SUBI	P2,1		;LENGTH OF TRANSFER -1
	ADD	T2,P2		;SOURCE ADDR+LENGTH OF SEG=LAST ADDR OF SOURCE 
	CAMLE	T2,T3		;SKIP IF LE LAST ADDR OF SOURCE SEG 
	JRST	JOBPKX		;DOESN'T FIT IN SOURCE SEGMENT

;HERE TO CHECK IF DESTINATION FITS IN DESTINATION SEGMENT
;NOTE THAT DESTINATION MUST BE A LOW SEGMENT - IF A HIGH SEGMENT IS
; SPECIFIED IT WILL BE OUT OF BOUNDS AND HENCE ILLEGAL.  THIS IS IN LIEU
; OF DETERMINING APPROPRIATE PRIVILEGES TO WRITE IN HIGH SEGMENT

	HRRZ	T2,T1		;T2=DESTINATION ADDRESS
	ADD	T2,P2		;LAST ADDR OF DESTINATION
	HLRZ	T3,P3		;T3=SIZE OF DESTINATION SEGMENT
	CAMLE	T2,T3		;SKIP IF FITS IN DESTINATION SEGMENT
	JRST	JOBPKX

;HERE WHEN ADDRESSES ARE VERIFIED TO BE LEGAL

	AOJE	P2,JOBPX1	;EXIT NOW IF 0 WORDS TO TRANSFER
	PUSHJ	P,JOBPKD##	;GO DO THE BLT
IFN  FTVM,<
	  JRST	JOBPKX		;LOSE (REFERENCE TO TARGET JOB WILL
				; CAUSE A PAGE FAULT)
>
JOBPX1:	SCHEDULE		;TURN ON SCHEDULING
	JRST	CPOPJ1##
JOBPKX:	SCHEDULE
	POPJ	P,

;STILL IN FTDAEM CONDITIONAL

;UUO TO TAKE JOB OUT OF DAEMON QUEUE
;CALL	MOVE	AC,XWD +LENGTH, ADDR OF ARGUMENT LIST
;	CALLI	AC,DAEFIN
;	  ERROR RETURN
;	OK RETURN
;FIRST ARG=JOB NUMBER
;REST OF ARGUMENTS=ACCOUNTING INFORMATION


DAEFIN:	PUSHJ	P,PRUSET	;SEE IF JOB IS PRIVILEGED
	  POPJ	P,
	PUSHJ	P,LGLPRC##	;SEE IF JOB NUMBER LEGAL
	  POPJ	P,		;NO, ERROR RETURN
	EXCH	J,T1		;J=JOB DAEMON HAS FINISHED

	PUSHJ	P,DAEDON##	;START USER NOW THAT DAEMON IS DONE
	JRST	CPOPJ1##	;SKIP RETURN

>	;END CONDITIONAL ON FTDAEM
IFE FTDAEM,<
JOBPEK=CPOPJ##
CALDAE=CPOPJ##
DAEFIN=CPOPJ##
>


IFN FT5UUO,<
;UUO TO FORCE A COMMAND FOR A JOB
;CALL	MOVE	AC,XWD +LENGTH OR 0, ADDR OF ARG LIST
;	CALLI	AC,FRCUUO
;	  ERROR RETURN
;	OK RETURN
;	FIRST ARG=SIXBIT COMMAND TO FORCE
;	SECOND ARG=JOB NUMBER OR THIS JOB IF NOT SPECIFIED


FRCUUO:	PUSHJ	P,PRUSET	;REQUIRES PRIVILEGES
	  POPJ	P,		;NO GOOD
	MOVSI	T4,MTTFCM##	;MINUS LENGTH OF COMMAND TABLE
	CAME	T1,TTFCOM##(T4)	;SKIP IF FOUND COMMAND
	AOBJN	T4,.-1
	JUMPGE	T4,CPOPJ##	;NO GOOD IF NOT LEGAL COMMAND
	MOVE	T1,J		;T1=OUR JOB
	CAIE	T3,1		;SKIP IF JOB NOT SPECIFIED
	PUSHJ	P,GETWD1##	;GET 2ND ARG=JOB NUMBER
	SKIPN	T1		;SUBMITTED ZERO SECOND ARGUMENT?
	MOVE	T1,J		;YES, USE THIS JOB #
	PUSHJ	P,LGLPRC##	;SKIP IF LEGAL JOB NUMBER
	POPJ	P,
	MOVSI	T3,JNA		;DON'T ALLOW FORCED COMMAND IF NOT A JOB
	TDNN	T3,JBTSTS##(T1)	;JOB NUMBER ASSIGNED?
	POPJ	P,		;NO, LOSE
	HRRZ	F,TTYTAB##(T1)	;ADDRESS OF TTY DDB
	HRRZ	U,DDBLDB##(F)	;GET POINTER TO LDB
	JUMPE	U,CPOPJ##	;FAIL ON DETACHED JOB
	HRRZ	T2,T4		;T2=INDEX OF COMMAND
	PUSHJ	P,COMFRC##	;FORCE COMMAND
	  JRST	CPOPJ1##		;OK
	POPJ	P,		;CAN'T

>	;END CONDITIONAL FT5UUO
IFE FT5UUO,<
FRCUUO==CPOPJ##
>
IFN FT5UUO!FTDAEM,<
;SUBROUTINE TO CHECK FOR PRIVILEGES AND RETURN FIRST ARGUMENT
;CALL	T1=CONTENTS OF USER'S  AC=+LENGTH, ADDR
;RETURN	T1=CONTENTS OF USER LOCATION ADDR
;	T3=+LENGTH OF ARGUMENT LIST

PRUSET::
	HRR	M,T1		;SOME CALLERS (EG CAL78.)
	HLRZ	T3,T1		;USE LENGTH EVEN IF NOT PRIVILEGED.
	PUSHJ	P,GETWDU##	;GET FIRST ARGUMENT
IFE FTLOGIN,<
	PJRST	CPOPJ1##	;OBVIOUSLY CAN'T CHECK PRIVS
	>;END IFE FTLOGIN
IFN FTLOGIN,<
	PUSH	P,T1		;USER'S AC
	PUSH	P,T3		;ARG LIST LENGTH
	MOVSI	T1,JP.POK	;NOW CHECK PRIVS
	PUSHJ	P,PRVBIT##	;SKIP RETURN IF NOT
	AOS	-2(P)		;FUDGE SKIP RETURN TO CALLER FOR PRIV OK
	POP	P,T3		;BUT GIVE HIM THIS IN ANY CASE
	PJRST	TPOPJ##
	>;END IFN FTLOGIN

>	;END CONDITIONAL ON FT5UUO!FTDAEM
IFN FTGALAXY,<
;UUO TO SET PARAMETERS ON SPOOLED FILES
;CALL:	MOVE	AC,[N,,E]
;	SPPRM.	AC,
;	  ERROR	RETURN
;	NORMAL	RETURN
;
;E:	CHANNEL #	(ONLY)
;	FORMS NAME	(SIXBIT)
;	COPIES		(1 TO 777)
;
;ERRORS:	-1 = ADDRESS CHECK
;		0  = ILLEGAL CHANNEL #
;		1  = ARG BLOCK TOO SHORT
;		2  = CHANNEL NOT OPEN
;		3  = DEVICE IS NOT SPOOLED
;		4  = COPIES TOO LARGE

SPPRM:	PUSHJ	P,SAVE1##	;SAVE P1
	HRR	M,T1		;PUT ARG ADR IN M
	HLRE	P1,T1		;GET LEN IN P1
	CAIGE	P1,2		;WITHIN RANGE?
	  PJRST	ECOD1##		;NO, ERROR
	PUSHJ	P,GETWRD##	;GET CHANNEL #
	  PJRST	RTM1
	CAIL	T1,0		;MAKE SURE ITS
	CAILE	T1,17		; A CHANNEL #
	  PJRST	ECOD0##
	PUSHJ	P,DVCNSG	;SETUP F
	  PJRST	ECOD2##		;NOT OPENED
	SKIPL	DEVSPL(F)	;SPOOLED?
	  PJRST	ECOD3##		;NO

SPPRM1:	PUSHJ	P,GETWR1##	;GET FORMS
	  PJRST	RTM1
	MOVEM	T1,DEVFRM##(F)	;STORE IT
	CAIGE	P1,3		;WAS COPIES THERE?
	PJRST	CPOPJ1##	;NO, JUST RETURN
	PUSHJ	P,GETWR1##	;YES, GET IT
	  PJRST	RTM1
	CAILE	T1,777		;IN RANGE?
	  PJRST	ECOD4##		;NO
	MOVEM	T1,DEVSPM##(F)	;STORE IT
	PJRST	CPOPJ1##	; AND RETURN
>	;END IFN FTGALAXY
	SUBTTL ALLOC. UUO

IFN FTGALAXY,<

;UUO TO ALLOCATE/DEALLOCATE MOUNTABLE DEVICES
;CALL WITH:
;	MOVE	AC,[N,,E]
;		ERROR RETURN
;	NORMAL RETURN

;THIS IS A PRIVILEGED UUO WHICH MAY BE EXECUTED BY THE SYSTEM
; MOUNTABLE-DEVICE ALLOCATOR ONLY.


;FUNCTIONS AND ARGUMENTS
	.ALLAD==1		;FUNCTION 1 -- ALLOCATE DEVICE
;		FUNCTION
;		DEVICE
;		JOB
	.ALLFD==2		;FUNCTION 2 -- FREE A DEVICE
;		FUNCTION
;		DEVICE

;DISPATCH TABLE
ALLDSP:	EXP	ERRIF		;ILLEGAL FUNCTION
	EXP	ALLF1		;ALLOCATE DEVICE
	EXP	ALLF2		;FREE A DEVICE
	ALLMXF==.-<ALLDSP+1>
;STILL IN IFN FTGALAXY
;
;ERROR CODES
	ALLIS%==1		;(1) INSUFFICIENT PRIVS
	ALLIF%==2		;(2) ILLEGAL FUNCTIONS
	ALLID%==3		;(3) ILLEGAL DEVICE
	ALLIJ%==4		;(4) ILLEGAL JOB
	ALLIA%==5		;(5) ILLEGAL ARGLIST

;ERROR ROUTINES

	ERCODE	ERRIS,ALLIS%
	ERCODE	ERRIF,ALLIF%
	ERCODE	ERRID,ALLID%
	ERCODE	ERRIJ,ALLIJ%
	ERCODE	ERRIA,ALLIA%
;STILL IN IFN FTGALAXY
;
ALLOC:	CAME	J,MDAJOB##	;IS HE MDA?
	JRST	ERRIS		;NO, LOSE
	MOVE	P1,T1		;SAVE USER AC
	HRR	M,T1		;POINT TO ARG BLOCK
	PUSHJ	P,GETWDU##	;GET FUNCTION WORD
	SKIPL	T1		;TOO SMALL?
	CAILE	T1,ALLMXF	;TOO BIG?
	SETZ	T1,		;YES MAKE IT ZERO
	JRST	@ALLDSP(T1)	;AND DISPATCH

;FUNCTION 1 -- ALLOCATE A DEVICE
;
ALLF1:	HLRZ	T1,P1		;GET LENGTH OF ARGLIST
	CAIE	T1,3		;MUST BE THREE WORDS
	JRST	ERRIA		;ILLEGAL ARGLIST
	PUSHJ	P,GETWD1##	;GET DEVICE WORD
	PUSHJ	P,ALLFND	;FIND THE DEVICE
	PJUMPE	F,ERRID		;BAD DEVICE
	PUSHJ	P,GETWD1##	;GET JOB NUMBER
	MOVSI	T2,JLOG		;GET JLOG BIT
	TDNN	T2,JBTSTS##(T1)	;LOGGED IT?
	JRST	ERRIJ		;NO, GIVE ERROR
	DPB	T1,PJOBN##	;YES, SET DEVJOB
	MOVSI	T2,DVDATJ	;GET "ALLOC" BIT
	IORM	T2,DEVCHR(F)	;SET IT
	MOVEI	T2,ASSCON!ASSPRG;GET "ASSIGN" BITS
	ANDCAM	T2,DEVMOD(F)	;AND CLEAR THEM
	PJRST	CPOPJ1##	;AND RETURN

;FUNCTION 2 - DEALLOCATE A DEVICE
;
ALLF2:	HLRZ	T1,P1		;GET LENGTH OF ARGLIST
	CAIE	T1,2		;BETTER BE TWO
	JRST	ERRIA		;ILLEGAL ARGLIST
	PUSHJ	P,GETWD1##	;GET THE DEVICE
	PUSHJ	P,ALLFND	;FIND IT
	PJUMPE	F,ERRID		;LOSE
	MOVSI	T1,DVDATJ	;GET ALLOC BIT
	ANDCAM	T1,DEVCHR(F)	;TURN IT OFF
	LDB	J,PJOBN##	;GET JOB NUMBER
	PJUMPE	J,CPOPJ1##	;DONE, RETURN
	PUSHJ	P,DEASG1##	;FORCE A DEASSIGN
	  JFCL			;IGNORE
	PJRST	CPOPJ1##	;RETURN
;STILL IN IFN FTGALAXY
;
;SUBROUTINE TO FIND THE SPECIFIED DEVICE (IN TL)
;	IF SUCCESSFUL, RETURN WITH F SETUP
;	IF NOT, (F)=0
;
ALLFND:	PUSHJ	P,DEVPHY	;FIND PHYS DEVICE
	JUMPE	F,CPOPJ##	;RETURN IF NONE
	MOVSI	T1,DVCMDA	;GET CONTROLLED BIT
	TDNN	T1,DEVCHR(F)	;TEST IT
	CLEAR	F,		;FAILED
	POPJ	P,		;AND RETURN

>	;END IFN FTGALAXY
	SUBTTL	DEVOP. UUO

;UUO TO PERFORM MISCELLANEOUS DEVICE FUNCTIONS
;
;CALL:	MOVE	AC,[+N,,ADR]
;	DEVOP. AC,0	;OR CALLI AC,171
;	  ERROR RETURN

IFN FT5UUO,<
;DEVOP FUNCTIONS ARE EITHER DEVICE INDEPENDENT OR DEVICE DEPENDENT.
; DEVICE INDEPENDENT OPERATIONS ARE HANDLED BELOW, AND DEVICE DEPENDENT
; OPERATIONS ARE HANDLED BY CALLING THE DEVICE SERVICE ROUTINE VIA
; THE DDVO (-4) DISPATCH WITH T1 CONTAINING THE FUNCTION CODE AND F
; POINTING TO THE DDB.

;DEVOP DISPATCH TABLE
;	XWD	CODE,ADR
DVPDIS:	XWD	1,DVPCAL	;(01) LOAD STD VFU (DEP)
	XWD	2,DVPCAL	;(02) ENABLE NON-STD VFU LOAD (DEP)
	XWD	3,DVPCAL	;(03) DISABLE VFU LOAD
	XWD	1000,DVPCAL	;READ/SET PAGE CTR (DEP)
	XWD	1002,DVPRHC	;READ/SET DEVICE CHAR (IND)
	XWD	1003,DVPRES	;READ ERROR STATUS
	XWD	1004,DVPCAL	;READ DEVICE STATUS
	DVPDSL==.-DVPDIS	;LENGTH OF DISPATCH

;DEVOP ERRORS
	DFACS%==-1		;ADDRESS CHECK
	DFIFC%==0		;ILLEGAL FUNCTION CODE
	DFPRV%==1		;NO PRIVILEGES
	DFDIF%==2		;FUNCTION NOT VALID FOR SPECIFIED DEVICE
	DFNLR%==3		;VALUE OUT OF RANGE
	DFNXD%==4		;NON-EX DEVICE
	DFNDV%==5		;NO DAVFU
	DFNIA%==6		;DEVICE NOT INITED
	DFDOL%==7		;DEVICE IS OFFLINE
	DFCNS%==10		;PAGE COUNTER NOT SET
	DFNPC%==11		;NO PAGE COUNTER
	DFENI%==12		;EXT ERROR RECOVERY NOT IMP
	DFNVC%==13		;NON VARIABLE CHAR SET
DEVOP::	PUSHJ	P,SAVE4##	;SAVE AC'S
	MOVE	P4,T1		;RELOCATE USER ARG
	HRR	M,T1		;LOAD ADDRESS
	HLRE	T2,T1		;GET LENGTH
	CAIGE	T2,2		;VALID?
	  PJRST	ECOD3##		;NO
	PUSHJ	P,GETWRD##	;GET FUNCTION CODE
	  PJRST	RTM1		;OOPS...BAD GUY
	JUMPLE	T1,RTZER	;BAD FUNCTION
	MOVE	P1,T1		;SAVE FUNCTION
	PUSHJ	P,GETWR1##	;GET NEXT ARG (DEVICE)
	  PJRST	RTM1		;LOSE
	PUSHJ	P,DVCNSG	;SEARCH FOR IT
	  PJRST	ECOD4##		;NONE SUCH
	MOVE	S,DEVIOS(F)	; AND S
	MOVE	T1,P1		;GET FUNCTION
	MOVE	T2,T1		;COPY INTO T2
	TRZE	T2,2000		;CHANGE SET
	TRO	T2,1000		;+ INTO READ FOR THE COMPARE
	HRLZI	T3,-DVPDSL	;LOAD AOBJN POINTER
DEVOP1:	HLRZ	T4,DVPDIS(T3)	;GET CODE
	HRRZ	P1,DVPDIS(T3)	;GET DISPATCH
	CAMN	T2,T4		;MATCH?
	JRST	(P1)		;YES, DISPATCH T1=FUNCTION
	AOBJN	T3,DEVOP1	;NO, LOOP
	PJRST	ECOD0##		;ILLEGAL FUNCTION CODE

;HERE TO CALL DEVICE SERVICE ROUTINE
DVPCAL:	HRRZ	T2,DEVSER(F)
	PJRST	DDVO(T2)

;HERE TO RETURN ERROR STATUS
DVPRES:	TRNE	T1,2000		;SET?
	PJRST	ECOD0##		;YES, ILLEGAL
	LDB	T1,PDVESE##
	PJRST	STOTC1##

;HERE TO READ/SET HARDWARE CHARACTERISTICS
DVPRHC:	MOVE	T2,T1
	MOVE	T1,DEVHCW(F)	;GET HCW WORD
	TRNE	T2,1000		;READ?
	PJRST	STOTC1##	;YUP, RETURN
	PUSHJ	P,PRVJ##	;IS JOB PRIVILEGED?
	  SKIPA			;YES, SKIP
	PJRST	ECOD1##		;NO.
	PUSHJ	P,GETWR1##	;GET THE CHARS
	  PJRST	RTM1		;ADDRESS CHECK
	MOVEM	T1,DEVHCW(F)	;STORE
	PJRST	CPOPJ1##	;AND RETURN
>	;END FT5UUO
	SUBTTL	FILOP. UUO

IFN FT5UUO,<
;UUO TO PERFORM FILE OPERATIONS
;CALL WITH:
;	MOVE	AC,[N,,E]
;	FILOP.	AC,
;	  ERROR RETURN
;	NORMAL RETURN
;

;BITS IN THE LH OF FOPFLG
FOP.SA==(1B0)		;THIS FILOP. DOES BOTH A LOOKUP AND
			; AN ENTER. WE MUST SAVE ARGUMENTS TILL
			; THE ENTER
FOP.LK==(1B1)		;DO A LOOKUP
FOP.EN==(1B2)		;DO AN ENTER
FOP.MA==(1B3)		;MULTI-ACCESS UPDATE
FOP.AP==(1B4)		;APPEND
FOP.PV==(1B5)		;REQUESTING PRIVS.
FOP.NS==(1B6)		;DO NOT SUPERSEDE
FOP.UR==(1B7)		;JUST UPDATE RIB
FOP.NF==(1B8)		;LIT IF INPUT FILE NOT FOUND ON APPEND OR UPDATE
FOP.AL==(1B9)		;PRE-ALLOCATE
FOP.RN==(1B10)		;THIS FILOP. DOES A RENAME
FOP.DL==(1B11)		;THIS FILOP. DELETES THE FILE

FOPTAB:		;DISPATCH TABLE FOR FILOP.
EXP	FOPILU					;(00) ILLEGAL
XWD	FOP.LK,FOPEN				;(01) READ
XWD	FOP.NS+FOP.EN,FOPEN			;(02) CREATE
XWD	FOP.EN,FOPEN				;(03) CREATE OR SUPERSEDE
XWD	FOP.SA+FOP.LK+FOP.EN,FOPEN		;(04) UPDATE
XWD	FOP.SA+FOP.LK+FOP.EN+FOP.MA,FOPEN	;(05) MULTI-ACCESS UPDATE
XWD	FOP.SA+FOP.LK+FOP.EN+FOP.AP,FOPEN	;(06) APPEND
EXP	FCLOS					;(07) CLOSE
XWD	FOP.UR,FCLOS				;(10) UPDATE RIB
EXP	FUSTI					;(11) USETI
EXP	FUSTO					;(12) USETO
XWD	FOP.RN+FOP.LK,FOPEN			;(13) RENAME
XWD	FOP.RN+FOP.DL+FOP.LK,FOPEN		;(14) DELETE
XWD	FOP.EN+FOP.AL,FOPEN			;(15) PREALLOCATE
FOPMAX==.-FOPTAB-1 	;MAXIMUM FUNCTION
	SALL
FILOP:	FRAME	<FOPFLG,FOPAP,FOPTMP,FOPBLK,FOPEXT>
	HRRZM	T1,FOPAP	;ADDRESS OF ARG LIST
	HLLM	M,FOPAP		;AC #
	HLRZ	T2,T1		;GET ARGUMENT COUNT
	HRR	M,T1		;POINT TO FIRST ARGUMENT
	PUSHJ	P,GETWDU##	;GET FIRST ARGUMENT
	TLZE	T1,(1B0)	;DOES HE WANT TO BE PRIV'D?
	TLO	T2,FOP.PV	;YES--REMEMBER THAT
	PUSHJ	P,PRVJO##	;IS HE PRIV'ED
	  TLZ	T2,FOP.PV	;NO, CLEAR THE BIT
	HLRZ	P1,T1		;REMEMBER CHANNEL #
	TLZ	T1,17		;CLEAR OUT CHAN #
	CAILE	T1,FOPMAX	;FUNCTION TOO BIG?
	JRST	FOPILU		;YES--ERROR
	HLLZ	T3,FOPTAB(T1)	;GET FLAGS
	IOR	T2,T3		;MAKE FLAGS,,LEN
	MOVEM	T2,FOPFLG	;SAVE THE FLAGS
	DPB	P1,PUUOAC##	;IN CASE OF LDB
	JRST	@FOPTAB(T1)	;DISPATCH BY FUNCTION
;HERE FOR FUNCTIONS WHICH OPEN A FILE
FOPEN:	HRRZ	T4,FOPFLG	;GET ARG COUNT
	CAIGE	T4,4		;MUST BE AT LEAST 4
	JRST	FOPILU		;ELSE ILL UUO ERROR
IFN FTVM,<
	CAIGE	T4,6		;LOOKUP / ENTER GIVEN?
	JRST	FOPVMX		;NO--ALL VALID
	HRRI	M,5(M)		;POINTER TO LOOKUP/ENTER BLOCK
	PUSHJ	P,GETWDU##	;GET POINTER
	HRR	M,T1		;PUT IN GOOD AC
	HLRZ	P2,T1		;ADDRESS OF THE RENAME BLOCK
	PUSHJ	P,FCLERB	;CHECK LOOKUP/ENTER/RENAME BLOCK
	JUMPE	P2,FOPEN0	;JUMP IF NO RENAME BLOCK
	HRR	M,P2		;ADDRESS OF THE RENAME BLOCK
	PUSHJ	P,FCLERB	;MAKE SURE THATS IN CORE
>	;END FTVM
FOPEN0:	CAIGE	T4,7		;PATH POINTER
	JRST	FOPVMX		;NO--ALL IS WELL
	HRR	M,FOPAP		;GET ARG POINTER
	HRRI	M,6(M)		;PATH PTR
	PUSHJ	P,GETWDU##	;GET ARGUMENT
	JUMPE	T1,FOPVMX	;JUMP IF PATH ISN'T REQUIRED
	HLRZ	T2,T1		;COPY LENGTH
	ADDI	T2,(T1)		;END ADDRESS
IFN FTVM,<
	TLZ	T1,-1		;START ADDRESS
	PUSHJ	P,TRNGE##	;TEST RANGE
>	;END FTVM
IFE FTVM,<
	HRR	M,T2		;GET LAST PATH ADDRESS
	PUSHJ	P,GETWDU##	;IF ILLEGAL, WON'T RETURN
>	;END FTVM
FOPVMX:	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,1(M)		;POINT TO OPEN BLOCK
IFN FTVM,<
	MOVE	T1,.UPMP+.UPFOP
	MOVEM	T1,FOPEXT
>
	TLO	M,400000	;INDICATE FROM FILOP
	PUSHJ	P,UOPEN		;TRY TO OPEN
	  JRST	FOPOER		;CAN NOT OPEN
	TLZ	M,400000
	HRRZ	T1,FOPFLG	;GET ARG COUNT
	CAIN	T1,4		;ONLY DOING AN OPEN?
	JRST	FOPWIN		;YES--GIVE THE GOOD RETURN
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,4(M)		;POINT TO BUFFER WORD
	PUSHJ	P,GETWDU##	;GET THE WORD
	MOVEM	T1,FOPTMP	;SAVE FOR A BIT
	HLRE	T2,T1		;GET THE NUMBER OF OUTPUT
				; BUFFERS REQUESTED
	JUMPE	T2,FOPEN1	;NONE--SKIP OUTBUF
IFN FTVM,<
	SKIPN	T1,FOPEXT
	MOVE	T1,.JDAT+JOBFF##
	MOVEM	T1,.JDAT+JOBFF##
	MOVEM	T1,.UPMP+.UPFOP
>
	SKIPG	T2		;SKIP IF NUMBER GIVEN
	MOVEI	T2,0		;ELSE USE DEFAULT
	HRR	M,T2		;PUT IN M
	PUSHJ	P,UOUTBF	;DO THE OUTBUF
FOPEN1:	HRRE	T1,FOPTMP	;GET THE NUMBER OF INPUT
				; BUFFERS REQUESTED
	JUMPE	T1,FOPEN2	;JUMP IF NONE REQUESTED
	SKIPG	T1		;TURN -1 INTO
	MOVEI	T1,0		; ZERO
	HRR	M,T1
	PUSHJ	P,UINBF		;BUILD BUFFERS
;HERE TO DO LOOKUP AND/OR ENTER
FOPEN2:	HRRZ	T1,FOPFLG	;GET # OF ARGUMENTS
	CAIN	T1,5		;DONE YET?
	JRST	FOPWIN		;YES--GIVE SKIP RETURN
	HRR	M,FOPAP		;GET ARG POINTER
	HRRI	M,5(M)		;GET POINTER TO LOOKUP BLK
	PUSHJ	P,GETWDU##	;GET THE POINTER
	HRR	M,T1		;SAVE ADDRESS OF BLOCK
	HRRM	M,FOPBLK	;SAVE ADDRESS FOR LATER
	PUSHJ	P,GETWDU##	;GET FIRST WORD
	MOVE	T2,DEVMOD(F)	;GET DEVCHR BITS
	TLNE	T2,DVDSK	;SKIP IF THIS IS NOT A DISK
	TLNE	T1,-1		;SKIP IF EXTENDED UUO
	JRST	FOPEN3		;NO DISK OR NOT EXTENDED
	TLO	P1,400000	;EXTENDED - INDICATE THAT
	HRRI	M,UUXNAM(M)	;POINT TO FILE NAME
	SKIPA	T2,T1		;YES--COPY COUNT TO T2
FOPEN3:	MOVEI	T2,4		;NO--4 WORD BLOCK
	TRZ	T2,400000	;IN CASE OF OLD FORMAT
	HRLM	T2,FOPBLK	;SAVE COUNT
	MOVEI	T3,UUNEXT-UUNNAM(M) ;WHERE TO FIND EXTENSION
	HRLZM	T3,FOPEXT	;REMEMBER FOR LATER
	MOVE	P2,FOPFLG	;GET FLAGS
	MOVSI	T1,DEPFOP	;WANT TO SET "FILOP. IN PROGRESS BIT"
	TLNN	P2,FOP.PV	;DOES HE WANT FULL FILE ACCESS
	TLO	T1,DEPFFA	;NO--MAKE SURE HE DOES NOT GET IT
	IORM	T1,DEVJOB(F)	;TURN ON BITS IN DDB
	MOVEI	T1,DEPECS	;NON-SUPERSEDING ENTER
	ANDCAM	T1,DEVSTA(F)	;CLEAR TO START WITH
	TLNE	P2,FOP.NS	;WANT TO SUPERSEDE?
	IORM	T1,DEVSTA(F)	;NO--TELL FNDFIL SUPERSEDE IS ILLEGAL
	HRRZ	T1,FOPFLG	;# OF ARGUMENTS
	MOVE	T2,DEVMOD(F)	;DEVICE CHARACTERISTICS
	CAIL	T1,10		;8TH ARGUMENT SPECIFIED?
	TLNN	T2,DVDSK	;ONLY IF A DSK
	JRST	FOPN3A		;NO
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,7(M)		;POINT TO "IN YOUR BEHALF" PPN
	PUSHJ	P,GETWDU##	;GET IT
	TLNE	P2,FOP.PV	;DON'T STORE IF NOT A PRIV'ED PROGRAM INVOKING PRIVS
	MOVEM	T1,DEVUPP##(F)	;STORE IT FOR FNDFIL
FOPN3A:	JUMPGE	P2,FOPEN4	;JUMP IF NOT BOTH LOOKUP AND ENTER
;HERE IF BOTH LOOKUP AND ENTER MUST BE DONE. WE CHANGE THE LENGTH OF
; THE BLOCK (IF REQUIRED) SO THAT WORDS LIKE .RBALC, .RBPOS ETC. ARE
; NOT STORED BUT ARE INSTEAD ARGUMENTS TO THE ENTER.
	HLRZ	T1,FOPBLK	;REMEMBER SIZE
IFN FTDSIM,<
	TLNN	P2,FOP.MA	;SIMULTANEOUS UPDATE?
>
	CAIGE	T1,UUXPRV+1	;5 OR MORE WORDS?
	JRST	FOPEN5		;NO--DO NOT SAVE ANYTHING
	HRR	M,FOPBLK	;ADDRESS OF BLOCK
	MOVEI	T1,UUXEXT+1	;ONLY NEED PPN/FILE/EXT
	PUSHJ	P,PUTWDU##	;DON'T LOOK BEYOND
FOPEN4:	TLNN	P2,FOP.LK	;LOOKUP NEEDED?
	JRST	FOPEN7		;NO--SKIP TO ENTER
FOPEN5:	HLR	M,FOPEXT	;GET EXTENSION ADDRESS
	PUSHJ	P,GETWDU##	;GET THE EXTENSION
	HRRM	T1,FOPEXT	;SAVE DATE BITS
	SKIPL	P1		;POINT AT PPN WORD -1
	AOSA	M
	SUBI	M,UUXEXT-UUXPPN+1
	PUSHJ	P,GETWD1##	;GET USERS PPN
	MOVEM	T1,FOPTMP	;AND SAVE IT FOR ENTER
	HRR	M,FOPBLK	;GET POINTER
	MOVE	T4,DEVSER(F)	;SETUP FOR DISPATCH
	MOVSI	T1,DVIN		;ATTEMPTING INPUT
	HLRZ	T2,FOPEXT	;ADDRESS OF EXT WORD
	PUSHJ	P,FOPTS		;CHECK DEVICE CHARACTERISTICS
	  JRST	FOPFNF		;SHORT DISPATCH VECTOR
	  PUSHJ	P,UDLK		;DO THE LOOKUP
	  JRST	FOPLER		;LOOKUP ERROR
FOPFNF:	;HERE ON UPDATE OR APPEND FILE NOT FOUND
	HRR	M,FOPBLK	;POINT TO BLOCK
	HLRZ	T1,FOPBLK	;GET LENGTH
	CAIL	T1,UUXPRV+1	;LONG BLOCK?
	PUSHJ	P,PUTWDU##	;YES--STORE COUNT BACK
FOPEN7:	TLNN	P2,FOP.EN	;NEED AN ENTER?
	JRST	FOPEN8		;NO--CHARGE AHEAD
	HRR	M,FOPBLK	;GET BLOCK ADR
	SKIPGE	P1		;IF EXTENDED UUO
	AOSA	M		;POINT M AT THE PPN WORD
	HRRI	M,UUNPPN-UUNNAM(M)	;POINT TO PPN WORD
	MOVE	T1,FOPTMP	;INDICATE ENTER IN SAME DIRECTORY AS LOOKUP
	TLNE	P2,FOP.LK	;DON'T RESTORE PPN WORD IF LOOKUP
				; WASN'T DONE.
	PUSHJ	P,PUTWDU##	;..
IFN FTDSIM,<
	MOVE	T1,FOPFLG
	MOVSI	T2,DEPSIM	;IF SIMULTANEOUS ACCESS,
	TLNE	T1,FOP.MA	;...
	IORM	T2,DEVJOB(F)	;LIGHT A BIT IN THE DDB
>
	MOVEI	T1,DEPPAL##	;IF PREALLOCATE,
	TLNE	P2,FOP.AL
	IORM	T1,DEVPAL##(F)	;TELL FILUUO
	HRR	M,FOPBLK	;GET BLOCK POINTER
	MOVE	T4,DEVSER(F)	;SETUP T4 FOR UDEN
	MOVSI	T1,DVOUT	;ATTEMPTING OUTPUT
	HLRZ	T2,FOPEXT	;ADDRESS OF EXT WORD
	PUSHJ	P,FOPTS		;CHECK DEVICE CHARACTERISTICS
	  JRST	FOPEN8		;SHORT DISPATCH VECTOR
	  PUSHJ	P,UDEN		;DO THE ENTER
	  JRST	FOPEER		;ENTER ERROR
FOPEN8:	TLNN	P2,FOP.RN	;RENAME FUNCTION?
	JRST	FOPN8A		;NO, PROCEED
	HRR	M,FOPAP		;ARGUMENT POINTER
	HRRI	M,5(M)		;POINT TO RENAME/DELETE BLOCK
	PUSHJ	P,GETWDU##	;GET ADDRESS OF RENAME/DELETE BLOCK
	HLR	M,T1		;ADDRESS OF BLOCK TO M
	HRRM	M,FOPBLK	;SAVE ADDRESS OF THE BLOCK
	PUSHJ	P,GETWDU##	;FIRST WORD OF THE BLOCK
	TLNN	T1,-1		;EXTENDED BLOCK
	HRRI	M,UUXNAM(M)	 ;YES, POINT AT THE FILE NAME
	MOVEI	T1,0		;ASSUME DELETE
	TLNE	P2,FOP.DL	;IS IT THE DELETE FUNCTION?
	PUSHJ	P,PUTWDU##	;YES, STORE A ZERO IN THE RENAME BLOCK
	MOVEI	T1,UUNEXT-UUNNAM(M) ;WHERE THE EXTENSION IS STORED
	HRLZM	T1,FOPEXT	;SAVE THAT IN CASE OF AN ERROR
	MOVE	T1,DEVMOD(F)	;DEVICE CHARACTERISTICS
	TLNN	T1,DVLNG	;LONG DISPATCH VECTOR?
	JRST	FOPN8A		;NO, DON'T ATTEMPT A RENAME
	HRR	M,FOPBLK	;RESTORE ADDRESS OF THE RENAME BLOCK
	MOVSI	T1,DEPFFA	;SO THE CLOSE WILL HAPPEN
	ANDCAM	T1,DEVJOB(F)	; IN FILUUO (CLRSTS)
	MOVE	T4,DEVSER(F)	;ADDRESS OF DEVICE DISPATCH VECTOR
	PUSHJ	P,URENAM	;DO THE RENAME
	  JRST	FOPLER		;RENAME ERROR
FOPN8A:	HRRZ	T1,FOPFLG	;GET # OF ARGUMENTS
	CAIGE	T1,7		;PATH BLOCK GIVEN
	JRST	FOPEN9		;NO--ALL IS WELL
	HRR	M,FOPAP		;GET ARG POINTER
	HRRI	M,6(M)		;POINT TO PATH WORD
	PUSHJ	P,GETWDU##	;FETCH POINTER
	MOVEM	T1,FOPTMP	;SAVE IN PDL
	HRR	M,T1		;PATH BLOCK
	HLRZ	T1,T1		;GET SIZE
	CAIGE	T1,3		;INTERESTING CASE
	JRST	FOPEN9		;NO--RETURN
	HRRZ	T1,P1		;CHANNEL #
	PUSHJ	P,PUTWDU##	;STORE FOR PATH. UUO
	MOVE	T1,FOPTMP	;PRESET AC
	PUSHJ	P,PTHUUO##	;DO THE PATH UUO
	  JFCL			;SHULD NEVER FAIL
FOPEN9:	MOVE	P2,FOPFLG	;GET FLAGS
	TLNN	P2,FOP.NF	;CREATING INSTEAD OF UPDATING
	JRST	FOPN9A		;NO--CONTINUE
	MOVSI	T1,DEPFFA	;YES--FORCE FILE INTO
	IORM	T1,DEVJOB(F)	; UPDATE MODE
	HRRI	M,0		;NO SPECIAL STUFF
	PUSHJ	P,CLOSE1	; ..
	PUSHJ	P,WAIT1##	; ..
FOPN9A:	SKIPE	P2,FOPFLG	;GET FLAGS
	TLNN	P2,FOP.AP	;WANT TO APPEND?
	JRST	FOPWIN		;NO--ALL DONE
	MOVE	T1,DEVMOD(F)	;IS THIS A DISK
	TLNN	T1,DVDSK	; ..
	JRST	FOPN11		;NO, ALL DONE UNLESS AN MTA
;HERE TO APPEND TO A DISK FILE
	MOVE	S,DEVIOS(F)	;GET STATUS BITS
	HRRZ	T3,DEVACC##(F)	;ADDRESS OF A.T.
	MOVE	T1,ACCWRT##(T3)	;SIZE OF FILE IN BLOCKS
	LDB	T2,PIOMOD##	;GET THE MODE
	CAIL	T2,SD		;DUMP MODE?
	JRST	FOPN10		;YES--CAN NOT MERGE DATA
	LDB	T2,ACZLBS##	;WORD IN LAST BLOCK
	TRNN	T2,BLKSIZ##-1	;IF FULL THERE IS NO NEED
	JRST	FOPN10		; TO READ IT
;AT THIS POINT WE READ C(T2) WORDS FROM BLOCK C(T1) INTO BUFFER AT C(T3)
	MOVEM	T2,FOPBLK	;SAVE WORD COUNT
	MOVEM	T1,FOPTMP	;SAVE BLK #
	HLRZ	U,DEVBUF(F)	;GET RING ADR
IFN FTKA10,<TLO	U,R>
	PUSHJ	P,OUTF		;ZERO BUFFER
	HRRZ	T3,DEVOAD(F)	;READ TO HERE
	MOVN	T2,FOPBLK	;NEG. WORD COUNT
	HRLZ	T2,T2		; ..
	HRRI	T2,1(T3)	; ..
	HRLM	T2,DEVUVA##(F)	;SAVE IN CASE CHECKSUM NEEDED
	ADDI	T2,(R)		;FOR MAPIO TO REMOVE
	MOVEM	T2,DEVDMP##(F)	;SAVE IN DDB
	MOVE	W,FOPTMP	;BLOCK #
	PUSHJ	P,FUSETO##	;SETUP POINTERS
	MOVEM	S,FOPTMP	;SAVE STATUS
	TRO	S,D		;SET DUMP MODE
	TLZ	S,IO		;READING
	PUSHJ	P,UUOSET##	;MAKE EVERYTHING OK
	  JFCL			;CAN NOT MISS
	PUSHJ	P,UUOPWQ##	;DO THE I/O
	PUSHJ	P,PWAIT1##	;WAIT FOR IT
	ANDI	S,740000	;PRESERVE ERROR BITS
	IORB	S,FOPTMP	;RESTORE OLD MODE
	MOVEM	S,DEVIOS(F)	;SAVE IN DDB
	MOVEI	J,BLKSIZ##	;WORDS IN BUFFER
	SUB	J,FOPBLK	;MINUS WORDS WE READ
	HLRZ	U,DEVBUF(F)	;RING HEADER
IFN FTKA10,<TLO	U,R>
	HRRZ	T2,DEVOAD(F)	;FOR BYTE POINTER
	ADD	T2,FOPBLK
	PUSHJ	P,IOSETC	;STORE CORRECT DATA IN HEADER
	MOVE	J,.C0JOB##	;RESET J
	MOVE	T1,DEVREL##(F)	;LAST BLOCK WRITTEN
	SUBI	T1,2		;REWRITE IT
FOPN10:	AOS	W,T1		;BLOCK TO WRITE
	PUSHJ	P,FUSETO##	;SET POINTERS
	JRST	FOPWIN		;ALL DONE
FOPN11:	TLNN	T1,DVMTA	;MAGTAPE?
	JRST	FOPWIN		;NO, ALL DONE
	HRRI	M,16
	PUSHJ	P,DOMTAP	;YES, SKIP TO EOF
	  JRST	FOPXIT		;IO ERROR, LOSE
	HRRI	M,7
	PUSHJ	P,DOMTAP	;BACKSPACE OVER EOF
	  JRST	FOPXIT
	LDB	T1,PIOMOD
	CAIL	T1,SD		;IF DUMP MODE,
	JRST	FOPWIN		; WE ARE DONE
	PUSHJ	P,DOMTAP	;BACKSPACE OVER LAST DATA RECORD
	  JRST	FOPXIT		;IO ERROR
	HLRZS	U,DEVBUF(F)	;TURN OUTPUT HDR INTO INPUT HDR
IFN FTKA10,<TLO U,R>
	PUSHJ	P,OUTF		;ZERO BUFFER
	HRRZ	T1,DEVOAD(F)
	HRRM	T1,DEVIAD(F)	;READ INTO OUTPUT BUFFER
IFN FTKA10,<TLO T1,R>
	EXCTUX	<MOVE T2,@T1>	;PICK UP PNTR TO NEXT BUF
	EXCTUU	<HRRM T1,@T1>	;TURN IT INTO A 1-BUFFER INPUT RING
	MOVEM	T2,FOPTMP	;SAVE NEXT BUFFER LOC
	PUSHJ	P,TPMIN##	;READ IN THE LAST RECORD
	LDB	T1,PUUOAC##	;CHAN NUMBER
	TLO	F,OUTPB		;IN CASE CLOSE WITH NO OUTPUTS -
	MOVEM	F,USRJDA##(T1)	; TAPUUO WILL IGNORE IF OUTPB=0
	PUSHJ	P,WAIT1		;WAIT FOR IT
	MOVE	U,DEVBUF(F)	;TURN IT BACK INTO AN OUTPUT HDR
	HRLZM	U,DEVBUF(F)	;CANT DO INPUT AFTER WRITING A TAPE
IFN FTKA10,<TLO U,R>
	HRRZ	T1,DEVOAD(F)	;WHERE WE READ
	MOVE	T3,FOPTMP
IFN FTKA10,<TLO T1,R>
	EXCTUU	<MOVEM T3,@T1>	;RESTORE BUFFER RING
	ADDI	T1,1
	EXCTUX	<MOVE T2,@T1>	;PICK UP WORDCOUNT
	HLRZ	J,T3		;MAX WORDCOUNT(+1) OF BUFFER
	SUBI	J,1(T2)		;AMOUNT LEFT
	JUMPE	J,FOPN12	;INIT NEW BUFFER IF NO ROOM IN THIS ONE
	ADDI	T2,-1(T1)	;POINT T2 TO LAST DATA IN BUFFER FOR IOSETC
	PUSHJ	P,IOSETC	;SET UP RING HEADER
	PUSHJ	P,DOMTAP	;BACKSP OVER RECORD SO WILL REWRITE IT
	  JRST	FOPXIT		;LOST!
	JRST	FOPWIN		;AND TELL USER HE WON
FOPN12:	SUBI	T1,1		;POINT AT RIGHT WORD FOR BUFCLR
	PUSHJ	P,BUFCLR	;ZERO THE BUFFER
	  JFCL			;SHOULD NEVER HAPPEN
	JRST	FOPWIN		;AND WE WON

DOMTAP:	PUSHJ	P,MTAPE0##	;TEL TAPUUO WHAT TO DO
	TRNN	S,IODERR!IODTER!IOIMPM
	AOSA	(P)		;WON
	MOVEI	T1,1		;LOST, ERROR CODE=1
	POPJ	P,		;RETURN TO CALLER
;HERE TO DO A USETI AND RETURN STATUS
FUSTI:	SKIPA	W,[FUSETI##]	;DISPATCH TO USETI
;HERE TO DO A USETO AND RETURN STATUS
FUSTO:	MOVEI	W,FUSETO##	;DISPATCH TO USETO
	PUSHJ	P,VALUUO##	;SETUP F AND MAKE SURE DEVICE IS INITED
	  JRST	FOPILU		;NOT A DISK
	HRRZ	T4,FOPFLG	;NUMBER OF ARGS
	CAIE	T4,2		;MUST BE EXACTLY TWO
	JRST	FOPILU		;IF NOT, LOSE
	PUSHJ	P,GETWD1##	;GET THE BLOCK NUMBER
	EXCH	T1,W		;BLOCK NUMBER IN W
	PUSHJ	P,(T1)		;CALL USET CODE IN FILSER
	HRRZ	T1,DEVIOS(F)	;I/O STATUS
	TRNN	T1,742000	;ERRORS OR END OF FILE?
	AOS	(P)		;NO, SKIP RETURN TO THE USER
	JRST	FOPXIT		;DONE

;HERE TO CLOSE A FILE AND RETURN STATUS

FCLOS:	MOVE	T1,P1		;COPY CHANNEL
	PUSHJ	P,DVCNSG	;REAL DEVICE
	 JRST	FCLOSI		;NO--RETURN IOIMPM
	HRRZ	T2,FOPFLG	;GET LENGTH
	SOSE	T1,T2		;ONLY 1 WORD?
	PUSHJ	P,GETWD1##	;NO--GET FLAGS
	HRR	M,T1		;COPY TO CORRECT PLACE
	MOVSI	T1,DEPFFA	;SET TO JUST UPDATE RIB
	MOVSI	T2,FOP.UR	;WANT REAL CLOSE?
	TDNE	T2,FOPFLG	; ..
	IORM	T1,DEVJOB(F)	;NO--SET DEPFFA
	PUSHJ	P,CLOSE1	;CLOSE THE FILE
	PUSHJ	P,WAIT1##	;WAIT FOR I/O
	HRRZ	T1,DEVIOS(F)	;GET STATUS
	TRNN	T1,740000	;ERROR BITS?
	AOS	(P)		;NO--SKIP RETURN
	JRST	FOPXIT		;DONE

FCLOSI:	MOVEI	T1,IOIMPM	;SET IOIMPM
	PJRST	FOPXIT		;DONE
;FILOP. EXIT ROUTINES
FOPWIN:	MOVNI	T1,1		;INDICATE SUCCESS
	JRST	FOPXIT		;STANDARD EXIT

;RIB ERROR
FOPRER:	SKIPA	T1,[TRNERR]
;ILLEGAL UUO
FOPILU:	MOVEI	T1,ILUERR	;ERROR CODE
	JRST	FOPXI1		;EXIT UUO

;OPEN ERROR
FOPOER:	TLZ	M,400000
	HRR	M,FOPAP		;ARG POINTER
	HRRI	M,2(M)		;POINT TO DEVICE
	PUSHJ	P,GETWDU##	;FETCH ARGUMENT
	PUSHJ	P,DEVSRG	;REAL DEVICE?
	  JRST	FOPNSD		;NO SUCH DEVICE
	SKIPA	T1,[DNAERR]	;DEVICE NOT AVAIL.
FOPNSD:	MOVEI	T1,NSDERR	;NO SUCH DEVICE
	JRST	FOPXI1		;DONE

;LOOKUP AND ENTER ERRORS
FOPLER:	TDZA	T4,T4		;FLAG LOOKUP FAILURE
FOPEER:	MOVNI	T4,1		;ENTER FAILURE
	HLR	M,FOPEXT	;ADDRESS OF EXTENSION
	PUSHJ	P,GETWDU##	;GET THE WORD
	IORI	T4,(T1)		;COMBINE WITH FLAG
	JUMPN	T4,FOPXI0	;JUMP IF NOT FNFERR ON LOOKUP
	MOVSI	P2,FOP.NF	;SET FILE-NOT-FOUND FLAG
	IORB	P2,FOPFLG	; ..
	TLNN	P2,FOP.EN	;ENTER NEEDED
	JRST	FOPXI0		;NO--FATAL ERROR ON READ
	HRR	T1,FOPEXT	;RESTORE DATE BITS
	PUSHJ	P,PUTWDU##	;STORE FOR ENTER
	JRST	FOPFNF		;TRY ENTER
FOPXI0:	TLZ	T1,-1		;JUST ERROR NUMBER IN T1
	MOVEI	T2,DEPPAL##		;IF THIS IS A DSK,
	MOVE	T3,DEVMOD(F)
	TLNE	T3,DVDSK
	ANDCAM	T2,DEVPAL##(F)	; CLEAR PRE-ALLOCATE
FOPXIT:	MOVSI	T2,DEPFOP!DEPFFA ;MUST CLEAR THESE OR DDB 
				; CAUSE PROBLEMS ON NEXT UUO
	ANDCAM	T2,DEVJOB(F)	;ZAP!
IFN FTVM,<
	SETZM	.UPMP+.UPFOP	;FILOP. IS DONE
>
	MOVE	T2,DEVMOD(F)
	TLNE	T2,DVDSK	;IF A DSK
	SETZM	DEVUPP##(F)	;ZERO "IN YOUR BEHALF" PPN
	JUMPL	T1,CPOPJ1##	;ALL DONE IF NO ERRORS
FOPXI1:	LDB	M,[POINT 4,FOPAP,12] ;GET AC NUMBER
	PJRST	PUTWDU##	;STORE CODE AND NON-SKIP RETURN

IFN FTVM,<

;SUBROUTINE TO ENSURE A LOOKUP/ENTER/RENAME BLOCK IS IN CORE
;CALLING SEQUENCE:
;	HRRI	M,ADDRESS OF THE BLOCK
;	PUSHJ	P,FCLERB

FCLERB:	PUSHJ	P,GETWDU##	;GET FIRST WORD OF BLOCK
	TLNN	T1,-1		;EXTENDED UUO?
	TRZA	T1,400000	;YES--CLEAR OLD STYLE BIT
	MOVEI	T1,4		;NO--4 WORDS
	HRRZ	T2,M		;START ADDRESS
	ADDM	T1,T2		;PLUS LENGTH GIVES END
	MOVEI	T1,(M)		;RESTORE START
	PJRST	TRNGE##		;MAKE SURE ALL OK

>;END IFN FTVM

;SUBROUTINE TO TEST WHETHER A DEVICE CAN DO THE TYPE OF I/O
; INDICATED AND WHETHER IT HAS A LONG DISPATCH VECTOR OR NOT
;CALLING SEQUENCE:
;	MOVSI	T1,DVIN OR DVOUT
;	MOVE	T2,ADDRESS OF THE EXTENSION WORD
;	PUSHJ	P,FOPTS
;RETURNS CPOPJ IF I/O DIRECTION IS LEGAL BUT DEVICE HAS A
; SHORT DISPATCH VECTOR, CPOPJ1 IF I/O DIRECTION IS LEGAL AND
; DEVICE HAS A LONG DISPATCH VECTOR, CPOPJ2 IF THE I/O DIRECTION
; IS ILLEGAL (FNFERR STORED IN THE EXTENSION WORD OF THE
; LOOKUP/ENTER BLOCK)
;PRESERVES T4

FOPTS:	TDNE	T1,DEVMOD(F)	;LEGAL I/O DIRECTION?
	JRST	FOPTS1		;YES
	HRR	M,T2		;NO, ADDRESS OF EXTENSION WORD
	PUSHJ	P,GETWDU##	;GET THE EXTENSION WORD
	HRRI	T1,FNFERR	;FILE NOT FOUND ERROR
	PUSHJ	P,PUTWDU##	;STORE THAT FOR THE USER
	JRST	CPOPJ2##	;ILLEGAL I/O DIRECTION RETURN
FOPTS1:	MOVSI	T1,DVLNG	;DEVICE HAS A LONG DISPATCH VECTOR BIT
	TDNE	T1,DEVMOD(F)	;DOES THE DEVICE HAVE A LONG DISPATCH VECTOR?
	AOS	(P)		;YES
	POPJ	P,		;NO
	SUBTTL PERF. UUO

	PERF.==CPOPJ##
> ;END FT5UUO
	SUBTTL	CLOSE UUO

;FOR PURPOSES OF COMMENTING THIS SUBROUTINE THE
;TERM 'BUFFER HEADER' SHALL REFER TO THE 3 WORD HEADER
;WHICH IS USED BY THE USER PROGRAM AND THIS EXEC FOR
;REFERING TO THE RING BUFFERS.

;THE CONTENTS OF THE 3 WORD HEADER (AS SET BY THE MONITOR
;		ON EACH INPUT AND OUTPUT UUO).
;		BIT 18-35=ADDRESS OF SECOND WORD OF THE
;		CURRENT BUFFER IN RING WHICH USER IS REFERENCING
;	WORD 2:	BYTE POINTER TO CURRENT ITEM.
;	WORD 3:	POSITIVE ITEM COUNT (NO. OF ITEMS LEFT ON
;		INPUT, NO. OF FREE ITEMS TO GO ON OUTPUT).

;EACH BUFFER IN THE RING HAS FOLLOWING FORMAT (AS THE USER SEES IT)

;	WORD 1:	RESERVED FOR BLOCK NUMBER FOR FIXED ADDRESS DEVICES
;	WORD 2:	BIT 0=USE BIT FOR THIS BUFFER
;		BIT 1-17=NO. OF WORDS WHICH FOLLOW (LENGTH OF BUFFER)/
;		BIT 18-35=ADDRESS OF SECOND WORD OF NEXT BUFFER IN RING
;	WORD 3:	LH=LINK TO NEXT BLOCK (SET BY MONITOR FOR DECTAPE)
;		RH=NO. OF WORDS OF DATA WHICH FOLLOW (USUALLY
;		SET BY EXEC EXCEPT IF THE USER HAS SPECIFIED
;		THAT HE WANTS TO COMPUTE WORD COUNT
;		HIMSELF INSTEAD OF HAVING THE MONITOR DO IT
;		USING THE BYTE POINTER IN THE 3 WORD HEADER).





;CALLING SEQUENCE
;	CLOSE D,
;	EXIT		ALWAYS RETURNS HERE
; THIS ROUTINES PROCESSES THE CLOSE UUO AND DETERMINES WHETHER THE
;OUTPUT ROUTINE SHOULD BE CALLED IF OUTPUT WERE ACTIVE, CLEARS
;THE INPUT BUFFER AREA IF INPUT WERE ACTIVE, AND CLEARS THE 
;ITEM COUNTS OF BOTH INPUT AND OUTPUT HEADERS SERVING TO BOTH
;TERMINATE THE USE OF THE DEVICE AND SET THE I/O ROUTINES TO
;ACCEPT ANOTHER INPUT OR OUTPUT COMMAND IN A CLEAR STATE.
;IN THE CASE OF OUTPUT DEVICES, THE CLOSE ROUTINE OF THE DEVICE HANDL-
;ING ROUTINE IS CALLED IN CASE ANY SPECIAL HANDLING IS REQUIRED.
CLOSE1::
IFN FTEQDQ,<
	PUSHJ	P,ENQCLS##	;CHECK FOR LOCKS STILL OUT
	SKIPA			;THERE WERE SOME
	JRST	ENQOK		;THERE WERE NO LOCKS
NQABRT:	MOVEI	T4,IOBKTL	;SET ERROR BIT...
	IORM	T4,DEVIOS(F)	;... IN DEVIOS
	POPJ	P,		;ABORT UUO
ENQOK:	>;END OF IFN FTEQDQ
IFN FTVM,<SETZM .UPMP+.UPFOP>
	HRRZ	T4,DEVSER(F)	;RESTORE T4
	PUSHJ	P,WAIT1##	;WAIT UNTIL DEVICE IS INACTIVE
	TRNN	M,CLSIN		;SUPPRESS INPUT CLOSE?
	TLOE	F,ICLOSB	;NO. INPUT ALREADY BEEN CLOSED?
	JRST	UCLS2		;YES
	LDB	T1,PIOMOD##	;NO
	CAIGE	T1,SD		;DUMP MODE?
	JRST	UCLSBI		;NO. CLOSE BUFFERED INPUT.
UCLS5:	PUSHJ	P,DCLI(T4)	;YES. DISPATCH TO DEVICE DEP. ROUTINE
	JRST	UCLS2		;MUST NOT DESTROY M,F,T4,W, OR P1-P4
UCLSBI:	MOVE	T1,DEVMOD(F)
	TLNN	T1,DVDTA	;IS IT A DTA, OR
	TLNE	F,INBFB+INPB	;WAS AN INPUT BUFFER SETUP?
	JRST	UCLS4		;YES
	TLNE	T1,DVDSK	;CLOSING A DISK FILE ?
	JRST	UCLS5		;YES, DO DEVICE DEPENDENT CLOSE ANYWAY.
	JRST	UCLS2		;NO, CLOSE NOT NECESSARY.
UCLS4:	TLNE	T1,DVLNG	;IS THIS A LONG DISPATCH TABLE?
	PUSHJ	P,DCLI(T4)	;YES, CLOSE INPUT
	HRRZ	T2,DEVBUF(F)
	JUMPE	T2,UCLS2	;IF NO BUFFER, LOOK FOR OUTPUT SIDE
IFN FTKA10,<
	HRLI	T2,R
>
	HRRZ	T1,T2		;ADDRESS OF THE FIRST WORD OF THE BUFFER HEADER
	PUSHJ	P,UADRCK	;MAKE SURE ITS IN CORE
	EXCTUX	<HRRZ	U,@T2>	;FIRST WORD OF 3 WORD BUFFER HEADER
	EXCTUX	<HRR	T2,@T2>	;REMEMBER CURRENT BUFFER IN T2
	HRLZI	T1,IOUSE	;USED BOTH FOR HEADER AND EACH BUFFER
	JUMPE	U,UCLS1		;HAS A RING BEEN SETUP?(NO IF 0)
	HLL	U,T2		;YES
	MOVEI	T1,(U)		;IS ADDRESS SPECIFIED BY CONTENTS OF
	PUSHJ	P,UADRCK	;FIRST WORD OF 3 WORD BUFFER HEADER IN BOUNDS?
	MOVEI	T3,10000	;ONLY ALLOW 10000 BUFFERS IN A RING
				; SETUP COUNT IN CASE USER HAS MESSED
				; BUFFER RING INTO A FIGURE SIX
UCLS0:	EXCTUX	<HRR	U,@U>	;ADVANCE CURRENT INPUT BUFFER ADDRESS
	MOVEI	T1,(U)		;IS ADDRESS OK?
	PUSHJ	P,UADRCK
	HRLZI	T1,IOUSE	;USE BIT FOR BOTH HEADER AND BUFFERS
	EXCTUU	<ANDCAM	T1,@U>	;YES, CLEAR USE BIT.
	CAME	T2,U		;DONE?
	SOJG	T3,UCLS0	;NO, HAVE WE SCANNED 10000 BUFFERS?
				; (WHICH MAY BE THE SAME)
				; YES
UCLS1:	HRR	U,DEVBUF(F)
	HLL	U,T2		;SET LH(U)
	EXCTUU	<IORM	T1,@U>	;FLAG AS VIRGIN BUFFER IN 3 WORD HEADER
	ADDI	U,2		;JBFCTR:=0
IFN FTVM,<
	HRRZ	T1,U
	PUSHJ	P,UADRCK	;MAKE SURE ITS IN CORE
>
	EXCTXU	<SETZM	@U>	;CLEAR INPUT ITEM COUNT.
	MOVE	S,[XWD IOEND,IODEND]
	MOVE	T1,DEVMOD(F)
	TLNE	T1,DVTTY	;IS THIS A TTY?
	TLO	S,FRCEND##	;YES, CLEAR OTHER EOF FLAG
	ANDCAB	S,DEVIOS(F)
UCLS2:	PUSHJ	P,UCLS3		;STORE UPDATED F
	TRNN	M,CLSOUT	;SUPPRESS OUTPUT CLOSE?
	TLOE	F,OCLOSB	;NO. OUTPUT ALREADY CLOSED?
	JRST	UCLS3		;YES
IFN	FT2REL,<
	PUSHJ	P,RELSEG##	;CLEAR SHARED SEG NAME IF FILE JUST CLOSED HAS
				; EXTENSION .SHR AND SEG HAS SAME DIRECTORY AND NAME
>
	LDB	T1,PIOMOD##	;NO.
	CAIGE	T1,SD		;DUMP MODE?
	JRST	UCLSBO		;NO. CLOSE BUFFERED OUTPUT
UCLS7:	HRRZ	T4,DEVSER(F)	;RESTORE T4
	PUSHJ	P,DCL(T4)	;YES. DISPATCH TO DEVICE DEP. ROUTINE
	JRST	UCLS3
UCLSBO:	TLNN	F,OUTBFB+OUTPB	;WAS AN OUTPUT BUFFER SET UP?
	JRST	UCLS6		;NO
	HLRZ	U,DEVBUF(F)	;VIRGIN OUTPUT BUFFER?
	JUMPE	U,UCLS6		;IF NO BUFFER, DON'T CLOSE UNLESS DISK
IFN FTKA10,<
	HRLI	U,R
>
	PUSHJ	P,CLSCHK
	EXCTUX	<SKIPG	@U>
	JRST	UCLS6		;YES, DO NOT CLOSE UNLESS IT IS A DISK FILE
	PUSHJ	P,WAIT2X	;ENSURE ALL BUFFERS WRITTEN
UCLS2B:	MOVE	T4,DEVSER(F)
	MOVEI	T1,DEPAIO!DEPOND
	ANDCAM	T1,DEVAIO(F)	;DON'T ALLOW NON-BLOCKING I/O DURING CLOSE
	PUSHJ	P,DCL(T4)	;CLOSE OUTPUT BUFFER
	HLRZ	U,DEVBUF(F)
IFN FTKA10,<
	HRLI	U,R
>
	HRLZI	T1,IOUSE
	EXCTUU	<IORM	T1,@U>
	ADDI	U,2
	EXCTXU	<SETZM	@U>	;JBFCTR:=0
	PUSHJ	P,WAIT1##
	TLO	F,OCLOSB	;SET OCLOSB AFTER OUTPUT IS COMPLETE
UCLS3:	LDB	T1,PUUOAC##
	HLLM	F,USRJDA##(T1)
	POPJ	P,		;EXIT THIS UUO

UCLS6:	MOVSI	T1,DVDSK!DVDTA
	TDNN	T1,DEVMOD(F)	;CLOSING A DISK OR DTA FILE ?
	JRST	UCLS3		;NO
	PUSHJ	P,CLSCHK
	JRST	UCLS7		;YES, CALL DSK CLOSE ANYWAY

;SUBROUTINE TO CHECK LEGALITY OF BUF HEADER FOR CLOSE
CLSCHK:	HLRZ	T1,DEVBUF(F)	;START OF BUFFER HEADER
	JUMPE	T1,CPOPJ
IFN FTVM,<
	MOVEI	T2,2(T1)	;END
	PJRST	TRNGE##		;MAKE SURE ITS IN CORE
>
IFE FTVM,<
	PJRST	UADRCK
>
	SUBTTL	INBUF & OUTBUF UUO'S
;CALLING SEQUENCE
;	INBUF D,N
;	EXIT		RETURNS HERE IF MEMORY NOT EXCEEDED
;CALLING SEQUENCE
;	OUTBUF D,N
;	EXIT		RETURNS HERE IF MEMORY NOT EXCEEDED
; SETS UP AN N BUFFER RING FOLLOWING THE USER'S PROGRAM FOR DEVICE
; D AND INITIALIZES THE JOB BUFFER AREA HEADER:
;	JBFADR0:=1,	JBFADR 1-17:=0
;	JBFADR 18-35:=ADDRESS OF FIRST BUFFER IN RING
;INPUT SETS DEVIAD:=ADDRESS OF FIRST BUFFER IN RING
;OUTPUT SET DEVOAD:=ADDRESS OF FIRST BUFFER IN RING
;W IS RESTORED.



UINBF::	TLO	F,INBFB		;FLAG INBUF UUO DONE
	HRRZ	T2,DEVBUF(F)	;GET BUFFER HEADER ADDRESS
	JUMPE	T2,ADRERR##	;ADDRESS CHECK IF NO HEADER
	PUSHJ	P,BUFCLC	;SET UP BUFFER RING
	HRRM	T3,DEVIAD(F)	;DEVIAD:=ADDRESS OF FIRST BUFFER
				; IN RING
	MOVSI	T1,DVDSK+DVMTA	;IF A DSK,
	TDNE	T1,DEVMOD(F)	; SAVE THE NUMBER OF BUFFERS
	DPB	M,PINBFN##	; IN THE DDB
	HRRZ	T2,DEVBUF(F)	;T2:=INPUT BUFFER AREA HEADER ADDRESS
	JRST	UOBF1

UOUTBF::TLO	F,OUTBFB	;FLAG OUTBUF UUO DONE
	HLRZ	T2,DEVBUF(F)	;GET BUFFER HEADER ADDRESS
	JUMPE	T2,ADRERR##	;ADDRESS CHECK IF NO HEADER
	PUSHJ	P,BUFCLC	;SET UP BUFFER RING
	HLRZ	T2,DEVBUF(F)	;T2:=OUTPUT BUFFER AREA HEADER ADDRESS
	HRRM	T3,DEVOAD(F)	;DEVOAD:=ADDRESS OF FIRST BUFFER
				; IN RING
IFN FTMSGSER,<
	LDB	T1,PDVTYP##	;GET DEVICE TYPE BYTE
	CAIN	T1,<.TYMPX/.TYEST> ;MPX DEVICE
	EXCTUU	<HLLZS @T4>	;LIST NOT RING
>
UOBF1:
IFN FTKA10,<
	HRLI	T2,R		;RELOCATE BUFFER AREA HEADER ADDRESS
>
	HRRZ	T1,T2		;CHECK ADR OF BUF HEADER
	PUSHJ	P,UADRCK
	EXCTXU	<MOVEM	T3,@T2>	;JBFADR:=IOUSE,ADDRESS OF FIRST BUFFER
				; IN RING
	LDB	T1,PUUOAC##
	MOVEM	F,USRJDA##(T1)
	POPJ	P,		;EXIT THIS UUO
	SUBTTL	OPEN & INIT UUO'S

;OPEN UUO - PERFORMS SAME OPERATION AS INIT
;MAY BE USED EASILY BY REENTRANT PROGRAMS
;CALLING SEQUENCE FROM USER AREA
;	OPEN D,ADR
;	ERROR RETURN
;	DEVICE INITED

;LH(ADR)=0,RH(ADR)=DATA MODE THIS INIT
;C(ADR+1) = SIXBIT /NAME/
;LH(ADR+2)=OUTPUT BUFFER HEADER ADDRESS
;RH(ADR+2)=INPUT BUFFER HEADER ADDRESS


UOPEN::	PUSHJ	P,GETWDU##	;SET T1 TO CONTENTS OF FIRST ARG(IO STATUS BITS)
	AOJA	M,UINIT0	;MAKE UUO POINT TO ARG+1(WITH R STILL
				; IN INDEX FIELD)


;CALLING SEQUENCE
;	INIT D,MODUS	D=JOB DEVICE CHANNEL
;			MODUS=IORDEL,IOCON,IOWC,MODE.
;	SIXBIT/NAME/	DEVICE NAME
;	XWD OBUF,IBUF	BUFFER AREA HEADER ADDRESSES
;	EXIT1		DEVICE NOT AVAILABLE
;	EXIT2		DEVICE PROPERLY ASSIGNED
;THE LEFT HALF OF NAME CONTAINS THE THREE LETTER DEVICE MNEMONIC,
;   THE RIGHT HALF IS EITHER ZERO (SYSTEM WILL ASSIGN AN ARBITRARY
;   UNIT) OR NON-ZERO TO REQUEST A SPECIFIC UNIT (LEFT JUSTIFIED).
;IF THE SELECTED DEVICE IS NOT AVAILABLE, CONTROL RETURNS TO EXIT1.
;OTHERWISE, THE DEVICE IS ASSIGNED TO THE USER AND ATTACHED TO HIS
;CHANNEL D.  THE DEVICE IS INITIALIZED IN THE FOLLOWING MANNER AFTER
;IOACT IS ZERO:
;	IOBEG:=1
;	DATA MODE:=BITS 32-35 OF AC UUO
;	IOCON:=BIT 31 OF AC UUO
;	IOWC:=BIT 30 OF AC UUO
;	IORDEL:=BIT 29 OF AC UUO
;	IOACT:=IODEND:=IOBKTL:=IODTER:=IODERR:=IOIMPM:=0
;	JBFADR:=JBFCTR:=0 FOR THE SPECIFIED BUFFERS.
;	DEVBUF:=OBUF,IBUF
UINIT::	HRRZ	T1,M		;SAVE FIRST ARG(IO STATUS BITS) IN T1
	HRR	M,-1(P)		;SET UUO TO ADR+1 OF USER ARGS
IFN FTVM,<
	PUSHJ	P,UINIT0	;TRY TO INIT THE DEVICE
	  TDZA	T1,T1		;FAIL
	MOVEI	T1,1		;WIN, GIVE SKIP RETURN
	ADDI	T1,2		;ACCOUNT FOR THE ARGUMENTS
	ADDM	T1,-1(P)	;BUMP RETURN PAST THE ARGUMENTS
	POPJ	P,		;RETURN
>
IFE FTVM,<
	AOS	-1(P)		;SET RETURN SKIP THE 2 ARGUMENTS
	AOS	-1(P)
>
UINIT0:
IFN FTEQDQ,<
	PUSHJ	P,ENQCLS##	;ANY LOCKS OUT?
	JRST	NQABRT		;YES, ABORT UUO
>
	PUSHJ	P,SAVE3##	;SAVE P1
	PUSH	P,M		;HERE ON OPEN UUO, SAVE ADR+1 OF USER ARGS
	PUSH	P,T1		;SAVE IO STATUS BITS(FIRST ARG)
	SKIPE	F,USRJDA##(P1)	;IS A DEVICE ALREADY ASSIGNED TO THIS CHAN?
	CAMLE	P1,USRHCU##	;YES, IS THIS CHAN. LESS OR EQUAL TO HIGHEST
				; CHAN. FOR THIS USER?
	JRST	UINITA		;NO, NO PREVIOUS DEVICE TO RELEASE
	PUSHJ	P,RELEA0	;RELEASE PREVIOUS DEVICE ON THIS CHAN.
UINITA:	MOVE	M,-1(P)		;RESTORE M (ADR+1 OF 3 ARGS)
	PUSHJ	P,GETWDU##	;C(T1)=DEVICE NAME IF IN BOUNDS
				; DO NOT RETURN IF OUT OF BOUNDS(PRINT ERR AND STOP)
				; SET J TO CURRENT JOB NUMBER
IFN FTPHYO,<
	SKIPGE	(P)		;SIGN BIT OF MODE-WORD=1?
	HRLI	P1,PHONLY	;YES, SET FOR PHYSICAL DEVICES ONLY
>
	PUSHJ	P,DEVSRC	;SEARCH FOR DEVICE NAME
				; (SET SYSDEV BIT IN LH OF
				; F IF THIS IS SYSTEM TAPE)
	  TDZA T3,T3		;NO SUCH DEVICE - TRY GENERIC
	JRST	UINIT2		;FOUND PHY DEV (OR LOGICAL)
IFE	FTGSRC!FTNET,<
	PUSHJ	P,DEVSRC	;SEARCH FOR DEVICE
>
IFN FTGSRC!FTNET,<
	PUSHJ	P,DVSRSP	;DOES ANY DEV OF THIS TYPE EXIST?
>
	  JRST UINITE		;NO - ERROR
IFN FTSPL,<
	SKIPN	DEVCHR(F)	;IS IT A "FAKE" DDB
	SKIPA	T2,SPLBIT##(F)	;YES, GET BIT FROM TABLE
	LDB	T2,DEYSPL##	;YES. GET SPOOLING BIT
	HRRZS	T2		;CLEAR TYPE BIT
	TDNE	T2,JBTSPL##(J)	;JOB SPOOLING THIS DEV?
	JRST	UINIT2		;YES. OK
>	;END CONDITIONAL ON FTSPL
	MOVEI	T3,ASSPRG	;FLAG THAT INIT'ED DEV UNACCEPTABLE
	PUSH	P,F		;SAVE DDB LOC
IFE FTGSRC,<
	PUSHJ	P,DEVSRC	;SEARCH FOR DEVICE
>
IFN FTGSRC,<
	PUSHJ	P,DVASRC	;TRY TO FIND GENERICALLY
>
	  SKIPA	F,(P)		;RESTORE POSSIBLE DDB
	JRST	UINIT1		;WON - CONTINUE
	TRNE	T1,770000	;IS IT DEVX?
	TRNE	T1,7700
	JRST	UINITD		;NO - LOSE
UINIT1:	POP	P,(P)		;YES - WIN
UINIT2:	MOVE	T2,JBTSTS##(J)	;IS THIS JOB
	TLNE	T2,JLOG		; LOGGIN IN?
	JRST	UINI2A		;YES, CONTINUE
	MOVE	T2,DEVMOD(F)	;NO, MAKE SURE JOB
	TLNN	T2,DVDSK!DVTTY	; IS TRYING FOR VALID DEVICE
	JRST	UINITE		;NO, ERROR
UINI2A:	MOVE	M,(P)		;RESTORE USER'S MODE SETTING
	TLNE	M,-1-.OPALL	;ANY UNDEFINED OPEN BITS SET?
	JRST	ILLMOD##	;YES--BOMB THE USER
	PUSH	P,T1		;SAVE NAME USER SUPPLIED
IFN FTNUL,<
	CAME	T1,[SIXBIT /NUL/] ;ALL MODES ARE LEGAL FOR NUL:
>
	PUSHJ	P,CHKMOD	;CHECK FOR LEGAL MODE, IF NOT RIGHT DONT RETURN
IFE FTDISK,<
	MOVE	T1,DEVNAM(F)	;PHYSICAL DEVICE NAME
	CAME	T1,SYSTAP##	;SYSTEM TAPE DEVICE ?
	JRST	UINIT1		;NO, DISK OR NOT SYSTEM TAPE
	AOSE	STREQ##		;SYSTEM TAPE, INCREMENT REQUEST COUNT
	PUSHJ	P,STWAIT##	;SYSTEM TAPE BUSY, PUT JOB IN WAIT
	MOVEM	J,STUSER##	;SET THIS JOB AS ONLY USER OF SYSTEM TAPE
				; CONTROL C DOES NOT STOP JOB WHILE USING S. T.
>
	POP	P,T1		;RESTORE NAME
	MOVE	T3,DEVMOD(F)	;DEVICE CHARACTERISTICS
	TLNN	T3,DVDTA	;IS THIS DEVICE A DECTAPE?
	JRST	UINITB		;NO
	LDB	T2,IADPTR##	;YES, GE NO OF USER CHANS DEV INITED ON
	HRR	T3,T2		;SAVE OLD NUMBER
	AOS	T2		;INCREASE CHANNEL COUNT
	DPB	T2,IADPTR##	;YES, STORE UPDATED CHANNEL COUNT FOR THIS DEV(DTA)
UINITB:	MOVEI	T2,ASSPRG	;TRY TO ASSIGN IT BY PROGRAM
	SETZM	M
	PUSHJ	P,ASSASG
	JRST	UINIT6		;NOT AVAILABLE, GIVE ERROR RETURN(POP T1)
	POP	P,M		;RESTORE USER'S MODE SETTING
IFN FT5UUO,<			;MISC 5 SERIES UUO FEATURES?
	MOVE	T2,[XWD DEPIBC,DEPDEL!DEPDER!DEPAIO]
				 ;DISABLE ERROR LOGGING AND ERROR RECOVERY
	ANDCAM	T2,DEVSTA(F)	;MAKE SURE NOT DISABLED
	MOVSI	T3,DEPSIE
	ANDCAM	T3,DEVJOB(F)	;DISABLE SYNCH ON ERROR
	TLNN	M,.OPDEL	;IS USER TRYING TO DISABLE ERROR LOGGING?
	JRST	UINIT3		;NO, LEAVE ERROR LOGGING ENABLED
	MOVE	J,JOB##		;YES, CURRENT JOB NUMBER
	MOVE	T2,JBTPPN##(J)	;PROJ PROG NUMBER FOR CURRENT JOB
	MOVEI	T3,DEPDEL	;SETUP TO STORE DISABLE BIT IN DDB
	CAME	T2,FSFPPN##	;IS THIS USER FAILSAFE PPN [1,2]?
	CAMN	T2,UMDPPN##	;NO, IS THS USER MODE DIAG [6,6]?
	IORM	T3,DEVSTA(F)	;YES, USER PRIVILEGED TO DISABLE ERROR LOGGING
UINIT3:	LDB	T3,PDVTYP##	;SET DEVTYP WORD
	CAIE	T3,.TYPTY/.TYEST ;IS IT A PTY?
	JRST	UINIB1		;NO, TREAT BIT AS DEPDER
	MOVSI	T3,DVDIBP	;YES, GET BATCH PTY BIT
	ANDCAM	T3,DEVCHR(F)	;START WITH IT OFF
	PUSHJ	P,PRVJ##	;IS JOB PRIV'ED?
	  SKIPA			;YES, DO THE CHECK
	JRST	UINIB2		;NO, IGNORE THE BIT
	MOVSI	T3,DVDIBP	;LOAD BATCH PTY BIT AGAIN
	TLNE	M,.OPBJP	;DID USER REQUEST IT?
	IORM	T3,DEVCHR(F)	;YES TURN IT ON
	JRST	UINIB2		;AND CONTINUE ON
UINIB1:	MOVEI	T3,DEPDER	;SETUP FOR POSSIBLE DISABLE ERROR RETRY
	TLNE	M,.OPDER	;USER WANT ERROR RETRY DISABLED?
	IORM	T3,DEVSTA(F)	;YES, SET DISABLE IN DDB
UINIB2:	MOVEI	T3,DEPAIO	;NON-BLOCKING I/O ON THIS FILE?
	TLNE	M,.OPAIO	;SKIP IF NO
	IORM	T3,DEVAIO(F)	;YES, FLAG ASYNCHRONOUS I/O
	MOVSI	T3,DEPIBC	;INHIBIT BUFFER CLEAR BIT
	TLNE	M,.OPIBC	;DOES THE USER WANT TO INHIBIT CLEARING OUTPUT BUFFER?
	IORM	T3,DEVTYP(F)	;YES, REMEMBER THAT
	MOVSI	T3,DEPSIE	;BIT FOR SYNCH ON I/O ERROR
	TLNE	M,.OPSIE	;TEST IF USER WANTS IT
	IORM	T3,DEVJOB(F)	;YES - SET FLG IN DDB
>				;END 5 SERIES UUO FEATURES
	HRRZ	T2,DEVSER(F)	;GET DISPATCH ADDRESS
;DSZ CALL NEVER RETURNS FOR DC44 DEVICES WHICH ARE DOWN
;THIS EXITS VIA DWNP11 IN ERRCON
	PUSHJ	P,DSZ(T2)	;LET ROUTINE PUT IN BUF SIZE
	DPB	T1,PBUFSZ##	;STORE THE BUFFER SIZE IN DEVCHR WORD
	PUSHJ	P,SETIOS	;SET DDB S STATUS WORD FROM RT. HALF OF AC UUO
				; WAIT FOR DEVICES TO BECOME INACTIVE IN CASE IT IS
				; INITED ON A DIFFERENT CHANNEL(OR MONITOR COMMAND
				; RESPONSE ON TTY)
	MOVSI	S,IOBEG
	IORB	S,DEVIOS(F)
	HRRZS	P1		;CLEAR LH(P1) FOR UINITL LOOP
UINITL:	SKIPL	USRHCU##	;SAVGET (CHAN 0)?
	CAMG	P1,USRHCU##	;NO, IS THIS CHAN. .GT. HIGHEST CHAN. IN USE?
	JRST	UINITC		;NO
	AOS	T1,USRHCU##	;YES, BUMP HIGHEST SO FAR BY ONE
	SETZM	USRJDA##(T1)	;AND CLEAR IT OUT
	JRST	UINITL		;AND KEEP LOOKING
UINITC:	MOVEM	F,USRJDA##(P1)
	TLO	F,INITB+ICLOSB+OCLOSB;SET INIT UUO BIT
				;PREVENT SUPERFLUOUS CALLS TO CLOSE (SEE LOOKUP,ENTER)
	AOS	M,(P)		;ADVANCE TO 3RD ARG(BUFFER HEADER)
	PUSHJ	P,GETWDU##	;C(T1)=BUFFER HEADER ARG
	HLRZ	T2,T1		;OUTPUT BUFFER HEADER FROM USER
	JUMPE	T2,UINIT4	;WAS ONE SPECIFIED?
	HRLM	T2,DEVBUF(F)	;SAVE BUFFER HDR LOC
	TLO	F,OBUFB		;SET OUTPUT BUFFER SPECIFIED BIT
	PUSHJ	P,UINITZ	;INITIALIZE OUTPUT BUFFER HEADER
UINIT4:	PUSHJ	P,GETWDU##	;USER'S ARG AGAIN
	HRRZ	T2,T1		;INPUT BUFFER HDR
	JUMPE	T2,UINIT5	;WAS ONE SPECIFIED?
	HRRM	T2,DEVBUF(F)
	TLO	F,IBUFB		;SET INPUT BUFFER SPECIFIED BIT
	MOVSI	S,IOEND		;CLEAR END OF FILE FLAG
	ANDCAB	S,DEVIOS(F)	;AND RETAIN S
	PUSHJ	P,UINITZ	;INITIALIZE INPUT BUFFER HEADER
UINIT5:	MOVEM	F,USRJDA##(P1)	;STORE UUO BITS AND  DEVICE
				; DATA BLOCK ADDRESS
	MOVE	T1,[XWD R,JOBJDA##]	;PREPARE TO STORE F
	ADDI	T1,0(P1)		;IN THE RIGHT CHANNEL
	MOVEM	F,@T1		;IN THE USERS AREA
	MOVE	T1,USRHCU##	;AND ALSO HIGHEST CHANNEL
	MOVEM	T1,JOBHCU##(R)	;TO THE USER AREA
	MOVE	T1,DEVMOD(F)	;GET THE GOOD WORD
	TLNN	T1,DVTTY	;IS THIS A TTY?
	JRST	TPOPJ1##	;SUCCESSFUL RETURN(POP T1)
	JRST	TTYOPN##	;YES, GO SET UP LDB

UINIT6:	PUSHJ	P,TTYKLQ##	;IF IT WAS A FREE TTY, DISCARD DDB
	TLNE	T3,DVDTA	;WAS DEVICE A DECTAPE?
	DPB	T3,IADPTR##	;YES, RESTORE NO. OF USER CHAN INITED ON
	CAIA
UINITD:	POP	P,(P)
UINITE:	POP	P,T1		;REMOVE IO STATUS ARG
	JRST	TPOPJ##		;AND GIVE ERROR RETURN AND POP T1
;CALLING SEQUENCE
;	PUSHJ P,UINITZ
;	EXIT		RETURNS HERE IF MEMORY NOT EXCEEDED.
;SETS JBFADR:=JBFCTR:=0 FOR THE BUFFER AREA HEADER WHOSE ADDRESS
;IS IN AC T2.  ALSO,JBFPTR 0-5:=JBFPTR 12-17:=0,JBFPTR 6-11:=BYTE SIZE


UINITZ::
IFN FTKA10,<
	HRLI	T2,R		;SET FOR RELOCATION
>
IFE FTVM,<
	MOVEI	T1,2(T2)	;CHECK 3RD WORD OF BUFFER HEADER
	PUSHJ	P,UADRCK
>
IFN FTVM,<
	MOVEI	T1,(T2)		;START ADR OF HEADER
	MOVEI	T2,2(T1)	;TOP ADR
	PUSHJ	P,LRNGE##	;MAKE SURE WHOLE HEADER IS IN CORE
	MOVEI	T2,-2(T2)	;RESET T2
>
	SKIPL	M		;IF NOT FROM FILOP,
	EXCTXU	<SETZM	@T2>	; CLEAR FIRST WORD (CURRENT BUFFER) OF 3 WORD HEADER
	AOS	T2		;POINT TO SECOND WORD (BYTE POINTER)
	PUSH	P,T2
	AOS	T2		;POINT TO THIRD WORD (ITEM COUNT)
	EXCTXU	<SETZM	@T2>	;SET ITEM COUNT TO ZERO
	PUSHJ	P,SETBYT	;SET BYTE SIZE ACCORDING TO MODE AS SET IN AC S
	POP	P,T2		;GET T2 BACK
	TLZ	T1,770077
	EXCTUU	<HLLM	T1,@T2>	;AND STORE IN SECOND WORD
	POPJ	P,		;RETURN
	SUBTTL	COMMON PART OF LOOKUP AND ENTER

;LONG DISPATCH TABLE UUOS - GET HERE ONLY IF DEVICE HAS LONG
;DISPACTH TABLE
;DISPACTH TO DEVICE DEPENDENT SERVICE ROUTINE
;ENTER UUO - ENTER FILE NAME IN DIRECTORY

UDEN:	PUSHJ	P,SAVE4##
IFN FTEQDQ,<
	PUSHJ	P,ENQCLS##	;LOCKS STILL OUT?
	JRST	LKNQER		;YES
>
	MOVEI	T1,CLSIN
	TLNN	F,OCLOSB	;FILE OPEN?
	PUSHJ	P,UDLKC		;YES. CLOSE IT[OCLOSB_1]
	MOVSI	S,IOBEG		;RESET BITS IN S
	IORM	S,DEVIOS(F)	; (CAN'T DO A MOVEM DUE TO
	MOVEI	S,IOIMPM!IODERR!IODTER!IOBKTL!IODEND!IOBOT!IOTEND
	ANDCAB	S,DEVIOS(F)	; POSSIBLE RACE WITH SERVICE ROUTINE)
	PUSHJ	P,ARGCHK	;ADDRESS CHECK ARG.
	PUSHJ	P,DEN(T4)	;ATTEMPT AN ENTER
	POPJ	P,		;FAILURE
	TLZ	F,OCLOSB
	TLO	F,ENTRB		;NOTE SUCCESSFUL ENTER
	JRST	DLKDEN		;STORE THE PROGRESS BITS

;LOOKUP UUO - LOOKUP FILE NAME IN DIRECTORY

UDLK:	PUSHJ	P,SAVE4##
IFN FTEQDQ,<
	PUSHJ	P,ENQCLS##	;LOCKS STILL OUT?
	JRST	LKNQER		;YES
>
	MOVEI	T1,CLSOUT	;INHIBIT OUTPUT CLOSE BIT
	TLNN	F,ICLOSB	;FILE OPEN?
	PUSHJ	P,UDLKC		;YES. CLOSE IT[ICLOSB_1]
	MOVE	S,[XWD IOEND,IOIMPM!IODERR!IODTER!IOBKTL!IODEND!IOBOT!IOTEND]
	ANDCAB	S,DEVIOS(F)
	PUSHJ	P,ARGCHK	;ADDRESS CHECK ARG.
	MOVE	T4,DEVSER(F)
	PUSHJ	P,DLK(T4)	;ATTEMPT A LOOKUP
	POPJ	P,		;FAILURE
	TLZ	F,ICLOSB
	TLO	F,LOOKB		;NOTE SUCCESSFUL LOOKUP
DLKDEN:	HLLM	F,USRJDA##(P1)	;STORE UUO PROGRESS BITS
	JRST	CPOPJ1##	;SUCCESS RETURN TO USER (CALL+2)

IFN FTEQDQ,<
LKNQER:	PUSHJ	P,GETWDU##	;GET ADDRESS OF LOOKUP BLOCK
	TLNN	T1,-1		;IS IT AN EXTENDED ONE?
	ADDI	M,2		;YES
	PUSHJ	P,GETWD1##	;GET CONTENTS OF WORD
	HRRI	T1,ENQERR	;SET ERROR CODE
	PJRST	PUTWDU##	;RETURN IT TO USER
>
UDLKC::	PUSH	P,M
	PUSH	P,T4
	HRRI	M,(T1)
	PUSHJ	P,CLOSE1
	POP	P,T4
	POP	P,M
	JRST	WAIT1##

ARGCHK:	MOVEI	T1,0(M)
	PUSHJ	P,UADCK1	;CHECK FIRST WORF OF TABLE
	MOVEI	T1,3(M)		;LOAD UP LAST WORD OF TABLE
	PJRST	UADCK1		;ADDRESS CHECK IT
	SUBTTL	COMMON PART OF RENAME, USETI/O, UGETF AND UTPCLR

;RENAME UUO - HERE ON SHORT DISPATCH TABLE DEVICES TOO


URENAM:	MOVE	T1,DEVMOD(F)	;IS THIS DEVICE A LONG DISPATCH TABLE?
	TLNN	T1,DVLNG
	JRST	CPOPJ1##	;NO, GIVE SKIP RETURN TO USER
	PUSHJ	P,ARGCHK	;ADDRESS CHECK END OF BLOCK
IFE FT2REL,<
	JRST	DRN(T4)		;YES, DISPATCH TO SERVICE ROUTINE
>
IFN FT2REL,<
	JRST	RNMSEG##	;OLD FILE IS .SHR AND RENAME SUCCESSFUL.
>

;SETO UUO - SET NEXT OUTPUT BLOCK NUMBER(DECTAPE)

UDSO:	PUSHJ	P,WAIT2		;WAIT FOR IO, FIX OUTPUT BUFFERS
	JRST	DSO(T4)

;SETI UUO - SET NEXT INPUT BLOCK NUMBER

UDSI:	PUSHJ	P,WAIT2		;WAIT FOR IO, FIX OUTPUT BUFFERS
	JRST	DSI(T4)

;GETF UUO - GET NEXT FREE BLOCK

UDGF:	JRST	DGF(T4)

;MTAPE UUO - MAGTAPE OPERATIONS

UMTAPE:	JRST	DMT(T4)

;UTPCLR - CLEAR DECTAPE DIRECT.

UTPCLR:	MOVE	T1,DEVMOD(F)	;IS THIS A LONG DISPATCH TABLE?
	TLNN	T1,DVLNG
	POPJ	P,		;NO,RETURN
	JRST	DCLR(T4)	;YES, DISPATCH
	SUBTTL	COMMON PART OF INPUT AND OUTPUT UUO'S

;INPUT UUO

;1)  IF OUTPUT ACTIVE ON THIS CHANNEL, WAIT FOR IT TO COMPLETE.
;2)  IF DUMP MODE, WAIT FOR DEVICE INACTIVE, CALL SERVICE
;	ROUTINE TO START INPUT, WAIT TILL COMPLETE, THEN RETURN TO USER.
;3)  IF NO BUFFER RING SETUP, SET UP 2 RING BUFFER.
;4)  IF FIRST REFERENCE, START SERVICE ROUTINE, GO TO
;5)  FLAG CURRENT BUFFER AS FREE TO RECEIVE MORE INPUT
;	(USE BIT SET TO 0).
;	START SERVICE ROUTINE FILLING FIRST BUFFER WITH USE BIT 0
;	(NEXT BUFFER OR ONE AHEAD OF IT)
;	(SERVICE ROUTINE WILL SET USE BIT WHEN IT FINISHES FILLING
;	BUFFER).
;7)  IF NEXT INPUT BUFFER IS FULL OF DATA, GO TO 10).
;8)  PUT JOB IN IO WAIT TILL NEXT BUFFER FILLED.
;9)  IF NEXT INPUT BUFFER STILL NOT FILLED, CHECK FOR END
;	OF FILE OR ERROR BITS SET BY SERVICE ROUTINE.
;10) CONVERT WORD COUNT AS STORED BY SERVICE ROUTINE IN THIRD
;	WORD OF BUFFER TO ITEM COUNT AND STORE IN THIRD WORD
;	OF HEADER (ITEM COUNT) ALSO SET BYTE POINTER (SECOND
;	WORD OF HEADER) AND RETURN TO USER.

CNGIN:	TRNN	M,-1		;IS USER CHANGING RINGS
	POPJ	P,		;NO - RETURN IMMEDIATELY
	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO COMPLETE
	TRNN	T2,-1		;DID HE HAVE A PREVIOUS BUFFER?
	JRST	SETNEW		;NO - SKIP NEXT
	HRRZ	T1,T2		;MAKE SURE THAT BUFFER WAS
	PUSHJ	P,UADRCK	;IN HIS ADDRESS SPACE
	HRLZI	T1,IOUSE	;BUFFER IN USE BIT
	EXCTUU	<ANDCAM	T1,@T2>	;AND THEN MAKE IT AVAILABLE
SETNEW:	EXCTUU	<HRRM	M,@U>	;POINT HEADER TO NEW RING
	HRR	T2,M		;AND RESET PTR TO CURRENT BUFFER
	HRLZI	T1,IOUSE	;BUFFER IN USE BIT
	EXCTUU	<IORM	T1,@U>	;VIRGIN BIT FOR NEW RING
	MOVE	S,DEVIOS(F)	;LOAD S JUST IN CASE
	POPJ	P,0		;RETURN WITH TRANSPARENT CHANGES

UIN:	IFN	FTPI,<		;IF WE SUPPORT PSISER
	XCT	OKSGNL##	;IS AN INTERRUPT REMOTELY POSSIBLE?
	JRST	UIN00		;NO--BE FAST
	PUSHJ	P,UIN00		;YES--DO THE INPUT
	PJRST	PSIIDN##	;CALL PSISER TO SEE IF ANYTHING HAPPENED
> ;END FTPI
UIN00:	TLNE	S,IO		;IS THIS DEVICE ALREADY DOING OUTPUT?
	PUSHJ	P,WAIT2		;YES, WAIT TILL IT IS FINISHED.
	TLO	F,INPB		;FOR THIS DEVICE.
	TLZ	F,ICLOSB
	HLLM	F,USRJDA##(P1)	;IN LH OF CURRENT JOB DEVICE CHANNEL
	LDB	T1,PIOMOD##	;IO MODE
	CAIL	T1,SD		;IT THE IO MODE DUMP(SD,D,DR)?
	JRST	INDMP		;YES
IN1:	HRRZ	U,DEVBUF(F)	;NO, GET ADDRESS OF BUFFER HEADER
IFN FTKA10,<
	HRLI	U,R		;SET INDEX FIELD FOR RELOCATION USING AC R
>
IFE FTVM,<
	MOVEI	T1,2(U)		;CHECK BUFFER HEADER
	PUSHJ	P,UADRCK
>
IFN FTVM,<
	HRRZ	T1,U		;START OF HEADER
	MOVEI	T2,2(T1)	;TOP OF HEADER
	PUSHJ	P,LRNGE##	;MAKE SURE ITS ALL THERE
>
	MOVE	S,DEVIOS(F)	;SETUP IO STATUS AGAIN FORM FROM MEMORY
				; AC S IS CLOBBERED BY AUTOMATIC CORE EXPANSION
				; ON AN IMPLICIT INBUF ON FIRST INPUT
	EXCTUX	<MOVE	T2,@U>	;GET WORD 1 OF 3 WORD BUFFER HEADER.
	HLL	T2,U		;SET INDEX FIELD FOR RELOCATION USING AC R
	PUSHJ	P,CNGIN		;GO SEE IF USER CHANGING RINGS
	HRRZ	T1,T2		;CHECK ADR. TO SEE IF OK
	PUSHJ	P,UADCK1
	EXCTUX	<SKIPG	@U>	;HAS A BUFFER RING BEEN SET UP (RH NON-ZERO)
				; WHICH HAS BEEN REFERENCED BY PREVIOUS INPUT (BIT0=0)
	JRST	INPUTF		;NO. GO SET UP BUFFER IF NECESSARY AND DO FIRST IO
	MOVE	S,DEVIOS(F)
	HRRZ	T1,DEVIAD(F)	;BUFFER ADR DEVICE WILL USE
	TDNN	S,[XWD IOEND,IOACT]	;BUFFER HAS BEEN ADR CHECKED IF I/O IS ACTIVE
	PUSHJ	P,UADRCK	;MAKE SURE IT'S LEGAL
	HRLZI	T1,IOUSE	;BUFFER IN USE BIT
	EXCTUX	<TDNN	T1,@T2>
	JRST	INPT1
IFN FTVM,<
	EXCTUX	<HRRZ T1,@T2>	;MAKE SURE A FAULT WONT HAPPEN
	PUSHJ	P,FLTST##	; BEFORE WE ADVANCE THE BUFFER HEADER
	  JRST	UUOFLT##	;OOPS - GET THE PAGE IN CORE
	EXCTUX	<SKIPGE T2,@T1>
	MOVSI	T2,1		;WRD 1 MUST BE IN CORE
	HLRZS	T2
	ADDI	T2,(T1)
	PUSHJ	P,LRNGE##
	EXCTUX	<HRRZ	T2,@U>
>
	MOVEI	T3,DEPIND	;DID WE RETURN EARLY BEFORE?
	TDNE	T3,DEVAIO(F)	; (ASYNC. IO, BUFFER NOT FULL)
	JRST	INPT3		;YES, DON'T ADVANCE BUFFERS NOW
IFN FTVM,<
IFN FTMSGSER,<
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,<.TYMPX/.TYEST>
	JRST	INPT0E		;NO--CHARGE AHEAD
	HRR	T1,DEVBUF(F)	;GET ADDRESS OF INPUT BUFFER HEADER

	MOVEI	T2,3(T1)	;TOP OF H-WORD HEADER
	PUSHJ	P,TRNGE##	;MAKE SURE IT'S IN CORE
INPT0E:>	;END FTMSGSER
	MOVSI	T1,IOUSE
	EXCTUX	<HRRZ T2,@U>	;RESTORE T2
>	;END FTVM

	EXCTUU	<ANDCAB	T1,@T2>	;FLAG CURRENT BUFFER AS FREE TO
				; RECEIVE MORE INPUT, CLEAR USE BIT
				; AND GET POINTER TO NEXT BUFFER
	HRRZS	T1		;AND CHECK ITS ADDRESS TO SEE IF IN BOUNDS
	PUSHJ	P,UADRCK
	EXCTUU	<HRRM	T1,@U>	;SET WORD 1 IN 3 WORD HEADER TO NEXT BUFFER
	TRNE	S,IOACT		;IS THE DEVICE ALREADY ACTIVE
	JRST	INPT0C		;YES
	MOVE	T3,DEVMOD(F)	;GET DEVICE CHARACTERISTIC WORD
	TLNN	T3,DVTTY	;IS IT A TTY?
	TRNE	S,IOCON		;DISCONTINUOUS MODE?
	JRST	INPT0B		;YES, LOOK AT FIRST BUFFER (NOT NEXT)
IFN FTVM,<
	SKIPN	.UPMP+.UPREL
	SKIPE	.UPMP+.UPVRT	;IF JOB IS VIRTUAL
	JRST	INPT0F		; DONT TRY N-BUF LOOKAHEAD
>
	TLNN	T3,DVDSK+DVMTA	;IF A DISK,
	TDZA	T3,T3
	LDB	T3,PINBFN##	;TRY N/2 - BUFFER LOOKAHEAD (N-BUF RING)
	LSH	T3,-1		;TRY 1-BUFFER LOOKAHEAD IF NOT A DISK
	HLL	T1,U		;SET RELOCATION IF A KA
INPT0T:	EXCTUX	<HRRZ	T1,@T1>	;GET LOC OF NEXT BUFFER
	PUSHJ	P,UADRCK	;MAKE SURE ITS OK
	SOJLE	T3,INPT0B	;LAST BUFFER TO CHECK IF T3 = 0
	HLL	T1,U		;NOT LAST TO CHECK (IF FULL)
	EXCTUX	<SKIPGE @T1>	;IS IT FULL?
	JRST	INPT0T		;YES, CHECK NEXT
	JRST	INPT0G		;NO, START IO INTO THIS BUFFER
IFN FTVM,<
INPT0F:	PUSHJ	P,FLTST##	;IS THIS BUFFER IN CORE?
	  JRST	INPT0D		;NO. GO BACK TO FIRST
	EXCTUX	<HLRZ T3,@T1>
	TRZ	T3,IOUSE	;YES, IS THE WHOLE BUFFER IN CORE?
	ADDI	T1,(T3)
	PUSHJ	P,FLTST##
INPT0D:	  EXCTUX <SKIPA T1,@U>	;NO, GO BACK TO FIRST BUFFER
	SUBI	T1,(T3)		;YES, START IO FOR THIS BUFFER IF EMPTY
	PUSHJ	P,UADRCK
>
INPT0B:	HLL	T1,U		;SET RELOCATION AGAIN
	EXCTUX	<SKIPL	@T1>	;IS THE USE BIT SET?
INPT0G:	PUSHJ	P,CALIN		;NO, START SERVICE ROUTINE FILLING EMPTY BUFFER
INPT0C:	EXCTUX	<HRR	T2,@T2>	;GET USE BIT FOR NEXT BUFFER
INPT0A:	EXCTUX	<SKIPGE	@T2>	;IS USE BIT SET YET?(BUFFER FILLED YET?)
	JRST	INPUT2		;YES, RETURN IMMEDIATELY TO USER
INPT2:	MOVEI	T1,DEPAIO	;ASYNCHRONOUS IO?
	TDNN	T1,DEVAIO(F)	;YES, DON'T BLOCK THE JOB
	PUSHJ	P,WSYNC##	;NO, PUT JOB IN IO WAIT TILL BUFFER FILLED.
INPT3:
IFN FTMSGSER,<
	PUSHJ	P,CHKMPX##	;AN MPX DDB OR A DDB CONNECTED TO AN MPX?
	  JRST	INPT3A		;YES, LET MSGSER WORRY ABOUT TROUBLE
>
	TLZE	S,IOSTBL	;RECOVERABLE ERROR?
	JRST	INPT1		;YES, TRY AGAIN
INPT3A:	EXCTUX	<SKIPL	@T2>	;RETURN WHEN BUFFER FILLED. CHECK TO MAKE SURE.
	JRST	INEOF		;NO, MUST BE EOF OR ERROR
INPUT2:	ADDI	T2,1		;YES, GET WORD COUNT AS SET BY IO SERVICE
IFN FTMSGSER,<
	LDB	J,PDVTYP##	;GET THE DEVICE TYPE
	CAIE	J,<.TYMPX/.TYEST> ;MPX: ?
	JRST	INPT2A		;NO--IGNORE 4-TH WORD
	EXCTUX	<HLRZ J,@T2>	;PICK UP THE UDX
	MOVE	T1,U		;ADDRESS OF RING HEADER
	ADDI	T1,3		;GET TO FORTH WORD
	EXCTUU	<MOVEM J,@T1>	;STORE FOR USER TO SEE
INPT2A:>
	EXCTUX	<HRRZ	J,@T2>	;RH OF 3RD WORD(FIRST SO-CALLED DATA WORD)
	MOVEI	T1,DEPIND
	ANDCAM	T1,DEVAIO(F)	;DON'T WANT TO USE BUFFER AGAIN
	SOJA	T2,IOSETC	;SET ITEM COUNT AND BYTE POINTER
				; IN 3 WORD HEADER AND RETURN TO USER

INPT1:	TRNN	S,IOACT		;IF DEVICE ISNT ALREADY GOING
	PUSHJ	P,CALIN		; START IT NOW
	JRST	INPT2		;BLOCK UNTIL BUFFER FILLED


INEOF:	TDNN	S,[XWD IOEND,IODERR+IOBKTL+IODTER+IOIMPM]
				; EOF OR ERROR BIT SET BY SERVICE ROUTINE
	JRST	INEOF1		;MONITOR ERROR
	TLNE	S,IOEND		;IS THIS EOF?
	TRO	S,IODEND	;YES, SET USER EOF BIT.
	IORB	S,DEVIOS(F)
IFN FTKI10!FTKL10,<
	TRNN	S,IOACT		;DEVICE ACTIVE?
	PUSHJ	P,RTEVMI##	;RETURNS EXEC VIRTUAL MEMORY IF ANY
>
	POPJ	P,		;RETURN TO USER'S PROGRAM
INEOF1:	MOVE	T1,DEVAIO(F)	;ASYNC?
	TRNN	T1,DEPAIO
	JRST	UUOER1##	;NO-MONITOR ERROR
	MOVEI	T1,DEPIND
	IORM	T1,DEVAIO(F)	;YES, INDICATE WE RETURNED EARLY
	POPJ	P,
;HERE ON FIRST INPUT AFTER INIT, INIT & LOOKUP, OR INIT & LOOKUP & INPUT

INPUTF:
IFN FTVM,<
	JUMPE	T1,INPTF1	;IF A BUFFER ADR IS SPECIFIED,
	PUSHJ	P,BRNGE##	;MAKE SURE WHOLE BUFFER IS IN CORE
	EXCTUX	<HRRZ  T2,@U>	;RESET T2
INPTF1:>
	HRLZI	T3,IOUSE	;BUFFER IN USE BIT
	EXCTUU	<ANDCAB	T3,@U>	;MARK THAT BUFFERS HAVE BEEN REFERENCED
				; BY CLEARING SIGN BIT OF 1ST WORD
				; IN 3 WORD BUFFER HEADER
	JUMPE	T3,INPUT3	;HAS A RING BEEN SET UP YET?
	HRRZ	T1,T2		;YES ADDRESS CHECK FIRST USER BUFFER
	PUSHJ	P,UADRCK	;
	EXCTUX	<SKIPG	@T2>	;IS USE BIT SET IN FIRST USER INPUT BUFFER?
				; CAN HAPPEN IF TTY AND USER HAS TYPED
				; IN LINE AFTER INBUF BUT BEFORE FIRST INPUT UUO
	JRST	INPUT2		;YES, DO NOT CALL SERVICE ROUTINE(SCNSER)
				; SINCE USER BUFFER ALREADY HAS DATA
	PUSHJ	P,WAIT1##	;WAIT FOR I/O TO STOP
	HRRM	T3,DEVIAD(F)	;YES, STORE ADR. OF 2ND WORD OF
				; A BUFFER FOR SERVICE ROUTINE
	PUSHJ	P,CALIN		;YES. GO START IO SERVICE ROUTINE
				; FILLING BUFFER
	JRST	INPT0A
INPUT3:	HLLZS	M		;USE DEFAULT NO OF BUFFERS
	PUSHJ	P,UINBF
	HLLZS	M		;CLEAR RIGHT HALF
	JRST	IN1
CALIN::	MOVSI	S,IOSTBL	;RESET ERROR FLAG
IFN FTMSGSER,<
	PUSHJ	P,CHKMPX##	;AN MPX DDB OR A DDB CONNECTED TO AN MPX?
	  MOVEI	S,0		;YES, DON'T CHANGE THE STATE OF TROUBLE
>
	ANDCAB	S,DEVIOS(F)	; IN DDB AND S
	TLNE	S,IOEND
	POPJ	P,
	PUSH	P,T2
	PUSH	P,U
	HRRZ	T1,DEVIAD(F)	;IS FIRST ADR. ABOVE JOB DATA AREA?
IFE FTVM,<
	PUSHJ	P,UADRCK
>
IFN FTKA10,<
	HRLI	T1,R		;RELOCATE KA10 STYLE
>
	EXCTUX	<HLRZ	T2,@T1>	;GET LENGTH OF BUFFER
	MOVE	T3,DEVMOD(F)
	TLNE	T3,DVTTY
	TRZ	T2,IOUSE	;CLEAR USE BIT IN CASE IT IS ON(TTY)
IFE FTVM,<
	HRRZS	T1
	ADDI	T1,(T2)		;TOP ADR IN BUFFER
	PUSHJ	P,UADRCK	;CHECK IT
>
IFN FTVM,<
	ADDI	T2,(T1)		;TOP ADR
	SUBI	T1,1		;1ST ADR-1 (WHERE ADVBFE STORES)
	PUSHJ	P,LRNGE##	;MAKE SURE WHOLE BUFFER IS IS CORE & LEGAL
>
IFN FTKI10!FTKL10,<
	PUSHJ	P,GTIEVM##	;GET EVM FOR THIS INPUT OPERATION IF THE
				; DEVICE REQUIRES IT
>
	MOVE	T4,DEVSER(F)
	PUSHJ	P,DIN(T4)	;DISPATCH TO IO SERVICE ROUTINE
	MOVE	J,.CPJOB##(P4)	;RESTORE J
	POP	P,U
	PJRST	T2POPJ##	;RESTORE T2 AND RETURN
;CALLING SEQUENCE
;     OUTPUT D,
;     EXIT
;OR
;     OUTPUT D, ADR
;     EXIT

;IF INPUT IS ACTIVE, WAIT FOR IT TO COMPLETE.
;IF DUMP MODE WAS SELECTED BY THE LAST INIT UUO OR SETSTS UUO
;   THE PROGRAM WAITS UNTIL THE DEVICE IN INACTIVE AND THEN
;   WRITES THE DUMPFILE AND RETURNS CONTROL TO THE USER'S PROGRAM
;   WHEN IO HAS COMPLETED.
;IF THE MODE IS NOT DUMP, THEN
;1) IF ADR IS NOT ZERO, WAIT FOR DEVICE TO BECOME INACTIVE THEN SET THE
;   CURRENT BUFFER ADDRESS EQUAL TO ADR AND AN INDICATOR (JBFADR0)
;   SPECIFYING THAT THIS BUFFER RING HAS NEVER BEEN REFERENCED FROM THE
;   USER'S PROGRAM BY AN INPUT OR AN OUTPUT UUO.  OTHERWISE, GO TO
;   2) DIRECTLY.

;2) IF THE BUFFER RING HAS NEVER BEEN REFERENCED (JBFADR0=1), THE
;   BUFFER IS CLEARED, IOUSE SET TO ZERO AND
;      IF THE CURRENT BUFFER ADDRESS IS ZERO, A TWO BUFFER RING IS SET UP.
;      THEN GO TO 8
;
;3) IF THE BUFFER RING HAS BEEN REFERENCED (JBFADR0=0	,THEN A CHECK IS
;   MADE TO DETERMINE IF THE WORD COUNT IS TO BE COMPUTED.
;      IF THE WORD COUNT IS TO BE COMPUTED (IOWC=0), IT IS SET EQUAL
;      TO THE ADDRESS FOR THE LAST DATA WORD MINUS THE ADDRESS OF THE
;      BUFFER MINUS ONE.

;4) IOUSE IS SET TO ONE, INDICATING THAT THE BUFFER IS FULL OR BEING
;   EMPTIED, AND THE CURRENT BUFFER ADDRESS IS ADVANCED.

;5) IF THE DEVICE IS NOT ACTIVE (IOACT=0), OUTPUT IS STARTED.
;6) IF THE CURRENT BUFFER IS FULL OR BEING EMPTIED (IOUSE=1),
;   THE PROGRAM WAITS UNTIL THE DEVICE FINISHES THE BUFFER
;   (THE OUTPUT SERVICE ROUTINE CLEARS THE USE BIT WHEN
;   IT FINISHES OUTPUTTING A BUFFER).
;7) THE CURRENT BUFFER IS CLEARED.
;8) THE J POINTER IS INITIATED TO THE CURRENT BUFFER ADDRESS+1
;   AND THE ITEM COUNT IS SET TO THE PRODUCT OF THE BUFFER SIZE
;   MINUS ONE AND THE INTEGER PART OF 36/BYTE SIZE.
;9) RETURN TO THE USER'S PROGRAM
;HERE ON OUTPUT UUO

UOUT:	IFN	FTPI,<		;IF WE SUPPORT PSISER
	XCT	OKSGNL##	;DID USER DO A PIINI UUO?
	JRST	UOUT00		;NO--CHARGE AHEAD
	PUSHJ	P,UOUT00	;YES--DO OUTPUT
	PJRST	PSIODN##	;CALL PSISER TO LOOK FOR INTERRUPTS
>
UOUT00:	TLO	F,OUTPB		;SET OUTPUT UUO BIT
	TLZ	F,OCLOSB	;CLEAR CLOSE OUTPUT BIT
	HLLM	F,USRJDA##(P1)	;SAVE NEW BIT SETTINGS.
IFN FTMSGSER,<
	LDB	T1,PDVTYP##	;GET THE DEVICE TYPE
	CAIN	T1,<.TYMPX/.TYEST> ;IS THIS MPX?
	PJRST	MSGOUT##	;YES--CALL MSGSER
> ;END FTMSGSER

;HERE FROM DEVICE SERVICE ROUTINES ON CLOSE UUO

OUT::	HRRZ	T4,DEVSER(F)	;RESTORE T4
	TLNN	S,IO		;IS THIS DEVICE ALREADY DOING INPUT?
	PUSHJ	P,WAIT1##	;YES, WAIT TILL IT BECOMES INACTIVE
	LDB	T1,PIOMOD##	;GET DATA MODE SET BY INIT OR SETSTS.
	CAIL	T1,SD		;IS IT DUMP MODE(SD,DR,D)?
	JRST	OUTDMP		;YES.
	PUSHJ	P,OUTA		;NO, CHECK FOR NON-ZERO ADDRESS(USER
				; CHANGING RING)
	HLRZ	U,DEVBUF(F)	;REL. ADDR. OF OUTPUT BUFFER HEADER
IFE FTVM,<
	MOVEI	T1,2(U)		;CHECK END OF 3 WORD HEADER
	PUSHJ	P,UADRCK
>
IFN FTVM,<
	MOVEI	T1,(U)		;START OF BUFFER HEADER
	MOVEI	T2,2(T1)	;TOP OF HEADER
	PUSHJ	P,LRNGE##	;MAKE SURE HEADER IS COMPLETELY IN CORE
>
IFN FTKA10,<
	HRLI	U,R		;SET INDEX FIELD FOR RELOCATION.
>
	EXCTUX	<SKIPG	T2,@U>	; CHECK FIRST WORD OF BUFFER RING HEADER
	JRST	OUTF		;RING NOT SET UP OR FIRST REFERENCE TO RING
IFN FTVM,<
	MOVEI	T1,-1(T2)	;BUF LOC-1 IS STORED THERE
	PUSHJ	P,UADRCK	;ENSURE ADVBFF WONT FAULT
>
	MOVEI	T1,DEPOND	;ASYNCHRONOUS OUTPUT?
	TLNN	S,IOSTBL	;IF TROUBLE, BLUNDER ON TO RECOVERY REGARDLESS
	TDNN	T1,DEVAIO(F)
	JRST	OUT0		;NO, PROCEED
	HLL	T2,U		;SET FOR RELOCATION
	HRRZ	T1,T2		;ADR CHECK POINTER TO CURRENT BUF
	PUSHJ	P,UADRCK
	EXCTUX	<SKIPGE @T2>	;IS THE CURRENT BUFFER EMPTY
	POPJ	P,		;NO, RETURN
	JRST	OUTS		;YES, ADVANCE THE BUFFER HEADER
OUT0:	TRNE	S,IOACT		;ADR CHECK CURRENT BUFFER ONLY IF NOT I/O ACTIVE
	JRST	OUT1		;BUFFER ALREADY ADDRESS CHECKED
	HRRZ	T1,DEVOAD(F)	;CURRENT BUFFER LOC DEVICE IS USING
	PUSHJ	P,UADRCK	;MAKE SURE IT'S LEGAL
IFN FTVM,<
	PUSHJ	P,BRNGE##	;MAKE SURE WHOLE BUFFER IS IN
	EXCTUX	<HRRZ T2,@U>	;OK - RESTORE T2
>
	HRRZI	T1,1(T2)	;PROCEED ONLY IF ADDR. OF WORD COUNT IN BOUNDS
	CAIG	T1,JOBPFI##	;IS 1ST ADR ABOVE JOB DATA AREA?
	JRST	ADRERR##	;NO, PRINT ERROR MESSAGE
OUT1:	HLL	T2,U		;SET TO RELOCATE
	MOVE	T1,DEVADV(F)	;IF BUFFERS SHOULDN'T BE DEADVANCED
	TDNN	T1,[DEPADV,,DEPOND]  ; ON ERROR INTERCEPT OR DUE TO TROUBLE
	AOSA	U
	JRST	OUT3		;THEN JUST START THE DEVICE
	EXCTUX	<HRRZ	T1,@U>	;GET RH OF BYTE POINTER.
	ADDI	T2,1		;REL. ADDR. OF 3RD WORD IN BUFFER.
	JUMPE	T1,OUT2		;WRDCNT ALREADY STORED IF INTERCEPT RETRY
	SUBI	T1,(T2)		;DISTANCE FILLED BY USER.
	TRNE	S,IOWC
OUT2:	EXCTUX	<HRRZ T1,@T2>
	SKIPGE	T3,T1		;PRESERVE USER'S WORDCOUNT
	PJRST	ADRERR##	;NEGATIVE WORDCOUNTS ARE ILLEGAL
	MOVE	T4,DEVMOD(F)
	TLNE	T4,DVDSK!DVDTA	;IF DISK OR DTA,
	MOVEI	T1,200		; MAKE SURE WHOLE BUFFER IS THERE
	PUSH	P,T2		;SAVE L(WRDCNT WORD)
IFN FTVM,<
	EXCH	T1,T2		;FST ADR INTO T1
	ADDI	T2,(T1)		;TOP ADR IN T2
	PUSHJ	P,LRNGE##	;MAKE SURE WHOLE BUFFER IS OK
>
IFE FTVM,<
	ADDI	T1,(T2)		;FORM REL. ADR OF LAST WORD TO OUTPUT
	PUSHJ	P,UADRCK
>
	LDB	T1,PIOMOD	;I/O MODE
	CAIE	T1,BYTMOD	;BYTE MODE?
	JRST	OUT2A		;NO
	EXCTUX	<LDB T1,[POINT 6,@U,5]>	;POSITION FIELD OUT OF THE USER'S BYTE POINTER
	MOVNS	T1
	ADDI	T1,^D36		;T1=36 - POSITION FIELD
	SKIPGE	T1		;IF.LE.0, NO BYTES ARE STORED IN THIS WORD
	MOVEI	T1,0		;0 BYTES IN THE LAST WORD
	EXCTUX	<LDB T4,[POINT 6,@U,11]>	;BYTE SIZE FROM USER'S BYTE POINTER
	IDIVI	T1,(T4)		;NUMBER OF BYTES IN THE LAST WORD
	SOS	T2,T3		;OUT2 ROUNDED UP
	MOVEI	T3,^D36
	IDIVI	T3,(T4)		;NUMBER OF BYTES PER WORD
	IMULI	T3,(T2)		;NUMBER OF BYTES IN THE RECORD NOT COUNTING
				; THE LAST WORD
	ADDI	T3,(T1)		;NUMBER OF BYTES IN THE RECORD
OUT2A:	POP	P,T2		;GOOD-RESTORE T2
	TRNN	S,IOWC		;COMPUTE WORD COUNT FOR USER?
	EXCTUU	<HRRM	T3,@T2>	;YES, STORE WORD COUNT IN 3RD WORD OF BUFFER.
	SUBI	U,1		;REL. ADDR. OF 1ST WORD IN HEADER
				; (POINTER TO CURRENT BUFFER).
	SUBI	T2,1		;REL. ADDR. OF 2ND WORD IN BUFFER
IFN FTVM<
	EXCTUX	<HRRZ T1,@T2>	;START OF NEXT BUF
	PUSH	P,T2
	PUSHJ	P,UADRCK	;MAKE SURE ITS IN CORE
	PUSHJ	P,BRNGE##
	POP	P,T2
>
	HRLZI	T1,IOUSE	;FLAG CURRENT BUFFER CONTAINS ACTIVE DATA.
	EXCTUU	<IORB	T1,@T2>
	EXCTUU	<HRRM	T1,@U>	;ADVANCE CURRENT BUFFER ADDRESS
OUT3:	MOVSI	T1,DEPADV	;DON'T DEADVANCE BUFFERS BIT
	ANDCAM	T1,DEVADV(F)	;CLEAR BEFORE RETRY. REPEAT OF ERRORS
				; WILL SET IT AGAIN.
	MOVSI	S,IOSTBL	;CLEAR TROUBLE FLAG
	ANDCAB	S,DEVIOS(F)
	TRNN	S,IOACT
	PUSHJ	P,CALOUT	;NO,START OUTPUT.
	HLRZ	U,DEVBUF(F)	;U TO REL. ADDR. OF BUFFER HEADER
IFN FTKA10,<
	HRLI	U,R		;SET TO RELOCATE
>
	EXCTUX	<MOVE	T2,@U>	;T2 TO REL. ADDR. OF 2ND WORD OF BUFFER.
	HRRZ	T1,T2
	PUSHJ	P,UADRCK
	HLL	T2,U
	MOVEI	T1,@U		;IN CASE WE REDO THE UUO
	EXCTUU	<HLLZS 1(T1)>	; AFTER AN OFF-LINE INTERCEPT
	EXCTUX	<SKIPL	@T2>	;HAS SERVICE ROUTINE EMPTIED NEXT BUFFER
				; YET (USE BIT = 0)?
	JRST	OUTS		;YES RETURN TO USER
	MOVEI	T1,DEPAIO	;ASYNC IO?
	TDNE	T1,DEVAIO(F)
	JRST	OUT4		;YES, DON'T BLOCK
	PUSHJ	P,WSYNC##	;NO - WAIT
	TLZE	S,IOSTBL	;ERROR OCCURED?
	JRST	OUT3		;YES - TRY AGAIN
	JRST	OUTS		;RETURN TO USER.
OUT4:	MOVEI	T1,DEPOND	;INDICATE BUFFER HEADER NOT
	IORM	T1,DEVAIO(F)	;YES,, YET SET UP FOR NEXT OUTPUT
	POPJ	P,		;RETURN WITHOUT CLEARING ANYTHING
OUTF:	TLO	S,IO		;INDICATE OUTPUT FOR IOSETC
	EXCTUX	<SKIPE	T2,@U>
	JRST	OUTF1
	PUSHJ	P,DFTNB		;GET DEFAULT NO OF BUFS
	HRR	M,T2	
	PUSHJ	P,UOUTBF
	HLRZ	U,DEVBUF(F)
IFN FTKA10,<
	HRLI	U,R
>
OUTF1:
IFN FTVM,<
	EXCTUX	<HRRZ T1,@U>	;CALL BUFCLR EARLY
	PUSHJ	P,BUFCLR	; TO ENSURE THAT A FAULT WONT HAPPEN
	  JRST	ADRERR##	; AFTER THE VIRGIN-RING BIT IS CLEARED
>
	HRLZI	T1,IOUSE
	EXCTUU	<ANDCAB	T1,@U>	;IOUSE:=0
	HRRM	T1,DEVOAD(F)
OUTS:	EXCTUX	<HRRZ	T1,@U>	;CLEAR NEXT OUTPUT BUFFER.
	MOVSI	T2,DEPIBC	;USER DID AN OPEN WITH INHIBIT BUFFER CLEAR BIT
	MOVSI	T3,IOIBC	;INHIBIT CLEARING THIS BUFFER BIT
	TDNE	T2,DEVTYP(F)	;DID THE USER ENABLE FOR INHIBITING CLEARING BUFFER?
	EXCTUX	<TDNN T3,@U>	;YES, DOES HE WANT THIS BUFFER NOT TO BE CLEARED
	CAIA			;NO, CLEAR R FROM THE LEFT HALF WORD IF ITS ON
	JRST	OUTS1		;YES, SKIP CLEARING THE NEXT BUFFER
	PUSHJ	P,BUFCLR	;BEING CLEARED.
	  JRST	ADRERR##	;ADDRESS CHECK
OUTS1:	EXCTUX	<HRRZ	T2,@U>
	HLL	T2,U
	EXCTUX	<LDB	J,[POINT 17,@T2,17]>
	MOVEI	T1,DEPOND	;CLEAR OUTPUT NOT YET DONE FLAG
	ANDCAM	T1,DEVAIO(F)
	SOJA	J,IOSETC
				; ADDRESS+1
				; JBFCTR:=(BUFFER SIZE-1)*[36/BYTE
				; SIZE]
				; RETURN TO USER'S PROGRAM

CALOUT::
	MOVSI	T1,DEPSIE	;BIT TO TEST
	TDNN	T1,DEVJOB(F)	;WANT TO LOOK FOR ERROR
	JRST	CALOU1		;NO-PROCEED
	MOVE	T1,DEVIOS(F)	;YES - CHECK I/O STATUS
	TRNE	T1,742000	;ANY ERRORS? (INCLUDE IOTEND)
	POPJ	P,		;RETURN (NO OUTPUT DONE)
CALOU1:	IFN FTKI10!FTKL10,<
	PUSHJ	P,GTOEVM##	;GET EVM FOR THIS OUTPUT OPERATION
				; IF THE DEVICE REQUIRES IT
>
	MOVE	T4,DEVSER(F)	;SETUP DISPATCH ADR. FOR SERVICE ROUTINE
	PUSHJ	P,DOU(T4)	;START DEVICE DOING OUTPUT
	MOVE	J,.CPJOB##(P4)	;RESTORE J
IFN FTKI10!FTKL10,<
	MOVE	S,DEVIOS(F)	;GET DEVICE STATUS
	TRNN	S,IOACT		;IS THE DEVICE I/O ACTIVE NOW?
	PJRST	RTEVMO##	;NO, RETURN ANY EXEC VIRTUAL MEMORY THE
				; DEVICE MAY HAVE ASSIGNED
>
	POPJ	P,		;I/O ACTIVE, JUST RETURN
;HERE ON DUMP MODE INPUT
INDMP:	MOVEI	T1,DDI(T4)	;DISPATCH TO DO DUMP MODE INPUT
	PJRST	DMPIO		;JOIN COMMON INPUT/OUTPUT CODE
;HERE ON DUMP MODE OUTPUT
OUTDMP: MOVEI	T1,DDO(T4)	;DISPATCH TO DO DUMP MODE OUTPUT
				; AND FALL INTO COMMON INPUT/OUTPUT CODE
;ROUTINE TO SETUP FOR DUMP MODE I/O. IF THIS IS A
;CHANNEL DEVICE (DSK OR MTA) CALL THE SERVICE
;ROUTINE DIRECTLY AND MAPIO WILL FIXUP THE IOWDS AS NECESSARY.  OTHERWISE,
;FIND THE LARGEST IOWD IN THE LIST, ALLOCATE ENOUGH EXEC VIRTUAL MEMORY
;TO COVER THAT IOWD, MAP THE FIRST IOWD, AND THEN CALL THE SERVICE ROUTINE
;TO START THE I/O
;CALLING SEQUENCE:
;	MOVEI	T1,DUMP I/O DISPATCH ADDRESS
;	PUSHJ	P,DMPIO
;NEVER RETURN IF ADDRESS CHECK

DMPIO:	PUSHJ	P,WSYNC##	;WAIT UNTIL THE DEVICE IS INACTIVE
IFN FTKI10!FTKL10,<
	PUSHJ	P,DMPEV##	;GET EVM FOR THE I/O IF NEEDED
>
	PUSHJ	P,(T1)		;CALL THE DEVICE ROUTINE TO START THE I/O
IFN FTKA10,<
	PJRST	WAIT1##		;WAIT UNTIL ITS DONE
>
IFN FTKI10!FTKL10,<
	PUSHJ	P,WAIT1##	;WAIT UNTIL ITS DONE
	PJRST	RTNEVM##	;RETURN ANY EVM JOB HAS FOR DOING I/O
>
;CALLING SEQUENCE:
;	PUSHJ P,OUTA
;	EXIT		ALWAYS RETURNS HERE
;IF THE ADDRESS FIELD OF AC UUO IS ZERO,EXIT. OTHERWISE,CHECK IOACT.
;IF IOACT=1, WAIT FOR IOACT=0.
;SET JBFADR18-35:=ADDRESS FIELD OF AC UUO. JBFADR0:=1 AND EXIT.

OUTA::	TRNE	M,-1		;IS BUFFER ADDRESS SPECIFIED?
	TLNE	F,OCLOSB	;THIS OPTION DOESN'T APPLY DURING CLOSE UUO
	POPJ	P,		;NO
	PUSHJ	P,WAIT2
	HLRZ	U,DEVBUF(F)
IFN FTKA10,<
	HRLI	U,R
>
	EXCTUU	<HRRM	M,@U>
	HRRM	M,DEVOAD(F)
	HRLZI	T1,IOUSE
	EXCTUU	<ANDCAM	T1,@U>
	POPJ	P,		;RETURN

;RESDV.-- UUO TO RESET CHANNEL
;CALL:	MOVE	AC,CHANNEL
;	RESDV.	AC,
;ERROR IF NOT IMPLEMENTED, OR CHANNEL NOT OPEN(AC=-1)
;OK IF DONE

IFN FT5UUO,<
RESDV:	JUMPL	T1,RTM1		;ERROR IF ILLEGAL CHANNEL
	CAMLE	T1,USRHCU##	;CHECK SIZE
	JRST	RTM1		;ERROR
	HRRZ	P1,T1		;SETUP CHANNEL NUMBER
	MOVE	F,USRJDA##(P1)	;SETUP DDB
	JUMPE	F,RTM1		;IF NONE--RETURN ERROR
	DPB	P1,PUUOAC##	;PUT CHANNEL # IN AC FIELD OF M
				; (IN CASE OF TROUBLE AND CALL HNGSTP)
	PUSHJ	P,RELEAC	;RESET IT
	JRST	CPOPJ1##	;SKIP RETURN
>
IFE FT5UUO,<RESDV==CPOPJ##>
	SUBTTL	RELEASE UUO

;RELEASE A DEVICE


RELEA1::
RELEA0:
RELEA2::RELEA3::
	TRZ	M,-1		;CLOSE BOTH INPUT AND OUTPUT
	PUSHJ	P,CLOSE1
	PUSHJ	P,WAIT1##	;WAIT FOR DEVICE TO BECOME INACTIVE
RELEAC::HRRZ	T4,DEVSER(F)	;RESTORE T4
RELEA5::PUSHJ	P,DRL(T4)	;DISPATCH TO DEVICE SERVICE ROUTINE
	MOVEI	S,IOACT		;CLEAR IO ACTIVE BIT
	ANDCAB	S,DEVIOS(F)	;AND RETURN WITH S SET
	LDB	T2,IADPTR##	;GET COUNT OF NO OF CHANS DEVICE ON(IF DTA)
	SOS	T2		;COUNT DOWN BY ONE
	MOVE	T1,DEVMOD(F)
	TLNE	T1,DVDTA	;DEVICE A DTA?
	DPB	T2,IADPTR##	;YES, STORE UPDATED COUNT
	SETZB	U,USRJDA##(P1)	;CLEAR DEVICE ASSIGNMENT
	MOVE	T1,USRHCU##	;HIGHEST IO CHANNEL IN USE
RELEA4:	HRRZ	T2,USRJDA##(T1)
	JUMPN	U,RELE4A	;NON-ZERO CHAN. ALREADY?
	MOVE	U,T2		;NO, SET U WHEN FIRST(HIGHEST) FOUND
	MOVEM	T1,USRHCU##	;STORE HIGHEST IN USE CHANNEL
RELE4A:	CAIE	T2,(F)		;IS THIS DEVICE SAME AS ONE BEING RELEASED?
	SOJGE	T1,RELEA4
	JUMPGE	T1,CPOPJ##	;EXIT IF ON ANOTHER CHANNEL

;HERE FROM ERROR STOP ROUTINES (SWAP READ ERROR, PARITY ERROR, ETC.)

RELEA9::MOVSI	T3,R
	PUSHJ	P,RTIEVM##
	PUSHJ	P,RTOEVM##
	MOVEI	T1,DEPAIO
	ANDCAM	T1,DEVAIO(F)	;CLEAR NON-BLOCKING I/O FLAG
IFE FTDISK,<
	MOVE	T1,DEVNAM(F)	;IS THIS SYSTEM TAPE?
	CAME	T1,SYSTAP##
	JRST	RELEA7		;IS DISK OR NOT SYSTEM TAPE
	SKIPN	STUSER##	;HAS COUNT ALREADY BEEN REDUCED AT ESTOP?
	JRST	RELEA7		;YES
	SETZM	STUSER##	;YES, CLEAR SYSTEM USER NO.
	SOSL	STREQ##		;YES, REDUCE COUNT
	SETOM	STAVAL##	;SOMEONE IS WAITING, SET AVAILABLE FLAG
>
RELEA7::MOVEI	T2,ASSPRG	;CLEAR ASSIGNED BY PROGRAM BIT
RELEA6::ANDCAB	T2,DEVMOD(F)	;CALLED FROM DEASSIGN
	TRZ	T2,777		;CLEAR JOB NO. FIELD
	TLNE	T2,DVDSK+DVMTA	;DSK?
	DPB	T2,PINBFN##	;YES, CLEAR NO OF BUFS
	TDNE	T2,[XWD TTYATC,ASSCON+ASSPRG]
	POPJ	P,		;DEVICE ASSIGNED BY OTHER MEANS TOO
	SETZM	DEVBUF(F)	;NO BUFFER HEADERS
	PUSHJ	P,CLRDVL	;DISCONNECT JOB FROM DDB
	MOVE	T2,DEVMOD(F)	;PUT DEVMOD IN T2
IFN FTMTSET,<
	TLNN	T2,DVTTY	;DON'T BE FOOLED BY NULL
	TLNN	T2,DVMTA
	JRST	RELE6A
	HRRI	T2,MTSIZ##+1	;GET DEFAULT MTA BLOCK SIZE
	DPB	T2,PBUFSZ##	;  SET SYSTEM DEFAULT IN BUFFER
	TRZ	T2,-1		;CLEAR FOR DENSITY
	DPB	T2,TDYDN1##	;  SET TO FORCE INSTALLATION DENSITY
	DPB	T2,PBUFRM##	;CLEAR FRAME-COUNT
RELE6A:>	;END CONDITIONAL ON FTMTSET
IFN FTNET,<
	MOVSI	T1,DVCNET	;CHECK FOR A NETWORK DEVICE
	TDNE	T1,DEVCHR(F)	;IS IT
	PJRST	ZAPNET##	;YES, CLEAR THE DDB
>;END FTNET
IFN FTDISK,<	PUSH	P,J		;SAVE JOB NO.
IFN FTSPL,<
	SKIPL	DEVSPL(F)	;IS DEVICE A SPOOLED DISK
>
	TLNE	T2,DVDSK	;IS DEVICE A DSK
	PUSHJ	P,CLRDDB##	;YES-RETURN DDB TO STORAGE
	POP	P,J		;RESTORE JOB NUMBER
> ;END IFN FTDISK
IFN FTMSGSER,<
	LDB	T2,PDVTYP##	;GET THE DEVICE TYPE
	CAIN	T2,.TYMPX/.TYEST;IS THIS AN MPX DDB?
	PUSHJ	P,ZAPMPX##	;YES--KILL IT OFF
> ;END FTMSGSER
	PJRST	XTKLDB##	;GO KILL XTC DDB IF NECESSARY
	SUBTTL	STATUS SETTING AND GETTING UUO'S


;CALLING SEQUENCE
;	STATO D,MASK
;	EXIT1		ALL SELECTED BITS ARE 0
;	EXIT2		SOME SELECTED BITS ARE 1
;TESTS BITS OF I/O STATUS WORD OF DEVICE ON USER'S CHANNEL D WHICH
;ARE SELECTED BY MASK.


USTATO::
IFN FTXTC,<
	PUSHJ	P,XTCIOS##	;GET S
>
	TRNE	S,(M)		;SKIP IF ANY INDICATED BITS ARE ONE
	AOS	(P)
	POPJ	P,		;RETURN TO USER


;CALLING SEQUENCE
;	STATUS D,ADR
;	EXIT		ALWAYS RETURNS HERE
;STORES I/O STATUS WORD OF DEVICE ON CHANNEL D IN LOCATION ADR.




USTATS::
IFN FTXTC,<
	PUSHJ	P,XTCIOS##	;GET S
>
	HRRZ	T1,S		;GET USER HALF OF IOS.
	PJRST	PUTWDU##	;ADDRESS CHECK AND STORE IN USER AREA


;CALLING SEQUENCE
;	STATZ D,MASK
;	EXIT1		SOME SELECTED BITS ARE 1
;	EXIT2		ALL SELECTED BITS ARE 0

;TESTS BITS OF I/O STATUS WORD OF DEVICE ON USER'S
;CHANNEL D WHICH ARE SELECTED BY MASK.


USTATZ::
IFN FTXTC,<
	PUSHJ	P,XTCIOS##	;GET S
>
	TRNN	S,(M)		;SKIP IF ALL INDICATED BITS ARE ZERO
	AOS	(P)
	POPJ	P,		;RETURN TO USER
;IN UUO - LIKE INPUT	SKIPS IF  EOF OR ERRORS OR BUFFER NOT FULL IF NON-BLOCKING I/O


TIN::	PUSHJ	P,UIN00		;DO INPUT UUO
	MOVEI	T1,DEPIND	;INPUT NOT YET DONE?
	TRNN	S,IOBKTL+IODTER+IODERR+IOIMPM+IODEND
	TDNE	T1,DEVAIO(F)
	AOS	JOBPD1##(R)
IFE FTPI,<
	POPJ	P,
>

IFN FTPI,<
	JRST	IOPTST
>


;OUT UUO - LIKE OUTPUT  -  SKIPS IF ERRORS OR NO EMPTY BUFFER IF NON-BLOCKING I/O


TOUT::	PUSHJ	P,UOUT00	;DO OUTPUT UUO
	MOVEI	T1,DEPOND	;OUTPUT NOT YET DONE?
	TRNN	S,IOBKTL+IODTER+IODERR+IOIMPM+IOTEND
	TDNE	T1,DEVAIO(F)
	AOS	(P)
IFE FTPI,<
	POPJ	P,
>
IFN FTPI,<
IOPTST:	MOVE	J,.C0JOB##
	XCT	OKSGNL##	;NO, HAVE PSISER
	POPJ	P,		;NOPE
	TLNE	S,IO		;GET THE DIRECTION BIT
	PJRST	PSIODN##	;OUTPUT
	PJRST	PSIIDN##	;INPUT
>


;5 UUOS FOR EACH INSTALLATION TO DEFINE
;OPCODES 42-46


	SUBTTL	ROUTINES TO ADVANCE BUFFERS

;ROUTINE TO ADVANCE OUTPUT BUFFER AT INTERRUPT LEVEL

;CALL:	PUSHJ P,ADVBFE
;	EXIT1		RETURN IF NEXT BUFFER IS EMPTY
;	EXIT2		RETURN IF NEXT BUFFER IS FULL
;CLEARS THE USE BIT (IOUSE:=0) OF THE BUFFER POINTED TO BY THE
;OUTPUT BUFFER ADDRESS (DEVOAD) OF THE CURRENT DEVICE DATA BLOCK
;AND ADVANCES THE BUFFER ADDRESS TO THE NEXT BUFFER IN THE RING.
;UPON RETURN, SKIPS IF THE NEXT BUFFER IS FULL.
;SECOND WORD OF NEXT BUFFER IS ADDRESS CHECKED TO
;MAKE SURE IT IS NOT IN JOB DATA AREA OR ABOVE USER AREA
;THE SECOND WORD OF CURRENT BUFFER WAS CHECKED AT UUO LEVEL
;OR PREVIOUS CALL TO ADVBFE


ADVBFE::MOVE	T1,DEVOAD(F)	;USER OR EXEC VIRTUAL ADDRESS OF CURRENT BUFFER
	TRNN	T1,-1		;HAS IT BEEN CLEARED BY A RELEASE?
	POPJ	P,		;YES, GIVE STOP I/O RETURN
IFN FTKI10!FTKL10,<
	PUSHJ	P,SVEUF##	;PUSH THE USER BASE REGISTER AND SETUP UBR
				; SO THAT CURRENT USER IS ADDRESSABLE
>
IFN FTMSGSER,<
	MOVEI	T2,DEPMSG	;IS THIS DEVICE CONTROLLED BY
	TDNE	T2,DEVMSG(F)	; BY MSGSER
	PJRST	MSGBFE##	;YES--GO ADVANCE THINGS
>
	PUSH	P,T3		;ITS POSSIBLE THAT SOME DEVICE ROUTINES
				; DEPEND ON T3 BEING INTACT ON RETURN
	MOVSI	T3,IOUSE	;SET TO TURN OFF THE USE BIT
IFN FTKI10!FTKL10,<
	HRRZ	T2,DEVEVM(F)	;IS THIS BUFFER MAPPED BY THE EXEC MAP?
	JUMPE	T2,ADVBE1	;JUMP IF NOT A MAPPED ADDRESS
	MOVEM	S,-1(T1)	;THE BUFFER IS ADDRESSABLE - STORE IOS
	ANDCAB	T3,(T1)		;GET THE SIZE AND ADDRESS OF THE NEXT BUFFER
				; AND CLEAR THE USE BIT
IFN FTVM,<
	HRRZ	T1,T3		;ADDRESS OF START OF BUFFER
	PUSHJ	P,IADCKL	;MAKE SURE ITS LEGAL (MIGHT BE PAGED OUT)
	  JRST	ADVBU2		;ILLEGAL ADDRESS (ADR CHECK)
	HRLM	T3,DEVEVM(F)	;LEGAL ADR, SAVE AS NEXT BUFFER LOC
	PUSHJ	P,BADCK		;IS WHOLE BUFFER LEGAL AND IN CORE?
	  JRST	ADVBU2		;NO, STOP IO
>
IFE FTVM,<
	PUSHJ	P,BADCK		;ADDRESS CHECK THE NEXT BUFFER
	  JRST	ADVBU2		;OUT OF BOUNDS - GIVE STOP I/O RETURN
>
	PUSHJ	P,ADVEVM##	;ADVANCE THE BUFFER IN EXEC VIRTUAL MEMORY
	  JRST	ADVBU2		;NOT ENOUGH PAGES TO COVER THE NEXT BUFFER
				; UUO LEVEL WILL ALLOCATE MORE ON THE NEXT UUO
	DPB	T1,PDVOAD##	;STORE THE EXEC VIRTUAL ADDRESS OF THE NEXT
				; BUFFER FOR THE DEVICE ROUTINE
	SKIPL	(T1)		;IS THE NEXT BUFFER AVAILABLE? (USE BIT ON)
	JRST	ADVBU2		;NO, GIVE STOP I/O RETURN
	JRST	ADVBU1		;GO CHECK FOR OTHER REASONS I/O SHOULD BE STOPPED
>
ADVBE1:
;HERE TO ADVANCE A BUFFER WHICH IS NOT MAPPED BY THE EXEC MAP
IFN FTKA10,<
	MOVEI	T1,@T1		;RELOCATE THE BUFFER ADDRESS
>
	EXCTXU	<MOVEM	S,-1(T1)>
	EXCTUU	<ANDCAB	T3,(T1)>;CLEAR THE USE BIT AND GET THE SIZE AND
				; ADDRESS OF THE NEXT BUFFER
IFN FTVM,<
	HRRZ	T1,T3		;ADDRESS OF START OF BUFFER
	PUSHJ	P,IADCKL	;MAKE SURE ITS LEGAL (MIGHT BE PAGED OUT)
	  JRST	ADVBU3		;ILLEGAL ADDRESS (ADR CHECK)
	HRRM	T3,DEVOAD(F)	;LEGAL ADR, SAVE AS NEXT BUFFER LOC
	PUSHJ	P,BADCK		;IS WHOLE BUFFER LEGAL AND IN CORE?
	  JRST	ADVBU3		;NO, STOP IO
>
IFE FTVM,<
	PUSHJ	P,BADCK		;ADDRESS CHECK THE NEXT BUFFER
	  JRST	ADVBU3		;OUT OF BOUNDS - GIVE STOP I/O RETURN
	HRRM	T3,DEVOAD(F)	;STORE USER VIRTUAL ADDRESS OF NEXT BUFFER
				; FOR THE DEVICE ROUTINE
>
IFN FTKA10,<
	ADDI	T3,(R)		;KA10 - RELOCATE BUFFER ADDRESS
>
	EXCTUX	<SKIPL (T3)>	;NEXT BUFFER AVAILABLE?
	JRST	ADVBU3		;NO, GIVE STOP I/O RETURN
	JRST	ADVBU1		;YES, CHECK FOR OTHER REASONS WHY I/O SHOULD STOP
;ROUTINE TO ADVANCE INPUT BUFFER AT INTERRUPT LEVEL

;CALL:	PUSHJ P,ADVBFF
;	EXIT1		RETURN IF NEXT BUFFER IS FULL
;	EXIT2		RETURN IF NEXT BUFFER IS EMPTY
;SETS THE USE BIT (IOUSE:=1) OF THE BUFFER POINTED TO BY THE
;INPUT BUFFER ADDRESS (DEVIAD) OF THE CURRENT DEVICE DATA BLOCK
;AND ADVANCES THE BUFFER ADDRESS TO THE NEXT BUFFER IN THE RING.
;UPON RETURN, SKIPS IF THE NEXT BUFFER IS EMPTY.
;SECOND WORD OF NEXT BUFFER IS ADDRESS CHECKED TO MAKE SURE
;IT IS NOT IN IO PROTECTED PART OF JOB DATA AREA OR ABOVE
;USER AREA
;ALSO END OF BUFFER IS CHECKED TO MAKE SURE NOT ABOVE JOB AREA


ADVBFF::MOVE	T1,DEVIAD(F)	;USER OR EXEC VIRTUAL ADDRESS OF CURRENT BUFFER
	TRNN	T1,-1		;HAS IT BEEN CLEARED BY A RELEASE?
	POPJ	P,		;YES, GIVE STOP I/O RETURN
IFN FTKI10!FTKL10,<
	PUSHJ	P,SVEUF##	;PUSH THE USER BASE REGISTER AND SETUP UBR
				; SO THAT CURRENT USER IS ADDRESSABLE
>
	PUSH	P,T3		;ITS POSSIBLE THAT SOME DEVICE ROUTINES
				; DEPEND ON T3 BEING INTACT UPON RETURN
IFN FTMSGSER,<
	MOVEI	T2,DEPMSG	;IF THIS DEVICE IS CONTROLLED
	TDNE	T2,DEVMSG(F)	; VIA MSGSER. SHUT IT DOWN NOW
	JRST	ADVBU2		; SINCE NEXT BUFFER MAY HAVE I/O TOO
>
	MOVSI	T3,IOUSE	;SET TO TURN ON THE USE BIT
IFN FTKI10!FTKL10,<
	HRRZ	T2,DEVEVM(F)	;IS THE BUFFER MAPPED BY THE EXEC MAP?
	JUMPE	T2,ADVBF1	;JUMP IF NOT A MAPPED ADDRESS
	MOVEM	S,-1(T1)	;THE BUFFER IS ADDRESSABLE - STORE IOS
	IORB	T3,(T1)		;GET THE SIZE AND ADDRESS OF THE NEXT BUFFER
				; AND TURN ON THE USE BIT
	TLZ	T3,IOUSE	;CLEAR THE USE BIT FOR ADVEVM
IFN FTVM,<
	HRRZ	T1,T3		;ADDRESS OF START OF BUFFER
	PUSHJ	P,IADCKL	;MAKE SURE ITS LEGAL (MIGHT BE PAGED OUT)
	  JRST	ADVBU2		;ILLEGAL ADDRESS (ADR CHECK)
	HRLM	T3,DEVEVM(F)	;LEGAL ADR, SAVE AS NEXT BUFFER LOC
	PUSHJ	P,BADCK		;IS WHOLE BUFFER LEGAL AND IN CORE?
	  JRST	ADVBU2		;NO, STOP IO
>
IFE FTVM,<
	PUSHJ	P,BADCK		;ADDRESS CHECK THE NEXT BUFFER
	  JRST	ADVBU2		;OUT OF BOUNDS - GIVE STOP I/O RETURN
>
	PUSHJ	P,ADVEVM##	;ADVANCE THE BUFFER IN EXEC VIRTUAL MEMORY
	  JRST	ADVBU2		;NOT ENOUGH PAGES TO COVER THE NEXT BUFFER
				; UUO LEVEL WILL ALLOCATE MORE ON NEXT UUO
	DPB	T1,PDVIAD##	;STORE THE EXEC VIRTUAL ADDRESS OF THE NEXT
				; BUFFER FOR THE DEVICE ROUTINE
	SKIPGE	(T1)		;IS THE NEXT BUFFER AVAILABLE? (USE BIT OFF)
	JRST	ADVBU2		;NO, GIVE STOP I/O RETURN
	JRST	ADVBU1		;GO CHECK FOR OTHER REASONS I/O SHOULD BE STOPPED
>
ADVBF1:
;HERE TO ADVANCE A BUFFER WHICH IS NOT MAPPED BY THE EXEC MAP
IFN FTKA10,<
	MOVEI	T1,@T1		;RELOCATE THE BUFFER ADDRESS
>
	EXCTXU	<MOVEM	S,-1(T1)>
	EXCTUU	<IORB	T3,(T1)>;TURN ON THE USE BIT AND GET THE ADDRESS
				; AND SIZE OF THE NEXT BUFFER
IFN FTVM,<
	HRRZ	T1,T3		;ADDRESS OF START OF BUFFER
	PUSHJ	P,IADCKL	;MAKE SURE ITS LEGAL (MIGHT BE PAGED OUT)
	  JRST	ADVBU3		;ILLEGAL ADDRESS (ADR CHECK)
	HRRM	T3,DEVIAD(F)	;LEGAL ADR, SAVE AS NEXT BUFFER LOC
	PUSHJ	P,BADCK		;IS WHOLE BUFFER LEGAL AND IN CORE?
	  JRST	ADVBU3		;NO, STOP IO
>
IFE FTVM,<
	PUSHJ	P,BADRCK	;ADDRESS CHECK THE NEXT BUFFER
	  JRST	ADVBU3		;OUT OF BOUNDS, GIVE STOP I/O RETURN
	HRRM	T3,DEVIAD(F)	;STORE THE USER VIRTUAL ADDRESS OF THE
				; NEXT BUFFER FOR THE DEVICE ROUTINE
>
IFN FTKA10,<
	ADDI	T3,(R)		;RELOCATE BUFFER ADDRESS
>
	EXCTUX	<SKIPGE (T3)>	;IS THE BUFFER EMPTY?
	JRST	ADVBU3		;NO, GIVE STOP I/O RETURN

;HERE TO SEE IF I/O SHOULD BE STOPPED SO JOB CAN BE SHUFFLED,
; SWAPPED, LOCKED, OR THE USER HAS TYPED CONTROL C


ADVBU1::LDB	T2,PJOBN##	;GET JOB NUMBER OF JOB I/O IS BEING DONE FOR
	SKIPGE	T2,JBTSTS##(T2)	;IS THE JOB RUNNABLE?
	TLNE	T2,SHF!CMWB!CNTRLC
	JRST	ADVBU2		;NO, GIVE STOP I/O RETURN
IFN FTLOCK,<
	TRNN	T2,LOK		;TRYING TO LOCK THE JOB IN CORE?
>
	TRNE	S,IOCON		;OR DISCONTINUOUS MODE I/O?
	JRST	ADVBU2		;YES, SHUT DOWN THE I/O
	AOSA	-1(P)		;SET SKIP (CONTINUE I/O) RETURN
ADVBU2:	PUSHJ	P,RTNEVM##	;SHUTTING DOWN I/O, GIVE BACH ANY EVM
ADVBU3:	POP	P,T3		;RESTORE T3
	POPJ	P,		;GIVE STOP OR CONTINUE I/O RETURN

;ROUTINE TO ADDRESS CHECK A BUFFER
;CALLING SEQUENCE:
;	MOVE	T3,USER VIRTUAL BUFFER ADDRESS
;	PUSHJ	P,BADRCK
;	RETURN HERE ON ADDRESS CHECK
;	RETURN HERE IF BUFFER IS OK
;PRESERVES T3

BADCK:
BADRCK::
IFE FTVM,<
	MOVEI	T1,-1(T3)	;T1 = ADDRESS OF WORD -1 OF BUFFER
	PUSHJ	P,IADRCK	;ADDRESS CHECK THAT
	  POPJ	P,		;OUT OF BOUNDS
	HRRZ	T2,T3
IFN FTKA10,<
	TLO	T2,R		;RELOCATE KA10 STYLE
>
	EXCTUX	<HLRZ T2,@T2>	;T2=NUMBER OF WORDS IN THE BUFFER
	TRZ	T2,IOUSE	;ZERO THE USE BIT
	ADDI	T1,1(T2)	;T1 = ADDRESS OF LAST WORD IN THE BUFFER
	PJRST	IADRCK		;ADDRESS CHECK THAT
>
IFN FTVM,<
	HRRZ	T1,T3		;T1=ADDRESS OF FIRST WORD IN THE BUFFER
	PUSHJ	P,IADRCK	;IN-CORE AND LEGAL?
	  POPJ	P,		;NO
	EXCTUX	<HLRZ	T2,(T1)>  ;SIZE
	TRZ	T2,IOUSE
	ADDI	T2,(T1)		;TOP OF BUFFER
	SOJA	T1,ZRNGE##	;LET VMSER CHECK THE LIMITS
>
;ROUTINE TO ADDRESS CHECK AT UUO LEVEL ONLY
;CALL	HRRZ T1,REL ADR.
;	PUSHJ P,UADCK1
;	NEVER RETURNS IF ERROR,STOPS JOB AND PRINTS ERROR
;BAD ADR. IF IN LOC 20-JOBPFI IN JOB DATA AREA
;OR IF ABOVE PROTECTION(USRREL) FOR CURRENT JOB

UADCK1::TRNN	T1,777760	;IN USER ACS?
	POPJ	P,		;YES, ADDRESS IS OK

;ROUTINE TO ADDRESS CHECK AT UUO LEVEL ONLY
;USER ACS ARE ALSO ILLEGAL(ADR IS FOR IO USE LATER AT
;INTERRUPT LEVEL)
;CALL:	HRRZ T1,REL.ADR.
;	PUSHJ P,UADRCK
;	NEVER RETURN IF ERROR

UADRCK::CAILE	T1,JOBPFI##	;IS ADR. IN IO PROT. PART OF JOB DATA AREA?
	CAMLE	T1,USRREL##	;NO, IS IT ABOVE PROTECT.?
	JRST	ADRERR##	;YES, STOP JOB AND PRINT ERROR
IFE FTVM,<
	POPJ	P,		;NO
>
IFN FTVM,<
	PUSHJ	P,FLTST##	;NO, IS PAGE IN CORE?
	  PJRST	UUOFLT##	;NOT THERE, CALL PAGE FAULT HANDLER
	CAML	T1,.UPMP+.UPHSS	;NO PAGE FAULT - IS IT IN THE LOW SEG?
	CAML	T1,.UPMP+.UPHSE
	POPJ	P,		;YES, OK
	PJRST	ADRERR##	;NO, ADDRESS CHECK
>
;ROUTINE TO ADDRESS CHECK AT ANY LEVEL
;CALL:	MOVE R,[XWD PROT.,RELOC,]
;	HRRZ T1,REL. ADR.
;	PUSHJ P,IADRCK
;	ERROR RETURN(ERROR MESSAGE NOT PRINTED,JOB NOT STOPPED)
;	OK RETURN

IADRCK::
IFN FTVM,<
	PUSHJ	P,FLTST##	;MAKE SURE IN CORE
	  POPJ	P,		;ITS NOT
>
IADCKL:	MOVS	T2,R		;GET PROTECTION(TO RH)
	CAILE	T1,JOBPFI##	;ADR. ABOVE PROT. PART OF JOB DATA AREA?
	CAILE	T1,(T2)		;YES, BELOW OR EQUAL TO PROTECT.?
	POPJ	P,		;NO
IFN FTVM,<
	CAML	T1,.UPMP+.UPHSS
	CAML	T1,.UPMP+.UPHSE	;MAKE SURE PAGE IS IN LOW SEGMENT
>
	AOS	(P)		;IT IS, SKIP
	POPJ	P,		;RETURN

;SUBROUTINE TO ADDRESS CHECK AN ASCIZ STRING IN A USER'S ADDRESS SPACE
;CALLING SEQUENCE:
;	MOVE	T1, BYTE POINTER TO STRING (LH=-1 IF LEFT JUSTIFIED STRING)
;	PUSHJ	P,CKSTR
;DOESN'T RETURN IF A PAGE FAULT WOULD OCCUR, RETURNS CPOPJ ON AN
; ADDRESS CHECK, CPOPJ1 IF OK TO REFERENCE THE STRING, T1=
; BYTE POINTER TO THE STRING
;PRESERVES T2-T4

CKSTR::	PUSHJ	P,SAVE4##	;SAVE P1-P3
	MOVEI	P4,200		;DON'T LET SOME TURKEY MAKE US LOOP TOO LONG
	HLRE	P1,T1		;LEFT HALF OF THE BYTE POINTER
	AOSN	P1		;IS IT -1?
	HRLI	T1,(POINT 7,0)  ;YES, MAKE IT A POINTER TO A LEFT JUSTIFIED STRING
	PUSH	P,T1		;SAVE THE BYTE POINTER
	PUSH	P,M		;AND M
	HRRI	M,-1(T1)	;SETUP M TO FETCH THE STRING
	MOVEI	P1,44		;SETUP ROTATE OFFSET
	LDB	P2,[POINT 6,T1,5]  ;GET RESIDUE
	SUB	P1,P2
	IDIVI	P2,7		;NUMBER OF BYTES IN THE FIRST WORD
	PUSHJ	P,GETWR1##	;GET THE FIRST WORD
	  JRST	CKSTR4		;ADDRESS CHECK
	LSH	T1,(P1)		;LEFT JUSTIFY FIRST BYTE
	JRST	CKSTR2		;CHECK IT
CKSTR1:	MOVEI	P2,5		;FIVE BYTES PER WORD
	PUSHJ	P,GETWR1##	;GET THE NEXT WORD
	 JRST	CKSTR4		;ADDRESS CHECK
CKSTR2:	TLNN	T1,(177B6)	;A NULL BYTE?
	JRST	CKSTR3		;YES, STRING IS OK
	LSH	T1,7		;LEFT JUSTIFY THE NEXT BYTE
	SOJG	P2,CKSTR2	;JUMP IF MORE BYTES IN THIS WORD
	SOJG	P4,CKSTR1	;GET NEXT WORD. IS STRING LONG?
	MOVEI	T1,1		;YES. PAUSE A SECOND AND LET OTHERS RUN
	PUSHJ	P,SLEEP
	MOVEI	P4,200		;THEN RESUME FOR ANOTHER
	JRST 	CKSTR1		;FRAGMENT
CKSTR3:	AOS	-2(P) 		;SKIP RETURN
CKSTR4:	POP	P,M		;RESTORE M
	JRST	TPOPJ##		;RESTORE BYTE POINTER AND RETURN
	SUBTTL	DUMP MODE COMMAND LIST PROCESSING ROUTINES

;ROUTINE TO SCAN A DUMP MODE COMMAND LIST
;AND FIND THE NEXT IO COMMAND WORD.  THE LIST
;CONSISTS OF IOWD FORMAT WORDS (LH=NEGATIVE
;WORD COUNT-RH=ADDRESS OF FIRST WORD MINUS 1) AND
;GO TO WORDS (LH=ANY POSITIVE VALUE-RH=ADDRESS
;OF NEXT GO TO WORD OR IOWD).  THE LIST IS
;TERMINATED BY A WORD OF ALL BINARY ZEROES.  WHERE
;NO GO TO WORD INTERVENES, THE WORDS OF A LIST
;OCCUPY SEQUENTIAL MEMORY LOCATIONS.  TO PREVENT
;LOOPING IN THIS ROUTINE, A MAXIMUM OF 3 SUCCESSIVE GO TO
;WORDS IS PERMITTED BE FOUND BEFORE AN IOWD MUST BE
;THIS ROUTINE IS CALLED AT UUO AND INTERRUPT LEVELS

;CALL:	MOVE M,[XWD R,RELATIVE ADDRESS OF FIRST COMMAND]
;	PUSHJ P,COMCHK
;THIS ENTRY (COMCHK) SHOULD ONLY BE USED THE
;FIRST TIME THE ROUTINE IS CALLED FOR A PARTICULAR
;DUMP IO REQUEST.  IT SETS UP THE BOUNDARY VALUES
;FOR SUBSEQUENT ADDRESS CHECKS AND MUST BE
;CALLED AT UUO LEVEL
;SUBSEQUENT CALLS: SET M=TO ADDRESS OF LAST COMMAND EXECUTED
;(AS RETURNED BY PREVIOUS CALL TO THIS ROUTINE)
;	PUSHJ P,NXCMR
;RETURN FROM BOTH CALLS IS TO CALL +1
;WITH ACCUMULATORS SET AS FOLLOWS:
;(T2)=USER UPPER LIMIT (SET BY COMCHK-MUST BE SET UP BEFORE CALLING NXCMR)
;(T3)=USER LOWER LIMIT (SET BY COMCHK-MUST BE SET UP BEFORE CALLING NXCMR)
;(M)=ADDRESS OF IOWD FOR NEXT DUMP MODE IO OPERATION
;(T1)=THE IOWD ITSELF OR 0 IF END OF LIST
;(S)=0 IF NO ERROR, -1 IF AN ERROR
;ERRORS ARE:	IO OUTSIDE THE USER'S AREA
;		MORE THAN 3 GO TO WORDS (LH .GE. 0) IN SUCCESSION
;		COMMAND LIST OUTSIDE THE USER'S AREA
;		(COMMANDS MAY BE IN AC'S, BUT IO TO
;		AC'S IS ILLEGAL
;AC'S CLOBBERED: S,T1,T2,T3,M
;USED BUT RESTORED: P1,P2,P3

COMCHK::MOVEI	T3,JOBPFI##	;HIGHEST PROTECTED LOCATION IN JOBDAT
	SKIPGE	USRHCU##	;IS A SAVE OR GET IN PROGRESS?MAY BE RUN UUO
	MOVEI	T3,JOBSAV##	;YES.  USE HIGHEST LOCATION NOT WRITTEN BY SAVE
	SOS	M		;BACK UP POINTER-IT WILL BE INCREMENTED
	HLRZ	T2,R		;HIGHEST USER LOCATION
NXCMR::	PUSHJ	P,SAVE4##	;SAVE P1-P4
	LDB	P4,PJOBN##	;P4=JOB NUMBER OF JOB DOING I/O
	EXCH	P4,J		;SAVE J IN P4 AND PUT THE JOB NUMBER IN J
IFN FTKI10!FTKL10,<
	PUSHJ	P,SVEUB##	;MAKE THE JOB ADDRESSABLE
	MOVEI	T1,JS.ASA	;FLAG SAYING MEMORY REFERENCES TO USER 0-17
	TDNE	T1,JBTSTS##(J)	; ARE TO SHADOW AC'S - IS IT ON?
	TLO	J,400000	;YES, REMEMBER THAT
	MOVEI	T1,(J)		;PICK UP THIS JOB'S NUMBER
	CAME	T1,.C0JOB##	;IS IT THE ONE WE'RE RUNNING
	PUSHJ	P,SETASA##	;NO, FLAG REFERENCES TO USER 0-17 AS SHADOW
				; AC REFERENCES
>
	HRREI	P1,-3		;ALLOW A MAXIMUM OF 3 GO TO WORDS
	PUSH	P,T2		;SAVE HIGHEST USER LOCATION
	AOSA	T1,M		;POINT TO THE NEXT OR FIRST IOWD
NXCMRA:	HRRM	T1,M		;GET NEXT COMMAND IF THIS ONE IS A GOTO WORD
	PUSHJ	P,GETWRD##	;GET THE IOWD
	  JRST	NXBAD		;ADDRESS CHECK
	JUMPE	T1,NXCOK	;IF 0, ITS THE LIST TERMINATOR
	TLNE	T1,-1		;A GOTO WORD ?
	JRST	NXCHIT		;NO, A REAL IOWD, GO CHECK IT
	AOJLE	P1,NXCMRA	;YES, ITS A GOTO WORD
NXBAD:	MOVEI	S,-1		;FLAG BAD COMMAND
	TDZA	T1,T1		;ZERO T1 AS IF THE LIST HAD TERMINATED
NXCOK:	MOVEI	S,0		;THE IOWD IS OK
IFN FTKI10!FTKL10,<
	SKIPL	J		;WAS JS.ASA FLAG ON?
	PUSHJ	P,CLRASA##	;NO, CLEAR SHADOW AC REFERENCE FLAG
>
	MOVE	J,P4		;RESTORE J
	JRST	NXOUT		;EXIT WITH T1, M AND S SET TO SHOW
				;RESULTS. IF CALL WAS TO COMCHK,T2 & T3 ALSO SET
				;TO USER BOUNDARIES. ALWAYS EXIT TO CALL +1
NXCHIT:
IFN FTEXE,<JUMPL J,NXCOK	;TRUCT COMCON IF SAVE IN PROGRESS
	  			; DON'T ADDRESS-CHECK
>;END IFN FTEXE
	HRRZ	P2,T1		;THIS IS IOWD OR GO TO NOT POINTING TO AC
	HLRO	P3,T1		;SAVE ADDRESS POINTED TO AND NEGATIVE COUNT
	CAMG	P2,T3		;IS START ABOVE PROTECTED AREA?
	JRST	NXBAD		;NO. REPORT ERROR
	MOVMS	P3		;WORD COUNT
	ADD	P2,P3		;END OF IO
IFN FTEXE,<
	SKIPGE	JOBHCU##(R)	;IF SAVE N IN PROGRESS,
	TLZ	P2,-1		; SUPPRESS CARRY IF ADR=-1
>
	CAMLE	P2,(P)		;END OF IO ABOVE USER UPPER LIMIT?
	JRST	NXBAD		;YES, IO WOULD RUN PAST END OF USER AREA
IFN FTVM,<
	SKIPGE	JOBHCU##(R)	;SAVE IN PROGRESS?
	JRST	NXCOK		;YES, IOWD LIST IS OK
	MOVE	T2,P2		;TOP ADR FOR IO
	MOVE	P2,T1		;PRESERVE T1
	MOVEI	T1,1(T1)	;START ADR FOR IO
	PUSHJ	P,ZRNGE##	;ALL PAGES IN CORE?
	  JRST	NXBAD		;NO, USER FIDDLED WITH HIS LIST
				; (LIST WAS CHECKED BEFORE IO STARTED - WAS OK THEN)
	MOVE	T1,P2		;YES, RESTORE T1
>
	JRST	NXCOK		;EXIT-FOUND A GOOD IOWD

;ROUTIE TO MAKE THE USER AREA REPRESENTED
;BY THE IOWD IN T1 ADDRESSABLE.
;IF THIS IS A KA10, THE IOWD IS BAD (ADDRESS
;CHECK), OR THE IOWD IS THE LIST TERMINATOR,
;RETURN IMMEDIATELY.  IF THIS IS AN I/O BUS
;DEVICE, MAPE THE NEW IOWD IN THE EXEC
;MAP.  THIS CAN ONLY FAIL IF THE NUMBER
;OF PAGES THIS JOB HAS IN THE EXEC
;MAP IS NOT GREAT ENOUGH TO COVER
;THE IOWD (ONLY HAPPEMS IF I/O INTO THE
;LIST SINCE THE LIST IS SCANNED AT UUO
;LEVEL).
NXOUT:	JUMPE	T1,T2POPJ##	;LAST WORD IN THE LIST OR ADDRESS CHECK?
				;YES, RESTORE T2 AND RETURN
IFN FTKI10!FTKL10,<
	SKIPN	DEVEVM(F)	; THE DEVICE GOES DIRECT TO MEMORY
				; THROUGH A CHANNEL
	JRST	NXOUTA		; JUST RELOCATED THE IOWD KA10 STYLE AND RETURN
	PUSH	P,T3		;SAVE LOWER BOUND ON I/O
	HLRE	T2,T1		;T2 = - WORD COUNT FOR CURRENT IOWD
	MOVNS	T2		;T2 = POSITIVE WORD COUNT
	SUBI	T2,2		;CALCULATE NUMBER OF PAGES NECESSARY
	IDIVI	T2,PAGSIZ##+2	; TO COVER THIS WORD COUNT BY MAPPING THE
	ADDI	T2,2		; AREA SPECIFIED BY THE IOWD IN THE EXEC MAP
	LDB	T3,PDEVMS##	;GET THE NUMBER OF PAGES OF EVM ALLOCATED
				; TO THIS DEVICE
	MOVEI	S,-1		;ASSUME THERE ARE NOT ENOUGH
	CAMLE	T2,T3		;ARE THERE ENOUGH PAGES TO COVER CURRENT
				; WORD COUNT?
	JRST	NXOUT1		;NO, ADDRESS CHECK RETURN
	PUSH	P,T1		;SAVE THE IOWD
	PUSHJ	P,SAVDDL##	;ADJUST IOWD FOR HIGH SEGMENT SAVE
	PUSHJ	P,UVACKS##	;COMPUTE UVA IN CASE SSAVE IN PROGRESS
	MOVEI	T3,1(T2)	;ADDRESS INTO WHICH I/O WILL BE DONE
	LDB	T2,PDEVMS##	;RESTORE NUMBER OF PAGES
	LDB	T1,PDEVM##	;GET PAGE NUMBER OF FIRST PAGE IN THE EXEC
				; MAP ALLOCATED TO THIS DEVICE
	PUSHJ	P,MAPUEI##	;MAP THE IOWD IN THE EXEC MAP
	MOVEI	S,0		;FLAG CURRENT IOWD OK
	HRRM	T3,(P)		;STORE EXEC VIRTUAL ADDRESS IN IOWD
	POP	P,T1		;T1 = XWD -N,EXEC VIRTUAL ADDRESS FOR I/O
NXOUT1:	POP	P,T3		;RESTORE LOWER BOUND ON I/O TO USER AREA
	SOJA	T1,T2POPJ##	;RESTORE UPPER BOUND AND RETURN
>
NXOUTA:	IFN FT2REL,<
	CONSO	PI,PIPROG##	;DON'T DIDDLE IOWD AT INTERRUPT LEVEL
	PUSHJ	P,SAVDDL##	;ADJUST IOWD FOR HIGH SEGMENT SAVE/GET
>
	MOVE	T2,T1		;GUARD AGAINST CARRY INTO THE LEFT HALF WORD
	ADDI	T1,(R)		;RELOCATE
	HLL	T1,T2		;RESTORE THE WORD COUNT
	JRST	T2POPJ##	;RESTORE T2 AND RETURN
	SUBTTL	DDB SCAN LOGIC


;ASSIGN DEVICE IF UNASSIGNED
;CALL:	MOVE J, JOB NUMBER
;	MOVE F, ADDR. OF DDB
;	MOVE T1,DEVICE NAME
;	MOVEI T2, EITHER ASSPRG OR ASSCON
;	PUSHJ P, ASSASG
;	CAN'T ASSIGN RETURN
;	ASSIGNED RETURN


ASSASG::
IFN FTDISK,<IFN FTSPL,<
	PUSHJ	P,SAVE2##
	SETZB	P1,P2		;P1 WILL GET DEVMOD IF SPOOLING
	HRRZ	T3,SPLBIT##(F)	;POSSIBLE SPOOL-BIT
	SKIPN	DEVCHR(F)	;FAKE (TABLE) DDB?
	JRST	ASSAS0		;YES, SPOOL IT
	LDB	T3,DEYSPL##	;SPOOL BIT FOR THE DEVICE
	SKIPGE	DEVSPL(F)	;IS THIS A SPOOLED DISK DDB ?
	TLOA	T3,DEPSPL	;YES.  ENSURE COPY HAS DEPSPL ON
	TDNN	T3,JBTSPL##(J)	;JOB SPOOLING THIS DEVICE?
	JRST	ASSAS1		;NO
	MOVE	P2,T3		;SPOOL BIT
	LDB	T3,PJOBN##	;YES, GET OWNER OF DEVICE
	MOVE	T4,DEVMOD(F)	;DEVMOD
	TRNE	T4,ASSCON	;ASSIGNED BY CONSOLE?
	CAME	T3,J		;YES. TO THIS JOB?
ASSAS0:	TLOA	T3,DEPSPL(P2)	;NO. SET UP TO SPOOL
	JRST	ASSAS2		;YES - USE PHYSICAL DEVICE
	MOVE	P1,DEVMOD(F)	;TELL SETDDB TO STUFF THIS IN DEVMOD
	HRRI	F,DSKDDB##	;SET F TO PROTOTYPE DISK DDB
ASSAS1:>			;CLOSE FTSPL CONDITIONAL
	MOVE	T4,DEVMOD(F)	;DEVMOD
	TLNN	T4,DVDSK	;DEVICE A DISK?
	JRST	ASAS1A		;NO
	PUSHJ	P,SETDDB##	;YES, GENERATE A NEW DDB
	  JRST	ASSAS5		;NO DDB SPACE


ASAS1A:
IFN FTSPL,<
	HLLZS	T3		;LH(T3)=0 OR DEPSPL
	IORM	T3,DEVSPL(F)	;LIGHT SPOOL-BIT IF NEEDED
ASSAS2:>			;CLOSE FTSPL
>				;CLOSE FTDISK
	NOSCHEDULE		;DISABLE SCHEDULING
	MOVEI	T3,DEPMSG
	TDNE	T3,DEVMSG(F)	;CONTROLLED BY MPX?
	JRST	ASSAS5		;YES, ALWAYS FAIL
	LDB	T1,PJOBN##	;GET JOB NUMBER IN DEV DATA BLOCK
	CAMN	T1,J		;IS IT ALREADY ASSIGNED TO THIS JOB
	JRST	ASSA2C		;YES
	MOVEI	T1,ASSPRG+ASSCON	;NO, IS IT ASSIGNED TO ANOTHER JOB?
IFN FTKL10,<
	CONO	PI,PIOFF##	;TEMPORARY UNTIL KL PI SYSTEM FIXED
	CONO	PI,SCNOFF##+PI.ON
>	;END IFN FTKL10
IFE FTKL10,<
	CONO	PI,SCNOFF##	;TURN SCANNER OFF
>
	TDNE	T1, DEVMOD(F)	;ARE EITHER ASSIGNED BITS SET?
	JRST	ASSAS4		;YES
	HRLZI	T1,DEPRAS	;GET RESTRICTED ASSIGNMENT BIT
	TDNN	T1,DEVSTA(F)	;IS THIS DEVICE RESTRICTED?
	JRST	ASSA2A		;NO, PROCEED
	PUSHJ	P,PRVJ##	;THIS JOB PRIVILEDGED TO ASSIGN?
	  JRST	ASSA2A
	JRST	ASSA4A		;NO, SET T2=-1 AS FLAG
ASSA2A:
IFN FTGALAXY,<
	SKIPE	%SIMDA##	;MDA NOT RUNNING?
	CAMN	J,MDAJOB##	;OR JOB=MDAJOB
	JRST	ASSA2B		;YES, SKIP ALL THIS
	MOVSI	T1,DVCMDA	;A CONTROLLED DEVICE?
	TDNE	T1,DEVCHR(F)	;?
	JRST	ASSA4A		;YES, LOSE
>	;END IFN FTGALAXY
ASSA2B:	PUSH	P,T2		;SAVE T2 OVER CALL TO SETDVL
	PUSHJ	P,SETDVL	;STORE JOB NUMBER IN DDB
	POP	P,T2		;RESTORE T2
	IORM	T2,DEVMOD(F)	;SET IN USE BITS
	CONO	PI,SCNON##	;TURN SCANNER ON
ASSA2C:
IFN FTMTSET,<
	TRNN	T2,ASSCON	;IF ASSIGN COMMAND,
	JRST	ASSAS3
	HLLZ	T1,DEVMOD(F)	;GET CHARACTERISTICS, SET RH FOR DPB
	TLNE	T1,DVMTA	;CHECK FOR MTA
	TLNE	T1,DVTTY	;BE SURE IT ISN'T NUL!
	JRST	ASSAS3		;NOT MTA
	HRRI	T3,MTSIZ##+1	;GET DEFAULT MTA BLOCK SIZE
	DPB	T3,PBUFSZ##	;  SET SYSTEM DEFAULT BUFFER
	DPB	T1,TDYDN1##	; SET TO FORCE INSTALLATION DENSITY
	DPB	T1,PBUFRM##	;CLEAR FRAME-COUNT
IFN FTDX10,<
	DPB	T1,PMTRTY##	;ENABLE AUTO ERROR-RETRY
>
>	;END CONDITIONAL ON FTMTSET
ASSAS3:	SCHEDULE		;TURN SCHEDULING ON
IFN FTGALAXY,<
	MOVSI	T1,DVCMDA	;CONTROLLED?
	TDNE	T1,DEVCHR(F)	;IS IT?
	SKIPN	%SIMDA##	;IF MDA ISN'T RUNNING
	JRST	ASSA3A		;NO HASLES
	MOVSI	T1,DVDATJ	;ALLOCATED?
	TDNN	T1,DEVCHR(F)	;?
	JRST	ASSA4A		;NO, LOSE
>	;END IFN FTGALAXY
ASSA3A:	IORM	T2,DEVMOD(F)	;SET IN USE BITS AGAIN IN CASE
				;  IT IS THE SAME JOB
	JRST	CPOPJ1##	;GIVE OK RETURN

;HERE IF CAN NOT DO IT

ASSA4A:	HRREI	T2,-1		;FLAG AS RESTRICTED DEVICE
ASSAS4:	CONO	PI,SCNON##	;TURN SCANNER ON
	SCHEDULE		;TURN SCHEDULING ON
ASSAS5:	POPJ	P,		;GIVE ERROR RETURN

IFN FT5UUO!FTNET!FTSFD,<
;DVCNSG -- ROUTINE TO FIND DDB FOR THOSE UUOS
;		WHICH HAVE DUAL STYLE ARGUMENT:
;		(1) 0-17 = CHANNEL NUMBER (INITED)
;		(2) ELSE = SIXBIT DEVICE NAME (GENERIC,...)
;CALL:	MOVE T1,ARGUMENT
;	PUSHJ P,DVCNSG
;RETURN CPOPJ IF NO SUCH DEVICE
;SKIP RETURN WITH F = DDB ADDRESS IF FOUND


DVCNSG::CAILE	T1,17		;SKIP IF KNOWN NOT TO BE A UDX
	PUSHJ	P,UDXDDB	;SEE IF T1 IS A UDX
	  SKIPA			;NO--DO ORDINARY STUFF
	JRST	CPOPJ1##	;YES--ALL DONE
	SKIPL	T1		;IF NEGATIVE
	CAILE	T1,17		;  OR .GT. 17,
	PJRST	DEVSRG		;  MUST BE SIXBIT
	SKIPE	F,USRJDA##(T1)	;GET DDB IF SETUP
	CAMLE	T1,USRHCU##	;CHECK FOR LEGALITY
	POPJ	P,		;ERROR IF BAD
	JRST	CPOPJ1##	;WIN IF ALL OK.
>	;END CONDITIONAL ON FT5UUO!FTNET!FTSFD

;SUBROUTINES TO MAINTAIN THE LOGICAL NAME TABLE.  THIS IS USED TO
;  SPEED UP THE LOGICAL NAME SEARCHING.

LDVTLN==4	;LENGTH OF THE TABLE IN WORDS.

INTERNAL FTHSLN

;SUBROUTINE TO MARK THE DDB IN F AS OWNED BY THE JOB IN J.
;  IF THE DEVICE HAS A NON-BLANK LOGICAL NAME IT IS PUT IN
;  THE JOB'S LOGICAL NAME TABLE.

SETDVL::PUSHJ	P,CLRDVL	;CLEAR CURRENT OWNER, IF ANY.
	DPB	J,PJOBN##	;STORE JOB NUMBER IN DDB
IFN FTHSLN,<
	JUMPE	J,CPOPJ##	;ALL DONE IF JOB ZERO.
	SKIPN	DEVLOG(F)	;HAS THE DEVICE A LOG. NAME?
	POPJ	P,		;NO, ALL DONE.
	PUSHJ	P,FNDPDB##	;FIND JOB'S PDB
	  POPJ	P,		;NONE, FORGET IT.
	SKIPLE	T1,.PDDVL##(W)	;IS THERE ALREADY A DDB TABLE?
	PJRST	SETDV1		;YES, JUST ADD TO EXISTING SET
;	PJRST	SETDVS		;NO, BUILD ONE.

;SUBROUTINE TO BUILD THE LOGICAL NAME TABLE.  USED WHEN THE FIRST
;  LOGICAL NAME IS ASSIGNED AND IF THE NUMBER OF LOGICAL NAMES
;  BECOMES TOO LARGE.

SETDVS:	MOVEI	T2,LDVTLN	;OBTAIN THE TABLE SPACE
	JUMPE	T2,SETDV2	;  THERE IS NONE, SCAN THE DDBS.
	PUSHJ	P,GETWDS##	;GET THAT MANY WORDS
	  JRST	SETDV2		;  NOT AVAIL, SCAN DDBS FOR LOG NAMES.
	HRLZ	T2,T1		;GOT THE SPACE -- CLEAR THE BLOCK.
	HRRI	T2,1(T1)	;FORM BLT ADDRESSES
	SETZM	(T1)		;CLEAR FIRST WORD
	BLT	T2,LDVTLN-1(T1)	;CLEAR THE REST OF THE WORDS
	SKIPL	.PDDVL(W)	;WERE THERE NO LOGICAL NAMES?
	JRST	SETDV3		;YES, JUST STORE THIS DDB.

;COME HERE IF THERE WERE TOO MANY LOGICAL NAMES TO FIT IN THE
;  TABLE.  TRY TO REBUILD THE TABLE BY SCANNING THE DDBS.

	MOVEM	T1,.PDDVL##(W)	;STORE POINTER TO TABLE
	PUSH	P,F		;PRESERVE F
	HLRZ	F,DEVLST##	;SCAN ALL DDBS
SETDV4:	SKIPN	DEVLOG(F)	;HAS THIS DDB A LOGICAL NAME?
	JRST	SETDV8		;NO, TRY NEXT DDB.
	LDB	T1,PJOBN##	;YES, BELONG TO THIS JOB?
	CAMN	T1,J
	PUSHJ	P,SETDV1	;YES, PUT IN LOG NAME TABLE
SETDV8:	HLRZ	F,DEVSER(F)	;GET NEXT DDB
	JUMPN	F,SETDV4	;DO THE REST OF THE LIST
	POP	P,F		;RESTORE F
	POPJ	P,		;AND RETURN.
;COME HERE IF CORE WAS GOTTEN SUCCESSFULLY AND THIS IS THE FIRST
;  DEVICE WITH A LOGICAL NAME.

SETDV3:	MOVEM	T1,.PDDVL##(W)	;STORE POINTER TO TABLE
;	PJRST	SETDV1		;PUT THIS DDB IN THE TABLE

;SUBROUTINE TO ADD A DDB POINTER TO THE SET OF POINTERS ALREADY
;  ASSOCIATED WITH A JOB.  IF THE TABLE IS FULL IT IS RELEASED
;  AND LOGICAL NAME SEARCHING WILL BE DONE BY SCANNING ALL DDBS
;  UNTIL THE NUMBER OF LOGICAL NAMES GETS SMALL ENOUGH TO FIT
;  IN THE TABLE.   DDB POINTER IN F, JOB NUMBER IN J.

SETDV1:	SKIPG	T1,.PDDVL##(W)	;IS THERE A TABLE?
	POPJ	P,		;NO, FORGET IT.
	HRLI	T1,-LDVTLN	;LENGTH OF TABLE (FOR AOBJN)
SETDV7:	SKIPN	T2,(T1)		;IS THE WORD ZERO?
	JRST	SETDV5		;YES, USE LEFT HALF.
	TLZN	T2,-1		;NO, IS L.H. ZERO?
	JRST	SETDV5		;YES, USE IT.
	JUMPE	T2,SETDV6	;NO, IF R.H. IS ZERO, USE IT.
	AOBJN	T1,SETDV7	;BOTH NON-ZERO, TRY NEXT WORD.
;	PJRST	SETDVF		;TOO MANY, FLUSH TABLE.

;SUBROUTINE TO RETURN THE TABLE TO FREE STORAGE AND
;  ARRANGE TO USE DDB SCAN.  USED IF THERE ARE TOO MANY LOGICAL
;  NAMES TO FIT IN THE TABLE.

SETDVF:	MOVEI	T1,LDVTLN	;LENGTH OF TABLE
	MOVE	T2,.PDDVL##(W)	;POINT TO TABLE
	PUSHJ	P,GIVWDS##	;RETURN THE TABLE SPACE

;COME HERE IF THE TABLE SPACE IS UNAVAILABLE OR, AFTER RETURNING
;  TABLE, IF THERE ARE TOO MANY LOGICAL NAMES.

SETDV2:	SETOM	.PDDVL##(W)	;FLAG NO VALID TABLE
>	;END OF IFN FTHSLN
	POPJ	P,		;RETURN.

IFN FTHSLN,<
;COME HERE IF L.H. IS ZERO AND THEREFORE SUITABLE FOR A DDB POINTER

SETDV5:	HRLM	F,(T1)		;STORE DDB POINTER IN TABLE
	POPJ	P,		; AND RETURN.

;COME HERE FIR R.H.

SETDV6:	HRRM	F,(T1)		;STORE DDB POINTER IN TABLE
	POPJ	P,		; AND RETURN.

>	;END OF IFN FTHSLN
;SUBROUTINE TO TERMINATE OWNERSHIP OF A DEVICE.  F POINTS TO THE
;  DDB.  PRESERVES J.

CLRDVL::LDB	T1,PJOBN##	;FIND OWNER
	JUMPE	T1,CPOPJ##	;NONE, NO PROBLEM.
	SETZ	T2,		;CLEAR JOB NUMBER IN DDB
IFN FTNET,<
	MOVSI	T3,DVCNET	;ON NETWORK?
	TDNN	T3,DEVCHR(F)	;SKIP FOR ZAPNET
>;END IFN FTNET
	DPB	T2,PJOBN##
IFN FTHSLN,<
	PUSH	P,J		;PRESERVE J
	MOVE	J,T1		;J = JOB NUMBER
	PUSHJ	P,FNDPDB##	;LOCATE JOB'S PDB
	  JRST	JPOPJ##		;NONE, FORGET IT.
	SKIPG	T1,.PDDVL##(W)	;POINT TO LOGICAL NAME TABLE
	JRST	CLRDV1		;NONE, TRY TO REBUILD.
	HRRZ	T3,F		;GET COPY OF F WITH L.H = 0
	HRLI	T1,-LDVTLN	;FIND THE DEVICE
CLRDV2:	SKIPN	T2,(T1)		;IS WHOLE WORD ZERO?
	JRST	CLRDV8		;YES, TRY NEXT WORD.
	CAIN	T3,(T2)		;NO, DOES R.H. POINT TO DDB?
	JRST	CLRDV4		;YES.
	HLRZS	T2		;NO, TRY LEFT HALF
	CAIN	T3,(T2)		;DOES L.H. POINT TO DDB?
	JRST	CLRDV3		;YES.
CLRDV8:	AOBJN	T1,CLRDV2	;NO, TRY NEXT WORD.
	POP	P,J		;NOT IN TABLE.  RESTORE J.
>	;END OF IFN FTHSLN
	POPJ	P,		;EXIT.
IFN FTHSLN,<
;COME HERE IF L.H. POINTER MATCHES.  CLEAR IT.

CLRDV3:	HRRZS	(T1)		;LEAVE R.H. POINTER, IF ANY.
	JRST	CLRDV5		; CHECK FOR EMPTY BLOCK

;COME HERE FOR R.H.

CLRDV4:	HLLZS	(T1)		;PRESERVE L.H. POINTER, IF ANY.
;	JRST	CLRDV5		; AND CHECK FOR EMPTY BLOCK.

;COME HERE TO CHECK FOR AN EMPTY BLOCK.  IF THE BLOCK IS
; EMPTY IT CAN BE FREED.

CLRDV5:	SKIPG	T1,.PDDVL##(W)	;POINT TO LOGICAL NAME TABLE
	JRST	JPOPJ##		;NONE, RESTORE J AND EXIT.
	HRLI	T1,-LDVTLN	;BUILD AOBJN POINTER
CLRDV6:	SKIPN	(T1)		;CHECK POINTERS TWO AT A TIME
	AOBJN	T1,CLRDV6	;DONE THEM ALL?
	JUMPL	T1,JPOPJ##	;AT LEAST ONE POINTER.
	PUSHJ	P,SETDVF	;NO POINTERS, FLUSH TABLE.
	SETZM	.PDDVL##(W)	;MARK JOB AS HAVING NO LOG. NAMES
	JRST	JPOPJ##		;RESTORE J AND RETURN.

;COME HERE IF THE TABLE IS NOT PRESENT.  TRY TO REBUILD IT.

CLRDV1:	JUMPE	T1,JPOPJ##	;IGNORE IF "NONE" RATHER THAN "INVALID"
	PUSHJ	P,SETDVS	;TRY TO REBUILD TABLE
	JRST	JPOPJ##		;RESTORE J AND RETURN.

>	;END OF IFN FTHSLN
;ROUTINE TO SEARCH FOR A DEVICE
;CALL:	HRR J,JOB NUMBER
;	MOVE T1,[SIXBIT .DEVICE NAME.]
;	PUSHJ P, DEVSRC
;	NOT FOUND
;	FOUND


DEVSRC::
	MOVEI	T2,DD%PHY	;SET UP FOR PHYSICAL SEARCH
IFE FT5UUO,<
IFN FTLOGIN,<
	MOVSI	F,JLOG		;DO NOT ALLOW LOGICAL NAMES IF JOB IS NOT
				;LOGGED IN OR ON BEING LOGGED OUT
	TDNE	F,JBTSTS##(J)
>>
	TRO	T2,DD%LOG	;SEARCH FOR LOGICAL TOO
	PJRST	DDBSRC		;GO DO IT

;SEARCH LOGICAL NAMES

DEVLG::
	MOVEI	T2,DD%LOG	;SEARCH FOR LOGICAL NAMES
	PJRST	DDBSRC		;GO DO IT
;come here to search for physical name

devphy::
	movei	t2,dd%phy	;set physical only flag
	pjrst	ddbsrc		; and go do the search
IFN FT5UUO!FTNET!FTSFD,<
;ROUTINE TO SEARCH FOR A DEVICE
; (INCLUDING GENERIC NAMES)
;SAME CALL AND RETURN AS DEVSRC


DEVSRG::PUSHJ	P,DEVSRC	;SEARCH PHYSICAL & LOGICAL NAMES
	  TDZA	T3,T3		;NOT FOUND
	JRST	CPOPJ1##	;FOUND
IFN FTSPL,<
;CALL DVSRSP TO SEARCH THE SPOOLING TABLE
; AND IF FAILS, GENERIC SEARCH
DVSRSP::HLLZ	T2,T1		;GENERIC NAME OF DEVICE
	MOVEI	F,SPLTAB##	;SCAN SPOOLABLE DEVICE TABLE FOR MATCH
SPLOOP:	CAMN	T2,SPLNAM##(F)
	JRST	SPLFND		;FOUND
	ADDI	F,SPLLEN##
	CAIGE	F,SPLTOP##
	JRST	SPLOOP
	JRST	SPLEND		;NOT A SPOOLING DEVICE - SCAN FOR GENERIC MATCH

SPLFND:	HRRZ	T2,SPLBIT##(F)	;SPOOLING DEVICE BIT
	TDNN	T2,JBTSPL##(J)	;JOB SPOOLING THIS DEVICE?
	JRST	SPLEND		;NO, FIND THE REAL DDB
	HRRZ	T2,T1
	JUMPE	T2,CPOPJ1##	;WE WON IF NO RH OF NAME
IFN FTNET,<
	LSH	T2,-6
	PUSHJ	P,DVSCVT
	  JRST	SPLEND		;NO - NOT REALLY SPOOLING
	PUSH	P,T1
	MOVE	T1,T2		;RH = SXX.  IS XX A STATION?
	PUSHJ	P,STBSCA##	;DOES THE NODE EXIST
	  TDZA	T3,T3		;NO, SET T3 FOR DVASRC
	JRST	TPOPJ1##	;YES, GIVE SKIP RETURN
	POP	P,T1		;RESTORE NAME
>;END FTNET CONDITIONAL

SPLEND:	SETZ	F,		;CLEAR F (NO DDB)
>;END FTSPL CONDITIONAL
IFN FTGSRC,<
	PJRST	DVASRC		;SEARCH FOR GENERIC, GIVE ERROR OR OK RETURN
>
IFE FTGSRC,<
	SETZ	T4,		;RESET FLAG
	POPJ	P,		;ERROR RETURN
>
>	;END CONDITIONAL ON FT5UUO!FTSFD
IFE FT5UUO!FTNET!FTSFD,<
DEVSRG==:DEVSRC
>
;ROUTINE TO CHECK TO SEE IF DEVICE 'OPRXXX' AND IF SO TO
;FUDGE T1 TO HAVE REAL TTY NAME IN IT

TSTOPR::
IFN FTNET,<


	PUSH	P,T1		;SAVE NAME IN CASE TEST FAILS
	HLRZ	T2,T1		;GET GENERIC NAME
	CAIE	T2,(SIXBIT/OPR/)	;IS IT OPR?
	JRST	TPOPJ##		;NO - BRANCH TO RESTORE OLD NAME
	TRNN	T1,-1		;ANY STATION NUMBER SPECIFIED?
	JRST	OPRGEN		;NO - GO FIND OPR FOR THIS JOB
	HRLZS	T1		;PUT NUMBER IN LH OF T1
	PUSHJ	P,CVTOCT	;GO CONVERT TO OCTAL DIGITS
	JRST	TPOPJ##		;ILLEGAL OCTAL - MUST NOT BE OPR
	JUMPE	T1,OPRCEN	;OPR0 IS ALWAYS CENTRAL SITE
	PUSHJ	P,STBSCA##	;GO SEE IF STA # IS VALID
	JRST	TPOPJ##		;INVALID STA - ERROR RETURN
OPRFND:	CAMN	T1,JBTLOC##	;IS IT AT CENTRAL SITE?
	JRST	OPRCEN		;YES--GO GET IT
	PUSHJ	P,STBOPR##	;GET OPR TTY LINE # AT THIS STA
	PUSHJ	P,CVTSBT	;CONVERT IT TO SIXBIT
	HLRZS	T1		;PUT IN RH
	HRLI	T1,(SIXBIT/TTY/)	;LH = SIXBIT/TTY/
OPRRET:	PJRST	T2POPJ##	;THROW AWAY OLD NAME (T2) AND RETURN

OPRGEN:	MOVE	T1,JBTLOC##(J)	;GET STA # OF JOB
	JRST	OPRFND		;NO - USE JOB LOCATION FOR OPR SEARCH
OPRCEN:	MOVE	T1,DEVOPR##	;YES - USE OPR NAME FROM COMMON
	JRST	OPRRET		;SCRAP OLD NAME AND RETURN

>	;END CONDITIONAL ON FTNET
IFE FTNET,<


	CAMN	T1,[SIXBIT/OPR/]	;IS IT DEVICE OPR?
	MOVE	T1,DEVOPR##	;YES - USE OPR DEV NAME
	POPJ	P,		;AND RETURN
>
IFN FTNET!FTMSGSER,<
;NUMBER CONVERSION ROUTINES
;CVTOCT - CONVERT SIXBIT NUMBER LEFT JUSTIFIED IN T1 TO
;OCTAL (RIGHT JUSTIFIED) IN T1


CVTOCT::TLNN	T1,770000	;IS THERE A FIRST CHARACTER?
	JUMPN	T1,CPOPJ##	;NO, CAN'T BE SIXBIT
	PUSH	P,T2		;SAVE ALL AC'S USED
	PUSH	P,T3		;..
	PUSH	P,T4		;..
	MOVE	T2,[POINT 6,T1]	;BYTE PTR TO T1
	SETZ	T3,
CVTOC2:	ILDB	T4,T2		;GET SIXBIT CHAR
	JUMPE	T4,CVTOC1	;NULL CHAR ENDS STRING
	CAIL	T4,'0'		;MUST BE BETWEEN 0 AND 7
	CAILE	T4,'7'		;TO BE A VALID OCTAL DIGIT
	JRST	CVTOC3		;OTHERWISE ERROR RETURN
	ROT	T3,3		;MAKE ROOM
	IORI	T3,-'0'(T4)	;PUT DIGIT IN
	JRST	CVTOC2		;GO DO SOME MORE

CVTOC1:	MOVE	T1,T3		;RETURN WITH OCTAL NUMBER IN T1
	AOS	-3(P)		;GOOD RETURN IS SKIP RETURN
	PJRST	CVTOC3		;GO RESTORE AC'S AND RETURN
>	;END CONDITIONAL ON FTNET!FTMSG

;CVTSBT - CONVERT OCTAL NUMBER TO SIXBIT

CVTSBT::PUSH	P,T2		;SAVE ALL AC'S USED
	PUSH	P,T3		;..
	PUSH	P,T4		;..
	MOVE	T3,[POINT 6,T4]	;PLACE FOR RESULT
	SETZ	T4,		;ZERO T4
	PUSHJ	P,CVTSB1	;CONVERT TO SIXBIT
	MOVE	T1,T4		;RETURN RESULT IN T1
CVTOC3:	POP	P,T4		;RESTORE AC'S
	POP	P,T3
	PJRST	T2POPJ##	;AND RETURN (POP T2)

CVTSB1:	IDIVI	T1,10		;GET A DIGIT
	HRLM	T2,0(P)		;SAVE IN LH OF CURRENT STACK WORD
	SKIPE	T1		;WHEN DONE - SKIP
	PUSHJ	P,CVTSB1	;RECURSIVELY DO ABOVE AGAIN
	HLRZ	T1,0(P)		;GET BACK THE DIGIT
	ADDI	T1,20		;CONVERT IT TO SIXBIT
	IDPB	T1,T3		;STORE IN RETURN WORD
	POPJ	P,0		;AND RETURN TO GET ANOTHER DIGIT
				;OR CALLER
;SUBROUTINE TO CHECK FOR A VALID (PDP-11 COMPATABLE) 2-CHAR
; DEVICE NAME. ENTER WITH NAME IN T1, EXIT WITH NEW NAME (IF ANY)
; ALSO IN T1.
;
;CALL:
;	PUSHJ	P,CK2CHR
;	HERE ALWAYS
;
;
CK2CHR:	MOVEI	T4,STLEN##	;GET POINTER TO SPECIAL DEVICE TABLE
	HLRZ	T2,T1		;GET THIS DEVICE NAME
DVSRC1:
	MOVE	T3,SPCTAB##(T4)	;GET TABLE ENTRY
	CAIN	T2,(T3)		;IS IT THIS DEVICE?
	JRST	[HLL T1,T3	;YES, RESET DEVICE NAME
		POPJ	P,]		;AND RETURN
	SOJGE	T4,DVSRC1	;MORE IN TABLE?
	POPJ	P,		;NO, EXIT
;SUBROUTINE TO SEARCH DDB'S FOR A DEVICE
;
;CALL:	
;	MOVEI	T2,FLAGS
;	PUSHJ	P,DDBSRC
;	  NOT FOUND
;	FOUND
;
;FLAGS:
;	DD%PHY		SEARCH FOR PHYSICAL NAMES
;	DD%LOG		SEARCH FOR LOGICAL NAMES
;
;ON EXIT, F WILL CONTAIN THE DDB IF WE FOUND ONE
;
;THE ALGORITHM IS AS FOLLOWS:
;
; 1.	IF LOGNAM MATCH & DD%LOG SET, TAKE THIS DEVICE
; 2.	OR, IF PHYNAM MATCH & DD%PHY SET & DD%LOG NOT SET, TAKE IT
; 3.	IF PHYNAM MATCH & BOTH SET, SAVE NAME TO SEE IF FIND LOGNAM MATCH
;
DD%LOG==:1B35	;FLAG BIT DEFINITIONS
DD%PHY==:1B34


DDBSRC:	JUMPE	T1,CPOPJ##	;DEVICE NAME OF 0 NOT ALLOWED
	PUSHJ	P,SAVE1##	;SAVE P1
	HRR	P1,T2		;SAVE FLAGS
IFN FTHSLN,<
	TRNN	P1,DD%LOG	;LOGICAL SEARCH?
>
	JRST	NOLGST		;NO, DON'T SET UP
IFN FTPHYO,<
	HLRZ	T2,P1		;CHECK FOR PHYSICAL ONLY
	CAIN	T2,PHONLY	;IS IT THERE?
	JRST	DEVLP7		;YES, CLEAR LOGICAL BIT
>	;END OF FTPHYO
IFN FTHSLN,<
	PUSHJ	P,FNDPDB##	;POINT TO PDB
	JRST	DEVLP7		;NO PDB = NO LOGICAL NAMES
	SKIPGE	T2,.PDDVL##(W)	;IS THERE A LOG NAME TABLE?
	JRST	NOLGST		;IT IS INVALID, SCAN DDB'S
	JUMPE	T2,DEVLP7	;NO LOGICAL NAMES
	HRLI	T2,-LDVTLN	;SET UP AOBJN POINTER
DEVLP4:	SKIPN	T3,(T2)		;IS THIS WORD CLEAR?
	JRST	DEVLP5		;YES, CHECK NEXT
	HLRZ	F,T3		;NO, CHECK LEFT HALF
	CAMN	T1,DEVLOG(F)	;LOGICAL NAME MATCH?
	JUMPN	F,CPOPJ1##	;YES, IF NON-BLANK
	HRRZ	F,T3		;TRY RIGHT HALF
	CAMN	T1,DEVLOG(F)	;LOGICAL NAME MATCH?
	JUMPN	F,CPOPJ1##	;YES, IF NON-BLANK

DEVLP5:	AOBJN	T2,DEVLP4	;CHECK ON NEXT WORD
>	;END OF IFN FTHSLN
DEVLP7:	TRNN	P1,DD%PHY	;PHYSICAL?
	POPJ	P,		;NO, NOT FOUND
	TRZ	P1,DD%LOG	;YES, TURN OFF LOG
NOLGST:	TLZ	P1,-1		;CLEAR PHONLY
	TRNN	P1,DD%PHY	;PHYSICAL SEARCH?
	JRST	DDSRC2		;NO DON'T SET UP
	TLNN	T1,77		;IS THIS A 2-CHAR DEVICE NAME?
	PUSHJ	P,CK2CHR	;YES, CHECK FOR WIERD NAMES
DDSRC0:	
IFN FTDISK,<
	PUSHJ	P,TSTDSK##	;IS THIS A DISK?
	  JRST	[TRNN	P1,DD%LOG  ;LOGICAL SEARCH?
		 JRST CPOPJ1##	 ;NO FOUND PHYSICAL
		 HRL	P1,F	;YES, SAVE DDB
		 JRST	.+1]	;AND CONTINUE
>
IFN FTTSK,<
	PUSHJ	P,TSTTSK##	;IS THIS A TSK DEVICE
	  CAIA			;NO, CONTINUE SEARCH
	JRST	CPOPJ1##	;YES, EXIT WITH F=DDB POINTER
>;END FTTSK
	PUSHJ	P,TSTOPR	;CHECK FOR "OPR"
IFE FTDISK,<
	CAMN	T1,[SIXBIT /SYS/]	;IS IT "SYS"?
	SKIPA	T1,SYSTAP##	;YES, CHANGE TO SYS TAPE DEVICE NAME
	TDZA	T2,T2		;NO, CLEAR SYSTEM TAPE FLAG
	MOVEI	T2,SYSDEV	;YES, SET SYSTEM TAPE FLAG
>
	MOVSI	T3,DVDSK
DDSRC2:	HLR	F,DEVLST##	;GET START OF CHAIN
DDSC2A:	TRNE	P1,DD%LOG	;LOGICAL NAME SEARCH?
	CAME	T1,DEVLOG(F)	;LOGICAL NAME MATCH?
	JRST	GETPHY		;NO
	LDB	T4,PJOBN##	;CHECK JOB #
	CAMN	T4,J		;THIS JOB?
	JRST	[TLZ	F,-1	;CLEAR SYS BITS
		JRST CPOPJ1##]	;GOOD RETURN
GETPHY:
	TRNN	P1,DD%PHY	;PHYSICAL SEARCH?
	JRST	DDSRC3		;NO, SKIP OVER THIS
IFE FTDISK,<
	TLO	F,(T2)		;SET SYS TAPE FLAG IF SEARCHING FOR SYS
>
IFN FTSPL,<
	SKIPGE	DEVSPL(F)	;NO MATCH ON SPOOLED DDB'S
	JRST	DDSRC3		;IT IS A SPOOLED DDB
>
	TDNN	T3,DEVMOD(F)	;IF TSTDSK SAYS IF ISN'T A DISK,
	CAME	T1,DEVNAM(F)	;OR IF DEVICE NAMES DON'T MATCH...
	JRST	DDSRC3		;THEN IGNORE THIS ONE (SINGLE-ACCESS)
	TLNN	P1,-1		;FOUND DDB ALREADY?
	HRL	P1,F		;SAVE THIS ADDRESS
	TRNN	P1,DD%LOG	;DO WE CARE ABOUT LOGICAL NAMES?
	JRST	CPOPJ1##	;NO, WE FOUND A PHYSICAL NAME
DDSRC3:	HLR	F,DEVSER(F)	;GET NEXT DDB
	TRNE	F,-1		;END OF CHAIN?
	JRST	DDSC2A		;NO
	TRNN	P1,DD%PHY	;ARE WE LOOKING FOR PHYSICAL?
	POPJ	P,		;NO, AND WE DIDN'T FIND A LOGICAL MATCH
	HLR	F,P1		;YES, GET SAVED ADDRESS
	JUMPN	F,CPOPJ1##	;EXIT WITH PHYSICAL DDB MATCH IF THERE WAS ONE
IFN FTRDX,<
	PUSHJ	P,TSTRDX##	;CHECK FOR REMOTE DATA ENTRY ROUTINE
	  SKIPA			;NO
	JRST	CPOPJ1##	;YES,
>;END IFN FTRDX
IFN FTNET,<
	TRNN	T1,505050	;MUST ME NUMBERIC RT HALF
	PUSHJ	P,TSTNET##	;YES CHECK FOR NETWORK DEVICE
	  SKIPA			;NOT A NETWORK DEVICE
	PJRST	CPOPJ1##	;YES, FOUND THE DEVICE ON THE NETWORK
>;END FTNET
IFN FTMSGSER,<
	PUSHJ	P,TSTMPX##	;NO, CHECK FOR MPX DDB
	 SKIPA			;NO--TRY FOR TTY
	JRST	CPOPJ1##	;YES--ALL DONE
>;END FTMSGSER
	CAME	T1,[SIXBIT /TTY/]	;IS THIS PUBLIC LOGICAL NAME TTY?
	JRST	GETDDB##	;SEE IF IT'S A TTY
	PUSH	P,U		;SAVE OUTPUT BYTE PTR(TTY) OR INIT ARG ADR
	PUSHJ	P,TTYFND##	;FIND TTY JOB IS ATTACHED TO
	JRST	UPOPJ1##	;GOOD RETURN
IFN FTGSRC!FTSFD,<
;DVASRC - MODIFIED DDB SEARCH ROUTINE TO SEARCH FOR GENERIC
;DEVICE NAMES

;THIS ROUTINE SEGREGATES SPECIFICATIONS INTO THREE CLASSES:
;	(1) SPECIFIC DEVICE - RH OF NAME IS NUMERIC
;		- ERROR RETURN TAKEN - NOT GENERIC
;	(2) GLOBAL GENERIC - RH OF NAME IS NULL
;		- GENERIC SEARCH DONE FIRST AT JOB SITE
;		IF NO SUCH DEVICE THERE SEARCH REPEATED AT 
;		CENTRAL SITE - OTHERWISE FAIL
;	(3) SPEFICIED GENERIC - RH OF NAME IS NN WHERE NN
;		IS THE STATION TO SEARCH AT
;INTERFACE TO DVSTAS PRESERVED (T3,T4)


DVASRC::SETZ	T4,		;RESET INTERNAL FLAG
	HRRZ	T2,T1		;GET RH OF NAME
	TRNE	T2,7777		;CHECK FOR LOCAL GENERIC DEVICE GGU
	JRST	DVSSRC		;NI, SPECIFIC MODE GENERIC GGGNN

;USER HAS SPECIFIED GENERIC DEVICE WITH NO STATION SPECIFICATION

IFN FTNET,<
	MOVE	T2,JBTLOC##(J)	;GET THIS GUY'S STAION NUMBER
	PUSHJ	P,DVSTAS	;SEARCH FOR A DEVICE AT THIS STATION
	  SKIPA	T2,JBTLOC##	;FAILED - TRY CENTRAL SITE (MAYBE)
	JRST	CPOPJ1##	;SUCCESS - FOUND A FREE DEVICE
	JUMPL	T4,CPOPJ##	;FAILED BUT FOUND AT LEAST ONE DEVICE
				;THAT MET THE SPEC AND WAS BUSY (T4=-1 AND NONSKIP RETURN)
				;NO DEVICE OF REQUIRED TYPE AT USER'S
				;SITE SO TRY CENTRAL SITE
>
	JRST	DVSTAS		;GO DO GENERIC SEARCH
;STILL IN FTGSRC!FTNET!FTSFD CONDITIONAL
;ROUTINE TO CONVERT STATION NAME
;ENTER NAME IN T1
;EXIT CPOPJ IF STATION ILLEGAL
;EXIT CPOPJ1 IF OK, T2=STATION NUMBER

DVSCVT::PUSH	P,T1		;SAVE NAME
IFN FTNET,<
	HRLZS	T1		;GET SNN
	TLZ	T1,77		;NOW ONLY NN
	PUSHJ	P,CVTOCT	;GO CONVERT NN TO OCTAL NUMBER
	JRST	TPOPJ##		;ERROR IN NN SPEC
				;MUST NOT HAVE BEEN SNN AFTER ALL
				;SO RESTORE T1 AND GIVE ERROR RETURN
	SKIPN	T2,T1		;IF NN IS ZERO PUT STA # IN T2
	MOVE	T2,JBTLOC##	;USE CENTRAL SITE NMBER
	JRST	TPOPJ1##	;GOOD RETURN.
>
IFE FTNET,<
	HRRZS	T1		;IF NO REMOTES, ONLY STATION ZERO LEGAL
	TRZ	T1,77		;CLEAR UNIT #
	CAIN	T1,'00 '		;SKIP IF STATION 0
	TDZA	T2,T2		;OK, SET T2=0 FOR CENTRAL SITE
	JRST	TPOPJ##		;NO, ILLEGAL
	JRST	TPOPJ1##	;RESTORE NAME AND GOOD RETURN
>
;USER HAS SPECIFIED NNU IN RH OF NAME
DVSSRC:	PUSH	P,T1
	PUSHJ	P,DVSCVT	;CONVERT NN TO OCTAL
	  JRST	TPOPJ##		;ILLEGAL STATION NUMBER
	DPB	T1,[POINT 6,T1,23] ;LEFT JUSTIFY THE UNIT NUMBER IF ANY
	TRZ	T1,7777		;CLEAR THE JUNK
				;AND FALL INTO GENERIC SEARCH
				;WITH NN AS STATION NUMBER
	PUSHJ	P,DVSTAS	;FIND DEVICE
	  JRST	TPOPJ##
	JRST	TPOPJ1##
;STILL IN FTGSRC!FTNET!FTSFD CONDITIONAL
;ROUTINE TO FIND A GENERIC DEVICE AT A SPECIFIC STATION
;CALL:
;		LH(T1) 3 CHAR GENERIC NAME TO SEARCH ON
;		RT(T1) UNIT NUMBER OR 0
;		C(T2) STATION TO SEARCH AT
;		RH(T3) HAS BITS TO TEST FOR FAIL ANYWAY

;THIS ROUTINE GIVES SUCCESS RETURN (SKIP) ONLY IF
;	(1) A FREE DEVICE IS FOUND WITH LH OF NAME MATCHING, OR
;	(2) CURRENT JOB (IN J) HAS DEVICE FOR WHICH A LH
;	MATCH HAS BEEN DONE AND THE DEVMOD BITS INDICATED IN T3 ARE OFF.

;THE DDB RETURNED WILL BE ONE ALREADY ASSIGNED TO THE JOB IF
;IT MEETS THE ABOVE CRITERIA

;C(T4) ARE RETURNED AS -1 IF A DEVICE MATCH IS MADE WHETHER OR NOT
;THE DEVICE CAN BE GIVEN TO THE JOB
;C(T4) .GE. 0 IF NO SUCH DEVICE


DVSTAS:	JUMPE	T1,CPOPJ##
	PUSHJ	P,SAVE3##	;SAVE P1-3
	PUSH	P,T1		;SAVE T1
	MOVEI	T4,0		;CLEAR FLAG
IFN FTNET,<
	SKIPN	T2		;IF ZERO STA # USE CENTRAL SITE
	MOVE	T2,JBTLOC##	;FOR SEARCH
>

	PUSHJ	P,CHKGEN	;SEARCH FOR SPECIAL GENERIC DEVICE
	 JRST	[SETZ F,
		 JRST TPOPJ##]	;DIDN'T FIND IT--BAD DEVICE NAME
	SETZB	P2,P3		;INITIALLY NO FREE DDB
;STILL IN FTGSRC!FTNET!FTSFD CONDITIONAL
DVSTAL:
IFN FTNET,<
	LDB	P1,PDVTYP##	;DEVICE TYPE
	CAIN	P1,.TYPTY/.TYEST;A PTY?
	JRST	DVST1		;YES, PTYS ARE AT THE CENTRAL SITE
	LDB	P1,PDVSTA##	;GET STA # FROM DDB
	CAME	P1,T2		;IS IT THE RIGHT STA?
	JUMPN	T2,DVSNXT	;NO - TRY NEXT DDB IF NOT 0 (REMSW=0)
DVST1:>
	HLLZ	P1,DEVNAM(F)	;MATCH ON LH OF NAME (GENERIC)
	TLNE	T1,77		;IS THIS A 2-CHAR NAME?
	JRST	DVST2
	PUSHJ	P,CKSPEC	;YES, CHECK FOR SPECIAL NAMES
	  JRST	DVST2A
	  JRST	DVST2		;NONE FOUND, CONTINUE
	PUSH	P,T3		;SAVE THIS
	CAMN	P1,[SIXBIT/LPT/] ;LL/LU
	JRST	DVLPTS		;IT'S A FUNNY LPT
	HLRZ	T3,TDVUDB##(F)	;IT'S A MAGTAPE, GET UDB
	HRRZ	T3,TUBCNF##(T3)	;GET CONFIG INFO
	TRNN	T3,TUC7TK##	;IS THIS 7-TRACK ?
	SKIPA	T3,[SIXBIT/M9/]	;NO, SETUP 9-TRACK
	MOVSI	T3,'M7 '	;YES, SET UP NAME
	JRST	DVST0		;GO COMPARE NAMES
DVLPTS:	MOVSI	P1,dvlptl	;SET UP BIT TO CHECK FOR LOWER CASE
	TDNn	P1,DEVchr(F)	;IS THIS A LC LPT?
	SKIPA	T3,[SIXBIT /LU/]
	MOVSI	T3,'LL '
DVST0:	CAMN	T1,T3		;IS THIS WHAT WE WANT ?
	JRST	[POP P,T3
		JRST DVST3]	;YES
	POP	P,T3		;NO, FALL THRU NAME CHECK TO DVSNXT
DVST2:	HRRZ	P1,DEVNAM(F)	;GET THE UNIT NUMBER
	LSH	P1,14		;POSITION TO HIGH ORDER
	TRNN	T1,770000	;IS THERE S PHYSICAL UNIT FOR GENERIC
	TRZ	P1,770000	;NO, CLEAR THE UNIT NUMBER
	HLL	P1,DEVNAM(F)	;MATCH ON LH OF NAME (GENERIC)
DVST2A:	CAME	P1,T1		;
	JRST	DVSNXT		;N0 - TRY NEXT DDB
DVST3:	MOVE	P3,F		;SAVE ANYTHING HERE
	HRROI	T4,-1		;SET FLAG (T4) TO -1 TO
				;INDICATE THAT A DDB HAS BEEN FOUND
	LDB	P1,PJOBN##	;GET JOB DDB ASSIGNED TO
	JUMPN	P1,DVSNF	;BRANCH IF ASSIGNED TO SOMEBODY
	MOVE	P1,DEVMOD(F)	;GET ASSIGN BITS
	TRNE	P1,ASSCON+ASSPRG	;IS IT ASSIGNED TO JOB 0 ?
	JRST	DVSNXT		;YES - TRY NEXT DDB ANYWAY
IFE FTDISK,<
	MOVE	P1,DEVNAM(F)	;NO, PHYSICAL DEVICE NAME
	CAMN	P1,SYSTAP##	;IS IT THE SYSTEM TAPE?
	JRST	DVSNXT		;YES, KEEP LOOKING
>
	MOVSI	P1,DEPRAS	;GET RESTRICTED ASSIGNMENT BIT
	TDNN	P1,DEVSTA(F)	;IS THIS DEVICE RESTRICTED?
	JRST	DVSTA1		;NO, PROCEED
	MOVE	P1,JBTPPN##(J)	;YES. GET JOB'S PRJ-PRG #
	CAMN	P1,FSFPPN##	;=1,2?
	JRST	DVSTA1		;OK TO USE DEVICE
	JUMPL	M,DVSNXT	;CANNOT USE IF FROM COMMAND AND NOT 1,2
	MOVSI	P1,JACCT	;NOT [1,2]. CHECK PRIVILEGES
	TDNN	P1,JBTSTS##(J)	;JACCT ON?
	JRST	DVSNXT		;NO, LOOK AT OTHER DEVICES
DVSTA1:	SKIPN	P2		;FOUND ONE BEFORE DON'T BOTHER
	MOVE	P2,F		;FOUND A FREE DEVICE THAT WE CAN USE-
				;SAVE IT AND CONTINUE TO SEE IF WE
				;CAN FIND ONE ALREADY ASSIGNED
				;TO THIS JOB
	JRST	DVSNXT		;GO DO SOME MORE LOOKING
;STILL IN FTGSRC!FTNET!FTSFD CONDITIONAL
;HERE IF THIS DDB IS ALREADY ASSIGNED OR INITED TO SOME JOB
DVSNF:	CAME	P1,J		;DDB ASSIGNED TO THIS JOB ?
	JRST	DVSNXT		;NO - NICE TRY ANYWAY
	TDNE	T3,DEVMOD(F)	;YES -- IS HE USING THE DEVICE
				;(IS THE DEVCE INIT'ED ON INIT OR
				;ASSIGN'ED ON ASSIGN)?
	JRST	DVSNXT		;YES - CAN'T USE THIS ONE TRY NEXT
				;FOUND A DEVICE ACCEPTABLE TO CALLER - OUR
				;IDEAL CASE ! - GIVE GOOD RETURN WITH
	JRST	TPOPJ1##	;F SET UP

DVSNXT:	HLRZ	F,DEVSER(F)	;GET NEXT DDB ON CHAIN
	JUMPE	F,DVSNX2	;END OF CHAIN
	JRST	DVSTAL		;NO, STILL LOOKING AT SAME DEVICES
DVSNX2:
	JUMPE	P2,DVSFL	;IF WE GET HERE AND
				;P2 = 0 THEN WE HAVE FOUND NO DDB'S
				;THAT ARE AVAILABLE (WE MAY HAVE
				;FOUND DDB'S IN USE THO) - SO GIVE
				;ERROR RETURN
	MOVE	F,P2		;IF P2 IS NOT 0 HOWEVER, WE WERE
				;TRYING TO FIND AN ASSIGNED DEVICE
				;AND FAILED BUT DID PREVIOUSLY FIND
				;A FREE DEVICE - SO USE IT
	JRST	TPOPJ1##	;GIVE GOOD RETURN WITH DDB IN F

DVSFL:	JUMPN	T3,DVSNET	;IF T3 WAS NOT ZERO - WE FAIL HERE
	JUMPE	P3,DVSNET	;IF T3=0, BUT NO SUCH DEVICE, FAIL
	MOVE	F,P3		;HOWEVER, IF T3=0 AND THERE WAS
	JRST	TPOPJ1##	;SOME DEVICE (EVEN THO NOT
				;AVAILABLE) GIVE IT TO CALLER
DVSNET:	PUSHJ	P,GENNET##	;TRY GENERIC NETWORK
	  PJRST	TPOPJ##		;FAIL
	PJRST	TPOPJ1##	;WE WIN F=DDB
>	;END CONDITIONAL ON FTGSRC!FTNET!FTSFD

;SUBROUTINE TO CHECK FOR DEVICE NAME OF <LL,LU>
;
;CALL:
;	HLLZ	P1,DEVNAM(F)
;	PUSHJ	P,CKSPEC
;	RETURN HERE IF MT OR DT
;	 RETURN HERE IF NOT LL OR LU
;	HERE IF LL/LU <AND> P1 WAS SIXBIT /LPT/
;	<OR> IF M7/M9 <AND> P1 WAS MTA/MTB/MTC
;
CKSPEC:	CAME	T1,[SIXBIT /LU/]
	CAMN	T1,[SIXBIT /LL/]	;IS IT ONE OF THOSE?
	JRST	CKSPC3		;YES, GO CHECK FOR LPT
	CAME	T1,[SIXBIT /M7/]	;M7?
	CAMN	T1,[SIXBIT /M9/]	;M9?
	JRST	CKSPC4		;YES
	CAME	T1,[SIXBIT /DT/]	;IS IT A "DT"?
	CAMN	T1,[SIXBIT /MT/]	;OR A "MT"?
	TLZ	P1,77		;IF SO, FIX P1 SO A MATCH WILL BE SEEN
	POPJ	P,		;RETURN
CKSPC3:	CAME	P1,[SIXBIT /LPT/]	;IS THIS A LPT DDB?
	JRST	CPOPJ1##	;NO
	JRST	CPOPJ2##	;YES, WE WILL DO SPECIAL STUFF
CKSPC4:	TLZ	P1,77		;CLEAR CONTROLLER TAPE
	CAME	P1,[SIXBIT/MT/] ;MT?
	JRST	CPOPJ1##	;NO
	JRST	CPOPJ2##	;YES
;SUBROUTINE TO SEARCH THE GENERIC DEVICE TABLE
;
;CALL:
;	MOVE	T1,[SIXBIT .DEVICE NAME.]
;	PUSHJ	P,CHKGEN
;	 HERE IF NOT FOUND
;	HERE IF FOUND WITH F = DDB
;
;p2 is saved (for assign in comcon), p1 and p3 are destroyed
CHKGEN::
	PUSH	P,P2		;SAVE P2
	PUSH	P,T1		;SAVE OLD NAME
	PUSHJ	P,FXSNAM	;FIX-UP NAME
	HLLZ	P1,T1		;GET DEVICE NAME
	POP	P,T1		;RESTORE OLD NAME
	MOVEI	P2,GTLEN##-1	;SET UP POINTER FOR GENERIC TABLE SEARCH
DVS2:	HLLZ	P3,GENTAB##(P2)		;GET DEVICE NAME FROM TABLE
	CAMN	P1,P3		;MATCH?	
	JRST	DVS3		;YES, FOUND DEVICE
	SOJGE	P2,DVS2
	JRST	DVS5		;NO, NONE ARE DEFINED
DVS3:	HRRZ	F,GENTAB##(P2)	;GET DDB POINTER
	AOS	-1(P)		;BUMP RETURN ADDRESS
	SKIPN	F		;SKIP RETURN IF DDB ADDRESS IN TABLE
DVS5:	HLRZ	F,DEVLST##	;NOT IN THE TABLE RETURN DEVLST
	POP	P,P2		;GET P2 BACK
	POPJ	P,		;RETURN (CPOPJ OR CPOPJ1)


;SUBROUTINE TO FIX SPECIAL 2-CHAR DEVICE NAMES
;CALL:
;	MOVE	T1,[SIXBIT .DEVICE NAME.]
;	PUSHJ	P,FXSNAM
;	HERE WITH T1 FIXED UP
FXSNAM::CAME	T1,[SIXBIT /LU/]	;FUNNY LPT?
	CAMN	T1,[SIXBIT /LL/] ;...
	HRLI	T1,'LPT'	;YES
	CAME	T1,[SIXBIT /DT/] ;DT?
	CAMN	T1,[SIXBIT /MT/] ;MT?
	TLO	T1,'  A'	;YES, ADD"A"
	CAME	T1,[SIXBIT /M7/] ;M7?
	CAMN	T1,[SIXBIT /M9/] ;OR M9?
	HRLI	T1,'MTA'	;YES
	POPJ	P,		;RETURN
	SUBTTL	BUFFER RING BUILDER & CLEARER

;ROUTINE TO SETUP N-RING IO BUFFER IN USER AREA

;CALL:	MOVEI	T2,ADDRESS OF BUFFER HEADER
	PUSHJ P,BUFCLC
;	EXIT			RETURNS HERE IF MEMORY NOT EXCEEDED
; SETS UP AN N BUFFER RING FOLLOWING THE USER'S PROGRAM, WHERE N
; IS IN THE ADDRESS FIELD OF AC M.
; THE BUFFER RING FORMAT IS AS FOLLOWS:
;	LOCATION		LH   CONTENTS   RH
; C(JOBFF) + 1              BUFFER         C(JOBFF) +1
;    + 0(BUFFER SIZE+2)      SIZE               + 1(BUFFER SIZE+2)
; C(JOBFF) +1               BUFFER         C(JOBFF) +1
;     +1(BUFFER SIZE+2)      SIZE                + 2(BUFFER SIZE+2)
;         .		.		     .
;	.		.		     .
;	.		.		     .
; C(JOBFF) + 1	        BUFFER	   C(JOBFF) + 1
;    + (N-2)(BUFFER SIZE+2)  SIZE               +(N-1)(BUFFER SIZE+2)
; C(JOBFF) + 1	        BUFFER	   C(JOBFF) + 1
;    + (N-1)(BUFFER SIZE+2)  SIZE		   
;THEN SET 	T3:=IOUSE,C(JOBFF) + 1
; AND		JOBFF:=C(JOBFF) + N(BUFFER SIZE + 2)
; P2 IS RESTORED.

BUFCLC::
IFN FTVM,<
	HRRZ	T1,T2		;ADDRESS OF BUFFER HEADER
	PUSHJ	P,UADRCK	;GET PAGE IN CORE IF IT ISN'T
>
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	LDB	P3,PBUFSZ##	;T1=BUFFER SIZE
	HRRZ	P1,JOBFF##(R)	;P1:=FIRST FREE LOCATION + 1
	ADDI	P1,1
	HRRZ	P2,P1
IFN FTKA10,<
	HRLI	P1,R
>
	HRL	P2,P3		;P2:=BUFFER SIZE,FIRST FREE LOC + 1
	ADDI	P3,2		;P3:=BUFFER SIZE + 2
	HRRZ	T2,M		;T2:=N=ADDRESS FIELD OF AC UUO
	SKIPN	T2		;SEE IF DEFAULT
	PUSHJ	P,DFTNB		;YES, GET DEFAULT
	HRR	M,T2
	MOVE	P4,T2		;PUT NO OF BUFFERS IN P4
	HRRZ	T1,P3		;BUFFER SIZE+2
	IMUL	T1,T2		;TIME NO. OF BUFFERS
	ADD	T1,P2		;LOC. OF FIRST BUFFER
	MOVEI	T1,-2(T1)	;READJUST FOR USRREL COMPARISON
IFN FTVM,<
	CAMG	T1,.UPMP+.UPREL	;CHECK AGAINST VM USRREL
	JRST	BUFC1		;ALREADY ENOUGH CORE FOR BUFFERS
	SKIPE	.UPMP+.UPREL	;IS THIS A VM USER?
	JRST	BUFC0		;YES, MORE CORE REQUIRED
>
	CAMG	T1,USRREL##	;WILL THIS SPACE FIT IN USER CORE?
	JRST	BUFC1		;YES, FO DO INBUF CODE
				; NO, AUTOMATICALLY EXPAND SIZE OF USER CORE
BUFC0:	PUSH	P,M		;SAVE A BUNCH OF ACS USED IN CORE AND IO WAIT
	PUSH	P,F
	PUSH	P,T4
	PUSH	P,T1		;SAVE HIGHEST USRADR TO TRY FOR
	PUSHJ	P,IOWAIT	;CALL IOWAIT BEFORE CORUUO TO
				;REDUCE MAX PDL EXCURSION
	MOVE	T1,(P)		;HIGHEST USER ADR TO TRY FOR
	PUSHJ	P,CHGCOR##	;TRY TO ASSIGN CORE
	JFCL			;ERROR RETURN-LET ADR CHECK HAPPEN AND STOP JOB
	POP	P,T1
	POP	P,T4
	POP	P,F
	POP	P,M
	MOVE	S,DEVIOS(F)	;CHGCOR MAY HAVE ALLOWED S TO BE CHANGED
BUFC1:
IFN FTVM,<
	MOVE	T2,T1		;TOP ADDRESS
	HRRZ	T1,P2		;FIRST ADDRESS
	PUSHJ	P,LRNGE##	;MAKE SURE ALL PAGES ARE IN CORE
>
BUFC2:	ADD	P2,P3		;P2:=C(P2) + C(P3)
	HRRZ	T1,P1		;IS LAST ADDR IN BOUNDS?
	PUSHJ	P,UADRCK
	EXCTXU	<MOVEM	P2,@P1>	;BUFFER HEADER+1:=C(P2)
	HRR	P1,P2		;P1 18-35:=C(P2 18-35)
	SOJG	P4,BUFC2	;N:=N-1.  IS N GR 0?
	HRR	P2,JOBFF##(R)
	ADDI	P2,1
	MOVEI	T1,-2(P1)	;CHECK LAST ADR. OF HEADER
	PUSHJ	P,UADRCK
	SUB	P1,P3
IFN FTMSGSER,<
	MOVE	T4,P1		;T4 = ADDRESS OF LAST BUFFER
> ;END FTMSGSER
	EXCTXU	<MOVEM	P2,@P1>	;LINK LAST BUFFER TO FIRST BUFFER
	ADDI	P1,-1(P3)
	HRRM	P1,JOBFF(R)	;JOBFF:=C(JOBFF)+1+N(BUFFER SIZE+2)
	HRRZ	T3,P2		;T3:=IOUSE,ADDRESS OF FIRST BUFFER
				; IN RING.
	HRLI	T3,IOUSE
	POPJ	P,		;RETURN
;SUBROUTINE TO COMPUTE DEFAULT NO OF BUFFERS
;RETURNS NUMBER IN T2, RESPECTS T1,T3
DFTNB:	MOVEI	T2,2		;ASSUME NOT A DISK
	MOVSI	T4,DVDSK
	TDNE	T4,DEVMOD(F)	;IS IT?
	MOVE	T2,NUMBF##	;YES
	POPJ	P,		;RETURN WITH ANSWER
;ROUTINE TO CLEAR IO BUFFER IN USER AREA
;CALLED AT INTERRUPT AND UUO LEVEL, AT INTERRUPT LEVEL ONLY ON KA10

;CALL:	HRRZ T1,REL. ADR. OF 2ND WORD OF USER BUFFER
;	PUSHJ P,BUFCLR
;	ERROR RETURN MEMORY EXCEEDED
;	EXIT		RETURNS HERE IF MEMORY NOT EXCEEDED
; CLEARS THE WORD COUNT AND DATA AREA OF THE BUFFER WHOSE ADDRESS
; IS IN T1 18-35.


BUFCLR::
IFE FTVM,<
	PUSHJ	P,IADRCK	;IN BOUNDS?
	POPJ	P,		;NO. ERROR RETURN
IFN FTKA10,<
	HRLI	T1,R
>
>	;END FTVM
IFN FTVM,<
	PUSHJ	P,UADRCK
>

	PUSH	P,T1		;SAVE FIRST BUFFER ADR.
	EXCTUX	<HLRZ T2,@T1>	;T2 18-35=SIZE
	TRZ	T2,IOUSE
	JUMPE	T2,TPOPJ##	;WORD COUNT=0 IS ILLEGAL
IFE FTVM,<
	ADD	T1,T2		;LAST ADR=2ND ADR+SIZE
	TLZ	T1,-1		;CLEAR LEFT HALF
	PUSHJ	P,IADRCK	;LAST ADDRESS IN BOUNDS?
	JRST	TPOPJ##		;NO. ERROR RETURN
>
IFN FTVM,<
	ADD	T2,T1
	PUSHJ	P,LRNGE##
	MOVE	T1,T2
>
	HLL	T1,(P)		;SET LAST ADR. FOR RELOC.
	POP	P,T2		;RESTORE FIRST ADR.
	NOSHUFF			;NO SHUFFLING
	MOVEI	T2,@T2		;ABS. ADR. OF 2ND WORD OF BUFFER
	HRL	T2,T2
	AOBJN	T2,.+1		;THIRD WORD IN BUFFER
	EXCTXU	<SETZM (T2)>	;CLEAR THIRD WORD
	AOS	T2		;SET DEST. ADR. TO 4TH WORD
	EXCTUU	<BLT T2,@T1>	;CLEAR BUFFER
	SHUFFLE			;SHUFFLING
	JRST	CPOPJ1##	;SUCESSFUL RETURN
	SUBTTL	RANDOM SUBROUTINES FOR I/O

;ROUTINE TO COMPUTE 12 BIT FOLDED CHECKSUM

;CALL:	PUSHJ P,CKS12
;	EXIT		ALWAYS RETURNS HERE
;CALCULATES FOLDED 12 BIT CHECKSUMS OF THE DATA WORDS IN THE
;BUFFER WHOSE ADDRESS IS IN AC T2.
;ON RETURN, THE LEFT HALF OF AC T1 CONTAINS A CHECKSUM OBTAINED
;BY ACCUMULATING, IN ONE'S COMPLEMENT, THE DATA WORDS AND FOLDING IT.
;AC T2 CONTAINS A 1.


CKS12::	AOS	T2		;T2:=-WORD COUNT,ADDRESS OF FIRST DATA WORD
	HRRZ	T1,0(T2)
	MOVNS	T1
	AOS	T2
	HRL	T2,T1
	CLEARM	T1		;INITIALIZE TWO'S COMPLEMENT SUM
CKS12A:	ADD	T1,0(T2)	;TWO'S COMPLEMENT ADD
	AOBJN	T2,CKS12A	;DONE?
	LSHC	T1,-30
	LSH	T2,-14
	ADD	T1,T2
	LSHC	T1,-14
	LSH	T2,-30
	ADD	T1,T2
	TRZE	T1,770000
	AOS	T1
	HRLZS	T1
	MOVEI	T2,1		;T2:=1
	POPJ	P,


REPEAT 0,<
;ROUTINE TO CLEAR RESIDUE OF WORD POINTED TO BY A BYTE POINTER

;CALL:	PUSHJ P,CLRBYT
;	EXIT		ALWAYS RETURNS HERE
;CALLED WITH A BYTE POINTER IN AC T1, IT CLEARS THE REST OF THE
;WORD POINTED TO BY THE BYTE POINTER.


CLRBYT::LDB	T2,[POINT 6,T1,5]	;T2:=P
	DPB	T2,[POINT 12,T1,11]	;T1 0-5:=0,T1 6-12:=P
	SETZM	T2
	DPB	T2,T1		;CLEAR BITS 36-P THROUGH 35
	POPJ	P,		;RETURN
>	;END REPEAT 0
;ROUTINE TO RELEASE ALL DEVICES ASSIGNED TO JOB



IORELS::MOVEI	T1,RELEA3	;RELEASE ALL IO DEVICES(DON'T CLOSE)

;ROUTINE TO DO IO FOR ALL DEVICES ASSIGNED TO JOB
;CALL	MOVEI T1,ADR. OF IO SUB.
;	PUSHJ P,IOALL
;	RETURNS WITH J=CURRENT JOB # ,UUO PRESERVED


IOALL::	PUSHJ	P,SAVE1##	;SAVE P1 TO PRESERVE PHYSICAL BIT
	PUSH	P,T1		;SAVE ADR. OF SUB.
	PUSH	P,M		;SAVE M
	HRRZ	P1,USRHCU##	;HIGHEST CHANNEL NUMBER IN USE
	CAILE	P1,17		;BIGGER THAN MAX NUMBER OF CHANNELS ?
	STOPCD	IOALL2,DEBUG,JAC,	;++JOB DATA AREA CLOBBERED
	MOVEI	M,0
IOALL0:	SKIPN	F,USRJDA##(P1)	;GET NEXT DDB ADR., IS IT IN USE?
	JRST	IOALL1		;NO, KEEP GOING
	MOVE	S,DEVIOS(F)
	DPB	P1,PUUOAC##
	MOVE	T4,DEVSER(F)	;SETUP ADR. OF DEV. DISP. TABLE
	LDB	T1,PJOBN##	;GET JOB NUMBER WHICH JOB IS ASSIGNED TO
	CAMN	T1,JOB##	;IS IT SAME AS CURRENT JOB(SHOULD BE EXCEPT FOR 140
				; RESTART WHILE THIS JOB WAS SWAPPED OUT)
				; DEVICE DATA BLOCKS JOB NUMBERS ARE SET TO 0 ON
				; 400 RESTART,BUT THE JOB DATA AREA DEVICE ASSIGNMENTS
				; FOR SWAPPED OUT JOBS HAVE NOT
	PUSHJ	P,@-1(P)	;YES,CALL THE SUB.
IOALL1:	SOJGE	P1,IOALL0	;DECREMENT USER CHANNEL NUMBER
IOALL2:	POP	P,M		;RESTORE M & RETURN RESTORING T1 TOO
	MOVE	J,JOB##		;GET JOB NO.
	JRST	TPOPJ##


;WAIT TILL ALL DEVICES ARE INACTIVE


IOWAIT::MOVEI	T1,WAIT1##
	JRST	IOALL
;ROUTINE TO CLEAR PROTECTED JOB DATA AREA IN MONITOR
;AND RECLAIM FREE AREA ABOVE USER PROGRAM FOR IO BUFFERS
;CALL:	MOVE R,ADR. OF CURRENT JOB DATA AREA
;	PUSHJ P,SETUSR


SETUSR::HLRZ	T1,JOBSA##(R)	;RESET FIRST FREE LOC. FOR THIS JOB
	MOVEM	T1,JOBFF##(R)
CLRUSR::SETZM	JOBENB##(R)	;INITIALIZE APR TRAPPING (I.E., NONE)
	MOVEI	T1,USRLO1##	;FIRST LOC+1 TO CLEAR
	HRLI	T1,USRLO##	;FIRST LOC.
	SETZM	USRLO##
	BLT	T1,USRHI##
	SETZM	USRHCU##	;CLEAR HIGHEST USER IO CHAN. IN USE
	POPJ	P,
;ROUTINE TO FLAG DEVICE ACTIVE
;CALL	MOVE S,IO STATUS BITS
;	MOVE F,ADDRESS OF DEVICE DATA BLOCK
;	PUSHJ P,SETACT
;CALLED BY ALL IO SERVICE ROUTINES AT UUO AND INTERRUPT LEVELS


REPEAT 0,<
ORACT:	TRO	S,IOACT
	IORB	S,DEVIOS(F)
	JRST	SETHNG
>
SETACT::TROA	S,IOACT
CLRACT::TRZ	S,IOACT
	TLZ	S,IOW
STOIOS::MOVEM	S,DEVIOS(F)
SETHNG::LDB	T1,PDVTIM##	;GET CODE FOR NO. OF SECONDS
	PUSH	P,T1		;STACK THE CODE
	MOVEI	T1,1		;COMPUTE 2**N-1
	LSH	T1,@0(P)	; ..
	SUBI	T1,1
	DPB	T1,PDVCNT##	;PUT TIME INTO THE COUNTER
IFN FTMSGSER&<FTKI10!FTKL10>&FTVM,<
	MOVEI	T1,DEPMSG	;LOAD UP THE MESSAGE BIT
	TDNE	T1,DEVMSG(F)	;CONTROLED BY MSGSER?
	PUSHJ	P,MPXIOS##	;YES--UPDATE IOACT IN MPX DDB
> ;END FTMSGSER&FTKI10&FTVM
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
DEVCHK::HLRZ	F,HNGLST##
DEVCK0:	MOVE	S,DEVIOS(F)	;IS DEVICE ACTIVE?
	MOVE	T4,DEVSER(F)	;DISPATCH TABLE ADDRESS
	MOVE	T1,DEVCHR(F)	;WORD CONTAINING DEVICE OFF-LINE BIT
	TLNE	T1,DVOFLN	;DID THE SERVICE ROUTINE SAY ITS ONN-LINE?
	PUSHJ	P,DOFL(T4)	;YES, SEE IF ITS STILL OFF-LINE
	  JRST	DEVCK1		;IT IS
	MOVSI	T1,DVOFLN	;ITS ON-LINE, CLEAR THE OFF-LINE BIT
	ANDCAM	T1,DEVCHR(F)
IFN FTPI,<
	PUSHJ	P,PSIONL##	;TELL THE USER ITS ON-LINE IF HE'S INTERESTED
>
DEVCK1:	TRNN	S,IOACT
	JRST	DEVCK2		;NO
	LDB	T1,PDVCNT##	;YES,DECREMENT
	SOJL	T1,DEVCK2	;0 MEANS IGNORE DEVICE
	DPB	T1,PDVCNT##
	JUMPN	T1,DEVCK2	;HAS COUNT GONE TO 0?
	PUSH	P,F
	PUSHJ	P,DHNG(T4)	;DISPATCH TO SERVICE ROUTINES TO 
				; UNHANG DEVICE
	  PUSHJ	P,DEVHNG##	;PRINT ERROR MESSAGE AND STOP JOB
	POP	P,F		;DO NOT PRINT MESS. AND STOP JOB RETURN
DEVCK2:	HLRZ	F,DEVSER(F)
	JUMPN	F,DEVCK0
	POPJ	P,
;ROUTINE TO SETUP R AND J FOR INTERRUPT SERVICE ROUTINE

;CALL	PUSHJ P,IOSET
;	EXIT	ALWAYS RETURNS HERE
;THIS PROGRAM IS CALLED FROM AN INTERRUPT SERVICE ROUTINE.
;IT PUTS THE ADDRESS OF THE DATA AREA OF THE JOB (C(JBTADR18-35))
;CONNECTED TO THE DEVICE SPECIFIED BY AC F IN AC R AND
;PUTS THE J POINTER (C(DEVCTR)) IN AC ITEM.


IOSET::	LDB	R,PJOBN##
	MOVE	J,DEVCTR(F)	;J:=J POINTER=C(DEVCTR)
	MOVE	R,JBTADR##(R)	;R:=C(JBTADR 18-35)
	MOVE	S,DEVIOS(F)	;GET IO STATUS FROM THE DDB
	POPJ	P,		;RETURN

;CALLING SEQUENCE
;	PUSHJ P,IOSETC
;	EXIT		ALWAYS RETURNS HERE

;SETS JBFPTR18-35:=C(T2 18-35)
;	JBFCTR:=C(J)*[WORD LENGTH/BYTE SIZE]
;WHERE	WORD LENGTH:=36 DECIMAL
;	BYTE SIZE:=C(JBFPTR6-11)
;	[X]:= INTEGER PART OF X




IOSETC::ADDI	U,1		;JBFPTR12-18:=0
	HRLZI	T1,7777		;JBFPTR18-35:=C(T2 18-35)+1
	EXCTUU	<ANDM T1,@U>
	EXCTUU	<HRRM T2,@U>
	EXCTUU	<AOS @U>
	TLNN	S,IO		;DO THINGS DIFFERENTLY ONLY ON INPUT.
	LDB	T1,PIOMOD	;I/O MODE
	CAIE	T1,PIMMOD	;COUNT BYTES FOR PIM OR BYTE
	CAIN	T1,BYTMOD	;BYTE MODE?
	SOJA	U,IOSET2	;YES, BACKUP U TO POINT AT 1ST WORD OF THE HEADER
	EXCTUX	<LDB T2,[POINT 6,@U,11]>	;T2:=BYTE SIZE
	PUSHJ	P,ITMCT1	;JBFCTR:=C(J)*[36/BYTE SIZE]
IOSET1:	ADDI	U,1
	EXCTXU	<MOVEM J,@U>
	POPJ	P,		;EXIT

;HERE IF BYTE MODE I/O, STORE BYTE COUNT COMPUTED BY THE SERVICE ROUTINE
IOSET2:	EXCTUX	<MOVE	T1,@U>	;POINTER TO THE CURRENT BUFFER
	HLL	T1,U		;RELOCATE
	ADDI	T1,1		;POINT AT THE COUNT WORD IN THE BUFFER
	EXCTUX	<MOVE	J,@T1>	;GET THE BYTE COUNT FROM THE BUFFER
	AOJA	U,IOSET1	;STORE IT IN THE USER'S RING HEADER
;ROUTINE TO SET UP CONDITIONS FOR RETURN FROM INTERRUPT LEVEL ON
;DEVICE ERROR (UNIT RECORD)
;SERVICE ROUTINES USING THIS FACILITY MUST FOLLOW THE FOLLOWING PROTOCOL

;A.  AT INTERRUPT LEVEL,
;       IF NO ERROR AT END OF DATA: CLEAR IOSTBL IN LH(S)
;       IF ERROR:
;	1. STOP DEVICE
;	2. PUSHJ P,DEVERR
;	3. SET INTERNAL FLAGS TO REMEMBER ERROR CONDITION TO EFFECT
;	   RESTART AT A LATER TIME
;	4. DISMISS INTERRUPT

;B. AT UUO LEVEL ENTRANCES THE FOLLOWING MUST BE DONE

;	1. INIT/RELEASE - RESET INTERNAL ERROR FLAGS
;	2. INPUT/OUTPUT - IF ERROR FLAGS (INTERNAL) SET:
;	   A. CALL HNGSTP
;	   B. SEE IF DEVICE OK NOW (CALL HNGSTP AGAIN IF NOT)
;	   C. SET DEVICE FOR RESTART FROM INFO SAVED IN INTERNAL FLAGS
;	      AND RESET FLAGS
;	   NOTE: IOSTBL WILL ALWAYS BE CLEARED AT UUO ENTRANCE TO SERVICE ROUTINE

;	   IF NO ERROR FLAGS SET, NORMAL EXECUTION


DEVERR::TLO	S,IOSTBL	;SET ERROR FLAG
IFN FTMSGSER,<
	MOVEI	T1,DEPMSG	;CONTROLLED BY MSGSER ?
	TDNN	T1,DEVMSG(F)
	JRST	DEVER1		;NO
	PUSH	P,F
	HRRZ	F,DEVXTR(F)	;YES, GET THE MPX DDB
	MOVSI	T1,IOSTBL
	IORM	T1,DEVIOS(F)	;LITE TROUBLE THERE ALSO
	POP	P,F		;RESTORE F
DEVER1:>
				;IN I/O WAIT?
	PUSHJ	P,SETIOD##	;YES - WAKE UP
IFN FTKI10!FTKL10,<
	PUSHJ	P,RTEVM##	;RETURN EVM IF ANY
>
	PJRST	CLRACT		;CLEAR I/O ACTIVE AND RETURN
;ROUTINE TO RETURN NO. OF ITEMS IN BUFFER

;CALL:	PUSHJ P,ITMSET
;	EXIT		ALWAYS RETURNS HERE
;SETS AC J:=(BUFFER SIZE-1)*[WORD LENGTH/BYTE SIZE]
;WHERE BUFFER SIZE:=BITS 1-17 OF THE BUFFER HEADER WORD POINTED TO
;		BY C(DEVADR)
;	WORD LENGTH:=36 DECIMAL
;	BYTE SIZE:=INTEGER PART OF X.

;CALLING SEQUENCE
;	PUSHJ P,ITMCNT
;	EXIT		ALWAYS RETURNS HERE
;SETS AC J:=C(J)*[WORD LENGHT/BYTE SIZE]

;CALLING SEQUENCE
;	PUSHJ P,ITMCT1
;	EXIT		ALWAYS RETURNS HERE
;SETS AC J:=C(J)*[WORD LENGHT/C(T2)]

ITMSET::LDB	J,[POINT 17,@DEVADR(F),17];J:=BUFFER SIZE-1
	SUBI	J,1
ITMCNT::LDB	T2,[POINT 6,DEVPTR(F),11];T2:=BYTE SIZE
ITMCT1::MOVEI	T1,44		;J:=C(J)*[WORD LENGTH/C(T2)]
	IDIV	T1,T2
	IMUL	J,T1
	POPJ	P,
;ROUTINE TO SET DEVICE STATUS WORD FROM UUO
;AND SETUP S


SETIOS::PUSHJ	P,WAIT2		;WAIT FOR DEVICE (INCLUDING TTY MONITOR COMMAND
				; RESPONSE WHEN USER INITS TTY)

	PUSHJ	P,CHKMOD	;CHECK FOR LEGAL MODE, IF NOT RIGHT DONT RETURN
	TRZ	M,IOACT		;LET USER SET ALL BITS EXCEPT IOACT
	HRRM	M,DEVIOS(F)
	POPJ	P,



;CHECK FOR A LEGAL MODE FOR DEVICE


CHKMOD:	LDB	T2,[POINT 4,M,35]	;GET DEVICE DATA MODE
	MOVEI	T1,1		;AND CHECK FOR LEGALITY
	LSH	T1,(T2)
	TDNE	T1,DEVMOD(F)
	POPJ	P,		;OK
	PUSHJ	P,TTYKLQ##	;DISCARD DDB IF IT WAS A FREE TTY
	JRST	ILLMOD##	;AND GIVE ILLEGAL MODE ERROR

;CHKPIM CHECKS WHETHER A DEVICE IS INITED IN PACKED IMAGE MODE
;IT GIVES 2 RETURNS:
;1 NORMAL RETURN DEVICE IS INITED IN PIM MODE
;2 SKIP   RETURN DEVICE IS NOT INITED IN PIM MODE

CHKPIM::PUSH	P,T1		;SAVE T1
	LDB	T1,PIOMOD##	;LOAD THE MODE
	CAIN	T1,PIMMOD	;ENABLED IN PIM MODE
	JRST	TPOPJ		;YES GIVE NON SKIP RETURN
	JRST	TPOPJ1		;NO GIVE SKIP RETURN
;SETUP BYTE POINTER AND ITEM COUNT
;CALL	PUSHJ P,NEWBUF
;	ADDRESS CHECK WHEN SETTING UP BUFFER
;	OK RETURN




NEWBUF::HRRZ	T1,DEVADR(F)	;T1:=INPUT BUFFER HEADER ADDRESS
IFN FTKI10!FTKL10,<
	SKIPN	DEVEVM(F)	;DOES THIS DDB HAVE EVM?
	STOPCD	.,STOP,NEV,	;++NO EVM
	HLRZ	T2,(T1)		;BUFFER SIZE
	TRZ	T2,IOUSE	;CLEAR USE BIT
	ADDI	T2,(T1)		;LAST WORD TO CLEAR
	HRLS	T1		;MAKE A BLT POINTER
	AOBJN	T1,.+1
	SETZM	(T1)		;ZERO THE FIRST WORD OF THE BUFFER
	AOS	T1
	BLT	T1,(T2)		;ZERO THE BUFFER
>
IFN FTKA10,<
NEWBF2:	PUSHJ	P,BUFCLR	;CLEAR INPUT BUFFER.
	POPJ	P,		;ADDRESS CHECK
>
NEWBF3:	HRLZI	T1,7737
	AND	T1,DEVPTR(F)	;DEVPTR 0-5:=0, DEVPTR 12:=0
	HRR	T1,DEVADR(F)	;DEVPTR 18-35:=C(DEVADR 18-35) + 1
	AOS	T1
	MOVEM	T1,DEVPTR(F)
	PUSHJ	P,ITMSET	;J:=(BUFFER SIZE-1)*[36/BYTE SIZE]
	MOVEM	J,DEVCTR(F)	;DEVCTR:=ITEM COUNT
	JRST	CPOPJ1##	;RETURN
;ROUTINE TO SETUP BYTE POINTER ACCORDING TO DATA MODE

;CALL:	PUSHJ P,SETBYT
;	EXIT		ALWAYS RETURNS HERE
;SETS	T1 0-5:=0
;	T1 6-11:=S
;	T1 12-13:=0
;	T1 14-17:=R
;WHERE S=36 IF DATA MODE (S 32-25) IS BINARY (B)
;	IMAGE (I), IMAGE BINARY (IB), OR DUMP (SD,D,DR)
;      S=7  IF DATA MODE IS 	ASCII PACKED (A)
;			ASCII LINE (AL)
;			ASCII SEQUENCED (AS)
;			ASCII SEQUENCED LINE (ASL)
;		OR	ALTERNATE MODE BREAK (AM)

;CLOBBERS T2

SETBYT::HRLI	T1,PBYTMD##	;ASSUME BYTE MODE
	LDB	T2,PIOMOD##	;GET MODE FROM S
	CAIN	T2,BYTMOD	;IS IT ?
	POPJ	P,		;YES, RETURN
	TRNN	S,14		;IS MODE LESS THAN 10?
	HRLI	T1,PASCII##	;YES,ASCII OR ASCII LINE
	TRNE	S,14		;10 OR GREATER?
	HRLI	T1,PIMAGE##	;YES, IMAGE,IMAGE BIN. OR BIN.
	PUSHJ	P,CHKPIM	;PACKED IMAGE MODE CHECK
	  SKIPA			;YES
	POPJ	P,		;NO
	LDB	T2,PDVTYP##	;PIM, IS IT TTY
	CAIE	T2,<.TYMPX/.TYEST> ;ALLOW PIM ON MPX
	CAIN	T2,<.TYTTY/.TYEST> ;TEST
	HRLI	T1,PIMTTY##	;YES
	POPJ	P,
;ROUTINE TO STORE DATA IN IOBUFFER FOR INPUT CHAR. AT A TIME DEVICES

;CALL:	PUSHJ P,STODAT
;	EXIT1		CHECKSUM ERROR
;	EXIT2		BLOCK FULL OR BLOCK COMPLETE
;	EXIT3		DATA STORED CORRECTLY
;CALLED FROM AN INPUT SERVICE ROUTINE WITH A DATA J IN AC DAT.
;STORES THE DATA J IN THE BUFFER, CHECKING TO SEE IF IT WERE
;THE FIRST J ON THE BUFFER AND SETTING UP THE POINTER AND
;WORD COUNT APPROPRIATELY CHECKING THE MODE TO SEE IF ANY SPECIAL
;PROCESSING NEED BE DONE. FOR EXAMPLE, THE TERMINATION
;OF A BUFFER ON CERTAIN CHARACTERS IN OTHER MODES, OR IF THE BUFFER
;IS FULL.  THERE ARE THREE RETURNS FROM THIS ROUTINE: THE FIRST
;RETURN OCCURS ON AN ERROR CONDITION, THE SECOND RETURN OCCURS
;ON A BLOCK FULL CONDITION OR BLOCK COMPLETE CONDITION, THE THIRD
;RETURN OCCURS ON THE DATA STORED CORRECTLY CONDITION.  THIS
;ROUTINE ALSO DOES SOME CHECKING ON INPUT OF BINARY RECORD,
;PAPER TAPE OR CARDS.
;CALLING SEQUENCE
;	PUSHJ P,STOSQD
;	XXXX		ALWAYS SKIPS 
;	EXIT		ALWAYS RETURNS HERE
;STORES THE WORD COUNT:=C(DEVPTR 18-35) -C(DEVIAD 18-35) - 1
;IN THE BUFFER.
STODAT::TLNN	S,IOFST		;IS THIS FIRST J OF BUFFER?
	JRST	STO0		;NO
	PUSHJ	P,NEWBUF	;SET UP A NEW BUFFER. J:=(BUFFER 
				; SIZE - 1)*[36/BYTE SIZE]
	POPJ	P,
STO0:	LDB	T2,PIOMOD##	;DATA MODE
	CAIN	T2,B		;MODE=BINARY?
	JRST	STOBIN
	TLZ	S,IOFST
STO1:	IDPB	U,DEVPTR(F)	;STORE DATA IN BUFFER.
	CAIE	T2,A		;MODE=ASCII, IMAGE, OR BINARY?
	CAIN	T2,I
	JRST	STOAIB
	CAIE	T2,IB		;IMAGE BINARY?
	CAIN	T2,B		;CHECKSUM BINARY?
	JRST	STOAIB		;YES
	ANDI	U,177		;NO, MUST BE ASCII LINE MODE.
	CAIG	 U,14		;LINE FEED,FORM FEED, OR VERTICAL TAB?
	CAIGE	U,12
	JRST	.+2		;NO
	JRST	STOSQF		;YES
	SOJGE	J,CPOPJ2##	;J:=C(J)-1. IS C(J) GR OR=0?
STOE1:	TRO	S,IOBKTL	;IOBKTL:=1
	POPJ	P,
STOAIB:	SOJG	J,CPOPJ2##;	J:=C(J)-1. IS C(J) GR 0?
	CAIN	T2,A		;MODE=ASCII?
	JRST	STOSQF		;YES
	CAIN	T2,B		;MODE=BINARY?
	JRST	STOBND		;YES, COMPUTE CHECKSUM AND CHECK.
	PUSHJ	P,ITMSET	;J:=(BUFFER SIZE-1)*[36/BYTE SIZE]
				; - C(DEVCTR)
	SUB	J,DEVCTR(F)
	MOVE	T2,DEVIAD(F)	;STORE ITEM COUNT
	ADDI	J,1		;IN FIRST WORD OF BUFFER
	AOJA	T2,STOSQE
STOSQD::TLZN	S,IOFST		;FIRST CALL?
	JRST	STOSQF		;NO
	PUSHJ	P,NEWBUF	;YES, CLEAR BUFFER,SET ITEM COUNT
	POPJ	P,		;ADDRESS CHECK
STOSQF:	MOVE	T2,DEVIAD(F)	;REL. ADR. OF BUFFER
	AOS	T2
	HRRZ	J,DEVPTR(F)	;J:=C(DEVPTR 18-35) -
				; C(DEVIAD 18-35) -1
	SUBI	J,(T2)
STOSQE:	HRRM	J,@T2		;WORD COUNT TO FIRST WORD IN BUFFER
	JRST	CPOPJ1##	;EXIT2. BLOCK COMPLETE


STOBIN:	TLZN	S,IOFST		;WILL THE NEXT J BE THE FIRST J
	JRST	STO1		;OF A BUFFER?  IOFST:=0
	HRRZ	T1,U		;YES.
	CAMLE	T1,J		;IS WORD COUNT LE (BUFFER SIZE-1)*
	JRST	STOE1		; [36/BYTE SIZE]?
	MOVE	J,T1		;J:=WORD COUNT
	MOVEM	U,@DEVPTR(F)	;STORE WORD COUNT IN BUFFER
	JRST	CPOPJ2##	;EXIT3.  DATA STORED CORRECTLY.

STOBND:	MOVEI	T2,@DEVIAD(F)
	PUSHJ	P,CKS12		;COMPUTE CHECKSUM
	ADD	T2, DEVIAD(F)
	HLLZ	T2,@T2		;DATA CHECKSUM=COMPUTED CHECKSUM?
	CAMN	T1,T2
	JRST	CPOPJ1##	;EXIT2. BLOCK COMPLETE
	TRO	S,IODTER	;IODTER:=1
	POPJ	P,		;EXIT1. CHECKSUM ERROR

	XLIST
	$LIT
	LIST
UUOEND::END