Google
 

Trailing-Edge - PDP-10 Archives - PCL_FOR_701 - 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 - V1335
SUBTTL /CHW/TL/RCC/CMF/PH/GDR/DAL/EVS/TW/JMF/DRT/JBS	22 JUL 80
	SEARCH	F,S
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
XP VUUOCN,1335
		;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
;
;
;                        SECTION                                   PAGE
;    1. UUO DISPATCH ROUTINE......................................   2
;    2. CALL & CALLI UUO'S........................................   7
;    3. EXIT & SETPOV UUO'S.......................................  19
;    4. RESET & APRENB UUO'S......................................  20
;    5. MISC. ACCOUNTING UUOS (JOBNO,JOBTIM,DATE & MSTIME)........  24
;    6. SLEEP SERVICE FOR SLEEP UUO, DTA, MTA AND SCNSER..........  26
;    7. PEEK UUO..................................................  27
;    8. POKE. UUO.................................................  28
;    9. PERF. MUUO................................................  31
;   10. CALLS TO SEGCON FOR SETUWP AND REMAP......................  35
;   11. TRIVIAL UUOS (LIGHTS, TIMER AND SWITCH)...................  36
;   12. DVPHY. UUO................................................  37
;   13. DEVCHR AND DEVSIZ UUO'S...................................  39
;   14. GETPPN AND DEVPPN UUO'S (ALSO RTZER)......................  45
;   15. IONDX.  UUO...............................................  46
;   16. SUBROUTINE TO FIND A DDB GIVEN ITS IO INDEX...............  48
;   17. GTNTN./GTXTN. UUO'S FOR TTY NAMES.........................  50
;   18. MVBFH. UUO
;        18.1   MOVE BUFFER HEADERS...............................  52
;   19. DEVSTS, DEVLNM, DEVRST, AND DEVURS UUO'S..................  53
;   20. SETDDT, WAIT AND GETLIN CALLI'S ; WAIT2 AND GETPPL........  56
;   21. ACCT. UUO - ACCOUNTING UUO................................  59
;   22. LOGIN, LOGOUT AND ATTACH UUO'S............................  61
;   23. GETTAB UUO................................................  67
;   24. SETNAM & CNGPPN UUO'S.....................................  73
;   25. DEVNAM UUO................................................  74
;   26. REAL-TIME AND HIBWAKE FEATURE.............................  75
;   27. DAEMON UUO'S AND ROUTINES.................................  84
;   28. ALLOC. UUO................................................  91
;   29. DEVOP. UUO................................................  95
;   30. FILOP. UUO................................................  97
;   31. PERF. UUO................................................. 109
;   32. CLOSE UUO................................................. 110
;   33. INBUF & OUTBUF UUO'S...................................... 114
;   34. OPEN & INIT UUO'S......................................... 115
;   35. COMMON PART OF LOOKUP AND ENTER........................... 121
;   36. COMMON PART OF RENAME, USETI/O, UGETF AND UTPCLR.......... 123
;   37. COMMON PART OF INPUT AND OUTPUT UUO'S..................... 124
;   38. RELEASE UUO............................................... 140
;   39. STATUS SETTING AND GETTING UUO'S.......................... 142
;   40. ROUTINES TO ADVANCE BUFFERS............................... 144
;   41. DUMP MODE COMMAND LIST PROCESSING ROUTINES................ 152
;   42. DDB SCAN LOGIC............................................ 156
;   43. BUFFER RING BUILDER & CLEARER............................. 178
;   44. RANDOM SUBROUTINES FOR I/O................................ 182


;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
;	M	;THE CONTENTS OF LOC 40
		; 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 
UUOSY1::MOVE	M,.UPMP+.UPMUO	;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,.CPJOB##	;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,.UPMP+.UPMUP	;SAVE RETURN ON PUSH DOWN LIST
	PUSHJ	P,FNDPDS##	;FIND JOB'S PDB
IFN FTACCT,<
	AOS	.PDUUC##(W)	;COUNT THE UUO
>
	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
	HRRZ	T3,USRHCU##
	SKIPE	F,USRJDA##(P1)	;GET ADDRESS OF DEVICE DATA BLOCK

	CAMLE	P1,T3

	JRST	NOCHAN		;CHANNEL NOT ASSIGNED
	HRLM	P1,.UPMP+.UPCTA	;STORE CHANNEL NUMBER
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
	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 FTMP,<
	TRNN	T3,UU.CP1	;CAN UUO BE EXECUTED ON ANY CPU
	PUSHJ	P,ONCPU0##	;NO, GET ONTO BOOTSTRAP CPU
>
	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:	PUSHJ	P,INCPD1##
USRXIT::
IFN FTNET,<
	NTDBUG	NO,EITHER	;MUST NOT HAVE THE INTERLOCK.  ANY LEVEL OK.
>
	JUMPE	F,UUOND1	;NO DDB
	HRRZ	T1,DEVSER(F)	;GET DISPATCH TABLE ADDRESS
IFN FTNET,<
	CAIE	T1,NETDSP##	;IS IT A NETWORK DEVICE?
	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
	CAIN	T1,SCNDSP##	;IS IT A TTY DDB?
	PUSHJ	P,TTYKLQ##	;YES, GIVE IT UP IF NOT IN USE
UUOND1:	MOVSI	T1,37		;GET MASK OF IR+IND FIELDS
	IORM	T1,.UPMP+.UPMUO	;OR INTO 40 SO UUO WATCHERS SEE IT
	MOVE	J,.CPJOB##	;CURRENT JOB NUMBER
IFN FTMP,<
	PUSHJ	P,UXITMP##	;CHECK IF JOB IS RUNNABLE ON THIS CPU
	  JRST	[MOVE T1,JBTSTS##(J) ;NO, GO DO A RESCHEDULE
		 JRST USRXT2]
>
	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	.CPTMF##	;NO. HAS CLOCK TICKED WHILE IN MONITOR?
	JRST	USRXT2		;YES, GO CALL SCHEDULER
	CAME	J,FORCEF##	;TRYING TO SWAP THIS JOB
	SKIPE	SCDRTF##	;NO, SHOULD WE DO A HIGH PRIORITY RESCHEDULE
;------ 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>,<
	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	PINOJN##	;SKIP IF CANNOT GRANT INTERRUPTS
	PUSHJ	P,PSIGEN##	;CAN, GIVE ANY TO THE USER
> ;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,.JDAT+JOBFDV##	;GET NEW PC
	JRST	USRXJI		;NO--GO DO .JBINT
>
IFE FTCCIN,<
	MOVE	T4,.JDAT+JOBFDV##	;GET NEW PC
>
	MOVEM	T2,.JDAT+JOBOPC##	;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:	JRST	UMPRET##	;RETURN TO COMMON FOR UUO EXIT
NOCHAN:	SKIPL	USRHCU##	;SAVE/SET IN PROGRESS?
	CAMG	P1,USRHCU##	;NO, MAKE SURE LEGAL CHANNEL
	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



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 LONG DISPATCH TABLE UUO
	UMTAPE,,UDGF		;(72,73)MTAPE,GETF
	UDSI,,UDSO		;(74,75)USETI,USETO
	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 52,53 AND 54 ARE RESERVED FOR EXPANSION BY DIGITAL

;TABLE OF CHECK-BITS FOR UUOS
CHKTAB::UU.EA+UU.CP1,,UU.CP1+3	;CALL,INIT
	0,,0			;42,43
	0,,0			;44,45
	0,,UU.CP1		;46,CALLI
	UU.CP1+UU.EA+3,,UU.CP1+UU.EA	;OPEN,TTCALL
	0,,0			;52,53
	0,,UU.CP1+UU.LER	;54,RENAME
	UU.CP1,,UU.CP1		;IN,OUT
	UU.CP1,,UU.CP1		;SETSTS,STATO
	UU.CP1,,UU.CP1		;GETSTS,STATZ
	UU.CP1,,UU.CP1		;INBUF,OUTBUF
	UU.CP1,,UU.CP1		;INPUT,,OUTPUT
	UU.CP1,,UU.CP1		;CLOSE,,RELEASE
	UU.CP1,,UU.CP1		;MTAPE,UGETF
	UU.CP1,,UU.CP1		;USETI,USETO
	UU.CP1+UU.LER,,UU.CP1+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, M SET TO POINT TO USER AC
;J SET TO JOB NUMBER
UCALL:	PUSHJ	P,UCALLX	;CALCULATE CALLI INDEX
	  POPJ	P,		;BAD ARGUMENT
	JRST	UCALLI		;LIKE CALLI
UCALLX::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
	JRST	CPOPJ1##	;GOOD RETURN
;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)
	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
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
	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 <
	XLIST
IFN FTPATT,<
X	CPOPJ,CPOPJ##,UU.CP1            ;(-3) PLACE FOR CUSTOMERS
                                        ;    TO PATCH UUOS
X	CPOPJ,CPOPJ##,UU.CP1            ;(-2) 
>
X	LIGHTS,LIGHTS,UU.CP1            ;(-1) SET LIGHTS (EXAMPLE
                                        ;    OF CUSTOMER DEFINED
                                        ;    UUO)
>

DEFINE NAMES,<
X	RESET,RESET,UU.CP1		;(0)RESET IO
X	DDTIN,DDTIN##,UU.CP1+UU.EA+25   ;(1)EXT-GET DDT CHAR.
X	SETDDT,SETDDT,UU.CP1            ;(2)SETDDT LOC IN PROTECTED
                                        ;    JOB DATA
X	DDTOUT,DDTOUT##,UU.CP1+UU.EA+25  ;(3)EXT:SEND DDT CHAR.
X	DEVCHR,DVCHR,UU.CP1             ;(4)DEVICE CHARACTISTICS
X	DDTGT,CPOPJ##,UU.CP1            ;(5)GET DDT MODE
X	GETCHR,DVCHR,UU.CP1             ;(6)DEVICE CHAR.(DIFF. NAME)
X	DDTRL,CPOPJ##,UU.CP1            ;(7)RELEASE DDT MODE
X	WAIT,WAIT,UU.CP1                ;(10)WAIT TILL DEVICE INACTIVE
X	CORE,CORUUO##,UU.CP1		;(11)CORE UUO
X	EXIT,EXIT,UU.CP1		;(12)EXIT
X	UTPCLR,UTPCLR,UU.CP1            ;(13)CLEAR DEC TAPE DIRECTORY
                                        ;    
X	DATE,DATE,UU.CP1                ;(14)GET DATE
X	LOGIN,LOGIN,UU.MEA+UU.CP1 	;(15)LOGIN
X	APRENB,APRENB,UU.CP1            ;(16)ENABLE APR FOR TRAPPING
X	LOGOUT,LOGOUT,UU.CP1 		;(17)LOGOUT
X	SWITCH,SWITCH,UU.CP1            ;(20)RETURN DATA SWITCHES
X	REASSI,REASSI##,UU.CP1          ;(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+UU.CP1     ;(25)SET PI TRAP LOC, AND
                                        ;    USER IO
X	TRPJEN,UUOERR##,UU.CP1          ;(26)DISMISS INTERRUPT TO
                                        ;    EXEC MODE(SUPERCEDED
                                        ;    BY UJEN)
X	RUNTIM,JOBTIM,UU.CP1            ;(27)RETURN TOTAL JOB RUNNING
                                        ;    TIME
X	PJOB,JOBNO,UU.CP1               ;(30)RETURN JOB NUMBER
X	SLEEP,SLEEP,UU.CP1              ;(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+UU.CP1 	;(35) RUN DEV:FILE
X	SETUWP,SETUWP,UU.CP1            ;(36) SET OR CLEAR USER MODE
                                        ;    WRITE PROTECT
X	REMAP,REMAP,UU.CP1              ;(37) REMAP TOP OF LOW SEGMENT
                                        ;    INTO HIGH SEG
X	GETSEG,UGTSEG##,UU.EA+6+UU.CP1 	;(40) GET SHARABLE HIGH SEG
X	GETTAB,GETTAB,UU.CP1            ;(41) GET EXEC ADDRESS OF
                                        ;    A JOB TABLE
X	SPY,USPY##,UU.CP1        ;(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+UU.CP1 	;(44) TEMPORARY FILE STORAGE
                                        ;    UUO (CCL)
X	DSKCHR,DSKCHR##,UU.CP1+UU.LEA   ;(45) DISK CHARACTERISTICS
                                        ;LAST CALLI IN 4.72
X	SYSSTR,SYSTUU##,UU.CP1          ;(46) RETURN NEXT STR IN
                                        ;    SYSTEM
X	JOBSTR,JOBSTR##,UU.LEA+UU.CP1 	;(47) RETURN NEXT STR IN
                                        ;    JOB
X	STRUUO,STRUUO##,UU.CP1+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,UU.CP1             ;(53) EXTENDED DEVICE CHARACTERISTICS
                                        ;    AND BUFFER SIZE


;CONTINUED ON NEXT PAGE
X	DEVSTS,DEVST,UU.CP1             ;(54) DEVSTS
X	DEVPPN,DEVPPU,UU.CP1            ;(55) RETURN PPN FOR DEVICE
X	SEEK,UUOSEK##,UU.CP1            ;(56) SEEK
                                        ;LAST CALLI IN 5.01
X	RTTRP,RTTRP##,UU.CP1+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##,UU.CP1            ;(63) FOR REMOTE COMM
X	DEVNAM,UDEVNM,UU.CP1            ;(64) GET PHYSICAL DEVICE
                                        ;    NAME
X	CTLJOB,CTLJOB##,UU.CP1          ;(65) FIND CONTROLLER OF
                                        ;    THIS JOB (IF BY PTY)
X	GOBSTR,GOBSTR##,UU.CP1+UU.LEA   ;(66) GENERALIZED JOBSTR
                                        ;    (ANY JOB'S SEARCH LIST)
                                        ;LAST CALLI IN 5.02
X	FOO,CPOPJ##,UU.CP1              ;(67) FOO
X	FOO,CPOPJ##,UU.CP1              ;(70) FOO
X	HPQ,HPQ##,UU.CP1                ;(71) HIGH PRIORITY QUEUE
                                        ;    UUO
X	HIBER,HIBUUO,UU.CP1             ;(72) HIBERNATE UUO

X	WAKE,WAKUUO,UU.CP1              ;(73) WAKE UUO
X	CHGPPN,CHGPPN,UU.CP1            ;(74) CHANGE PPN
X	SETUUO,SETUUO##,UU.CP1          ;(75) SET
X	DEVGEN,DEVGEN,UU.CP1            ;(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.CP1+UU.EA+3  ;(100) ACCESS-ALLOWED UUO
X	DEVSIZ,DVSIZ,UU.CP1             ;(101) RETURN BUFFER SIZE
X	DAEMON,CALDAE,UU.CP1+UU.LEA     ;(102) CALL DAEMON
X	JOBPEK,JOBPEK,UU.CP1+UU.EA+2    ;(103) READ/WRITE ANOTHER
                                        ;    JOB'S CORE
X	ATTACH,UATTAC,UU.CP1 		;(104) ATTACH OR DETACH JOBS.
X	DAEFIN,DAEFIN,UU.LEA+UU.CP1 	;(105) DAEMON FINISHED -
                                        ;    RESTART USER JOB
X	FRCUUO,FRCUUO,UU.LEA+UU.CP1	;(106) FORCE COMMAND FOR
                                        ;    JOB
X	DEVLNM,DEVLNM,UU.CP1            ;(107) SET DEVICE LOGICAL
                                        ;    NAME
                                        ;LAST CALLI IN 5.03


;CONTINUED ON NEXT PAGE
X	PATH.,PTHUUO##,UU.CP1+UU.LEA    ;(110) TEST/SET FULL PATHS
                                        ;    TO FILES
X	METER.,METER##,UU.LEA           ;(111)PERFORMANCE METERING
X	MTCHR.,MTACHR##,UU.CP1		;(112)GET MAGTAPE CHARACTERISTICS
X	JBSET.,JBSET.##,UU.EA+2+UU.CP1	;(113)JOB SETUUO
X	POKE.,POKE,UU.CP1+UU.EA+3       ;(114)CHANGE MONITOR
X	TRMNO.,TRMNO##,UU.CP1           ;(115)TERMINAL NUMBER FOR
                                        ;    JOB
X	TRMOP.,TRMOP##,UU.LEA+UU.CP1    ;(116)TERMINAL OPERATIONS
                                        ;    UUO
X	RESDV.,RESDV,UU.CP1             ;(117)RESET DEVICE OR CHANNEL
X	UNLOK.,UNLOK.##,UU.CP1          ;(120)UNLOCK A LOCKED JOB
                                        ;LAST CALLI IN 5.04
X	DISK.,DSKUUO##,UU.CP1+UU.EA     ;(121)RANDOM DISK FUNCTIONS
X	DVRST.,DEVRST,UU.CP1            ;(122)RESTRICT DEVICE TO
                                        ;    OPER ONLY
X	DVURS.,DEVURS,UU.CP1            ;(123)UNRESTRICT DEVICE
                                        ;LAST CALLI IN 5.05 & 5.06
X	XTTSK.,XTUUO##,UU.LEA+UU.CP1    ;(124)DA28C DEPENDENT FUNCTIONS
X	CAL11.,CALL11##,UU.LEA+UU.CP1   ;(125)MULTI-FUNCTION CALLI
                                        ;    FOR THE PDP-11
X	MTAID.,MTARID##,UU.CP1          ;(126)FOR MTA ERROR REPORTING
X	IONDX.,UIONDX,UU.CP1            ;(127)RETURN IO INDEX

X	CNECT.,CONECT##,UU.CP1+UU.EA+1	;(130)CONNECT A DEVICE TO
                                        ;    AN MPX CHAN
X	MVHDR.,MOVHDR,UU.CP1		;(131)MOVE BUFFER HEADER
X	ERLST.,ERLST##,UU.CP1+UU.EA+2	;(132)ERROR LIST
X	SENSE.,SENSE##,UU.CP1+UU.LEA	;(133)SENSE
X	CLRST.,CLRST##,UU.CP1+UU.LEA	;(134)CLEAR STATUS


;CONTINUED ON NEXT PAGE
X	PIINI.,PIINI##,UU.CP1+UU.EA     ;(135)INITIALIZE SOFTWARE
                                        ;    INTERRUPT SYSTEM
X	PISYS.,PISYS##,UU.CP1           ;(136)MANIPULATE SOFT. INTERRUPT
                                        ;    SYSTEM
X	DEBRK.,DEBRK##,UU.CP1           ;(137)DISMISS A SOFTWARE
                                        ;    INTERRUPT
X	PISAV.,PISAVE##,UU.CP1+UU.LEA   ;(140)SAVE THE PI SYSTEM
X	PIRST.,PIRST##,UU.CP1+UU.EA+UU.CEA ;(141)RESTORE THE PI SYSTEM
X	IPCFR.,UIPCFR##,UU.CP1	        ;(142) IPCF READ
X	IPCFS.,UIPCFS##,UU.CP1        	;(143) IPCF SEND
X	IPCFQ.,UIPCFQ##,UU.CP1        	;(144) IPCF QUERY
X	PAGE.,UPAGE.##,UU.CP1           ;(145) PAGING UUOS

X	SUSET.,USUSET##,UU.CP1          ;(146) SUPER USETI/O
X	COMPT.,CPOPJ##,UU.CP1           ;(147) CALL TO COMPATABILITY
                                        ;    PACKAGES
                                        ;LAST CALLI IN 5.07/6.01
X	SCHED.,SCHED.##,UU.CP1		;(150) SCHEDULING UUO
X	ENQ.,ENQ##,UU.CP1		;(151) ENQUEUE
X	DEQ.,DEQ##,UU.CP1		;(152) DEQUEUE
X	ENQC.,ENQC##,UU.CP1		;(153) ENQ CONTROLLER


;CONTINUED ON NEXT PAGE
X	TAPOP.,UTAPOP##,UU.LEA+UU.CP1	;(154) TAPOP. UUO (SEE TAPSER)
X	FILOP.,FILOP,UU.CP1+UU.LEA      ;(155) FILOP. UUO

X	CAL78.,CPOPJ##,UU.CP1		;(156) FOR DAS78 (NOW OBSOLETE)
X	NODE.,NODE.U##,UU.CP1		;(157) RESERVED FOR NETWORKS
X	ERRPT.,ERRPT.##,UU.CP1		;(160) ERROR REPORTING UUO FOR DAEMON
X	ALLOC.,CPOPJ##,UU.CP1		;(161) OBSOLETE, ALLOC.UUO
X	PERF.,UPERF.,UU.CP1		;(162) PERFORMANCE ANALYSIS UUO
					;LAST UUO IN 6.02
X	DIAG.,DIAUUO,UU.CP1		;(163) DIAGNOSTIC UUO
X	DVPHY.,DVPHY.,UU.CP1		;(164) DVPHY.UUO

X	GTNTN.,GTNTN,UU.CP1		;(165) GET THE NETWORK TTY NUMBER
X	GTXTN.,GTXTN,UU.CP1		;(166) GET THE -10 TTY NAME

X	ACCT.,ACCT,UU.CP1		;(167) ACCOUNTING UUO
X	DTE.,DTE.##,UU.CP1		;(170) DTE. UUO
X	DEVOP.,DEVOP,UU.CP1+UU.LEA	;(171) DEVOP. UUO

X	SPPRM.,SPPRM,UU.CP1+UU.LEA	;(172) SPPRM. UUO
					;LAST UUO IN 6.03
X	MERGE.,UMERGE##,UU.CP1+UU.EA+6	;(173) MERGE. UUO
X	UTRP.,UUTRP,UU.CP1+UU.LER	;(174) UTRP. UUO
X	PIJBI.,PIJOB##,UU.CP1		;(175) PIJBI. UUO
X	SNOOP.,SNOOP,UU.CP1		;(176) SNOOP. UUO
X	TSK.,TSK.##,UU.CP1		;(177) TSK. UUO
X	KDP.,KDP.##,UU.CP1		;(200) KDP. UUO
					;LAST UUO IN 7.00
X	QUEUE.,GLXINF##,UU.CP1		;(201) QUEUE. UUO
X	RECON.,RECON,UU.CP1		;(202) RECON. UUO



;***ADD NEW CALLI'S ABOVE THIS LINE *****
IFN FTPATT,<
X	CPOPJ,CPOPJ##,UU.CP1   ;2 SPARE UUO'S FOR PATCHING - DIGITAL ONLY
X	CPOPJ,CPOPJ##,UU.CP1   ;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
	LIST
	SALL
>
;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
	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:	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,.JDAT+JOBAPR##
	MOVEI	T1,AP.POV
	JRST	APRENB		;SET TRAP LOC.

	SUBTTL	RESET & APRENB UUO'S


RESET::
IFN FTKL10,<
	PUSHJ	P,GIVPMR##
	PUSHJ	P,FEDRST##	;RELEASE FRONT END DEVICE
>;END IFN FTKL10
	PUSHJ	P,SNPRST	;REMOVE BREAK POINTS
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
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,<
	MOVEI	T1,[CAME J,.CPSTS##-.CPCDB##(P1) ;MAKE SURE SCHEDULING ALLOWED
		    SETZM .CPSTS##-.CPCDB##(P1)
		    POPJ P,]
				; IN CASE THIS FOLLOWS A TRPSET UUO
				;(IF STOPTS IS NON-ZERO, THIS MUST BE
				; THE JOB THAT STOPPED TIME SHARING)
	PUSHJ	P,CPUAPP##	;ZERO .CPSTS FOR ALL CPU'S
>
IFN FTMP,<
	PUSHJ	P,CRESET##	;RESET UUO SET CPU SPECIFICATION
>
	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
	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,IPCFRC##	;SIGNAL RESET TO SYS:INFO
>
	MOVEI	T1,RELEA5	;RELEASE ALL DEVICES
	PUSHJ	P,IOALL		; WITHOUT WAITING
	PUSHJ	P,TTYRES##	;NORMALIZE CONTROLLING TTY, IF ANY
	MOVEI	T1,HIGHXC##-20	;NUMBER OF EXTENDED CHANNELS
	HRRZ	T2,.UPMP+.UPCTA
	SKIPE	T2		;STILL HAVE FUNNY SPACE?
	PUSHJ	P,GVFWDS##	;GIVE IT BACK
	HLLZS	.UPMP+.UPCTA
IFN FTWATCH,<
	HRRZS	JBTPC##(J)	;NOT IN IOWAIT NOW (FOR ^T'ERS)
>
	PUSHJ	P,SETUSR	;CLEAR USERS JOB DATA AREA

IFN FTMDA,<
	PUSHJ	P,MDARST	;CHECK ANY STRUCTURE LOCKS
> ;END FTMDA
	MOVSI	T1,777777-USRMOD	;CLEAR ALL UUO PC FLAGS IN LH, EXCEPT USER MODE
	ANDCAM	T1,.JDAT+JOBPD1##	;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,.JDAT+JOBENB##  ;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

;HERE WHENEVER ANYJOB DOES A RESET
;CALL WITH J=JOB

IFN FTMDA,<
MDARST:	PUSHJ	P,FNDPDS##
	MOVE	T1,UDATEX##	;GET NOW
	MOVEM	T1,.PDSTM##(W)	;MARK LAST RESET TIME
	MOVSI	T1,(JS.OLS)	;GET OWNS LOCKED STR BIT
	TDNN	T1,JBTST2##(J)	;OWN ANY AT ALL?
	POPJ	P,		;NO, ALL DONE
	ANDCAM	T1,JBTST2##(J)	;YES, NOTED
				;SAVE PDB
	PUSHJ	P,SNDMDR##	;INFORM MDA
	  POPJ	P,		;IGNORE ERROR
	POPJ	P,
> ;END FTMDA
UTADC%==1			;ADDRESS CHECK
UTUNF%==2			;UNKNOWN FUNCTION
UTBTN%==3			;BAD TRAP NUMBER

ERCODE	UTEADC,UTADC%
ERCODE	UTEUNF,UTUNF%
ERCODE	UTEBTN,UTBTN%

UUTRP:	HLRZ	U,T1
	CAILE	U,NUTRPF
	JRST	UTEUNF
	HRR	M,T1
	PUSHJ	P,GETWRD##
	  JRST	UTEADC
	PUSHJ	P,SAVE1##
	MOVE	P1,T1
	JRST	@UTPTBL(U)

UTPTBL:	UTPRED
	UTPSET
NUTRPF==.-UTPTBL-1

UTPRED:	PUSHJ	P,GETTRN
	  POPJ	P,
	MOVE	T1,(U)
	PUSHJ	P,PUTWR1##
	  JRST	UTEADC
	SOJG	P1,UTPRED
	JRST	CPOPJ1##

UTPSET:	PUSHJ	P,GETTRN
	  POPJ	P,
	PUSHJ	P,GETWR1##
	  JRST	UTEADC
	MOVEM	T1,(U)
	SOJG	P1,UTPSET
	JRST	CPOPJ1##

GETTRN:	PUSHJ	P,GETWR1##
	  JRST	UTEADC
	SKIPLE	T1
	CAILE	T1,2
	JRST	UTEBTN
	MOVEI	U,.UPMP+.UPTVC(T1)
	SOJA	P1,CPOPJ1##
	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
	SKIPN	T1
	SKIPA	T1,J
	MOVE	J,T1		;J PROCESS # IN QUESTION
	PUSHJ	P,FNDPDB##	;FIND THE PDB
	  JRST	JOBTM3		;IF NONE RETURN ZERO
	MOVE	J,.CPJOB##	;SETUP 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##	;LEAVE IN T1
	.MOVE	T3,.PDEB2##(W)	;SAME FOR EBOX TICKS
	MULI	T3,RTUPS##
	DIV	T3,.CPEBJ##
	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
	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##
SLEEPF::
	PUSH	P,F		;PRESERVE F
	PUSHJ	P,SLEEP		;ZZZZZ
	JRST	FPOPJ##		;RESTORE F AND RETURN

	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::
	SETZ	F,		;LET WORLD KNOW THIS ISN'T AN I/O UUO
	IMUL	T1,TICSEC##	;CONVERT TO TICKS
	ANDI	T1,7777
MSLEEP:	TRNN	T1,7776		;0 TIME?(CHECK ONLY 12 BITS)
	MOVEI	T1,2		;YES. SLEEP 1 JIFFY
	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:	SYSPIF
	IDPB	T1,CLOCK##
	IDPB	J,CLOCK##
	SYSPIN
	SETOM	CLKNEW##	;NEW ENTRY HAS BEEN MADE
	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
	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
	MOVSI	T1,PVSPYA	;SEE IF USER MAY SPY ON ALL CORE
	PUSHJ	P,PRVBIT##	;..
	  JRST	PEEKOK		;YES.  OK
	JUMPL	P1,RTZER	;PHYSICAL ONLY REQUIRES PEEK ON ALL
				; OF CORE PRIVILEGES
	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:	PUSHJ	P,PPPADR	;IF PHYSICAL ONLY, GET VIRTUAL ADR
	  JRST	RTZER
	MOVE	T1,0(T2)	;YES.  GET WORD
	JRST	STOTAC##	;RETURN IT TO USER IN AC.
PEEKHI:	CAIL	T2,400000	;IS THIS IN THE
	CAML	T2,MONVFF##	; HISEG
	JRST	RTZER		; NO
	JRST	GOPEEK		; YES

>	;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	P2,T1		;SAVE ARGUMENT
	MOVSI	T1,JP.POK	;CHECK FOR POKE
	PUSHJ	P,PRVBIT##	;  PRIVILEGES
	  CAIA
	JRST	RTZER		;NO--BOMB USER
	HRR	M,P2		;POINT TO BLOCK
	PUSHJ	P,GETWDU##	;GET LOCATION
	CAIL	T1,MONORG	;BELOW THE BOTTOM OF THE MONITOR VIRTUAL ADDRESS SPACE?
	CAML	T1,MONVFF##	;BELOW THE TOP OF THE MONITOR VIRTUAL ADDRESS SPACE?
	CAIA
	JRST	POKE0
	CAILE	T1,17		;CHECK ADDRESS
	CAML	T1,MEMSIZ##	;  SEE IF LEGAL
	PJRST	ECOD2##		;NO--BOMB USER WITH ERROR 2
POKE0:	MOVE	T2,T1
	PUSHJ	P,PPPADR	;GET VIRTUAL ADR IF ARG IS PHYSICAL ADR
	  JRST	ECOD2##
	MOVE	P1,T2		;SAVE ADDRESS
	MOVE	P2,T2
	PUSHJ	P,GETWD1##	;GET USER'S IDEA OF OLD CONTENTS
	MOVE	T4,T1		;SAVE IT
	PUSHJ	P,GETWD1##	;GET NEW VALUE
	PUSHJ	P,POKADR	;COMPUTE ADDRESS
POKE1:	SYSPIF			;TO BE SAFE
	CAME	T4,(P1)		;COMPARE OLD VALUE
	JRST	POKE.1		;FAIL--BOMB USER
	MOVEM	T1,(P1)		;WIN--STORE
	SYSPIN			;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
IFN FTDAEM,<
	MOVE	T1,[.SWEPK,,.ERSWE] ;EVENT,,ERROR CODES FOR DAEMON
	HRRZ	U,P2		;SECOND WORD OF ERPTBK
	HLRZ	F,P2		;IS ADDRESS POKED
	PUSHJ	P,DAERPT##	;TELL DAEMON TO LOG IT
>
	JRST	CPOPJ1##	;SKIP RETURN

POKE.1:	SYSPIN			;TURN ON SYSTEM
	PJRST	ECOD1##		;RETURN CODE 1
>
IFE FTPOKE,<POKE==CPOPJ##>

;SUBROUTINE TO COMPUTE ADDRESS FOR POKE OR SNOOP

POKADR:	CAIL	P1,MONORG	;BELOW THE HIGH SEGMENT?
	CAML	P1,MONVFF##	;OR ABOVE THE HIGH SEGMENT?
	POPJ	P,		;YES, MUST BE MAPPED ONE-TO-ONE
	MOVE	T2,P1		;MONITOR VIRTUAL ADDRESS
	LSHC	T2,W2PLSH##-1	;PAGE NUMBER DIVIDED BY TWO
	TLNN	T3,400000	;EVEN OR ODD PAGE?
	TDOA	T2,[POINT 18,.EPPM##-.EPMP##,17] ;EVEN PAGE NUMBER
	TDO	T2,[POINT 18,.EPPM##-.EPMP##,35] ;ODD PAGE NUMBER
	ADD	T2,.CPTOS##	;RELOCATE FOR THIS CPU
	LDB	T3,T2		;GET CONTENTS OF EXEC MAP SLOT CORRESPONDING TO THE PAGE
IFN FTKL10&FTMP,<
	TRZE	T3,PM.CSH	;CACHED?
	PUSHJ	P,UNCACH##	;UNCACHE THE PAGE FOR ALL CPUS
>
	TRO	T3,PM.WRT	;ALLOW WRITING
	HRRM	T3,.UPMP+.MTEMP	;STORE IN A PER-PROCESS TEMPORARY SLOT
	MOVEI	T2,.TEMP/PAGSIZ##;VIRTUAL PAGE NUMBER TO USE IN PER-PROCESS MAPPED ADDRESS
	DPB	T2,[POINT 9,P1,26] ;MONITOR VIRTUAL ADDRESS FOR POKE/SNOOP
	CLRPGT	(0)		;CLEAR PAGING MEMORY SO NEW MAPPING IS USED
	POPJ	P,		;AND RETURN
;SUBROUTINE TO MAKE A PHYSICAL ADDRESS ADDRESSABLE IF PHYSICAL ONLY
; UUO OR UUO ARGUMENT IS .GT. 256K.
;
;CALL WITH (T2) = PHYSICAL ADDRESS
;RETURNS WITH (T2) = VIRTUAL ADDRESS WHICH MAPS TO PHYSICAL ADDRESS
IFN FTPEEKSPY!FTPOKE,<
PPPADR:	TLNN	T2,17		;22 BIT ADDRESS?
	SKIPGE	P1		; OR PHYSICAL ONLY UUO?
	SKIPA	T1,T2		;YES
	JRST	PPPAD1		;NO, T2 = VIRTUAL ADDRESS USER WANTS
	LSH	T1,W2PLSH##	;PAGE NUMBER
	TRO	T1,PM.ACC+PM.WRT ;ACCESS ALLOWED + WRITABLE (POKE)
	HRRM	T1,.UPMP+.MTEMP	;ADDRESSABLE VIA TEMP
	ANDI	T2,PG.BDY##	;COMPUTE VIRTUAL ADDRESS OF LOC
	IORI	T2,.TEMP
	CLRPGT	(0,.TEMP)
	JRST	CPOPJ1##
PPPAD1:	MAP	T1,(T2)
	PJRST	FLTCHK##
>
	SUBTTL	SNOOP. UUO - INSERT BREAK POINTS IN THE MONITOR

;UUO ALLOWS A PROGRAM TO INSERT BREAK POINTS IN THE MONITOR
; USEFUL FOR PERFORMANCE ANALYSIS, FAULT INSERTION, TRACE FUNCTIONS, ETC.
;CALLING SEQUENCE:
;	MOVE	AC,[FUNCTION,,ADDRESS]
;	SNOOP.	AC,
;	  ERROR RETURN
;	NORMAL RETURN

SNOOP:	HLRZ	U,T1		;FUNCTION
	CAILE	U,NLSNOP	;IS IT LEGAL?
	JRST	SNPIAL		;NO, ILLEGAL ARGUMENT LIST
	PUSHJ	P,PRUSET	;T1 = LENGTH OF THE ARGUMENT LIST
	  JRST	SNPNPV		;NOT PRIVILEGED
	JRST	@SNPDSP(U)	;DISPATCH

SNPDSP:	SNPDBP			;(0) DEFINE BREAK POINTS
	SNPIBP			;(1) INSERT BREAK POINTS
	SNPRBP			;(2) REMOVE BREAK POINTS
	SNPUBP			;(3) UNDEFINE BREAK POINTS
NLSNOP==.-SNPDSP-1

;ERROR RETURNS FROM THE SNOOP UUO
SOIAL%==1
SONPV%==2
SOSAS%==3
SOMBX%==4
SOIBI%==5
SONFS%==6
SOADC%==7
SOINL%==10
SOWMS%==11

	ERCODE	SNPIAL,SOIAL%	;ILLEGAL ARGUMENT LIST
	ERCODE	SNPNPV,SONPV%	;NOT PRIVILEGED
	ERCODE	SNPSAS,SOSAS%	;SOMEONE IS ALREADY SNOOP.'ING
	ERCODE	SNPMBX,SOMBX%	;MAXIMUM NUMBER OF BREAKPOINTS EXCEEDED
	ERCODE	SNPIBI,SOIBI%	;FUNCTION ILLEGAL BECAUSE BREAKPOINTS ALREADY INSERTED
	ERCODE	SNPNFS,SONFS%	;NO MONITOR FREE CORE
	ERCODE	SNPADC,SOADC%	;ADDRESS CHECK
	ERCODE	SNPINL,SOINL%	;ILLEGAL FUNCTION IF NOT LOCKED
	ERCODE	SNPWMS,SOWMS%	;WRONG MONITOR CHECKSUM

;OFFSETS IN BREAKPOINT CODE BLOCK
SNPAOS==0			;AOS .+SNPCNT
SNPUSI==1			;USER SUPPLIED INSTRUCTION
SNPSER==2			;SOSA AT ERROR RETURN OF USER INSTRUCTION
SNPSNR==3			;SOSA AT NORMAL RETURN OF USER INSTRUCTION
SNPRMI==4			;REPLACED MONITOR INSTRUCTION
SNPJER==5			;JRST AT ERROR RETURN OF MONITOR INSTRUCTION
SNPJNR==6			;JRST AT NORMAAL RETURN OF MONITOR INSTRUCTION
SNPCNT==7			;CURRENT USE COUNT FOR THIS BREAKPOINT
SNPBCB==^D8			;SIZE OF BREAKPOINT CODE BLOCK
;HERE TO DEFINE BREAK POINTS (FUNCTION 0)

SNPDBP:	SYSPIF			;INTERLOCK SYSTEM
	SKIPE	SYSBPJ##	;SNOOP FACILITY ALREADY IN USE?
	CAMN	J,SYSBPJ##	;YES, IN USE BY THIS JOB?
	CAIA			;FREE OR IN USE BY THIS JOB, ALL IS WELL
	JRST	[SYSPIN		;UNLOCK
		JRST SNPSAS]	;SOMEONE ALREADY SNOOPING
	MOVEM	J,SYSBPJ##	;RESERVE THE SNOOP FACILITY FOR THIS JOB
	SYSPIN			;UNLOCK THE SYSTEM AND PROCEDE
	JUMPLE	T1,[PUSHJ P,RTNBPS ;NEGATIVE OR ZERO ARGUMENT LIST LENGTH IS ILLEGAL
		JRST SNPIAL]	;RETURN BREAK POINTS AND GIVE ERROR RETURN
	TRNE	T1,1		;MUST BE ODD
	CAIGE	T1,3		;AND GE 3
	JRST	[PUSHJ P,RTNBPS	;RETURN BREAK POINTS
		JRST SNPIAL]	;AND GIVE ILLEGAL ARGUMENT LIST ERROR RETURN
	HRRZ	T2,SYSBPP##	;NUMBER OF BREAK POINTS DEFINED SO FAR
	LSH	T2,1		;TIMES 2 WORDS PER ARGUMENT
	MOVNS	T2		;MINUS TWO TIMES THE NUMBER OF B.P.S ALREADY DEFINED
	CAILE	T1,2*MAXNBP##+1(T2)
	JRST	SNPMBX		;MAXIMUM NUMBER OF BREAK POINTS EXCEEDED
	PUSHJ	P,CKBINS	;SEE IF BREAK POINTS HAVE BEEN INSERTED
	  JRST	SNPIBI		;THEY HAVE, ILLEGAL FUNCTION IF BREAK POINTS ARE INSERTED
	PUSHJ	P,SAVE2##	;SAVE P1-P2
	SOS	P1,T1		;CHECKSUM WORD
	LSH	P1,-1		;TWO WORDS PER BREAK POINT
	PUSHJ	P,GETWR1##	;GET THE MONITOR CHECKSUM
	  JRST	[PUSHJ P,RTNBPS	;ADDRESS CHECK, RETURN BREAK POINTS
		JRST SNPADC]	;AND GIVE AN ERROR RETURN
	CAME	T1,MSTCKS##	;USER SUPPLIED CHECKSUM AGREE WITH  MONITOR COMPUTED ONE?
	JRST	[PUSHJ P,RTNBPS	;NO, RETURN BREAK POINTS
		JRST SNPWMS]	;AND GIVE WRONG MONITOR CHECKSUM RETURN
	HRRZ	T1,SYSBPP##	;CURRENT NUMBER OF BREAK POINTS DEFINED
	JUMPN	T1,[HLRZ P2,SYSBPP##  ;POINTER TO THE BREAK POINT TABLE
		ADDI P2,(T1)	;NEXT FREE SLOT IN BREAK POINT TABLE
		JRST SNPDB1]	;GO DEFINE NEXT BREAK POINT
	MOVEI	T2,MAXNBP##	;NO BREAK POINTS DEFINED YET, ALLOCATE A BREAK POINT TABLE
	PUSHJ	P,GTFWDC##	;GET SPACE
	  JRST	SNPNFS		;NO FUNNY SPACE AVAILABLE
	HRLZM	T1,SYSBPP##	;STORE THE ADDRESS OF THE TABLE, NO B.P.S DEFINED YET
	MOVE	P2,T1		;WORKING INDEX INTO THE TABLE
;HERE WITH P2 = POINTER TO THE BREAK POINT TABLE
;A BREAK POINT CODE BLOCK (BPCB) LOOKS LIKE THIS
;BPCB+SNPAOS	AOS	BPCB+SNPCNT	;EXECUTING BREAK POINT
;BPCB+SNPUSI	USER SUPPLIED BREAK POINT INSTRUCTION
;BPCB+SNPSER	SOSA	BPCB+SNPCNT	;DONE EXECUTION OF BP, NON-SKIP
;BPCB+SNPSNR	SOSA	BPCB+SNPCNT	;DONE EXECUTION OF BP, SKIP
;BPCB+SNPRMI	REPLACED MONITOR INSTRUCTION, 0 IF BPS NOT INSERTED
;BPCB+SNPJER	JRST	BP+1
;BPCB+SNPJNR	JRST	BP+2
;BPCB+SNPCNT	NON-ZERO IF THE BREAK POINT IS CURRENTLY BEING EXECUTED

SNPDB1:	PUSHJ	P,GETWR1##	;MONITOR ADDRESS WHERE BREAK POINT IS TO BE INSERTED
	  JRST	[PUSHJ P,RTNBPS	;;ADDRESS CHECK, RETURN BREAK POINTS
		JRST SNPADC]	;AND GIVE ADDRESS CHECK ERROR RETURN
	TLZ	T1,-1		;CLEAR LH JUNK
	CAIG	T1,17		;TRYING TO INSERT IT IN AN AC?
	JRST	[PUSHJ P,RTNBPS ;YES, RETURN BREAKPOINTS
		 JRST SNPIAL]	;AND GIVE ILL ARG LIST RETURN
	HRLM	T1,(P2)		;STORE MONITOR ADDRESS OF THE BREAK POINT
	MOVEI	T2,SNPBCB	;EIGHT WORDS ARE REQUIRED FOR THE BREAK POINT CODE
	PUSHJ	P,GETWDS##	;GET THE SPACE
	  JRST	[PUSHJ P,RTNBPS	;NOT AVAILABLE, RETURN BREAK POINTS
		JRST SNPNFS]	;AND GIVE NO FREE SPACE ERROR RETURN
	HRRM	T1,(P2)		;STORE ADDRESS OF THE CODE BLOCK ASSOCIATED WITH THIS B.P.
	AOS	SYSBPP##	;ONE MORE BREAK POINT DEFINED
	PUSHJ	P,GETWR1##	;BREAK POINT INSTRUCTION
	  JRST	[PUSHJ P,RTNBPS	;ADDRESS CHECK, RETURN BREAK POINTS
		JRST SNPADC]	;AND GIVE ADDRESS CHECK ERROR RETURN
	HRRZ	T2,(P2)		;RESTORE ADDRESS OF THE CODE BLOCK
	MOVSI	T3,(AOS)	;AOS
	HRRI	T3,SNPCNT(T2)	; BP CODE + SNPCNT
	MOVEM	T3,SNPAOS(T2)	;STORE THAT TO BE EXECUTED BEFORE BP INSTRUCTION
	SETZM	(T3)		;BREAK POINT ISN'T IN EXECUTION
	MOVEM	T1,SNPUSI(T2)	;STORE THE USER SUPPLIED BREAK POINT INSTRUCTION
	SETZM	SNPRMI(T2)		;INDICATE THAT BREAK POINT HAS NOT BEEN INSERTED YET
	HRLI	T3,(SOSA)	;SOSA BP CODE + SNPCNT
	MOVEM	T3,SNPSER(T2)	;BREAK POINT INSTRUCTION DIDN'T SKIP
	MOVEM	T3,SNPSNR(T2)	;BREAK POINT INSTRUCTION SKIPPED
	MOVSI	T1,(JRST)	;UNCONDITIONAL JUMP
	HLRZ	T3,(P2)		;MONITOR ADDRESS OF THE BREAK POINT
	ADDI	T1,1(T3)	;BREAK POINT ADDRESS + 1
	MOVEM	T1,SNPJER(T2)	;JRST BP+1
	ADDI	T1,1		;BREAK POINT ADDRESS + 2
	MOVEM	T1,SNPJNR(T2)	;JRST BP+2
IFN FTKL10&FTMP,<
	PUSH	P,P1		;SAVE COUNT
	HLRZ	P1,(P2)		;EXEC VIRTUAL ADDRESS OF THE B.P.
	PUSHJ	P,POKADR	;MAKE SURE THAT THE PAGE IS UNCACHED IN ALL MAPS
	POP	P,P1		;RESTORE COUNT
>
	AOS	P2		;NEXT SLOT IN THE BREAK POINT TABLE
	SOJG	P1,SNPDB1	;LOOP OVER THE USER'S ENTIRE ARGUMENT LIST
	JRST	CPOPJ1##	;AND GIVE GOOD RETURN
;HERE TO INSERT BREAK POINTS (FUNCTION 1)

SNPIBP:	PUSHJ	P,LOKEVC##	;JOB MUST BE LOCKED CONTIGUOUSLY IN EVM
	  JRST	SNPINL		;ITS NOT, ILLEGAL IF NOT LOCKED ERROR RETURN
	CAME	J,SYSBPJ##	;IS THIS JOB THE CURRENT OWNER OF THE SNOOP FACILITY?
	JRST	SNPSAS		;NO, SOMEONE ELSE IS ALREADY  SNOOPING
	PUSHJ	P,CKBINS	;HAVE BREAK POINTS ALREADY BEEN INSERTED?
	  JRST	SNPIBI		;YES, ILLEGAL FUNCTION IF BREAK POINTS ARE INSERTED
IFN FTDAEM,<
	SETZ	F,		;F=0, U=FUNCTION
	MOVE	T1,[.SWESN,,.ERSWE] ;EVENT,, SOFTWARE EVENT REPORT
	PUSHJ	P,DAERPT##	;GET IT RECORDED IN THE ERROR FILE
>
	PUSHJ	P,SAVE4##	;SAVE WORKING ACS
	HRRZ	P2,SYSBPP##	;NUMBER OF BREAK POINTS WHICH HAVE BEEN DEFINED
	HLRZ	P3,SYSBPP##	;ADDRESS OF THE BREAK POINT TABLE
	MOVSI	P4,(JRST)	;BREAK POINT INSTRUCTION IS A JRST TO THE BREAK POINT CODE
	SYSPIF			;LOCK SYSTEM
SNPIB1:	MOVS	P1,(P3)		;ADDRESS OF THE BREAK POINT
	MOVE	T1,(P1)		;MONITOR INSTRUCTION
	MOVSS	P1		;ADDRESS OF THE BREAK POINT CODE
	HRRI	P4,(P1)		;JRST TO THE BREAK POINT CODE
	MOVEM	T1,SNPRMI(P1)	;STORE MONITOR INSTRUCTION IN BREAK POINT CODE
	HLRZS	P1		;VIRTUAL ADDRESS OF THE BREAK POINT
	PUSHJ	P,POKADR	;MAKE IT WRITABLE
	MOVEM	P4,(P1)		;STORE JRST TO BREAK POINT CODE AT THE BREAK POINT
	AOS	P3		;NEXT ENTRY IN THE BREAK POINT TABLE
	SOJG	P2,SNPIB1	;INSERT ALL OF THE BREAK POINTS
	SYSPIN			;NOW, UNLOCK THE SYSTEM
	JRST	CPOPJ1##	;AND GIVE THE USER THE GOOD RETURN
;HERE TO REMOVE BREAK POINTS (FUNCTION 2)

SNPRBP:	CAME	J,SYSBPJ##	;THIS JOB OWN THE BREAK POINT FACILITY
	JRST	SNPSAS		;NO, SOMEONE ELSE IS SNOOPING
REMBPS:	PUSHJ	P,SAVE4##	;SAVE WORKING ACS
	HRRZ	P2,SYSBPP##	;NUMBER OF BREAK POINTS DEFINED
	HLRZ	P3,SYSBPP##	;ADDRESS OF THE BREAK POINT TABLE
	SYSPIF			;NO INTERRUPTIONS
REMBP1:	MOVE	P1,(P3)		;ADDRESS OF BREAK POINT CODE BLOCK
	MOVE	P4,SNPRMI(P1)	;ORIGINAL MONITOR INSTRUCTION
	HLRZS	P1		;MONITOR ADDRESS OF THE BREAK POINT
	PUSHJ	P,POKADR	;MAKE BREAK POINT LOCATION WRITABLE
	MOVEM	P4,(P1)		;STORE ORGINAL MONITOR INSTRUCTION BACK AT B.P. ADDRESS
	MOVE	P1,(P3)		;ADDRESS OF THE BREAK POINT CODE BLOCK
IFE FTMP,<
	SETZM	SNPRMI(P1)	;INDICATE THAT THE BREAK POINT IS NO LONGER INSERTED
>
	AOS	P3		;NEXT ENTRY IN THE BREAK POINT TABLE
	SOJG	P2,REMBP1	;REMOVE ALL OF THE BREAK POINTS
	SYSPIN			;ALLOW INTERRUPTS

;NOW LOOP OVER ALL BREAK POINTS MAKING SURE THEY AREN'T
; CURRENTLY IN EXECUTION ON SOME OTHER CPU BEFORE
; ACTUALLY INDICATING BREAK POINT HAS BEEN REMOVED
; IF SOME CPU IS EXECUTING THE BREAK POINT, WAIT UNTIL IT'S DONE

IFN FTMP,<
	HRRZ	P2,SYSBPP##	;NUMBER OF BREAK POINTS DEFINED
	HLRZ	P3,SYSBPP##	;ADDRESS OF BREAK POINT TABLE
REMBP2:	HRRZ	P1,(P3)		;ADDRESS OF BREAK POINT CODE BLOCK
REMBP3:	SKIPN	SNPCNT(P1)	;BREAK POINT CURRENTLY BEING EXECUTED?
	JRST	REMBP4		;NO, REMOVE IT
	MOVEI	T1,0		;YES, SLEEP FOR A TIC
	PUSHJ	P,SLEEPF	;ZZZZZZ
	JRST	REMBP3		;CHECK AGAIN
REMBP4:	SETZM	SNPRMI(P1)	;REMOVE THE BREAK POINT
	AOS	P3		;NEXT ENTRY IN BREAK POINT TABLE
	SOJG	P2,REMBP2	;LOOP OVER ALL BREAK POINTS
>
	JRST	CPOPJ1##	;AND GIVE THE USER THE OK RETURN
;HERE TO UNDEFINE BREAK POINTS (FUNCTION 3)

SNPUBP:	CAME	J,SYSBPJ##	;CURRENT JOB OWN THE SNOOP FACILITY?
	JRST	SNPSAS		;NO, SOMEONE ELSE IS ALREADY SNOOPING
	PUSHJ	P,CKBINS	;ARE BREAK POINTS INSERTED?
	  JRST	SNPIBI		;YES, ILLEGAL IF BREAK POINTS ARE INSERTED
	AOS	(P)		;SET FOR SKIP RETURN
;	PJRST	RTNBPS

;MISC. SUBROUTINES

RTNBPS:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	HRRZ	P1,SYSBPP##	;NUMBER OF DEFINED BREAK POINTS
	HLRZ	P2,SYSBPP##	;ADDRESS OF THE BREAK POINT TABLE
	JUMPE	P1,RTNBP2	;JUMP IF NO BREAK POINTS CURRENTLY DEFINED
RTNBP1:	MOVEI	T1,SNPBCB	;EIGHT WORDS PER BREAK POINT CODE BLOCK
	HRRZ	T2,(P2)		;ADDRESS OF THIS BREAK POINT CODE BLOCK
	PUSHJ	P,GIVWDS##	;RETURN THE MONITOR FREE CORE
	AOS	P2		;NEXT ENTRY IN THE BREAK POINT TABLE
	SOJG	P1,RTNBP1	;LOOP OVER THE ENTIRE BREAK POINT TABLE
RTNBP2:	MOVEI	T1,MAXNBP##	;LENGTH OF THE BREAK POINT TABLE
	HLRZ	T2,SYSBPP##	;ADDRESS OF THE BREAK POINT TABLE
	SKIPE	T2		;IF A TABLE HAS BEEN ALLOCATED,
	PUSHJ	P,GVFWDS##	; RETURN THE SPACE
	SETZM	SYSBPJ##	;NO LONGER ANYONE SNOOPING
	SETZM	SYSBPP##	;AND NO BREAK POINT TABLE IS ALLOCATED
	POPJ	P,		;RETURN

CKBINS:	HRRZ	T2,SYSBPP##	;NUMBER OF BREAK POINTS
	JUMPE	T2,CPOPJ1##	;BREAK POINTS AREN'T INSERTED IF NONE ARE DEFINED
	HLRZ	T2,SYSBPP##	;ADDRESS OF THE BREAK POINT TABLE
	HRRZ	T2,(T2)		;ADDRESS OF BREAK POINT CODE BLOCK FOR FIRST BREAK POINT
	SKIPN	SNPRMI(T2)	;IF NON-ZERO, BREAK POINTS HAVE BEEN INSERTED
	AOS	(P)		;ZERO, BREAK POINT IS DEFINED BUT NOT INSERTED
	POPJ	P,		;GIVE INSERTED OR NOT INSERTED RETURN

SNPRST:	CAME	J,SYSBPJ##	;DOES JOB DOING THE RESET OWN THE SNOOP FACILITY?
	POPJ	P,		;NO, NOTHING TO DO
	PUSHJ	P,CKBINS	;YES, ARE THE BREAK POINTS INSERTED?
	  PUSHJ	P,REMBPS	;YES, REMOVE THEN
	  JFCL			;FOR SKIPS
	PJRST	RTNBPS		;BREAK POINTS ARE REMOVED, NOW UNDEFINE THEM
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
	CAILE	T4,PRFMAX	;IS THE FUNCTION DEFINED?
	  JRST	PREFNI		; NO, GIVE HIM UNIMPLEMENTED ERROR
	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 PMRSET,PMRSTR,PMRRED,PMRSTP,PMRREL
IFN FTRSP,<
	EXTERN PMRBPF,PMRBPN
>;END IFN FTRSP
IFE FTRSP,<
	PMRBPF==PREFNI
	PMRBPN==PREFNI
>;END IFE FTRSP
>;END IFN FTKL10

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


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

	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	DIAG. UUO


IFN FTKS10,<
DIACLR==:CPOPJ##
DIAUUO==CPOPJ##			;NO DIAG. UUO ON THE KS10
>
IFE FTKS10,<
IFE FTDHIA,<
DIAUUO==CPOPJ##			;NO DIAG. UUO
>
IFN FTDHIA,<
REPEAT 0,<
;FUNCTIONS DEFINED IN FILIO AND TAPUUO:
1	ASSIGN SINGLE UNIT
2	ASSIGN ALL UNITS ON A CHAN/KONTROLLER
3	RELEASE CHANNEL/KONTROLLER AND ALL UNITS
4	SPECIFY CHANNEL PROGRAM
5	RELEASE CHANNEL PROGRAM
6	GET CHANNEL STATUS
7	GET KONTROLLER AND UNIT NUMBERS

FUNCTIONS DEFINED IN UUOCON
10	READ CSB
11	READ DSB
FUNCTIONS DEFINED IN MOSSER
100	GET MEMORY
101	GIVE MEMORY
>

DIAUUO:	PUSH	P,T1
	HRR	M,T1		;ADR OF BLOCK
	PUSHJ	P,GETWDU##	;GET ARG
	CAIN	T1,7		;WANT KON/UNIT NUMBER?
	JRST	DIAKUN		;YES, TELL HIM
	CAIE	T1,10		;WANT TO READ CSB
	CAIN	T1,11		; OR DSB ?
	JRST	DIAXSB		;YES, DO SO
;STILL IN FTDHIA CONDITIONAL
;IF GOING TO DO IO HE'D BETTER BE ALL IN CORE
	SKIPE	.UPMP+.UPVRT
	JRST	[POP	P,(P)
		 JRST	DIAVRT]

	SETZ	T1,		;SAY WE WANT USER-IOT
	PUSHJ	P,STOTAC##	;TRPSET CALLS GETTAC
	PUSHJ	P,TRPSTU	;CHECK PRIVS, SET USRIOT
	  JRST	[POP P,(P)	;NO PRIVS, LOSE
		JRST DIANPV]
	POP	P,T1		;OK, RESTORE ARGUMENT
	PUSHJ	P,STOTAC##	;TRPSET STORES 0 IN THE AC
	HLRE	T2,T1		;NUMBER OF ARGUMENTS
	JUMPGE	T2,WRONGN	;ILLEGAL N
	PUSHJ	P,SAVE4##
	MOVN	P1,T2		;P1=NUMBER OF ARGS
	HRR	M,T1		;LOC OF ARG BLOCK
	PUSHJ	P,GETWDU##	;GET FUNCTION
	CAILE	T1,MXDIAG##	;LEGAL?
IFE FTKL10,<
	JRST	BADFNC		;ILLEGAL FNCTION
>
IFN FTKL10,<
IFE FTMOS,<
	JRST	BADFNC		;ILLEGAL FNCN
>
IFN FTMOS,<
	JRST	[CAIN T1,100	;GET MEMORY?
		 JRST DIAGTM##	;YES
		 CAIN T1,101	;GIVE MEMORY?
		 JRST DIAGVM##	;YES
		 JRST BADFNC]	;ILLEGAL FUNCTION
>>
	CAIGE	P1,2		;LEGAL?
	JRST	WRONGN		;ILLEGAL N
	MOVE	P2,T1		;P2=FUNCTION CODE
	PUSHJ	P,GETWD1##	;GET KON/UNIT WORD
	LDB	T2,[POINT 7,T1,6] ;CONTROLLER NUMBER
	HLRZ	P3,SYSKON##	;GET FIRST DISK KDB
;STILL IN FTDHIA CONDITIONAL
DIADRS:
IFN FTMP,<
	MOVE	T3,P3
	LDB	T3,KOZCPU##	;RIGHT CPU?
	CAME	T3,.CPCPN##
	JRST	DIADR1		;NO, KEEP LOOKING
>
	MOVE	T3,KONREG##(P3)
	ADDI	T3,KONEBK##(P3)	;POINT AT FIRST IO WORD IN KDB
	LDB	T3,[POINT 7,(T3),9]	;KON NUM FROM KDB
	CAIN	T3,(T2)		;MATCH?
	JRST	DIAUNI		;YES, WE HAVE KON
DIADR1:	HLRZ	P3,KONNXT##(P3)	;NO, STEP TO NEXT
	JUMPN	P3,DIADRS	;AND TEST IT
	MOVEI	W,MT0KDB##	;NOT A DISK, TRY MAGTAPES
DIADR2:	LDB	T4,[POINT 7,TKBCSO##(W),9]
IFN FTMP,<
	LDB	T3,TKYCPU##	;CPU CONTROLLER LIVES ON
	CAMN	T3,.CPCPN##	;IS IT US?
>
	CAIE	T4,(T2)		;YES, RIGHT CONTROLLER?
	JRST	DIADR3		;NO, TRY NEXT KDB
	LDB	P3,[POINT 3,T1,29] ;YES, GET UNIT NUMBER
	ADDI	P3,TKBUDB##(W)	;POINT TO RIGHT UDB
	SKIPN	U,(P3)		;IS THERE SUCH A UNIT?
	JRST	ILLUNI		;NO, YOU LOSE
	HRROS	U		;YES, INDICATE IT'S A TAPE
	PUSHJ	P,FNDPDS##	;RESET W
	JRST	DIADSP		;AND CALL TAPUUO
DIADR3:	HRRZ	W,TKBKDB##(W)	;STEP TO NEXT TAPE KDB
	JUMPN	W,DIADR2	;TEST IT
	JRST	ILLKON		;ILLEGAL CONTROLLER NUMBER
DIAUNI:	LDB	T1,[POINT 3,T1,29] ;UNIT
	MOVE	T3,P3	
	HRLI	T3,-10		;AOBJN POINTER TO UNITS
DIAUN1:	HRRZ	U,(T3)
	LDB	T2,UNYPUN##	;UNIT FROM UDB
	CAMN	T1,T2		;RIGHT ONE?
	JRST	DIAUN2		;YES, SEE IF SAME KON
	AOBJN	T3,DIAUN1	;NO, TRY NEXT
	JRST	ILLUNI		;NO MATCH, YOU LOSE
DIAUN2:	HRRZ	T1,UNIKON##(U)	;ON SAME KONTROLLER?
	CAIE	T1,(P3)
	JRST	ILLUNI		;ILLEGAL UNIT
	JRST	DIADSP		;YES, DO IT

;STILL IN FTDHIA CONDITIONAL
;HERE TO GET KONTROLLER/UNIT
DIAKUN:	POP	P,(P)		;REMOVE SAVED T1
	PUSHJ	P,GETWD1##	;GET DEVICE NAME
	PUSHJ	P,DEVSRG	;FIND IT
IFE FTDUAL,<
	  JRST	ILLUNI		;NO SUCH UNIT
>
IFN FTDUAL,<
	  JRST	DIAALT##
>
	MOVEI	P2,7		;SET UP FUNCTION
	MOVE	T2,DEVMOD(F)
	TLNE	T2,DVMTA	;IS IT A MAG TAPE?
	JRST	DSPMTA		;YES
	JRST	DSPDSK		;NO, DISK


;HERE FROM STOP1A ON ^C OR EXIT, HALT,...  ;OR FROM HNGDSK
DIACLR::PUSHJ	P,FNDPDB##	;FIND FDB
	  POPJ	P,		;THERE ISN'T ONE
	SKIPN	F,.PDDIA##(W)	;DIAG GOING?
	POPJ	P,		;NO
	PUSHJ	P,SAVE3##	;YES, SAVE SOME ACS
	HLL	U,F		;GET DISK/TAPE FLAG
	TDZA	P2,P2		;ENTRY 0 = ^C POINT

DIADSP:	MOVE	F,.PDDIA##(W)	;SET UP F
	SKIPL	U		;DISK?
DSPDSK:	SKIPA	T2,[DSKDIA##]	;YES
DSPMTA:	MOVEI	T2,MTADIA##	;NO
	PUSHJ	P,(T2)		;DISPATCH TO FILUUO OR TAPUUO
DIANUI::  SKIPA	T1,[XC.UIO]	;LOST - CLEAR USRIOT
	JRST	CPOPJ1##	;;WON - SKIP RETURN
	ANDCAM	T1,.JDAT+JOBPD1##
	MOVSI	T1,NSWP!NSHF	;JOB IS NOW MOVABLE
	LDB	T2,PJOBN##
	ANDCAM	T1,JBTSTS##(T2)
	POPJ	P,

;FINISH UP GET CHANNEL STATS
;ENTER WITH P1=NO OF ARGS, P2=LOC OF ICWA
DIAGCS::CAILE	P1,4		;ASKING FOR TOO MUCH?
	MOVEI	P1,4		;YES, MAX HE CAN GET
DIAGC1:	MOVE	T1,(P2)		;GET A WORD FROM LOW CORE
	PUSHJ	P,PUTWD1##	;TELL USER
	SOJLE	P1,CPOPJ1##	;DONE IF 0
	AOJA	P2,DIAGC1	;GET NEXT WORD

;STILL IN FTDHIA CONDITIONAL
;HERE FOR THE CODE COMMON TO BOTH READ CPU STATUS BLOCK AND READ
;DEVICE STATUS BLOCK
DIAXSB:	POP	P,(P)		;FLUSH SAVED T1
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVEI	P1,(T1)		;SAVE FUNCTION
	MOVSI	T1,JP.POK	;MUST HAVE POKE PRIVS OR
	PUSHJ	P,PRVBIT##	;BE [1,2] OR JACCT
	  SKIPA			;HE'S OK
	JRST	DIANPV		;NOT ENOUGH PRIVS
	PUSHJ	P,GETWD1##	;GET CPU NUMBER
	SKIPL	T1		;IF NEGATIVE
	CAIL	T1,CPUN##	;OR GREATER THAN THE NUMBER OF CPUS
	JRST	DIANSC		;IT'S ILLEGAL
	PUSHJ	P,ONCPUS##	;GET TO THAT CPU
	  JRST	DIACNR		;CPU NOT RUNNING
	PJRST	@.+1-10(P1)	;DO THE FUNCTION SPECIFIC STUFF IN COMMON
	EXP	DIACSB##	;(10) READ CPU STATUS BLOCK
	EXP	DIADSB##	;(11) READ DEVICE STATUS BLOCK


INTERN	WRONGN,DINEFC,DIABAL

ERCODE	DIANPV,1		;NOT ENOUGH PRIVS
ERCODE	WRONGN,2		;ILLEGAL NUMBER OF ARGS
ERCODE	ILLKON,3		;ILLEGAL CONTROLLER NUMBER
ERCODE	ILLUNI,4		;ILLEGAL UNIT NUMBER
ERCODE	DIUNAA,5		;SOME UNITS ALREADY ASSIGNED
ERCODE	UNNDMD,6		;UNIT NOT IN DIAG MODE
ERCODE	UNAAJB,7		;UNIT ASS'D TO ANOTHER JOB
ERCODE	DINEFC,10		;NOT ENOUGH FREE CORE
ERCODE	NOASUN,11		;NO ASSIGNED UNITS
ERCODE	IOWCPB,12		;IOWD CROSSES PAGE BOUNDARY
ERCODE	BADFNC,13
ERCODE	DIAVRT,14
ERCODE	DIANSC,15		;NO SUCH CPU
ERCODE	DIACNR,16		;CPU NOT RUNNING
ERCODE	DIABAL,17		;SOME ARGUMENT IS ILLEGAL
>		;END FTDHIA
>;END IFE FTKS10
	SUBTTL	RECON. UUO - SYSTEM LOGICAL RECONFIGURATION UUO

;THIS UUO PROVIDES THE SUPPORT NECESSARY FOR A USER PROGRAM TO LOGICALLY
; RECONFIGURE THE SYSTEM AND SUPPEND ITS OPERATION TEMPORARLY SO THAT
; OPERATIONS CAN PHYSICALLY RECONFIGURE AND THEN RESUME
;CALLING SEQUENCE:
;	MOVE	AC,[FUNCTION,,ADDRESS]
;	RECON.	AC,
;	  ERROR RETURN
;	NORMAL RETURN

RECON:	HLRZ	U,T1		;FUNCTION
	CAILE	U,NLRECN	;IS IT LEGAL?
	JRST	RCNIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,PRUSET	;GET LENGTH OF ARGUMENT LIST AND CHECK PRIVILEGES
	  JRST	RCNNPV		;NOT PRIVILEGED
	JRST	@RCNDSP(U)	;DISPATCH

RCNDSP:	RCNROM			;(0) RUN ONLY ME
	RCNSPN			;(1) SUPPEND SYSTEM
NLRECN==.-RCNDSP-1

;ERROR RETURNS
RCIAL%==1
RCNPV%==2
RCNTS%==3
RCNIJ%==4
RCNCD%==5
RCNAC%==6

	ERCODE	RCNIAL,RCIAL%	;ILLEGAL ARGUMENT LIST
	ERCODE	RCNNPV,RCNPV%	;NOT PRIVILEGED
	ERCODE	RCNTAS,RCNTS%	;TIME-SHARING ALREADY STOPPED ON SOME CPU
	ERCODE	RCNIJN,RCNIJ%	;ILLEGAL JOB NUMBER
	ERCODE	RCNCND,RCNCD%	;SYSTEM CANNOT BE SNAP SHOTTED
	ERCODE	RCNADC,RCNAC%	;ADDRESS CHECK
;HERE TO MAKE ONLY ONE JOB RUNNABLE ON THE SYSTEM (FUNCTION 0)

RCNROM:	CAIE	T1,2		;MUST BE EXACTLY ONE ARGUMENT
	JRST	RCNIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,GETWR1##	;GET JOB NUMBER
	  JRST	RCNADC		;ADDRESS CHECK
	CAME	T1,[-1]		;DEFAULT TO THE CURRENT JOB?
	MOVE	J,T1		;NO, USE USER SUPPLIED JOB NUMBER
	PUSHJ	P,FNDPDB##	;VALIDATE JOB NUMBER
	  JRST	RCNIJN		;ILLEGAL JOB NUMBER
	MOVEI	T1,[CAME T2,.CPSTS##-.CPCDB##(P1)
		    SKIPN .CPSTS##-.CPCDB##(P1)
		    CAIA
		    SETO T2,
		    POPJ P,]
	MOVE	T2,.CPJOB##	;JOB NUMBER OF REQUESTOR
	PUSHJ	P,CPUAPP##	;HAS TIME-SHARING BEEN STOPPED ON ANY CPU?
	JUMPL	T2,RCNTAS	;TIME-SHARING HAS ALREADY BEEN STOPPED ON SOME CPU
	MOVEI	T1,[MOVEM J,.CPSTS##-.CPCDB##(P1)
		    POPJ P,]
	PUSHJ	P,CPUAPP##	;MAKE THIS JOB BE THE ONLY RUNNABLE JOB ON THE SYSTEM
	JRST	CPOPJ1##	;TELL THE USER THAT HE DID GOOD

;HERE TO SUSPEND THE SYSTEM (FUNCTION 1)

RCNSPN:	MOVEI	T1,[ASCIZ /SEND ALL Suspending system operation
/]
	PUSHJ	P,[PUSHJ P,FRCSET## ;SETUP TO SEND FROM [SYSTEM]
		   PJRST CONMES##]  ;TELL THE WORLD
RCNSP1:	MOVEI	T1,^D10		;WAIT UNTIL EVERYONE SEES IT
	PUSHJ	P,SLEEP
	SKIPE	SNDCTR##
	JRST	RCNSP1
	MOVEI	T1,SYSRST##	;RESTART ADDRESS
	HRRM	T1,.JBSA##	;STORE THAT FOR REBOOT
	MOVSI	T1,60000	;SUSPEND THIS CPU AND SNAP SHOT BITS
	IORM	T1,.CPRUN##	;MAKE US GO AWAY AS SOON AS THE NULL JOB RUNS
	MOVEI	T1,^D10		;LET THINGS SETTLE DOWN
	PUSHJ	P,SLEEP		;ZZZZZZ
	MOVSI	T1,20000	;DUMP FAILED BIT
	TDNN	T1,.CPRUN##	;DID IT FAIL?
	JRST	RCNSP2		;SYSTEM WAS RESUMED, GIVE GOOD RETURN TO USER
	ANDCAM	T1,.CPRUN##	;YES, CANNOT SUSPEND THE SYSTEM
	JRST	RCNCND		;GIVE THE USER AN ERROR RETURN
RCNSP2:	PUSHJ	P,FRCSET##
	PUSHJ	P,INLMES##
	ASCIZ	/SEND ALL System resumed
/
	JRST	CPOPJ1##
	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)

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

REMAP=UREMAP##			;CORE1 MODULE IN SEGCON

	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,<
	DATAO	PI,T1		;SENT USER'S AC TO CONSOLE LIGHTS
>;END IFN 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 FTKI10,<
	DATAI	APR,T1		;GET 36 BIT SWITCHES
>
IFN FTKL10!FTKS10,<
	SETZ	T1,		;RETURN ZERO ON KL10
>
	JRST	STOTAC##	;GO STORE VALUE
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
	PUSHJ	P,NXDDB		;POINT AT NEXT DEVICE ON CHAIN
	  JUMPE	F,DVPHY4
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
	PUSHJ	P,NXDDB		;POINT AT NEXT DEVICE ON CHAIN
	  JUMPE	F,DVPHY4
	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##
	PUSHJ	P,NXDDB
	  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:	JUMPE	F,CPOPJ##
	MOVEI	T1,NOTTTL
	LDB	T2,PDVTYP##
NOTPT1:	CAIE	T2,@NOTTBL-1(T1)
	SOJG	T1,NOTPT1
	JUMPLE	T1,NOTPT3
NOTPT2:	PUSHJ	P,NXDDB		;POINT AT NEXT DEVICE ON CHAIN
	  JFCL
	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,.TYTSK/.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
	SUBTTL	DEVCHR AND DEVSIZ UUO'S

;RETURN DEVICE CHARACTERISTICS


IFN FTSPL, <
DVCH0:
	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:
>
	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,.CPJOB##	;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,.CPJOB##	;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
;RETURN DEVICE TYPE (AND OTHER PROPERTIES)
DVTYP:	AOS	(P)		;SKIP-RETURN SINCE UUO IS IMPLIEMENTED
	PUSH	P,T1		;SAVE DEVICE NAME
	PUSHJ	P,DVCHR		;GET DEVICE CHARACTERISTICS
	JUMPE	T1,T2POPJ##	;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
	POP	P,T2		;PUT DEVICE NAME IN T2
	PUSHJ	P,GNRCDV	;IS IT A GENERIC DEVICE?
	  TLO	T1,TY.GEN	;YES
	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

;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
	SETZI	T1,		;IF MODE IS ILLEGAL,
	CAIL	P1,SD		;TEST FOR DUMP MODE
	JRST	SIZRT1		;IT IS, RETURN AC=0
	MOVNI	T1,2
	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
SIZRT1:	AOS	-1(P)		;GIVE SKIP RETURN
SIZRET:	POP	P,M		;RESTORE LOC OF AC
	PJRST	STOTAC##	;STOTAC, THEN RETURN

;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
	PUSHJ	P,NXDDB		;POINT AT NEXT DEVICE ON CHAIN
	  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:	MOVSI	T1,JACCT
	TDNE	T1,JBTSTS##(J)	;LOGIN OR LOGOUT CUSP RUNNING ?
	JRST	GETPPL		;YES, SPECIAL PROJ,PROG 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 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


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

	SUBTTL	IONDX.  UUO
;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,SAVE1##	;SAVE P1
	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
;DESTROYS P1
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:	MOVEI	P1,0		;START AT CHANNEL ZERO
DSKUD1:	PUSHJ	P,NXTCH		;NEXT CHANNEL
	  JRST	ZPOPJ##		;NOT FOUND
	MOVE	T2,DEVNAM(T1)	;DEVICE NAME
	CAIE	T1,(F)		;DVCNSG FIND THIS DDB?
	CAMN	T2,NDXARG	;FIND A CHANNEL FOR THIS DDB?
	SOSA	T1,P1		;YES
	JRST	DSKUD1		;NO, KEEP LOOKING
	JRST	CPOPJ1##	;FOUND RETURN
	SUBTTL	SUBROUTINE TO FIND A DDB GIVEN ITS IO INDEX
;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,HIGHXC##	;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>
	SUBTTL	GTNTN./GTXTN. UUO'S FOR TTY NAMES

;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
	HRRZ	U,DDBLDB##(F)	;GET THE LDB
IFN FTNET,<
	MOVEI	T1,LDRREM##	;GET THE REMOTE BIT
	TDNN	T1,LDBDCH##(U)	;NETWORK TTY?
	JRST	GTNTN1		;NO, LOCAL TTY
	MOVE	T2,LDBREM##(U)	;GET THE WORD WITH "CONNECTED" BIT
	TLNN	T2,LRLCON##	;IS THIS TERMINAL CONNECTED
	JRST	ECOD2##		;TERMINAL NOT CONNECTED. TELL THE USER
	LDB	T2,LDPRNN##	;GET THE NUMBER OF TERMINAL'S NODE
	LDB	T1,LDPRLN##	;GET THE REMOTE LINE NUMBER
	HRLI	T1,(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 GIVEN 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
	MOVE	T3,LDBREM##(U)	;GET THE REMOTE STATUS BITS
	TLNN	T3,LRLCON##	;IS THIS TERMINAL "CONNECTED"
	JRST	GTXTN2		;TERMINAL IS NOT CONNECTED.
	LDB	T3,LDPRNN##	;GET THE NUMBER OF THE NODE THAT OWNS THE TTY
	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
	JUMPGE	M,STOTC1##	;EXIT THE UUO
	PJRST	CPOPJ1		;IF INTERNAL CALL, EXIT SKIP RETURN
	SUBTTL	MVBFH. UUO -- MOVE BUFFER HEADERS

;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
	PUSHJ	P,SETUF
	  JRST	ECOD1##		;ERROR -- BAD CHANNEL NUMBER
	HRLM	P1,.UPMP+.UPCTA	;SAVE CHAN
	LDB	T1,PUUOAC##	;GET AC #
	HRRI	M,1(T1)		;PLUS 1
	PUSHJ	P,GETWDU##	;PICK UP THE WORD
	MOVE	P1,T1
	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,P1		;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:	PUSHJ	P,JDAADR
	MOVEM	F,(T1)		;SAVE UPDATED FLAGS
	JRST	CPOPJ1##	;GOOD RETURN
	SUBTTL	DEVSTS, DEVLNM, DEVRST, AND DEVURS UUO'S

;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
IFN FTSPL,<
	SKIPE	T1,DEVCHR(F)	;ZERO IF SPOOLED DDB
>
	MOVE	T1,DEVSTS(F)	;GET DEVICE STATUS WORD
	JRST	STOTC1##	;USER, RETURNING T1 IN AC
;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
IFN FTMDA,<
	JRST	[SKIPN T2	;DEVICE OWNED BY ANYONE AT ALL?
		 CAME J,MDAJOB	;NO, IS THIS MDA?
		 JRST DEVLN3	;OWNED, OR NOT MDA, ERROR
		 JRST DEVLN0]	;LET MDA GET UNOWNED DEVICE
DEVLN0:
>;END IFN FTMDA
IFE FTMDA,<
	JRST	DEVLN3		;NO, RETURN -3
>;END IFE FTMDA
	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:	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
	MOVE	T1,DEVMOD(F)	;IF NOT ASSIGNED ...
	TRNE	T1,ASSCON!ASSPRG ;DON'T FIX LOGICAL NAME TABLE
	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##
;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	T2,DVDSK
	MOVSI	T1,DEPRAS	;GET RESTRICTED ASSIGNMENT BIT
IFN FTSPL,<
	SKIPE	DEVCHR(F)	;DON'T DO IT TO SPLTAB
>
	TDNE	T2,DEVMOD(F)	;DON'T UNRESTRICT DISKS
	POPJ	P,		;IF SPLTAB, GIVE ERROR RETURN
	ANDCAM	T1,DEVSTA(F)	;CLEAR THE BIT IN DDB
	PJRST	CPOPJ1##	;AND SKIP RETURN
	SUBTTL	SETDDT, WAIT AND GETLIN CALLI'S	; WAIT2 AND GETPPL


SETDDT:	MOVEM	T1,.JDAT+JOBDDT##	;SET BOTH USRDDT & JOBDDT IN JOB DATA AREA IN CASE
	MOVEM	T1,USRDDT##	; USER LOOKS AT JOBDDT BEFORE RESCHEDULING OCCURS

	POPJ	P,		;RETURN TO USER

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,PROG 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


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:
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
>
	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:	HRRZ	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
	PUSHJ	P,BRNGE##	;MAKE SURE ENTIRE DEVOAD BUFFER IS IN CORE

	TRZ	S,760000	;YES, CLEAR ERROR BITS
IFN FTMP,<
	PUSHJ	P,SETCPF##	;GET ON RIGHT CPU
>
	PUSH	P,M
	PUSHJ	P,CALOUT	;CRANK UP THE DEVICE
	POP	P,M
	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 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		;ADDRESS 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
	MOVE	J,.CPJOB##	;RESTORE REQUESTING JOB'S JOB NUMBER
	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 TOO LONG
ERCODE	ACTADC,2		;ADDRESS CHECK
ERCODE	ACTIAL,3		;ILLEGAL ARGUMENT LIST
ERCODE	ACTNSJ,4		;NO SUCH JOB
ERCODE	ACTNPV,5		;NOT PRIVILEGED
>;END IFN FTACCT
IFE FTACCT,<
ACCT==CPOPJ##			;NO ACCT UUO
>
	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



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?
	MOVE	T1,JBTPRV##(J)	;GET MY PRIVILEGE WORD
	MOVEM	T1,.PDCAP##(W)	; AND SAVE AS CAPABILITY WORD

	PUSHJ	P,SETLOG##	;SET JLOG, INCREMEN LOGNUM, BATNUM
	PUSHJ	P,QSRLGI##

	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,.JDAT+JOBPD1##	;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
	XWD	J,JBTPRV##	;JOB PRIVILEGE BITS



	XWD	W,.PDNM1##	;1ST HALF OF USER'S NAME
	XWD	W,.PDNM2##	;2ND HALF OF USER'S NAME

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
;LOGOUT UUO



LOGOUT:	PUSHJ	P,TTYFNU##
	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##

;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
	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,TTYDTC##	;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
	HRRZ	U,DDBLDB##(F)	;GET LDB ADDRESS FROM DDB LINK
	MOVSI	T1,600000	;FLAG BITS TO CLEAR
	ANDCAM	T1,0(P)		;ZAP!
	HLRZ	T1,0(P)		;GET LINE NUMBER REQUESTED
	CAIL	T1,TTPLEN##	;IS IT LEGAL?
	JRST	TPOPJ##		;NO. FAIL RETURN.
	MOVEI	T3,LDRDSR##
	MOVE	T2,LINTAB##(T1)	;"TO" TTY
	CAIG	T1,TCONLN##
	TDNE	T3,LDBDCH##(T2)	;ATTACHING TO LOCAL TTY?
	JRST	UATC1C		;NO, OK
	MOVE	T1,JBTPPN##(J)	;GET MY PPN
	CAME	T1,HELPPP##
	CAMN	T1,FSFPPN##	;OR A PRIV'D JOB?
	JRST	UATC1C		;OK
	JUMPE	U,TPOPJ##	;IF "FROM" TTY UNKNOWN PLAY IT SAFE
	MOVE	T3,LDBDCH##(U)
	TRNN	T3,LDRPTY##
	TRNE	T3,LDRDSR##
	JRST	TPOPJ		;CAN'T DO IT
UATC1C:	PUSHJ	P,PTYDTC##	;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.

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 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
GETTAB:	HLRZ	T2,T1		;GET USER SUPPLIED JOB NUMBER
	HRRE	T3,T1		;GET TABLE NUMBER IN T3
	CAIN	T3,.GTRNG
	HLRE	T3,T1
	CAIGE	T3,GTTBLN	;IS TABLE NUMBER LEGAL?
	CAMGE	T3,MINTBB	; (NEGATIVE NUMBERS LEGAL FOR CUSTOMER'S TABLES)
	POPJ	P,		;NO. ERROR RETURN, AC UNCHANGED
	HRRE	T4,T1
	CAIN	T3,GTSELF	;IS THIS A GETTAB IMMEDIATELY?
	MOVEI	T3,.GTSLF	;YES--GO HANDLE SPECIALLY
	LDB	T1,[POINT 3,NUMTAB(T3),11]	;GET CODE
	JUMPE	T1,CPOPJ##	;JUMP IF UNDEFINED
	HRRE	J,T2
	CAIE	T4,.GTRNG	;GO IF USER WANTS RANGE
	CAIE	T1,GT.RNG	;TABLE WITH A RANGE ?
	JRST	GETTB0		;NO
	LDB	T2,[POINT 9,NUMTAB(T3),8] ;GET INDEX INTO RANGE TABLE
	HLRE	T1,RNGTAB(T2)	;LOWER BOUND
	HRRE	T2,RNGTAB(T2)	;UPPER BOUND
	CAMG	J,T2		;TOO LARGE ?
	CAMGE	J,T1		;OR TOO SMALL ?
	POPJ	P,		;YES, ERROR RETURN
	JRST	GETTBX		;NO, GO GET THE ANSWER
GETTB0:	CAIE	T1,GT.RNG
	CAIN	T1,GT.ITM
	JRST	GETTB1
	CAIL	T2,-2
	MOVE	J,.CPJOB##
	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

;AT THIS POINT T3=TABLE NUMBER AND J=INDEX
GETTB1:	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
	CAIE	T1,GT.RNG
	CAIN	T1,GT.ITM	;SPECIAL TABLE
	LDB	T2,[POINT 9,NUMTAB(T3),8]	;GET MAXIMUM
	JUMPE	T2,RTZER1	;IF T2=0 NUMTAB IS WRONG
	CAIE	T4,.GTRNG
	JRST	GETTB2
	CAIE	T1,GT.RNG
	SKIPA	T1,T2
	MOVE	T1,RNGTAB(T2)
	JRST	STOTC1##
GETTB2:	SKIPL	J		;SKIP IF TOO SMALL
	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
;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
;	  "R" - DATA WITHIN A RANGE TABLE
; TBL   - ADDRESS OF TABLE (OR INDEX INTO PDB)
; MAX   - MAXIMUM FOR RANDOM TABLES SHIFTED LEFT 9 BITS
; OFS	- ADDRESS OF ENTRY IN RANGE CHECKING TABLE

DEFINE	GT(FT,TYPE,TBL,MAX,OFS),<
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>
>
IFIDN <TYPE>,<R>,<
IFE FT,< ZERO>
IFN FT,< EXP	<OFS>B8+<GT.RNG>B11+<J>B17+TBL>
>
>
DEFINE	RANGE(FT,FIRST,LAST,RNG,NAME),<
IFN FT,<
RNG'OFS==.-RNGTAB
IFNB <NAME>,<
NAME::	FIRST,,LAST
>
IFB <NAME>,<
	FIRST,,LAST
>
>>
ZERO:
RNGTAB:	0			;ENTRY 0 NOT USED
	RANGE	1,<GTBSTT-NUMTAB>,<GTTBLN-1>,NUM
	RANGE	1,<CTTWDT##-TTTWDT##>,<TTTWDN##-1-<TTTWDT##-CTTWDT##>>,TTT
	RANGE	FTIPCF,<.GTCSD##-.GTSID##>,SDTBLN##,SID
RNGTBL==.-RNGTAB
	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	1,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	1,J,JBTPRV##	;(006) PRIVILEGE BITS
	GT	1,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	1,I,SWPTBL##,SWPMXL##	;(013) SWAPPING DATA
	GT	1,J,JBTSGN##	;(014) HIGH SEG #
	GT	1,I,ODPTBL##,ODPMXL##	;(015) ONCE ONLY DISK PARAMETERS
	GT	1,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	1,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	1,P,.PDNM1##	;(031) USER NAME (0FIRST)
	GT	1,P,.PDNM2##	;(032) USER NAME (0LAST)
	GT	FTCNO,P,.PDCNO##	;(033) CHARGE NUMBER
	EXP	ZERO			;(034) UNUSED
	GT	FTWATC,J,JBTWCH##	;(035) WATCH BITS
	GT	FTSPL,J,JBTSPL##	;(036) SPOOL TABLE
	GT	FTRTTR!FTHPQ,J,JBTRTD##,ITMRTD## ;(037) REAL TIME
	GT	FTTLIM,J,JBTLIM##	;(040) CORE AND TIME LIMITS
	EXP	ZERO			;(041) UNUSED
	EXP	ZERO			;(042) UNUSED
	GT	1,I,COMTB2##,COMMX2##	;(043) SET COMMANDS
	GT	1,I,APRSTS##,LENSTS##	;(044) CRASH TABLE
	GT	1,I,ISCAN##,ISTMXL##	;(045) SWAP-IN LIST
	GT	1,I,OSCAN##,OSTMXL##	;(046) SWAP-OUT LIST
	GT	1,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	FTMP,J,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	1,I,SDVTBL##,SDVMXL##	;(072) ERSATZ DEVICE NAMES
	GT	FTRSP,I,.GTSCN##,SCNMXL##	;(073) SCNSER DATA
	GT	1,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
	GT	1,S,JBTUPM##	;(100)POINTER TO USER PAGE MAP
	GT	FTWATCH,I,WATTAB##,WTCMXL##	;(101) WATCH COMMANDS*
	GT	1,P,.PDCVL##	;(102) CURRENT VM LIMITS
	GT	1,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	1,P,.PDDVL##	;(110) POINTER TO DEVICE LOG NAME TABLE
	GT	1,P,.PDABS##	;(111) ADDRESS BREAK SETTING
	EXP	ZERO		;(112) RESERVED
	GT	1,I,.GTVM##,GTVMXL##	;(113) VM DATA
	GT	1,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
	EXP	ZERO				;(124) UNUSED
	EXP	ZERO				;(125) UNUSED
;CONTINUED ON NEXT PAGE
	GT	FTIPCF,R,.GTSID##,,SIDOFS	;(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	1,P,.PDSTR##		;(135) DEVICE PROGRAM WAS RUN FROM
	GT	1,P,.PDDIR##		;(136) DIRECTORY PROGRAM WAS RUN FROM
	GT	1,P,.PDNAM##		;(137) PROGRAM NAME
	GT	1,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	FTACCT&FTKCT,P,.PDVKC##	;(143)JOB'S VIRTUAL KCT
	GT	FTACCT,P,.PDUUC##	;(144)JOB'S UUO COUNT
	GT	1,P,.PDSFD##		;(145) FIRST SFD IN PATH PROGRAM WAS RUN FROM
	GT	1,P,.PDSFD##+1		;(146) SECOND
	GT	1,P,.PDSFD##+2		;(147) THIRD
	GT	1,P,.PDSFD##+3		;(150) FOURTH
	GT	1,P,.PDSFD##+4		;(151) FIFTH
	GT	FTWATCH,J,JBTPC##	;(152) JOB'S PC
	GT	1,P,.PDCAP##	;(153) CAPABILITY WORD (MAX PRIVILEGES)
	.GTRNG==.-NUMTAB
	GT	1,I,RNGTAB,<<RNGTBL-1>B26> ;(154) RANGE TABLE FOR GETTABS
.GTSLF==.-NUMTAB
	GT	1,R,NUMTAB,,NUMOFS	;(155) .GTSLF REVISITED
	GT	1,R,TTTWDT##,,TTTOFS	;(156) SIXBIT TERMINAL NAMES
	GT	1,P,.PDOBI##	;(157) OPERATOR AND BATCH INFORMATION
	GT	1,I,DVCSTS##,LENDVS##	;(160) CONI/DATAI DEVICE STATUS
	GT	FTNET,I,NDBTBL##,NDBMXL## ;(161) NDB BYTE POINTERS
	GT	1,J,JBTPDB##		;(162) JOB PDB ADDRESS
	GT	FTEQDQ,P,.PDEQJ##	;(163) ENQ Q-HEADER
	GT	1,I,DFLTTB##,DFLMXL##	;(164) SET DEFAULT COMMAND ARGUMENTS

;INSERT NEW TABLES ABOVE HERE
GTTBLN=.-NUMTAB			;LENGTH OF TABLE
IFN FTPATT,<
	Z			;FOR PATCHING
	Z
>
	$HIGH			;BACK TO THE HIGH SEGMENT

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 (THIS WORD IS FULL)
	FTBITS<0,1,DAEMON,1,SPL,JCON,POKE,PEEK,1,CCIN,IPCF,PI,1,EQDQ,MIC,MLOG,MDA>
;(1) REAL-TIME AND SCHEDULING FEATURES
	FTBITS<HPQ,1,1,RTTRAP,TRPSET,LOCK,RTC,0,1,1,NSCHED,PSCD,CMSR>
;(2) COMMAND FEATURES (THIS WORD IS FULL)
	FTBITS<ATTACH,1,1,1,1,WATCH,1,1,VERS,1,1,1,1,MONL,MOFF,EXE,PJOB>
;(3) ACCOUNTING FEATURES
	FTBITS<TIME,KCT,1,CNO,TLIM,FDAE,EMRT,ACCT>
;(4) NON I/O FEATURES NOT RELATED TO DEBUGGING
	FTBITS<1,MP,EL,2SWP,1,1,1,METR,KI10,0,22BI,0,KL10,1,KS10>
;(5) NON I/O DEBUGGING FEATURES
	FTBITS<0,0,1,1,TRAC,PATT,WHY,RSP,1>
;(6) DISK UUO FEATURES (THIS WORD IS FULL)
	FTBITS<1,SFD,1,1,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,1,DMRB,DETS,DUFC,DBBK,SWPE,0,1,1,CBDB,0,SLCK>
;(10) SCANNER, RP04 FEATURES
	FTBITS<HDPX,GPO2,630H,MODM,SCNR,SCLC,DIAL,TPAG,TBLK,CAFE,2741,0,TVP,D10H,RDX,1>
;(11) OTHER PERIPHERALS (THIS WORD IS FULL)
	FTBITS<1,MTSE,CDRS,1,LPTR,NET,1,CRTR,CPTR,1,MSGS,XTC,DN60,TSK,TLAB,1,1>
;(12) OTHER PERIPERALS (SECOND WORD)
	FTBITS<DX10>
;(13) DISK "INVISIBLE" FEATURES (SECOND WORD)
	FTBITS<DUAL>
;(14) DISK UUO FEATURES (SECOND WORD)
	FTBITS<PSTR>
;(15) LIST OF MONITOR NON-I/O FEATURES WHICH DIRECTLY IMPACT CUSPS (SECOND WORD)
	FTBITS <MPB>
	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
	MOVE	T3,JBTSGN##(J)	;HI SEG CHARACTERISTICS FOR THIS JOB
	MOVE	T4,.JDAT+JOBPD1##	;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
	MOVSI	T2,(UP.GET)	;CLEAR GET IN PROGRESS FLAG
	ANDCAM	T2,.UPMP+.UPBTS

	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

CHGPPN:	TRNE	T1,777777	;PROG. # = 0?
	TLNN	T1,777777	;NO, PROG. = 0?
	  POPJ	P,		;NO ZER0'S ALLOWED
	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
	SUBTTL	DEVNAM UUO


;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
	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

	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::TDZA	T3,T3		;FORCE CALL TO DAERPT
TRPSTU::SETOM	T3		;DON'T CALL DAERPT (DIAG. UUO)

	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

	SETZM	.CPSTS##	;CLEAR THE STOP TIME SHARING FLAG
IFN FTDAEM,<
	JUMPN	T3,TRPST0	;AVOID DAEMON CALL IF NOT TRPSET UUO
	HRRZ	U,T1		;SECOND WORD OF ERPTBK IS CONTENTS
	HLRZ	F,T1		;  OF AC AT TRPSET CALL
	MOVE	T1,[.SWETP,,.ERSWE] ;EVENT,,ERROR CODES FOR DAEMON
	PUSHJ	P,DAEDSJ##	;TELL DAEMON TO LOG IT
	PUSHJ	P,GETTAC##	;RESTORE ARGUMENT
TRPST0:
>
	JUMPE	T1,TRPST1	;IS AC 0?(DO NOT SET PI LOC IF YES)
IFN FTMP,<
	PUSHJ	P,CHKCPU##	;LOCKED? OR GET LOCKED
	  POPJ	P,		;CAN'T RUN ON 0
	PUSHJ	P,ONCPUN##	;GET ON THE RIGHT CPU
	PUSHJ	P,GETTAC##	;RESTORE ARGUMENT
>
	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 FTLOCK,<
	PUSHJ	P,LOKEVC##	;IF KI10, JOB MUST BE LOCKED IN EVM
				; IS IT?
>
	  POPJ	P,		;NO, ERROR RETURN
	PUSHJ	P,GETTAC##	;RESTORE USER'S AC ARGUMENT TO T1
	MOVEM	J,.CPSTS##	;SET STOP TIME SHARING FLAG, SO NO OTHER JOBS
				; JOBS WILL RUN AND NO CORE SHUFFLING
	PUSHJ	P,SAVE2##	;SAVE TEMPS
	MOVE	P1,T2		;SAVE INTERRUPT LOCATION
	HRR	M,T1		;LOCATION OF THE INTERRUPT INSTR
	PUSHJ	P,GETWDU##	;GET THE INSTRUCTION
	MOVE	P2,T1		;SAVE IT
	HRR	M,T1		;ADDRESS POINTED TO BY IRP INSTR
	PUSHJ	P,GETWDU##	;GET THAT
	HRRZ	U,JBTADR##(J)	;EVA OF THE JOB
	ADD	P2,U		;RELOCATE THE IRP INSTR
	ADD	T1,U		;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
	PUSHJ	P,PUTWDU##	;STORE IT FOR THE USER
	ADD	P1,.CPTOS##	;ADD IN DRAP OFFSET FOR THIS CPU
	EXCH	P2,(P1)		;AND STORE IN MONITOR TRAP LOC.
	MOVE	T1,P2		;RETURN PREVIOUS CONTENTS TO THE USERS
TRPST1:	AOS	(P)		;OK RETURN
	MOVSI	T2,(XC.UIO)	;SET USER IO PC FLAG
	IORM	T2,.JDAT+JOBPD1##	;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


HIBUUO:	PUSHJ	P,INCPD1##

IFN FTPI,<
	XCT	PINOJN		;SKIP IF USER NOT ENABLED FOR TRAPS
	SKIPN	@JBTPIA##(J)	;ARE THERE ANY PENDING INTERRUPTS
	JRST	HIBER		; NOT ENABLED OR NONE PENDING
	POPJ	P,		;EXIT NOW TO GRANT INTERRUPT
>
HIBER::	MOVSI	T2,(JS.HIB)	;SET HIBER BIT
	IORM	T2,JBTST2##(J)
	PUSHJ	P,HIBER4	;DO THE UUO
	  JFCL
	MOVSI	T2,(JS.HIB)	;CLEAR HIBER BIT
	ANDCAM	T2,JBTST2##(J)
	POPJ	P,
HIBER4:	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
	SYSPIF			;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
	SYSPIN			;RESTORE THE PI STATUS
	JRST	CPOPJ1##	;GIVE A SKIP RETURN TO THE USER
HIBER1:	DPB	P1,PJBSTS##	;STORE THE SLEEP CODE IN JBTSTS WORD
	SYSPIN			;RESTORE PI SYSTEM
	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
HIBER3:	PUSHJ	P,FNPDBS##	;GET THE PDB ADDRESS
	PUSHJ	P,CLRIPT##	;CLEAR IN-CORE PROTECT TIME
	PJRST	WSCHED##	;GO RESCHEDULE
;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
	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
	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
	JRST	WAKEOK		;GO WAKE THE JOB UP
WAKEME:	SKIPA	T1,J
WAKOK1:	EXCH	J,T1		;SET UP J PROPERLY
WAKEOK:	MOVSI	T2,(JS.HIB)	;JOB DID SLEEP UUO BIT
	TDNN	T2,JBTST2##(J)	;SLEEP OR HIBER?
	JRST	SETWAK		;SLEEP, JUST SET WAKE BIT
IFN FTPI,<
	MOVE	T2,T1		;GET JOB NUMBER OF WAKER
	SIGNAL	C$WAKE		;SIGNAL WAKEUP
	  JRST	WAKEIT		;WAKE UP JOB SINCE PSISER DIDN'T
	JRST	CPOPJ1##	;GIVE SKIP RETURN
>
WAKEIT:	MOVEI	T1,RNQ##	;PREPARE TO PUT JOB IN THE RUN QUEUE
	SYSPIF			;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
	SYSPIN			;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
	SYSPIF			;GUARD AGAINST HIGH PI WAKE UP
	SETOM	.CPCKF##	;FLAG THE SCHEDULER FOR CPU
	SKIPN	.CPRTF##	;IS THERE A FORCED SCHEDULE TO BE DONE
	SETOM	.CPRTF##	;NO, MARK  ONE IS IN PROGRESS FOR CPU
	TDNN	T2,JBTSTS##(J)	;IS THIS JOB SWAPPED OUT
	JRST	WAKOK3		;NO. PROCEED.
	SKIPG	T2,.CPRTF##	;ANYONE IN .CPRTF?
	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,.CPRTF##	;NO. PUT OUR NUMBER IN.
WAKOK3:	SYSPIN	(CLKBIT##+PI.IIO) ;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,

;WAKPST IS A ROUTINE TO EITHER WAKE UP A HIBERNATING
;	JOB OR POST THE WAKE UP IF SLEEPING/RUNNING
;	T1=JOB NUMBER
;CLOBBERS T2

WAKPST::MOVSI	T2,(JS.HIB)	;IS JOB HIBERNATING
	TDNE	T2,JBTST2##(T1)	;OR SLEEPING
	PJRST	WAKJOB		;HIBERNATING, GO WAKE IT NOW
	PUSH	P,J		;SAVE J
	MOVE	J,T1		;COPY JOB NUMBER
	PUSHJ	P,SETWAK	;POST THE WAKE UP
	  PJRST	JPOPJ##		;ALWAYS NON-SKIP RETURN
	PJRST	JPOPJ##		;RESTORE J AND RETURN
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
	SYSPIN			;TURN ON PIS AGAIN
	JRST	WAKOKA		;AND RETURN AFTER CHECKING FOR HPQ STUFF
SETWAK:	SYSPIF			;GUARD AGAINST PI LEVEL ACTIVITY
NOTNAP:	MOVSI	T2,WAKEB##	;SET WAKEUP BIT INSTEAD
	IORM	T2,JBTRTD##(J)	;SET WAKE UP BIT
	SYSPIN			;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

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

	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
;	JOBPEK	AC,
;	  ERROR RETURN
;	NORMAL RETURN
;ADDR:	XWD FLAGS+JOB NUMBER,NUMBER OF WORDS TO TRANSFER
;	XWD SOURCE ADDRESS,DESTINATION ADDRESS
;FLAGS ARE:
;	1B0 - 0=READ, 1=WRITE
;	1B1 - READ UPMP OF SPECIFIED JOB
;	1B2 - READ EXEC VIRTUAL ADDRESS BETWEEN 340000 AND 377777
;	      AS IF MAPPED THROUGH SPECIFIED JOB'S MAP


JOBPEK:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSHJ	P,PRUSET	;REQUIRES PRIVILEGES
	  JRST	JPKNPV		;NOT PRIVILEGED
	TLNE	T1,(JK.EVA)	;IF EVM FLAG IS SET, INSURE THAT WRITE
	TLZ	T1,(JK.WRT!JK.UPM) ;  AND UPMP FLAGS ARE CLEARED
	HLRZ	P1,T1		;RH P1=OTHER JOB NUMBER
	TRZ	P1,(JK.ALL)	;CLEAR FLAGS
	HLL	P1,T1		;LH P1=FLAGS
	HRREI	P2,-1(T1)	;P2=LENGTH-1 OF TRANSFER
	HRRZ	T1,P1		;T1=OTHER JOB NUMBER
	PUSHJ	P,LGLPRC##	;SKIP IF LEGAL JOB NUMBER
	  JRST	JPKIJN		;NO, REFUSE TO DO IT
	MOVSI	T2,SWP		;JOB ON ITS WAY OUT OR IN?
	TDNE	T2,JBTSTS##(T1)	;LOSE IF SO
	JRST	JPKSWP		;RETURN IF SWP=1
	MOVSI	T2,(JS.SIP)	;T2 = JOB IN TRANSIT
	SKIPE	JBTADR##(P1)	;SKIP IF JOB SWAPPED
	TDNE	T2,JBTST2##(P1)	;SKIP IF ALL IN CORE
	JRST	JPKSWP		;NOT IN CORE
	CAILE	P2,1000-1	;SKIP IF UNDER MAX
	MOVEI	P2,1000-1
	PUSHJ	P,GETWD1##	;GET XWD SOURCE, DESTINATION
	PUSH	P,T1		;SAVE T1
	TLNE	P1,(JK.WRT)	;SKIP IF READ
	HLRZS	T1		;ADDR IN OUR JOB
	HRRZS	T2,T1		;. .
	ADD	T2,P2		;HIGHEST ADDRESS IN OUR JOB
	PUSHJ	P,TRNGE##	;SEE IF PROCEEDING WILL CAUSE A PAGE FAULT
	TLNN	P1,(JK.EVA!JK.UPM) ;DON'T CHECK HERE IF FUNNY SPACE
	CAIE	J,(P1)		;JOBPEK ON SELF?
	JRST	JOBPK1		;NO, PROCEED
	MOVE	T1,(P)		;GET XWD BACK
	TLNN	P1,(JK.WRT)	;SKIP IF WRITE
	HLRZS	T1		;OTHER ADDR IN OUR JOB
	HRRZS	T2,T1		; ...
	ADD	T2,P2		;HIGHEST ADDR IN JOB
	PUSHJ	P,TRNGE##	;CHECK IT
JOBPK1:	POP	P,T1		;RESTORE XWD

;STILL IN FTDAEM CONDITIONAL
;HERE TO CHECK IF SOURCE ADDR IS FROM HIGH SEGMENT

	MOVE	P3,JBTADR##(J)	;P3=JBTADR FOR OUR JOB
	MOVE	T4,JBTADR##(P1)	;T4=JBTADR FOR SPECIFIED JOB
	TLNE	P1,(JK.WRT)	;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
	TLNN	P1,(JK.EVA)	;SOURCE IN EVM MAPPED THROUGH USER?
	JRST	JOBPK2		;NO
	CAIL	T2,340000	;INSURE THAT THE ADDRESS IS IN
	CAILE	T2,377777	;  THE PER-PROCESS AREA
	JRST	JPKIAD		;ILLEGAL IF NOT
	JRST	JOBPK5		;CHECK DESTINATION ADDRESS
JOBPK2:	CAMGE	T2,T3		;SKIP IF SOURCE ADDR GT LOW SEGMENT SIZE
	JRST	JOBPK4		;SOURCE ADDRESS IS IN LOW SEGMENT
	MOVE	T4,JBTSGN##(P1)	;HIGH SEGMENT NUMBER FOR SPECIFIED JOB
	TLNE	P1,(JK.WRT)	;SKIP IF READ, NOT IF WRITE
	MOVE	T4,JBTSGN##(J)	;HIGH SEGMENT NUMBER FOR THIS JOB
	JUMPE	T4,JPKIAD	;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
	JUMPL	T4,JOBPK3	;GO IF A SPY SEG.
	LDB	T3,[POINT 9,JBTUPM##(T4),8]	;HIGH SEG ORIGIN PAGE #
	LSH	T3,P2WLSH##	;VIRTUAL ADDRESS OF HIGH SEG.
JOBPK3:	SUB	T2,T3		;T2=ADDRESS IN SEGMENT FOR TRANSFER
	JUMPL	T2,JPKIAD	;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
				;FALL INTO JOBPK4
;HERE TO CHECK IF SOURCE ADDRESS FITS IN SOURCE SEGMENT
JOBPK4:	ADD	T2,P2		;SOURCE ADDR+LENGTH OF SEG=LAST ADDR OF SOURCE 
	CAMLE	T2,T3		;SKIP IF LE LAST ADDR OF SOURCE SEG 
	JRST	JPKIAD		;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

JOBPK5:	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	JPKIAD

;HERE WHEN ADDRESSES ARE VERIFIED TO BE LEGAL
	AOJE	P2,CPOPJ1##	;EXIT NOW IF 0 WORDS TO TRANSFER
	PJRST	JOBPKD##	;DO THE BLT AND GIVE SKIP/NON-SKIP
				;RETURN
;ERROR CODES RETURNED BY JOBPEK (MORE IN KXSER)
	ERCODE	JPKNPV,JKNPV%	;NOT PRIVILEGED
	ERCODE	JPKIJN,JKIJN%	;ILLEGAL JOB NUMBER
	ERCODE	JPKSWP,JKSWP%	;JOB SWAPPED
	ERCODE	JPKIAD,JKIAD%	;ILLEGAL ADDRESS

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


;UUO TO FORCE A COMMAND FOR A JOB OR A TTY
;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 TTY IOINDEX


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
	CAIN	T3,1		;SUPPLIED A SECOND ARG?
	TDZA	T1,T1		;NO, DEFAULT TO ZERO
	PUSHJ	P,GETWD1##	;YES, GET IT
	CAIGE	T1,.UXTRM	;LOOK LIKE A TERMINAL?
	JRST	FRCUU1		;NO, MUST BE JOB NUMBER
	SUBI	T1,.UXTRM	;YES, REMOVE OFFSET
	CAIL	T1,TTPLEN##	;LEGAL TERMINAL?
	  POPJ	P,		;NO, ERROR RETURN
	HRRZ	U,LINTAB##(T1)	;YES, GET LDB ADDRESS
	JRST	FRCUU2		; AND FORCE THE COMMAND ON IT
FRCUU1:	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
FRCUU2:	HRRZ	T2,T4		;T2=INDEX OF COMMAND
	PUSHJ	P,COMFRL##	;FORCE COMMAND
	  JRST	CPOPJ1##		;OK
	POPJ	P,		;CAN'T

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

;UUO TO SET PARAMETERS ON SPOOLED FILES
;CALL:	MOVE	AC,[N,,E]
;	SPPRM.	AC,
;	  ERROR	RETURN
;	NORMAL	RETURN
;
;E:	FUNCTION CODE
;	CHANNEL # OR DEVICE NAME
;	A SPOOLING PARAMETER BLOCK
;
;ERRORS:	-1 = ADDRESS CHECK
;		 0 = ARG BLOCK TOO SHORT
;		 1 = NO SUCH DEVICE
;		 2 = DEVICE NOT ASSIGNED OR INITED
;		 3 = DEVICE NOT SPOOLED
;		 4 = NO FREE CORE FOR SPB
;		 5 = ILLEGAL FUNCTION
SPPRM:	PUSHJ	P,SAVE2##	;SAVE AN AC
	HRR	M,T1		;POINT AT ARGUMENT ADDRESS
	HLRE	P1,T1		;GET LENGTH IN P1
	CAIGE	P1,2		;ENOUGH THERE?
	PJRST	ECOD0##		;NO, ERROR
	PUSHJ	P,GETWRD##	;GET FUNCTION
	  PJRST	RTM1
	CAIG	T1,2		;CORRECT CODE?
	SOSGE	P2,T1
	PJRST	ECOD5##		;NO, LOSE
	PUSHJ	P,GETWR1##	;GET DEVICE SPEC
	  PJRST	RTM1
	PUSHJ	P,DVCNSG	;FIND THE DDB
	  PJRST	ECOD1##		;NO SUCH DEVICE
	MOVEI	T1,ASSCON!ASSPRG  ;GET ASSIGNED + INITED BITS
	SKIPE	P2
	MOVEI	T1,ASSPRG
	TDNN	T1,DEVMOD(F)	;IS DDB EITHER
	PJRST	ECOD2##		;NOPE
	SKIPL	DEVSPL(F)	;SPOOLED?
	JUMPE	P2,ECOD3##	;NO, LOSE IF FUNCTION 1
	HRRZ	T1,DEVSPM##(F)	;IS THERE A SPOOL PARAM BLOCK?
	JUMPN	T1,SPPRM1	;YES, USE IT
	MOVEI	T2,SPBMAX##	;HOW MUCH CORE WE NEED
	PUSHJ	P,GTFWDC##	;GET THAT CORE
	  PJRST	ECOD4##		;NO FREE CORE
	HRRZM	T1,DEVSPM##(F)	;REMEMBER WHERE IT IS
	HRLZ	T2,T1		;SET ADR,,0
	HRRI	T2,1(T1)	;ADR,,ADR+1
	SETZM	0(T1)		;CLEAR FIRST WORD
	BLT	T2,SPBMAX##-1(T1) ;CLEAR THE REST
				;FALL INTO SPPRM1
SPPRM1:	SUBI	P1,1		;ADJUST FOR DEVICE NAME
	CAILE	P1,SPBMAX##	;BIGGER THAN MAX
	MOVEI	P1,SPBMAX##	;YES, USE MAX
	MOVNS	P1		;MAKE P1 NEGATIVE
	HRLS	P1		;MAKE IT A
	HRR	P1,T1		;POINTER
SPPRM2:	PUSHJ	P,GETWR1##	;GET NEXT WORD
	  PJRST	RTM1		;ADDR CHECK
	MOVEM	T1,(P1)		;SAVE USERS ARG
	AOBJN	P1,SPPRM2	;LOOP FOR ALL ARGS
	JUMPE	P2,CPOPJ1##	;GOOD RETURN IF FUNCTION 1
	PJRST	SPLREN##	;FUNCTION 2 LET FILSER RENAME

	SUBTTL	DEVOP. UUO

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

;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	11,DVPCAL	;(11) LOAD RSX-20F LP RAM
	XWD	12,DVPCAL	;(12) LOAD RSX-20F LP VFU
IFN FTMDA,<
	XWD	13,DVPMDC	;CLEAR MDA RESTRICTION
	XWD	14,DVPMDS	;SET MDA RESTRICTION
>;END IFN FTMDA
	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
IFN FTSPL,<
	SKIPN	DEVCHR(F)	;IF SPOOLED
	PJRST	ECOD4##		; LOSE
>
	MOVE	S,DEVIOS(F)	; AND S
	MOVE	T1,P1		;GET FUNCTION
	MOVE	T2,T1		;COPY INTO T2
	TRNE	T2,2000		;CHANGE SET INTO
	TRON	T2,1000		;+ READ FOR COMPARE
	TRZ	T2,2000		;BUFFER NET CUSTOMER ARG.
	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:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;GET ON CPU WHICH OWNS DEVICE
>
	HRRZ	T2,DEVSER(F)
	PJRST	DDVO(T2)	;CALL THE SERVICE ROUTINE

;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

IFN FTMDA,<
;HERE TO CLEAR 'CONTROLLED BY MDA BIT
DVPMDC:	SKIPA	T3,[ANDCAM T2,DEVCHR(F)]

;HERE TO MAKE A DEVICE CONTROLLED BY MDA
DVPMDS:	MOVE	T3,[IORM T2,DEVCHR(F)]
	CAME	J,MDAJOB##	;IS THIS MDA?
	PJRST	ECOD1##		;NO, TOO BAD
	MOVE	T2,DEVMOD(F)	;IF A DISK
	TLNE	T2,DVDSK
	PJRST	ECOD2##		; FORGET IT
	MOVSI	T2,DVCMDA	;YES, GET THE BIT
	XCT	T3		;SET/CLEAR THE BIT
	PJRST	CPOPJ1##	;WIN
>;END IFN FTMDA
	SUBTTL	FILOP. UUO

;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
FOP.SO==(1B12)		;SUPER I/O
FOP.XC==(1B13)		;EXTENDED CHANNEL

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
XWD	FOP.SO,FOPEN				;(16) OPEN FOR SUPER I/O
EXP	FOPIN					;(17) INPUT
EXP	FOPOUT					;(20) OUTPUT
EXP	FOPSST					;(21) SETSTS
EXP	FOPGST					;(22) GETSTS
EXP	FOPREL					;(23) RELEASE
EXP	FOPWAT					;(24) WAIT FOR I/O TO STOP
EXP	FOPSEK					;(25) SEEK
EXP	FOPRRC					;(26) REWRITE RIB IF CHANGED
FOPMAX==.-FOPTAB-1 	;MAXIMUM FUNCTION
	SALL
FILOP:	FRAME	<FOPFLG,FOPAP,FOPTMP,FOPBLK,FOPEXT>
	HRRZM	T1,FOPAP	;ADDRESS OF ARG LIST
	HLLM	M,FOPAP		;AC #
	HLRE	T2,T1		;GET ARGUMENT COUNT
	JUMPLE	T2,FCLOSI	;ILLEGAL IF NEGATIVE OR ZERO
	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
	TLZE	T1,(1B1)	;ASSIGN A FREE CHANNEL?
	TLO	T2,FOP.XC	;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,177777	;CLEAR OUT CHAN #
	CAIGE	P1,HIGHXC##	;OUT OF RANGE?
	CAILE	T1,FOPMAX	;FUNCTION TOO BIG?
	JRST	FOPILU		;YES--ERROR
	TLNE	T2,FOP.XC	;ASSIGN AN EXTENDED CHANNEL?
	JUMPN	P1,FOPILU	;YES, NUMBER FIELD MBZ
	HLLZ	T3,FOPTAB(T1)	;GET FLAGS
	IORB	T2,T3		;MAKE FLAGS,,LEN
	MOVEM	T2,FOPFLG	;SAVE THE FLAGS
	HRRZ	T2,FOPTAB(T1)	;FUNCTION
	PUSHJ	P,SETUF		;NO, SETUP F
	  JRST	[CAIE T2,FOPEN	;OPEN?
		 JRST FCLOSI	;NO, IOIMPM
		 JRST .+1]	;YES, PROCEED
	HRLM	P1,.UPMP+.UPCTA	;STORE UDX FOR THIS UUO
	CAIE	T2,FOPEN	;OPEN?
	JRST	(T2)		;NO, JUST DISPATCH
	CAILE	P1,17		;YES, TRADITIONAL CHANNEL?
	TLNE	T3,FOP.XC	;NO, ASSIGN AN EXTENDED CHANNEL?
	JRST	(T2)		;DISPATCH BY FUNCTION
	JUMPE	F,FOPILU	;EXTENDED CHANNEL, ILLEGAL IF NOT ALREADY OPEN
	JRST	(T2)		;DISPATCH
;ROUTINE TO GET NEXT INITED CHAN. DDB.
;CALL - P1 CHANNEL TO START FROM
;RETURNS - CPOPJ - NO MORE INITED CHANS
;	 - CPOPJ1 - T1 POINTS TO DDB
;                   P1 HAS CHAN # +1
NXTCH::	CAIGE	P1,HIGHXC##
	SKIPGE	USRHCU##
	POPJ	P,
	HRRZ	T1,.UPMP+.UPCTA
	CAILE	P1,17
	JUMPE	T1,CPOPJ##
	PUSH	P,F
NXTCH1:	PUSHJ	P,SETUF
	  JRST	[CAIE P1,HIGHXC##
		 AOJA P1,NXTCH1
		 JRST FPOPJ##]
	HRRZ	T1,F
	AOJA	P1,FPOPJ1##

;SUBROUTINE TO SETUP F TO POINT TO THE DDB ASSOCIATED WITH THE USERS CHANNEL
; PRESERVES T2,T3

SETUF::	PUSHJ	P,SAVE1##	;SAVE P1
	SETZ	F,		;ASSUME NO DDB
	HRRZS	P1		;ZERO LEFT HALF - PHYSICAL ONLY BIT?
	HRRZ	T1,.UPMP+.UPCTA ;ADDRESS OF EXTENDED CHANNEL TABLE
	CAIG	P1,17		;TRADITIONAL CHANNEL?
	JRST	SETUF1		;YES
	JUMPE	T1,CPOPJ##	;NO, ERROR IF NO EXTENDED CHANNEL TABLE
	ADD	T1,P1		;ADDRESS OF THE DDB
	CAIGE	P1,HIGHXC##	;HIGHER THAN HIGHEST ALLOWED?
	SKIPN	F,-20(T1)	;AND IS THERE A DDB?
	POPJ	P,		;ERROR
	JRST	SETUF2		;GOOD RETURN, F SETUP
SETUF1:	CAMG	P1,USRHCU##	;A LEGAL CHANNEL?
	SKIPN	F,USRJDA##(P1)	;AND HAS IT BEEN OPENED?
	POPJ	P,		;NO, ERROR
SETUF2:	MOVE	S,DEVIOS(F)	;SETUP I/O STATUS
	JRST	CPOPJ1##	;YES, GOOD RETURN, F SETUP
;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
	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
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
	TLZ	T1,-1		;START ADDRESS
	PUSHJ	P,TRNGE##	;TEST RANGE
FOPVMX:	MOVSI	T1,FOP.XC	;EXTENDED CHANNEL REQUESTED BIT
	TDNN	T1,FOPFLG	;WAS AN EXTENDED CHANNEL REQUESTED?
	JRST	FOPVM4		;NO, PROCEED TRADITIONALLY
	HRRZ	T1,.UPMP+.UPCTA ;AN EXTENDED CHANNEL TABLE ALREADY SETUP?
	JUMPN	T1,FOPVM1	;YES, FIND A FREE CHANNEL
	MOVEI	T2,HIGHXC##-20	;NO, ALLOCATE AN EXTENDED CHANNEL TABLE
	PUSHJ	P,GTFWDC##	;GET FUNNY WORDS CACHED
	  JRST	FOPOER		;NONE AVAILABLE
	HRRM	T1,.UPMP+.UPCTA ;STORE THE ADDRESS OF THE XCT
	MOVSI	T2,(T1)		;FORM A BLT POINTER
	HRRI	T2,1(T1)	; ..
	SETZM	(T1)		;ZERO FIRST WORD OF THE TABLE
	BLT	T2,HIGHXC##-21(T1) ;ZAP, THE TABLE IS INITIALIZED
;HERE WITH T1 = ADDRESS OF THE EXTENDED CHANNEL TABLE
FOPVM1:	MOVEI	P1,0		;START AT THE BEGINNING OF THE TABLE
FOPVM2:	MOVE	T2,T1		;ADDRESS OF THE TABLE
	ADD	T2,P1		;PLUS CURRENT CHANNEL NUMBER
	SKIPN	(T2)		;CHANNEL IN USE?
	JRST	FOPVM3		;NO, AVAILABLE
	CAIGE	P1,HIGHXC##-20	;YES, LOOKED AT THE ENTIRE TABLE?
	AOJA	P1,FOPVM2	;NO, LOOP OVER ENTIRE TABLE
	JRST	FOPOER		;ERROR
;HERE WHEN AN AVAILABLE CHANNEL WAS FOUND
FOPVM3:	ADDI	P1,20		;EXTENDED CHANNEL NUMBER
;STORE CHANNEL NUMBER FOR THE USER
FOPVM4:	HRLM	P1,.UPMP+.UPCTA	;CHANNEL NUMBER
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	PUSHJ	P,GETWDU##	;GET CHANNEL NUMBER
	DPB	P1,[POINT 9,T1,17] ;STORE POSSIBLE EXTENDED CHANNEL NUMBER
	TLZ	T1,(1B1)	; AND CLEAR THE ASSIGN EXT CHAN BIT
	PUSHJ	P,PUTWDU##	;STORE THAT FOR THE USER
	HRRI	M,1(M)		;POINT TO OPEN BLOCK
	MOVE	T1,.UPMP+.UPFOP
	MOVEM	T1,FOPEXT
	MOVE	P2,FOPFLG	;FLAGS
	TLNE	P2,FOP.RN+FOP.DL ;RENAMES OR DELETES
	JUMPN	F,[TLNE F,LOOKB!ENTRB ;YES -- ACTIVE LOOKUP OR ENTER
		   JRST FOPEN2	;YES -- SKIP THE OPEN
		   JRST .+1]	;NO -- DO THE OPEN
	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
	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
	TLNE	T1,DEPFFA	;PRIVILEGED INVOKING PRIVILEGES?
	TDZA	T1,T1		;NO
	MOVSI	T1,(UP.PFO)	;YES
	IORM	T1,.UPMP+.UPBTS	;FOR ACCESSOR'S IPCF CAPABILITIES
	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,UUXSIZ+1	;5 OR MORE WORDS?
	JRST	FOPEN5		;NO--DO NOT SAVE ANYTHING
	HRR	M,FOPBLK	;ADDRESS OF BLOCK
	MOVEI	T1,UUXPRV+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
	TLNN	F,LOOKB+ENTRB	;RENAME, FILE ALREADY OPEN?
	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
	TLO	M,400000	;SO FTUUUO DOESN'T CLOBBER USER'S AC
	PUSHJ	P,PTHUUO##	;DO THE PATH UUO
	  JFCL			;SHOULD NEVER FAIL
	TLZ	M,400000
	HRLM	P1,.UPMP+.UPCTA	;RESET IO CHAN
	PUSHJ	P,SETUF		;F GOT WIPED
	  JRST	FOPXI1		;CAN'T HAPPEN
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
	TLNE	T1,DVTTY	;NUL:?
	JRST	FOPWIN		;YES, DONE
	TLNN	T1,DVDSK	; ..
	JRST	FOPN11		;NO, ALL DONE UNLESS AN MTA

;HERE TO APPEND TO A DISK FILE
FOPN9B:	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
	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
	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
	HRRZ	T2,DEVOAD(F)	;FOR BYTE POINTER
	ADD	T2,FOPBLK
	PUSHJ	P,IOSETC	;STORE CORRECT DATA IN HEADER
	MOVE	J,.CPJOB##	;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
	PUSHJ	P,OUTF		;ZERO BUFFER
	HRRZ	T1,DEVOAD(F)
	HRRM	T1,DEVIAD(F)	;READ INTO OUTPUT BUFFER
	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
	TLO	F,OUTPB		;IN CASE CLOSE WITH NO OUTPUTS -
	PUSHJ	P,JDAADR
	MOVEM	F,(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
	HRRZ	T1,DEVOAD(F)	;WHERE WE READ
	MOVE	T3,FOPTMP
	EXCTUU	<MOVEM T3,@T1>	;RESTORE BUFFER RING
	EXCTUX	<MOVE T2,1(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,(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:	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
	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,760000	;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?
	TDNN	T2,FOPFLG	; ..
	JRST	FCLOS1		;YES
	TLNE	F,ENTRB		;NO, FILE ENTERED
	TLNE	F,OCLOSB	;AND STILL OPEN?
	JRST	FCLOSI		;NO, LIGHT IOIMPM
	IORM	T1,DEVJOB(F)	;YES--SET DEPFFA
	HLLZS	M		;TURN OFF CLOSE-BITS
FCLOS1:	PUSHJ	P,CLOSEF	;CLOSE THE FILE
	PUSHJ	P,WAIT1##	;WAIT FOR I/O
	HRRZ	T1,DEVIOS(F)	;GET STATUS
	TRNE	T1,740000	;ERROR BITS?
	JRST	FOPXIT		;DONE
	MOVSI	T2,FOP.UR
	TDNN	T2,FOPFLG
	AOSA	(P)
	SKIPA	T1,DEVMOD(F)
	JRST	FOPXIT
IFN FTNUL,<
	TLNN	T1,DVTTY	;GOOD RETURN IF NUL
>
	TLNN	T1,DVDSK	;DISK?
	JRST	FOPWIN		;NO, GOOD RETURN
	MOVE	T2,DEVACC##(F)
	SOS	T1,DEVREL##(F)
	CAMGE	T1,ACCWRT##(T2)	;AT EOF?
	JRST	FOPN10		;NO, JUST POSITION TO THAT BLOCK
	JRST	FOPN9B		;YES, POSITION TO LAST BLOCK.

FCLOSI:	MOVEI	T1,IOIMPM	;SET IOIMPM
	PJRST	FOPXIT		;DONE
FOPWAT:	MOVEI	W,WAIT		;WAIT
	JRST	FOPOU1
FOPIN:	SKIPA	W,[TIN]		;INPUT
FOPOUT:	MOVEI	W,TOUT		;OUTPUT
	HRRZ	T1,FOPFLG
	CAIG	T1,1		;MORE THAN 1 ARGUMENT?
	TRZA	T1,-1		;NO, NO CLOSE BITS
	PUSHJ	P,GETWD1##	;YES, GET THE CLOSE BITS
	HRR	M,T1
	HRRZ	T4,DEVSER(F)
FOPOU1:	PUSHJ	P,(W)		;DO THE IN, OUT, OR WAIT
	  AOS	(P)		;GOOD RETURN
	HRRZ	T1,S		;DEVICE STATUS
	PJRST	STOTAC##	;RETURN THAT FOR THE USER

FOPSST:	HRRZ	T1,FOPFLG
	CAIGE	T1,2
	JRST	FOPILU
	PUSHJ	P,GETWD1##
	HRR	M,T1
	AOS	(P)		;GOOD RETURN
	PJRST	SETIOS		;SET STATUS

FOPGST:	AOS	(P)		;GOOD RETURN
	LDB	T1,PUUOAC##
	HRR	M,T1
	PJRST	USTATS		;GET STATUS

FOPREL:	AOS	(P)		;GOOD RETURN
	PJRST	RELEA1		;DO THE RELEASE

FOPSEK:	AOS	(P)		;GOOD RETURN
	PJRST	UUOSKF##	;DO THE SEEK

FOPRRC:	MOVE	T1,DEVMOD(F)	
	TLNN	T1,DVDSK	;DISK?
	JRST	CPOPJ1##	;NO
	AOS	(P)
	PJRST	FWRBIC##	;YES, REWRITE RIB IF CHANGED

;SUBROUTINE TO RETURN THE ADDRESS OF A CHANNEL IN USRJDA OR THE EXTENDED
; CHANNEL TABLE IN T1
;RETURNS WITH T1 EQUAL TO THE ADDRESS OF THE CHANNEL TABLE ENTRY

JDAADP::HRRZ	T2,P1
	CAIA
JDAADR::HLRZ	T2,.UPMP+.UPCTA	;CHANNEL NUMBER 
	CAILE	T2,HIGHXC##	;LEGAL CHANNEL NUMBER?
	STOPCD	CPOPJ,JOB,ICL,	;++ILLEGAL CHANNEL NUMBER
	MOVEI	T1,USRJDA##(T2)	;ASSUME A TRADITIONAL CHANNEL
	CAIG	T2,17		;A TRADITIONAL CHANNEL?
	POPJ	P,		;YES
	HRRZ	T1,.UPMP+.UPCTA	;NO
	ADDI	T1,-20(T2)	;ADDRESS OF EXTENDED CHANNEL
	POPJ	P,		;RETURN
;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!
	SETZM	.UPMP+.UPFOP	;FILOP. IS DONE
	MOVSI	T2,(UP.PFO)	;PRIV'ED FILOP
	ANDCAM	T2,.UPMP+.UPBTS	;CLEAR THAT
	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

;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,3		;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


;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	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.

;HERE FROM FILOP
CLOSEF:	TDNE	T1,DEVJOB(F)	;IF UPDATE RIB
	JRST	CLOSE2		; CAN KEEP ENQ LOCKS
				;NOT CHECKPOINT, FALL INTO CLOSE1
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
CLOSE2:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;GET JOB ON THE RIGHT CPU TO DO FILE OPERATION
>
	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
	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)
	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)
	EXCTUU	<IORM	T1,@U>	;FLAG AS VIRGIN BUFFER IN 3 WORD HEADER
	ADDI	U,2		;JBFCTR:=0
	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
	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
	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)
	HRLZI	T1,IOUSE
	EXCTUU	<IORM	T1,@U>
	EXCTXU	<SETZM	2(U)>	;JBFCTR:=0
	PUSHJ	P,WAIT1##
	MOVSI	T1,DEPFFA	;IF FILOP UPDATE-RIB
	TDNN	T1,DEVJOB(F)	; DON'T LIGHT OCLOSB CAUSE FILE STAYS OPEN
	TLO	F,OCLOSB	;SET OCLOSB AFTER OUTPUT IS COMPLETE
UCLS3:	PUSHJ	P,JDAADR
	HLLM	F,(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##
	MOVEI	T2,2(T1)	;END
	PJRST	TRNGE##		;MAKE SURE ITS IN CORE

	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:	HRRZ	T1,T2		;CHECK ADR OF BUF HEADER
	PUSHJ	P,UADRCK
	EXCTXU	<MOVEM	T3,@T2>	;JBFADR:=IOUSE,ADDRESS OF FIRST BUFFER
				; IN RING
	PUSHJ	P,JDAADR
	MOVEM	F,(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


;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
	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

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)
	PUSHJ	P,SETUF		;IS A DEVICE ALREADY ASSIGNED TO THIS CHAN?
				;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
	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,^-.OPALL&777770 ;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
	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
	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!.OPFSP	;IS USER TRYING TO DISABLE ERROR LOGGING?
	JRST	UINIT3		;NO, LEAVE ERROR LOGGING ENABLED
	MOVE	J,.CPJOB##	;YES, CURRENT JOB NUMBER
	MOVEI	T3,DEPDEL	;SETUP TO STORE DISABLE BIT IN DDB
	LDB	T2,PDVTYP##
	CAIN	T2,.TYPTY/.TYEST
	JRST	UINITX
	MOVE	T2,JBTPPN##(J)	;PROJ PROG NUMBER FOR CURRENT JOB
	CAME	T2,FSFPPN##	;IS THIS USER FAILSAFE PPN [1,2]?
	CAMN	T2,UMDPPN##	;NO, IS THS USER MODE DIAG [6,6]?
UINITX:	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	UINIB0		;NO, SEE IF IT'S A TASK
	MOVSI	T3,DVDIBP	;YES, GET BATCH PTY BIT
	ANDCAM	T3,DEVCHR(F)	;START WITH IT OFF
	PUSHJ	P,PRVJ##	;IS JOB PRIV'ED?
	  TLNN	M,.OPBJP	;YES, DID USER REQUEST IT?
	JRST	UINIB2		;NO, IGNORE THE BIT
	MOVSI	T3,DVDIBP	;LOAD BATCH PTY BIT AGAIN
	IORM	T3,DEVCHR(F)	;TURN IT ON
	JRST	UINIB2		;AND CONTINUE ON
UINIB0:	CAIE	T3,.TYTSK/.TYEST ;IS THIS A TASK DEVICE
	JRST	UINIB1		;IF NOT, DON'T CHECK .OPDMR
	MOVSI	S,IOSDMR	;IF IT IS A TASK, FIRST
	ANDCAB	S,DEVIOS(F)	;  MAKE SURE THAT IOSDMR IS CLEAR
	TLNE	M,.OPDMR	;BUT IF THE USER ASKED FOR "DISABLE
	MOVSI	S,IOSDMR	;  MESSAGE RE-ASSEMBLY" THEN
	IORB	S,DEVIOS(F)	;  GIVE IT TO HIM
	JRST	UINIB2		;DON'T CHECK FOR ANY OTHER MEANINGS
UINIB1:	MOVEI	T2,DEPDER	;SETUP FOR POSSIBLE DISABLE ERROR RETRY
	TLNE	M,.OPDER	;USER WANT ERROR RETRY DISABLED?
	IORM	T2,DEVSTA(F)	;YES, SET DISABLE IN DDB
UINIB2:	MOVEI	T2,DEPAIO	;NON-BLOCKING I/O ON THIS FILE?
	TLNE	M,.OPAIO	;SKIP IF NO
	IORM	T2,DEVAIO(F)	;YES, FLAG ASYNCHRONOUS I/O
	MOVSI	T2,DEPIBC	;INHIBIT BUFFER CLEAR BIT
	TLNE	M,.OPIBC	;DOES THE USER WANT TO INHIBIT CLEARING OUTPUT BUFFER?
	IORM	T2,DEVTYP(F)	;YES, REMEMBER THAT
	MOVSI	T2,DEPSIE	;BIT FOR SYNCH ON I/O ERROR
	TLNE	M,.OPSIE	;TEST IF USER WANTS IT
	IORM	T2,DEVJOB(F)	;YES - SET FLG IN DDB
	CAIE	T3,.TYDSK/.TYEST
	JRST	UINIB3
	MOVE	T2,DEVRRC##(F)
	TLZ	T2,DEPRRC##!DEPRHC##!DEPPHO##
	TLNE	M,.OPRRC	;REWRITE RIB ON CHANGE?
	TLO	T2,DEPRRC##	;YES
	SKIPGE	P1		;PHYSICAL ONLY?
	TLO	T2,DEPPHO##	;YES, REMEMBER THAT.
	HLLM	T2,DEVRRC##(F)
UINIB3:	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
	HRLM	P1,.UPMP+.UPCTA
	CAILE	P1,17
	JRST	UINITC
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:	PUSHJ	P,JDAADR	;CHANNEL ADDRESS
	MOVEM	F,(T1)
	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:	PUSHJ	P,JDAADR	;CHANNEL ADDRESS
	MOVEM	F,(T1)		;STORE UUO BITS AND  DEVICE
				; DATA BLOCK ADDRESS
	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
	SETZ	F,		;CLEAR F TO CIRCUMVENT UUONET.
	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::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
	PUSH	P,T2
	EXCTXU	<SETZM	2(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,1(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
>
IFN FTMP,<
	PUSHJ	P,SETCPF##
>
	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
IFE FTWATCH,<
	  POPJ	P,		;FAILURE
>
IFN FTWATCH,<
	  CAIA			;FAILURE
	TRZ	M,-1		;SUCCESS
	PUSHJ	P,WCHFIL	;TELL THE WORLD
	  CAI	"E"
	TRNE	M,-1
	POPJ	P,		;EXIT IF ERROR
>
	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
>
IFN FTMP,<
	PUSHJ	P,SETCPF##
>
	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
IFE FTWATCH,<
	  POPJ	P,		;FAILURE
>
IFN FTWATCH,<
	  CAIA			;FAILURE
	TRZ	M,-1		;SUCCESS
	PUSHJ	P,WCHFIL	;TELL THE WORLD
	  CAI	"L"
	TRNE	M,-1
	POPJ	P,		;EXIT IF ERROR
>
	TLZ	F,ICLOSB
	TLO	F,LOOKB		;NOTE SUCCESSFUL LOOKUP
DLKDEN:	PUSHJ	P,JDAADR	;STORE UUO PROGRESS BITS
	HLLM	F,(T1)
	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
>

;SUBROUTINE TO DO THE CLOSE FOR LOOKUP/ENTER
UDLKC::	PUSH	P,M		;SAVE ACS
	PUSH	P,T4
	HRRI	M,(T1)
	PUSHJ	P,CLOSE1	;DO THE CLOSE
	POP	P,T4
	POP	P,M		;RESTORE ACS
	JRST	WAIT1##		;WAIT TILL IO DONE AND RETURN

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
IFN FTWATCH,<
;ROUTINE TO PRINT WATCH-FILE DATA
;CALL:	HRR 	M,UVA OF ERROR CODE (HRRI M,0 IF SUCCESS)
;	PUSHJ	P,WCHFIL
;	  CAI	'X'
WCHFIL:	MOVE	J,.CPJOB##
	MOVE	T1,JBTWCH##(J)
	HRR	T1,JBTSTS##(J)
	MOVS	T2,.UPMP+.UPMUO
	TRNE	T1,JS.ASA
	CAIN	T2,(ENTER)
	CAIA			;SAVE - WATCH IT
	POPJ	P,		;RUN/GET - DON'T WATCH
	TRNN	T1,JS.XO
	TLNN	T1,JW.WFL
	POPJ	P,
	PUSH	P,U
	PUSH	P,F
	PUSHJ	P,TTYFND##
	POP	P,F
	JUMPE	U,UPOPJ##
	PUSHJ	P,PRLBK##
	MOVE	T1,DEVJOB(F)
	TLNN	T1,DEPFOP
	JRST	WCHFI1
	PUSHJ	P,INLMES##
	ASCIZ	/F/
WCHFI1:	HRRZ	T3,@-1(P)
	PUSHJ	P,COMTYO##
	HLRZ	T1,.UPMP+.UPCTA
	PUSHJ	P,PRTDI8##
	PUSHJ	P,INLMES##
	ASCIZ	/: /
	PUSHJ	P,PRTDDB##
	TRNN	M,-1
	JRST	WCHFI2
	PUSHJ	P,INLMES##
	ASCIZ	/, error /
	PUSHJ	P,GETWDU##
	HRRZS	T1
	PUSHJ	P,PRTDI8##
WCHFI2:	PUSHJ	P,PRRBK##
	PUSHJ	P,PCRLF##
	JRST	UPOPJ##
>
	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
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	JRST	RNMSEG##	;OLD FILE IS .SHR AND RENAME SUCCESSFUL.

;HERE FROM SEGCON
UDREN::
IFE FTWATCH,<
	PJRST	DRN(T4)		;DO THE RENAME
>
IFN FTWATCH,<
	PUSHJ	P,DRN(T4)	;DO THE RENAME
	  SOSA	(P)		;FAILURE
	TRZ	M,-1		;SUCCESS
	PUSHJ	P,WCHFIL	;TELL THE WATCHER
	  CAI	"R"
	PJRST	CPOPJ1##
>

;SETO UUO - SET NEXT OUTPUT BLOCK NUMBER(DECTAPE)
UDSO:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	PUSHJ	P,WAIT2		;WAIT FOR IO, FIX OUTPUT BUFFERS
	JRST	DSO(T4)

;SETI UUO - SET NEXT INPUT BLOCK NUMBER
UDSI:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	PUSHJ	P,WAIT2		;WAIT FOR IO, FIX OUTPUT BUFFERS
	JRST	DSI(T4)

;GETF UUO - GET NEXT FREE BLOCK
UDGF:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	JRST	DGF(T4)

;MTAPE UUO - MAGTAPE OPERATIONS
UMTAPE:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	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
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	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:	TLNN	S,IO		;IS THIS DEVICE ALREADY DOING OUTPUT?
	JRST	UIN01		;NO
	MOVE	T1,DEVCHR(F)	;IS THIS A FULL DUPLEX DEVICE
	TLNN	T1,DVC2IO	; IF IT IS, DON'T WAIT FOR OUTPUT
	PUSHJ	P,WAIT2		;YES, WAIT TILL IT IS FINISHED.
IFN FTKL10&FTMP,<
	PUSHJ	P,OTHNBF	;RESET DEVNBF
>
UIN01:	TLO	F,INPB		;FOR THIS DEVICE.
	TLZ	F,ICLOSB
	PUSHJ	P,JDAADR	;IN LH OF CURRENT JOB DEVICE CHANNEL
	HLLM	F,(T1)
	LDB	T1,PIOMOD##	;IO MODE
	CAIL	T1,SD		;IT THE IO MODE DUMP(SD,D,DR)?
	JRST	INDMP		;YES
IN1:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;GET JOB ON RIGHT CPU TO DO IO
				; IF NON-QUEUED PROTOCOL
>
	HRRZ	U,DEVBUF(F)	;NO, GET ADDRESS OF BUFFER HEADER
	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 FROM MEMORY
				; AC S IS CLOBBERED BY AUTOMATIC CORE EXPANSION
				; ON AN IMPLICIT INBUF ON FIRST INPUT
	EXCTUX	<HRRZ	T2,@U>	;GET WORD 1 OF 3 WORD BUFFER HEADER.
	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
	MOVSI	T1,IOUSE	;BUFFER IN USE BIT
	EXCTUX	<TDNN	T1,@T2>
	JRST	INPT1
	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 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 4-WORD HEADER
	PUSHJ	P,TRNGE##	;MAKE SURE IT'S IN CORE
INPT0E:>	;END FTMSGSER
	MOVSI	T3,IOUSE
	EXCTUX	<HRRZ T2,@U>	;RESTORE T2
	EXCTUU	<ANDCAB	T3,@T2>	;FLAG CURRENT BUFFER AS FREE TO
				; RECEIVE MORE INPUT, CLEAR USE BIT
				; AND GET POINTER TO NEXT BUFFER
IFN FTMP & FTKL10,<
	HRRZ	T1,T2		;WE JUST TOUCHED THE CURRENT BUFFER
	PUSHJ	P,OUCHE##	; SO GET IT OUT OF THE CACHE
	HRRZ	T1,T3		;IN CASE USER DRAGGED IN NEXT USE BIT
	PUSHJ	P,OUCHE##	;MAKE SURE SERVICE ROUTINE KNOWS WHERE TO STOP
>
	HRRZ	T1,T3		;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)
	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
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
	EXCTUX	<SKIPGE @T1>	;IS IT FULL?
	JRST	INPT0T		;YES, CHECK NEXT
	JRST	INPT0G		;NO, START IO INTO THIS BUFFER
INPT0F:	PUSHJ	P,FLTST##	;IS THIS BUFFER IN CORE?
	  JRST	INPT0D		;NO. GO BACK TO FIRST
	EXCTUX	<HLRZ T3,@T1>
	ANDI	T3,IOSIZ	;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
	HRRZS	T1		;PREPARE FOR CT1
	PUSHJ	P,UADRCK
INPT0B:	EXCTUX	<SKIPL	@T1>	;IS THE USE BIT SET?
INPT0G:	PUSHJ	P,CALIN		;NO, START SERVICE ROUTINE FILLING EMPTY BUFFER
INPT0C:	EXCTUX	<HRR	T2,@U>	;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 FTKL10&FTMP,<
	HRRZ	T1,T2		;ADDRESS OF BUFFER WE JUST TOUCHED
	PUSHJ	P,OUCHE##	;GET IT OUT OF CACHE
>
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 FTKL10&FTMP,<
	PUSHJ	P,ISITQ		;NON-TTY AND QUEUED PROTOCOL?
	  JRST	INPT0X		;NO
INPT0Z:	PUSHJ	P,CKNBF##	;SET LH(DEVNBF) FOR ALL THE BUFFERS WE CAN GET
	MOVSI	T1,-1		;IF THERE ARE NO BUFFERS FOR US TO USE
	TDNN	T1,DEVNBF(F)
	JRST	[SKIPN DEVNBF(F);ANY FILLED BUFFERS AT ALL?
		 JRST INPT0X	;NO. (SYSTEM ERROR?)
		 PUSHJ P,CSDMP##;YES, SWEEP FOR THEM
		 JRST INPT0Z]	;GO UPDATE LH(DEVNBF) AND TRY AGAIN
	ADDM	T1,DEVNBF(F)	;ACCOUNT FOR THE BUFFER WE'RE ABOUT TO USE
INPT0X:	MOVEI	T1,-1(T2)	;IN CASE USER LOOKED AT USE-BITS
	PUSHJ	P,KLBUFB	;OUCHE BOTH ENDS OF BUFFER FORM HIM
>
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
	EXCTUU	<MOVEM J,3(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)
	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:	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:	
IFN FTKL10&FTMP,<
	PUSHJ	P,ISITQ		;QUEUED PROTOCOL?
	  JRST	INPTF2		;NO
	SETZM	DEVNBF(F)	;YES, NO BUFFERS TO START
	SETZM	DEVSBF(F)
>
INPTF2:	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
IFN FTMP,<
;SUBROUTINE TO SEE IF A DDB IS QUEUED PROTOCOL
;RETURNS CPOPJ IF NO, CPOPJ1 IF YES
;RETURNS DEYPCL BYTE IN T1
;RESPECTS T2
ISITQ:	LDB	T1,DEYPCL##	
	JUMPE	T1,CPOPJ##	;NOT QUEUED PROTOCAL IF 0
	LDB	T3,DEYCPF##	;MAYBE
	CAIE	T3,7		;IS IT TTY/PTY?
	AOS	(P)		;NO, REALLY IS QUEUED
	POPJ	P,

IFN FTKL10,<
;SUBROUTINE TO SAVE DEVNBF, RESTORE SAVED VALUE
OTHNBF:	PUSHJ	P,ISITQ		;QUEUED PROTOCAL?
	  POPJ	P,		;NO
	MOVE	T1,DEVNBF(F)	;YES
	EXCH	T1,DEVSBF(F)	;SAVE CURRENT DEVNBF, RESTORE SAVED VALUE
	MOVEM	T1,DEVNBF(F)	; (SWITCHING FROM INPUT TO OUTPUT OR VICE VERSA)
	POPJ	P,
>>
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		;DEVICE SEEN EOF?
	POPJ	P,		;YES, DON'T START IT
	PUSH	P,T2		;NO, START IO ON THE DEVICE
	PUSH	P,U
	HRRZ	T1,DEVIAD(F)	;IS FIRST ADR. ABOVE JOB DATA AREA?
	EXCTUX	<HLRZ	T2,@T1>	;GET LENGTH OF BUFFER
	MOVE	T3,DEVMOD(F)
	TLNE	T3,DVTTY
	ANDI	T2,IOSIZ	;CLEAR BOOKKEEPING BITS
	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

	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##	;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
	PUSHJ	P,JDAADR	;SAVE NEW BIT SETTINGS.
	HLLM	F,(T1)
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
	TLNE	S,IO		;IS THIS DEVICE ALREADY DOING INPUT?
	JRST	UOUT01		;NO
	MOVE	T1,DEVCHR(F)	;SEE IF THIS IS A FULL DUPLEX DEVICE
	TLNN	T1,DVC2IO	; IF SO, DON'T WAIT FOR INPUT
	PUSHJ	P,WAIT1##	;YES, WAIT TILL IT BECOMES INACTIVE
IFN FTKL10&FTMP,<
	PUSHJ	P,OTHNBF
>
UOUT01:	LDB	T1,PIOMOD##	;GET DATA MODE SET BY INIT OR SETSTS.
	CAIL	T1,SD		;IS IT DUMP MODE(SD,DR,D)?
	JRST	OUTDMP		;YES.
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET JOB ON CPU OWNING DEVICE
				; IF NON-QUEUED PROTOCOL
>
	PUSHJ	P,OUTA		;NO, CHECK FOR NON-ZERO ADDRESS(USER
				; CHANGING RING)
	HLRZ	U,DEVBUF(F)	;REL. ADDR. OF OUTPUT BUFFER HEADER
	MOVEI	T1,(U)		;START OF BUFFER HEADER
	MOVEI	T2,2(T1)	;TOP OF HEADER
	PUSHJ	P,LRNGE##	;MAKE SURE HEADER IS COMPLETELY IN CORE

	EXCTUX	<SKIPG	T2,@U>	; CHECK FIRST WORD OF BUFFER RING HEADER
	JRST	OUTF		;RING NOT SET UP OR FIRST REFERENCE TO RING
	MOVEI	T1,-1(T2)	;BUF LOC-1 IS STORED THERE
	PUSHJ	P,UADRCK	;ENSURE ADVBFF WONT FAULT

	HRRZS	T1,T2
	MOVEI	T3,DEPOND	;ASYNCHRONOUS OUTPUT?
	TLNN	S,IOSTBL	;IF TROUBLE, BLUNDER ON TO RECOVERY REGARDLESS
	TDNN	T3,DEVAIO(F)
	JRST	OUT0		;NO, PROCEED
	PUSHJ	P,UADRCK	;ADR CHECK POINTER TO CURRENT BUF
IFN FTMP&FTKL10,<
	PUSHJ	P,OUCHE##	;CHASE OUT ANY OLD COPY
>
	EXCTUX	<SKIPL @T2>	;IS THE CURRENT BUFFER EMPTY
	JRST	OUTS		;YES, ADVANCE THE BUFFER HEADER
	MOVE	T3,DEVCHR(F)	;IF THIS ISN'T ONE OF NETSER'S
	TLNN	T3,DVCNET	; DEVICES, THEN WE'RE
	POPJ	P,		; DONE, OTHERWISE CALL THE DRIVER
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
	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:	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
	MOVE	T4,DEVMOD(F)	;GET CHARACTERISTICS
	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
	TLNE	T4,DVDSK!DVDTA	;IF DISK OR DTA,
	MOVEI	T1,200		; MAKE SURE WHOLE BUFFER IS THERE
OUT2B:	PUSH	P,T2		;SAVE L(WRDCNT WORD)
	EXCH	T1,T2		;FST ADR INTO T1
	ADDI	T2,(T1)		;TOP ADR IN T2
	PUSHJ	P,LRNGE##	;MAKE SURE WHOLE BUFFER IS OK
	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
	MOVE	T4,DEVMOD(F)	;GET CHARACTERISTICS
	TLNE	T4,DVDSK	;IF DSK AND NOT LAST BUFFER
	TLNE	F,OCLOSB	; THEN NO PARTIAL WORDS
	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
	EXCTUX	<HRRZ T1,@T2>	;START OF NEXT BUF
	PUSH	P,T2
	PUSHJ	P,UADRCK	;MAKE SURE IT'S IN CORE
	PUSHJ	P,BRNGE##
	POP	P,T2
	HRLZI	T1,IOUSE	;FLAG CURRENT BUFFER CONTAINS ACTIVE DATA.
	HRL	W,S		;SAVE CURRENT STATE OF IOACT
	EXCTUU	<IORB	T1,@T2>
	EXCTUU	<HRRM	T1,@U>	;ADVANCE CURRENT BUFFER ADDRESS
IFN FTKL10&FTMP,<
	PUSHJ	P,ISITQ		;NON-TTY, QUEUED PROTOCOL
	  JRST	OUT3		;NO
	PUSHJ	P,CKNBF##	;SET LH(DEVNBF) FOR ALL THE BUFFERS WE CAN DO
	PUSHJ	P,STONBF##	;SAVE SWEEP NUMBER, CPU
	AOS	DEVNBF(F)	;UPDATE RH(DEVNBF)
	PUSHJ	P,CKNBF##	;ADD IT TO LH IF ON RIGHT CPU
>
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)
	PUSHJ	P,CALOUI
	HLRZ	U,DEVBUF(F)	;U TO REL. ADDR. OF BUFFER HEADER
	EXCTUX	<HRRZ	T2,@U>	;T2 TO REL. ADDR. OF 2ND WORD OF BUFFER.
	HRRZ	T1,T2
	PUSHJ	P,UADRCK
	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
	TLZN	S,IOSTBL	;ERROR OCCURED?
	JRST	OUTS		;RETURN TO USER.
	HRL	W,S		;YES.  RESET LH(W)
	JRST	OUT3		;AND TRY AGAIN
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	
	MOVEM	S,DEVIOS(F)	;IN CASE UOUTBF CALLS CORE1
	PUSHJ	P,UOUTBF
	HLRZ	U,DEVBUF(F)
OUTF1:	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>
	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

CALOUI:	TLNE	W,IOACT
	POPJ	P,
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:	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##	;RESTORE J
	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 FTMP,<
	PUSHJ	P,SETCPF##	;GET RUNNING ON RIGHT CPU
				; IF NON-QUEUE PROTOCOL
>
	PUSHJ	P,DMPEV##	;GET EVM FOR THE I/O IF NEEDED
	PUSHJ	P,(T1)		;CALL THE DEVICE ROUTINE TO START THE I/O
	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		;YES, FORCE OUT ALL CURRENT BUFFERS
	HLRZ	U,DEVBUF(F)	;CURRENT OUTPUT BUFFER
	EXCTUU	<HRRM	M,@U>	;SAVE IN RING HEADER
	HRRM	M,DEVOAD(F)	;SAVE AS NEXT BUF TO WRITE
	HRLZI	T1,IOUSE
	EXCTUU	<ANDCAM	T1,@U>	;CLEAR THE USE-BIT
	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

RESDV:	JUMPL	T1,RTM1		;ERROR IF ILLEGAL CHANNEL
	HRRZ	P1,T1		;SETUP CHANNEL NUMBER
	PUSHJ	P,SETUF		;SETUP DDB
	  JRST	RTM1		;IF NONE--RETURN ERROR
	HRLM	P1,.UPMP+.UPCTA	;PUT CHANNEL #
				; (IN CASE OF TROUBLE AND CALL HNGSTP)
	PUSHJ	P,RELEAC	;RESET IT
	JRST	CPOPJ1##	;SKIP RETURN

	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::
IFN FTMP,<
	PUSHJ	P,SETCPF##
>
	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
	PUSHJ	P,JDAADR	;CLEAR DEVICE ASSIGNMENT
	SETZM	(T1)		;U=0 IF NO EXTENDED CHANS OPEN
	PUSH	P,P1		;SAVE CHANNEL
	MOVEI	P1,0		;START AT CHANNEL 0
RELE5A:	PUSHJ	P,NXTCH		;GET NEXT CHANNEL
	  JRST	RELEA4		;FINISHED
	CAIN	T1,(F)		;SAME DEVICE ON ANOTHER CHANNEL?
	JRST	P1POPJ##	;YES, EXIT
	JRST	RELE5A		;LOOP FOR THE NEXT OPEN CHANNEL
RELEA4:	POP	P,P1		;RESTORE P1

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

RELEA9::JUMPE	F,CPOPJ##
	MOVEI	T3,0
	PUSHJ	P,RTIEVM##
	MOVEI	T3,0
	PUSHJ	P,RTOEVM##
	MOVEI	T1,DEPAIO
	ANDCAM	T1,DEVAIO(F)	;CLEAR NON-BLOCKING I/O 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
IFN FTPI,<
	SKIPE	DEVPSI(F)	;SOMEONE PSI'ING ON THIS DEVICE
	PUSHJ	P,PSIRMV##	;YES, REMOVE FROM PSI CHAIN
>; END FTPI
	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 FTMDA,<
	MOVSI	T1,DVCMDA	;SEE IF MDA CONTROLS THIS DEVICE
	TDNE	T1,DEVCHR(F)	;DOES IT?
	PUSHJ	P,RELMDA	;YES, TELL'EM
>;END FTMDA
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 FTSPL,<
	SKIPL	DEVSPL(F)	;IS DEVICE A SPOOLED DISK
>
	TLNE	T2,DVDSK	;IS DEVICE A DSK
	PJRST	CLRDDB##	;YES-RETURN DDB TO STORAGE
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
IFN FTMDA,<
RELMDA:	PUSH	P,T2		;SAVE DEVMOD
	MOVE	T1,DEVNAM(F)	;GET DEVICE NAME
	LDB	T2,PDVTYP##	;GET DEVICE TYPE
	MOVE	T3,J		;GET OWNER'S JOB
	PUSH	P,W		;IPCSER WIPES W
	PUSHJ	P,SNDFIN##	;TELL MDA
	  JFCL			;IGNORE ERROR (SLEEP MAY BE BETTER)
	POP	P,W		;GET BACK PDB
	JRST	T2POPJ##	;RESTORE DEVMOD, AND RETURN
>;END IFN FTMDA
	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
	LDB	T1,PIOMOD##	;I/O MODE
	TRNN	S,IODEND	;EOF
	CAIL	T1,SD		;OR DUMP MODE?
	JRST	TIN1		;YES
	HRRZ	T1,DEVBUF(F)	;BUFFER HEADER ADDRESS
	PUSHJ	P,UADRCK	;LEGAL?
	EXCTUX	<HRRZ T2,(T1)>	;CURRENT USER BUFFER
	MOVEI	T1,-1(T2)	;DEVIOS WORD
	PUSHJ	P,LRNGE##	;LEGAL?
	EXCTUX	<SKIPGE (T2)>	;IF THE BUFFER ISN'T EMPTY,
	EXCTUX	<MOVE S,-1(T2)>	;GET DEVIOS FROM THE BUFFER
TIN1:	MOVEI	T1,DEPIND	;INPUT NOT YET DONE?
	TRNN	S,IOBKTL+IODTER+IODERR+IOIMPM+IODEND
	TDNE	T1,DEVAIO(F)
	JRST	IOPTST		;GIVE FAIL RETURN TO USER
	POPJ	P,


;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)
	JRST	IOPTST		;GIVE FAIL RETURN TO USER
	POPJ	P,

IFN FTPI,<
IOPTST:	AOS	(P)		;INCREMENT FOR FAIL RETURN
	MOVE	J,.CPJOB##	;GET CURRENT JOB NUMBER
	XCT	OKSGNL##	;HAVE PSISER
	POPJ	P,		;NOPE
	PJRST	PSIEDN##	;LET PSISER REPORT ERROR
>
IFE FTPI,<
IOPTST==CPOPJ1##		;IF PSISER NOT INSTALLED
>


;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
	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
	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 FTMP&FTKL10,<
	PUSHJ	P,KLBUFM	;GET BUF OUT OF CACHE
>
	HRRZ	T1,T3		;ADDRESS OF START OF NEXT 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
	TLZ	T3,^-IOSIZ	;ENSURE JUST SIZE
	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
	EXCTXU	<MOVEM	S,-1(T1)>
	EXCTUU	<ANDCAB	T3,(T1)>;CLEAR THE USE BIT AND GET THE SIZE AND
				; ADDRESS OF THE NEXT BUFFER
IFN FTKL10&FTMP,<
	PUSHJ	P,KLBUF		;GET BUF ENDPOINTS OUT OF CACHE
>
	HRRZ	T1,T3		;ADDRESS OF START OF NEXT 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

	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
	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
	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,^-IOSIZ	;CLEAR THE BOOKEEPING BITS FOR ADVEVM
	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
	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
	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 FTMP&FTKL10,<
	PUSHJ	P,KLBUF		;GET BUF ENDS OUT OF CACHE
>
	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

	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
	CAMN	T2,FORCE##	;IF TRY TO FORCE THIS JOB OUT
	JRST	ADVBU2		; GIVE STOP I/O RETURN
	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 BACK ANY EVM
ADVBU3:
IFN FTMP&FTKL10,<
	HRRZ	T1,T3
	PUSHJ	P,OUCHE##	;REMOVE LINE FROM CACHE
>
	JRST	T3POPJ##	;RESTORE T3
;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::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
	ANDI	T2,IOSIZ
	ADDI	T2,(T1)		;TOP OF BUFFER
	SOJA	T1,ZRNGE##	;LET VMSER CHECK THE LIMITS
IFN FTMP&FTKL10,<

;SUBROUTINE TO FIX UP A BUFFER WITH RESPET TO CACHE
; INSURES THAT THE ENDPOINTS OF A BUF ARE OUT OF CACHE
; ENTER T1 = ADDR OF BUFFER (CALL KLBUFM IF IN EVM)
; PRESERVES T3
KLBUFB:	EXCTUX	<HRRZ T4,1(T1)>
	JRST	KLBUF2
KLBUFM:	SKIPA	T4,1(T1)	;GET WORD COUNT
KLBUF:	TDZA	T4,T4		;CHAN DEV - DONT WORRY ABOUT TOP
KLBUF2:	ADDI	T4,1(T1)	;POINT TO END OF BUFFER
	PUSHJ	P,OUCHE##	;CHASE FROM CACHE
	TRNN	T1,3		;S - WORD IN SAME LINE?
	SOJA	T1,KLBUF1	;NO, CHASE PREVIOUS LINE
	ADDI	T1,1		;YES, POINT AT WORDCOUNT
	TRNN	T1,3		;WRDCNT IN SAVE LINE?
KLBUF1:	PUSHJ	P,OUCHE##	;NO, CHASE WRDCNT
	SKIPE	T1,T4		;IF CPU HAS TOP OF BUF IN CACHE
	PJRST	OUCHE##		;REMOVE TOP LINE AND RETURN
	POPJ	P,		;CHAN DEV - DOESN'T HAVE LOC IN CACHE
>
;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
;
;PRESERVES ALL ACS.

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

;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
;
;PRESERVES ALL ACS.

UADRCK::CAML	T1,.UPMP+.UPHSS	;IS ADDRESS IN THE USER HIGH SEGMENT?
	CAML	T1,.UPMP+.UPHSE	; . . .
	CAIG	T1,JOBPFI##	;NO, ABOVE PROTECTED JOBDAT?
	JRST	ADRERR##	;IN HIGH SEG OR PROTECTED JOBDAT, ERROR
	EXCTUX	<SKIP (T1)>	;LEGAL ADDRESS, SEE IF IT EXISTS
	  ERJMP	UUOFLT##	;IF NOT, SEE WHY NOT (MAYBE NEED PFH)
	POPJ	P,		;ADDRESS IS OK TO REFERENCE
;ROUTINE TO ADDRESS CHECK AT ANY LEVEL
;CALL:	HRRZ T1,REL. ADR.
;	PUSHJ P,IADRCK
;	ERROR RETURN(ERROR MESSAGE NOT PRINTED,JOB NOT STOPPED)
;	OK RETURN
;
;PRESERVES ALL ACS.

REPEAT	0,<			;CAN'T USE AT INTERRUPT LEVEL YET
IADRCK::EXCTUX	<SKIP (T1)>	;SEE IF WE CAN TOUCH IT
	  ERJMP	CPOPJ##		;IF WE CAN'T, TAKE ERROR RETURN
IADCKL:	CAIG	T1,JOBPFI##	;IS ADDRESS IN PROTECTED JOBDAT?
	POPJ	P,		;YES, ERROR EVEN IF IT DOES EXIST
	CAML	T1,.UPMP+.UPHSS	;IS ADDRESS IN USER HIGH SEGMENT?
	CAML	T1,.UPMP+.UPHSE	; . . .
	AOS	(P)		;LOW SEG ADDRESS, SUCCESSFUL RETURN
	POPJ	P,		;RETURN
> ;END REPEAT 0

IADRCK::PUSHJ	P,FLTST##	;MAKE SURE IN CORE
	  POPJ	P,		;ITS NOT
IADCKL:	CAILE	T1,JOBPFI##	;ADR. ABOVE PROT. PART OF JOB DATA AREA?
	CAMLE	T1,.UPMP+.UPHVA	;YES, BELOW OR EQUAL TO PROTECT.?
	POPJ	P,		;NO
	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?
	PUSHJ	P,SCDCHK##	;YES, SEE IF SCHED WANTS TO LOOK AROUND
	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:	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
	HRRZ	T2,.UPMP+.UPHVA	;HIGHEST VIRTUAL ADDR
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
	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,.CPJOB##	;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
	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	USRHCU##	;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
	SKIPGE	USRHCU##	;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
;ROUTINE 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
	SKIPN	DEVEVM(F)	; THE DEVICE GOES DIRECT TO MEMORY
				; THROUGH A CHANNEL
	JRST	T2POPJ##	; 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
	MOVEI	T3,1(T1)	;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

	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 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
	MOVEI	T3,DEPMSG
	TDNE	T3,DEVMSG(F)	;CONTROLLED BY MPX?
	JRST	ASSAS5		;YES, ALWAYS FAIL
	NOSCHEDULE		;DISABLE SCHEDULING
	SCNOFF
	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?
	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 FTMDA,<
	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
ASSA2B:
>;END IFN FTMDA
	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
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
>
ASSAS3:
>	;END CONDITIONAL ON FTMTSET
	IORM	T2,DEVMOD(F)	;SET IN USE BITS AGAIN IN CASE
				;  IT IS THE SAME JOB
	AOSA	(P)		;GIVE OK RETURN
ASSA4A:	HRREI	T2,-1		;FLAG AS RESTRICTED DEVICE
ASSAS4:	SCNON
	SCHEDULE		;TURN SCHEDULING ON
ASSAS5:	POPJ	P,		;GIVE ERROR RETURN
;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::CAIL	T1,HIGHXC##	;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
	CAIL	T1,HIGHXC##	;  OR .GT. 17,
	PJRST	DEVSRG		;  MUST BE SIXBIT
	HRLM	T1,.UPMP+.UPCTA
	PUSHJ	P,JDAADR	;GET ADDRESS OF THE CHANNEL TABLE SLOT
	CAIL	T1,.FPMC	;IS IT A LEGAL ADDRESS?
	SKIPN	F,(T1)		;YES, ANY DDB?
	POPJ	P,		;NO
	JRST	CPOPJ1##	;YES
;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.


;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
	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
	CAME	J,.UPMP+.UPJOB	;THIS JOB MAPPED?
	JRST	SETDVF		;NO, SEARCH THE DDB'S
	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:	PUSHJ	P,NXDDB		;POINT AT NEXT DEVICE ON CHAIN
	  JUMPE	F,FPOPJ##
	JRST	SETDV4		;AND TEST IT
;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
	POPJ	P,		;RETURN.

;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 FOR R.H.

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

;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##
	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.
	POPJ	P,		;EXIT.
;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.

;SUBROUTINE TO FIND THE NEXT DDB
;ENTER WITH F=0 TO GET 1ST DDB IN SYSTEM, F=DDB ADDR TO GET NEXT DDB
;RETURNS CPOPJ WITH F=0 IF NO MORE DDBS
;CALL NXDDB TO DO A LOGICAL HLRZ F,DEVSER(F)
;CALL NXDDP TO DO A LOGICAL HLR F,DEVSER(F)
;RETURNS CPOPJ WITH F=DDB ADDRESS IF JUST SWITCHED FROM LOW DDBS
; (DEVLST CHAIN) TO HIGH DDBS (IN SWAPPABLE AREA)
;RETURNS CPOPJ1 NORMALLY, WITH F POINTING AT NEXT DDB
;PRESERVES ALL ACS (EXCEPT F)
NXDDB::	HRRZS	F		;CLEAR LH
NXDDP::	JUMPE	F,[HLRZ F,DEVLST## ;IF START
		JRST CPOPJ1##]	;POINT TO START OF DDBS
	PUSH	P,T1
	HRRZ	T1,F		;SAVE CURRENT F
	HLR	F,DEVSER(F)	;STEP TO NEXT DDB
	TRNE	F,-1		;IS THERE ONE?
	JRST	TPOPJ1##	;YES, GOOD RETURN
	CAMLE	T1,SYSSIZ##	;ALREADY POINTING AT FUNNY SPACE?
	CAIN	T1,DSKDDB##	;IF NO NETWORKS
	SKIPN	.UPMP		;DSKDDB IS END OF CHAIN
				; BUT NO FUNNY SPACE FOR NULL JOB	
	TRZA	F,-1		;YES, NO MORE
	HLR	F,.UPMP+.UPLST	;NO, POINT AT FUNNY SPACE
	JRST	TPOPJ##		;AND RETURN

;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+DD%LOG ;SET UP FOR PHYSICAL SEARCH
	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


;SEARCH LOGICAL NAMES, NOT DDBS IN FUNNY SPACE
DEVCHN::MOVEI	T2,DD%LOG+DD%CHN
	JRST	DDBSRC


;SEARCH PHYSICAL, LOGICAL NAMES, NOT DDBS IN FUNNY SPACE
DEVNFS::MOVEI	T2,DD%LOG+DD%PHY+DD%CHN
	PJRST	DDBSRC
;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
>
IFE 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!FTMPG

;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##-1	;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
;RETURNS T2=PREDESSOR ON PHYSICAL MATCH OF DEVNAM
;
;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
DD%CHN==:1B33
DD%PHO==:1B32	;ON IF PHYSICAL ONLY


DDBSRC:	JUMPE	T1,CPOPJ##	;DEVICE NAME OF 0 NOT ALLOWED
	PUSHJ	P,SAVE1##	;SAVE P1
	HRR	P1,T2		;SAVE FLAGS
	HLRZ	T2,P1		;CHECK FOR PHYSICAL ONLY
	CAIN	T2,PHONLY	;IS IT THERE?
	JRST	[TRO P1,DD%PHO	;DISALLOW LOGICAL NAME MATCHES IN TSTDSK
		 JRST DEVLP7]	;AND CLEAR LOGICAL BIT
	TRNN	P1,DD%CHN	;SEARCH IN DEVLST CHAIN ONLY ?
	TRNN	P1,DD%LOG	;LOGICAL SEARCH?

	JRST	NOLGST		;NO, DON'T SET UP
	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
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
	TDNN	T1,[77,,-1]	;IS THIS A 2-CHAR DEVICE NAME?
	PUSHJ	P,CK2CHR	;YES, CHECK FOR WIERD NAMES
	TRNE	P1,DD%CHN	;DON'T LOOK AT DISKS IF SEARCHING ONLY DEVLST
	JRST	DDSRC0
	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
DDSRC0:
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"
	MOVSI	T3,DVDSK
DDSRC2:	HLR	F,DEVLST##	;GET START OF CHAIN
	DDBSRL
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	DDSRCV		;CLEAR SYS BITS AND GOOD RETURN
GETPHY:	TRNN	P1,DD%PHY	;PHYSICAL SEARCH?
	JRST	DDSRC3		;NO, SKIP OVER THIS
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)
	TRNN	P1,DD%LOG	;DO WE CARE ABOUT LOGICAL NAMES?
	JRST	DDSRCW		;NO, WE FOUND A PHYSICAL NAME
	TLNN	P1,-1		;FOUND DDB ALREADY?
	HRL	P1,F		;SAVE THIS ADDRESS
DDSRC3:	HRRZ	T2,F		;SAVE PREDECESSOR
	PUSHJ	P,NXDDP		;POINT AT NEXT DEVICE ON CHAIN
	  TRNN	P1,DD%CHN	;DON'T LOOK IN FUNNY SPACE IF SEARCHING
	TRNN	F,-1		;  ONLY DEVLST CHAIN OR IF WE RUN OUT
	CAIA			;  OF DDB'S
	JRST	DDSC2A		;NO
	DDBSRU
	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
	JUMPE	J,CPOPJ##	;FAIL IF NOT LOGGED IN
	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
DDSRCV:	TLZ	F,-1
DDSRCW:	DDBSRU
	JRST	CPOPJ1##
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!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
	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
	MOVE	T2,(P)		;GET DEVICE NAME
	TRNE	T2,77		;UNIT NUMBER PRESENT?
	LSH	T1,-3		;YES, RIGHT JUSTIFY STATION NUMBER
	SKIPN	T2,T1		;IF NN IS ZERO PUT STA # IN T2
	MOVE	T2,JBTLOC##	;USE CENTRAL SITE NMBER
	JRST	TPOPJ1##	;GOOD RETURN.
>
IFE FTNET,<
	TRNN	T1,50		;CHECK FOR
	TRNN	T1,20		; 0-7
	JRST	TPOPJ##		;NOT 0-7
	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
	DDBSRL
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
;STILL IN FTGSRC!FTNET!FTSFD CONDITIONAL
	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
	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
	DDBSRU
	JRST	TPOPJ1##	;F SET UP

DVSNXT:	PUSHJ	P,NXDDB		;POINT AT NEXT DEVICE 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
	DDBSRU
	JRST	TPOPJ1##	;GIVE GOOD RETURN WITH DDB IN F

DVSFL:	DDBSRU
	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


;ROUTINE TO CHECK A DEVICE NAME TO SEE IF IT IS GENERIC.
;CALL:	MOVE	T2,SIXBIT NAME
;	PUSHJ	P,GNRCDV
;	RETURN HERE IF GENERIC
;	RETURN HERE IF NOT

GNRCDV:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSHJ	P,SAVT##	;  AND T1-T4
	PUSH	P,F		;  AND F
	MOVE	T1,T2		;MOVE NAME TO T1
	PUSHJ	P,DEVLG		;LOGICAL NAME?
	  TLNN	T1,770000	;NO, SIXBIT ARGUMENT?
	JRST	FPOPJ1##	;NOT GENERIC IF LOGICAL NAME OR NOT SIXBIT
	PUSHJ	P,LNMTST##	;IS IT A PATH. LOGICAL NAME?
	  TRNE	T1,77		;NO, IS IT DEVNNN?
	JRST	FPOPJ1##	;NOT GENERIC IF EITHER
	PUSHJ	P,CK2CHR	;CONVERT 2 CHARACTER NAMES TO 3
	CAME	T1,[SIXBIT/TTY/] ;GENERIC TTY?
	PUSHJ	P,ALIASD##	;NO, GENERIC DSK?
	JRST	FPOPJ##		;YES, GIVE NON-SKIP RETURN
	TRNE	T1,-1		;DEV
	TRNE	T1,7777		;  OR DEVNN?
	PUSHJ	P,CHKGEN	;YES, CHECK FOR GENERIC
	  JRST	FPOPJ1##	;NOT FOUND
	JRST	FPOPJ##		;FOUND
;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::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,.JDAT+JOBFF##	;P1:=FIRST FREE LOCATION + 1
	ADDI	P1,1
	HRRZ	P2,P1
	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
	ADDI	T1,0(P2)	;ADD LOCATION OF 1ST BUFFER
	SUBI	T1,2		;READJUST FOR USRREL COMPARISEN
	TLZE	T1,-1		;CHECK IF HE WENT OVER 256K
	PJRST	ADRERR##	;BETTER NOT ALLOW THAT!
	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,.CPREL##	;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:	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,.JDAT+JOBFF##
	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,.JDAT+JOBFF## ;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
	TDNN	T4,DEVMOD(F)	;IS IT?
	POPJ	P,		;NOT A DISK
	LDB	T2,PDYBFN##	;DEFAULT PECIFIED?
	JUMPN	T2,CPOPJ##	;RETURN IF SO
	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::PUSHJ	P,UADRCK
	PUSH	P,T1		;SAVE FIRST BUFFER ADR.
	EXCTUX	<HLRZ T2,@T1>	;T2 18-35=SIZE
	ANDI	T2,IOSIZ
	JUMPE	T2,TPOPJ##	;WORD COUNT=0 IS ILLEGAL
	ADD	T2,T1
	PUSHJ	P,LRNGE##
	MOVE	T1,T2
	POP	P,T2		;RESTORE FIRST ADR.
	NOSHUFF			;NO SHUFFLING
	HRLI	T2,1(T2)
	ADDI	T2,2
	EXCTXU	<SETZM -1(T2)>	;CLEAR THIRD 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,SAVE3##	;SAVE P1 TO PRESERVE PHYSICAL BIT
	PUSH	P,T1		;SAVE ADR. OF SUB.
	PUSH	P,M		;SAVE M
	HLRZ	P3,.UPMP+.UPCTA
	HRRZ	P2,USRHCU##	;HIGHEST CHANNEL NUMBER IN USE
	CAILE	P2,17		;BIGGER THAN MAX NUMBER OF CHANNELS ?
	STOPCD	IOALL2,DEBUG,JAC,	;++JOB DATA AREA CLOBBERED
	MOVNS	P2
	MOVSI	P2,-1(P2)
	HRRI	P2,USRJDA##
	MOVEI	P1,0
	MOVSI	M,400000	;DON'T RETURN ERROR CODES TO USER
IOALL0:	HRRZ	T1,.UPMP+.UPCTA
	CAILE	P1,17
	JUMPE	T1,IOALL2
	SKIPN	F,(P2)		;GET NEXT DDB ADR., IS IT IN USE?
	JRST	IOALL1		;NO, KEEP GOING
	MOVE	S,DEVIOS(F)
	HRLM	P1,.UPMP+.UPCTA
	MOVE	T4,DEVSER(F)	;SETUP ADR. OF DEV. DISP. TABLE
	LDB	T1,PJOBN##	;GET JOB NUMBER WHICH JOB IS ASSIGNED TO
	CAMN	T1,.CPJOB##	;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:	AOS	P1
	AOBJN	P2,IOALL0	;DECREMENT USER CHANNEL NUMBER
	CAILE	P1,20
	JRST	IOALL2
	HRRZ	P2,.UPMP+.UPCTA
	JUMPE	P2,IOALL2
	HRLI	P2,-HIGHXC+20
	MOVEI	P1,20
	JRST	IOALL0
IOALL2:	HRLM	P3,.UPMP+.UPCTA
	POP	P,M		;RESTORE M & RETURN RESTORING T1 TOO
	MOVE	J,.CPJOB##	;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:	PUSHJ P,SETUSR


SETUSR::HLRZ	T1,.JDAT+JOBSA##	;RESET FIRST FREE LOC. FOR THIS JOB
	MOVEM	T1,.JDAT+JOBFF##
CLRUSR::SETZM	.JDAT+JOBENB##	;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 STORES IN DDB AT CLOCK LEVEL
;NEEDED SINCE NO INTERLOCK ON PI7 AND UUO LEVEL ON OTHER CPU
STORS7::
IFE FTMP,<
	MOVEM	S,DEVIOS(F)
>
IFN FTMP,<
	MOVSI	T2,IOW
	EXCH	S,DEVIOS(F)
	TLNE	S,IOW
	IORM	T2,DEVIOS(F)
	MOVE	S,DEVIOS(F)
>
	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,<
	MOVEI	T1,DEPMSG	;LOAD UP THE MESSAGE BIT
	TDNN	T1,DEVMSG(F)	;CONTROLLED BY MSGSER?
	JRST	TPOPJ##		;NO, ALL DONE HERE
	PUSH	P,F		;YES, SAVE F FOR A MOMENT
	HRRZ	F,DEVXTR(F)	;ADDRESS OF MPX DDB
	PUSHJ	P,SETHNG	;DO GOOD THINGS FOR IT TOO
	POP	P,F		;RESTORE DEVICE DDB ADDRESS
> ;END FTMSGSER
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
IFN FTMP,<
;ROUTINE TO STORE S IN A RACE-FREE MANNER
;GETS THE DEVICE INTERLOCK IF NOT ON PI-LEVEL
LKSTRS::CONSO	PI,PI.IPA-PI.IP7
	JRST	LKSTR1
	PIOFF
	MOVEM	S,DEVIOS(F)
	PJRST	ONPOPD##
LKSTR1:	MOVEM	S,DEVIOS(F)
	POPJ	P,
>
DEVCHK::HLRZ	F,HNGLST##
DEVCK0:
IFN FTMP,<
	PUSHJ	P,CHKCPI##	;DEVICE ON THIS CPU?
	  JRST	DEVCK2		;NO, IGNORE IT
	JUMPL	T4,DEVC0A	;DUAL-PORTED?
	PUSHJ	P,ISITQ		;YES, QUEUED PROTOCAL?
	  JRST	DEVC0A
	CAIN	T1,7		;YES, IO START ON THIS CPU?
	MOVEI	T1,0	
	CAME	T1,.CPCPN##
	JRST	DEVCK2		;NO, LET OTHER CPU HANDLE IT
>
DEVC0A:	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 OFF-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 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;PUTS THE J POINTER (C(DEVCTR)) IN AC ITEM.


IOSET::	MOVE	J,DEVCTR(F)	;J:=J POINTER=C(DEVCTR)
	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
	EXCTUX	<HRRZ	J,1(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
	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)
	MOVE	S,DEVIOS(F)	;SET UP "S" SINCE WE JUST CHANGED DEVIOS
	MOVSI	T1,DVTTY	;TTY DEVICE TYPE BIT
	TDNN	T1,DEVMOD(F)	;TTY?
	POPJ	P,
	HRRZ	U,DDBLDB##(F)	;YES, SET UP U
	PJRST	UUOLDB##	; AND TELL THE NETWORK



;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
	SKIPN	DEVEVM(F)	;DOES THIS DDB HAVE EVM?
	STOPCD	.,STOP,NEV,	;++NO EVM
	HLRZ	T2,(T1)		;BUFFER SIZE
	ANDI	T2,IOSIZ	;CLEAR BOOKEEPING BITS
	ADDI	T2,(T1)		;LAST WORD TO CLEAR
	HRLI	T1,1(T1)	;MAKE A BLT POINTER
	ADDI	T1,2
	SETZM	-1(T1)		;ZERO THE FIRST WORD OF THE BUFFER
	BLT	T1,(T2)		;ZERO THE BUFFER

NEWBF3:	MOVSI	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
;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
	AOJA	J,STOSQE	;IN FIRST WORD OF BUFFER
STOSQD::TLZN	S,IOFST		;FIRST CALL?
	JRST	STOSQF		;NO
	PUSHJ	P,NEWBUF	;YES, CLEAR BUFFER,SET ITEM COUNT
	POPJ	P,		;ADDRESS CHECK
STOSQF:	HRRZ	T2,DEVIAD(F)	;REL. ADR. OF BUFFER
	HRRZ	J,DEVPTR(F)	;J:=C(DEVPTR 18-35) -
				; C(DEVIAD 18-35) -1
	SUBI	J,1(T2)
STOSQE:	HRRM	J,1(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

;THIS PAIR OF ROUTINES MAY BE USED BY ROUTINES
; THAT ARE CALLED FROM BOTH UUO-LEVEL AND INTERRUPT LEVEL
; TO DETERMINE IF THEY MAY BLOCK. (IE ARE AT LOGICAL
; UUO LEVEL)

UUOLVL::PUSH	P,T1		;ROUTINE TO SKIP IF AT UUO LEVEL
	HRRZ	T1,P		;GET THE ADDRESS OF OUR STACK
	CAMLE	T1,SYSSIZ##	; AND IF IT'S NOT IN THE SYSTEM'S
	AOS	-1(P)		; LOW SEG WE ARE AT UUO LEVEL
	JRST	TPOPJ##

INTLVL::PUSH	P,T1		;ROUTINE TO SKIP IF AT LOGICAL INTERRUPT LEVEL
	HRRZ	T1,P		;GET THE ADDRESS OF OUR STACK,
	CAMG	T1,SYSSIZ##	; AND IF IT'S IN THE SYSTEM LOW SEG
	AOS	-1(P)		; WE ARE AT INTERRUPT OR CLOCK LEVEL
	JRST	TPOPJ##
	XLIST
	$LIT
	LIST
UUOEND::END