Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99q-bb - uuocon.x23
There is 1 other file named uuocon.x23 in the archive. Click here to see a list.
TITLE 	UUOCON - UUO HANDLER AND UUO+IO ROUTINES - V2075
SUBTTL /CHW/TL/RCC/CMF/PH/GDR/DAL/EVS/TW/JMF/DRT/JBS/RCB  16-MAY-89

	SEARCH	F,S,DEVPRM,BTSPRM
	$RELOC
	$HIGH

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

.CPYRT<1973,1988>


XP VUUOCN,2075	;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::HRLZ	M,.USMUO	;UUO OP CODE
	IOR	M,.USMUE	;RESULTS OF THE EFFECTIVE ADDRESS CALCULATION
	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
	MOVE	T1,.USMUO	;MUUO FLAGS
	TLNE	T1,(XC.USR)	;DON'T PUSH FLAGS IF EXEC MODE UUO
	PUSH	P,.USMUO	;PUSH FLAGS
	PUSH	P,.USMUP	;SAVE RETURN ON PUSH DOWN LIST
	PUSHJ	P,FNDPDS##	;FIND JOB'S PDB
	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,.USCTA	;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
>
IFN FTXMON,<
	TRNE	M,^-17		;ONLY IF A REAL EFFECTIVE ADDRESS
	TRNN	T3,UU.PCS	;DOES UUO DO ITS OWN SECTION ADJUSTMENTS?
	JRST	DISP4		;YES, DON'T CHEAT IT
	PUSH	P,T1		;NO, SAVE T1
	LDB	T1,[POINT SECWID,M,SECPOS] ;GET SECTION TO BE USED
	PUSHJ	P,STPCS##	;SET IT UP AS PCS
	DPB	T1,[POINT SECWID,.USUPF,SECPOS] ;SAVE AS UUO PCS (FOR CONTEXT SWITCHING)
	POP	P,T1		;RESTORE AC CONTENTS
DISP4:
> ;END OF IFN FTXMON
	TRNE	T3,UU.MSK	;CHECK ARGUMENTS FOR VALIDITY?
	PUSHJ	P,UUOCHK##	;YES (DONT ALLOW PAGE FAULT IN UUO PROCESSING)
IFN FTXMON,<
	HRLI	U,(MCSEC1)	;ASSUME UUO CAN BE EXECUTED IN SECTION 1
	TRNE	T3,UU.SE1	;CAN UUO BE EXECUTED IN SECTION 1?
	XJRST	[MCSEC1+.+1]	;YES, GET INTO SECTION 1
> ;END IFN FTXMON
	MOVE	T2,.USMUO	;UUO FROM SYSTEM?
	TLNN	T2,(XC.USR)
	JRST	(U)		;YES
	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::XJRST	[0+.+1]		;DO THE REST OF THIS IN SECTION 0

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,<
	CAIN	T1,NETDSP##	;IS IT A NETWORK DEVICE?
	JRST	[PUSHJ	P,ZAPNET##	;YES, DISCONNECT IF NO LONGER NEEDED
		JRST	UUOND1]		;RETURN TO USER IN EITHER CASE
> ;END IFN 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,.USMUO	;OR INTO 40 SO UUO WATCHERS SEE IT
	SETZM	.USPFU		;CLEAR COUNT OF PAGE FAULTS IN THIS UUO
	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 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
>
	XCT	PINOJN##	;SKIP IF CANNOT GRANT INTERRUPTS
	PUSHJ	P,PSIGEN##	;CAN, GIVE ANY TO THE USER
	MOVE	P1,JBTSTS##(J)	;STATUS WORD FOR CURRENT USER
				; ON THIS CPU
	TRNN	P1,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
	SKIPGE	T4,.JDAT+JOBFDV##	;GET NEW PC
	JRST	USRXJI		;NO--GO DO .JBINT

	MOVEM	T2,.JDAT+JOBOPC##	;STORE INTERRUPTED PC
	HRRM	T4,(P)		;STORE NEW PC
	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,DOINT1##	;YES--SWITCH PC


USRXCT:	MOVEI	P1,UTRP		;CLEAR
	ANDCAB	P1,JBTSTS##(J)	;  TRAP FLAG
;HERE TO RESTORE USER HARDWARE STATE AND JUMP TO USER
USRXNT:	PUSHJ	P,ZAPEPL##	;RESET EXTENDED PDL IF ANY USED
	TRNE	P1,JS.NTO	;NON-BLOCKING TTY I/O?
USRXNX::PUSHJ	P,TTMORE##	;YES, DO IT NOW
	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,.USMUO	;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,.USMUO	;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
	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,,URELEA		;(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.PCS+UU.EA+UU.CP1,,UU.CP1+3	;CALL,INIT
	0,,0			;42,43
	0,,0			;44,45
	0,,UU.CP1		;46,CALLI
	UU.PCS+UU.CP1+UU.EA+3,,UU.PCS+UU.CP1+UU.SE1+UU.EA	;OPEN,TTCALL
	0,,0			;52,53
	0,,UU.PCS+UU.CP1+UU.LER	;54,RENAME
	UU.PCS+UU.CP1,,UU.PCS+UU.CP1		;IN,OUT
	UU.CP1,,UU.CP1		;SETSTS,STATO
	UU.PCS+UU.CP1,,UU.CP1	;GETSTS,STATZ
	UU.CP1,,UU.CP1		;INBUF,OUTBUF
	UU.PCS+UU.CP1,,UU.PCS+UU.CP1		;INPUT,,OUTPUT
	UU.CP1,,UU.CP1		;CLOSE,,RELEASE
	UU.CP1,,UU.PCS+UU.CP1	;MTAPE,UGETF
	UU.PCS+UU.CP1,,UU.PCS+UU.CP1		;USETI,USETO
	UU.PCS+UU.CP1+UU.LER,,UU.PCS+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 UUOS MUST BE ADDED AT END SINCE CALLI DEPENDS ON POSITION IN TABLE.
;CUSTOMERS SHOULD ADD UUOS IN CNAMES MACRO SO CALLI ADDRESS WILL BE NEGATIVE.
;IN THIS WAY BOTH DIGITAL AND ITS CUSTOMERS CAN ADD UUOS WITHOUT CONFLICT,
;DIGITAL GOING POSITIVE, CUSTOMERS GOING NEGATIVE.


DEFINE CNAMES <
	XLIST
IFN FTPATT,<
X	CPOPJ,CPOPJ##,UU.CP1            ;(-3) PLACE FOR CUSTOMERS TO PATCH UUOS
X	CPOPJ,CPOPJ##,UU.CP1            ;(-2) PLACE FOR CUSTOMERS TO PATCH UUOS
> ;END IFN FTPATT
X	LIGHTS,LIGHTS,UU.CP1		;(-1) SET LIGHTS ON CONSOLE
> ;END DEFINE CNAMES


DEFINE NAMES,<
X	RESET,RESET,UU.CP1		;(000) RESET IO
X	DDTIN,DDTIN##,UU.CP1+UU.SE1+UU.EA+25 ;(001)READ DDT CHARACTER
X	SETDDT,SETDDT,UU.CP1		;(002) SET DDT ADDRESS IN JOB DATA AREA
X	DDTOUT,DDTOUT##,UU.CP1+UU.SE1+UU.EA+25 ;(003) SEND DDT CHARACTER
X	DEVCHR,UDVCHR,UU.CP1		;(004) READ DEVICE CHARACTERISTICS
X	DDTGT,CPOPJ##,UU.CP1		;(005) GET DDT MODE
X	GETCHR,UDVCHR,UU.CP1		;(006) READ DEVICE CHARACTERISTICS
X	DDTRL,CPOPJ##,UU.CP1		;(007) RELEASE DDT MODE
X	WAIT,WAIT,UU.CP1		;(010) WAIT FOR I/O TO STOP
X	CORE,CORUUO##,UU.CP1		;(011) CHANGE CORE ALLOCATIONS
X	EXIT,EXIT,UU.CP1		;(012) CAUSE PROGRAM TO EXIT
X	UTPCLR,UTPCLR,UU.CP1		;(013) CLEAR DECTAPE DIRECTORY
X	DATE,UDATE,UU.CP1		;(014) READ DATE IN DECSYSTEM-10 FORMAT
X	LOGIN,ULOGIN,UU.MEA+UU.CP1	;(015) LOGIN JOB
X	APRENB,APRENB,UU.CP1		;(016) ENABLE APR TRAPPING
X	LOGOUT,LOGOUT,UU.CP1		;(017) TERMINATE JOB
X	SWITCH,SWITCH,UU.CP1		;(020) RETURN CONSOLE DATA SWITCHES
X	REASSI,REASSI##,UU.CP1		;(021) REASSIGN DEVICE TO ANOTHER JOB
X	TIMER,TIMER,UU.CP1		;(022) READ TIME OF DAY (JIFFIES)
X	MSTIME,MSTIME,UU.CP1		;(023) READ TIME OF DAY (MILLISECONDS)


;CONTINUED ON NEXT PAGE
X	GETPPN,GETPPN,UU.CP1		;(024) RETURN PROJECT-PROGRAMMER NUMBER
X	TRPSET,TRPSET,UU.LEA+UU.CP1	;(025) SET PI TRAP LOC, AND USER I/O
X	TRPJEN,UUOERR##,UU.CP1		;(026) DISMISS INTERRUPT TO EXEC MODE
X	RUNTIM,JOBTIM,UU.CP1		;(027) RETURN TOTAL JOB RUNNING TIME
X	PJOB,JOBNO,UU.CP1		;(030) RETURN JOB NUMBER
X	SLEEP,SLEEP,UU.CP1		;(031) SLEEP FOR N SECONDS
X	SETPOV,SETPOV,UU.CP1		;(032) SET PUSH DOWN OVERFLOW TRAP
X	PEEK,UPEEK,UU.CP1		;(033) READ A WORD OF MONITOR CORE
X	GETLIN,GETLN,UU.CP1		;(034) READ CONTROLLING JOB'S TTY NAME
X	RUN,URUN##,UU.EA+6+UU.CP1	;(035) RUN PROGRAM FROM DEV:FILE[PATH]
X	SETUWP,SETUWP,UU.CP1		;(036) SET/CLEAR USER WRITE PROTECT
X	REMAP,REMAP,UU.CP1		;(037) REMAP TOP OF LOW SEG TO HIGH SEG
X	GETSEG,UGTSEG##,UU.EA+6+UU.CP1	;(040) GET SHARABLE HIGH SEG
X	GETTAB,GETTAB,UU.CP1		;(041) GET EXEC ADDRESS OF A JOB TABLE
X	SPY,USPY##,UU.CP1		;(042) MAP MONITOR'S LOW SEG
X	SETNAM,SETNAM,UU.CP1		;(043) SETNAME OF THIS PROGRAM
					;LAST CALLI IN 4.50

X	TMPCOR,TMPUUO##,UU.EA+UU.CP1+2 	;(044) TEMPORARY FILE STORAGE UUO (CCL)
X	DSKCHR,DSKCHR##,UU.CP1+UU.LEA   ;(045) RETURN DISK CHARACTERISTICS
                                        ;LAST CALLI IN 4.72

X	SYSSTR,SYSTUU##,UU.CP1          ;(046) RETURN NEXT STRUCTURE IN SYSTEM
X	JOBSTR,JOBSTR##,UU.LEA+UU.CP1	;(047) RETURN NEXT STRUCTURE IN JOB S/L
X	STRUUO,STRUUO##,UU.CP1+UU.LEA	;(050) PERFORM STRUCTURE FUNCTIONS
X	SYSPHY,SYSPHY##,UU.CP1		;(051) RETURN PHYSICAL DISK UNITS
X	FRECHN,CPOPJ##,UU.CP1		;(052) RETURN FIRST FREE I/O CHANNEL
X	DEVTYP,UDVTYP,UU.CP1		;(053) EXTENDED DEVICE CHARACTERISTICS


;CONTINUED ON NEXT PAGE
X	DEVSTS,DEVST,UU.CP1		;(054) DEVSTS
X	DEVPPN,DEVPPU,UU.CP1		;(055) RETURN PPN FOR DEVICE
X	SEEK,CPOPJ##,UU.CP1		;(056) SEEK
					;LAST CALLI IN 5.01

X	RTTRP,RTTRP##,UU.CP1+UU.EA+4	;(057) REAL TIME TRAP
X	LOCK,LOKJOB##			;(060) LOCK JOB IN CORE
X	JOBSTS,UJBSTS##,UU.CP1+UU.SE1	;(061) READ STATUS OF JOB AND ITS PTY
X	LOCATE,ULOCAT,UU.CP1+UU.SE1	;(062) SET STATION FOR SPOOLING
X	WHERE,UWHERE,UU.SE1		;(063) READ STATION FOR DEVICE
X	DEVNAM,UDVNAM,UU.CP1		;(064) GET PHYSICAL DEVICE NAME
X	CTLJOB,CTLJOB##,UU.CP1		;(065) FIND CONTROLLER OF THIS JOB
X	GOBSTR,GOBSTR##,UU.CP1+UU.LEA	;(066) GENERALIZED JOBSTR
					;LAST CALLI IN 5.02

X	FOO,CPOPJ##,UU.CP1		;(067) FOO
X	FOO,CPOPJ##,UU.CP1		;(070) FOO
X	HPQ,HPQ##,UU.CP1		;(071) SET HIGH PRIORITY QUEUE
X	HIBER,HIBUUO,UU.CP1		;(072) SLEEP UNTIL INTERRUPT
X	WAKE,WAKUUO,UU.CP1		;(073) WAKE UUO
X	CHGPPN,CHGPPN,UU.CP1		;(074) CHANGE PPN
X	SETUUO,SETUUO##,UU.CP1		;(075) SET SYSTEM/JOB PARAMETERS
X	DEVGEN,DEVGEN,UU.CP1		;(076) DEVICE GENERIC NUMBER UUO
X	OTHUSR,GETPPL,UU.CP1		;(077) CHECK FOR OTHER JOBS SAME PPN
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+UU.SE1	;(104) ATTACH OR DETACH JOBS
X	DAEFIN,DAEFIN,UU.LEA+UU.CP1	;(105) DAEMON FINISHED
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.,CPOPJ##			;(111) PERFORMANCE METERING (OBSOLETE)
X	MTCHR.,MTACHR##,UU.CP1		;(112) GET MAGTAPE CHARACTERISTICS
X	JBSET.,UJBSET##,UU.EA+2+UU.CP1	;(113) JOB SETUUO
X	POKE.,POKE,UU.CP1+UU.EA+3	;(114) CHANGE MONITOR
X	TRMNO.,TRMNO##,UU.CP1+UU.SE1	;(115) TERMINAL NUMBER FOR JOB
X	TRMOP.,TRMOP##,UU.LEA+UU.CP1+UU.SE1 ;(116) TERMINAL OPERATIONS UUO
X	RESDV.,RESDV,UU.CP1		;(117) RESET DEVICE OR CHANNEL
X	UNLOK.,UUNLOK##,UU.CP1+UU.SE1	;(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 OPR 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) PDP11 COMMUNICATIONS
X	MTAID.,MTARID##,UU.CP1		;(126) SET MAGTAPE REELID
X	IONDX.,UIONDX,UU.CP1		;(127) RETURN IO INDEX
X	CNECT.,CONECT##,UU.CP1+UU.EA+1	;(130) CONNECT A DEVICE TO MPX CHANNEL
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 PI SYSTEM
X	PISYS.,PISYS##,UU.CP1		;(136) MANIPULATE PI 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+UU.SE1	;(142) IPCF READ
X	IPCFS.,UIPCFS##,UU.CP1+UU.SE1	;(143) IPCF SEND
X	IPCFQ.,UIPCFQ##,UU.CP1+UU.SE1	;(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) SET/READ SCHEDULER PARAMETERS
X	ENQ.,UENQ##,UU.CP1		;(151) ENQUEUE
X	DEQ.,UDEQ##,UU.CP1		;(152) DEQUEUE
X	ENQC.,UENQC##,UU.CP1		;(153) ENQ CONTROLLER


;CONTINUED ON NEXT PAGE
X	TAPOP.,UTAPOP##,UU.LEA+UU.CP1	;(154) PERFORM MAGTAPE FUNCTIONS
X	FILOP.,FILOP,UU.CP1+UU.LEA	;(155) PERFORM FILE OPERATIONS
X	CAL78.,CALL78##,UU.CP1		;(156) DAS78 COMMINUCATIONS
X	NODE.,NODE.U##,UU.CP1+UU.SE1	;(157) ANF-10 NETWORK FUNCTIONS
X	ERRPT.,UERRPT##,UU.CP1		;(160) ERROR REPORTING UUO FOR DAEMON
X	ALLOC.,CPOPJ##,UU.CP1		;(161) OBSOLETE
X	PERF.,UPERF.,UU.CP1		;(162) PERFORMANCE ANALYSIS UUO
					;LAST UUO IN 6.02

X	DIAG.,DIAUUO,UU.CP1+UU.SE1	;(163) DIAGNOSTIC UUO
X	DVPHY.,UDVPHY,UU.CP1		;(164) RETURN DEVICE NAMES
X	GTNTN.,GTNTN,UU.CP1+UU.SE1	;(165) GET THE NETWORK TTY NUMBER
X	GTXTN.,GTXTN,UU.CP1+UU.SE1	;(166) GET THE -10 TTY NAME
X	ACCT.,ACCT,UU.CP1		;(167) ACCOUNTING UUO
X	DTE.,UDTE##,UU.CP1		;(170) MANIPULATE DTE DEVICES
X	DEVOP.,UDEVOP,UU.CP1+UU.LEA	;(171) PERFORM DEVICE FUNCTIONS
X	SPPRM.,SPPRM,UU.CP1+UU.LEA	;(172) SET SPOOLING PARAMETERS
					;LAST UUO IN 6.03

X	MERGE.,UMERGE##,UU.CP1+UU.EA+6	;(173) MERGE .EXE FILE INTO CORE IMAGE
X	UTRP.,UUTRP,UU.CP1+UU.LER	;(174) SET USER TRAPPING
X	PIJBI.,PIJOB##,UU.CP1		;(175) GENERATE CROSS JOB PI INTERRUPTS
X	SNOOP.,SNOOP,UU.CP1		;(176) SNOOP. UUO
X	TSK.,UTSK##,UU.CP1		;(177) ANF-10 TASK COMMUNICATIONS
X	KDP.,UKDP##,UU.CP1		;(200) MANIPULATE KDP DEVICES
					;LAST UUO IN 7.00

X	QUEUE.,GLXINF##,UU.CP1+UU.SE1	;(201) COMMUNICATE WITH SYSTEM PIDS
X	RECON.,RECON,UU.CP1+UU.SE1	;(202) PERFORM SYSTEM RECONFIGURATION
					;LAST UUO IN 7.01

X	PITMR.,PITMR##,UU.CP1		;(203) SET PI TIMER
X	ACCLG.,ACCLOG,UU.CP1		;(204) LOGIN INTERLOCK
X	NSP.,SCUUUO##,UU.CP1+UU.SE1	;(205) DECNET I/O
X	NTMAN.,NTMAN##,UU.CP1+UU.SE1	;(206) DECNET NETWORK MANAGEMENT
X	DNET.,DNET##,UU.CP1+UU.SE1	;(207) DECNET INFORMATION
X	SAVE.,USAVE##,UU.CP1+UU.EA+6	;(210) SAVE CORE IMAGE ON DISK
X	CMAND.,CMAND,UU.CP1		;(211) USER DEFINABLE COMMANDS
X	PIBLK.,PIBLK##,UU.CP1		;(212) READ PI INTERRUPT BLOCK
X	SCS.,SCS##,UU.CP1+UU.SE1	;(213) SCS. UUO
X	SEBLK.,USEBLK##,UU.CP1		;(214) READ SYSTEM ERROR BLOCK (DAEMON)
					;LAST UUO IN 7.02

X	CTX.,CTXUUO##,UU.CP1!UU.SE1	;(215) MANIPULATE JOB CONTEXTS
X	PIFLG.,PIFLG##,UU.CP1		;(216) SET/READ PI FLAGS
X	IPCFM.,UIPCFM##,UU.SE1		;(217) IPCF MULTI-PURPOSE UTILITY
X	LLMOP.,ULLMOP##,UU.CP1+UU.SE1	;(220) PERFORM ETHERNET DIAGNOSTICS
X	LATOP.,.LATOP##,UU.SE1		;(221) PERFORM LAT FUNCTIONS
X	KNIBT.,UKNIBT##,UU.CP1!UU.SE1	;(222) PERFORM KLNI BOOT FUNCTIONS
X	CHTRN.,UCHTRN##,UU.CP1		;(223) CHARACTER TRANSLATION
X	ETHNT.,UETHNT##,UU.CP1!UU.SE1	;(224) ETHERNET I/O
X	ENTVC.,ENTVC,UU.CP1!UU.SE1	;(225) MANIPULATE PROGRAM ENTRY VECTORS
X	NETOP.,NETOP,UU.CP1!UU.SE1	;(226) MULTI-PURPOSE NETWORK FUNCTIONS
					;LAST UUO IN 7.03

X	DDP.,DDPUUO##,UU.CP1		;(227) MANIPULATE DDP DEVICES
X	SEGOP.,SEGOP##,UU.CP1		;(230) MANIPULATE HIGH SEGMENTS

;***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
	MOVSI	T1,(JS.SAC)	;BIT TO TEST
	TDNE	T1,JBTST2##(J)	;DOING AN AUTO-RESTORE ON PROGRAM EXIT?
	JRST	MONRET		;YES, DON'T TYPE EXTRA JUNK
	PUSHJ	P,TTYFUW##	;FIND TTY FOR CURRENT JOB
				; SET J TO JOB NO.,U TO LDB ADDRESS
				; 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::MOVSI	T1,(JS.SAC)	;BIT TO TEST
	TDNE	T1,JBTST2##(J)	;DOING AN AUTO-RESTORE ON PROGRAM EXIT?
	JRST	[PUSHJ	P,TTYFNU##	;FIND TTY
		 MOVSI	T1,(UP.DST)	;GET HNGSTP BIT
		 IORM	T1,.USBTS	;LIGHT IT FOR STOP1C PROCESSING
		 JUMPE	U,MONRE1	;DON'T TOUCH LDB IF DETACHED
		 MOVSI	T1,LDLCOM##	;COMMAND MODE BIT
		 SE1XCT <ANDCAM T1,LDBDCH##(U)> ;CLEAR IT (STOP COMCON)
		 JRST	MONRE1]		;DON'T TYPE OUT OR ALLOW COMMANDS
	PUSHJ	P,TTYFUW##	;WAIT FOR A TTY TO TYPE ON
	PUSHJ	P,PRRSP3##	;NO--PRINT [XXX], CRLF, DOT
	PUSHJ	P,TTYSTC##	;PUT TTY INTO COMMAND MODE
MONRE1:	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 FTSCA,<
	PUSHJ	P,SCSRST##	;CALL SCSUUO ON RESET
>; END IFN FTSCA
IFN FTENET,<
	PUSHJ	P,ENTRST##	;CALL ETHUUO ABOUT RESET
	PUSHJ	P,LATRST##	;CALL LATSER ABOUT RESET
IFN FTKL10,<
	PUSHJ	P,KNIRST##	;CALL KNISER ABOUT RESET
>; END IFN FTKL10
>; END IFN FTENET
IFN FTDECNET,<
	SNCALL	(SCURST##,MS.HGH) ;RESET DECNET-10
>
IFN FTLOCK,<
	PUSHJ	P,UNLOCK##	;TURN OFF NSHF AND NSWP AND RETURN CORE
	  JFCL
>
	PUSHJ	P,CLRLPG##	;CLEAR ALL LOCKED PAGES
	MOVEI	T1,[CAMN 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
	HRRZS	.PDLBS##(W)	;CLEAR LARGE DISK BUFFERS IF SET BY UUO
	PUSHJ	P,CLRBRK##	;CLEAR ADDRESS BREAK IF SET BY UUO
	PUSHJ	P,CLRPSI##	;RESET SOFTWARE INTERRUPT STATUS

	PUSHJ	P,ENQRST##	;CLEAR ALL LOCKS
	PUSHJ	P,IPCFRC##	;SIGNAL RESET TO SYS:INFO

	MOVEI	T1,RELEA1	;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,.USCTA
	SKIPE	T2		;STILL HAVE FUNNY SPACE?
	PUSHJ	P,GVFWDS##	;GIVE IT BACK
	HLLZS	.USCTA
	HLLZS	JBTDDB##(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
	PUSHJ	P,FNDPDS##	;FIND THE JOB PDB
	PUSH	P,P2		;SAVE AWAY P2
	SKIPE	P2,.PDTSL##(W)	;JOB HAVE A TEMPORARY SEARCH LIST?
	PUSHJ	P,SLGVT##	;YES, GIVE IT BACK
	POP	P,P2		;RESTORE P2
	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

;ROUTINE TO ENABLE/DISABLE APR FOR TRAPPING TO USER AND EXEC
;CALL:	MOVEI T1, APR CONSO FLAGS FOR USER TRAPPING
;	PUSHJ P,SETAPR
;	RETURN WITH APR RESET AND INTERRUPT LOCATION CONSO'S SET

SETAPR::
SETAP1::PUSHJ	P,SETRP		;SETUP THE TRAP LOCATIONS (PAGE FAULT,
				; ARITHMETIC, PDL OVF)
;	PJRST	SETCNA		;SET USER ENABLES FOR NXM AND CLOCK AND
				; SET THE APR PIA AND EXIT

;SUBROUTINE TO SETUP USER'S APR CONSO MASK AND THE APR PIA
;CALLING SEQUENCE:
;	MOVE	T1,USER'S APR ENABLE BITS
;	PUSHJ	P,SETCNA
;	ALWAYS RETURN HERE

SETCNA::HRL	T1,T1		;COPY ENABLE BITS TO LEFT HALF
	TLZ	T1,-1-XP.CLK-UE.PEF-UE.NXM ;CLEAR ALL BUT CLOCK, NXM, & PARITY
	HRR	T1,.CPEEB##	;SET MONITOR ENABLE BITS
	CONO	PI,PI.OFF	;DISALLOW INTERRUPTS WHILE CHANGING APR BITS
	HLRM	T1,.CPCN1##	;USER'S ENABLE BITS
	HRRM	T1,.CPCON##	;MONITOR'S ENABLE BITS
	CONO	APR,IP.ECI+APRCHN## ;SET CLOCK ENABLE AND APR PIA
	CONO	PI,PI.ON	;RESTORE PI
	POPJ	P,		;RETURN
;ROUTINE TO SETUP USER TRAP LOCATIONS AS SPECIFIED BY USER ENABLE BITS
; PAGE FAULT (ILL. MEM. REF.), ARITHMETIC (INTEGER OVERFLOW, FLOATING
; POINT OVERFLOW OR UNDERFLOW, AND DIVIDE CHECK), PUSH DOWN LIST OVERFLOW
; TRAP 3 IS ALWAYS IGNORED IN USER MODE.
;CALLING SEQUENCE:
;	MOVE	T1,USER ENABLE BITS
;	PUSHJ	P,SETRP
;	ALWAYS RETURN HERE
;T1 IS PRESERVED.

SETRP:	TRNE	T1,AP.AOV+AP.FOV;IS HE?
	TDZA	T2,T2		;YES, SET TO FIELD TRAPS
	MOVSI	T2,(JFCL)	;IGNORE ARITHMETIC TRAPS IF USER NOT ENABLED
	HRRI	T2,UE.AOT	;SET DISPATCH ADDRESS
	MOVEM	T2,.USAOT	;STORE IN UPT
	MOVEI	T2,UP.PDT	;IF USER NOT ENABLED FOR POV HANDLE LIKE EXEC POV
	TRNE	T1,AP.POV	;IS HE ENABLED?
	MOVEI	T2,UE.PDT	;YES, HANDLE DIFFERENTLY
	MOVEM	T2,.USPDT	;YES, SET FOR SEPDLO OR SUPDLO TO HANDLE PDL OV
	PJRST	APPSI##		;SETUP TRAP LOCATIONS FOR ANY INTERRUPTS THE
				; USER IS ENABLED FOR

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

IFN FTMDA,<
MDARST:	PUSHJ	P,FNDPDS##
	MOVE	T1,DATE##	;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
	SUBTTL	UTRP. UUO - SET TRAP LOCATIONS

;UUO ALLOWS A PROGRAM TO PLACE AN INSTRUCTION (ADDRESS OF LUUO BLOCK) IN TRAP
; LOCATIONS. MAKES OVERFLOW, UNDERFLOW TRAPPING FAST, LUUOS IN NON-ZERO SECTIONS
; POSSIBLE.
;CALLING SEQUENCE:
;	MOVE	AC,[FUNCTION,,ADDRESS]
;	UTRP.	AC,
;	  ERROR RETURN
;	NORMAL RETURN


UTADC%==1			;ADDRESS CHECK
UTUNF%==2			;UNKNOWN FUNCTION
UTBTN%==3			;BAD TRAP NUMBER
UTIUT%==4			;ILLEGAL USER TRAP INSTR

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

UUTRP:	HLRZ	U,T1		;GET FUNCTION
	CAILE	U,NUTRPF	;LEGAL FUNCTION?
	JRST	UTEUNF		;NO
	HRR	M,T1		;ADDRESS OF ARGUMENT LIST
	PUSHJ	P,GETWRD##	;GET ARGUMENT COUNT
	  JRST	UTEADC		;ADDRESS CHECK
	PUSHJ	P,SAVE1##	;SAVE AN AC
	MOVE	P1,T1		;ARGUMENT COUNT TO P1
	JRST	@UTPTBL(U)	;DISPATCH TO SET OR READ TRAP LOCATIONS

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

;HERE TO READ CONTENTS OF TRAP LOCATIONS
UTPRED:	PUSHJ	P,GETTRN	;GET TRAP NUMBER
	  POPJ	P,		;ADDRESS CHECK OR BAD TRAP NUMBER
	MOVE	T1,.USTVC(U)	;GET CONTENTS OF TRAP LOCATION
	PUSHJ	P,PUTWR1##	;STORE IT FOR THE USER
	  JRST	UTEADC		;ADDRESS CHECK
	SOJG	P1,UTPRED	;EXHAUSED COUNT?
	JRST	CPOPJ1##	;YES, GIVE GOOD RETURN

;HERE TO SET CONTENTS OF TRAP LOCATION
UTPSET:	PUSHJ	P,GETTRN	;GET TRAP NUMBER
	  POPJ	P,		;ADDRESS CHECK OR BAD TRAP NUMBER
	PUSHJ	P,GETWR1##	;GET INSTRUCTION/ADDRESS TO STORE IN TRAP LOCATION
	  JRST	UTEADC		;ADDRESS CHECK
	JUMPE	U,UTPSE2	;ANY VALUE IS FINE FOR LUUO BLOCK
	TLNE	T1,777000	;OPCODE ZERO?
	  JRST	UTPSE2		;NO, JUST GO STUFF
	JUMPN	T1,UTEIUT	;ILLEGAL UNLESS DEFAULTING
	PUSH	P,.USTVC	;SAVE CURRENT CONTENTS OF ALL TRAP LOCATIONS
	PUSH	P,.USTVC+1
	PUSH	P,.USTVC+2
	PUSH	P,.USTVC+3
	MOVE	T1,.JDAT+JOBENB##
	PUSHJ	P,SETRP		;SETUP TRAP LOCATIONS TO MONITOR DEFAULTS
	MOVE	T1,(U)		;GET MONITOR DEFAULT FOR CURRENT TRAP NUMBER
	POP	P,.USTVC+3	;RESTORE ALL OTHER TRAP LOCATIONS
	POP	P,.USTVC+2
	POP	P,.USTVC+1
	POP	P,.USTVC
UTPSE2:	MOVEM	T1,.USTVC(U)	;STORE USER SUPPLIED INTRUCTION/ADDRESS, OR DEFAULT
	SOJG	P1,UTPSET	;LOOP OVEN ENTIRE ARGUMENT LIST
	JRST	CPOPJ1##	;AND GIVE DONE GOOD RETURN

;SUBROUTINE TO FETCH AND VALIDATE A TRAP NUMBER, RETURNS CPOPJ IF BAD, CPOPJ1
; IF OKAY, TRAP NUMBER IN U
GETTRN:	PUSHJ	P,GETWR1##	;GET NEXT TRAP NUMBER
	  JRST	UTEADC		;ADDRESS CHECK
	SKIPL	T1		;NEGATIVE TRAP NUMBERS ARE ILLEGAL
	CAILE	T1,2		;SO ARE TRAP NUMBERS GREATER THAN 2
	JRST	UTEBTN		;BAD TRAP NUMBER
	MOVEI	U,(T1)		;RETURN TRAP NUMBER IN U
	SOJA	P1,CPOPJ1##	;DECREMENT ARGUMENT COUNT AND GOOD RETURN
	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


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

;RETURN JOB RUNNING TIME IN MILLISECONDS
JOBTIM:	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,UDCPUT##	;UPDATE CPU TIME IF PROCESS IS RUNNING SOMEWHERE
	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##


;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::	IMUL	T1,TICSEC##	;CONVERT TO TICKS
	ANDI	T1,7777
	TDZA	F,F		;LET WORLD KNOW THIS ISN'T AN I/O UUO
HSLEEP:	TLO	T1,(1B0)	;FLAG IT'S FROM HIBER
	TRNN	T1,7776		;0 TIME?(CHECK ONLY 12 BITS)
	HRRI	T1,2		;YES. SLEEP 1 JIFFY
	PUSHJ	P,SAVT##	;PRESERVE T2-T4 FOR CALLER
	PUSH	P,T1		;SAVE SLEEP TIME
	PUSH	P,W		;SAVE W FOR DTASRN WHERE IT POINTS
				; TO CONTROLER DATA BLOCK
	PUSHJ	P,FNDPDS##	;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

	HRLI	T1,CTXWKJ##	;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:	MOVE	T2,.CPJCH##	;NO, GET JCH TO AWAKEN
	SYSPIF
	IDPB	T1,CLOCK##
	IDPB	T2,CLOCK##
	SETOM	CLKNEW##	;NEW ENTRY HAS BEEN MADE
	SYSPIN
	JRST	SLPNAP		;SET JOB STATUS WORD SO JOB WILL NOT RUN
XSLEEP:	MOVE	T2,T1		;TIME TO SLEEP
	MOVE	T1,.CPJCH##	;JCH TO AWAKEN
	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
	DMOVEM	16,.JDAT+JOBDAC##+16 ;[~~] SETSTT RESTORES 16&17 FROM HERE.
	MOVE	T2,TICSEC##	;GET SECONDS WORTH OF JIFFIES
	JUMPL	T1,SETHBR##	;DON'T RESTORE SLPQ/NAPQ IF HIBER (HSLEEP)
	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	GOPEEK		;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:	MOVE	T3,T2		;COPY ADDRESS
	CAMGE	T3,SYSSIZ##	;IS HE ASKING FOR LEGAL VALUE?
	  JRST	GOPEK1		;YES
	CAIL	T3,CSBORG##	;IS THIS IN THE
	CAML	T3,MONVFF##	; HISEG
	  JRST	RTZER		; NO
GOPEEK:	JUMPGE	P1,GOPEK1	;VIRTUAL
	CAMGE	T2,MEMSIZ##	;IF PHYSICAL, IS IT LEGAL?
GOPEK1:	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.

>	;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,CSBORG##	;BELOW THE BOTTOM OF THE MONITOR VIRTUAL ADDRESS SPACE?
	CAML	T1,MONVFF##	;BELOW THE TOP OF THE MONITOR VIRTUAL ADDRESS SPACE?
	CAIA
	JRST	POKE0
	JUMPGE	P1,POKE0	;ALLOW IF VIRTUAL ADDRESS
	CAILE	T1,17		;CHECK ADDRESS
	CAML	T1,MEMSIZ##	;  SEE IF LEGAL
	PJRST	ECOD2##		;NO--BOMB USER WITH ERROR 2
POKE0:	MOVE	T2,T1
	MOVE	P2,T2
	PUSHJ	P,PPPADR	;GET VIRTUAL ADR IF ARG IS PHYSICAL ADR
	  JRST	ECOD2##
	MOVE	P1,T2		;SAVE ADDRESS
	PUSHJ	P,GETWD1##	;GET USER'S IDEA OF OLD CONTENTS
	PUSH	P,T1		;SAVE IT
	PUSHJ	P,GETWD1##	;GET NEW VALUE
	PUSHJ	P,POKADR	;COMPUTE ADDRESS (PRESERVES T1)
	POP	P,T4		;RESTORE USER'S IDEA OF OLD CONTENTS
	SYSPIF			;TO BE SAFE
	CAME	T4,(P1)		;COMPARE OLD VALUE
	JRST	POKE.1		;FAIL--BOMB USER
	CAIL	P1,JBTPPN##	;RANGE-CHECK
	CAIL	P1,JBTPPN##+JOBN## ;FOR PPN TABLE
	JRST	POKE2		;NOT A PPN
	PUSHJ	P,PPNCHK	;SEE IF WE LIKE THE PPN
	  JRST	POKE.1		;FAILED
POKE2:	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 IN CASE OF CRASH
	MOVEI	T1,.SWEPK	;EVENT CODE (POKE)
	MOVE	T2,P2		;EVENT-SPECIFIC DATA WORD (ADDR POKED)
	SKIPE	[M.LPOK##]	;WANT TO LOG POKES?
	PUSHJ	P,SWESEB##	;LOG EVENT
	SETZ	F,		;NOT AN I/O UUO
	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
;PRESERVES T1

POKADR:	CAIL	P1,CSBORG##	;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
	LSH	T2,W2PLSH
	HRLI	T2,(POINT 36,0,35)
	ADD	T2,.CPMAP##	;RELOCATE FOR THIS CPU
	LDB	T3,T2		;GET CONTENTS OF EXEC MAP SLOT CORRESPONDING TO THE PAGE
IFN FTKL10&FTMP,<
	TDZE	T3,[PM.CSH]	;CACHED?
	PUSHJ	P,UNCACH##	;UNCACHE THE PAGE FOR ALL CPUS
>
	TDO	T3,[PM.WRT]	;ALLOW WRITING
	MOVEM	T3,.UPMP+.UMTMP

	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			;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:	MOVE	T1,T2
	SKIPGE	P1		;PHYSICAL ONLY UUO?
	JRST	PPPAD1		;NO
	PUSHJ	P,PPPV2P
	  POPJ	P,
	TLNN	T2,-1
	JRST	CPOPJ1##

PPPAD1:	LSH	T1,W2PLSH	;PAGE NUMBER
	HRLI	T1,(<PM.DCD>B2+PM.WRT+PM.PUB)
	MOVEM	T1,.UPMP+.UMTMP

	ANDI	T2,PG.BDY	;COMPUTE VIRTUAL ADDRESS OF LOC
	IORI	T2,.TEMP
	CLRPT	.TEMP
	JRST	CPOPJ1##

PPPV2P::SE1ENT
	MAP	T1,(T2)
	PUSHJ	P,FLTCHK##
 	  POPJ	P,
	TLZ	T1,(MP.NAD)
	JRST	CPOPJ1##
>
	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
	SNPNUL			;(4) NULL FUNCTION. FOR BREAKPOINTS.
NLSNOP==.-SNPDSP-1
Comment	@
Usefull labels for Breakpoints:
BP$000	Gets called by the .SONUL breakpoint function. Usefull for being
	able to execute code at UUO level.
BP$001	Gets called right before the breakpoints are removed. Usefull for
	installing cleanup code which gets called on a reset.
	@

;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		;ILLEGAL FUNCTION IF BREAK POINTS INSERTED
	SETZB	F,T2		;F=0, EVENT-SPECIFIC DATA WORD
	MOVEI	T1,.SWESN	;EVENT CODE (SNOOP)
	PUSHJ	P,SWESEB##	;LOG EVENT
	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
	AOS	(P)		;SET FOR SKIP RETURN TO USER
				;FALL INTO REMBPS

REMBPS:	PUSHJ	P,CKBINS	;BREAK POINTS ACTUALLY INSERTED?
	  SKIPA			;YES
	POPJ	P,		;NO, SO ALL IS KOSHER
	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
>
	POPJ	P,		;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

;THE NULL FUNCTION
SNPNUL:	CAME	J,SYSBPJ##	;THIS BEING EXECUTED BY SNOOP OWNER?
	JRST	SNPSAS		; NOPE. SOMEONE ELSE.
BP$000:	POPJ	P,		;FINISHED
	JRST	CPOPJ1##	;IN CASE SNOOPED INSTRUCTION SKIPS.

;MISC. SUBROUTINES

RTNBPS:	PUSHJ	P,SAVE2##	;SAVE P1-P2
BP$001:!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,REMBPS	;REMOVE BREAK POINTS IF INSERTED
	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

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
12	SPECIFY CHANNEL PROGRAM FOR READ IN REVERSE
15	SHUTDOWN I/O ON TAPE CHANNEL
16	START I/O ON TAPE CHANNEL
17	ENABLE MICROCODE LOADING
20	DISABLE MICROCODE LOADING
21	LOAD MICROCODE

FUNCTIONS DEFINED IN UUOCON
10	READ CSB
11	READ DSB
13	ENABLE/DISABLE AUTO LOAD OF DX20'S
14	OBTAIN USER IOT
24	EXECUTE S-BUS DIAGNOSTIC FUNCTION
FUNCTIONS DEFINED IN MOSSER
100	GET MEMORY
101	GIVE MEMORY
FUNCTIONS DEFINED IN KLPSER AND KNISER
22	SET IPA CHANNEL MAINTENANCE MODE
23	CLEAR IPA CHANNEL MAINTENANCE MODE
FUNCTIONS DEFINED IN KLPSER
105	RESET REMOTE SYSTEM
106	START REMOTE SYSTEM
107	PORT COUNTER FUNCTIONS
112	WRITE CI MAINTENANCE DATA
113	READ CI MAINTENANCE DATA
>
DIAUUO:	PUSHJ	P,SAVE4##	;DO THIS NOW
	PUSH	P,T1
	HRR	M,T1		;ADR OF BLOCK
	PUSHJ	P,GETWDU##	;GET ARG
	MOVSI	P4,-DIDSLN	;AOBJN POINTER TO DIAG TABLE
DIAUO1:	LDB	T3,[POINT 9,DIADST(P4),17]	;GET FUNCTION
	CAIE	T3,(T1)		;THIS FUNCTION?
	AOBJN	P4,DIAUO1	;NO
	JUMPGE	P4,[POP  P,T1
		    JRST DIAAIF]
	MOVE	P4,DIADST(P4)	;GET DISPATCH WORD
	MOVE	P2,T1		;MOVE FUNCTION TO P2

;IF GOING TO DO IO HE'D BETTER BE ALL IN CORE

	TLNE	P4,(DI.NVR)	;NOT ALLOWED TO BE VIRTUAL?
	SKIPN	.USVRT		;NO, IS HE?
	JRST	DIAUO2		;NOT VIRTUAL OR DON'T CARE
	POP	P,(P)		;FIX STACK
	JRST	DIAAVC		;LOSE
DIAUO2:	TLNN	P4,(DI.UIO)	;GIVE USER I/O ON THIS FUNCTION?
	JRST	DIAUO3		;NO
	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 DIAANP]
DIAUO3:	POP	P,T1		;OK, RESTORE ARGUMENT
	TLNE	P4,(DI.UIO)	;DIDN'T CALL TRPSET
	PUSHJ	P,STOTAC##	;TRPSET STORES 0 IN THE AC
	HRR	M,T1		;POINT BACK TO THE USER'S ARG BLOCK
	TLNE	P4,(DI.NON)	;CHECK N?
	JRST	DIAUO4		;NO
	HLRE	T2,T1		;NUMBER OF ARGUMENTS
	JUMPGE	T2,DIAAIA	;ILLEGAL N
	MOVN	P1,T2		;P1=NUMBER OF ARGS
	CAIGE	P1,2		;LEGAL?
	JRST	DIAAIA		;ILLEGAL N
DIAUO4:	SETZ	F,		;NO DDB YET
	HLRZ	T1,P2		;GET POSSIBLE CPU NUMBER
	TLZ	P2,-1		;AND CLEAR THE ARGUMENT
IFE FTMP,<
	TLNE	P4,(DI.CPU)	;WOULD FUNCTION ACCEPT CPU NUMBER?
	JUMPN	T1,DIAABA	;YES, GIVE AN ERROR IF ONE SPECIFIED
>; END IFE FTMP
IFN FTMP,<
	TLNN	P4,(DI.CPU)	;CPU NUMBER SUPPLIED IN FUNCTION WORD?
	JRST	DIAUO5		;NO
	PUSHJ	P,ONCPUS##	;GET ON THAT CPU
	  JRST	DIAANR		;NOT RUNNING
DIAUO5:
>; END IFN FTMP
	TLNN	P4,(DI.KDB!DI.UDB!DI.DEV) ;NEED ONE OF THESE?
	JRST	DIAUO7		;NO
	PUSHJ	P,GETWD1##	;GET KON/UNIT WORD
	TLNE	P4,(DI.DEV)	;CPU/KONT/UNIT DESIGNATOR?
	JRST	DIAUO6		;YES
	LDB	T2,[POINT 7,T1,6] ;CONTROLLER NUMBER
	PUSHJ	P,DIAKDU	;FIND THE SPECIFIED KDB/UDB
	  JRST	DIAAIC		;NO SUCH DEVICE
	  JRST	DIAAIU		;ILLEGAL UNIT NUMBER
	JRST	DIAUO7		;FINISH UP
DIAUO6:	MOVE	T2,T1		;COPY ARGUMENT
	PUSHJ	P,DIADEV	;FIND THE SPECIFIED DEVICE
	  JRST	DIAAIC		;NO SUCH DEVICE
	  JRST	DIAAIU		;ILLEGAL UNIT
DIAUO7:	SSX	P4,IFIW		;AVOID ILL MEM REFS
	JRST	(P4)		;GO DISPATCH
;ROUTINE TO FIND A DEVICE
;CALL:	PUSHJ	P,DIADEV
;	  <RETURN 1>		;NO SUCH DEVICE
;	  <RETURN 2>		;ILLEGAL UNIT ON DEVICE
;	<RETURN 3>		;W = KDB, U = UNIT #, F = DDB

DIADEV:	SETZB	W,U		;NO KDB OR UDB YET
	SETZ	F,		;NO DDB YET
	MOVE	P1,T2		;COPY ARGUMENT

;CHECK FOR A POSSIBLE CPU NAME
IFE FTMP,<
	CAMN	T2,.CPPHY##	;OUR NAME?
	JRST	CPOPJ2##	;THEN IT'S A CPU (U ALREADY = ZERO)
> ;END IFN FTMP
IFN FTMP,<
	PUSHJ	P,CPUFND##	;DOES CPU EXIST?
	  JRST	DIADE1		;NOT A CPU
	CAIL	T1,M.CPU##	;REASONABLE NUMBER?
	JRST	CPOPJ1##	;ILLEGAL UNIT OF A SORT
	MOVE	U,T1		;COPY CPU NUMBER
	JRST	CPOPJ2##	;AND RETURN
> ;IFN FTMP

;SEARCH FOR A POSSIBLE KONTROLLER
DIADE1:	HLLZ	T2,P1		;GET KONTROLLER PORTION OF DEVICE NAME
	MOVSI	T1,-TYPMAX-1	;SET TO SEARCH ALL OF KDBTAB
	PUSHJ	P,FNDKON	;LOOK FOR A KDB WITH THIS NAME
	  JRST	[CAMN	T2,P1	;SECOND TIME THROUGH?
		 JRST	DIADE2	;GO TRY FOR A RANDOM DEVICE
		 MOVE	T2,P1	;LOAD UP FULL NAME (WITH POSSIBLE CPU NUMBER)
		 JRST	.-2]	;AND TRY AGAIN
	MOVE	W,T3		;COPY KDB ADDRESS
	MOVNI	U,1		;ASSUME ALL DRIVES
	HRRZ	T1,P1		;GET DRIVE DESIGNATOR
	JUMPE	T1,CPOPJ2##	;ONLY KONTROLLER SPECIFIED
	PUSHJ	P,DIANUM	;TRANSLATE TO UNIT NUMBER
	  JRST	DIADE2		;NOT NUMERIC
	MOVE	U,T1		;COPY DRIVE NUMBER
	JRST	CPOPJ2##	;RETURN

;SEARCH FOR A POSSIBLE DEVICE NAME
DIADE2:	MOVE	T1,P1		;GET ARGUMENT BACK AGAIN
	PUSHJ	P,DEVPHY	;SCAN THE DDBS FOR A MATCH
	  POPJ	P,		;NO SUCH DEVICE
	JRST	CPOPJ2##	;RETURN WITH DDB IN F
DIANUM:	SKIPN	T3,T1		;COPY
	JRST	CPOPJ1##	;ZERO
	SETZ	T1,		;CLEAR RESULT
	MOVE	T4,KDBDSP(W)	;DRIVER DISPATCH
	MOVE	T4,DRVCNF(T4)	;GET INTERESTING BITS
	TRNE	T4,DR.NMC	;CPU NUMBER ENCODED IN KONT NAME?
	SOJA	T1,CPOPJ1##	;YES--THEN NOT REALLY A DRIVE DESIGNATOR
	TRNE	T4,DR.DDN	;USING DECIMAL NUMBERS?
	SKIPA	T4,[12]		;YES
	MOVEI	T4,10		;ELSE OCTAL

DIANU1:	TLNE	T3,770000	;LEFT JUSTIFIED?
	JRST	DIANU2		;YES
	LSH	T3,6		;SLIDE OVER SOME
	JRST	DIANU1		;LOOP BACK

DIANU2:	LSHC	T2,6		;GET A CHARACTER
	ANDI	T2,77		;MASK DOWN
	CAIL	T2,'0'		;RANGE
	CAILE	T2,'0'(T4)	; CHECK
	POPJ	P,		;NOT NUMERIC
	IMULI	T1,(T4)		;SCALE RESULT
	ADDI	T1,-'0'(T2)	;INCLUDE DIGIT
	JUMPN	T3,DIANU2	;LOOP IF MORE
	JRST	CPOPJ1		;AND RETURN
;ROUTINE TO SCAN THE KDBS AND UDBS FOR A MATCH
;CALL:	PUSHJ	P,DIAKDU
;	  <RETURN 1>		;NO SUCH DEVICE
;	  <RETURN 2>		;ILLEGAL UNIT ON DEVICE
;	<RETURN 3>		;W = KDB, U = UDB

DIAKDU:	PUSH	P,P1		;SAVE P1 (UUO ARG COUNT)
	MOVSI	P1,-TYPMAX-1	;AOBJN POINTER TO KDB TABLE
DIAKD1:	SKIPN	W,KDBTAB##(P1)	;GET A KDB ADDRESS
DIAKD2:	AOBJN	P1,DIAKD1	;TRY ANOTHER
	JUMPGE	P1,P1POPJ##	;CAN'T FIND SPECIFIED DEVICE

DIAKD3:
IFN FTMP,<
	MOVE	T3,KDBCAM(W)	;CPU ACCESSIBILITY MASK
	TDNE	T3,.CPBIT##	;IS IT US?
> ;END IFN FTMP
	CAME	T2,KDBDVC(W)	;YES, RIGHT CONTROLLER?
	JRST	DIAKD5		;NO, TRY NEXT KDB
	SKIPG	KDBUNI(W)	;MULTI-UNIT CONTROLLER?
	JRST	DIAKD4		;NO, USE UNIT NUMBER
	HLRZ	T3,KDBUNI(W)	;YES. GET THIS KDB'S UNIT NUMBER
	LDB	T4,[POINT 3,T1,29]
	CAIE	T3,(T4)		;RIGHT UNIT (KDB)?
	JRST	DIAKD5		;NO. TRY NEXT KDB
	LDB	P3,[POINT 3,T1,35] ;YES. GET SLAVE NUMBER
	CAIA

DIAKD4:	LDB	P3,[POINT 3,T1,29] ;GET UNIT NUMBER
	ADD	P3,KDBIUN(W)	;POINT TO RIGHT UDB
	POP	P,P1		;RESTORE P1
	SKIPN	U,(P3)		;IS THERE SUCH A UNIT?
	JRST	CPOPJ1##	;NO
	JRST	CPOPJ2##	;RETURN GOODNESS

DIAKD5:	SKIPE	W,KDBNXT(W)	;STEP TO NEXT KDB
	JRST	DIAKD3		;GO TEST IT
	JRST	DIAKD2		;TRY ANOTHER DEVICE TYPE
;HERE TO GET KONTROLLER/UNIT
DIAKUN:	PUSHJ	P,GETWD1##	;GET DEVICE NAME
	MOVEI	T2,DD%PHY!DD%LOG!DD%ALT ;PHYSICAL, LOGICAL, ALTERNATE PORTS
	PUSHJ	P,DDBSRC	;SCAN THE DDBS FOR A MATCH
	  TDZA	T3,T3		;NOT FOUND
	JRST	DIAKU1		;ONWARD
	PUSHJ	P,DVSRSP	;MAYBE A SPOOLED DEVICE (DISK)?
	  JRST	DIAAIU		;NO SUCH DEVICE
DIAKU1:	LDB	T2,PDVTYP##	;GET DEVICE TYPE
	SKIPN	W,KDBTAB##(T2)	;GET KDB ADDRESS
	JRST	DIAAIU		;KNOWN DEVICE BUT NO DIAG CODE
	MOVEI	P2,.DIAKU	;SET UP FUNCTION
	PJRST	DIADSP		;GO DISPATCH


;HERE FROM STOP1A ON ^C OR EXIT, HALT,...  ;OR FROM HNGDSK
IFN FTKS10,<DIACLR==:CPOPJ##>
IFN FTKL10,<
DIACLR::SE1ENT			;ENTER SECTION ONE
IFN FTSCA,<PUSHJ P,PPDCLR##>	;CLEAR STALE STUFF IN PCBS
	PUSH	P,M		;SAVE M
	HRROS	M		;SO DON'T STORE IN USER'S ACS
	PUSHJ	P,TPDSIA##	;START UP TAPE SCHEDULING
	  JFCL
	POP	P,M		;RESTORE M
	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
	SETZ	P2,		;ENTRY 0 = ^C POINT
> ;END IFN FTKL10

;HERE TO DISPATCH WITH THE FOLLOWING ACS SETUP FOR THE DRIVER:
;	P1 = NUMBER OF ARGUMENTS
;	P2 = FUNCTION CODE
;	P3 = SUBROUTINE
;	W  = KDB ADDRESS
;	U  = UDB ADDRESS
;	F  = CONTENTS OF .PDDIA

DIADSP:	JUMPN	F,DIADS2	;DON'T RESET F IF ALREADY FOUND A DDB
	PUSH	P,W		;SAVE POSSIBLE KDB ADDRESS
	PUSHJ	P,FNDPDS##	;RELOAD W WITH PDB ADDRESS
	HRRZ	F,.PDDIA##(W)	;MAYBE THERE'S A DIAG. DDB
	POP	P,W		;RESTORE POSSIBLE KDB ADDRESS
	JUMPN	W,DIADS1	;NOT CPU IF ACS 'F' OR 'W' NON-ZERO
	XMOVEI	T2,CPUDIA##	;SPECIAL CPU/DIAG TABLE
	JRST	DIADS3		;ENTER LOOP

DIADS1:	SKIPA	T2,KDBDSP(W)	;GET DRIVER DISPATCH FROM KDB
DIADS2:	MOVE	T2,DEVDRV(F)	;GET DRIVER DISPATCH FROM DDB
	JUMPE	T2,DIANUI	;GIVE UP IF NO DISPATCH
	SKIPN	T2,DRVDIA(T2)	;SUPPORT DIAG UUO?
	JRST	DIANUI		;NOPE
DIADS3:	XMOVEI	T3,1(T2)	;IGNORE FIRST (PREPROCESSOR) ENTRY

DIADS4:	SKIPN	(T3)		;END OF TABLE?
	JRST	DIANUI		;FUNCTION NOT SUPPORTED BY DRIVER
	HLRZ	T4,(T3)		;GET A FUNCTION CODE
	CAIE	T4,(P2)		;A MATCH?
	AOJA	T3,DIADS4	;TRY ANOTHER
	HRRZ	P3,(T3)		;GET SUBROUTINE ADDRESS
IFN FTXMON,<HLL	P3,T2>		;MAKE RELATIVE TO SECTION WHERE TABLE LIVES
	PUSHJ	P,@(T2)		;CALL PREPROCESSOR SUBROUTINE (WILL CALL C(P3))
DIANUI::  SKIPA	T1,[XC.UIO]	;LOST
	JRST	CPOPJ1##	;RETURN
	ANDCAM	T1,.JDAT+JOBPD1## ;CLEAR USRIOT IF ERROR
	MOVSI	T1,NSWP!NSHF	;JOB IS NOW MOVABLE
	MOVE	J,.USJOB	;J MAY HAVE BEEN CLOBBERED
	ANDCAM	T1,JBTSTS##(J)	;UNLOCK JOB
	POPJ	P,		;RETURN
IFN FTKL10,<
;FINISH UP GET CHANNEL STATS
;ENTER WITH P1=NO OF ARGS, P2=LOC OF ICWA
DIAGCS::MOVEI	T2,-4(P1)	;SAVE NO OF ARGS -4
	HRRZ	T3,(P2)		;SAVE ADDR OF 1ST IOWD
	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,DIAGC2	;DONE IF 0
	AOJA	P2,DIAGC1	;GET NEXT WORD
DIAGC2:	JUMPLE	T2,CPOPJ1##	;RETURN IF HE DOESN'T WANT CCWS STORED
DIAGC3:	MOVE	T1,(T3)		;GET A CCW
	PUSHJ	P,PUTWD1##	;GIVE IT TO THE USER
	JUMPE	T1,CPOPJ1##	;RETURN AFTER STORING TERMINATING ZERO
	SOJLE	T2,CPOPJ1##	;RETURN IF COUNT EXHAUSTED
	TLNN	T1,577777	;REAL IOWD?
	SOS	T3,T1		;CHAN JUMP - GET NEW ADDRESS
	AOJA	T3,DIAGC3	;GO GET NEXT IOWD
>; END IFN FTKL10
;HERE FOR THE CODE COMMON TO BOTH READ CPU STATUS BLOCK AND READ
;DEVICE STATUS BLOCK
DIAXSB:	MOVSI	T1,JP.POK	;MUST HAVE POKE PRIVS OR
	PUSHJ	P,PRVBIT##	;BE [1,2] OR JACCT
	  SKIPA			;HE'S OK
	JRST	DIAANP		;NOT ENOUGH PRIVS
	PUSHJ	P,GETWD1##	;GET CPU NUMBER
	SKIPL	T1		;IF NEGATIVE
	CAIL	T1,M.CPU##	;OR GREATER THAN THE NUMBER OF CPUS
	JRST	DIAANC		;IT'S ILLEGAL
IFN FTMP,<
	PUSHJ	P,ONCPUS##	;GET TO THAT CPU
	  JRST	DIAANR		;CPU NOT RUNNING
>
	CAIL	P2,.DIACS	;FUNCTION CODE IN RANGE?
	CAILE	P2,.DIADS	;...?
	JRST	DIAAIF		;NO, CAUGHT IT JUST IN TIME
	PJRST	@.+1-.DIACS(P2)	;DO THE FUNCTION SPECIFIC STUFF IN COMMON
	IFIW	DIACSB##	;READ CPU STATUS BLOCK
	IFIW	DIADSB##	;READ DEVICE STATUS BLOCK
;HERE TO EXECUTE AN S-BUS DIAGNOSTIC FUNCTION
IFN FTKL10,<
DIASBD:	CAIE	P1,3		;MUST BE 3 WORDS IN ARGUMENT BLOCK
	JRST	DIAAIA		;BAD ARGUMENT LIST LENGTH
	MOVSI	T1,JP.POK	;MUST HAVE POKE PRIVS OR
	PUSHJ	P,PRVBIT##	;BE [1,2] OR JACCT
	  SKIPA			;HE'S OK
	JRST	DIAANP		;NOT ENOUGH PRIVS
	PUSHJ	P,GETWD1##	;GET SECOND WORD OF BLOCK (TO-MEMORY WORD)
	SETZ	T2,		;CLEAR FROM-MEMORY WORD
	SBDIAG	T1		;DO THE FUNCTION
	PUSH	P,T2		;SAVE FROM-MEMORY WORD
	PUSHJ	P,PUTWDU##	;RETURN UPDATED TO-MEMORY WORD
	POP	P,T1		;RESTORE FROM-MEMORY WORD
	PUSHJ	P,PUTWD1##	;RETURN FROM-MEMORY WORD
	JRST	CPOPJ1##	;SKIP RETURN
>; END IFN FTKL10

;HERE TO READ A UNIBUS REGISTER
IFN FTKS10,<
DIARUR:	CAIE	P1,2		;MUST BE 2 WORDS IN ARGUMENT BLOCK
	JRST	DIAAIA		;BAD ARGUMENT LIST LENGTH
	MOVSI	T1,JP.POK	;MUST HAVE POKE PRIVS OR
	PUSHJ	P,PRVBIT##	;BE [1,2] OR JACCT
	  SKIPA			;HE'S OK
	JRST	DIAANP		;NOT ENOUGH PRIVS
	PUSHJ	P,GETWD1##	;GET SECOND WORD OF BLOCK (UNIBUS REGISTER)
	PUSHJ	P,UBGOOD##	;WILL IT PAGE FAULT?
	  JRST	DIAANU		;YES, RETURN AN ERROR
	RDIO	T1,(T1)		;READ THE REGISTER
	JRST	STOTC1##	;RETURN IN AC AND SKIP RETURN
>; END IFN FTKS10

;HERE TO ALLOCATE A BUFFER IN WHICH TO DUMP THE IPA20 DRAM
IFN FTKL10&<FTSCA!FTENET>,<
DIAADB:	MOVSI	T1,JP.POK	;MUST HAVE POKE PRIVS OR
	PUSHJ	P,PRVBIT##	;BE [1,2] OR JACCT
	  SKIPA			;HE'S OK
	JRST	DIAANP		;NOT ENOUGH PRIVS
	SKIPE	IPKDDB(W)	;BUFFER ALREADY ALLOCATED?
	JRST	CPOPJ1##	;YES, NOTHING TO DO
	MOVEI	T2,DRMSIZ	;SIZE OF THE DRAM IN WORDS
	PUSHJ	P,GFWNZS##	;ALLOCATE SPACE
	  JRST	DIAAFC		;NO FREE CORE
	MOVEM	T1,IPKDDB(W)	;SAVE THE ADDRESS
	MOVE	T2,T1		;COPY THE BUFFER ADDRESS
	AOS	T3,T1		;BUILD A BLT POINTER
	MOVEI	T1,DRMSIZ-1	;NUMBER OF WORDS TO ZERO
	SETZM	(T2)		;ZERO FIRST WORD
	EXTEND	T1,[XBLT]	;ZERO THE REST OF THE BUFFER
	JRST	CPOPJ1##	;SKIP RETURN
>; END IFN FTKL10&<FTSCA!FTENET>
;READ DEVICE SERIAL NUMBER
DIADSN:	JUMPE	W,DIAAIU	;ILLEGAL UNIT IF NO KDB OR UDB GIVEN
	XMOVEI	T3,KDBSER(W)	;ASSUME KONTROLLER S/N WANTED
	PUSHJ	P,DIAUDB	;TRANSLATE C(U) TO UDB ADDR IN T2
	  CAIA			;WANTS KONTROLLER
	XMOVEI	T3,UDBDSN(T2)	;POINT TO S/N FOR DRIVE
	MOVE	T1,0(T3)	;WORD ONE
	PUSHJ	P,PUTWD1##	;RETURN TO USER
	MOVE	T1,1(T3)	;WORD TWO
	PUSHJ	P,PUTWD1##	;GIVE TO USER
	JRST	CPOPJ1##	;RETURN GOODNESS


;ROUTINE TO FIND THE TUB ASSOCIATED FOR THE DRIVE IN AC 'U'
DIAUDB:	JUMPL	U,CPOPJ##	;CALLER REALLY WANTS KDB IF -1
	MOVE	T1,KDBIUN(W)	;DRIVE TABLE
DIAUD1:	SKIPN	T2,(T1)		;GET A UDB
	JRST	DIAUD2		;NONE THERE
	CAMN	U,UDBPDN(T2)	;FOUND THE UDB?
	JRST	CPOPJ1##	;YES
DIAUD2:	CAMGE	T1,KDBFUN(W)	;END OF TABLE?
	AOJA	T1,DIAUD1	;KEEP SEARCHING
	POPJ	P,		;NON-EXISTANT DRIVE
;READ DEVICE REGISTERS
DIAREG:	PUSHJ	P,SAVE3##	;SAVE SOME ACS
	JUMPN	W,DIARG1	;SKIP DDB STUFF IF A KONTROLLER GIVEN
	SKIPE	P1,F		;NEED A DDB
	SKIPN	T2,DEVDRV(F)	;GET DRIVER DISPATCH
	JRST	DIAABA		;SAY BAD ARGUMENT LIST
	MOVE	P2,DRVDDL(T2)	;COPY DDB LENGTH
	JRST	DIARG2		;GO RETURN DATA

;HERE IF AT LEAST A KONTROLLER
DIARG1:	MOVE	P1,W		;SAVE DATA STRUCTURE ADDRESS
	MOVE	T2,KDBDSP(W)	;GET ITS DISPATCH TABLE
	MOVE	P2,DRVKLN(T2)	;ASSUME WILL BE SNIFFING AT THE KDB
	JUMPL	U,DIARG2	;ANY UNIT NUMBER?

;HERE TO FIND THE UDB
	PUSHJ	P,DIAUDB	;FIND UDB
	  JRST	DIAAIU		;ILLEGAL UNIT
	MOVE	P1,T2		;COPY UDB ADDRESS
	MOVE	T2,KDBDSP(W)	;GET DISPATCH AGAIN
	MOVE	P2,DRVULN(T2)	;AND THE UDB LENGTH

;HERE WITH P1 = DATA STRUCTURE AND P2 = LENGTH
DIARG2:	PUSHJ	P,GETWD1##	;GET WORD COUNT WORD
	HRRE	T2,T1		;GET STARTING OFFSET
	CAIL	T2,0		;RANGE
	CAIL	T2,(P2)		; CHECK
	JRST	DIAAIA		;ILLEGAL NUMBER OF ARGUMENTS
	SKIPL	P3,T1		;COPY AOBJN POINTER
	JRST	DIAAIA		;DOESN'T WANT ANY WORDS COPIED??

;NOW RETURN THE REQUESTED WORDS
DIARG3:	HRRZ	T1,P3		;GET OFFSET
	ADD	T1,P1		;INDEX INTO KDB/UDB
	MOVE	T1,(T1)		;FETCH A WORD
	PUSHJ	P,PUTWD1##	;STORE IN USER'S ARGUMENT BLOCK
	SOSLE	P2		;END OF KDB/UDB?
	AOBJN	P3,DIARG3	;LOOP FOR ALL REQUESTED WORDS
	JRST	CPOPJ1##	;RETURN
;HERE TO OBTAIN KONTROLLER INFORMATION
DIAKIN:	CAIGE	P1,4+IFN FTKS10,<1> ;MUST HAVE ROOM FOR RESPONSE
	JRST	DIAAIA		;ERROR IF NOT
	PUSHJ	P,GETWD1##	;GET KONTROLLER NAME
	MOVE	T2,T1		;POSITION FOR FNDKON
	MOVSI	T1,-<TYPMAX+1>	;SEARCH ENTIRE TABLE
	PUSHJ	P,FNDKON	;GET KONTROLLER BY NAME
	  JRST	DIAAIC		;NONESUCH
	MOVE	T4,KDBDSP(T3)	;GET DRIVER DISPATCH TABLE
	LDB	T1,[POINTR(DRVCNF(T4),DR.DVT)] ;GET DEVICE TYPE
	LSHC	T1,-6		;POSITION FOR CANONICAL RETURN
	LDB	T1,[POINTR(DRVCF2(T4),DR.KTY)] ;GET KONTROLLER TYPE
	LSHC	T1,-14		;POSITION
	LDB	T1,[POINTR(DRVCF2(T4),DR.DMX)] ;MAX. DRIVES THIS KONTROLLER
	LSHC	T1,-6		;POSITION
	MOVE	T1,KDBCAM(T3)	;GET CPU ACCESSABILITY MASK
	LSHC	T1,30		;POSITION
	SKIPL	KDBUNI(T3)	;IF MULTI-UNIT KON ON CHANNEL,
	TLO	T1,(1B0)	;NOTE THAT
	SKIPE	DRVULP(T4)	;IF LOADABLE MICROCODE,
	TLO	T1,(1B1)	;NOTE THAT
	PUSHJ	P,PUTWD1##	;STORE INTO USER'S RETURN BLOCK
IFN FTKL10,<
	MOVE	T1,KDBDVC(T3)	;GET 7-BIT DEVICE CODE
	SUBI	P1,4		;OFFSET FOR HOW MANY WORDS WE DO
>
IFN FTKS10,<
	MOVE	T1,KDBCHN(T3)	;POINT TO CHN DB
	MOVE	T1,CHNDVC(T1)	;GET DEVICE INFO
	LSH	T1,-32		;POSITION IVI
	ANDI	T1,177		;MASK TO VALUE WE WANT
	SUBI	P1,5		;OFFSET FOR HOW MANY WORDS WE DO
>
	SKIPGE	T2,KDBUNI(T3)	;GET MASSBUSS UNIT
	TDZA	T2,T2		;ZERO IF NOT MULTI-UNIT
	HLRZS	T2		;LH QUANTITY
	DPB	T2,[POINT 3,T1,35-7] ;INCLUDE IN WORD
	LSH	T1,2		;MAKE 9-BIT DVC/IVI
	PUSHJ	P,PUTWD1##	;STUFF INTO USER'S BLOCK
IFN FTKS10,<
	MOVE	T1,KDBDVC(T3)	;GET CSR (OR OTHER UNIBUS ADDRESS)
	PUSHJ	P,PUTWD1##	;GIVE THAT TO USER AS WELL
>
DIAKI1:	JUMPLE	P1,CPOPJ1##	;RETURN SUCCESS AT END OF BLOCK
	SETZ	T1,		;GET A ZERO
	PUSHJ	P,PUTWD1##	;STORE IT IN UNUSED WORD
	PUSHJ	P,SCDCHK##	;DON'T KAF
	SOJA	P1,DIAKI1	;CLEAR ALL UNUSED WORDS IN ARG BLOCK
;HERE TO RETURN UNIT INFORMATION
DIAUIN:	CAIGE	P1,6		;CAN WE RETURN ALL THE INFO?
	JRST	DIAAIA		;ERROR IF NOT
	PUSHJ	P,GETWD1##	;GET NAME OF UDB IN QUESTION
	MOVE	T4,T1		;SAVE AGAINST FNDKON
	HLLZ	T2,T1		;KEEP LH AS KDB NAME
	MOVSI	T1,-<TYPMAX+1>	;SEARCH ALL OF KDBTAB
	PUSHJ	P,FNDKON	;GO FOR IT
	  JRST	DIAAIC		;NO MATCHING KONTROLLER
	MOVE	T2,KDBIUN(T3)	;START OF UDB TABLE
DIAUI1:	SKIPN	T1,(T2)		;IS THERE A UDB HERE?
	JRST	DIAUI2		;NO, LOOK FOR ANOTHER
	CAMN	T4,UDBNAM(T1)	;YES, DOES IT MATCH
	JRST	DIAUI3		;YES, GO FOR IT
DIAUI2:	CAMGE	T2,KDBFUN(T3)	;NO, HAVE WE CHECKED THE LAST POSSIBLE UNIT?
	AOJA	T2,DIAUI1	;LOOK UNTIL WE HAVE
	JRST	DIAAIU		;ERROR--ILLEGAL UNIT
DIAUI3:	MOVE	T4,T1		;PUT UDB ADDRESS IN BETTER PLACE
	PUSHJ	P,GETWD1##	;GET AOBJN POINTER TO KONT TABLE
	PUSH	P,M		;SAVE ARG BLOCK POINTER
	HLLZ	T2,T1		;GET -COUNT
	CAMGE	T2,[-MXPORT,,0]	;WITHIN RANGE?
	MOVSI	T2,-MXPORT	;ADJUST IT
	XMOVEI	T3,UDBKDB(T4)	;POINT TO UNIT'S KDB TABLE
	HLL	T1,T2		;GET # ENTRIES WE WILL RETURN
	PUSHJ	P,PUTWDU##	;UPDATE ARG BLOCK
	HRRI	M,-1(T1)	;SETUP FOR STORING KDB NAMES
DIAUI4:	SKIPE	T1,(T3)		;GET A KDB ADDRESS
	MOVE	T1,KDBNAM(T1)	;AND ITS NAME
	PUSHJ	P,PUTWD1##	;RETURN TO USER
	AOS	T3		;ADVANCE POINTER
	AOBJN	T2,DIAUI4	;LOOP THROUGH TABLE
	POP	P,M		;RESTORE ARG BLOCK POINTER
	MOVE	T1,UDBDSN(T4)	;GET FIRST HALF OF SERIAL NUMBER
	PUSHJ	P,PUTWD1##	;RETURN IT
	MOVE	T1,UDBDSN+1(T4)	;SECOND HALF
	PUSHJ	P,PUTWD1##	;BE COMPLETE
	MOVE	T1,UDBPDN(T4)	;PHYSICAL DEVICE NUMBER
	TSO	T1,UDBCAM(T4)	;CPU ACCESS MASK IN LH
	PUSHJ	P,PUTWD1##	;STORE THAT FOR USER AS WELL
	SUBI	P1,6		;OFFSET FOR HOW MANY WE USED
	JRST	DIAKI1		;STORE ZEROS IN UNUSED WORDS
;HERE TO RETURN A LIST OF UNITS ON A GIVEN KONTROLLER
DIALKU:	CAIGE	P1,3		;ENOUGH FOR KDB NAME AND AT LEAST ONE UNIT?
	JRST	DIAAIA		;ERROR IF NOT
	PUSHJ	P,GETWD1##	;GET KDB NAME
	MOVE	T2,T1		;COPY ITS NAME
	MOVSI	T1,-<TYPMAX+1>	;SET TO SEARCH ENTIRE TABLE
	PUSHJ	P,FNDKON	;FIND DESIRED KDB
	  JRST	DIAAIC		;NONESUCH
	MOVE	T4,KDBDSP(T3)	;POINT TO DRIVER DISPATCH TABLE
	LDB	T1,[POINTR(DRVCF2(T4),DR.DMX)] ;MAX. DRIVES ON KONTROLLER
	CAIGE	P1,2(T1)	;HAVE A BIG ENOUGH ARG. BLOCK?
	JRST	DIAAIA		;NO, DON'T CAUSE ANY DAMAGE
	SETZ	T4,		;KEEP A COUNT OF NUMBER OF NAMES WE RETURN
	MOVE	T2,KDBIUN(T3)	;START OF UDB TABLE
DIALK1:	SKIPE	T1,(T2)		;GET NEXT UDB POINTER
	MOVE	T1,UDBNAM(T1)	;AND ITS NAME
	JUMPE	T1,DIALK2	;SKIP OVERHEAD IF NONE
	AOJ	T4,		;COUNT UP ANOTHER NAME
	PUSHJ	P,PUTWD1##	;STUFF IN USER'S BLOCK
DIALK2:	CAMGE	T2,KDBFUN(T3)	;WAS THIS THE LAST POSSIBLE UNIT?
	AOJA	T2,DIALK1	;LOOP OVER ALL POSSIBLE UNITS
	MOVE	T1,T4		;GET NUMBER OF UNIT NAMES STORED
	PUSHJ	P,STOTAC##	;TELL USER HOW MANY THERE WERE
	SUBI	P1,2(T4)	;ACCOUNT FOR HOW MANY WE USED
	JRST	DIAKI1		;CLEAR OUT REMAINDER AND SUCCEED
;DIAG SUPPORT FOR UNIT RECORD DEVICES
URDDIA::IFIW	URDPPR			;PREPROCESSOR ROUTINE
	DIAFNC	(SDS,URDSDS,URDSDS)	;SET DEVICE STATUS
	DIAFNC				;TERMINATE TABLE

URDPPR:	JRST	(P3)		;GO PROCESS DIAG. UUO


;SET DEVICE STATUS
URDSDS:
IFN FTMP,<
	LDB	T1,DEYCPU##	;GET CPU FOR TARGET DEVICE
	PUSHJ	P,ONCPUN##	;PUT US ON THAT CPU
> ;END IFN FTMP
	PUSHJ	P,GETWD1##	;GET NEXT ARGUMNET
	CAIL	T1,0		;RANGE
	CAILE	T1,SDSLEN	; CHECK
	JRST	DIAABA		;BAD ARGUMENT LIST
	JRST	@SDSTAB(T1)	;GO DISPATCH BASED ON SUB-FUNCTION

SDSTAB:	IFIW	DIAABA		;SET IGNORE (ILLEGAL)
	IFIW	DIAABA		;CLEAR IGNORE (ILLEGAL)
	IFIW	DDBDET		;SET DETACHED
	IFIW	DDBATT		;SET ATTACHED
SDSLEN==.-SDSTAB		;LENGTH OF TABLE
;DISPATCH TABLE FOR DIAG

	DEFINE	DIAGDS	(FLAGS,CODE,ADDR)<

		%%FLG==0
	IRP	FLAGS,<
			%%FLG=%%FLG!DI.'FLAGS
		>
	EXP	%%FLG!<<.DI'CODE>B17+ADDR>

>
;FLAG BITS:
	DI.KDB==1B0			;NEEDS KONTROLLER
	DI.UDB==1B1			;NEEDS UNIT
	DI.UIO==1B2			;GIVE USER USER I/O
	DI.NVR==1B3			;USER CAN'T BE VIRTUAL
	DI.NON==1B4			;DON'T BOTHER TO CHECK N
	DI.CPU==1B5			;CPU NUMBER SPECIFIED IN LH OF FNC WORD
	DI.DEV==1B6			;NEEDS SOME SORT OF DEVICE

;NOTE THAT THE DISPATCH ENTRY IS NOT GIVEN FOR DEVICE SPECIFIC FUNCTIONS

DIADST:
IFN FTKL10,<
	DIAGDS	(<KDB,UDB,UIO,NVR>,ASU,DIADSP)	;ASSIGN UNIT
	DIAGDS	(<KDB,UDB,UIO,NVR>,AAU,DIADSP)	;ASSIGN ALL UNITS
	DIAGDS	(<KDB,UDB,UIO,NVR>,RAU,DIADSP)	;RELEASE CHANNEL/KON ALL UNITS
	DIAGDS	(<KDB,UDB,UIO,NVR>,SCP,DIADSP)	;SPECIFY CHANNEL PROG
	DIAGDS	(<KDB,UDB,UIO,NVR>,RCP,DIADSP)	;RELEASE CHANNEL PROG
	DIAGDS	(<KDB,UDB,UIO,NVR>,GCS,DIADSP)	;GET CHANNEL STATUS
	DIAGDS	(<NON>,AKU,DIAKUN)		;GET KONTROLLER AND UNIT #S
>; END IFN FTKL10
	DIAGDS	(<NON>,ACS,DIAXSB)		;READ CSB
	DIAGDS	(<NON>,ADS,DIAXSB)		;READ DSB
IFN FTKL10,<
	DIAGDS	(<KDB,UDB,UIO,NVR>,SCR,DIADSP)	;CHANNEL PGM FOR READ REVERSE
>; END IFN FTKL10
	DIAGDS	(<UIO,NON>,GUI,CPOPJ1##)	;GET USER I/O
IFN FTKL10,<
	DIAGDS	(<KDB,UDB,NON,CPU>,ELD,DIADSP)	;ENABLE MICROCODE LOADING
	DIAGDS	(<KDB,UDB,NON,CPU>,DLD,DIADSP)	;DISABLE MICROCODE LOADING
	DIAGDS	(<KDB,UDB,NON,CPU>,LOD,DIADSP)	;LOAD MICROCODE
	DIAGDS	(<KDB,CPU>,ISM,DIADSP)		;SET IPA CHANNEL MAINT MODE
	DIAGDS	(<KDB,CPU>,ICM,DIADSP)		;CLEAR IPA CHANNEL MAINT MODE
	DIAGDS	(<CPU>,SBD,DIASBD)		;EXECUTE SBUS DIAG FUNCTION
	DIAGDS	(<DEV>,DSN,DIADSN)		;READ DEVICE SERIAL NUMBER
>; END IFN FTKL10
IFN FTKS10,<
	DIAGDS	(<CPU>,RUR,DIARUR)		;READ UNIBUS REGISTER
>; END IFN FTKS10
IFN FTKL10&<FTSCA!FTENET>,<
	DIAGDS	(<DEV>,ADB,DIAADB)		;ALLOCATE IPA20 DUMP BUFFER
>; END IFN FTKL10&<FTSCA!FTENET>
	DIAGDS	(,OKI,DIAKIN)			;OBTAIN KONTROLLER INFO
	DIAGDS	(,OUI,DIAUIN)			;OBTAIN UNIT INFO
	DIAGDS	(,LKU,DIALKU)			;LIST KONTROLLER'S UNITS
	DIAGDS	(<DEV>,SDS,DIADSP)		;SET DEVICE STATUS
	DIAGDS	(<DEV>,DVR,DIAREG)		;READ DEVICE REGISTERS

IFN FTKL10,<
	DIAGDS	(<UIO>,GTM,MOSGTM##)		;GET MEMORY
	DIAGDS	(<UIO,NON>,GVM,MOSGVM##)	;GIVE MEMORY
IFN FTSCA,<
	DIAGDS	(,RRS,DIARRS##)			;RESET REMOTE SYSTEM
	DIAGDS	(,SRS,DIASRS##)			;START REMOTE SYSTEM
	DIAGDS	(<CPU>,ACC,DIACTR##)		;PORT COUNTER FUNCTIONS
	DIAGDS	(,WCM,DIAWMD##)			;WRITE CI MAINTENANCE DATA
	DIAGDS	(,RCM,DIARMD##)			;READ CI MAINTENANCE DATA
>; END IFN FTSCA
>; END IFN FTKL10
DIDSLN==.-DIADST				;LENGTH OF TABLE

DEFINE	X	(COD,VAL),<
	ERCODE	DIA'COD,VAL
	INTERN	DIA'COD
>
	DIAECD
	SUBTTL	RECON. UUO - SYSTEM LOGICAL RECONFIGURATION UUO

;THIS UUO PROVIDES THE SUPPORT NECESSARY FOR A USER PROGRAM TO LOGICALLY
; RECONFIGURE THE SYSTEM AND SUSPEND 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:	HLRE	U,T1		;FUNCTION
	CAML	U,[NLRECC]	;IS IT A LEGAL CUSTOMER FUNCTION?
	CAILE	U,NLRECN	;IS IT LEGAL?
	JRST	RCNIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,PRUSET	;GET LENGTH OF ARGUMENT LIST AND CHECK PRIVS
	  JRST	RCNNPV		;NOT PRIVILEGED
	JRST	@RCNDSP(U)	;DISPATCH

RCNCST:				;CUSTOMER FUNCTIONS GO HERE
RCNDSP:	IFIW	RCNROM		;(0) RUN ONLY ME
	IFIW	RCNSPN		;(1) SUSPEND SYSTEM
	IFIW	RCNCI7		;(2) TAKE CI7 CONTINUABLE DUMP
	IFIW	RCNNAR		;(3) SET/CLEAR DF.NAR
	IFIW	RCNBTX		;(4) SUPPLY NEW VALUE OF BOOTXT
	IFIW	RCNRLD		;(5) RELOAD THE SYSTEM
	IFIW	RCNATC		;(6) FORCE AUTCON TO RUN
	IFIW	CPOPJ##		;(7) DETACH CPU OR DEVICE (OBSOLETE)
	IFIW	CPOPJ##		;(10) ATTACH CPU OR DEVICE (OBSOETE)
	IFIW	RCNMOL		;(11) SET MEMORY ON-LINE
	IFIW	RCNMOF		;(12) SET MEMORY OFF-LINE
	IFIW	RCNCPU		;(13) FIND CPU MASK FOR A DEVICE
	IFIW	CPOPJ##		;(14) WAIT FOR ACTIVE I/O TO STOP (OBSOLETE)
	IFIW	RCNSDF		;(15) SET DUMP/RELOAD FLAGS IN DEBUGF
	IFIW	RCNCDF		;(16) CLEAR DUMP/RELOAD FLAGS IN DEBUGF
	IFIW	RCNRBM		;(17) READ BOOTSTRAP MICROCODE INFORMATION
	IFIW	RCNSBM		;(20) SUPPLY NEW BOOTSTRAP MICROCODE
NLRECN==.-RCNDSP-1
NLRECC==RCNCST-RCNDSP

;ERROR RETURNS
RCIAL%==1
RCNPV%==2
RCNTS%==3
RCNIJ%==4
RCNCD%==5
RCNAC%==6
RCNIS%==7
RCNIC%==10
RCNCR%==11
RCNCA%==12
RCNDS%==13
RCNAA%==14
RCNID%==15
RCNDU%==16
RCNND%==17
RCNNL%==20
RCNMM%==21
RCNTB%==22
RCNLJ%==23
RCNBN%==24
RCNEM%==25
RCMLD%==26

	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
	ERCODE	RCNIST,RCNIS%	;ILLEGAL STRING
	ERCODE	RCNICN,RCNIC%	;ILLEGAL CPU NUMBER
	ERCODE	RCNCIR,RCNCR%	;CPU STILL RUNNING
	ERCODE	RCNCAD,RCNCA%	;CAN'T ATTACH DISK
	ERCODE	RCNDIS,RCNDS%	;DEVICE IS SPOOLED
	ERCODE	RCNDAA,RCNAA%	;DEVICE IS ALREADY ATTACHED
	ERCODE	RCNILD,RCNID%	;ILLEGAL DEVICE
	ERCODE	RCNDIU,RCNDU%	;DEVICE IN USE
	ERCODE	RCNCDD,RCNND%	;CAN NOT DETACH DISK
	ERCODE	RCNLNL,RCNNL%	;LOKCON NOT LOADED
	ERCODE	RCNRMM,RCNMM%	;REMOVING MONITOR MEMORY
	ERCODE	RCNJTB,RCNTB%	;JOB(S) TOO BIG
	ERCODE	RCNMLJ,RCNLJ%	;MOVING LOCKED JOB(S)
	ERCODE	RCNBNA,RCNBN%	;BOOTSTRAP NOT AVAILABLE
	ERCODE	RCNNEM,RCNEM%	;NON-EXISTANT MICROCODE
	ERCODE	RCNMLD,RCMLD%	;MICROCODE LENGTHS DIFFER
;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
	PUSHJ	P,RECROM	;SET TO "RUN ONLY ME"
	  JRST	RCNTAS		;TIME-SHARING HAS ALREADY BEEN STOPPED
	JRST	CPOPJ1##	;TELL THE USER THAT HE DID GOOD
;HERE TO SUSPEND THE SYSTEM (FUNCTION 1)

RCNSPN:	PUSH	P,T1		;SAVE MONBTS ADDRESS
IFN FTMP,<PUSHJ P,ONCPU0##>	;GET ON THE BOOT CPU
	PUSHJ	P,RECROM	;SET TO "RUN ONLY ME"
	  JRST	RCNTAS		;NOT MUCH WE CAN DO!
	MOVEI	T1,[ASCIZ /Expect an interruption of service/]
	PUSHJ	P,RECSAL	;SEND ALL, BUT DON'T WAIT FOR COMPLETION
	MOVEI	T1,5		;SLEEP FOR A BIT
	PUSHJ	P,SLEEP
	PUSHJ	P,RCNIOW	;WAIT FOR I/O TO COMPLETE
	MOVEI	T1,[ASCIZ /Suspending system operation/]
	PUSHJ	P,RECSAW	;SEND ALL AND WAIT FOR COMPLETION
	HRROI	T1,[IORM T2,.CPRUN##-.CPCDB##(P1) ;LIGHT SUSPEND BIT
		    POPJ P,]
	MOVSI	T2,(CR.SPD)	;GET THE SUSPEND BIT
	PUSHJ	P,CPUAPP##	;MAKE ALL GO AWAY EXECPT FOR BOOT
	PUSHJ	P,RCNIOW	;WAIT FOR I/O TO COMPLETE
	POP	P,T1		;GET BACK USER AC, WHICH CONTAINS MONBTS ADDR
	HRRZM	T1,MBTCOM##	;STORE IT INTO THE MONBTS COMMUNICATION AREA
	MOVEI	T1,SYSRST##	;RESTART ADDRESS
	HRRM	T1,.JBSA##	;STORE THAT FOR REBOOT
	MOVSI	T1,(CR.SPD!CR.TSS) ;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
	MOVEI	T1,[SETZM .CPSTS##-.CPCDB##(P1) ;CLEAR TIMESHARING STOPPED
		    POPJ P,]
	PUSHJ	P,CPUAPP##	;DO IT FOR ALL CPUS
	MOVSI	T1,(CR.TSS)	;DUMP FAILED BIT
	TDNN	T1,.CPRUN##	;DID IT FAIL?
	JRST	RCNSP3		;SYSTEM WAS RESUMED, GIVE GOOD RETURN TO USER
	ANDCAM	T1,.CPRUN##	;YES, CANNOT SUSPEND THE SYSTEM
	JRST	RCNCND		;GIVE THE USER AN ERROR RETURN
RCNSP3:	MOVEI	T1,[ASCIZ /System resumed/]
	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	RECSAL		;SEND ALL, DON'T WAIT FOR COMPLETION
;HERE TO TAKE A CI7 CONTINUABLE DUMP (FUNCTION 2)

RCNCI7:	MOVE	T1,JBTPPN##(J)	;GET PPN OF JOB
	CAME	T1,FFAPPN##	;MUST BE 1,2 TO DO THIS
	JRST	RCNNPV		;NO, NOT PRIVILEGED
	MOVSI	T1,(DF.RDC!DF.DDC) ;DON'T DO THIS IF WE WILL RELOAD
	TDNN	T1,DEBUGF##	;  ON IT OR IF WE WON'T TAKE THE DUMP
	PUSHJ	P,BTAVAL##	;IS THE BOOTSTRAP AVAILABLE?
	  JRST	RCNCND		;NO, CAN'T DO IT
	STOPCD	.+1,DEBUG,CI7,	;++CI7 CONTINUABLE SNAPSHOT DUMP
	JRST	CPOPJ1##	;GIVE SUCCESS RETURN


;HERE TO SET/CLEAR DF.NAR IN DEBUGF TO ENABLE/DISABLE AUTO RELOADS.
;  (FUNCTION 3)

RCNNAR:	CAIE	T1,2		;MUST HAVE EXACTLY ONE ARGUMENT
	JRST	RCNIAL		;ELSE ILLEGAL
	PUSHJ	P,GETWR1##	;GET THE ARGUMENT
	  JRST	RCNADC		;ADDRESS CHECK
	MOVSI	T2,(DF.NAR)	;GET THE RELEVANT BIT
	SKIPE	T1		;WANT TO SET THE BIT?
	IORM	T2,DEBUGF##	;YES, DO SO
	SKIPN	T1		;WANT TO CLEAR THE BIT?
	ANDCAM	T2,DEBUGF##	;YES, DO SO
	JRST	CPOPJ1##	;GIVE SUCCESS RETURN
;HERE TO SPECIFY A NEW BOOTXT STRING (FUNCTION 4)

RCNBTX:	SOJLE	T1,RCNIAL	;DISCOUNT THIS WORD, CHECK FOR LENGTH ERROR
	CAILE	T1,BTXLEN##	;IS IT TOO LONG?
	JRST	RCNIAL		;YES, GIVE ERROR RETURN
	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVE	P1,T1		;SAVE +LENGTH FOR FIRST LOOP
	MOVN	P2,T1		;  AND -LENGTH FOR SECOND LOOP
	MOVE	P3,M		;SAVE M ALSO
RCNBT1:	PUSHJ	P,GETWR1##	;GET NEXT WORD IN STRING
	  JRST	RCNADC		;ADDRESS CHECK
	MOVE	T2,[POINT 7,T1]	;GET BYTE POINTER TO STRING
RCNBT2:	ILDB	T3,T2		;GET NEXT BYTE
	JUMPE	T3,RCNBT3	;GO IF FOUND THE END
	CAIN	T3,12		;ANY LINE FEEDS IN THE STRING?
	JRST	RCNIST		;YES, CR+LF WILL SCREW UP BOOT (RESTRICT TO CR)
	TLNE	T2,(76B5)	;DONE WITH THIS WORD YET?
	JRST	RCNBT2		;NO, CONTINUE
	SOJG	P1,RCNBT1	;YES, GET NEXT WORD
	JRST	RCNIAL		;SIZE OF STRING WAS WRONG
RCNBT3:	SOJN	P1,RCNIAL	;SIZE OF STRING WAS WRONG
	HRLZ	P1,P2		;MAKE AOBJN POINTER TO STRING WORDS
	MOVE	M,P3		;RESTORE M
RCNBT4:	PUSHJ	P,GETWD1##	;GET NEXT WORD IN STRING
	MOVEM	T1,BOOTXT##(P1) ;STORE IN MEMORY
	AOBJN	P1,RCNBT4	;LOOP FOR ALL WORDS
	JRST	CPOPJ1##	;GIVE SKIP RETURN


;HERE TO RELOAD THE SYSTEM.  (FUNCTION 5)

RCNRLD:	MOVE	T1,JBTPPN##(J)	;GET PPN OF JOB
	CAME	T1,FFAPPN##	;MUST BE 1,2 TO DO THIS
	JRST	RCNNPV		;NO, NOT PRIVILEGED
IFN FTMP,<PUSHJ P,ONCPU0##>	;GET TO THE BOOT CPU (FOR AESTHETIC REASONS)
	MOVSI	T1,(DF.RIP)	;RELOAD IN PROGRESS
	IORM	T1,DEBUGF##	;TELL DIE AND REBOOT ABOUT IT
	STOPCD	.,STOP,RLD,	;++RELOAD MONITOR
;HERE TO FORCE AUTCON TO RUN AND POSSIBLY ADD DEVICES. (FUNCTION 6)

RCNATC:	CAIE	T1,2		;MUST BE EXACTLY 1 ARGUMENT
	JRST	RCNIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,GETWR1##	;GET CPU NUMBER
	  JRST	RCNADC		;ADDRESS CHECK
	CAME	T1,[-1]		;ALL CPUS?
	CAIG	T1,M.CPU##	;NO, A LEGAL CPU?
	CAIA			;ALL OR LEGAL
	JRST	RCNICN		;ILLEGAL CPU SPECIFIED
	MOVE	T3,T1		;SAVE CPU ARGUMENT
	PUSHJ	P,RECROM	;SET "RUN ONLY ME"
	  JRST	RCNTAS		;TIMESHARING ALREADY STOPPED
	PUSHJ	P,RCNIOW	;WAIT FOR I/O TO STOP
	JUMPL	T3,RCNAC1	;GO IF ALL CPUS SPECIFIED
	PUSHJ	P,SAVE1##	;SAVE AN AC
	IMULI	T3,.CPLEN##	;OFFSET INTO CDBS FOR THIS CPU
	MOVE	P1,.C0SLF##(T3)	;CDB FOR SPECIFIED CPU
	PUSHJ	P,RCNDOA	;AUTOCONFIGURE DEVIECS ON THAT CPU
	JRST	RCNAC2		;ONWARD
RCNAC1:	MOVEI	T1,RCNDOA	;SUBROUTINE TO EXECUTE ACROSS CPUS
	PUSHJ	P,CPUAPP##	;DO THE AUTOCONFIGURATION ON ALL CPUS
RCNAC2:	PUSHJ	P,RECCRM	;CLEAR "RUN ONLY ME"
	JRST	CPOPJ1##	;GOOD RETURN

;SUBROUTINE TO CAUSE AUTCON TO BE RUN ON A SPECIFIED CPU
;CALL WITH P1 = THE CDB ADDRESS FOR THE CPU
RCNDOA:
IFN FTMP,<
	MOVE	T1,.CPCPN##-.CPCDB##(P1) ;CPU NUMBER
	PUSHJ	P,ONCPUS##	;GET ONTO THE CORRECT CPU
	  POPJ	P,		;NOOP IF NOT RUNNING
> ;END IFN FTMP
	PJRST	AUTCPU##	;DO IT
;HERE TO SET MEMORY ON LINE (FUNCTION 11)

RCNMOL:	PUSHJ	P,RCNMEM	;DO ARGUMENT CHECKING
	  POPJ	P,		;PROPAGATE FAILURE
	PUSHJ	P,SAVE2##	;SO COMCON WON'T CLOBBER THEM
	AOS	(P)		;WE WILL SUCCEED
	PJRST	MEMONU##	;HAVE COMCON PUT THE PAGES ON-LINE

RCNMEM:	CAIGE	T1,3		;HAVE ENOUGH ARGUMENTS?
	JRST	RCNIAL		;NO, ILLEGAL ARGUMENT LIST
	PUSHJ	P,GETWR1##	;GET FIRST PAGE TO SET ONLINE
	  JRST	RCNADC		;ADDRESS CHECK
	MOVE	T2,T1		;SAVE IT
	PUSHJ	P,GETWR1##	;GET FIRST PAGE TO LEAVE ALONE (LAST PAGE+1)
	  JRST	RCNADC		;ADDRESS CHECK
	EXCH	T1,T2		;GET IN RIGHT ORDER
	TLNN	T1,-1		;IF EITHER IS RIDICULOUS
	TLNE	T2,-1		; ...
	JRST	RCNIAL		;ILLEGAL ARGUMENT LIST
	CAML	T1,T2		;MUST BE IN RIGHT ORDER
	JRST	RCNIAL		;OR ILLEGAL ARG LIST
	JRST	CPOPJ1##	;GIVE OK RETURN
;HERE TO SET MEMORY OFF LINE (FUNCTION 12)

RCNMOF:	SKIPN	[M.LOK##]	;IS LOKCON LOADED?
	JRST	RCNLNL		;ERROR IF NOT
IFN FTMP,<
	PUSHJ	P,ONCPU0##	;AVOID POSSIBLE RACE WITH COMCON
>
	PUSHJ	P,RCNMEM	;CHECK OUR ARG LIST
	  POPJ	P,		;PROPAGATE FAILURE
	PUSHJ	P,CKMOL##	;CHECK THAT RANGE DOESN'T OVERLAP THE MONITOR
	  JRST	RCNRMM		;IT DOES SO WE CAN'T DO IT
	LDB	T3,[POINT 14,NWCORE##,26] ;GET TOTAL SIZE (ON OR OFF)
	CAIL	T1,(T3)		;LOWER BOUND BEYOND END?
	JRST	CPOPJ1##	;YES, IT'S ALREADY OFF
	CAIL	T2,(T3)		;UPPER BOUND BEYOND END?
	MOVE	T2,T3		;YES,CHANGE UPPER BOUND
	PUSH	P,T1		;SAVE LOWER BOUND
	PUSH	P,T2		;AND UPPER BOUND
	PUSHJ	P,NEWCMX##	;SEE IF ALL JOBS CAN CONTINUE TO RUN
	JUMPLE	T1,[ADJSP P,-2	;IF .LE. 0, REMOVING MONITOR MEMORY
		    JRST RCNRMM];GO EXPLAIN THE PROBLEM
	PUSH	P,J		;SAVE J
	MOVEI	J,0		;STARTING WITH JOB 0,
	PUSHJ	P,JBSTBG##	;MAKE SURE ALL JOBS CAN STILL RUN (I.E., NONE IS TOO BIG)
	  JRST	RCNMF2		;NONE ARE
	POP	P,J		;RESTORE J
	ADJSP	P,-2		;BALANCE STACK
	JRST	RCNJTB		;JOB(S) TOO BIG
RCNMF2:	MOVEI	J,0		;STARTING WITH JOB 0,
	DMOVE	T1,-2(P)	;RETRIEVE BOUNDS
	PUSHJ	P,CKLJB##	;SEE IF RANGE OVERLAPS SOME LOCKED JOB
	  JRST	RCNMF3		;IT DOESN'T SO ALL IS WELL
	POP	P,J		;RESTORE J
	ADJSP	P,-2		;BALANCE STACK
	JRST	RCNMLJ		;ERROR IF NEED TO MOVE LOCKED JOB(S)
RCNMF3:	POP	P,J		;RESTORE J
	POP	P,T2		;RESTORE UPPER BOUND
	POP	P,T1		;AND LOWER BOUND
	AOS	(P)		;WILL SUCCEED NOW
	PJRST	MEMOFU##	;GO SET THE MEMORY OFF-LINE
;HERE TO FIND THE CPU ACCESSABILITY MASK FOR A DEVICE (FUNCTION 13)

RCNCPU:	CAIGE	T1,2		;MUST HAVE AT LEAST ANOTHER WORD
	JRST	RCNIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,GETWR1##	;GET DEVICE TO DETACH
	  JRST	RCNADC		;ADDRESS CHECK
	CAME	T1,[SIXBIT /CPU/] ;IS IT GENERIC CPU?
	JRST	RCNCP1		;NO, TRY FOR SPECIFIC CPU
IFN FTMP,<
	SETZ	T2,		;YES, ZERO BIT ACCUMULATION
	MOVEI	T1,[MOVE T1,.CPRUN##-.CPCDB##(P1) ;GET RUN BITS
		    TLNN T1,(CR.NRN!CR.RMV!CR.DET!CR.SPD) ;IS IT AVAILABLE?
		    TDO	 T2,.CPBIT##-.CPCDB##(P1) ;YES, ADD IN ITS BIT
		    POPJ P,]	;END OF ROUTINE
	PUSHJ	P,CPUAPP##	;COLLECT THE BITS FOR ALL RUNNING CPUS
	MOVE	T1,T2		;COPY BIT MASK TO RETURN AC
>
IFE FTMP,<
	MOVE	T1,.CPBIT##	;GET OUR BIT
>
	JRST	STOTC1##	;RETURN BIT MASK TO USER
RCNCP1:	MOVE	T2,T1		;COPY FOR FINDERS
IFN FTMP,<
	PUSHJ	P,CPUFND##	;IS IT A CPU?
	  JRST	RCNCP2		;NO, TRY DEVICES
	CAIL	T1,M.CPU##	;YES, IS IT IN RANGE?
	JRST	RCNICN		;NO, GIVE ERROR
	MOVE	T1,T3		;COPY MASK
	ANDI	T1,77		;KEEP ONLY LOW PORTION
>
IFE FTMP,<
	MOVE	T1,.CPBIT##	;GET OUR BIT (IN CASE IT'S US)
	CAME	T2,.CPPHY##	;IS IT OUR PHYSICAL NAME?
	CAMN	T2,.CPLOG##	;OR OUR LOGICAL NAME?
>
	JRST	STOTC1##	;YES, RETURN ITS BIT TO THE USER
RCNCP2:	MOVE	T1,T2		;RESTORE DEVICE NAME
	PUSHJ	P,DEVPSN	;SEARCH FOR DEVICE
	  JRST	RCNCP4		;CHECK FOR DISK UNIT ANYWAY
	SKIPGE	DEVSPL(F)	;SPOOLED?
	JRST	RCNDIS		;YES, ERROR
	MOVE	T2,DEVMOD(F)	;CHECK TO SEE IF THIS IS DSK
	TLNE	T2,DVDSK	;TRYING TO FIND A DISK?
	JRST	RCNCP4		;YES, DO IT DIFFERENTLY
IFN FTMP,<
	TLNE	T2,DVTTY	;TTY?
	SKIPN	U,DDBLDB##(F)	;YES, GET LDB
	JRST	RCNC2A		;NOT TTY OR NO LDB, USE DDB
	LDB	T2,LDPCPU##	;GET OWNING CPU
	JRST	RCNC2B		;CONTINUE
RCNC2A:	LDB	T2,DEYCPF##	;GET OWNING CPU NUMBER
	CAIE	T2,CPFBIT##	;NEED A BIT MASK?
	JRST	RCNC2B		;NO
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,.TYMTA	;MAGTAPE?
	STOPCD	RCNC2B,DEBUG,NMCPUM,	;++NEED MISSING CPU MASK
	SKIPE	T1,TDVUDB##(F)	;YES, GET ITS UDB ADDRESS
	MOVE	T1,UDBCAM(T1)	;AND THE CPU ACCESSABILITY MASK
	JRST	STOTC1##	;RETURN WINNING MASK TO USER
RCNC2B:	MOVEI	T1,1		;GET A BIT
	LSH	T1,(T2)		;CONVERT TO A MASK
	CAIN	T2,CPFBOO##	;GENERIC BOOT CPU?
	MOVEI	T1,77		;YES, ALL CPUS CAN REACH IT
>
IFE FTMP,<
RCNCP3:	MOVEI	T1,1		;BOTTOM BIT ONLY IF NO MP
>
	JRST	STOTC1##	;RETURN WINNITUDE TO USER

;HERE TO FIND A DSK
RCNCP4:	PUSHJ	P,SRSTR##	;LOOK FOR A STRUCTURE
	  JRST	RCNCP6		;NO, TRY FOR A UNIT
IFE FTMP,<
	JRST	RCNCP3		;GO WITH CPU0 IF VALID STR
>
IFN FTMP,<
	MOVEI	T3,77		;START BY ASSUMING AVAILABLE ON ALL CPUS
RCNCP5:	PUSHJ	P,GETCAM##	;GET BITS FOR THIS SPINDLE
	AND	T3,T1		;STRUCTURES ARE RESTRICTIVELY ACCUMULATED
	HLRZ	U,UNISTR(U)	;GET NEXT UNIT IN STRUCTURE
	JUMPN	U,RCNCP5	;LOOP OVER ALL UNITS IN STR
	MOVE	T1,T3		;PUT BITS IN RIGHT AC
	JRST	STOTC1##	;RETURN BITS WITH WINNITUDE
> ;END OF IFN FTMP

;HERE TO FIND A DISK UNIT
RCNCP6:	SETO	T2,		;ALLOW ONLY FULL MATCHES, NOT ABBREVIATIONS
	PUSHJ	P,SRUNA##	;LOOK FOR A MATCHING UNIT
	  JRST	RCNILD		;NOT A DISK, SO IT'S ILLEGAL
	  JFCL			;LOGICAL MATCH IS OK
IFE FTMP,<
	JRST	RCNCP3		;RETURN ONLY CPU IF NO SMP FEATURE
>
IFN FTMP,<
	PUSHJ	P,GETCAM##	;GET BITS FOR THE SPINDLE (BOTH PORTS)
	JRST	STOTC1##	;RETURN IT WINNINGLY TO THE USER
>
;HERE TO WAIT FOR ALL I/O ON THE SYSTEM TO CEASE (FUNCTION 14)

RCNIOW::MOVEI	F,DEVLST##-DEVSER ;START AT FIRST DDB
RCNIO1:	HLRZ	F,DEVSER(F)	;STEP TO NEXT DDB
	JUMPE	F,RCNIO3	;DONE WITH LOW CORE DDBS
	LDB	T1,PDVTIM##	;GET HUNG TIMER
	JUMPE	T1,RCNIO1	;IGNORE DEVICES WHICH CAN'T HANG
	MOVEI	T1,IOACT	;I/O ACTIVE BIT
	TDNN	T1,DEVIOS(F)	;IS IT ON HERE?
	JRST	RCNIO1		;NO, KEEP LOOKING
RCNIO2:	SETZ	T1,		;YES, SET ARGUMENT FOR A TICK
	PUSHJ	P,SLEEP		;SNOOZE A BIT
	JRST	RCNIOW		;AND START LOOKING AGAIN

;HERE WHEN NO LOW CORE DDB HAS IOACT LIT
RCNIO3:	HLRZ	T1,SYSCHN##	;POINT TO FIRST CHANNEL DB ON SYSTEM
RCNIO4:	SKIPL	CHNBSY(T1)	;IS THIS CHANNEL ACTIVE?
	JRST	RCNIO2		;YES, SNOOZE A WHILE
	HLRZ	T1,CHNSYS(T1)	;NO, POINT TO NEXT DB
	JUMPN	T1,RCNIO4	;CHECK ALL CHANNEL DATA BLOCKS FOR BUSY
	MOVE	T1,[ACTDRB,,ACTDRB] ;WHAT AN EMPTY DRB QUEUE LOOKS LIKE
	CAME	T1,ACTDRB##	;CI DISK I/O PENDING?
	JRST	RCNIO2		;YES--DO IT ALL OVER AGAIN
	POPJ	P,		;RETURN
;HERE TO SET/CLEAR DUMP/RELOAD BITS IN DEBUGF (FUNCTIONS 15 AND 16)

DFFLGS==DF.RDC!DF.RJE!DF.NAR!DF.CP1!DF.DDC!DF.DJE!DF.DCP ;LEGAL FLAGS TO DIDDLE

RCNSDF:	SKIPA	P1,[IORB T1,DEBUGF##] ;GET INSTRUCTION TO EXECUTE FOR SET
RCNCDF:	MOVE	P1,[ANDCAB T1,DEBUGF##] ;GET INSTRUCTION TO EXECUTE FOR CLEAR
	CAIE	T1,2		;MUST BE EXACTLY ONE ARGUMENT
	JRST	RCNIAL		;ILLEGAL ARGUMENT LIST
	PUSHJ	P,GETWR1##	;GET FLAGS
	  JRST	RCNADC		;ADDRESS CHECK
	AND	T1,[DFFLGS]	;KEEP JUST LEGAL FLAGS
	XCT	P1		;SET/CLEAR THE FLAGS
	PJRST	STOTC1##	;STORE NEW FLAGS IN AC AND SKIP RETURN
;HERE TO READ BOOTSTRAP MICROCODE INFORMATION

RCNRBM:	CAIGE	T1,2		;MUST BE AT LEAST TWO WORDS
	JRST	RCNIAL		;BAD ARGUMENT LIST LENGTH
	PUSHJ	P,SAVE3##	;FREE UP SOME AC'S
	MOVE	P1,T1		;SAVE ARGUMENT BLOCK LENGTH
	PUSHJ	P,BTAVAL##	;SEE IF BOOTSTRAP IS AVAILABLE
	  JRST	RCNBNA		;NO
	MOVE	P2,T2		;COPY VIRTUAL ADDRESS OF BOOTSTRAP AREA
	MOVSI	T3,-UCDNUM	;SET TO SCAN FOR EXISTANT MICROCODES
	SETZ	T1,		; AND COUNT THEM TOO
RCNRB1:	SKIPE	.BTUCD(T2)	;LENGTH NON-ZERO?
	ADDI	T1,1		;YES, MICROCODE EXISTS
	ADDI	T2,2		;ADVANCE TO NEXT PAIR OF MICROCODE DESCRIPTORS
	AOBJN	T3,RCNRB1	;LOOP FOR MAXIMUM NUMBER OF MICROCODES
	PUSHJ	P,PUTWR1##	;STORE THE NUMBER OF ENTRIES RETURNED
	  JRST	RCNADC		;ADDRESS CHECK
	JUMPE	T1,CPOPJ1##	;IF NO MICROCODES, WE'RE DONE
	LSH	T1,1		;ACCOUNT FOR TWO-WORD RETURNED DATA PAIRS
	CAILE	T1,-2(P1)	;DID USER SPECIFY A LONG ENOUGH ARGUMENT LIST?
	JRST	RCNIAL		;NO, BAD ARGUMENT LIST LENGTH
	MOVSI	P1,-UCDNUM	;SET TO SCAN THROUGH MICROCODES AGAIN
	MOVE	P3,P2		;COPY BOOTSTRAP VECTOR ADDRESS
RCNRB2:	SKIPN	T1,.BTUCD(P2)	;CHECK LENGTH, DOES MICROCODE EXIST?
	JRST	RCNRB3		;NO
	HRL	T1,P1		;COPY MICROCODE INDEX
	PUSHJ	P,PUTWR1##	;STORE IT
	  JRST	RCNADC		;ADDRESS CHECK
	MOVE	T1,.BTUCD+1(P2)	;GET OFFSET TO MICROCODE DATA
	ADD	T1,P3		;GET ACTUAL ADDRESS OF MICROCODE DATA
	MOVE	T1,(T1)		;GET FIRST WORD (VERSION NUMBER)
	PUSHJ	P,PUTWR1##	;STORE IT
	  JRST	RCNADC		;ADDRESS CHECK
RCNRB3:	ADDI	P1,1		;NEXT MICROCODE INDEX
	ADDI	P2,2		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	P1,RCNRB2	;LOOP FOR REMAINDER OF ENTRIES
	JRST	CPOPJ1##	;SKIP RETURN
;HERE TO SUPPLY A NEW BOOTSTRAP MICROCODE

RCNSBM:	CAIGE	T1,3		;MUST BE AT LEAST THREE WORDS
	JRST	RCNIAL		;BAD ARGUMENT LIST LENGTH
	PUSHJ	P,SAVE3##	;FREE UP SOME AC'S
	PUSHJ	P,BTAVAL##	;SEE IF BOOTSTRAP IS AVAILABLE
	  JRST	RCNBNA		;NO
	MOVE	P1,T2		;COPY VIRTUAL ADDRESS OF BOOTSTRAP AREA
	PUSHJ	P,GETWR1##	;GET NEXT WORD OF BLOCK (UCODE INDEX,,LENGTH)
	  JRST	RCNADC		;ADDRESS CHECK
	HLRZ	T2,T1		;COPY UCODE INDEX
	ADD	T2,P1		;OFFSET BY BASE OF MICROCODE
	SKIPN	T3,.BTUCD(T2)	;DOES THIS MICROCODE EXIST (NON-ZERO LENGTH)?
	JRST	RCNNEM		;NOPE
	CAIE	T3,(T1)		;LENGTHS MATCH?
	JRST	RCNMLD		;NOPE
	MOVE	P3,.BTUCD+1(T2)	;GET OFFSET TO MICROCODE WITHIN BOOTSTRAP
	ADD	P3,P1		;INCLUDE BASE OF MICROCODE
	MOVE	P1,.BTUCD(T2)	;COPY LENGTH OF MICROCODE
	PUSHJ	P,GETWR1##	;GET NEXT WORD OF BLOCK (ADDRESS OF UCODE DATA)
	  JRST	RCNADC		;ADDRESS CHECK
	MOVE	P2,T1		;SET UP FOR AN XBLT
	MOVE	T2,P1		;COPY LENGTH OF MICROCODE
	PUSHJ	P,ARNGE##	;CHECK VALIDITY OF ADDRESSES
	 JRST	RCNADC		;ADDRESS CHECK
	  JRST	RCNADC		;DITTO
	DMOVE	T1,P1		;COPY ACS
	MOVE	T3,P3		;IN CASE OF KS-10
	XBLTUX	T1,		;COPY THE MICROCODE
	JRST	CPOPJ1##	;SKIP RETURN
;ROUTINE TO SET FOR "RUN ONLY ME" FOR RECON. UUO FUNCTIONS
;CALL:
;	J/ JOB NUMBER TO "RUN ONLY"
;	PUSHJ	P,RECROM
;	  <NON-SKIP>		;TIMESHARING ALREADY STOPPED
;	<SKIP>			;TIMESHARING STOPPED FOR ALL BUT SPECIFIED JOB

RECROM::
IFN FTMP,<
	PUSHJ	P,SBSCD##	;GET SCHEDULAR INTERLOCK (RESTORE ON POPJ)
>; END IFN FTMP
	MOVEI	T1,[CAME T2,.CPSTS##-.CPCDB##(P1)
		    SKIPN .CPSTS##-.CPCDB##(P1)
		    CAIA
		    SETO T2,
		    POPJ P,]
	MOVE	T2,.CPJOB##	;GET JOB NUMBER OF REQUESTOR
	PUSHJ	P,CPUAPP##	;HAS TIME-SHARING BEEN STOPPED ON ANY CPU?
	JUMPL	T2,CPOPJ##	;ERROR RETURN IF TIMESHARING ALREADY STOPPED
	MOVEI	T1,[MOVEM J,.CPSTS##-.CPCDB##(P1)
		    POPJ P,]
	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	CPUAPP##	;MAKE THIS JOB THE ONLY RUNNABLE JOB ON SYSTEM


;ROUTINE TO CLEAR "RUN ONLY ME"
RECCRM::MOVEI	T1,[SETZM .CPSTS##-.CPCDB##(P1)
		    POPJ  P,]
	PJRST	CPUAPP##	;CLEAR "RUN ONLY ME"



;ROUTINES TO DO SEND ALL FOR RECON. UUO FUNCTIONS.
;CALL:
;	T1/ TEXT ADDRESS
;	PUSHJ	P,RECSAL/RECSAW
;RECSAW WAITS FOR THE MESSAGE TO BE OUTPUT BEFORE RETURNING.
;BOTH ROUTINES EXPECT TO BE RUNNING ON BOOT CPU SO SNDCTR IS
;INTERLOCKED WITH RESPECT TO COMCON.

RECSAL:	TDZA	T2,T2		;NO WAIT
RECSAW:	SETO	T2,		;WAIT
	PUSH	P,T2		;SAVE THE FLAG
	PUSH	P,T1		;SAVE THE TEXT ADDRESS
RECSA1:	SKIPN	SNDCTR##	;SEND ALL IN PROGRESS?
	JRST	RECSA2		;NO
	MOVEI	T1,1		;YES, SLEEP FOR A SECOND
	PUSHJ	P,SLEEP
	JRST	RECSA1		;CHECK AGAIN

RECSA2:	POP	P,T1		;RESTORE TEXT ADDRESS
	PUSHJ	P,RECSAX	;DO THE CO-ROUTINE CALL TO FRCSET
	POP	P,T2		;GET THE WAIT FLAG
	JUMPE	T2,CPOPJ##	;RETURN IF NO WAIT FOR OUTPUT NEEDED
RECSA3:	MOVEI	T1,1		;SLEEP FOR A SECOND
	PUSHJ	P,SLEEP
	SKIPE	SNDCTR##	;SEND ALL COMPLETED?
	JRST	RECSA3		;NO, SLEEP A LITTLE LONGER
	POPJ	P,		;ALL DONE

RECSAX:	PUSHJ	P,FRCSET##	;SET UP TO TYPE ON FRCLIN
	PUSH	P,T1		;SAVE TEXT ADDRESS
	PUSHJ	P,INLMES##	;INSERT THE "SEND ALL "
	ASCIZ	/SEND ALL /
	POP	P,T1		;RESTORE TEXT ADDRESS
	PUSHJ	P,CONMES##	;OUTPUT IT
	PJRST	CRLF##		;APPEND A CRLF AND RETURN
;HERE FROM CLOCK1 WHEN SNAPSHOT HAS BEEN TAKEN TO STICK OUR HEAD IN THE SAND
RMVCPU::
IFN FTKL10,<
IFN FTENET,<
	PUSHJ	P,KNIRMV##	;ZAP THE KLNI
>; END IFN FTENET
IFN FTSCA,<
	PUSHJ	P,PPDRMV##	;ZAP THE KLIPA
>; END IFN FTSCA
	MOVEI	T1,LG.CSL!LG.CSW ;TURN OFF CACHE BITS
	ANDCAM	T1,.CPEBR##	;FOR 400 RE-START
	MOVE	F,.CPCPN##	;CPU NUMBER
	MOVE	F,DTEMAS##(F)	;THE MASTER DTE
	PUSHJ	P,TTDRLD##	;CLEAR F.E. TTY STATUS
	PUSHJ	P,SVPPC##	;TURN OFF "KEEP ALIVE"
>
IFN	FTKS10,<
	PUSHJ	P,DISKAL##	;DISABLE KEEP ALIVE
>
	PUSHJ	P,CSDMP##	;EMPTY CACHE
	AOS	.CPCSN##	;INSURE SWEEP GETS RECORDED

	CONO	PI,CLRPIS##	;DON'T MAINTAIN OK WORDS
	CONO	APR,APRRST##	;BLAST THE PROCESSOR
	MOVE	1,.+1		;GET AN INFINITE LOOP
	JRST	1		;AND DISAPPEAR
	SUBTTL	CMAND. UUO PLAY WITH USER-DEFINABLE COMMANDS.

CMAND:	HLRZ	U,T1		;GET FUNCTION CODE
	CAIL	U,NLCMDN	;RANGE CHECK
	 JRST	CMDIAL		;BAD FUNCTION CODE
	HRR	M,T1		;POINT TO OUR ARGUMENT LIST NOW.
	JRST	@CMDDSP(U)	;AND DISPATCH

CMDDSP:	IFIW	CMDINT		;INITIALIZE AND INSERT COMMANDS
	IFIW	CMDADD		;ADD COMMANDS TO TABLE
	IFIW	CMDDEL		;DELETE A COMMAND FROM TABLE.
	IFIW	CMDLST		;LIST COMMAND NAMES
	IFIW	CMDRET		;RETURN INFORMATION ABOUT A COMMAND
	IFIW	CMDDMP		;DUMP COMMAND DATA BASE
NLCMDN==.-CMDDSP

;ERROR CODES RETURNED
CMIAL%==1			;ILLEGAL ARGUMENT LIST
CMADC%==2			;ADDRESS CHECK
CMNER%==3			;NOT ENOUGH ROOM IN FUNNY SPACE
CMDNF%==4			;DID NOT FINISH (NO ROOM IN USER BUFFER)
CMNSN%==5			;NO SUCH NAME (FOR .CMRET FUNCTION)

	ERCODE	CMDIAL,CMIAL%	;DEFINE ERROR RETURNS
	ERCODE	CMDADC,CMADC%
	ERCODE	CMDNER,CMNER%
	ERCODE	CMDDNF,CMDNF%
	ERCODE	CMDNSN,CMNSN%

;BYTE SIZE VALUES FOR .PDUNQ
CM.BSZ==6			;BYTE SIZE IN BITS
CM.BPW==^D36/CM.BSZ		;NUMBER OF BYTES PER WORD
CM.BP1==CM.BPW-1		;ROUND-UP VALUE FOR WORDS TO STORE BYTES
CM.BPE==2*CM.BPW+1		;NUMBER OF BYTES PER COMMAND ENTRY IN TABLE

;SACFLG VALUE FOR COMCON
XP CM.SAC,40			;AUTO-PUSH COMMAND
;XP CM.???,20			;FREE BIT
;XP CM.UNQ,17			;UNIQUENESS BITS
;FUNCTION .CMINI
;DEFINE A NEW COMMAND LIST

CMDINT:	PUSHJ	P,SAVE1##	;IN CASE RECURSIVE UUO (HA!)
	PUSHJ	P,RMVCMD	;REMOVE ANY CURRENTLY DEFINED USER COMMANDS
	PUSHJ	P,CMDCNT	;COUNT NUMBER OF COMMANDS TO DEFINE
	  POPJ	P,		;PROPAGATE ERROR
CMDIN1:	JUMPE	P1,CPOPJ1	;IF NO COMMANDS TO DEFINE, RETURN SUCCESS.
	PUSHJ	P,CMDCOR	;GET CORE FOR OUR FREECORE DIRECTORY.
	  POPJ	P,
	PUSHJ	P,CMDINS	;AND ADD COMMANDS SUPPLIED IN THIS UUO
	  POPJ	P,		;PROPAGATE ERROR.
	RETSKP			;RETURN SUCCESS.
;FUNCTION .CMADD
;UUO FUNCTION TO ADD COMMANDS TO OUR LIST.
CMDADD:	PUSHJ	P,SAVE1##	;AVOID TRASHING A MONITOR UUO.
	PUSHJ	P,CMDCNT	;COUNT NUMBER OF COMMANDS TO ADD
	  POPJ	P,		;HMM. MUST HAVE HAD A BUM ADDRESS
	SETZ	T1,		;START COUNTING FROM 0
	SKIPN	T2,.PDCMN##(W)	;GET POINTER TO COMMAND NAMES
	JRST	CMDIN1		;NONE DEFINED. CALL THE DEFINE CODE.
CMDAD1:	SKIPN	(T2)		;IS THIS COMMAND DEFINED?
	AOJ	T1,		;NO, BUMP COUNT OF AVAILABLE COMMANDS.
	AOBJN	T2,CMDAD1	;AND CONTINUE FOR ALL COMMANDS IN DIRECTORY.
	CAMG	P1,T1		;DO WE HAVE ENOUGH ROOM TO DEFINE COMMANDS?
	JRST	CMDAD4		;YES, JUST ADD THEM.
	HLRO	T2,.PDCMN##(W)	;GET NEGATIVE SIZE OF CURRENT COMMAND DIRECTORY
	ADD	T2,T1		;CONVERT TO NEGATIVE NUMBER OF COMMANDS TAKEN
	SUB	P1,T2		;TOTAL NUMBER OF COMMANDS WE WILL NEED.
	PUSHJ	P,CMDXPN	;NOT ENOUGH ROOM, EXPAND OUR DIRECTORY.
	  POPJ	P,		;PROPAGATE ERROR.
CMDAD4:	PJRST	CMDINS		;AND INSERT OUR COMMANDS
;FUNCTION .CMDEL
;DELETE COMMANDS
CMDDEL:	PUSHJ	P,SAVE4##
	PUSHJ	P,GETWRD##	;GET NUMBER OF COMMANDS TO DELETE
	  JRST	CMDADC		;BLOW UP
	MOVE	P1,T1		;COPY NUMBER OF COMMANDS TO DO
CMDDE1:	SOJLE	P1,CPOPJ1##	;RETURN SUCCESS.
	PUSHJ	P,GETWR1##	;GET NEXT COMMAND NAME TO DELETE
	  JRST	CMDADC		;BAD ADDRESS
	PUSHJ	P,CMDINI	;INITIALIZE POINTERS
	JUMPE	P2,CMDDE1	;IF NO COMMANDS, DON'T TRY SEARCHING
	JUMPE	T1,CMDDE1	;IF NULL COMMAND, PUNT
CMDDE2:	CAME	T1,(P2)		;IS THIS THE COMMAND WE WANT?
	JRST	CMDDE3		;NOPE, TRY FOR NEXT ONE
	PUSHJ	P,CMDREM	;REMOVE IT.
CMDDE3:	PUSHJ	P,CMDADV	;ADVANCE POINTERS
	  JRST	CMDDE2		;AND TRY NEXT LOCATION IN COMMAND DIRECTORY
	JRST	CMDDE1		;AND DO THE NEXT COMMAND HE SUPPLIED US WITH
;FUNCTION .CMLST
;LIST THE COMMAND NAMES WE HAVE DEFINED. SUITABLE FOR USE BY "HELP" IN
;INFORMING THE USER SIMPLY THE NAMES AND NUMBER OF COMMANDS HE HAS DEFINED.

CMDLST:	PUSHJ	P,SAVE4##	;SINCE CMDINI TRASHES ALL 4 P REGISTERS
	SETZ	P1,		;START WITH ZERO COMMANDS
	PUSHJ	P,CMDINI	;INITIALIZE POINTERS TO COMMAND LISTS
	JUMPE	P2,CMDLS4	;IF NO COMMANDS, DON'T COUNT EM
CMDLS1:	SKIPE	(P2)		;DO WE HAVE A COMMAND NAME DEFINED?
	SKIPN	(P3)		;AND DO WE HAVE A POINTER TO A COMMAND BLOCK?
	SKIPA			;NO, DON'T COUNT THIS COMMAND
	AOJ	P1,		;INCREMENT NUMBER OF COMMANDS WE HAVE FOUND
	PUSHJ	P,CMDADV	;ADVANCE TO NEXT COMMAND POINTER
	  JRST	CMDLS1		;AND GO TRY TO COUNT ANOTHER COMMAND
CMDLS4:	PUSHJ	P,GETWRD##	;FIND OUT HOW MANY WORDS HE HAS ALLOCATED FOR US
	  JRST	CMDADC		;ADDRESS CHECK.
	EXCH	T1,P1		;SAVE NUMBER OF WORDS WE ARE ALLOWED
	PUSHJ	P,PUTWRD##	;TELL THE USER HOW MANY COMMANDS WE HAVE
	  JRST	CMDADC		;ADDRESS CHECK, TELL HIM NOT TO USE HISEG
	PUSHJ	P,CMDINI	;RE-INITIALIZE POINTERS TO COMMANDS
	JUMPE	P2,CPOPJ1##	;IF NO COMMANDS, RETURN
CMDLS2:	SKIPE	T1,(P2)		;DO WE HAVE A COMMAND NAME DEFINED?
	SKIPN	(P3)		;AND DOES IT HAVE A POINTER TO A COMMAND BLOCK
	JRST	CMDLS3		;NO, SKIP IT
	PUSHJ	P,CMDPUT	;PUT THIS COMMAND NAME IN HIS BLOCK
	  POPJ	P,		;PROPAGATE ERROR
CMDLS3:	PUSHJ	P,CMDADV	;ADVANCE TO NEXT COMMAND
	  JRST	CMDLS2		;AND GO GET THE NEXT NAME TO STORE
	RETSKP			;RETURN SUCCESS, WE HAVE GIVEN HIM ALL NAMES
;FUNCTION .CMRET
;RETURN INFORMATION ON A SINGLE COMMAND

CMDRET:	PUSHJ	P,SAVE4##	;SINCE CMDINI DESTROYS ALL P ACS
	PUSHJ	P,GETWRD##	;GET NUMBER OF WORDS WE ARE ALLOWED TO RETURN
	  JRST	CMDADC		;BOGUS ADDRESS
	MOVE	P1,T1		;SAVE NUMBER OR WORDS WE ARE ALLOWED
	HRRZ	T1,M		;FIRST ADDRESS WE ARE GOING TO RETURN TO
	HRLI	T1,(IFIW)	;MAKE SECTION RELATIVE
	MOVE	T2,P1		;GET WORD COUNT
	PUSHJ	P,ARNGE##	;RANGE CHECK ARGUMENTS
	  JRST	CMDADC		;ADDRESS CHECK
	  JFCL			;ADDRESS OK BUT ILLEGAL FOR I/O (IGNORED HERE)
	PUSHJ	P,GETWR1##	;GET NEXT WORD (NAME TO SEARCH FOR)
	  JRST	CMDADC		;ADDRESS CHECK
	SUBI	M,2		;SO THAT WE CAN OVERWRITE THESE ARGUMENTS
	PUSHJ	P,CMDINI	;INITIALIZE COMMAND TABLE POINTERS
	JUMPE	P2,CMDNSN	;IF NO COMMANDS, WE AREN'T GOING TO FIND IT
CMDRE2:	CAMN	T1,(P2)		;IS THIS THE COMMAND WE ARE LOOKING FOR?
	JRST	[SKIPN U,(P3)	;DOES IT HAVE A BLOCK POINTER?
		JRST .+1	;NOPE, IGNORE IT
		JRST CMDCRT]	;AND LIST THE COMMAND INTO HIS BUFFER
	PUSHJ	P,CMDADV	;NO, ADVANCE TO NEXT COMMAND
	  JRST	CMDRE2		;AND LOOK FOR NEXT COMMAND
	JRST	CMDNSN		;NO SUCH COMMAND NAME
;FUNCTION .CMDMP
;DUMP THE COMMAND DATA BASE. SUITABLE FOR READING/RESTORING AN ENTIRE
;COMMAND DATA BASE ACROSS LOGINS.

CMDDMP:	PUSHJ	P,SAVE4##	;AVOID TRASHING A MONITOR UUO
	PUSHJ	P,GETWRD##	;GET NUMBER OF WORDS WE ARE ALLOWED TO RETURN
	  JRST	CMDADC		;HE GAVE US A TURKEY ADDRESS.
	MOVE	P1,T1		;SAVE NUMBER OF WORDS WE ARE ALLOWED TO RETURN
	HRRZ	T1,M		;FIRST ADDRESS WE ARE GOING TO RETURN STUFF TO.
	HRLI	T1,(IFIW)	;MAKE SECTION RELATIVE
	MOVE	T2,P1		;GET WORD COUNT
	PUSHJ	P,ARNGE##	;RANGE CHECK ARGUMENTS
	  JRST	CMDADC		;ADDRESS CHECK
	  JFCL			;ADDRESS OK BUT ILLEGAL FOR I/O (IGNORED HERE)
	SUBI	M,1		;SINCE WE DO PUTWD1'S LATER
	PUSHJ	P,CMDINI	;INITIALIZE POINTERS
	JUMPE	P2,CMDDM9	;IF NO COMMANDS, TELL HIM THAT.

CMDDM1:	SKIPE	(P2)		;DO WE HAVE A COMMAND DEFINED?
	SKIPN	U,(P3)		;GET POINTER TO THIS COMMAND'S BLOCK
	JRST	CMDDM8		;NO COMMAND, TRY FOR NEXT COMMAND
	PUSHJ	P,CMDCRT	;RETURN THIS COMMAND TO USER'S BUFFER
	  POPJ	P,		;HMM. MUSTA RUN OUTA BUFFER SPACE
CMDDM8:	PUSHJ	P,CMDADV	;ADVANCE POINTERS
	  JRST	CMDDM1		;AND RETURN NEXT COMMAND
CMDDM9:	SETZ	T1,		;A ZERO WORD TERMINATOR
	PUSHJ	P,CMDPUT	;TERMINATE LIST OF COMMANDS
	  POPJ	P,		;WHAT TERRIBLE LUCK!
	RETSKP
;UTILITY ROUTINES, CALLED BY ABOVE FUNCTIONS

;RETURN A COMMAND TO USER'S BUFFER.
;ARGS
;P1/ NUMBER OF WORDS LEFT IN USERS BUFFER
;P2-P4/ AS SET UP BY CMDINI AND CMDADV

CMDCRT:	MOVE	T4,(U)		;GET NUMBER OF WORDS IN OUR BLOCK
	MOVEI	T1,1(T4)	;MAKE IT NUMBER OF WORDS USER UNDERSTANDS
	LDB	T2,P4		;GET UNIQUENESS BITS
	HRL	T1,T2		;MAKE IT THE FLAGS IN LEFT HALF
	PUSHJ	P,CMDPUT	;PUT THIS WORD IN USER'S BUFFER
	  POPJ	P,		;HMM. WE JUST RAN OUT OF ROOM.
	MOVE	T1,(P2)		;GET COMMAND NAME
	PUSHJ	P,CMDPUT	;PUT IT IN THE USER'S BUFFER
	  POPJ	P,		;RAN OUT OF ROOM.
	SUBI	T4,1		;DECREMENT NUMBER OF WORDS LEFT TO GO
CMDCR3:	ADDI	U,1		;POINT TO NEXT WORD IN COMMAND BLOCK
	MOVE	T1,(U)		;GET WORD FROM COMMAND BLOCK
	PUSHJ	P,CMDPUT	;AND PUT IT IN USER'S BLOCK
	  POPJ	P,
	SOJG	T4,CMDCR3	;DO UNTIL FINISHED THIS BLOCK
	RETSKP			;RETURN INDICATING THAT IT FIT.


;PUT WORDS INTO USER'S BUFFER, CHECKING TO MAKE SURE THEY FIT.
;PRESERVES THE T ACS, MODIFIES M AND P1
CMDPUT:	PUSHJ	P,SAVT##	;AVOID TRASHING T ACS
	SOJLE	P1,CMDDNF	;MAKE SURE WE CAN FIT THIS IN USER'S BUFFER
	PUSHJ	P,PUTWR1##	;PUT THIS IN NEXT WORD OF USER'S BUFFER
	  JRST	CMDADC		;ADDRESS CHECK
	RETSKP			;RETURN SUCCESS


;REMOVE A COMMAND FROM TABLES.
;CALL WITH (P2)NAME, (P3)DISPATCH, P4/BPT TO UNIQNESS
CMDREM:	SETZB	T2,(P2)		;YUP, WIPE COMMAND NAME
	EXCH	T2,(P3)		;WIPE DISPATCH POINTER
	HRRZ	T1,(T2)		;GET NUMBER OF WORDS IN ENTRY
	PUSHJ	P,GVFWDS##	;RETURN THE FUNNY SPACE
	SETZ	T2,		;CLEAR AGAIN.
	DPB	T2,P4		;AND WIPE UNIQUENESS BITS (JUST FOR GRINS)
	POPJ	P,		;AND RETURN.

;ADVANCE POINTERS TO NEXT COMMAND. MADE INTO ROUTINE TO GUARANTEE EVERYONE
;USES SAME PROCEDURE.
CMDADV:	AOJ	P3,		;INCREMENT POINTER TO DISPATCH
	IBP	P4		;INCREMENT UNIQUENESS POINTER
	AOBJN	P2,CPOPJ	;RETURN NON SKIP IF STILL THINGS TO LOOK AT
	RETSKP			;NOTHING MORE TO LOOK AT. SKIP RETURN.

;INITIALIZE POINTERS FOR ABOVE. SETS UP P2,P3,P4
;CHECK FOR P2=0 TO INDICATE NO COMMAND DATA BASE
CMDINI:	MOVE	P2,.PDCMN##(W)	;GET POINTER TO COMMAND NAMES
	HRRZ	P3,.PDUNQ##(W)	;GET POINTER TO COMMAND DISPATCHES
	HRLI	P4,(POINT CM.BSZ,,CM.BSZ-1) ;BYTE POINTER FOR UNIQUENESS BITS
	HLR	P4,.PDUNQ##(W)	;GET POINTER TO OUR TABLE OF UNIQUENESS
	POPJ	P,

;EXPAND COMMAND DIRECTORY. NEW NUMBER OF COMMANDS IN P1.
CMDXPN:	PUSHJ	P,SAVE2##	;AVOID TRASHING OUR TOP LEVEL
	MOVE	P2,.PDCMN##(W)	;SAVE A POINTER TO CURRENT COMMAND LIST
	PUSHJ	P,CMDCOR	;AND ALLOCATE MORE CORE.
	  POPJ	P,		;PROPAGATE THIS ERROR.
	HLRO	T3,P2		;MINUS NUMBER OF COMMAND SLOTS WE USED TO HAVE
	MOVNS	T3		;NUMBER OF COMMAND SLOTS
	HRL	T1,P2		;POINTER TO OLD COMMAND DIRECTORY
	HRR	T1,.PDCMN##(W)	;POINTER TO NEW COMMAND DIRECTORY
	MOVE	T2,T3		;COPY NUMBER OF COMMANDS TO COPY
	ADDI	T2,(T1)		;POINTER TO FIRST WORD BEYOND THESE COMMANDS.
	BLT	T1,-1(T2)	;COPY OLD COMMANDS TO NEW TABLE.
	HRR	T1,.PDUNQ##(W)	;POINTER TO NEW DISPATCHES TABLE
	HRRZ	T2,T1		;DESTINATION FOR BLT
	ADD	T2,T3		;POINT TO FIRST WORD BEYOND DISPATCHES.
	BLT	T1,-1(T2)	;COPY NEW DISPATCHES.
	IDIVI	T3,CM.BPW	;NUMBER OF WORDS IN UNQTAB
	HLR	T1,.PDUNQ##(W)	;NEW POINTER TO UNQTAB
	HRRZ	T2,T1		;DESTINATION FOR BLT
	ADD	T2,T3		;POINT TO FIRST WORD BEYOND UNQTAB
	BLT	T1,-1(T2)	;AND COPY THE UNQTAB DATA
	IMULI	T3,CM.BPE	;NUMBER OF WORDS FOR USED FOR ENTIRE TABLE
	MOVE	T1,T3		;COPY NUMBER OF WORDS TO RETURN
	HRRZ	T2,P2		;WHERE OUR TABLE IS
	PUSHJ	P,GVFWDS##	;AND RETURN FUNNY FOR OLD COMMAND DIRECTORY
	RETSKP			;RETURN SUCCESS

;ALLOCATE CORE FOR COMMANDS DIRECTORY. RETURNS WITH .PDCMN AND .PDUNQ SET UP
;AND ALL COMMAND NAMES SET TO ZERO.

CMDCOR:	PUSHJ	P,SAVE2##	;PRESERVE P ACS
	MOVEI	T2,CM.BP1(P1)	;NUMBER OF COMMANDS TO DEFINE (ROUNDING UP)
	IDIVI	T2,CM.BPW	;NUMBER OF WORDS IN UNQTAB
	MOVE	P2,T2
	IMULI	T2,CM.BPW	;NUMBER OF WORDS FOR OUR TABLES (MULTIPLE OF 6)
	MOVE	P1,T2
	ASH	T2,1		;NUMBER OF WORDS FOR NAMES+DISPATCH
	ADD	T2,P2		;ADD IN NUMBER OF WORDS FOR UNQTAB
	PUSHJ	P,GTFWDC##	;GET CACHED FUNNY SPACE.
	  JRST	CMDNER		;NOT ENOUGH ROOM.
	MOVE	T2,T1		;POINTER TO COMMAND NAMES
	ADD	T2,P1		;POINTER TO COMMAND DISPATCHES
	MOVEI	T3,1(T1)	;MAKE A BLT POINTER TOWARDS NAMES
	HRL	T3,T1		;LEFT HALF OF BLT POINTER
	SETZM	(T1)		;CLEAR FIRST WORD OF COMMAND NAMES
	BLT	T3,-1(T2)	;AND ALL THE REST OF THE WORDS TOO.
	MOVN	T3,P1		;NEGATIVE NUMBER OF COMMANDS ALLOWED IN LIST
	HRL	T1,T3		;MAKE AN AOBJN POINTER TO COMMANDS
	MOVE	T3,T2		;POINTER TO COMMAND DISPATCHES
	ADD	T3,P1		;POINTER TO COMMAND UNQTAB
	HRL	T2,T3
	MOVEM	T2,.PDUNQ##(W)	;SAVE POINTERS (NOTE ORDER: .PDCMN CAN'T BE
	MOVEM	T1,.PDCMN##(W)	;	SAVED UNTIL .PDUNQ IS SET UP)
	RETSKP

;INSERT COMMANDS SUPPLIED BY UUO TO OUR LIST OF USER DEFINED COMMANDS. IT IS
;THE RESPONSOBILITY OF THE CALLER TO INSURE THAT THERE ARE ENOUGH AVAILABLE
;COMMAND SLOTS IN THE COMMAND DIRECTORY (.PDCMN).
CMDINS:	PUSHJ	P,SAVE4##	;AVOID TRASHING ACS.
	PUSHJ	P,CMDINI	;INITIALIZE POINTERS
CMDIN2:	UMOVE	U,(M)		;GET LENGTH OF COMMAND ENTRY
	JUMPE	U,CPOPJ1	;AT END, EXIT.
	UMOVE	P1,1(M)		;GET COMMAND NAME
	JUMPE	P1,CMDIN6	;IF NO COMMAND NAME, PITCH IT.
CMDI25:	CAMN	P1,(P2)		;IS THIS THE SAME COMMAND AS OURS?
	JRST	CMDIN4		;YES, USE IT.
	PUSHJ	P,CMDADV	;ADVANCE POINTERS
	  JRST	CMDI25		;AND TRY FOR ANOTHER COMMAND
	PUSHJ	P,CMDINI	;INITIALIZE POINTERS AGAIN
CMDIN3:	SKIPN	(P2)		;IS THIS COMMAND NAME TAKEN?
	JRST	CMDIN5		;NO, CONTINUE
	PUSHJ	P,CMDADV	;ADVANCE POINTERS
	  JRST	CMDIN3		;AND TRY FOR ANOTHER SLOT
	STOPCD	RMVCMD,DEBUG,NCE ;++NO COMMAND SLOT AVAILABLE.

CMDIN4:	PUSHJ	P,CMDREM	;REMOVE THIS COMMAND
CMDIN5:	HLRZ	T1,U		;GET UNIQNESS BITS
	DPB	T1,P4		;STORE FOR THIS COMMAND
	HRRZS	U		;CLEAR FLAGS
	CAIGE	U,3		;MUST CONTAIN AT LEAST UP TO .CMFIL
	JRST	CMDIAL		;ILLEGAL ARGUMENT LIST.
	SOS	T2,U		;OUR TABLE IS ONE WORD SHORTER THAN USER'S
	PUSHJ	P,GTFWDC##	;GET SOME CACHED FREESPACE
	  JRST	CMDNER		;NO MORE ROOM
	MOVEM	T1,(P3)		;SAVE POINTER TO THIS BLOCK
	HRRZM	U,(T1)		;SAVE LENGTH IN BLOCK
	MOVEI	T2,1(T1)	;DESTINATION OF THIS BLOCK
	HRLI	T2,2(M)		;SOURCE FROM USER
	ADDI	T1,-1(U)	;POINT TO LAST WORD IN OUR BLOCK
	EXCTUX	<BLT T2,(T1)>	;AND COPY OUR DATA
	MOVEM	P1,(P2)		;AND NOW SAVE THE COMMAND NAME
CMDIN6:	ADDI	M,1(U)		;POINT PAST THIS COMMAND
	JRST	CMDIN2		;AND ADD THE NEXT COMMAND


;COUNT COMMANDS SUPPLIED IN UUO. RETURNS NUMBER OF COMMANDS TO DEFINE IN P1

CMDCNT:	SETZ	P1,		;START WITH 0 COMMANDS COUNTED.
	PUSHJ	P,SAVUM##	;SAVE M (U AND W GO ALONG FOR THE RIDE)
CMDCN1:	PUSHJ	P,GETWRD##	;GET FIRST WORD OF ARGUMENT (LENGTH)
	  JRST	CMDADC		;ADDRESS CHECK.
	JUMPE	T1,CPOPJ1##	;END OF LIST, GET CORE TO STORE THESE IN.
	HRRZS	T1		;CLEAR FLAGS AWAY THIS TIME.
	CAIL	T1,4		;MUST CONTAIN UP TO THE FILENAME
	CAILE	T1,MAXLVL##+6	;SFDS+PPN+EXT+NAME+DEV+COMMAND+FLAGS
	JRST	CMDIAL		;ILLEGAL ADDRESS LIST
	MOVE	T2,T1		;SAVE LENGTH
	ADDI	M,2		;POINT TO NAME OF COMMAND
	PUSHJ	P,GETWRD##	;GET COMMAND NAME
	  JRST	CMDADC		;ADDR CHECK
	JUMPE	T1,CMDIAL	;MUST HAVE A NAME
	ADDI	M,-2(T2)	;POINT TO NEXT COMAND BLOCK
	AOJA	P1,CMDCN1	;AND FIND ANOTHER COMMAND

;REMOVE ALL COMMANDS.
RMVCMD:
	PUSHJ	P,SAVE4##	;WE USE P1 AND P2
	PUSHJ	P,CMDINI	;INITIALIZE POINTERS
	JUMPE	P2,CPOPJ##	;IF NO POINTER TO NAMES, SUCCESS
RMVCM1:	SKIPE	(P2)		;ZERO OUT THE COMMAND NAME FIRST
	SKIPN	T2,(P3)		;AND GET POINTER TO THE FILESPEC BLOCK
	JRST	RMVCM2		;NO NAME OR POINTER, IGNORE THIS COMMAND
	PUSHJ	P,CMDREM	;REMOVE THIS COMMAND
RMVCM2:	PUSHJ	P,CMDADV	;ADVANCE POINTERS
	 JRST	RMVCM1		;AND DO ANOTHER COMMAND

	HLRO	T1,.PDCMN##(W)	;GET NUMBER OF ENTRIES
	IMUL	T1,[-CM.BPE]	;CONVERT TO POSITIVE NUMBER OF 6 BIT BYTES
	ADDI	T1,CM.BP1	;ROUND UP TO NEAREST WORD
	IDIVI	T1,CM.BPW	;AND CONVERT BACK DOWN TO NUMBER OF WORDS
	HRRZ	T2,.PDCMN##(W)	;GET POINTER TO TABLE
	PUSHJ	P,GVFWDS##	;AND RETURN THE TABLES THEMSELVES.
	SETZM	.PDCMN##(W)	;WIPE POINTER TO COMMAND NAMES
	SETZM	.PDUNQ##(W)	;AND POINTER TO UNQTAB AND DISPATCHES
	POPJ	P,
	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:
	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:	SETZ	T1,		;RETURN ZERO
	JRST	STOTAC##	;GO STORE VALUE
	SUBTTL	ENTVC. UUO

;THE ENTVC. UUO SETS OR RETURNS THE PROGRAMS CURRENT ENTRY VECTOR
;CALLING SEQUENCE:
;	XMOVEI	AC,ADDR
;	ENTVC.	AC,
;	<ERROR RETURN>
;	<NORMAL RETURN>
;	...
;ADDR/	FUNCTION		;READ OR SET (SIGN BIT ON MEANS SET)
;ADDR+1/LENGTH			;(JRST) OR 0-N (WHERE N IS .LE.37)
;ADDR+2/EXEC-ADDR		;30 BIT ADDRESS OF ENTRY VECTOR OR START ADDRESS
;				; IF LENGTH = 0 OR (JRST)
;

ENTVC:	PUSHJ	P,SAVE4##	;SAVE SOME ACS
	MOVEI	T2,3		;WANT THREE WORDS OF ARG LIST
	PUSHJ	P,ARNGE##	;SEE IF THE LIST IS WELL-FORMED
	  JRST	ENVADC		;NO
	  JFCL			;IGNORE I/O ILLEGAL HERE
	PUSHJ	P,SXPCS##	;MAKE SURE THE REFERENCES WILL WORK
	  JRST	ENVADC		;ADDRESS CHECK
	SKIPL	T1		;IF GLOBAL,
	SOSA	T1		;PRE-DECREMENT GLOBALLY
	HRRI	T1,-1(T1)	;ELSE LOCALLY
	MOVE	M,T1		;POINT AT ARGUMENT LIST (PREDECREMENTED)
	MOVSI	P4,-3		;FETCH 3 ARGS INTO P1-P3
ENTVC1:	PUSHJ	P,GETEW1##	;GET NEXT ARG
	  JRST	ENVADC		;ADDRESS CHECK
	MOVEM	T1,P1(P4)	;STORE ARGUMENT IN AN AC
	AOBJN	P4,ENTVC1	;FETCH ALL 3 ARGUMENTS
	SKIPN	P2		;LENGTH = 0?
	MOVEI	P2,(JRST)	;YES, SUBSTITUTE (JRST)
	HRRZ	T1,P1		;FUNCTION CODE
	JUMPN	T1,ENVIFC	;ONLY FUNCTION 0 IS DEFINED FOR NOW
	TLNE	P1,377777	;ANY UNKNOWN BITS?
	JRST	ENVIAL		;ILLEGAL ARG LIST
	JUMPL	P1,ENTVC4	;GO IF SET FUNCTION
;HERE TO READ THE ENTRY VECTOR
	SKIPE	P3,.USUSA	;ENTRY VECTOR SETUP?
	JRST	ENTVC2		;YES
	MOVEI	P2,(JRST)	;NO, JUST RETURN STARTING ADDRESS
	SKIPE	P3,.USUSN	;INCLUDING SECTION IF APPLICABLE
	LSH	P3,P2WLSH	; ..
	HRR	P3,.JDAT+.JBSA##; ..
	TRNN	P3,-1		;EXCEPT IF NO START ADDRESS,
	SETZB	P2,P3		;THEN THERE'S NOTHING AT ALL
	JRST	ENTVC3		;STORE THE ANSWERS AND RETURN
ENTVC2:	LDB	P2,[POINT 5,P3,5] ;LENGTH
	TLZ	P3,(77B5)	;VIRTUAL ADDRESS OF THE ENTRY VECTOR
	JUMPN	P2,ENTVC3	;RETURN ANSWER IF HAVE A REAL LENGTH
	MOVEI	P2,(JRST)	;NO, ADMIT TO START ADDRESS FORMAT
	CAIN	P3,1		;IF SPECIAL FOR S0,
	SETZ	P3,		;WE HAVE NO ADDRESS
	TRNE	P3,-1		;IF HAVE AN ADDRESS TO USE,
	JRST	ENTVC3		;THEN USE IT
	PUSH	P,M		;NO, SAVE USER ADDRESS
	HLLZ	M,P3		;GET SECTION FOR REFERENCE
	HRRI	M,.JBSA##	;USE ITS JOBDAT
	PUSHJ	P,PFHMWD##	;FETCH START ADDRESS
	  SETZ	T1,		;GOT NOTHING
	TLZ	T1,-1		;IGNORE JOBFF
	SKIPN	P3,T1		;UPDATE IF HAVE A VALUE
	TDZA	P2,P2		;NO, ZERO THE LENGTH AFTER ALL
	HLL	P3,M		;YES, RETRIEVE SECTION NUMBER
	POP	P,M		;RESTORE USER ADDRESS
ENTVC3:	SUBI	M,1		;BACK UP FOR STORING ANSWERS
	MOVE	T1,P2		;LENGTH TO T1
	PUSHJ	P,PUTEWD##	;STORE THAT
	  JRST	ENVADC		;ADDRESS CHECK
	MOVE	T1,P3		;ADDRESS TO T1
	PUSHJ	P,PUTEW1##	;STORE THAT
	  JRST	ENVADC		;ADDRESS CHECK
	JRST	CPOPJ1##	;AND GIVE SKIP RETURN TO THE USER
;HERE TO SET THE ENTRY VECTOR
ENTVC4:	SKIPN	P2		;IF CLEARING LENGTH
	SETZ	P3,		;ALSO CLEAR ADDRESS
	JUMPE	P2,ENTVC5	;JUST STORE IT IF CLEARING
	CAIN	P2,(JRST)	;JUST SETTING THE START ADDRESS?
	JRST	ENTVC5		;YES, JUST STORE THE ADDRESS AND RETURN
	SKIPL	P2		;MUST HAVE POSITIVE LENGTH
	CAILE	P2,37		;LENGTH LESS THAN 32 WORDS?
	JRST	ENVIAL		;DON'T HAVE ROOM FOR ANY MORE SO SAY ILL ARG
	TRO	P2,40		;TO MAKE IT EASY TO TEST FOR "REAL" ENTRY VECTOR
	DPB	P2,[POINT 6,P3,5] ;FOR .USUSA
	CAIGE	P2,42		;EXCLUDING A REENTER ADDRESS?
	SETZM	.JDAT+.JBREN##	;YES, DON'T CONFUSE HUMANS
	SETZM	.JDAT+.JBVER##	;ALWAYS CLEAR THIS IN CASE OMITTED FROM VECTOR
	CAIGE	P2,43		;SPECIFYING A VERSION NUMBER?
	JRST	ENTVC5		;NO, JUST STORE NUMBERS AND RETURN
	MOVE	M,P3		;ARG LIST POINTER
	ADDI	M,2		;WHERE THE VERSION NUMBER IS
	TLZ	M,770000	;ISOLATE THE ADDRESS
	PUSHJ	P,GETXWD##	;GET THE VERSION NUMBER
	  JRST	ENTVC5		;IGNORE ADDRESS CHECK
	MOVEM	T1,.JDAT+.JBVER## ;STORE IT WHERE HUMANS LOOK
ENTVC5:	SKIPE	P2		;IF REAL LENGTH,
	SKIPE	P3		;FOR S0 JOBDAT,
	CAIA			;NO
	MOVEI	P3,1		;YES, FIX IT
	MOVEM	P3,.USUSA	;STORE ADDRESS OF ENTRY VECTOR
	JRST	CPOPJ1##	;AND TELL HIM HE DID GOOD

;ERROR CODES
EVIAL%==1			;ILLEGAL ARGUMENT LIST
EVIFC%==2			;ILLEGAL FUNCTION CODE
EVADC%==3			;ADDRESS CHECK

	ERCODX	ENVIAL,EVIAL%
	ERCODX	ENVIFC,EVIFC%
	ERCODX	ENVADC,EVADC%
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.

UDVPHY:	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,DVPKON	;MAYBE KONTROLLER HACK
	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
DVPHY7:	PUSHJ	P,NXDDB		;POINT AT NEXT DEVICE ON CHAIN
	  JUMPE	F,DVPHY4
	LDB	T1,PDVTYP##
	CAIE	T1,.TYDSK
	CAME	T1,P1
DVPHY4:	TDZA	T1,T1
DVPHY5:	MOVE	T1,DEVNAM(F)
	JUMPE	T1,DVPHY6	;IF NO DEVICE, JUST STORE
	CAIE	P1,.TYTTY	;IS IT A TTY?
	 JRST	DVPHY6		;NO, JUST STORE
	MOVE	T2,DDBLDB##(F)	;YES, GET ASSOCIATED LDB
	JUMPE	T2,DVPHY7	;SKIP THIS ONE IF NOT ATTACHED
DVPHY6:	AOS	(P)
	PJRST	PUTWDU##
;HERE TO RETURN KONTROLLER NAMES
DVPKON:	HRRZ	T4,M		;SAVE START OF INTERESTING ARGUMENTS
	HLRE	T2,T1		;GET LH OF AOBJN WORD
	CAML	T2,[-100]	;RANGE
	CAIL	T2,0		; CHECK
	JRST	DPENDT		;ILLEGAL DEVICE SEARCH REQUESTED
	HRRZ	T2,T1		;GET RH OF AOBJN WORD
	CAILE	T2,77		;WITHIN RANGE OF DEFINABLE DEVICES?
	JRST	DPENDT		;ILLEGAL DEVICE SEARCH REQUESTED
	CAILE	T2,TYPMAX	;WITHIN RANGE OF KNOWN DEVICES?
	JRST	[SETZB	T1,T2	;NO, SET TO RETURN ZEROS
		 JRST	DVPKO4]	;AND DO SO
	SUBI	T2,<TYPMAX+1>	;FIND LEAST LEGAL LH
	HLRE	T3,T1		;GET USER'S LH
	CAMGE	T3,T2		;IS USER'S ARG IN RANGE?
	HRL	T1,T2		;NO, KEEP IT WITHIN THE TABLE
	MOVE	T2,T1		;COPY TO A SAFE PLACE
	PUSHJ	P,GETWD1##	;GET STARTING KONTROLLER NAME
	EXCH	T1,T2		;SHUFFLE ARGS A BIT
	PUSHJ	P,FNDKON	;FIND SPECIFIED KONTROLLER
	  JUMPN	T2,DPENDT	;ILLEGAL DEVICE
	JUMPE	T2,DVPKO2	;RETURN FIRST NAME IF DESIRED

;NOW SCAN FOR THE NEXT KDB
DVPKO1:	SKIPE	T3,KDBNXT(T3)	;LINK TO NEXT
	JRST	DVPKO3		;AND RETURN THIS NAME
	SKIPA			;FIRST TIME HERE
	SKIPN	T3,KDBTAB##(T1)	;GET FIRST KDB OF THIS TYPE
	AOBJN	T1,.-1		;ADVANCE TO NEXT DEVICE TYPE
DVPKO2:	SKIPGE	T1		;SKIP IF POINTER RAN OUT
DVPKO3:	SKIPA	T2,KDBNAM(T3)	;RETURN THIS NAME
	SETZ	T2,		;ZERO MEANS NO MORE KONTROLLERS
DVPKO4:	TLO	T4,-1		;INDICATE SUCCESS
	HRRZ	M,T4		;GET USER ARG BLOCK ADDR BACK
	PUSHJ	P,PUTWDU##	;UPDATE AOBJN POINTER
	MOVE	T1,T2		;GET KONTROLLER NAME
	PUSHJ	P,PUTWD1##	;UPDATE IT TOO
	SKIPG	T4		;FAILURE?
	AOS	(P)		;NO--SKIP
	POPJ	P,		;RETURN
FNDKON:	SKIPN	T3,KDBTAB##(T1)	;GET INITIAL KDB OF THIS TYPE
	JRST	FNDKO2		;NONE THERE
	JUMPE	T2,CPOPJ1##	;RETURN IF LOOKING FOR FIRST KONTROLLER

FNDKO1:	CAMN	T2,KDBNAM(T3)	;MATCH?
	JRST	CPOPJ1##	;YES
	SKIPE	T3,KDBNXT(T3)	;LINK TO NEXT
	JRST	FNDKO1		;KEEP SEARCHING

FNDKO2:	AOBJN	T1,FNDKON	;TRY NEXT DEVICE TYPE
	POPJ	P,		;GIVE UP
;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:	SKIPN	F,DDBTAB##(T1)	;SEE IF AUTCON KNOWS ABOUT THIS TYPE
	HLRZ	F,DEVLST##	;ELSE MUST SCAN THE WHOLE CHAIN
	JUMPE	F,CPOPJ##	;PUNT IF EMPTY (SUB-)LIST

DVSDV1:	SKIPE	T2,DEVNAM(F)	;SEE IF IT'S A PROTOTYPE
	TLNN	T2,-1		;OR HAS NO USEFUL NAME
	JRST	DVSDV2		;YES, SKIP THIS ONE
	LDB	T2,PDVTYP##	;GET DEVICE TYPE
	CAIN	T2,(T1)		;MATCH?
	JRST	CPOPJ1##	;YES
DVSDV2:	PUSHJ	P,NXDDB		;ADVANCE TO NEXT DDB
	  JUMPE	F,CPOPJ##	;THERE ARE NO MORE
	JRST	DVSDV1		;LOOP BACK AND TRY AGAIN


;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
	XWD	ZERO5,.TYTTY
	XWD	ZERO5,.TYDSK
	XWD	ZERO5,.TYMPX
	XWD	ZERO5,.TYTSK
	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

UDVCHR:	PUSHJ	P,DVCHR		;CALL INTERNAL ROUTINE TO DO THE WORK
	PJRST	STOTAC##	;AND RETURN THE ANSWER TO THE USER

DVCH1:	TLOE	P1,PHONLY	;ALREADY HAVE REAL DEVICE ?
	JRST	DVCH2		;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	DVCH2		;SKIP OVER SAVE AND CLEARING P2
DVCHR:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	SETZ	P2,		;FIRST CALL - ZERO P2
DVCH2:	PUSHJ	P,DVCNSG	;SEARCH FOR DEVICE
	  JRST	ZPOPJ##		;NOT A DEVICE, GIVE ERROR
	SETZ	T3,
	TLNN	P1,PHONLY	;DON'T CHECK FOR LNM IF PHYSICAL ONLY
	PUSHJ	P,LNMNUL##	;LOGICAL NAME MAPPED TO NUL?
	  CAMN	T1,[SIXBIT /NUL/] ;OR EXPLICIT NUL REFERENCE?
	MOVEI	T3,-1-TTYATC	;YES, LH WILL BE CHANGED
	SKIPE	DEVCHR(F)	;IF NOT A FAKE DDB,
	SKIPL	DEVSPL(F)	;IF A SPOOLED DEVICE,
DVCH3:	SKIPA	T1,DEVMOD(F)
	JRST	DVCH1		; GO GET DEVMOD FOR REAL DEVICE
	PUSHJ	P,CHKSPL	;DEVICE SPOOLED?
	  TRZA	T1,ASSCON!ASSPRG  ;YES, IGNORE WHAT REAL DEV IS DOING
	JRST	DVCH4		;NO
	IOR	T1,P2		; AND SET ASSCON, ASSPRG FROM SPOOLED DDB
	TLO	T1,DVAVAL	;YES, SET AVAILABLE-BIT
DVCH4:	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 FTNET,<
	TLNN	T1,DVTTY	;IS THIS A TTY?
	JRST	DVCH5		;NO, SKIP VTM TEST
	MOVE	T2,DDBLDB(F)	;YES, GET LDB
	JUMPE	T2,DVCH5	;OK IF NONE
	SE1XCT	<SKIPGE LDBREM##(T2)> ;VTM + SET HOST?
	TLZ	T1,DVAVAL	;YES, IT'S NOT AVAILABLE AFTER ALL
DVCH5:>
	TLO	T1,(T3)		;SET LH = -1 IF NUL:
	POPJ	P,		;RETURN
;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

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
;RETURN DEVICE TYPE (AND OTHER PROPERTIES)
UDVTYP:	AOS	(P)		;SKIP-RETURN SINCE UUO IS IMPLIEMENTED
	PUSHJ	P,DVTYP
	PJRST	STOTAC##	;AND STORE THE ANSWER

DVTYP:	PUSH	P,T1		;SAVE DEVICE NAME
	PUSHJ	P,DVCHR		;GET DEVICE CHARACTERISTICS
	JUMPE	T1,T2POPJ##	;NO SUCH DEV - RETURN 0
DVTY1:
	PUSHJ	P,CHKSPL	;SEE IF DEVICE IS SPOOLED
	  TLOA	T2,.TYSPL!DVAVAL	;YES, SPOOL+AVAILABLE

	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
	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
	SKIPN	T2		;IF A DISK,
	JUMPL	T3,DVTY2	; IF "DVDIRIN" IS ON ITS NUL:
	CAIE	T2,.TYRDA	;IS IT A RDA
	CAIN	T2,.TYTSK	;IS IT A TASK
	TLOA	T1,.TYINT	;YES, SET INTERACTIVE MODE
	CAIG	T2,.TYDTA	;DSK OR DTA?
	TLO	T1,.TYMAN	;YES - LOOKUP/ENTER MANDATORY
DVTY2:	LDB	T2,PJOBN##	;OWNER OF DEVICE
	SKIPE	DEVCHR(F)	;NO OWNER IF SPOOLED

	DPB	T2,[POINT 9,T1,26]	;IN BITS 18-26
IFN FTMPXSER,<
	TLO	T1,TY.MPX	;ASSUME OK
	PUSHJ	P,LGLMPX##	;IS IT OK?
	  TLZ	T1,TY.MPX	;NO--CLEAR BIT
>
	MOVSI	T2,DVLPTL	;IS THIS A LOWER CASE LPT?
	TDNE	T2,DEVCHR(F)
	TLO	T1,TY.LL	;YES
	MOVSI	T2,DVCMDA	;IS THIS AN
	TDNE	T2,DEVCHR(F)	;MDA DEVICE?
	TLO	T1,TY.MDA	;YES
	POPJ	P,
SUBTTL	CAL11. UUO


;UUO TO COMMUNICATE WITH PDP11S

CALL11:	PUSH	P,T1		;SAVE USER'S ARG
	HRLOI	P2,377777	;ASSUME PRIV. JOB.
	PUSHJ	P,PRUSET	;SKIP IF PRIV.
	  TLO	P2,400000	;NOT PRIV.
	POP	P,T1		;RESTORE USER'S ARG
	HRR	M,T1		;GET USER'S AC
	HLRE	T3,T1		;GET COUNT
	JUMPLE	T3,ECOD7##	;.LE. ZERO ARGS NOT ENOUGH!
	PUSHJ	P,GETWDU##	;GET FUNCTION CODE INTO T1
	SOJL	T3,ECOD7##	;ERROR CODE 7: NOT ENOUGH ARGS
	MOVE	P3,T3		;SAVE LENGTH
	MOVE	P1,T1		;COPY FUNCTION WORD TO A SAFER PLACE
	SKIPL	P1		;OLD STYLE FUNCTION WORD?
	PUSHJ	P,C11OLD	;YES--HACK IT UP A BIT
	PUSHJ	P,C11ARG	;DECODE THE TYPE, CPU, AND PORT NUMBER
	  POPJ	P,		;RETURN ON ERRORS
	MOVE	T3,P3		;RESTORE LENGTH
	SKIPN	T2,DLXCAL##(W)	;GET CAL11. TABLE POINTER
	MOVE	T2,[XWD CAL11L,CAL11D]	;NONE, USE DEFAULT
	HLRZ	T4,T2		;GET LENGTH OF TABLE
	CAML	T1,T4		;FUNCTION TOO LARGE?
	JRST	ECOD2##		;YES, ERROR CODE 2.
	ADD	T2,T1		;NO, POINT TO TABLE ENTRY
	MOVE	T1,0(T2)	;PICK UP ENTRY
	AND	T1,P2		;CLEAR SIGN BIT IF PRIV
	JUMPL	T1,ECOD1##	;IF STILL SET, NEED PRIV.
	PUSHJ	P,0(T1)		;GO DO FUNCTION
	  POPJ	P,		;PROPAGATE ERROR BACK TO USER
	PJRST	CPOPJ1##	;SKIP RETURN


;TABLE FOR CAL11. UUO IF THERE IS NO SERVICE ROUTINE
CAL11D:	XWD	400000,ECOD2##	;(0) DEPOSIT
	XWD	400000,ECOD2##	;(1) EXAMINE
	XWD	400000,ECOD2##	;(2) QUEUE A MESSAGE
	XWD	0,CAL11N	;(3) RETURN NAME
	XWD	0,CAL11S	;(4) UP/DOWN STATUS
	XWD	400000,ECOD2##	;(5) SEND
	XWD	400000,ECOD2##	;(6) RECEIVE
	XWD	0,CAL11T	;(7) TYPE
CAL11L==.-CAL11D		;LENGTH OF TABLE
;CROCK TO FUDGE UP A NEW FORMAT FUNCTION WORD FROM AN OLD STYLE WORD.
;THIS INSURES COMPATIBILITY WITH PRE-702 MONITORS.  EARLY 702 NONSENSE
;USING 400+DTE NUMBERS LOSE.  SO DO KMC/DUPS.  TO ALLOW CAL11. TO STILL
;WORK ON CPUS OTHER THAN CPU ZERO, WE'LL PICK UP THE JOB'S SET CPU COMMAND
;ARGUMENT AND SET THE CPU NUMBER TO THE FIRST CPU AVAILABLE.  NO CHECKING
;IS DONE AT THIS TIME TO MAKE SURE  THE SELECTED CPU HAS THE PORT WE'RE
;INTERESTED IN.  THAT'LL GET CAUGHT LATER.

C11OLD: HLRZ	T1,P1		;GET PORT NUMBER
	CAIGE	T1,10		;DL10 PORT?
	TDZA	T1,T1		;YES
	MOVEI	T1,.C11DT	;MUST BE A DTE
	TLZ	P1,777770	;KEEP ONLY THE PORT NUMBER
	DPB	T1,C11TYP	;SET THE TYPE CODE
	TLO	P1,(C1.1NF)	;SET NEW FORMAT

IFN FTMP,<
	MOVE	T1,JBTSPS##(J)	;SEE IF THE USER
	TRC	T1,7777		; GAVE A SET CPU
	TRCE	T1,7777		;  COMMAND OR UUO
	SKIPA	T1,.CPCPN##	;RUN ON THIS CPU
	MOVEI	T1,0		;LOCK HIM ON CPU0
	DPB	T1,C11CPU	;STORE IT
> ;END IFN FTMP
	POPJ	P,		;RETURN


;HERE TO DECODE THE TYPE, CPU, PORT NUMBER, AND FUNCTION CODE
;CALL:	MOVE	P1,FUNCTION WORD
;	PUSHJ	P,C11ARG
;
;ON RETURN, W=BASE TABLE ADDR, P1=WINDOW ADDR, T1=FUNCTION CODE

C11ARG:	LDB	T1,C11TYP	;GET THE TYPE CODE
	LDB	T2,C11CPU	;GET THE CPU NUMBER
	LDB	T3,C11POR	;GET THE PORT NUMBER
	HRRZ	T4,P1		;GET THE FUNCTION CODE
	CAILE	T2,M.CPU-1	;LEGAL CPU NUMBER?
	JRST	ECOD16##	;NO
	CAIN	T1,.C11DL	;DL10?
	JRST	C11DLX		;YES
	CAIN	T1,.C11DT	;DTE-20?
	JRST	C11DTX		;YES
	CAIN	T1,.C11KD	;KDP?
	JRST	C11KDX		;YES
	CAIN	T1,.C11DR	;DMR?
	JRST	C11DRX		;YES
	JRST	ECOD17##	;ILLEGAL TYPE CODE

C11DLX:
IFN FTKL10,<
	SKIPN	[EXP DL10XI##]	;ANY DL10S?
	JRST	ECOD21##	;NO DL10 SUPPORT
;REMOVE THE FOLLOWING INSTUCTION IF DL10S ARE MADE TO WORK ON CPU1
	MOVEI	T2,0		;GET THE CPU NUMBER
	CAIL	T3,10		;DL10 HAS PORTS 0-7
	JRST	ECOD20##	;ILLEGAL PORT NUMBER
	MOVE	T1,T2		;GET THE CPU NUMBER
	LSH	T1,3		;TIME THE NUMBER OF DL10 PORTS PER CPU (8)
	ADDI	T1,(T3)		;PLUS THE PORT NUMBER
	SKIPE	W,DLXBAT##(T1)	;GET THE BASE TABLE FOR THIS PORT
	SKIPN	P1,DLXWIN##(W)	;GET THE WINDOW ADDRESS
	JRST	ECOD3##		;THERE ISN'T ONE
	JRST	C11CPN		;GO PUT US ON THE RIGHT CPU
> ;END IFN FTKL10
IFN FTKS10,<JRST ECOD21##>	;NO DL10 SUPPORT


C11DTX:
IFN FTKL10,<
	CAIL	T3,4		;DTE HAS PORTS 0-3
	JRST	ECOD20##	;ILLEGAL PORT NUMBER
	MOVE	T1,T2		;THE CPU NUMBER
	LSH	T1,2		;TIMES THE NUMBER OF DTES PER CPU (4)
	ADDI	T1,(T3)		;PLUS THE DTE NUMBER
	SKIPN	W,DTEBAS##(T1)	;HAVE ONE FOR THIS DTE?
	JRST	ECOD3##		;NO
	MOVE	P1,DLXWIN##(W)	;GET CPU#,,DTE#
	JRST	C11CPN		;GO PUT US ON THE RIGHT CPU
> ;END IFN FTKL10
IFN FTKS10,<JRST ECOD22##>	;NO DTE SUPPORT


C11KDX:
IFN FTKL10,<JRST ECOD23##>	;NO KDP SUPPORT
IFN FTKS10,<
	CAIL	T3,M.KDUP##	;VALID LINE NUMBER
	JRST	ECOD3##		;NOPE
	MOVE	W,KDPBAS##(T3)	;GET BASE TABLE ADDRESS
	JRST	C11CPN
> ;END IFN FTKS10

C11DRX:
IFN FTKL10,<JRST ECOD24##>	;NO DMR SUPPORT
IFN FTKS10,<
	CAIL	T3,M.DMRN##	;VALID LINE NUMBER
	JRST	ECOD3##		;NOPE
	MOVE	W,DMRBAS##(T3)	;GET BASE TABLE ADDRESS
> ;END IFN FTKS10

C11CPN:
IFE FTMP,<JUMPN T2,ECOD16##>	;WEED OUT JUNK CPU NUMBERS
IFN FTMP,<
	MOVE	T1,T2		;GET THE CPU NUMBER
	PUSHJ	P,ONCPUS##	;SWITCH TO THAT CPU
	  JRST	ECOD16##	;CPU NOT RUNNING
> ;END IFN FTMP
	HRRZ	T1,T4		;GET THE FUNCTION CODE
	JRST	CPOPJ1##	;AND RETURN


;BYTE POINTERS TO FIELDS IN THE FUNCTION WORD
C11TYP:	POINT	3,P1,11		;TYPE CODE
C11CPU:	POINT	3,P1,14		;CPU NUMBER
C11POR:	POINT	3,P1,17		;PORT NUMBER
CAL11N::MOVE	T1,DLXNMT##(W)	;GET NAME
	JRST	STOTC1##	;AND RETURN

CAL11T::SKIPE	T1,DLXFEK##(W)	;GET ADDRESS OF FEK
	HRLZ	T1,FEKNNM(T1)	;GET NODE NUMBER (IF ANY)
	HRR	T1,DLXTYP##(W)	;GET TYPE OF FRONT END
	JRST	STOTC1##	;RETURN

CAL11S::SKIPE	T1,DLXFEK##(W)	;GET ADDR OF FEK FOR THIS PORT
	SKIPL	T1,FEKBLK(T1)	;SKIP IF PORT UP
	TDZA	T1,T1		;DOWN
	MOVEI	T1,1		;UP
	JRST	STOTC1##	;SKIP RETURN
	SUBTTL	NETOP. UUO

;CALL:	XMOVEI	AC,ARGLIS
;	NETOP.	AC,
;	  ERROR CODE IN AC
;	SUCCESS, AC UNCHANGED
;
;
NETOP:	PUSHJ	P,SXPCS##	;VALIDATE THE ARG BLOCK POINTER
	  JRST	NOPADC		;ADDRESS ERROR
	MOVE	M,T1		;COPY FOR FETCHING
	PUSHJ	P,GETEWD##	;GET LENGTH,,FCN
	  JRST	NOPADC		;ADDRESS ERROR
	MOVE	T4,T1		;SAVE IT
	HLRZ	T2,T1		;GET LENGTH OF ARG BLOCK
	HRRZS	T1		;ISOLATE FUNCTION CODE
	SKIPE	T1		;FUNCTION 0 IS ILLEGAL
	CAILE	T1,NETFMX	;LEGAL FUNCTION CODE?
	  JRST	NOPILF		;NOPE
	CAMGE	T2,NETFNL(T1)	;ARG LIST LONG ENOUGH?
	  JRST	NOPLTS		;NOPE
	MOVE	T1,M		;GET ADDRESS OF ARG LIST
	PUSHJ	P,ARNGE##	;ADDRESS CHECK THE ARG BLOCK ITSELF
	  JRST	NOPADC		;NOT ALL ADDRESSABLE
	  JRST	NOPADC		;CAN'T STORE RESULTS
	HRRZ	T1,T4		;GET FCN CODE AGAIN
	PJRST	@NETFND(T1)	;AND GO FOR IT

	DEFINE	NETFNS,<
NETFUN	(0,NOPILF)	;; 0 - ILLEGAL FUNCTION
NETFUN	(7,NET.DI)	;; 1 - DEVICE INFO
>

	DEFINE	NETFUN(LENGTH,DISPATCH),<EXP	LENGTH>
NETFNL:	NETFNS			;TABLE OF ARG LIST LENGTHS
NETFMX==.-NETFNL-1		;MAXIMUM NET. FUNCTION CODE

	DEFINE	NETFUN(LENGTH,DISPATCH),<IFIW	DISPATCH>
NETFND:	NETFNS			;TABEL OF DISPATCH ADDRESSES

	NOADC%==1	;ADDRESS CHECK
	NOILF%==2	;ILLEGAL FUNCTION
	NOLTS%==3	;ARG LIST TOO SHORT
	NONSD%==4	;NO SUCH DEVICE
	NODNC%==5	;DEVICE NOT CONNECTED
	NONTY%==6	;DEVICE IS NOT A TTY

	ERCODX	NOPADC,NOADC%
	ERCODX	NOPILF,NOILF%
	ERCODX	NOPLTS,NOLTS%
	ERCODX	NOPNSD,NONSD%
	ERCODX	NOPDNC,NODNC%
	ERCODX	NOPNTY,NONTY%

	INTERN	NOPADC,NOPDNC		;ERRORS NEEDED BY NRTSER & LATSER
;FUNCTION CODE 1 - .NOGDI - Device info
; User must fill in words 0 and 2 of arg block
;
;ARGLIS+0/	LENGTH,,FUNCTION
;	+1/	Flags indicating how device is connected
;	+2/	SIXBIT DEVICE NAME, UDX, OR OPEN CHANNEL NUMBER
;	+3/	Output, same results as DEVCHR UUO
;	+4/	Output, same results as DEVTYP UUO
;	+5/	ADDRESS OF STRING BLOCK FOR OUTPUT NODE NAME STRING
;	+6/	ADDRESS OF STRING BLOCK FOR OUTPUT PORT NAME STRING
;
NET.DI:	PUSHJ	P,SAVE2##	;GET A COUPLE OF ACS TO USE
	UMOVE	T1,2(M)		;GET DEVICE/UDX/CHANNEL
	MOVE	P1,T1		;SAVE IT
	S0PSHJ	DVCHR		;FIND DDB AND GET DEVCHR UUO STUFF
	  JUMPE	T1,NOPNSD	;NO SUCH DEVICE
	UMOVEM	T1,3(M)		;STORE DEVCHR UUO INFO
	S0PSHJ	[PUSH	P,P1	;;PUSH DEVICE NAME AND
		   PJRST DVTY1]	;CALL DEVTYP ROUTINE
	UMOVEM	T1,4(M)		;SAVE DEVTYP INFO FOR USER
	ANDI	T1,77		;CLEAR ALL BUT DEVICE TYPE
	CAIE	T1,.TYTTY	;IS IT A TTY?
	  JRST	NOPNTY		;NOPE, PUNT.
	SKIPN	U,DDBLDB##(F)	;GET LDB ADDRESS FOR TTY
	  JRST	NOPDNC		;NOT CONNECTED
	HLLZ	T1,LDBTTW##(U)	;GET WORD WITH NET TYPE BITS
	TLNN	T1,LTLUSE##	;IS IT IN USE?
	  JRST	NOPDNC		;NOT CONNECTED
	TLZ	T1,^-<LTLANF##!LTLNRT##!LTLLAT##>
	UMOVEM	T1,1(M)		;TELL USER THE NETWORK TYPE
	JFFO	T1,.+2		;ENCODE THE FIRST NET TYPE WE FIND
	  JRST	NETDIS		;NO BITS, TREAT LOCAL LIKE ANF
	PJRST	@[IFIW NETDIA##		;ANF
		 IFIW NETDID##		;DECNET (CTERM OR NRT)
		 IFIW NETDIL##](T2)	;LAT
	SUBTTL	NETOP. UUO

;NETDIS - NETOP. function to return node and port ID for a local TTY
;
;Call: (in section 1 already)
;
;	F/ DDB of terminal
;	U/ LDB of terminal
;	M/ Address of user's NETOP. arg list
;Return:
;	ECDX?	depending on error
;	RETSKP	node name stored in string block pointed to by user's arg list
;
;Uses P1,P2 (already saved by higher routine), T1-T4, M

NETDIS:	MOVE	P1,M		;SAVE ARG LIST POINTER
IFN FTNET,<
	PUSHJ	P,GTNTS1	;GET NODE#,,LINE# IN T1
	  JRST	NOPDNC		;NOT CONNECTED
>
	EXCTUX	<SKIPN	M,5(P1)>	;DOES HE WANT NODE NAME?
	  JRST	NTDIS1		;NO
IFE FTNET,<SETZ T1,>		;NULL NODE NAME IF NO NETWORKS
IFN FTNET,<MOVE T1,STANAM##>	;GET OUR NODE NAME
	PUSHJ	P,PU6STB	;PUT SIXBIT INTO STRING BLOCK
	  JRST	NOPADC		;CAN'T
NTDIS1:	EXCTUX	<SKIPN	M,6(P1)>;DOES THE GUY WANT PORT NAME?
	  JRST	CPOPJ1##	;NO, DONE
	MOVE	T1,DEVNAM(F)	;YES, GET DEVICE NAME
	PUSHJ	P,PU6STB	;STORE SIXBIT NAME INTO STRING BLOCK
	  JRST	NOPADC		;NO LUCK
	JRST	CPOPJ1##	;DONE
;
;PU6STB - STORE A SIXBIT WORD INTO USER'S 8 BIT STRING BLOCK
;
;CALL: M/ADDRESS OF STRING BLOCK
;    	T1/SIXBIT WORD
;
;RETURN:	+1 ADDRESS CHECK
;		+2 SUCCESS
;
PU6STB::PUSHJ	P,SAVE2##	;GET A COUPLE OF SPARE REGS
	MOVE	P1,T1		;SAVE THE SIXBIT
	MOVE	T1,M		;COPY BLOCK POINTER
IFN FTXMON,<PUSHJ P,SSPCS##>	;PRESERVE PCS IN CASE WE NEED TO CHANGE IT
	PUSHJ	P,SXPCS##	;VALIDATE ITS FORM
	  POPJ	P,		;NO GO
	MOVEI	T4,2		;STRING BLOCK MIGHT ONLY NEED TO BE 2 LONG
	TRNE	P1,7777		;UNLESS WE HAVE 5 OR 6 CHARS
	MOVEI	T4,3		;THEN IT NEEDS TO BE 3 WORDS LONG
	PUSHJ	P,GETEWD##	;SEE HOW LONG IT IS
	  POPJ	P,		;NOT ADDRESSABLE AT ALL!
	HRRZ	T3,T1		;GET LENGTH IN WORDS
	CAIGE	T3,(T4)		;IF IT'S NOT LONG ENOUGH
	  POPJ	P,		;THEN PUNT
	PUSH	P,M		;SAVE START ADDRESS OF STRING BLOCK
	SETZ	T4,		;NO CHARS DONE YET
PU6ST1:	HRLI	T4,-4		;4 CHARS PER WORD
	SETZ	T1,		;ZAP THE TARGET WORD
	MOVE	T2,[POINT 8,T1]	;SET UP BYTE POINTER
PU6ST2:	JUMPE	P1,PU6ST3	;IF NO MORE CHARS, QUIT
	SETZ	P2,		;ZAP THE FREE AC
	ROTC	P1,6		;GET NEXT CHAR IN P2
	ADDI	P2," "		;MAKE IT ASCII
	IDPB	P2,T2		;STORE IT
	AOBJN	T4,PU6ST2	;KEEP STUFFING
PU6ST3:	JUMPE	T1,PU6ST4
	PUSHJ	P,PUTEW1##	;STORE A WORD OF RESULT
	  JRST	MPOPJ##		;CAN'T
	JRST	PU6ST1		;KEEP DOING IT
PU6ST4:	POP	P,M		;GET BACK ORIGINAL ADDRESS
	HRL	T3,T4		;RECORD HOW MANY CHARS DONE
	MOVE	T1,T3
	PJRST	PUTEWD##	;INFORM THE USER (MAYBE TAKE FAIL RETURN)
;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
	PUSHJ	P,CHKSPL	;SPOOLED DEVICE?
	  MOVEI	F,DSKDDB##	;YES, SET FOR A DISK

	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
SUBTTL	DEVGEN UUO


;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
	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
	SE1XCT	<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
	CAIN	T1,.TYTSK	;TSK?
	JRST	DSKUDX		;YES, RETURN CHANNEL
	MOVE	T3,T1
	LSH	T1,9		;ALLOW FOR UNIT NUMBER
	LDB	T2,PUNIT##	;PICK UP UNIT NUMBER
	CAIN	T3,.TYRDA	;RDX DEVICE
	ANDI	T2,7		;YES, ONLY LOW ORDER 3 BITS
	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
	CAIN	T3,.TYPTY
	SKIPA
	IOR	T1,T2
	CAIN	T3,.TYRDA	;RDX DEVICE
	JRST	DEVUD1		;YES
	CAIN	T3,.TYRX2	;FLOPPY DISK
	JRST	DEVUD1			;YES
	CAIE	T3,.TYMTA	;IS THIS A MAG TAPE
	CAIN	T3,.TYDTA	; 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 ;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	;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>
	REPEAT .TYRX2-<.-TYPTAB>,<
	EXP	0>
	TYPES	<RXA>
	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:	S0PSHJ	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
	MOVE	U,DDBLDB##(F)	;GET THE LDB
	PUSHJ	P,GTNTS1	;GET [NODE #,,LINE #] IN T1
	  JRST	ECOD2##		;TTY NOT CONNECTED
	PJRST	STOTC1##	;RETURN THE NODE,,LINE

;COMMON SUBROUTINE TO GET NODE AND LINE NUMBER
;ARG U=LDB ADDRESS
;RETURN	CPOPJ	IF TTY NOT CONNECTED OR SET HOSTED AWAY
;	CPOPJ1	WITH T1=XWD NODE NUMBER,LINE NUMBER
GTNTS0::SE1ENT			;ENTRY FROM SECTION 0
GTNTS1::			;ENTRY FROM SECTION 1
IFN FTNET,<
	SKIPL	T1,LDBTTW##(U)	;ANF NETWORK VIRTUAL TERMINAL?
	JRST	GTNTSL		;NO, LOCAL TTY
	MOVE	T2,LDBREM##(U)	;GET THE WORD WITH "CONNECTED" BIT
	TLNN	T2,LRLCON##	;IS THIS TERMINAL CONNECTED
	POPJ	P,		;TERMINAL NOT CONNECTED.
	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	CPOPJ1		;EXIT
GTNTSL:	TLNE	T1,LTLUSE##	;MUST BE REALLY CONNECTED TO SOMETHING
	SKIPGE	LDBREM##(U)	;IF LOCAL LINE SET HOSTED AWAY
	POPJ	P,		;THEN GIVE NOT CONNECTED RETURN

>	;END IFN FTNET
	LDB	T1,LDPLNO##	;GET THE LINE NUMBER
IFN FTNET,<
	HRL	T1,JBTLOC##	;GET THE LOCAL NODE NUMBER
>
	PJRST	CPOPJ1		;GIVE GOOD RETURN
;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

	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
	SKIPGE	LDBTTW##(T2)	;ANF NETWORK TERMINAL?
	JRST	ECOD1##		;YES, ILLEGAL DEVICE
>	;END IFN FTNET
GTXTN5:	S0PSHJ	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	LOCATE UUO

;LOCATE UUO (CALLI 62)
;PLACES THE CALLER AT THE DESIRED STATION SITE
;CALL: AC HAS STATION NAME OR NUMBER TO LOCATE AT

ULOCAT:	NETDBJ			;INTERLOCK THIS WITH NETSER
	SKIPE	F,TTYTAB##(J)	;POINT TO JOB'S TTY
	CAME	T1,[EXP -1]	;IF ARG IS -1...
	JRST	ULOCA1		;NO
	PUSHJ	P,FNDDEV	;PUT JOB WHERE TTY IS
	JRST	ULOCA2		;LOCATE THE JOB
ULOCA1:	MOVE	T2,T1		;COPY ARGUMENT
	PUSHJ	P,CVTOCT	;CONVERT TO OCTAL
	  MOVE	T1,T2		;CAN'T, RESTORE
	SKIPN	T1		;0 IMPLIES LOCAL STATION
	SKIPA	T1,JBTLOC##	;USE CENTRAL STATION NUMBER
	SKIPE	[M.ANF##]	;ANF-10 MONITOR?
	TLNN	T1,-1		;AND POSSIBLY A NODE NAME?
	JRST	ULOCA2		;NO, MUST BE NODE NUMBER
	PUSHJ	P,SRCNDB##	;DO WE KNOW ABOUT IT?
	  POPJ	P,		;NO, CAN'T LOCATE
	HLRZ	T1,NDBNNM##(W)	;GET NODE NUMBER
ULOCA2:	CAILE	T1,77		;IS THE STATION IN RANGE
	POPJ	P,		;NO, ERROR RETURN
	MOVEM	T1,JBTLOC##(J)	;LOCATE JOB
	JRST	CPOPJ1##	;GIVE GOOD RETURN

;ROUTINE TO FIND LOCATION OF A DEVICE
;RETURN WITH T1=LOCATION
FNDDEV::LDB	T1,PDVSTA##	;GET DDB LOCATION
	MOVSI	T2,DVTTY	;SEE IF
	TDNN	T2,DEVMOD(F)	; TTY
	POPJ	P,		;NO.
	MOVE	U,DDBLDB##(F)	;YES, SET UP U
	PJRST	FNDSTA##	;AND COMPUTE FROM LDB
	SUBTTL	WHERE UUO

;WHERE UUO (CALLI 63)
;IF AC CONTAINS 0 TO 17 THE CALLER WANTS THE LOCATION OF THE DEVICE
;INITED ON THE CHANNEL NUMBER SPECIFIED IN AC. LH(AC) = STA STATUS BITS
;IF AC IS GREATER THAN 17 IT IS ASSUMED TO BE A SIXBIT DEVICE NAME
;THAT THE CALLER WISHES TO KNOW THE STATION OF. LH(AC) = STA STATUS BITS

UWHERE:	NETDBJ			;INTERLOCK THIS WITH NETSER
	CAMN	T1,[SIXBIT/OPR/] ;IS IT AN OPR
	JRST	UWHER2		;USE THE JOB LOCATION
	PUSHJ	P,DVCNSG	;SEARCH FOR DEVICE OR CHANNEL
	  JRST RTZER		;NONE--RETURN ERROR AS 0
	PUSHJ	P,FNDDEV	;GET STATION NUMBER
	JUMPN	T1,UWHER1	;USE IT IF NON ZERO
	LDB	T2,PDVTYP##	;GET TYPE OF DEVICE
	CAIE	T2,.TYD78	;IF DAS78 DEV LEAVE IT 0
	MOVE	T1,JBTLOC##	; OTHERWISE USE CENTRAL SITE NUMBER
UWHER1:	SKIPN	DEVCHR(F)	;IF A "FAKE" DDB,
UWHER2:	HRRZ	T1,JBTLOC##(J)	;TELL WHERE JOB IS
IFN FTKL10,<
	LDB	T2,PDVTYP##	;GET TYPE OF DEVICE
	CAIN	T2,.TYD78	;A DAS78 DEVICE?
	JRST	STOTC1##	;STATUS BITS TO 0 AND RETURN
> ;END IFN FTKL10
	CAME	T1,JBTLOC##	;CENTRAL SITE?
	SKIPN	[M.ANF##]	;ANF-10 MONITOR?
	JRST	STOTC1##	;YES, STATUS BITS ALL ZERO
IFN FTNET,<
	PUSHJ	P,SRCNDB##	;FIND THE NODE BLOCK
	  JRST	RTZER		;DOES NO EXIST
	HLRZ	T1,NDBNNM##(W)	;GET THE NODE NUMBER
>;END IFN FTNET
	JRST	STOTC1##	;STORE T1 IN USER'S AC
	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,.USCTA	;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
	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
	CAIG	F,SPLTOP##	;IF IN SPLTAB,DEVJOB
	CAIGE	F,SPLTAB##	;INVALID, BUT SHOULD BE 0
	CAIA			;(NOT THE CASE)
	JRST	DEVLN3		;YES..NOT ASSIGNED
	LDB	T2,PJOBN##
	MOVE	T1,DEVMOD(F)	;DEVICE INITED OR ASSIGNED?
	CAMN	T2,J		;MY DEVICE
	TRNN	T1,ASSCON!ASSPRG
IFE FTMDA,<JRST	DEVLN3>		;NO, RETURN -3
IFN FTMDA,<
	JRST	[CAME  J,MDAJOB	;IS MDA DOING THIS?
		 JRST  DEVLN3	;NO, CAN'T SUCCEED
		 JUMPE T2,.+1	;YES, CONTINUE IF NO OWNER
		 CAME  T2,MDAJOB ; OR MDA IS RESPONSIBLE FOR DDB
		 JRST  DEVLN3
		 JRST  .+1]	;LET MDA GET UNOWNED DEVICE
>;END IFN FTMDA
	PUSHJ	P,SAVE1##	;SAVE P1
	PUSHJ	P,GETWD1##	;GET LOGICAL NAME
	LDB	J,PJCHN##	;SET TARGET JOB/CONTEXT HANDLE
	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
	MOVE	T1,DEVMOD(F)	;IF NOT ASSIGNED ...
	TRNE	T1,ASSCON!ASSPRG ;DON'T FIX LOGICAL NAME TABLE
	DPB	J,PJCHN##	;STORE JCH IN DDB
	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
	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
	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?
	TRNE	S,760000	;ANY ERRORS?
	PJRST	WAIT1##		;YES, JUST WAIT FOR I/O TO STOP
	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 FTMPXSER,<
	LDB	T1,PDVTYP##	;DEVICE TYPE
	CAIN	T1,.TYMPX	;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
>
IFN FTKL10&FTMP,<
	PUSHJ	P,UPDNBF	;INCREMENT DEVNBF FOR THIS BUFFER
>
	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
	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
	MOVE	T2,JBTSTS##(J)	;GET JOB STATUS
	TLNE	T2,JLOG		;NOT LOGGED IN
	TLNE	T2,JACCT	;OR JACCT
	CAIA			;IS OK
	JRST	ACTNPV		;ELSE NOT PRIVED
	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
	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



ULOGIN:	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,JBTPPN##(J)	;GET OUR PPN
	MOVEM	T1,.PDLPN##(W)	; AND SAVE AS LOGGED-IN PPN
	MOVE	T1,JBTPRV##(J)	;GET MY PRIVILEGE WORD
	MOVEM	T1,.PDCAP##(W)	; AND SAVE AS CAPABILITY WORD

	PUSHJ	P,SLPTR##	;GET POINTER TO SEARCH LIST IN P2
	  JRST	LOGIN2		;ERROR, DON'T TRY TO TELL QUASAR
	MOVE	P1,P2		;FILFND WANTS S/L POINTER IN P1
	PUSHJ	P,SLNMSG##	;TELL QUASAR JOB'S SEARCH LIST
	  JFCL			;QUASAR NOT RUNNING

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

	MOVE	T2,[JACCT,,JS.XO] ;RESET THESE BITS TO INDICATE LOG-IN IS
	ANDCAM	T2,JBTSTS##(J)	; NOW COMPLETE AND ^C IS AGAIN PERMITTED.
	MOVSI	T2,(UP.CXO)
	ANDCAM	T2,.USBTS	;CLEAR XO CORE IMAGE
	HRRZ	M,.JDAT+JOBPD1##+1 ;LOCATION OF UUO IN USER AREA
	SKIPN	%SIQSR##	;QUASAR RUNNING?
	TDZA	T2,T2		;NO--MPB BATCH SYSTEM
	MOVSI	T2,(JB.LBT)	;GET THE BATCH BIT
	TDNE	T2,JBTLIM	;IS IT BATCH?
	AOS	BATNUM##	;YES, INCREMENT BATCH COUNT.
	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.
	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

	XWD	W,.PDCNO##	;CHARGE NUMBER THIS JOB

LOGTOP==.-LOGTAB	;NO. OF TABLES TO BE SET
;ACCLOG UUO

ACCLOG:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVE	P1,T1		;STORE OUR FLAGS
	TLNN	P1,(AC.MAX!AC.BMX!AC.DCR)	;AT LEAST ONE BIT ON?
	  JRST	ACLILL		;NO, SO GIVE HIM AN ERROR
	SYSPIF			;NOW LOCK THIS CODE
	TLNN	P1,(AC.MAX)	;DO WE WANT LOGMAX CHECKING?
	  JRST	ACLBAT		;NO, SO CHECK BATMAX
	MOVE	T2,LOGMAX##	;GET MAX NUMBER OF JOBS
	TLNN	P1,(AC.BMX)	;BATCH LOGIN?
	SUB	T2,BATMIN##	;INCLUDE RESERVED BATCH SLOTS IN TALLY
	CAMG	T2,LOGNUM##	;IF MORE SLOTS THAN JOBS LOGGED IN THEN SKIP
	  JRST	ACLMXF		;NO ROOM, ERROR FAIL FOR LOGMAX
ACLBAT:	TLNN	P1,(AC.BMX)	;DO WE WANT BATMAX CHECKING?
	  JRST	ACLDCR		;NO, SO CHECK IF LOGIN FAILED
	MOVE	T2,BATNUM##	;GET CURRENT NUMBER OF BATCH JOBS
	CAMLE	T2,BATMAX##	;IF LESS THAN OR EQUAL ITS OK (SCNSER DID INC)
	  JRST	ACLBMF		;GREATER, SO GO KILL THIS
ACLDCR:	TLNN	P1,(AC.DCR)	;IS THIS A JOB THAT FAILED TO LOGIN?
	  JRST	ACLDON		;NO, ALL DONE
	SYSPIN			;UNLOCK, WE SHOULD BE CLEAR NOW
	PUSHJ	P,FNDPDS##	;GET POINTER TO PDB
	MOVSI	T1,(PD.LGN)	;GET THE COUNT BIT
	TDNN	T1,.PDDFL##(W)	;IS IT SET?
	  TRNA			;NO, SO SKIP
	  JRST	ACLDCE		;YES, THEN DON'T DO DECR.
	MOVSI	T1,JLOG		;GET THE LOGIN BIT
	TDNE	T1,JBTSTS##(J)	;ARE WE LOGGED IN?
	  JRST	ACLJLE		;YES, WE CAN'T DECREMENT IF LOGGED IN
	MOVSI	T1,(PD.LGN)	;NO, GET THE RIGHT BITS BACK
	IORM	T1,.PDDFL##(W)	;MARK THAT WE'RE DECREMENTING
	SOS	LOGNUM##	;THEN DECREMENT LOGNUM
	JRST	CPOPJ1##	;AND WE ARE DONE
ACLDON:	MOVSI	T1,(PD.LGN)	;GET THE COUNT BIT
	TDNN	T1,.PDDFL##(W)	;IS IT ALREADY OFF?
	  JRST	ACLRTN		;YES, THEN RETURN
	ANDCAM	T1,.PDDFL##(W)	;NO, SO CLEAR IT AND
	AOS	LOGNUM##	;INCREMENT LOGNUM
ACLRTN:	SYSPIN			;UNLOCK NOW
	JRST	CPOPJ1##	;AND RETURN TO USER

ACLMXF:	SYSPIN			;LOGMAX FAILURE, TURN LOCK OFF
	JRST	ACLMXE		;RETURN WITH ERROR

ACLBMF:	SYSPIN			;BATMAX FAILURE, TURN LOCK OFF
	JRST	ACLBME		;RETURN AN ERROR

	ERCODE	ACLMXE,ACLMX%	;LOGMAX CHECK FAILED (TOO MANY)
	ERCODE	ACLBME,ACLBM%	;BATMAX CHECK FAILED (TOO MANY)
	ERCODE	ACLILL,ACLIL%	;ACCLG. ERROR, INCORRECT BITS SET
	ERCODE	ACLJLE,ACLJL%	;ACCLG. ERROR, USER TRIED DECR WITH JLOG ON
	ERCODE	ACLDCE,ACLDC%	;ACCLG. ERROR, DECR TRIED WITHOUT INCR DONE
;LOGOUT UUO



LOGOUT:	PUSHJ	P,TTYFNU##
	MOVE	T1,JBTSTS##(J)	;JOB STATUS
	TLNN	T1,JLOG		;LOGGED IN?
	JRST	LOGOUA		;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,LGINAM##	;RUNNING LOGIN
	CAMN	T1,LGONAM##	; OR LOGOUT?
	CAIA			;YES, ALLOWED TO DO THIS
	JRST	EXIT
LOGOUA:	MOVSI	T1,(PD.LGO)	;INDICATE LOGOUT UUO IN PROGRESS
	IORM	T1,.PDDFL##(W)	; ..
	JRST	JOBKL##		;GO DO THE WORK
;ATTACH UUO - PRIVILEGED, FOR DAEMON, ATTACH COMMAND.
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  RTZERP		;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	RTZERP		;NO. GIVE FAIL RETURN.
	MOVE	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	RTZERP		;NO, FAIL RETURN
	SKIPA	T1,(P)		;YES, RESTORE JOB NUMBER
UATC1A:	HRR	T1,J		;NEGATIVE JOB ARGUMENT MEANS SELF
	HRRZS	T1		;MAKE SURE NO LEFT HALF BITS
	HRRZ	F,TTYTAB##(T1)	;DDB OF JOB DESIRED
	JUMPE	F,RTZERP	;IF NONE, FAIL RETURN
	MOVE	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	RTZERP		;NO. FAIL RETURN.
	MOVE	T2,LINTAB##(T1)	;"TO" TTY
IFN FTNET,<
	SKIPL	LDBTTW##(T2)	;ANF NETWORK TERMINAL?
	JRST	UATC1W		;NO, PROCEED
	MOVE	T3,LDBREM##(T2) ;GET THE REMOTE WORD
	TLNN	T3,LRLCON##	;IS THIS TTY CONNECTED?
	  JRST	RTZERP		;NO, NEVER MIND!
> ;END IFN FTNET
UATC1W:	JUMPE	U,UATC1X	;JUMP IF NO "FROM" TTY
IFN FTNET,<
	SKIPGE	LDBREM##(U)	;IF LOCAL LINE SET HOSTED AWAY
	  JRST	RTZERP		;THEN NOT AVAILABLE FOR ATTACH
>
	PUSHJ	P,PTYDTC##	;DETACH VIA F
UATC1X:	HLRZ	U,0(P)		;GET LINE NUMBER
	MOVE	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 RTZERP		;FAIL RETURN (SHOULDN'T HAPPEN)
	MOVEI	T1,JS.RPC	;JOB ALLOWED MONITOR LEVEL?
	TDNE	T1,JBTST2##(J)
	HRLI	P1,200000	;NO--FORCE USER MODE
	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	RTZERP		;NO, RETURN
	PUSHJ	P,TTYSRC##	;YES, SET UP 4
	  PJRST	RTZERP		;SHOULD NEVER FAIL
	HLRZ	T1,(P)		;GET TTY NUMBER HE WANTED DET'D
	TRZ	T1,600000	;GET RID OF FLAGS
	CAIN	T1,177777	;IS IT -1? (DEFAULT FOR SELF)
	JRST	UATAC6		;YES, CHECK USER MODE
	LDB	P1,LDPLNO##	;GET REAL TTY NUMBER
	CAME	T1,P1		;SAME?
	PJRST	RTZERP		;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	RTZERP		;NO, RETURN
	JRST	UATAC3		;YES, NOW DET HIM.
	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	;RANGE TABLE?
	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	GETTB1		;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	GETTB5		;NO, GO GET THE ANSWER
GETTB1:	CAIE	T1,GT.RNG	;RANGE?
	CAIN	T1,GT.ITM	;OR ITEM INDEX?
	JRST	GETTB2		;YES
	CAIL	T2,-2		;WANT JOB'S HIGH SEGMENT?
	MOVE	J,.CPJOB##	;YES, INDEX = CURRENT JOB NUMBER
	CAIE	T2,-2		;YES--SEE IF REQUESTING HI-SEG
	JRST	GETTB2		;NO--SKIP AHEAD
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,FNSPCS##	;GET HIGH SEG FOR THIS SECTION
	  PUSHJ	P,[JUMPL  J,CPOPJ1## ;OK IF SPY
		   PUSH   P,T1	;SAVE ONE FOUND
		   PUSHJ  P,NXSPCS## ;ARE THERE ANY MORE
		     JRST TPOPJ## ;NO MORE
		   ADJSP  P,-3	;FIX STACK
		   POPJ   P,  ]	;ERROR RETURN (AMBIGUOUS)
	JUMPE	T1,TPOPJ##	;NO SEGMENT AT ALL, RESTORE T1 AND ERROR
	POP	P,T1
	TLZ	J,-1
;AT THIS POINT T3=TABLE NUMBER AND J=INDEX
GETTB2:	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
	JUMPN	T2,GETTB3	;JUMP IF NON-ZERO MAXIMUM
	CAIE	T1,GT.ITM	;INDEXED BY ITEM?
	JRST	RTZER1		;NO, THEN NUMTAB IS REALLY WRONG
	HRRZ	T4,NUMTAB(T3)	;GET TABLE ADDRESS FROM NUMTAB
	CAIN	T4,NULGTB	;THE "NULL" GETTAB TABLE?
	JRST	RTZER1		;YES, TABLE NOT IN MONITOR
	JRST	GETTB4		;TABLE WITH ONE ENTRY, GO PROCESS IT

GETTB3:	CAIE	T4,.GTRNG
	JRST	GETTB4
	CAIE	T1,GT.RNG
	SKIPA	T1,T2
	MOVE	T1,RNGTAB(T2)
	JRST	STOTC1##

GETTB4:	SKIPL	J		;SKIP IF TOO SMALL
	CAMLE	J,T2		;SKIP IF VALID INDEX
	POPJ	P,		;INDEX IS TOO BIG
	CAIE	T1,GT.PDB	;IS DATA IN PDB?
	JRST	GETTB5		;NO--GET FROM TABLE
	PUSHJ	P,FNDPDB##	;TRY TO FIND PDB
	  JRST	RTZER1		;NO PDB, RETURN ZERO
	HRRZ	T3,NUMTAB(T3)	;INDEX INTO PDB
	ADD	T3,W		;ADD PDB ADDRESS TO GET OFFSET INTO PDB
	MOVE	T1,(T3)		;COPY THE PDB DATUM
	JRST	STOTC1##	;STORE AS ANSWER

GETTB5:	CAIN	T3,.GTSGN	;IS THIS .GTSGN?
	JRST	GETTB6		;YES--HANDLE SPECIALLY
	MOVE	T1,@NUMTAB(T3)	;GET WORD
	JRST	STOTC1##	;SKIP RETURN T1 IN HIS AC

GETTB6:	SETZB	T1,T2		;START FROM THE BEGINNING, PRESET RETURN AC
	PUSHJ	P,GNXHSB##	;FIND A HISEG BLOCK FOR THE JOB IN J
	  JRST	GETTB7		;RETURN FROM T2
	MOVE	T2,.HBSGN(T1)	;REMEMBER THE ENTRY
	PUSHJ	P,GNXHSB##	;GET THE NEXT ONE
	  JRST	GETTB7		;RETURN FROM T2 IF ONLY ONE HISEG
	JRST	ECOD0##		;PUNT IF TWO OR MORE HISEGS FOR THE TARGET JOB
GETTB7:	MOVE	T1,T2		;GET RETURN VALUE (0 OR OLD JBTSGN ENTRY)
	JRST	STOTC1##	;SKIP RETURN T1 IN USER 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,,NULGTB>
IFN FT,< JOBMXL##+<GT.JOB>B29+J,,TBL>
>
IFIDN <TYPE>,<S>,<
IFE FT,< JBTMXL##+<GT.SEG>B29,,NULGTB>
IFN FT,< JBTMXL##+<GT.SEG>B29+J,,TBL>
>
IFIDN <TYPE>,<P>,<
IFE FT,< JOBMXL##+<GT.JOB>B29,,NULGTB>
IFN FT,< JOBMXL##+<GT.PDB>B29+W,,TBL>
>
IFIDN <TYPE>,<I>,<
IFE FT,< NULGTB>
IFN FT,< MAX+<GT.ITM>B29+J,,TBL>
>
IFIDN <TYPE>,<R>,<
IFE FT,< NULGTB>
IFN FT,< EXP	<OFS>B8+<GT.RNG>B11+<J>B17+TBL>
>
>

NULGTB::0		;THE NULL GETTAB TABLE - SATISFY DUMMY GLOBALS

DEFINE	RANGE(FT,FIRST,LAST,RNG,NAME),<
IFN FT,<
RNG'OFS==.-RNGTAB
IFNB <NAME>,<
NAME::	FIRST,,LAST
>
IFB <NAME>,<
	FIRST,,LAST
>
>>
RNGTAB:	0			;ENTRY 0 NOT USED
	RANGE	1,<GTBSTT-NUMTAB>,<GTTBLN-1>,NUM
	RANGE	1,CTTWDT##-TTTWDT##,TTTWDN##+CTTWDT##-TTTWDT##-1,TTT
	RANGE	1,<.GTCSD##-.GTSID##>,SDTBLN##,SID
	RANGE	1,<CCNTAB##-TCNTAB##>,<TCNLIM##-TCNTAB##>,TCN
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	1,P,.PDTTM##		;(004) RUNTIME IN JIFFIES
	GT	1,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
.GTSGN==.-NUMTAB
	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	1,J,JBTRCT##		;(017) DISK READS
	GT	1,J,JBTWCT##		;(020) DISK WRITES
	EXP	NULGTB			;(021) UNUSED
	EXP	NULGTB			;(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
	EXP	NULGTB			;(027) UNUSED
	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	1,P,.PDCNO##		;(033) CHARGE NUMBER
	EXP	NULGTB			;(034) UNUSED
	GT	1,J,JBTWCH##		;(035) WATCH BITS
	GT	1,J,JBTSPL##		;(036) SPOOL TABLE
	GT	FTRTTR!FTHPQ,J,JBTRTD##	;(037) REAL TIME
	GT	1,J,JBTLIM##		;(040) CORE AND TIME LIMITS
	EXP	NULGTB			;(041) UNUSED
	EXP	NULGTB			;(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	1,I,WHYTXT##,WHYMXL##	;(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	1,I,PIDTAB##,MIDMXL##	;(076) PROCESS ID TABLE
	GT	1,I,IPCTAB##,IPCMXL##	;(077) IPCF MISC. DATA
	GT	1,S,JBTUPM##		;(100)POINTER TO USER PAGE MAP
	GT	1,I,WATTAB##,WTCMXL##	;(101) WATCH COMMANDS*
	GT	1,P,.PDCVL##		;(102) CURRENT VM LIMITS
	GT	1,P,.PDMVL##		;(103) MAX VM LIMITS
	GT	1,P,.PDIPA##		;(104) IPCF STATISTICS
	GT	1,P,.PDIPC##		;(105) IPCF POINTERS
	GT	1,P,.PDIPI##		;(106) THIS JOB'S [SYSTEM]INFO
	GT	1,P,.PDIPQ##		;(107) FLAGS AND QUOTAS
	EXP	NULGTB			;(110) OBSOLETE
	GT	FTKL10,P,.PDABS##	;(111) ADDRESS BREAK SETTING
	EXP	NULGTB			;(112) RESERVED
	GT	1,I,.GTVM##,GTVMXL##	;(113) VM DATA
	GT	1,P,.PDVRT##		;(114) PAGING RATES
	GT	1,I,.GTSST##,SSDMXL##	;(115) SCHEDULER STATISTICS
	EXP	NULGTB			;(116) OBSOLETE
	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	NULGTB			;(124) UNUSED
	EXP	NULGTB			;(125) UNUSED
;CONTINUED ON NEXT PAGE
	GT	1,R,.GTSID##,,SIDOFS	;(126) SPECIAL PIDS
	GT	1,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,I,NETGTT##,.NTMXL## ;(141) NETSER PERF MEASUREMENTS
	GT	FTPSCD,I,SCDPER##,%PERLN## ;(142) PERFORMANCE TABLE
	GT	1,P,.PDVKC##		;(143)JOB'S VIRTUAL KCT
	GT	1,P,.PDUUC##		;(144)JOB'S UUO COUNT
	GT	1,P,.PDSFD##		;(145) FIRST SFD 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	1,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,DVSXCT##,LENDVS##	;(160) CONI/DATAI DEVICE STATUS
	GT	FTNET,I,NDBTBL##,NDBMXL## ;(161) NDB BYTE POINTERS
	GT	1,J,JBTPDB##		;(162) JOB PDB ADDRESS
	GT	1,P,.PDEQJ##		;(163) ENQ Q-HEADER
	GT	1,I,DFLTTB##,DFLMXL##	;(164) SET DEFAULT COMMAND ARGUMENTS
	GT	1,P,.PDLBS##		;(165) BIG BUFFERS
	GT	1,P,.PDPGM##		;(166) PROGRAM TO RUN
	GT	FTMDA,P,.PDSTM##	;(167) TIME OF LAST RESET
	GT	FTDECNET,I,DCNGTB##,DCNGTL## ;(170) DECNET Q-HEADERS
	GT	FTDECNET,P,.PDSJB##	;(171) PTR TO DECNET SESSION JOB BLOCK
	EXP	NULGTB			;(172) OBSOLETE. DECNET QUOTA WORD
	GT	FTNET,I,.GTNDA##,NDAMXL## ;(173) NDB ADDRESS TABLE
	GT	FTNET,I,OBJTAB##,AOTMXL## ;(174) ANF-10 OBJECT TRANSLATION

;CONTINUED ON NEXT PAGE
	GT	1,I,CTXTAB##,CTXMXL##	;(175) CONTEXT DATA
	GT	1,S,JBTIMI##		;(176) IMAGE IN (PHYSICAL PROGRAM) SIZE
	GT	1,S,JBTIMO##		;(177) IMAGE OUT SIZE
	GT	1,J,JBTDDB##		;(200) I/O WAIT DDB
	GT	1,J,JBTVIR##		;(201) VIRTUAL PROGRAM SIZE
	GT	FTENET,I,ETHGTB##,ETHMXL## ;(202) ETHERNET INFORMATION
	EXP	0			;(203)	 OBSOLETE (HIGH SEG SECTION #)
	GT	1,I,CSTTAB##,COMMXC##	;(204) CUSTOMER DEFINED COMMANDS
	GT	1,I,NXMTAB##,NXMMXL##	;(205) NON-EX MEMORY BIT TABLE
	GT	1,I,BOOTXT##,BTXMXL##	;(206) BOOTS AUTO-RELOAD STRING
	GT	1,I,.GTCHN##,CHNMXL##	;(207) CHANNEL DATA BLOCK OFFSETS
	GT	1,I,KDBTAB##,<<TYPMAX>B26> ;(210) KDB CHAIN HEADERS
	GT	1,I,DDBTAB##,<<TYPMAX>B26> ;(211) DDB CHAIN HEADERS
	GT	1,R,TCNTAB##,,TCNOFS	;(212) SIXBIT TTY CLASS NAMES
	GT	1,P,.PDLPN##		;(213) LOGGED-IN PPN

;INSERT NEW TABLES ABOVE HERE
IFN FTPATT,<
	Z			;FOR PATCHING
	Z
>
GTTBLN=.-NUMTAB			;LENGTH OF TABLE
	$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,1,1,1,1,POKE,PEEK,1,1,1,1,1,1,MIC,MLOG,MDA>
;(1) REAL-TIME AND SCHEDULING FEATURES
	FTBITS<HPQ,1,1,RTTRAP,1,LOCK,0,0,1,1,NSCHED,PSCD,1>
;(2) COMMAND FEATURES (THIS WORD IS FULL)
	FTBITS<1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1>
;(3) ACCOUNTING FEATURES
	FTBITS<1,1,1,1,1,FDAE,EMRT,1>
;(4) NON I/O FEATURES NOT RELATED TO DEBUGGING (THIS WORD IS FULL)
	FTBITS<1,MP,1,1,1,1,1,0,0,0,1,0,KL10,1,KS10,1,SCA>
;(5) NON I/O DEBUGGING FEATURES
	FTBITS<0,0,1,1,0,PATT,1,RSP,1>
;(6) DISK UUO FEATURES (THIS WORD IS FULL)
	FTBITS<1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1>
;(7) DISK "INVISIBLE" FEATURES (THIS WORD IS FULL)
	FTBITS<1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0>
;(10) SCANNER, RP04 FEATURES
	FTBITS<0,0,0,1,1,1,1,1,1,1,0,0,1,0,1,1>
;(11) OTHER PERIPHERALS (THIS WORD IS FULL)
	FTBITS<1,1,1,1,1,NET,1,1,1,1,MPXS,1,1,1,TLAB,1,1>
;(12) OTHER PERIPERALS (SECOND WORD)
	FTBITS<1>
;(13) DISK "INVISIBLE" FEATURES (SECOND WORD)
	FTBITS<DUAL>
;(14) DISK UUO FEATURES (SECOND WORD)
	FTBITS<1,1>
;(15) LIST OF MONITOR NON-I/O FEATURES WHICH DIRECTLY IMPACT CUSPS (SECOND WORD)
	FTBITS <1>
	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
	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)
	MOVSI	T2,(IC.LIP)	;UUO DONE FROM A PUBLIC PAGE?
	TDNN	T2,.JDAT+JOBPD1##
	JRST	SETNM2		;NO, THEN ALWAYS LEGAL TO CLEAR XO
	SETZ	T1,		;START WITH FIRST SEGMENT
SETNM1:	PUSHJ	P,GNXHSB##	;GET NEXT HIGH SEGMENT DATA BLOCK
	  JRST	SETNM2		;IF THE END, MUST BE OK TO CLEAR XO
	MOVE	T3,.HBSGN(T1)	;GET SEGMENT BITS
	TLNE	T3,GTSSEG	;HE SEG CONCEALED?
	JRST	SETNM4		;YES, THEN CAN'T CLEAR XO
	JRST	SETNM1		;TRY NEXT SEGMENT
SETNM2:	MOVEI	T2,JS.RUU!JS.XO!JS.XOR	;CLEAR EXECUTE ONLY SO CAN SAVE
	ANDCAM	T2,JBTSTS##(J)	; A PROGRAM LOADED BY XO LOADER
				; ALWAYS CLEAR JACCT WITH JS.XO
	SETZ	T1,		;START WITH FIRST SEGMENT
SETNM3:	PUSHJ	P,GNXHSB##	;GET NEXT HIGH SEGMENT DATA BLOCK
	  JRST	SETNM4		;THAT WAS THE LAST ONE
	MOVE	T3,.HBSGN(T1)	;GET SEGMENT BITS
	TLNE	T3,GTSSEG	;SEGMENT CONCEALED (ONLY IF IC.LIP CLEAR)?
	TLO	T3,REDOMP	;YES, MAP MUST BE REDONE
	MOVEM	T3,.HBSGN(T1)	;PUT BITS BACK
	JRST	SETNM3		;NEXT SEGMENT
SETNM4:	MOVSI	T2,(UP.GET!UP.CXO) ;CLEAR GET IN PROGRESS FLAG
	ANDCAM	T2,.USBTS
	PUSHJ	P,MAPHGH##	;REDO THE MAP IN CASE CONCEALED
	MOVE	T1,JBTPRG##(J)	;RESTORE NAME
	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	/:/
	PUSH	P,P2
	SETZ	P2,		;NOT VERSION COMMAND, DON'T CALL PGMFIL
	PUSHJ	P,VERBTH##	;TYPE NAME AND VERSION
	POP	P,P2
	PJRST	PRRBKC##	;TYPE RIGHT BRACKET <CRLF>


;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
	CAMN	T1,.PDLPN##(W)	;RETURNING TO OUR LOGGED-IN PPN?
	JRST	CHGPP1		;NOT-LOGGED-IN IS GOLDEN
	MOVE	T2,T1		;COPY NEW PPN TO A SAFER PLACE
	MOVE	T1,[<JP.POK,,0>!CHGPPP##] ;EITHER POKE OR CUST PRIV
	PUSHJ	P,PRVBIT##	; OR JACCT OR [1,2]
	  SKIPA	T1,T2		;YES (I HATE BACKWARDS RETURNS)
	POPJ	P,		;NO, USER LOSES
	PUSHJ	P,PPNCHK	;SEE IF WE LIKE THE PPN
	  POPJ	P,		;PPN CANNOT BE CHANGED
CHGPP1:	MOVEM	T1,JBTPPN##(J)	;OK, CHANGE PPN
	JRST	CPOPJ1##	;AND GIVE OK RETURN


;THIS ROUTINE IS FURNISHED AS AN EXAMPLE OF HOW CUSTOMERS MIGHT
;WHAT TO EXCLUDE CHANGING TO PARTICULAR PPNS.
PPNCHK:	CAMN	T1,FFAPPN##	;OPERATOR?
	JRST	CPOPJ1##	;OK TO CHANGE TO [OPR]
	CAML	T1,MFDPPN##	;ALLOWING PPN CHANGES TO ONE OF
	CAMLE	T1,NEWPPN##	; THESE COULD BE QUITE DISASTEROUS
PPNCH1:	AOS	(P)		;OTHER CHECKS COULD BE MADE HERE
	POPJ	P,		;DON'T ALLOW SPECIAL SYSTEM PPNS
	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.


UDVNAM:	PUSHJ	P,DVCNSG	;SEARCH FOR CHANNEL OR DEVICE
	  JRST RTZER		;NONE--RETURN ERROR AS 0
	TLZ	F,-1
	CAIE	F,DSKDDB##	;CLAIM TO BE GENERIC DSK?
	SKIPA	T1,DEVNAM(F)	;USE NAME FROM DDB
	PUSHJ	P,LNMNUL##	;LOGICAL NAME MAPPED TO NUL?
	  CAIA			;NO--LEAVE NAME ALONE
	MOVSI	T1,'NUL'	;ELSE RETURN NUL
	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)


TRPSET:	TDZA	T3,T3		;FORCE SW EVENT LOGGING
TRPSTU:	SETOM	T3		;DON'T LOG SW EVENT (DIAG. UUO)
	MOVE	T2,JBTPRV##(J)	;IS JOB PRIVILEGED TO DO TRPSET UUO?
	MOVE	T4,JBTSTS##(J)	;...
	AND	T4,T3		;KEEP JACCT BIT IF DIAG. ONLY
	TLNN	T2,PVTRPS	;DOES JOB HAVE TRPSET PRIV?
	TLNE	T4,JACCT	;OR JACCT IF DIAG. UUO?
	SKIPA			;YES, CONTINUE
	POPJ	P,		;NO, ERROR RETURN

IFN FTMP,<
TRPSE0:	PUSHJ	P,LOKSCD##	;GET SCHEDULAR INTERLOCK
	SKIPE	.CPSTS##	;TIMESHARING STOPPED?
	CAMN	J,.CPSTS##	;YES, BY THIS JOB?
	JRST	TRPSE1		;NOT STOPPED, OR STOPPED BY THIS JOB
	PUSHJ	P,ULKSCD##	;RELEASE SCHEDULAR INTERLOCK
	PUSHJ	P,WSCHED##	;WAIT FOR OTHER JOB TO FINISH
	JRST	TRPSE0		;AND TRY AGAIN
TRPSE1:	PUSHJ	P,TRPSTX	;DO TRPSET CODE
	  SKIPA			;PROPOGATE NON-SKIP RETURN
	AOS	(P)		;PROPOGATE SKIP RETURN
	PJRST	ULKSCD##	;RELEASE SCHEDULAR INTERLOCK AND RETURN
>; END IFN FTMP

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

TRPSTX:	SETZM	.CPSTS##	;CLEAR THE STOP TIME SHARING FLAG
	CAMN	J,TGHJOB##	;TGHA?
	JRST	TRPST0		;WE DON'T TRUST HIM, BUT HAVE NO CHOISE
	MOVE	T2,T1		;EVENT-SPECIFIC DATA WORD (TRPSET AC)
	MOVEI	T1,.SWETP	;EVENT CODE (TRPSET)
	PUSHJ	P,SWESEB##	;LOG EVENT
	SETZ	F,		;AVOID IME
	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##>	;JOB MUST BE LOCKED IN EVM
	  POPJ	P,		;NO (OR LOCKING UNSUPPORTED), 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,.CPEPT##	;ADD IN TRAP 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.
;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##

	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
	MOVE	P1,T1		;SAVE ARGUMENT
	SKIPE	.USWLC		;USER WRITE-LOCKED PAGES?
	JRST	HIBE4A		;YES
	MOVEI	T1,UP.NVS	;JOB HAS PAGES ON THE DISK BIT
	SKIPE	.USVRT		;JOB VIRTUAL?
	TDNE	T1,.USBTS	;YES, DO WE KNOW ABOUT WRITE LOCKED PAGES?
	CAIA			;JOB NOT VIRTUAL OR WE HAVE ALREADY COUNTED WLP
	PUSHJ	P,XPANDH##	;CAUSE PAGES TO BE WRITE LOCKED
HIBE4A:	MOVE	T1,P1		;RESTORE ARGUMENT
	HLRZ	T2,T1		;GET THE PROTECTION BITS
	DPB	T2,HIBPRT##	;STORE PROTECTION CODE IN LEFT HALF OF JBTRTD(J)
	TRNN	T2,TTILCE##	;TTY WAKEUPS ENABLED?
	TRZ	T2,UDIUUB##	;NO, CAN'T BE DEMANDING INPUT
	MOVEI	T3,TTIUDI##	;USER DEMANDING INPUT BIT
	ANDCAM	T3,JBTRTD##(J)	;ASSUME SHOULD BE CLEAR
	TRNE	T2,UDIUUB##	;DOES THE USER WANT INPUT?
	IORM	T3,JBTRTD##(J)	;YES, FLAG IT
	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
	TRNE	T2,TTILCE##	;IS JOB GOING INTO CHARACTER MODE?
	PUSHJ	P,HIBTTY##	;YES, GO SET UP LINE CHARACTERISTICS
	JUMPGE	T1,HIBER2	;DOES JOB WANT TO BE SWAPPED OUT IMMEDIATELY?
				; (HBRSWP SET)
	PUSHJ	P,ZERIPT##	;YES, MARK HIM AS SWAPPABLE.
	MOVE	T1,P1		;PICKUP. ARGUMENT OF UUO AGAIN
HIBER2:	HLRZ	T2,T1		;SAVE THE FLAGS
	HRRZS	T1		;GET THE SLEEP TIME IN MILLISEC
	JUMPE	T1,HIBER0	;IF NO SLEEP TIME,DONT ENTER CLOCK REQUEST
	IMUL	T1,TICSEC##	;CONVERT TO JIFFIES
	TRNE	T2,HBRSEC##	;IS SLEEP TIME ACTUALLY IN SECONDS?
	JRST	HIBER5		;YES,DON'T DIVIDE
	IDIVI	T1,^D1000	;CONVERT FROM MILLISECONDS
	SKIPE	T2		;IS THIS AN EVEN NUMBER OF JIFFIES
	AOS	T1		;NO, ALWAYS ROUND UP TO NEXT JIFFY
HIBER5:	CAMGE	T1,TICSEC##
	SKIPA	P1,[NAPQ##]	;NAP IF .LT. SECOND
HIBER0:	MOVEI	P1,SLPQ##	;PREPARE TO PUT JOB IN SLEEP QUEUE
	PUSH	P,T1		;SAVE ADJUSTED SLEEP TIME
	MOVSI	T2,WAKEB##	;CHECK IF JOB HAS BEEN AWAKENED
	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	TPOPJ1##	;GIVE A SKIP RETURN TO THE USER
HIBER1:	DPB	P1,PJBSTS##	;STORE THE SLEEP CODE IN JBTSTS WORD
	SYSPIN			;RESTORE PI SYSTEM
	AOS	-1(P)		;GIVE SKIP RETURN WHEN JOB WAKES UP
	POP	P,T1		;RESTORE ADJUSTED SLEEP TIME
	CAILE	T1,777777	;WAS THIS A VERY LARGE NUMBER
	MOVEI	T1,777777	;YES, THEN SLEEP THE MAXIMUM TIME
	JUMPN	T1,HSLEEP	;GO ENTER SLEEP TIME IN CLOCK REQUEST QUEUE
HIBER3:	PUSHJ	P,FNDPDS##	;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:
	MOVE	T2,T1		;GET JOB NUMBER OF WAKER
	SIGNAL	C$WAKE		;SIGNAL WAKEUP
	JFCL			;ALWAYS WAKE JOB (IN CASE PSISER DIDN'T)

	MOVSI	T2,(JS.HIB)	;JOB DID SLEEP UUO BIT
	TDNN	T2,JBTST2##(J)	;SLEEP OR HIBER?
	JRST	SETWAK		;SLEEP, JUST SET WAKE BIT
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
	CAMGE	T1,FRSHPQ##	;PRE-EMPTIVE HPQ?
	  JRST	CPOPJ1##	;NO
	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
	SKIPE	T3,SCDRTF##	;IS THERE A FORCED SCHEDULE TO BE DONE
	TRNN	T3,-1		;FOR A REAL JOB?
	MOVNM	J,SCDRTF##	;FLAG
	TDNN	T2,JBTSTS##(J)	;IS THIS JOB SWAPPED OUT
	JRST	WAKOK3		;NO. PROCEED.
	SKIPG	T2,SCDRTF##	;ANYONE IN SCDRTF?
	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,SCDRTF##	;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

;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
	CPLOCK	(SCD)		;UNTIL JOB GETS PUT INTO JDCQ
	PUSHJ	P,STDAEM##	;IS DAEMON RUNNING?
	  JRST	[CPUNLK	(SCD)
		 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
	CPUNLK	(SCD)		;DAEMON CAN RUN NOW
	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 IN PER-PROCESS SPACE
;	      AS IF MAPPED THROUGH SPECIFIED JOB'S MAP


JOBPEK:	HRR	M,T1		;SET UP FOR CALLS TO GETWRD
	HLRZ	T2,T1		;SAVE LENGTH
	PUSHJ	P,GETWRD##	;GET FIRST WORD (PRESERVES T2)
	  JRST	RTZER		;BAD ARG LIST
	MOVE	P1,T1		;SAVE FIRST WORD
	MOVSI	T1,JP.POK	;ONLY POKE PRIVS WILL WIN FOR A WRITE FUNCTION
	TLNN	P1,(JK.WRT)	;BUT IF WRITE IS OFF,
	TLO	T1,PVSPYA	; ALLOW SPYALL PRIVS TO LET THE USER READ
	PUSHJ	P,PRVBIT##	;USER SUFFICIENTLY PRIVILEGED (PRESERVES T2)?
	  SKIPA	T1,P1		;YES, RE-LOAD T1 AND SKIP
	JRST	JPKNPV		;NO, ERROR
	MOVSI	P1,(JK.ALL)	;FLAGS
	AND	P1,T1		;SAVE THEM IN P1
	JUMPE	T2,JPKOLD	;OLD FORMAT
	CAIGE	T2,4		;MUST BE AT LEAST 4 ARGS
	JRST	RTZER
	HRRI	P1,(T1)		;JCH IN RH(T1)
	LDB	P4,[POINT 10,T1,17] ;COUNT
	PUSHJ	P,GETWR1##	;GET NEXT WORD
	  JRST	RTZER		;(CURRENTLY IGNORED)
	PUSHJ	P,GETWR1##
	  JRST	RTZER
	MOVE	P2,T1		;READ ADDRESS
	PUSHJ	P,GETWR1##	;WRITE ADDRESS
	  JRST	RTZER
	MOVE	P3,T1
	JRST	JPKCMN
JPKOLD:	HRRZ	P4,T1		;COUNT TO P4
	LDB	T1,[POINT 9,T1,17] ;JOB #
	IORI	P1,(T1)		;IN RH(P1)
	PUSHJ	P,GETWR1##	;GET ADDRESS WORD
	  JRST	RTZER
	HLRZ	P2,T1		;READ ADDR
	HRRZ	P3,T1		;WRITE ADDR
JPKCMN:	TLNE	P1,(JK.WRT)	;WRITE?
	EXCH	P2,P3		;YES, ADDRESSES ARE BACKWARDS
	TLNE	P1,(JK.EVA!JK.UPM) ;OTHER GUY TO BE MAPPED THROUGH EVM?
	TLO	P2,(JK.EVA)	;YES, SET THAT
	TLNE	P1,(JK.UPM)	;AND IF UPT
	HRRI	P2,.UPMP	;FORCE IT
;HERE WITH DATA SET UP AS THE FOLLOWING:
;
;	P1=FLAGS,,OTHER JCH
;	J=OUR JOB #
;	P2=OTHER ADDRESS (+JK.EVA IF APPLICABLE)
;	P3=OUR ADDRESS (+JK.EVA IF APPLICABLE)
;	P4=# WORDS TO TRANSFER

JOBPK0:	SETZ	F,		;FLAG INDICATING WE HAVE DDB
	MOVE	T1,P3		;ADDRESS IN OUR JOB
	TLZ	T1,(JK.ALL)	;CLEAR FLAGS
	MOVEI	T2,(P4)		;GET LIMIT
	PUSHJ	P,ARNGE##	;CHECK IT
	  JRST	JPKIAD		;NO
	  JFCL			;DON'T CARE IF I/O ILLEGAL FOR NOW
;HERE WITH ADDRESS IN OUR JOB VERIFIED AS LEGAL

JOBPK1:	TLNN	P2,(JK.EVA)	;IS HIS ADDRESS IN EVM?
	JRST	JOBPK2		;NO, CAN'T VERIFY ANYTHING ABOUT IT YET
	MOVEI	T2,(P2)		;IN EVM, GET ADDRESS
	CAIL	T2,FYSORG
	CAILE	T2,.LPPP-1	;IS IT LEGAL?
	JRST	JPKIAD		;NO
JOBPK2:	PUSHJ	P,SIPCHK	;SEE IF JOB IS STABLE, GET THE MM IF IT IS
	  JRST	JPKDNA		;NOT AVAILABLE
	HRRZ	T1,P1		;GET OTHER JCH
	PUSHJ	P,CTXJPK##	;GET JBTSWP POINTER (MAY NOT BE SWAPPED)
	  JRST	JKIJC0		;ILLEGAL JOB/CONTEXT NUMBER
JOBPK7:	JUMPE	T2,JOBPK3	;JOB IS IN CORE
JPKSUP:	PUSHJ	P,GETSCR	;GET DDB, BUFFER PAGE, AND REMEMBER IT
	  JRST	JKSER0		;OOPS
	EXCH	T1,T2		;UPT POINTER TO T1, IOWD TO T2
	PUSH	P,T1		;SAVE UPT POINTER
	PUSHJ	P,REDSWP	;READ THE SWAPPING SPACE
	  JRST	JKSERR		;OOPS
	PUSHJ	P,SIPCHK	;SEE IF JOB IS IN TRANSIT AGAIN
	  JRST	JKDNA1		;DATAT NOT AVAILABLE
	HRRZ	T1,P1		;GET OTHER JCH
	PUSHJ	P,CTXJPK##	;GET SWAP PARAMETER AGAIN
	  JRST	JKIJCH		;WENT AWAY
	PUSHJ	P,GETSCR	;REMAP .JBPK IN CASE WE GOT SWAPPED
	  JRST	JKSERR
	POP	P,T3		;RESTORE OLD POINTER
	CAMN	T3,T2		;CHANGED?
	JRST	JOBPK5		;NO, ASSUME UPT READ IS RIGHT
	JUMPN	T2,JPKSUP	;SWAPPED AT A DIFFERENT ADDR, TRY AGAIN
	HRRZ	T1,P1		;(LOAD JCH FOR BELOW)
JOBPK3:	ANDI	T1,JOBMSK	;ONLY JOB #
	HRRZ	T1,JBTUPM##(T1)	;GET UPT PAGE
	HRLI	T1,(<PM.DCD>B2+PM.PUB+PM.WRT) ;MAP THE UPT, MAY NEED TO WRITE
	MOVEM	T1,.UPMP+.UMJBK	;SET MAP SLOT
	CLRPT	.JBPK		;CLEAR THAT
;HERE WITH THE "OTHER" UPT MAPPED AT .UMJBK
;T2 CONTAINS SWAPPING POINTER FOR UPT IF JOB IS SWAPPED

JOBPK5:	TLNE	P2,(JK.EVA)	;IS IT IN EVM?
	JRST	JPKEVM		;YES, NO ADDRESS CHECKING
	HRRZ	T1,P1		;JCH
	PUSHJ	P,CTXSGN##	;GET SEGMENT INFO (JBTSGN INTO T1)
	  JRST	JKIJCH		;GONE AWAY?
	JUMPE	T1,JPKLW0	;CAN'T BE IN HS IF THERE ISN'T ANY
	PUSH	P,T2		;SAVE UPT POINTER
JOBP5B:	LDB	T3,[PSG2LH+.HBSG2(T1)] ;GET SECTION HIGH SEG IS IN
	HLRZ	T4,P2		;MIGHT BE IN HIS HIGH SEG
	TRZ	T4,(JK.ALL)	;CLEAR FLAGS (LEAVING SECTION #)
	CAIE	T4,(T3)		;IS THIS RIGHT SECTION?
	JRST	JOBP5A
	MOVEI	T3,(P2)		;NOT IN EVM, ADDR CHECK HIS (SECT REL) ADDR
	PUSH	P,J		;SAVE J
	SKIPGE	J,.HBSGN(T1)	;GET SEGMENT #
	SKIPA	T2,[PSPOLH+.HBSPO(T1)]
	SKIPA	T2,JBYHSO##
	SKIPA	T4,J		;SIZE IF SPY SEG
	TLZA	J,-1		;CLEAR BITS
	TLZA	T4,-1		;CLEAR BITS
	HLRZ	T4,JBTADR##(J)	;GET TOP
	LDB	T2,T2		;GET ORIGIN
	LSH	T2,P2WLSH
	JUMPN	T4,JOBP5C	;JBTADR SET UP (OR SPY SEG)
	LDB	T4,IMGOUT##	;SIZE ACTUALLY ON SWAP SPACE (NOT
				;QUITE RIGHT IF EXPANDING, BUT SAFER)
	LSH	T4,P2WLSH	;CONVERT TO WORDS
	SOS	T4
JOBP5C:	ADDI	T4,(T2)		;END OF HIGH SEG
	HLL	T4,.HBSGN(T1)	;BITS TO T4
	POP	P,J		;RESTORE J
	CAIL	T3,(T2)		;IN HIS HIGH SEG?
	CAILE	T3,(T4)		;?
	JRST	JOBP5A
	JUMPLE	T4,JPKLOW	;SPY SEG
	TLNN	T4,SHRSEG	;SHARABLE?
	JRST	JPKLOW		;NON-SHARABLE, CAN'T BE SHARABLE TOO
;HERE FOR JOBPEK INVOLVING SHARABLE HIGH SEG
JPKHI:	HRRZ	J,.HBSGN(T1)	;GET SEGMENT NUMBER, MINUS CRUD
	SKIPN	JBTADR##(J)	;IS HIGH SEG IN CORE?
	  JRST	JPKHSW		;NO, SWAPPED
JPKHI1:	MOVNS	T2		;MAKE NEGATIVE
	ADDI	T2,(P2)		;RELATIVE ADDRESS
	LSH	T2,W2PLSH	;PAGE # TO FIND
	PUSHJ	P,SNPAGS##	;FIND IT
	HRLI	T1,(<PM.DCD>B2!PM.WRT!PM.PUB!PM.COR) ;PAGE POINTER
	MOVEM	T1,.UPMP+.UMJBK	;MAKE ADDRESSABLE
	CLRPT	.JBPK
	TLNE	P1,(JK.WRT)	;WRITING?
	PUSHJ	P,ZERSWP##	;CLEAR DISK COPY OF HIGH SEG
	MOVE	J,.CPJOB##	;GET JOB # BACK
	MOVSI	T1,(PM.COR)	;FLAG NO SWAP SPACE TO WRITE
	POP	P,T2		;RESTORE UPT POINTER
	JRST	JPKMOV		;MOVE THE DATA

JOBP5A:	SKIPN	T1,.HBLNK(T1)	;CHECK NEXT SEGMENT
	JRST	JPKLOW		;NOT IN ANY HIGH SEG
	JRST	JOBP5B		;LOOP BACK

;HERE IF HIGH SEG SWAPPED
;J HAS HISEG #, T2 HAS SWAPPING POINTER FOR JCH WE ARE LOOKING AT

JPKHSW:	HRRZ	T3,P2		;OTHER ADDRESS
	SUB	T3,T2		;MAKE RELATIVE TO HIGH SEG ORIGIN
	LSH	T3,W2PLSH	;PAGE IN QUESTION
	SKIPL	T1,JBTSWP##(J)	;IS HIGH SEG FRAGMENTED?
	JRST	JPKHS5		;NO, EASY CASE
JPKHS1:	SKIPGE	T4,(T1)		;POINTER TO ANOTHER FRAGMENT?
	JRST	[MOVEI	T1,(T4)	;YES, GO TO IT
		 JRST	JPKHS1	]
	JUMPE	T4,JKSERR	;HUH?
	LDB	T4,FRGCT4##	;GET COUNT OUT OF T4
	CAILE	T4,(T3)		;DESIRED ADDRESS IN THIS FRAG?
	JRST	JPKHS4		;YES
	SUBI	T3,(T4)		;NO, SUBTRACT OUT
	AOJA	T1,JPKHS1	;LOOK AT NEXT FRAG

JPKHS4:	MOVE	T1,(T1)		;ENTRY
JPKHS5:	TLZ	T1,(PM.NAD)	;(KEEP ONLY A DISK ADDRESS, THIS SYMBOL CLOSE)
	ADDI	T1,(T3)		;ACTUAL SWAPPING POINTER
	POP	P,T3		;UPT POINTER
	MOVE	T2,T1		;SAVE DISK ADDR
	PUSHJ	P,GETSCR	;GET SWAPPING SPACE
	  JRST	JKSER0
	EXCH	T1,T2		;IOWD TO T2, POINTER TO T1
	PUSH	P,T3		;UPT POINTER
	PUSH	P,T1		;HS SWAP POINTER
	TLNE	P1,(JK.WRT)	;WRITING?
	CAIE	P4,PAGSIZ	;EXACTLY ONE PAGE?
	JRST	JPKHS6		;NO
	TRNN	P2,PG.BDY	;AND STARTING ON A PAGE BOUNDARY?
	JRST	JPKHS7		;WRITING ONE PAGE ON PAGE BOUNDARY
JPKHS6:
	PUSHJ	P,REDSWP
	  JRST	JKSER2
JPKHS7:	PUSH	P,J		;SAVE J
	MOVE	J,.CPJOB##	;IN CASE WE SLEEP
	PUSHJ	P,SIPCHK	;SEE IF JOB STABLE
	  JRST	JKDNA3		;NOT AVAILABLE
	POP	P,J		;RESTORE J
	PUSHJ	P,CTXJPK##
	  JRST	JKIJC2
	POP	P,T1		;RESTORE SWAPPING POINTER
	POP	P,T3		;OLD POINTER
	SKIPE	JBTADR##(J)	;HIGH SEG STILL OUT
	JRST	JPKHI1		;LOOK AGAIN
	MOVE	J,.CPJOB##	;RESTORE JOB # TO J
	CAMN	T2,T3		;JOB IN SAME PLACE?
	JRST	JPKMOV		;YES, ASSUME OK
	JRST	JOBPK7		;JOB CHANGED STATE
;HERE FOR JOBPEK INTO EVM
;T2 HAS UPT SWAPPING POINTER

JPKEVM:	TLNE	P1,(JK.UPM)	;UPT?
	JRST	JPKMOV		;YES, ALREADY MAPPED
	MOVEI	T1,(P2)		;GET ADDRESS
	SUBI	T1,FYSORG	;RELATIVE PAGE IN FUNNY SPACE
	LSH	T1,W2PLSH	;CONVERT TO PAGE
	SKIPN	T1,.JBPK+.UMORG(T1) ;GET POINTER FOR THIS PAGE
	JRST	JKXIAD		;NON-EXISTANT
	TLNN	T1,(<PM.DCD>B2)	;SWAPPED?
	JRST	JPKEVS		;YES
	HRLI	T1,(<PM.DCD>B2!PM.PUB!PM.COR!PM.WRT)	;MAKE SURE WE KNOW NO SWAP SPACE
	MOVEM	T1,.UPMP+.UMJBK
	CLRPT	.JBPK
	JRST	JPKMOV

JPKEVS:	TLZ	T1,(PM.NAD)	;SAVE SWAPPING POINTER
	DMOVE	T3,T1		;SAVE UPT POINTER (T4) AND THIS POINTER (T3)
	PUSHJ	P,GETSCR	;GET DDB IF IF DON'T HAVE ALREADY
	  JRST	JKSER0		;ERROR
	PUSH	P,T3		;SAVE THIS PAGE POINTER
	PUSH	P,T4		;SAVE UPT POINTER
	PUSHJ	P,SIPCHK	;SWAPPING I/O IN PROGRESS NOW?
	  JRST	JKDNA2		;NOT AVAILABLE
	HRRZ	T1,P1		;OTHER JCH
	PUSHJ	P,CTXJPK##	;FIND INTERESTING PARAMETERS
	  JRST	JKIJC2		;ILLEGAL JOB
	POP	P,T3		;RESTORE UPT POINTER
	POP	P,T1		;AND POINTER FOR THIS PAGE
	CAME	T2,T3		;UPT STILL IN SAME PLACE?
	JRST	JOBPK7		;NO
	TLNE	P1,(JK.WRT)	;WRITING?
	TLNE	P2,PG.BDY	;YES, ON A PAGE BOUNDARY?
	JRST	JPKES1		;NO
	CAIN	P4,PAGSIZ	;AND WRITING EXACTLY A PAGE?
	JRST	JPKMOV		;NO READING IF WRITING EXACTLY A PAGE
JPKES1:	PUSH	P,T3		;SAVE UPT POINTER
	PUSH	P,T1		;AND POINTER TO THIS SLOT
	MOVE	T2,DEVDMP##(F)	;GET IOWD
	PUSHJ	P,REDSWP	;READ SWAPPING SPACE
	  JRST	JKSER2		;LOSE
	PUSHJ	P,SIPCHK	;SEE IF SWAPPING I/O IN PROGRESS NOW
	  JRST	JKDNA2		;NOT AVAILABLE
	HRRZ	T1,P1
	PUSHJ	P,CTXJPK##	;GET SWAPPING POINTER
	  JRST	JKIJC2
	POP	P,T1		;RESTORE SWAPPING PTR FOR THIS SLOT
	POP	P,T3		;AND FOR UPT
	CAMN	T2,T3		;JOB SAME PLACE?
	JRST	JPKMOV		;YES
	JRST	JOBPK7
;HERE FOR LOW SEG, SPY SEG, OR NON-SHARABLE HIGH SEG
;T1 HAS SECTION # INVOLVED, UPT SWAPPING PONTER (IF SWAPPED, ZERO IF NOT) ON STACK
;UPT MAPPED THROUGH .UMJPK

JPKLOW:	POP	P,T2		;RESTORE SWAPPING POINTER
JPKLW0:	HLRZ	T1,P2		;GET SECTION #
JPKLW1:	CAILE	T1,MXSECN	;LEGAL SECTION?
	JRST	JKXIAD		;NO, FLUNK OUT NOW
	SKIPN	T2		;UPT IN CORE?
	SKIPN	.JBPK+.UPWLP	;MAP CONTAIN WRITE LOCKED PAGES?
	TDZA	T3,T3		;NO TO EITHER, THIS IS EASY
	MOVE	T3,.UPMP+.UMJBK	;YES TO BOTH, REMEMBER WHERE UPT IS
	SKIPN	T1		;IS IT SECTION 0?
	SKIPA	T1,.JBPK+.UMUPM	;YES, USE .UPMAP
	MOVE	T1,.JBPK+SECTAB(T1) ;ELSE GET SECTION POINTER
	TLNE	T1,(<PM.DCD>B2)	;IN CORE?
	JRST	JPKLW2
JPKSUM:	TLZ	T1,(PM.NAD)	;CLEAR BITS
	MOVE	T3,T1		;SAVE SECTION MAP POINTER
	PUSHJ	P,GETSCR	;GET SCRATCH DDB IF NEEDED
	  JRST	JKSER0		;OH WELL
	MOVE	T1,T3		;RESTORE POINTER TO PAGE WE WANT
	PUSH	P,T2		;SAVE T2
	MOVE	T2,DEVDMP##(F)	;(NOTE THAT MAP ONLY SWAPPED IF UPT WAS)
	PUSHJ	P,REDSWP	;READ SWAPPING SPACE
	  JRST	JKSERR		;FIX STACK
	PUSHJ	P,SIPCHK	;GET MM AND CHECK IN PROGRESS STATE
	  JRST	JKDNA1		;ERROR
	HRRZ	T1,P1
	PUSHJ	P,CTXJPK##	;GET UPT POINTER AGAIN
	  JRST	JKIJCH		;FIX STACK AND RETURN
	POP	P,T3		;RESTORE SAVED POINTER
	CAME	T3,T2		;STILL THE SAME?
	JRST	JOBPK7		;JOB CHANGED STATE
	PUSHJ	P,GETSCR	;IN CASE WE GOT SWAPPED
	  JRST	JKSER0
	JRST	JPKLW4		;YES,CONTINUE
;HERE WITH JOB IN CORE
JPKLW2:	TLNN	T1,(<PM.ACD^!PM.DCD>B2)	;IS THIS INDIRECT SECTION?
	JRST	JPKLW3		;NO
	LDB	T1,[POINT 5,T1,17] ;GET SECTION #
	JRST	JPKLW1		;CONTINUE
JPKLW3:	TLZ	T1,(PM.CSH)	;JUST TO BE SAFE
	MOVEM	T1,.UPMP+.UMJBK	;MAP USER MAP AT .JBPK
	CLRPT	.JBPK
JPKLW4:	HRRZ	T4,P2		;SECTION RELATIVE ADDRESS IN HIS AREA
	LSH	T4,W2PLSH	;PAGE #
	SKIPN	T1,.JBPK(T4)	;DOES PAGE EXIST IN HIS MAP?
	JRST	JKXIAD		;NON-EXISTENT
	CAMN	T1,[PM.ZER]	;ABZ PAGE?
	JRST	JKXABZ		;YES
	TLNN	T1,(PM.COR)	;IN CORE?
	JRST	JPKPAG		;NO
	SKIPE	T3		;MAP CONTAIN WRITE LOCKED PAGES?
	TLOE	T1,(PM.WRT)	;AND IS THIS PAGE WRITE LOCKED?
	JRST	JPKLW7		;NO TO EITHER, JUST DO THE COPY
	TLNN	P1,(JK.WRT)	;WRITING?
	JRST	JPKLW7		;NO, NO NEED TO WRITE ENABLE THE PAGE
	MOVEM	T1,.JBPK(T4)	;STORE POINTER BACK WITH PM.WRT ON
	MOVEM	T3,.UPMP+.UMJBK	;AND STORE POINTER TO UPT SO CAN DECREMENT WLP
	CLRPGT			;CLEAR EVERYTHING SINCE MAY BE DOING THIS TO US
	SOS	.JBPK+.UPWLP	;DECREMENT COUNT OF WRITE LOCKED PAGES
	S1PSHJ	[PUSHJ P,SAVT##	;ALL T'S ARE IMPORTANT
		 MOVE T2,T1	;ARGUMENT FOR RTNFS0
		 PJRST RTNFS0##];RETURN SWAPPING SPACE
	JRST	JPKLW7		;GO DO THE COPY
JPKPAG:	MOVE	T3,T1		;SAVE PAGE TO WRITE
	PUSHJ	P,GETSCR	;GET DDB ET ALL IF WE DON'T HAVE ALREADY
	  JRST	JKSER0
	PUSH	P,T2		;UPT POINTER
	PUSH	P,T3		;PAGE TO READ
	MOVE	T2,T1		;IOWD TO T2
	MOVE	T1,T3		;PAGE TO READ
	TLNE	P1,(JK.WRT)	;IS THIS A WRITE?
	CAIE	P4,PAGSIZ	;OF EXACTLY ONE PAGE?
	JRST	JPKPG2		;NO, MUST READ
	TRNN	P2,HLGPNO	;AND ONLY WORKS IF STARTING ON PAGE BOUNDARY
	JRST	JPKPG4
JPKPG2:	MOVE	T1,(P)		;RESTORE ADDRESS
	TLZ	T1,(PM.NAD)
	PUSHJ	P,REDSWP
	  JRST	JKSER2		;LOSE
JPKPG4:	PUSHJ	P,SIPCHK	;GET MM
	  JRST	JKDNA2
	PUSHJ	P,GETSCR	;MAKE SURE MAPPING IS RIGHT
	  JRST	JKSER2
	HRRZ	T1,P1
	PUSHJ	P,CTXJPK##	;GET SWAPPING PIONTER AGAIN
	  JRST	JKIJC2		;LOSE
	POP	P,T1
	POP	P,T3		;RESTORE SAVED POINTER
	CAME	T2,T3		;CONTEXT STAYED IN SAME PLACE?
	JRST	JOBPK7		;NO
	JRST	JPKMOV		;CONTINUE
JPKLW7:	HRLI	T1,(<<PM.DCD>B2!PM.WRT!PM.COR!PM.PUB>) ;BE SURE PAGE ACCESIBLE AND WRITABLE (AND NOT CACHED)
	MOVEM	T1,.UPMP+.UMJBK
	CLRPT	.JBPK
;HERE WITH DATA TO BE MOVED TO/FROM .JBPK

JPKMOV:	MOVEI	T4,.JBPK	;POINT TO WHERE DATA IS
	DPB	P2,[POINT 9,T4,35] ;PAGE OFFSET
	PUSH	P,T1		;SAVE PAGE POINTER
	HLRZ	T1,P3		;SECTION
	PUSHJ	P,STPCS##
	POP	P,T1
	HRLI	T4,(P3)		;GET OUR ADDRESS
	MOVSI	T3,(XCT)	;INSTURCTION TO DO
	TLNN	P1,(JK.WRT)	;WRITING?
	TLOA	T3,(Z PX.MEM,)	;READING, SET MONITOR TO USER
	TLOA	T3,(Z PX.SRC,)	;WRITING, SET USER TO MONITOR
	MOVSS	T4		;IF READING, ADDRESSES ARE REVERSED
	HRRI	T3,[BLT T4,(T2)] ;INSTR TO EXECUTE
	LDB	T2,[POINT 9,P2,35] ;PAGE OFFSET IN OTHER MAP
	ADDI	T2,-1(P4)	;IF ALL, # OF WORDS WE WOULD TRANSFER
	CAIGE	T2,PAGSIZ	;CROSS A PAGE BOUNDARY IF WE DO?
	JRST	JPKMO4		;NO, NO SWEAT
	LDB	T2,[POINT 9,P2,35] ;GET OFFSET AGAIN
	SUBI	T2,PAGSIZ	;COMPUTE ACTUAL TRANSFER SIZE WE CAN MAKE
	MOVNS	T2
	ADD	P2,T2		;UPDATE FOR NEXT TIME
	ADD	P3,T2		;..
	SUB	P4,T2		;# WORDS LEFT
	JRST	JPKMO5
JPKMO4:	MOVEI	T2,(P4)		;# OF WORDS TO MOVE
	SETZ	P4,		;# OF WORDS LEFT AFTER
JPKMO5:	ADDI	T2,-1(T4)	;LAST WORD WRITTEN
	XCT	T3		;XCT PROPER PXCT
IFN FTMP,<
	  ERJMP	[PUSHJ	P,DWNMM##
		 JRST	JPKIAD	]
>
IFE FTMP,<
	ERJMP	JPKIAD
>
IFN FTMP,<
	PUSHJ	P,DWNMM##
>
	TLNN	T1,(PM.COR)	;WAS PAGE IN CORE?
	TLNN	P1,(JK.WRT)	;NO, WAS THIS A WRITE?
	JRST	JPKMO6		;DONE IF READ OR PAGE WASN'T SWAPPED
	TLZ	T1,(PM.NAD)
	MOVE	T2,DEVDMP##(F)	;DUMP IOWD
	PUSHJ	P,WRTSWP	;WRITE SWAPPING SPACE BACK
	  JRST	JPKIOE
JPKMO6:	JUMPN	P4,JOBPK2
	JRST	CPOPJ1##
;SUBROUTINE TO SEE IF JOB IS STABLE.  RETURNS CPOPJ1 WITH THE MM IF JOB IS
;(JOB MAY BE IN OR OUT OF CORE, BUT CANNOT MOVE UNTIL MM RETURNED)
;RETURNS CPOPJ W/O MM IF AIO SET AND WE WOULD HAVE HAD TO BLOCK
;ENTER WITH P1=FLAGS,,OTHER JOB #
;USES T1-T4

SIPCHK:	MOVSI	T2,(JS.SIP)	;IS JOB SWAPPING?
	MOVEI	T3,(P1)
	ANDI	T3,JOBMSK##	;GET HIS JOB #
IFN FTMP,<
	PUSHJ	P,MMOWN##
	  PUSHJ	P,UPMM##	;GET THE MM
>
	CAME	T3,FIT##	;SWAPPER WAITING ON THIS JOB?
	CAMN	T3,FORCE##	;?
	JRST	SIPCK2		;YES, DELAY
	TDNE	T2,JBTST2##(T3)	;OR IS JOB SWAPPING?
	JRST	SIPCK2		;YES
	MOVEI	T1,(P1)		;GET JCH
	PUSHJ	P,CTXSGN##	;GET HIGH SEG #
	  JRST	SIPCK5		;OH WELL
	JUMPE	T1,SIPCK6
SIPCK3:	SKIPLE	T2,.HBSGN(T1)	;SPY SEGS DON'T GET SWAPPED MOST OF THE TIME
	TLNE	T2,SHRSEG	;AND NON-SHARABLE ONES GO WITH THE LOW SEG
	JRST	SIPC3A		;MAY BE MORE SEGS
	HRRZS	T2		;CLEAR JUNK
	CAMN	T2,FIT##	;THIS SEG?
	JRST	SIPCK2		;YES, DELAY
SIPC3A:	HRRZ	T1,.HBLNK(T1)	;NEXT SEG
	JUMPN	T1,SIPCK3

SIPCK6:	SKIPLE	T4,JBTHSQ##	;ANY JOBS IN HSQ QUEUE?
	TLZA	T4,-1		;YES, GO FORWARD
	JRST	SIPCK5		;DONE
SIPCK4:	CAIN	T4,(T3)		;THIS JOB IN THE HSQ QUEUE?
	JRST	SIPCK2		;YES
	HRRE	T4,JBTJIL##(T4)	;NEXT JBTHSQ ENTRY
	JUMPG	T4,SIPCK4	;CONTINUE IF MORE

SIPCK5:
IFN FTMP,<
	PUSH	P,J		;SAVE J
	MOVEI	J,(T3)
	TRNE	P1,CTXMSK##	;IF NO CONTEXT NUMBER SPECIFIED
	PUSHJ	P,CTXJCJ##	;GET CURRENT CONTEXT
	  MOVEI	T1,(P1)		;CURRENT IS THIS ONE
	CAIE	T1,(P1)		;IS CURRENT CONTEX ONE WHICH IS RUNNING?
	  JRST	JPOPJ1##	;NO, NO NEED TO CHECK CACHE (WAS SWEPT WHEN
				;THIS CONTEXT WENT TO THE SWAP SPACE)
	PUSHJ	P,ANYRUN##	;RUNNING ON SOME CPU?
	  JRST	SIPCK1		;CACHE ALWAYS WRONG
IFN FTKL10,<
	PUSHJ	P,SBCCSH##	;IS DATA VISIBLE?
> ;END FTKL10
	  JRST	JPOPJ1##	;OK TO PROCEED
SIPCK1:	POP	P,J
	TLNE	P1,(JK.AIO)	;DON'T BLOCK?
	PJRST	DWNMM##		;NO, GIVE UP THE MM AND RETURN
> ;END IFN FTMP
IFE FTMP,<
	JRST	CPOPJ1##
>
SIPCK2:
IFN FTMP,<
	PUSHJ	P,DWNMM##	;YES, DELAY
>
	SETZ	T1,
	PUSHJ	P,SLEEPF
	JRST	SIPCHK

;ERROR RETURNS WHICH FIX THE STACK, RETURN MM

JKDNA3:	POP	P,(P)
JKDNA2:	POP	P,(P)
JKDNA1:	POP	P,(P)
	MOVEI	T1,JPKDNA
	JRST	JPKERR

JKXIAD:	SKIPA	T1,[JPKIAD]
JKXIJN:	MOVEI	T1,JPKIJN
	JRST	JPKERR

JKIJC2:	POP	P,(P)
	JRST	JKIJCH

JKSER2:	POP	P,(P)		;FIX STACK ONE MORE
JKSERR:	SKIPA	T1,[JPKIOE]
JKIJCH:	MOVEI	T1,JPKIJN
	POP	P,(P)
	JRST	JPKERR

JKIJC0:	MOVEI	T1,JPKIJN
	JRST	JPKERR

JKXABZ:	SKIPA	T1,[JPKABZ]
JKSER0:	MOVEI	T1,JPKIOE
JPKERR:	MOVE	J,.CPJOB##	;IN CASE WAS DOING HIGH SEG
IFN FTMP,<
	PUSHJ	P,TGVMM##	;GIVE UP MM IF OWNED
>
	JRST	(T1)
;ERROR CODES RETURNED BY JOBPEK
	ERCODE	JPKNPV,JKNPV%	;NOT PRIVILEGED
	ERCODE	JPKIJN,JKIJN%	;ILLEGAL JOB NUMBER
	ERCODE	JPKIAD,JKIAD%	;ILLEGAL ADDRESS
	ERCODE	JPKDNA,JKDNA%	;DATA NOT ADDRESSABLE
	ERCODE	JPKIOE,JKIOE%	;I/O ERROR
	ERCODE	JPKMNC,JKSWP%	;MONITOR IS NOT CAPABLE
	ERCODE	JPKABZ,JKABZ%	;ALLOCATED BUT ZERO PAGE


;STILL IN FTDAEM CONDITIONAL
;SUBROUTINE TO ALLOCATE A DDB AND A PAGE OF FUNNY SPACE TO READ
; PAGES FROM THE SWAPPING SPACE INTO
;CALLING SEQUENCE:
;	PUSHJ	P,GETSCR
;	  ERROR RETURN - NO CORE AVAILABLE
;	NORMAL RETURN - F POINTS AT THE DDB,
;			 T2 AND DEVDMP(F) ARE IOWDS POINTING TO FUNNY SPACE PAGE

GETSCR:	JUMPE	F,GETSC1	;NEED TO DO SOMETHING
	HRRZ	T1,DEVDMP##(F)	;GET IOWD
	AOS	T1		;VIRTUAL ADDRESS IN REAL FUNNY SPACE
	MAP	T1,(T1)		;GET PAGE
	LSH	T1,W2PLSH	;GET PAGE #
	ANDI	T1,PM.PAG	;SAVE ONLY PAGE #
	HRLI	T1,(<PM.DCD>B2!PM.WRT)
	MOVEM	T1,.UPMP+.UMJBK ;POINT .JBPK BACK AT IT
	CLRPT	.JBPK
	MOVE	T1,DEVDMP##(F)
	JRST	CPOPJ1##
GETSC1:
	PUSH	P,T2
	PUSH	P,T3
	PUSH	P,T4		;SAVE MOST OF THE TS
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN MM?
	  JSP	T2,GTSCMM	;NO, REMEMBER THAT AND PROCEED
	PUSHJ	P,DWNMM##	;GIVE UP MM, BELOW ROUTINES GET BY HAND
	SETZ	T2,
GTSCMM:	PUSH	P,T2		;SAVE MM FLAG
>; END IFN FTMP
	MOVEI	T2,DDBLEN##
	PUSHJ	P,GFWDUD##
	  JRST	GTSCER
	PUSHJ	P,FAKDDX##
	  JRST	GTSCER
	PUSH	P,R
	SETZ	R,		;CLEAR R
	MOVSI	T1,(1B0)	;WANT IT UNCACHED
	PUSHJ	P,CREFSP##	;GET FUNNY SPACE PAGE
	  JRST	GTSCRR		;RESTORE R AND ERROR
	MAP	T2,(T1)		;GET PHYSICAL ADDRESS
	LSH	T2,W2PLSH	;CONVERT TO PAGE #
	ANDI	T2,PM.PAG	;PAGE # ONLY
	HRLI	T2,(<PM.DCD>B2!PM.WRT)
	MOVEM	T2,.UPMP+.UMJBK	;POINT .JBPK AT IT
	CLRPT	.JBPK
	SOS	T1
	HRLI	T1,-PAGSIZ
	MOVEM	T1,DEVDMP##(F)
	AOS	-<4+<IFN FTMP,<1>>>(P)
GTSCRR:	POP	P,R
GTSCER:
IFN FTMP,<
	POP	P,T2		;RESTORE MM FLAG
	SKIPN	T2
	PUSHJ	P,UPMM##	;IF HAD THE MM, GET IT BACK
>
	POP	P,T4
	POP	P,T3
	POP	P,T2
	POP	P,(P)		;RESTORE CALLER'S ADDRESS
	PUSHJ	P,@1(P)		;AND GIVE (SKIP) CO-ROUTINE RETURN
	  CAIA			;FAIL
	AOS	(P)
GIVCOR:	JUMPE	F,CPOPJ##
	PUSH	P,T1		;SAVE T1
	MOVEI	T1,PAGSIZ
	AOS	T2,DEVDMP##(F)
	HRRZS	T2
	PUSHJ	P,GVFWDS##
	PUSHJ	P,CLRDDB##
	JRST	TPOPJ##

;SUBROUTINE TO READ/WRITE SWAPPING SPACE
;CALLING SEQUENCE:
;	MOVE	T1,SWAPPING POINTER
;	MOVE	T2,IOWD
;	PUSHJ	P,RED/WRTSWP
;	  ERROR RETURN - I/O ERROR
;	NORMAL RETURN, T1 = IOWD

REDSWP:	TDZA	S,S
WRTSWP:	MOVSI	S,IO
	PUSHJ	P,SWPADR##
	  STOPCD	(CPOPJ,DEBUG,SDS) ;++SWPADR DIDN'T SKIP
	JUMPLE	U,CPOPJ##	;I/O ERROR IF UNIT GONE
IFN FTMP,<
	PUSHJ	P,REMMM##
>
	PUSH	P,J		;STOAU TRASHES J
	PUSHJ	P,STOAU##
	EXCH	T1,T2
	PUSH	P,.USMBF
	MOVEM	T1,.USMBF
	PUSHJ	P,MONIOU##	;I/O NOT USING DISK CACHE
	EXCH	T1,T2
	POP	P,.USMBF
	POP	P,J
	JUMPE	T3,CPOPJ1##
	POPJ	P,
;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
;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,-TTFCML##	;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
	MOVE	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
	MOVE	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
	JRST	TPOPJ##
SUBTTL	SPPRM. UUO

;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
	SKIPN	DEVCHR(F)
	PJRST	ECOD2##		;YES--NOT ASSIGNED OR INITED
				;FALL INTO SPPRM1
	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
	PUSHJ	P,SETSPB##	;CREATE SPB AND SET UP DEVSPM IF NECESSARY
				; RETURNS WITH T1 POINTING TO SPB
	  PJRST	ECOD4##		;NO FREE CORE
	SKIPN	DEVCHR(F)	;FAKE DDB?
	PJRST	ECOD2##		;YES--NOT ASSIGNED OR INITED
				;FALL INTO SPPRM1
SPPRM1:	SUBI	P1,2		;ADJUST FOR DEVICE NAME AND FUNCTION
	JUMPLE	P1,SPPRM3	;IF NO ARGS TO SAVE
	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
SPPRM3: 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	;LOAD STD VFU (DEP)
	XWD	2,DVPCAL	;ENABLE NON-STD VFU LOAD (DEP)
	XWD	3,DVPCAL	;DISABLE VFU LOAD
	XWD	11,DVPCAL	;LOAD RSX-20F LP RAM
	XWD	12,DVPCAL	;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
	XWD	1005,DVPCAL	;READ/SET FORMS TYPE (DEP)
	XWD	1006,DVPCL1	;READ/CLEAR DECTAPE READ/WRITE INFO
	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
UDEVOP:	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
	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: LDB	T2,PJOBN##	;GET JOB WHO OWNS DEVICE
	CAME	T2,J		;DO WE OWN IT?
	TRNE	T1,1000		;READ?
	CAIA			;OK
	JRST	ECOD6##		;DEVICE MUST BE INITED
DVPCL1:
IFN FTMP,<
	PUSHJ	P,SETCPP##	;GET ON CPU WHICH OWNS DEVICE
	  JRST	ECOD7##		;CPU DEAD, SAY DEVICE OFFLINE
>
	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/SET 'CONTROLLED BY MDA BIT (DVCMDA)
;
LBLBTS==(77000,,0)		;BITS 'FINP+LBLNED+LBLWAT+LBLSTP+FOUT+LBLEOF'

DVPMDC:	TDZA	T3,T3		;INDICATE 'CLEAR' FUNCTION
DVPMDS:	MOVEI	T3,1		;INDICATE 'SET' FUNCTION
	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
	SKIPN	T3		;MUST BE CLEARING MAG TAPE
	TLNN	T2,DVMTA	; STATUS BIT - IF NO, THEN
	SKIPA			; DO NOT CLEAR THE
	TLO	T3,400000	; TAPE LABELING STATUS BITS
	MOVSI	T2,DVCMDA	;LOAD UP DVCMDA
	XCT	[ANDCAM T2,DEVCHR(F)
		 IORM	T2,DEVCHR(F)](T3) ;CLEAR/SET DVCMDA
	JUMPGE	T3,CPOPJ1##	;RETURN IF NOT CLEARING DVCMDA FOR MTA
	MOVE	S,DEVIOS(F)	;LOAD UP S
	TLZ	S,LBLBTS	;CLEAR TAPE LABELING BITS
	MOVEM	S,DEVIOS(F)	;SAVE NEW STATE
	JRST	CPOPJ1##	;RETURN
>;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 FILOP. FUNCTION WORD

FO.PRV==(1B0)		;USE PRIVILEGES
FO.ASC==(1B1)		;ASSIGN EXTENDED CHANNEL
FO.UOC==(1B2)		;USE ALREADY-OPENED CHANNEL
FO.CFW==(1B3)		;CHANNEL ADDRESS AND FUNCTION CODE WORD

FO.CHN==(777B17)	;CHANNEL NUMBER FIELD
FO.FNC==777777		;FUNCTION CODE FIELD OR ADDRESS

;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
FOP.OC==(1B14)		;USE ALREADY-OPENED CHANNEL
FOP.AW==(1B15)		;ALLOCATION IS SPECIFIED IN WORDS
FOP.RD==(1B16)		;DEVICE MUST BE A DISK
;DISPATCH TABLE FOR FILOP. FUNCTIONS

FOPTAB:
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+FOP.RD,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
XWD	FOP.RD,CPOPJ1##				;(25) SEEK
XWD	FOP.RD,FOPRRC				;(26) REWRITE RIB IF CHANGED
EXP	FOPGTF					;(27) UGETF
EXP	FOPMTP					;(30) MTAPE
EXP	FOPUTP					;(31) UTPCLR
XWD	FOP.RN+FOP.LK+FOP.AW,FOPEN		;(32) RENAME W/ALLOC. IN WORDS
EXP	FOPFIL					;(33) RETURN FILESPEC
EXP	FOPXIN					;(34) EXTENDED DUMP MODE INPUT
EXP	FOPXOU					;(35) EXTENDED DUMP MODE OUTPUT
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,FOPE65	;ILLEGAL IF NEGATIVE OR ZERO
	HRR	M,T1		;POINT TO FIRST ARGUMENT
	PUSHJ	P,GETWDU##	;GET FIRST ARGUMENT
	TLO	T2,FOP.PV	;ASSUME PRIVILEGES DESIRED
	TLZE	T1,FO.ASC	;ASSIGN A FREE CHANNEL?
	TLO	T2,FOP.XC	;YES, REMEMBER THAT
	TLZE	T1,FO.UOC	;USE ALREADY-OPENED CHANNEL?
	TLO	T2,FOP.OC	;YES--REMEMBER IT
	TLZE	T1,FO.PRV	;DOES HE WANT TO BE PRIV'D?
	PUSHJ	P,PRVJO##	;IS HE PRIV'ED
	  TLZ	T2,FOP.PV	;NO, CLEAR THE BIT
	TLZN	T1,FO.CFW	;CHANNEL AND FUNCTION WORD?
	JRST	FILOP1		;NO, PROCEED TRADITIONALLY
	HRR	M,T1		;POINT TO CHANNEL AND FUNCTION WORD
	PUSHJ	P,GETWDU##	;GET IT
	MOVE	P1,T1		;SAVE IT
	HLR	M,T1		;POINT TO CHANNEL WORD
	TLNE	T2,FOP.XC	;ASSIGN AN EXTENDED CHANNEL?
	TDZA	T1,T1		;YES, DON'T USE STALE CHANNEL NUMBER
	PUSHJ	P,GETWDU##	;GET CHANNEL NUMBER
	EXCH	T1,P1		;GET BACK FUNCTION CODE
	JUMPL	P1,FOPE61	;NEGATIVE CHANNEL NUMBER IS TOO BIG
	SKIPA	M,FOPAP		;RESTORE M
FILOP1:	LDB	P1,[POINT 9,T1,17]  ;EXTRACT CHANNEL NUMBER
	CAILE	P1,HIGHXC##	;OUT OF RANGE?
	JRST	FOPE61		;ERROR - CHANNEL TOO BIG
	ANDI	T1,-1		;REDUCE TO JUST FUNCTION CODE
	CAILE	T1,FOPMAX	;FUNCTION TOO BIG?
	JRST	FOPE60		;ERROR - UNKNOWN FILOP. FUNCTION
	TLNE	T2,FOP.XC	;ASSIGN AN EXTENDED CHANNEL?
	JUMPN	P1,FOPE62	;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,.USCTA	;STORE UDX FOR THIS UUO
	CAIE	T2,FOPEN	;OPEN?
	JRST	[MOVE T4,DEVMOD(F) ;DEVICE CHARACTERISTICS
	TLNN T4,DVTTY	;NUL SAYS ITS A DSK

		 TLNN T4,DVDSK	;IS IT A DSK?
		 TLNN T3,FOP.RD	;NO IS A DSK REQUIRED
		 JRST (T2)	;NO, JUST DISPATCH
		 JRST CPOPJ1##] ;YES, FUNCTIONS IS A NOOP
	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,.USCTA
	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,.USCTA	;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:	SKIPL	USRHCU##	;SAVE/GET IN PROGRESS?
	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

;ROUTINE TO STORE IN-YOUR-BEHALF PPN IF SPECIFIED

FOPIYB:	HRRZ	T1,-2(P)	;# OF ARGUMENTS
	MOVE	T2,DEVMOD(F)	;DEVICE CHARACTERISTICS
	SKIPGE	DEVSPL(F)	;SPOOLED DEVICE?
	TLO	T2,DVDSK	;YES--PRETEND IT'S A DISK
	CAIL	T1,10		;8TH ARGUMENT SPECIFICATION
	TLNN	T2,DVDSK	;ONLY IF A DSK
	POPJ	P,		;NO
	HRR	M,-3(P)		;GET ARGUMENT POINTER
	HRRI	M,7(M)		;POINT TO "IN-YOU-BEHALF" PPN
	PUSHJ	P,GETWDU##	;GET IT
	TLNE	P2,FOP.PV	;DON'T STORE IF NOT PRIV'ED PROG INVOKING PRIVS
	MOVEM	T1,DEVUPP##(F)	;STORE IT FOR FNDFIL
	MOVSI	T1,(UP.IYB)	;IN YOUR BEHALF (FOR IPCSER)
	SKIPE	DEVUPP##(F)	;SPECIFIED?
	IORM	T1,.USBTS	;YES
	POPJ	P,
;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

;CHECK OUT THE LOOKUP/ENTER AND RENAME/DELETE BLOCKS, IF ANY

	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
	TRNN	M,-1		;LOOKUP/ENTER BLOCK GIVEN?
	JRST    FOPN0A		;NO
	PUSHJ	P,FCLERB	;CHECK LOOKUP/ENTER BLOCK
	  JRST	FOPE63		;ADDRESS CHECK
FOPN0A:	JUMPE	P2,FOPEN0	;JUMP IF NO RENAME/DELETE BLOCK
	HRR	M,P2		;ADDRESS OF THE RENAME/DELETE BLOCK
	PUSHJ	P,FCLERB	;MAKE SURE THATS IN CORE
	  JRST	FOPE63		;ADDRESS CHECK

;RANGE CHECK THE "RETURNED" PATH BLOCK, IF ANY

FOPEN0:	HRRZ	T4,FOPFLG	;GET ARG COUNT
	CAIGE	T4,7		;PATH POINTER
	JRST	FOPEN6		;NO--ALL IS WELL
	HRR	M,FOPAP		;GET ARG POINTER
	HRRI	M,6(M)		;PATH PTR
	PUSHJ	P,GETWRD##	;GET ARGUMENT
	  JRST	FOPE63		;ADDRESS CHECK READING ARGUMENTS
	JUMPE	T1,FOPEN6	;JUMP IF PATH ISN'T REQUIRED
	TLNN 	T1,-1		;LENGTH SPECIFIED?
	TLO 	T1,3		;NO, DEFAULT TO 3
	HLRZ	T2,T1		;COPY LENGTH
	HRLI	T1,(IFIW)	;MAKE SECTION RELATIVE
	PUSHJ	P,ARNGE##	;RANGE CHECK
	  JRST	FOPE63		;ADDRESS CHECK
	  JFCL			;ADDRESS OK BUT ILLEGAL FOR I/O (IGNORED HERE)

; RANGE CHECK THE "RETURNED" FILESPEC BLOCK, IF ANY
FOPEN6:	CAIGE	T4,11		;HAVE A POINTER?
	JRST	FOPVMX		;NO
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,10(M)		;FILESPEC BLOCK OFFSET
	PUSHJ	P,GETWRD##	;GET ARGUMENT
	  JRST	FOPE63		;ADDRESS CHECK READING ARGUMENT
	HLRE	T2,T1		;GET THE LENGTH
	JUMPE	T2,FOPVMX	;OK IF NO POINTER
	JUMPL	T2,FOPE66	;FILESPEC BLOCK LENGTH NEGATIVE OR ZERO?
	HRLI	T1,(IFIW)	;MAKE SECTION RELATIVE
	PUSHJ	P,ARNGE##	;RANGE CHECK
	  JRST	FOPE63		;ADDRESS CHECK
	  JFCL			;ADDRESS OK BUT ILLEGAL FOR I/O (IGNORED HERE)
;ALLOCATE AN "EXTENDED" I/O CHANNEL IF NECESSARY

FOPVMX:	MOVSI	T1,FOP.XC	;EXTENDED CHANNEL REQUESTED BIT
	TDNN	T1,FOPFLG	;WAS AN EXTENDED CHANNEL REQUESTED?
	JRST	FOPVM4		;NO, PROCEED TRADITIONALLY
	HRRZ	T1,.USCTA	;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	FOPE56		;ERROR - NO PER-PROCESS SPACE AVAILABLE
	HRRM	T1,.USCTA	;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	FOPE57		;ERROR - NO FREE CHANNELS AVAILABLE
;HERE WHEN AN AVAILABLE CHANNEL WAS FOUND
FOPVM3:	ADDI	P1,20		;EXTENDED CHANNEL NUMBER
	SETZ	F,		;IF WE JUST ASSIGNED A CHANNEL, IT AIN'T OPEN
;STORE CHANNEL NUMBER FOR THE USER
FOPVM4:	HRLM	P1,.USCTA	;CHANNEL NUMBER
	MOVE	P2,FOPFLG	;GET THE FILOP CONTROL FLAGS
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	PUSHJ	P,GETWDU##	;GET CHANNEL NUMBER
	DPB	P1,[POINT 9,T1,17] ;STORE POSSIBLE EXTENDED CHANNEL NUMBER
	TLNE	T1,FO.ASC	;ASSIGN EXTENDED CHANNEL?
	TLNN	T1,FO.CFW	;AND CHANNEL AND FUNCTION WORD?
	JRST	FOPVM5		;NO, PROCEED TRADITIONALLY
	HRR	M,T1		;POINT TO FUNCTION WORD
	PUSHJ	P,GETWDU##	;GET CHANNEL AND FUNCTION WORD
	HLR	M,T1		;POINT TO CHANNEL NUMBER WORD
	SKIPA	T1,P1		;GET CHANNEL NUMBER
FOPVM5:	TLZE	T1,FO.ASC	;CLEAR THE ASSIGN EXT CHAN BIT
	PUSHJ	P,PUTWDU##	;STORE CHANNEL FOR THE USER IF REQUESTED
	HRR	M,FOPAP		;RESTORE ARGUMENT POINTER
	TLNN	P2,FOP.OC	;USE ALREADY-OPENED CHANNEL?
	JRST	FOPVM6		;NO, MUST DO AN OPEN
	JUMPE	F,FOPE46	;A CHANNEL MUST BE OPEN
	TLNE	P2,FOP.RN!FOP.DL;CHANNEL OPEN, IF FOR A RENAME OR DELETE
	TLNE	F,LOOKB!ENTRB	;THEN A FILE MUST BE LOOKUP'ED AS WELL
	JRST	FOPEN2		;VALID CHANNEL - SKIP THE OPEN
	JRST	FOPE46		;ERROR - CHANNEL NOT OPENED
;HERE TO OPEN A NEW FILE FOR SOME SORT OF ACCESS

FOPVM6:	HRRI	M,1(M)		;POINT TO OPEN BLOCK
	MOVE	T1,.USFOP
	MOVEM	T1,FOPEXT
;	TLNE	P2,FOP.RN+FOP.DL ;RENAMES OR DELETES
;	JUMPN	F,FOPEN2	;YES, GO IF THE FILE IS ALREADY OPEN
	MOVSI	T1,(UP.FIP)	;MARK FILOP
	IORM	T1,.USBTS	;IN PROGRESS
	PUSHJ	P,UOPEN		;TRY TO OPEN
	  JRST	FOPOER		;CAN NOT OPEN
	MOVSI	T1,DVDSK	;DISK DDB?
	TDNN	T1,DEVMOD(F)
	JRST	FOPVM7		;NO, NO SUPER I/O IF NOT A DISK
	MOVSI	T1,DEPSIO##	;CLEAR THE BIT INITIALLY
	ANDCAM	T1,DEVPTB##(F)
	TLNN	P2,FOP.SO	;SUPER I/O FOR THIS FUNCTION?
	JRST	FOPVM7		;NO
	IORM	T1,DEVPTB##(F)	;LIGHT BIT SO SETSUP KNOWS
FOPVM7:	HRRZ	T1,FOPFLG	;GET ARG COUNT
	CAIN	T1,4		;ONLY DOING AN OPEN?
	JRST	FOPFSP		;YES--SEE IF RETURNED FILESPEC WANTED
	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
	SKIPG	T2		;SKIP IF NUMBER GIVEN
	MOVEI	T2,0		;ELSE USE DEFAULT
	HRRZ	T3,FOPFLG	;GET ARGUMENT COUNT
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,12(M)		;POINT AT BUFFER SIZE WORD
	CAIL	T3,13		;SIZE WORD SPECIFIED?
	PUSHJ	P,GETWDU##	;YES, GET SIZE
	CAIGE	T3,13		;SIZE WORD SPECIFIED?
	TDZA	U,U		;NO, USE DEFAULT BUFFER SIZE
	HLRZ	U,T1		;YES, USE USER SUPPLIED BUFFER SIZE
	CAIGE	T3,12		;BUFFER STARTING ADDRESS SPECIFIED?
	JRST	FOPENA		;NO, DO NORMAL OUTBUF
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,11(M)		;POINT AT BUFFER STARTING ADDRESS
	PUSHJ	P,GETWDU##	;GET BUFFER STARTING ADDRESS
	HLRZS	T1		;OUTPUT BUFFER STARTING ADDRESS
	JUMPE	T1,FOPENA	;IF ZERO, SETUP THE BUFFERS AT JOBFF
	HRR	M,T2		;NUMBER OF BUFFERS
	PUSHJ	P,FOUTBF	;SET UP OUTPUT RING STARTING AT (T1)
	JRST	FOPEN1		;CHECK FOR INPUT BUFFERS
FOPENA:	SKIPN	T1,FOPEXT
	MOVE	T1,.JDAT+JOBFF##
	MOVEM	T1,.JDAT+JOBFF##
	MOVEM	T1,.USFOP
	HRR	M,T2		;PUT IN M
	PUSHJ	P,UOUTBS	;DO THE OUTBUF
FOPEN1:	HRRE	T2,FOPTMP	;GET THE NUMBER OF INPUT
				; BUFFERS REQUESTED
	JUMPE	T2,FOPEN2	;JUMP IF NONE REQUESTED
	SKIPG	T2		;SKIP IF NUMBER GIVEN
	MOVEI	T2,0		;ELSE USE DEFAULT
	HRRZ	T3,FOPFLG	;GET ARGUMENT COUNT
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,12(M)		;POINT AT BUFFER SIZE WORD
	CAIL	T3,13		;SIZE WORD SPECIFIED?
	PUSHJ	P,GETWDU##	;YES, GET SIZE
	CAIGE	T3,13		;SIZE WORD SPECIFIED?
	TDZA	U,U		;NO, USE DEFAULT BUFFER SIZE
	HRRZ	U,T1		;YES, USE USER SUPPLIED BUFFER SIZE
	CAIGE	T3,12		;BUFFER STARTING ADDRESS SPECIFIED?
	JRST	FOPENB		;NO, DO NORMAL INBUF
	HRR	M,FOPAP		;GET ARGUMENT POINTER
	HRRI	M,11(M)		;POINT AT BUFFER STARTING ADDRESS
	PUSHJ	P,GETWDU##	;GET BUFFER STARTING ADDRESS
	HRRZS	T1		;INPUT BUFFER STARTING ADDRESS
	JUMPE	T1,FOPENB	;IF ZERO, SETUP BUFFERS AT JOBFF
	HRR	M,T2		;NUMBER OF BUFFERS
	PUSHJ	P,FINBF		;SET UP INPUT RING STARTING AT (T1)
	JRST	FOPEN2		;CHECK FOR INPUT BUFFERS
FOPENB:	HRR	M,T2		;NUMBER OF BUFFERS
	PUSHJ	P,UINBS		;BUILD BUFFERS
;HERE TO DO LOOKUP AND/OR ENTER
FOPEN2:	HRRZ	T1,FOPFLG	;GET # OF ARGUMENTS
	CAIN	T1,5		;DONE YET?
	JRST	FOPFSP		;YES--SEE IF RETURNED FILESPEC WANTED
	MOVE	P2,FOPFLG	;FLAGS
	MOVE	T1,DEVIOS(F)	;DEVICE STATUS
	LDB	T1,PIOMOD##	;I/O MODE
	TLNE	P2,FOP.AP	;APPENDING?
	CAIL	T1,SD		;AND BUFFERED MODE?
	JRST	FOPN2A		;NO TO EITHER
	MOVE	T1,DEVMOD(F)	;DEVICE CHARACTERISTICS
	TLNN	T1,DVTTY	;NUL:?
	TLNN	T1,DVDSK	;MAKE SURE ITS REALLY A DSK
	JRST	FOPN2A		;SKIP THIS IF NOT A REAL DISK
	HLRZ	U,DEVBUF(F)	;POINTER TO OUTPUT BUFFER HEADER	
	PUSHJ	P,OUTF		;MAKE SURE CAN'T PAGE FAULT AFTER LOOKUP/ENTER
FOPN2A:	HLLZ	T1,FOPFLG	;GET CONTROL FLAGS BACK
	MOVSI	T2,(UP.FIP)     ;FILOP IN PROGRESS
	TLNN	T1,FOP.PV	;WANT TO USE OUR PRIVS?
	TLO	T2,(UP.IYB)	;NO, THEN LIE ABOUT JACCT
	IORM	T2,.USBTS	;FOR ACCESSOR'S IPCF CAPABILITIES
	TLNE	T1,FOP.RN!FOP.DL;IF A RENAME OR DELETE FUNCTION
	TLNN	T1,FOP.OC	;ON AN ALREADY-OPENED CHANNEL
	CAIA			; (IT ISN'T)
	JRST	FOPEN8		;JUST DO THE RENAME/DELETE
	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
	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
	HRLM	T2,FOPBLK	;SAVE COUNT
	MOVEI	T3,UUNEXT-UUNNAM(M) ;WHERE TO FIND EXTENSION
	HRLZM	T3,FOPEXT	;REMEMBER FOR LATER
	MOVE	P2,FOPFLG	;GET FLAGS
	MOVSI	T1,DEPFOP	;WANT TO SET "FILOP. IN PROGRESS BIT"
	TLNN	P2,FOP.PV	;DOES HE WANT FULL FILE ACCESS
	TLO	T1,DEPFFA	;NO--MAKE SURE HE DOES NOT GET IT
	IORM	T1,DEVJOB(F)	;TURN ON BITS IN DDB
	MOVEI	T1,DEPECS	;NON-SUPERSEDING ENTER
	ANDCAM	T1,DEVSTA(F)	;CLEAR TO START WITH
	TLNE	P2,FOP.NS	;WANT TO SUPERSEDE?
	IORM	T1,DEVSTA(F)	;NO--TELL FNDFIL SUPERSEDE IS ILLEGAL
	PUSHJ	P,FOPIYB	;STORE IN-YOUR-BEHALF PPN IF NEEDED
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
	TRZ	T1,RB.BIT
	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
	HLRZ	T1,FOPBLK	;GET FLAG BITS
	ANDI	T1,RB.BIT
	IORI	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
	MOVE	T2,T1
	TRZ	T2,RB.BIT
	CAIL	T2,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##	;..
	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
	JUMPE	T1,FOPN8B	;RENAME TO ZERO (DELETE) IS A SHORT BLOCK
	TLNN	T1,-1		;EXTENDED BLOCK
	HRRI	M,UUXNAM(M)	;YES, POINT AT THE FILE NAME
FOPN8B:	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
	MOVSI	T1,DEPALW	;ALLOCATION-IN-WORDS FLAG
	TLNE	P2,FOP.AW	;IS HE DOING IT?
	IORM	T1,DEVJOB(F)	;YES, TELL FILSER
	MOVEI	T1,UUNEXT-UUNNAM(M) ;WHERE THE EXTENSION IS STORED
	HRLZM	T1,FOPEXT	;SAVE THAT IN CASE OF AN ERROR
	MOVE	T2,DEVMOD(F)	;DEVICE CHARACTERISTICS
	TLNN	T2,DVLNG	;LONG DISPATCH VECTOR?
	JRST	FOPN8A		;NO, DON'T ATTEMPT A RENAME
	PUSHJ	P,FOPIYB	;STORE IN-YOUR-BEHALF PPN IF NEEDED
	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
	MOVE	T1,DEVMOD(F)	;DEVICE CHARACTERISTICS
	TLNN	T1,DVTTY	;AVOID NUL:

	TLNN	T1,DVDSK	;ONLY DISKS HAVE PATHS
	  JRST	FOPEN9		;NOT A DISK, SO DON'T DO THE PATH
	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
	HLRZS	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,FLMCOM	;SO FILUUO DOESN'T CLOBBER USER'S AC
	PUSHJ	P,PTHUUO##	;DO THE PATH UUO
	  JFCL			;SHOULD NEVER FAIL
	TLZ	M,FLMCOM
	HRLM	P1,.USCTA	;RESET IO CHAN
	PUSHJ	P,SETUF		;F GOT WIPED
	  JRST	FOPXI1		;CAN'T HAPPEN
FOPEN9:	MOVE	P2,FOPFLG	;GET FLAGS
	TLZN	P2,FOP.NF	;CREATING INSTEAD OF UPDATING
	JRST	FOPN9A		;NO--CONTINUE
	MOVEM	P2,FOPFLG	;YES--CLEAR FLAG
	MOVSI	T1,DEPFFA	;FORCE FILE INTO
	IORM	T1,DEVJOB(F)	; UPDATE MODE
	HRRI	M,CLSDLL	;DON'T DEALLOCATE
	PUSHJ	P,CLOSE1	; ..
	PUSHJ	P,WAIT1##	; ..
	TLNE	F,OCLOSB	;DID THE CLOSE REALLY HAPPEN?
	JRST	FOPN3A		;YES, MUST BE SFD, LET FILSER GIVE HIM ERROR
FOPN9A:	SKIPE	P2,FOPFLG	;GET FLAGS
	TLNN	P2,FOP.AP	;WANT TO APPEND?
	JRST	FOPFSP		;NO--SEE IF RETURNED FILESPEC WANTED
	MOVE	T1,DEVMOD(F)	;IS THIS A DISK
	TLNE	T1,DVTTY	;NUL:?
	JRST	FOPFSP		;YES--SEE IF RETURNED FILESPEC WANTED
	TLNN	T1,DVDSK	; ..
	JRST	FOPN11		;NO, ALL DONE UNLESS AN MTA
	MOVEI	T1,UP.MLB	;MERGE LAST BLOCK
	IORM	T1,.USBTS	; IF WE CAN

;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
	JUMPE	T1,FOPN10	;DON'T TRY TO MERGE IF NEW FILE
	MOVEM	T1,FOPTMP	;SAVE BLK #
	HLRZ	U,DEVBUF(F)	;GET RING ADR
	MOVE	T1,FOPFLG	;GET THE FLAGS
	HRR	T1,.USBTS	;AND RELEVANT UPT BITS FOR TESTING
	TLNE	T1,FOP.AP	;IF THIS IS APPEND,
	TRNN	T1,UP.MLB	;ONLY DO THIS IF FOPEN2 DIDN'T
	PUSHJ	P,OUTF		;UNVIRGINIZE HEADER - ZERO BUFFER
	MOVE	T1,FOPTMP	;RESTORE BLK #
	HRRZ	T3,DEVACC##(F)	;ADDRESS OF A.T. AGAIN
	MOVEI	T2,UP.MLB	;MERGE LAST BLOCK FLAG
	TDNN	T2,.USBTS	;SHOULD WE?
	JRST	FOPN10		;NO - DON'T READ IN LAST BLOCK
	ANDCAM	T2,.USBTS	;YES - CLEAR THE FLAG AND CONTINUE
	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(FOPTMP) INTO BUFFER AT C(T3)
	MOVEM	T2,FOPBLK	;SAVE WORD COUNT
	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
IFN FTXMON,<
	SETZ	T2,		;NO PARTIAL SECTION UPDATES FROM MAPIO
	DPB	T2,DEYISN##	;SAVE IN CASE CHECKSUM NEEDED
>
	MOVE	W,FOPTMP	;BLOCK #
	PUSHJ	P,USETO0##	;SETUP POINTERS
	MOVEM	S,FOPTMP	;SAVE STATUS
	TRO	S,D		;SET DUMP MODE
	TLZ	S,IO		;READING
	PUSHJ	P,UUOSET##	;MAKE EVERYTHING OK
	JRST	FCLOSI		;RETURN IOIMPM
	PUSHJ	P,UUOPWR##	;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
	HLRZ	U,DEVBUF(F)	;RING HEADER
	HRRZ	T2,DEVOAD(F)	;FOR BYTE POINTER
	EXCTUX	<HLRZ	J,(T2)>	;BUFFER SIZE
	TRZ	J,400177	;CLEAR EXTRANEOUS BITS
	SUB	J,FOPBLK	;MINUS WORDS WE READ
	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,USETO0##	;SET POINTERS
	JRST	FOPFSP		;SEE IF RETURNED FILESPEC WANTED
FOPN11:	TLNN	T1,DVMTA	;MAGTAPE?
	JRST	FOPFSP		;NO--SEE IF RETURNED FILESPEC WANTED
	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	FOPFSP		; DONE--SEE IF RETURNED FILESPEC WANTED
	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
	MOVE	T3,DEVSER(F)	;DISPATCH ADDRESS
	PUSHJ	P,DIN(T3)	;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	FOPN13		;WIN, CONTINUE ONWARD
FOPN12:	PUSHJ	P,BUFCLR	;ZERO THE BUFFER
	  JFCL			;SHOULD NEVER HAPPEN
FOPN13:
IFN FTTLAB,<
	MOVE	U,TDVUDB##(F)	;UDB ADDRESS
	LDB	T1,TUYLTP##	;GET LABEL TYPE
	SKIPE	T1		;BYPASS?
	SKIPN	%SITLP##	;LABLE PROCESSOR?
	JRST	FOPFSP		;NO--SEE IF RETURNED FILESPEC WANTED
	MOVEI	T1,LR.CLI	;SEND INPUT CLOSE
	PUSHJ	P,TPCLSX##	;MSG TO MDA
>
	JRST	FOPFSP		;DONE--SEE IF RETURNED FILESPEC WANTED

DOMTAP:	PUSHJ	P,MTAPE0##	;TEL TAPUUO WHAT TO DO
	PUSHJ	P,TPSKPW##	;WAIT,  THEN CONTINUE
	TRNN	S,IODERR!IODTER!IOIMPM
	AOSA	(P)		;WON
	HRRZ	T1,S		;LOST, RETURN ERROR STATUS BITS
	POPJ	P,		;RETURN TO CALLER
;HERE TO DO A USETI AND RETURN STATUS
FUSTI:	SKIPA	W,[DSI]		;DISPATCH TO USETI
;HERE TO DO A USETO AND RETURN STATUS
FUSTO:	MOVEI	W,DSO		;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
	MOVE	T4,DEVMOD(F)	;GET DEVICE CHARACTERISTICS
	TLNE	T4,DVDSK	;IF DISK,
	TLNE	F,ENTRB!LOOKB	;AND NO ENTER OR LOOKUP,M=ADDR OF BLK#
	HRR	M,W		;(NO) SETUP M WITH BLOCK#
	TLNN	T4,DVLNG	;LONG DISPATCH TABLE?
	JRST	FOPFSP		;NO, DON'T DISPATCH (NO-OP)
IFN FTMP,<
	PUSHJ	P,SETCPF##	;GET ON RIGHT CPU
>
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,WAIT2		;WAIT FOR I/O
	MOVE	T1,(P)		;GET DISPATCH OFFSET BACK
	CAIN	T1,DSO		;USETO?
	SKIPA	T1,[IOERR]	;YES--ONLY CHECK REAL I/O ERROS
	MOVEI	T1,IOERR+IODEND	;ELSE CHECK I/O ERRORS PLUS EOF
	EXCH	T1,(P)		;SAVE CONDITIONS TO CHECK,GET DISPATCH OFFSET
	ADD	T1,DEVSER(F)	;DISPATCH TABLE ADDR
	PUSHJ	P,(T1)		;CALL USET CODE
	HRRZ	T1,DEVIOS(F)	;I/O STATUS
	TDNN	T1,(P)		;ERRORS OR END OF FILE?
	AOS	-1(P)		;NO, SKIP RETURN TO THE USER
	POP	P,(P)		;TRIM STACK
	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
	HRRI	M,CLSDLL	;DON'T DEALLOCATE
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
	TLNN	T1,DVTTY	;GOOD RETURN IF NUL

	TLNN	T1,DVDSK	;DISK?
	JRST	FOPFSP		;NO--SEE IF RETURNED FILESPEC WANTED
	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	T2,WAIT		;WAIT
	JRST	FOPOU1
FOPXIN:	PUSHJ	P,FOPLM		;MAKE SURE ITS DUMP MODE AND IF SO, SET DEPSOO
FOPIN:	MOVEI	T2,TIN		;INPUT
	MOVEI	T3,DSI		;USETI
	JRST	FOPOU3
FOPXOU:	PUSHJ	P,FOPLM		;MAKE SURE ITS DUMP MODE AND IF SO, SET DEPSSO
FOPOUT:	MOVEI	T2,TOUT		;OUTPUT
	MOVEI	T3,DSO		;USETO
FOPOU3: ADD	T3,DEVSER(F)	;DISPATCH TABLE
	HRRZ	T1,FOPFLG
	MOVE	T4,DEVMOD(F)
	CAIG	T1,2		;MORE THAN 2 ARGUMENTS?
	JRST	FOPOU2		;NO, SKIP USETI/USETO CODE
	PUSH	P,M		;SAVE CURRENT ARGUMENT POINTER
	HRRI	M,2(M)		;GET THE THIRD ARGUMENT
	PUSHJ	P,GETWDU##	;GET THE BLOCK NUMBER ADDRESS
	JUMPE	T1,FOPOU5	;IF ADDRESS=0, THEN NO USETI/O
	HRR	M,T1		;POINT TO THE ADDRESS
	PUSHJ	P,GETWDU##	;READ THE ACTUAL BLOCK NUMBER
	PUSH	P,W		;SAVE W
	MOVE	W,T1		;PUT IT IN W
	PUSH	P,T2		;SAVE ADDRESS OF I/O ROUTINE
	TLNN	T4,DVLNG	;LONG DISPATCH TABLE?
	JRST	FOPOU4		;NO, DON'T DISPATCH (NO-OP)
IFN FTMP,<
	PUSHJ	P,SETCPF##	;GET ON RIGHT CPU
>
	PUSH	P,T3		;SAVE T3
	PUSHJ	P,WAIT2		;WAIT FOR I/O
	POP	P,T3		;RESTORE T3
	PUSHJ	P,(T3)		;CALL USETI/USETO
FOPOU4:	POP	P,T2		;RESTORE ADDRESS OF I/O ROUTINE
	POP	P,W		;RESTORE W
FOPOU5:	POP	P,M		;RESTORE ARGUMENT POINTER
	HRRZ	T1,FOPFLG
FOPOU2:	CAIG	T1,1		;MORE THAN 1 ARGUMENT?
	TDZA	T1,T1		;NO, NO BUFFER ADDRESS
	PUSHJ	P,GETWD1##	;YES, GET THE BUFFER ADDRESS
	HRR	M,T1
IFN FTXMON,<
	SKIPGE	DEVISN(F)	;MULTI-SECTION I/O?
	DPB	T1,[POINT 23,M,35] ;YES, THEN ALLOW IOWD LIST TO START IN ANY SECTION
>
	HRRZ	T4,DEVSER(F)
FOPOU1:	PUSHJ	P,(T2)		;DO THE IN, OUT, OR WAIT
	  AOS	(P)		;GOOD RETURN
	MOVSI	T1,DEPSOO	;MULTI-SECTION I/O BIT
	ANDCAM	T1,DEVISN(F)	;CLEAR THAT ALWAYS
	HRRZ	T1,S		;DEVICE STATUS
	PJRST	STOTAC##	;RETURN THAT FOR THE USER

FOPLM:	LDB	T1,PIOMOD##	;GET I/O MODE
	CAIGE	T1,SD		;ONLY DUMP MODE IS LEGAL
	JRST	[POP P,(P)	;POP OFF CALLER'S RETURN ADDRESS
		 MOVEI T1,IDMERR;ILLEGAL DATA MODE ERROR CODE
		 JRST STOTAC##]	;RETURN THAT TO THE USER
	MOVSI	T1,DEPSOO	;OK FOR IOWDS TO CROSS SECTION BOUNDARIES
	IORM	T1,DEVISN(F)	;LITE THAT FOR V2PADR
	POPJ	P,		;RETURN


FOPLP:	AOS	-1(P)		;FILOP. WILL SKIP
	MOVE	T1,DEVMOD(F)	;MUST HAVE LONG DISPATCH TABLE
	TLNN	T1,DVLNG
	JRST	TPOPJ##		;ELSE FILOP. EXITS IMMEDIATELY
	MOVE	T4,DEVSER(F)	;GET ADDR OF DISPATCH TABLE
	POPJ	P,

FOPRRC:	AOS	(P)
	PJRST	FWRBIC##	;YES, REWRITE RIB IF CHANGED
; RETURN THE FILESPEC ASSOCIATED WITH A CHANNEL
; POSSIBLE ERRORS ARE:
;	ADDRESS CHECK READING ARGUMENTS
;	ADDRESS CHECK STORING ANSWER
;	NEGATIVE OR ZERO ARGUMENT COUNT
;	ARGUMENT LIST TOO SHORT
;
FOPFIL:	PUSHJ	P,FOPFI0	;GET THE FILESPEC
	  PJRST	FOPXIT		;FAILED--PROPAGATE ERROR BACK
	JRST	CPOPJ1##	;RETURN


FOPFI0:	PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVE	P1,DEVMOD(F)	;GET DEVICE TYPE BITS
	PUSHJ	P,GETWR1##	;GET THE WORD COUNT AND ARGUMENT BLOCK ADDRESS
	  JRST	FOPF63		;ADDRESS CHECK READING ARGUMENTS
	HLRE	P2,T1		;COPY WORD COUNT
	JUMPLE	P2,FOPF65	;NEGATIVE OR ZERO ARGUMENT COUNT?
	HRRI	M,-1(T1)	;POINT TO THE ARGUMENT BLOCK


; NODE NAME
REPEAT 0,< ;NODE NAME RESERVED FOR NOW
IFE FTNET,<MOVEI T1,0>		;CLEAR NODE NAME IF NO NETWORKS
IFN FTNET,<
	PUSHJ	P,FNDDEV	;GET STATION NUMBER
	SKIPN	T1		;USE IT IF NON ZERO
	MOVE	T1,JBTLOC##	; OTHERWISE USE CENTRAL SITE NUMBER
	SKIPN	DEVCHR(F)	;A SPOOLED DDB?
	HRRZ	T1,JBTLOC##(J)	;YES--USE JOB'S LOCATION
	NETDBL			;GET THE NETSER INTERLOCK
	PUSHJ	P,SRCNDB##	;FIND THE NODE BLOCK
	  TDZA	T1,T1		;CAN'T, SO RETURN ZERO
	HLRZ	T1,NDBSNM##(W)	;GET THE ADDRESS OF THE NODE NAME
	MOVE	T1,(T1)		;GET THE SIXBIT NODE NAME
	NETDBU			;RELEASE THE NETSER INTERLOCK
>;END IFN FTNET
> ;END REPEAT 0
	MOVEI	T1,0		;NODE NAME RESERVED FOR NOW
	PUSHJ	P,FOPFIX	;STORE THE NODE NAME
; DEVICE
	MOVE	T1,DEVNAM(F)	;GET DEVICE NAME
	TLNN	P1,DVDSK	;A DISK?
	JRST	FOPFI1		;NO--GO CLEAN UP DEVICE NAME
	HRRZ	T2,DEVUNI##(F)	;UDB POINTER
	JUMPE	T2,FOPFI2	;NO UNIT IF A KNOWN SEGMENT
	MOVE	T1,UDBNAM(T2)	;MAYBE JUST OPENED A UNIT
	SKIPN	UNILOG(T2)	;BETTER CHECK
	JRST	FOPFI2		;NOT PART OF A STRUCTURE
	HRRZ	T2,DEVACC##(F)	;GET ACCESS TABLE ADDRESS
	JUMPE	T2,FOPFI2	;MAY BE ZERO (SUPER I/O)
	LDB	T2,ACYFSN##	;GET STRUCTURE NUMBER
	MOVE	T1,@TABSTR##(T2);FINALLY GET STRUCTURE NAME
	JRST	FOPFI2		;SKIP NETWORK STUFF
FOPFI1:
REPEAT 0,< ;DON'T ASSEMBLE IF NODE NAME RESERVED FOR FUTURE
	TLNE	P1,DVTTY	;A TTY?
	JRST	FOPFI2		;YES--DON'T MESS WITH THE NAME
	LSHC	T1,-6		;SHIFT UNIT NUMBER INTO T2
	LSH	T1,-^D12	;SHIFT OUT STATION NUMBER
	LSHC	T1,^D18		;LEFT JUSTIFY DEVICE AND UNIT IN T1
> ;END REPEAT 0
FOPFI2:	PUSHJ	P,FOPFIX	;STORE THE DEVICE NAME
; FILE NAME AND EXTENSION
	TLNN	P1,DVDIR	;A DIRECTORY DEVICE?
	JRST	FOPFI6		;NO--FINISH UP
	MOVE	T1,DEVFIL(F)	;GET FILE NAME
	PUSHJ	P,FOPFIX	;STORE IT
	HLLZ	T1,DEVEXT(F)	;GET EXTENSION
	PUSHJ	P,FOPFIX	;STORE IT

; DIRECTORY
	TLNN	P1,DVDSK	;CAN ONLY BE A DISK
	JRST	FOPFI6		;ALL OTHERS DON'T HAVE A DIRECTORY
	MOVE	T1,DEVPPN(F)	;GET THE PPN
	PUSHJ	P,FOPFIX	;STORE IT

	HRRZ	P1,DEVSFD##(F)	;GET PATH POINTER
	JUMPE	P1,FOPFI6	;THERE ISN'T ONE
	PUSH	P,[0]		;MARK THE END OF THE PATH
FOPFI3:	PUSH	P,NMBNAM##(P1)	;SAVE THE SFD NAME
FOPFI4:	HLRZ	P1,NMBPPB##(P1)	;BACK ONE LEVEL
	TRZN	P1,NMPUPT##	;NAME SHOULD BE OUTPUT?
	JUMPN	P1,FOPFI4	;NO, GET NEXT LEVEL IF NOT AT END
	JUMPN	P1,FOPFI3	;YES, SAVE NAME AND GET NEXT LEVEL
FOPFI5:	POP	P,T1		;GET AN SFD NAME
	JUMPE	T1,FOPFI6	;END OF PATH--FINISH UP
	PUSHJ	P,FOPFIX	;STORE IN THE USER'S BLOCK
	JRST	FOPFI5		;LOOP OVER WHOLE PATH
; TERMINATE THE LIST WITH A NULL WORD
FOPFI6:	MOVEI	T1,0		;GET A ZERO
	PUSHJ	P,FOPFIX	;TERMINATE THE BLOCK
	JRST	CPOPJ1##	;AND RETURN


; STORE A WORD IN THE USER'S ARGUMENT BLOCK
FOPFIX:	SOJL	P2,FOPF66	;ARGUMENT LIST TOO SHORT?
	PUSHJ	P,PUTWR1##	;STORE THE WORD
	  JRST	FOPF64		;ADDRESS CHECK STORING ARGUMENTS
	POPJ	P,		;RETURN


; ERROR RETURNS
FOPF63:	MOVEI	T1,ACRERR	;ADDRESS CHECK READING ARGUMENTS
	POPJ	P,		;RETURN

FOPF64:	MOVEI	T1,ACSERR	;ADDRESS CHECK STORING ANSWER
	POP	P,(P)		;PRUNE STACK
	POPJ	P,		;RETURN

FOPF65:	MOVEI	T1,NZAERR	;NEGATIVE OR ZERO ARGUMENT COUNT
	POPJ	P,		;RETURN

FOPF66:	MOVEI	T1,ATSERR	;ARGUMENT BLOCK TOO SHORT
	POP	P,(P)		;PRUNE STACK
	POPJ	P,		;RETURN
;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,.USCTA	;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,.USCTA	;NO
	ADDI	T1,-20(T2)	;ADDRESS OF EXTENDED CHANNEL
	POPJ	P,		;RETURN
;FILOP. EXIT ROUTINES
FOPFSP:	HRRZ	T1,FOPFLG	;GET ARG BLOCK LENGTH
	CAIGE	T1,11		;INCLUDED A POINTER TO A FILESPEC BLOCK?
	JRST	FOPWIN		;NO--FINISH UP
	PUSHJ	P,GETTAC##	;LOAD T1 WITH USER'S AC
	HRRI	M,7(T1)		;POINT TO FILESPEC POINTER -1
	PUSHJ	P,FOPFI0	;RETURN FILESPEC ASSOCIATED WITH THE CHANNEL
	  JFCL			;IGNORE THE FACT THAT THE BLOCK MIGHT BE TOO
				; SHORT, BECAUSE WE CAN'T RETURN AN ERROR AT
				; THIS POINT.

FOPWIN:	MOVNI	T1,1		;INDICATE SUCCESS
	JRST	FOPXIT		;STANDARD EXIT

;ILLEGAL UUO
FOPILU:	MOVEI	T1,ILUERR	;ERROR CODE
	JRST	FOPXIT		;EXIT UUO

FOPE46:	MOVEI	T1,CNOERR	;CHANNEL-NOT-OPEN ERROR
	JRST	FOPXI1		;ERROR RETURN TO USER

FOPE56:	MOVEI	T1,NPCERR	;NO-PER-PROCESS-SPACE ERROR
	JRST	FOPXI1		;ERROR RETURN TO USER

FOPE57:	MOVEI	T1,NFCERR	;NO-FREE-CHANNEL ERROR
	JRST	FOPXI1		;ERROR RETURN TO USER

FOPE60:	MOVEI	T1,UFFERR	;UNKNOWN-FILOP.-FUNCTION ERROR
	JRST	FOPXI1		;ERROR RETURN TO USER

FOPE61:	MOVEI	T1,CTBERR	;CHANNEL-TOO-BIG ERROR
	JRST	FOPXI1		;ERROR RETURN TO USER

FOPE62:	MOVEI	T1,CIFERR	;CHANNEL-ILLEGAL ERROR
	JRST	FOPXI1		;ERROR RETURN TO USER

FOPE63:	MOVEI	T1,ACRERR	;ADDRESS CHECK READING ARGUMENTS
	JRST	FOPXIT		;ERROR RETURN TO USER

FOPE64:	MOVEI	T1,ACSERR	;ADDRESS CHECK STORING ANSWER
	JRST	FOPXIT		;ERROR RETURN TO USER

FOPE65:	MOVEI	T1,NZAERR	;NEGATIVE OR ZERO ARGUMENT COUNT
	JRST	FOPXIT		;ERROR RETURN TO USER

FOPE66:	MOVEI	T1,ATSERR	;ARGUMENT BLOCK TOO SHORT
	JRST	FOPXIT		;ERROR RETURN TO USER


;OPEN ERROR
FOPOER:	HRRZ	T1,T4		;POSITION ERROR CODE FROM UOPEN
	JRST	FOPXI1		;AND GIVE ERROR RETURN TO USER
;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:	JUMPE	F,FOPXI1
	MOVSI	T2,DEPFOP!DEPFFA!DEPALW ;MUST CLEAR THESE OR DDB
				; CAUSE PROBLEMS ON NEXT UUO
	ANDCAM	T2,DEVJOB(F)	;ZAP!
	MOVE	T2,DEVMOD(F)
FOPXI1:	SETZM	.USFOP		;FILOP. IS DONE
	MOVSI	T2,(UP.IYB!UP.FIP) ;IN YOUR BEHALF
	ANDCAM	T2,.USBTS	;CLEAR THAT
REPEAT 0,<			;NOT A REAL GOOD IDEA RIGHT NOW
	MOVE	T2,FOPFLG	;GET FLAGS BACK
	TLNE	T2,FOP.OC	;DID WE USE AN OPEN CHANNEL?
	JRST	FOPXI2		;YES, NOTHING ELSE TO DO
	JUMPE	F,FOPXI2	;DITTO IF NO DDB
	TLNN	T2,FOP.RN!FOP.DL ;RENAME OR DELETE?
	JUMPL	T1,FOPXI2	;NO, ONLY CLOSE (MAYBE) IF ERRORS
	HRR	M,FOPAP		;GET ADDRESS OF BLOCK
	PUSH	P,T1		;SAVE RETURN STATUS
	PUSHJ	P,GTWST2##	;GET FIRST WORD
	HRRZ	T1,FOPTAB(T1)	;GET DISPATCH ADDRESS
	TLNN	T2,FOP.RN!FOP.DL ;RENAME OR DELETE?
	CAIN	T1,FOPEN	;NO, WAS THIS AN OPEN FUNCTION?
	PUSHJ	P,URELEA	;YES, RELEASE THE CHANNEL
	POP	P,T1		;RESTORE RETURN STATUS
>; END REPEAT 0
FOPXI2:	JUMPL	T1,CPOPJ1##	;ALL DONE IF NO ERRORS
	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,GETWRD##	;GET FIRST WORD OF BLOCK
	  POPJ	P,		;ADDRESS CHECK
	MOVEI	T4,UUNPPN	;OFFSET TO PPN/PATH POINTER IN SHORT BLOCK
	SKIPE	T2,T1		;COPY WORD COUNT WORD
	TLNE	T2,-1		;EXTENDED UUO?
	JRST	FCLER1		;ZERO WORD IS SHORT BLOCK
	MOVEI	T4,UUXPPN	;OFFSET TO PPN/PATH POINTER IN EXTENDED BLOCK
	TRZA	T2,RB.BIT	;CLEAR OLD STYLE BIT
FCLER1:	MOVEI	T2,3		;4 WORDS
	CAIL	T2,(T4)		;ROOM ENOUGH FOR A PATH?
	SKIPN	T1		;OR DOING A DELETE?
	SETZ	T4,		;NO OR YES, DON'T CHECK PATH BLOCK
	AOS	T2		;LENGTH DIDN'T INCLUDE .RBCNT
	HRRZ	T1,M		;START ADDRESS
	HRLI	T1,(IFIW)	;MAKE SECTION RELATIVE
	PUSHJ	P,ARNGE##	;RANGE CHECK
	  POPJ	P,		;ADDRESS CHECK
	  JFCL			;ADDRESS OK BUT ILLEGAL FOR I/O (IGNORED HERE)
	JUMPE	T4,CPOPJ1##	;ALL DONE IF NO PATH POINTER
	PUSH	P,M		;SAVE M
	ADDI	M,(T4)		;OFFSET TO PPN/PATH POINTER
	PUSHJ	P,GETWRD##	;GET IT
	  JRST	MPOPJ##		;ADDRESS CHECK
	JUMPE	T1,MPOPJ1##	;RETURN IF NOT A PATH POINTER
	TLNE	T1,-1		;DITTO
	JRST	MPOPJ1##	;ALL DONE
	HRRI	M,1(T1)		;POINT AT PPN WORD-1 IN PATH BLOCK
	MOVE	T2,SFDLVL##	;MAXIMUM SFD NESTING
FCLER2:	PUSHJ	P,GETWR1##	;GET NEXT WORD OF BLOCK
	  JRST	MPOPJ##		;ADDRESS CHECK
	JUMPE	T1,MPOPJ1##	;DONE IF HIT A ZERO WORD
	SOJGE	T2,FCLER2	;KEEP LOOKING FOR A ZERO WORD
	JRST	MPOPJ1##	;SFD LEVEL EXHAUSTED, RETURN


;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	FOPTS2		;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
FOPTS2:	TLNN	T1,DVOUT	;IS IT OUTPUT?
	 JRST	FOPTS1		;NO, DON'T CHECK DEVSPL
	SKIPGE	DEVSPL(F)	;IF SPOOLED OUTPUT,
	 JRST	CPOPJ1##	;  THEN DO THE ENTER
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:	TDNN	T1,DEVJOB(F)	;IF NOT UPDATE RIB
	JRST	CLOSE1		; CAN'T KEEP ENQ LOCKS
	MOVEI	T1,UP.MLB	;FOP.UR FUNCTION IN PROGRESS
	ANDCAM	T1,.USBTS	; SO ASSUME NO OUTPUT WILL BE REQUIRED.
	JRST	CLOSE2		;CHECKPOINTING, ALLOWED TO KEEP ENQ LOCKS
CLOSE1::
	PUSHJ	P,ENQCLS##	;CHECK FOR LOCKS STILL OUT
	  SKIPA			;THERE WERE SOME
	JRST	CLOSE2		;THERE WERE NO LOCKS
NQABRT:	MOVEI	T4,IOBKTL	;SET ERROR BIT...
	IORM	T4,DEVIOS(F)	;... IN DEVIOS
	POPJ	P,		;ABORT UUO
CLOSE2:	LDB	T4,PJCHN##	;GET JCH FOR THIS DDB
	CAME	T4,.CPJCH##	;SAME AS EXECUTING JOB?
	POPJ	P,		;DON'T TOUCH
IFN FTMP,<PUSHJ	P,SETCPF##>	;GET JOB ON THE RIGHT CPU TO DO FILE OPERATION
	SETZM	.USFOP
	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,[PUSHJ P,SSPCS## ;DCLI ROUTINE MAY CHANGE PCS
		   JRST  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,[PUSHJ P,SSPCS## ;SAVE PCS IN CASE ROUTINE CHANGES IT
		   JRST  DCLI(T4)] ;AND CLOSE INPUT SIDE
	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	UCLS8		;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,[PUSHJ P,SSPCS## ;ROUTINE MAY CHANGE PCS
		   JRST  DCL(T4)]  ;SO SAVE FOR IT
	JRST	UCLS8
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
	MOVE	T4,DEVSER(F)
	MOVEI	T1,DEPAIO!DEPOND
	PUSH	P,DEVAIO(F)	;SAVE STATUS FOR LATER USE.
	ANDCAM	T1,DEVAIO(F)	;DON'T ALLOW NON-BLOCKING I/O DURING CLOSE
	PUSHJ	P,[PUSHJ P,SSPCS## ;ROUTINE MAY CHANGE PCS
		   JRST  DCL(T4)]  ;SO SAVE IT
	POP	P,T1		;RETRIEVE OLD STATUS.
	ANDI	T1,DEPAIO	;SET NON BLOCKING BIT IN T1.
	IORM	T1,DEVAIO(F)	;RESET, IF IT WAS SET.
	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
UCLS8:	MOVSI	T2,DVDSK	;GET DISK BIT
	TDNE	T2,DEVMOD(F)	;IS THIS A DISK?
	SETZM	DEVUPP##(F)	;CLEAR IN-YOUR-BEHALF PPN
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	UCLS8		;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.



FINBF:	MOVEI	T3,BUFCLF	;SETUP RING FILOP STYLE
	JRST	UINBF1		;JOIN COMMON CODE
UINBF::	MOVEI	U,0		;USE DEFAULT BUFFER SIZE
UINBS:	PUSHJ	P,BUFNZS	;CHECK FOR NON-ZERO SECTION, DON'T RETURN IF SO
	MOVEI	T3,BUFCLC	;SETUP BUFFER AT JOBFF
UINBF1:	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,(T3)		;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

FOUTBF:	MOVEI	T3,BUFCLF	;SETUP RING FILOP STYLE
	JRST	UOUTB1		;JOIN COMMON CODE
UOUTBF::MOVEI	U,0		;USE DEFAULT BUFFER SIZE
UOUTBS:	PUSHJ	P,BUFNZS	;CHECK FOR NON-ZERO SECTION, DON'T RETURN IF SO
	MOVEI	T3,BUFCLC	;SETUP BUFFER AT JOBFF
UOUTB1:	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,(T3)		;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 FTMPXSER,<
	LDB	T1,PDVTYP##	;GET DEVICE TYPE BYTE
	CAIN	T1,.TYMPX	;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

;SUBROUTINE TO CHECK IF INBUF/OUTBUF WAS DONE IN A NON-ZERO SECTION. I.E.,
; JOBFF IS MEANINGLESS. DOESN'T RETURN IF SO. USES ONLY T3

BUFNZS:	SE1ENT			;MUST BE IN SECTION 1
	XSFM	T3		;GET FLAGS AND PCS
	ANDI	T3,MXSECN	;ISOLATE PCS
	JUMPE	T3,CPOPJ##	;OK IF SECTION ZERO
	LSH	T3,P2WLSH	;PAGE ZERO IN SECTION
	MOVE	T3,@[IW MS.MAP,UMAPS(T3)] ;GET POINTER FOR PAGE ZERO OF SECTION
	CAME	T3,@[IW MS.MAP,UMAPS] ;SAME AS PAGE 0 IN SECTION 0?
	S0JRST	ILLBUF##	;NO, ILLEGAL INBUF/OUTBUF
	POPJ	P,		;OK RETURN
	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:
	MOVE	J,.CPJCH##	;GET CURRENT JOB'S JOB/CONTEXT HANDLE
	PUSHJ	P,ENQCLS##	;ANY LOCKS OUT?
	  JRST	UOPE33		;ERROR - ENQ LOCKS OUTSTANDING
	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)
	MOVE	J,.CPJOB##	;GET ONLY JOB # NOW
	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,URELEA	;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
	MOVSI	T2,(UP.FIP)	;FILOP. IN PROGRESS?
	TLNN	T1,-1		;OR LH NON-ZERO?
	TDNE	T2,.USBTS	;...
	JRST	UINIA1		;YES
	CAIGE	T1,1000		;LEGAL UDX FOR AN OPEN UUO?
	JRST	UOPE12		;NO, RETURN 'NO SUCH DEVICE' ERROR
UINIA1:	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 FTNET,<
	PUSHJ	P,DEVSRC	;SEARCH FOR DEVICE
>
	PUSHJ	P,DVSRSP	;DOES ANY DEV OF THIS TYPE EXIST?

	CAIA			;ERROR
	JRST	UINIT7		;FOUND IT, PLUNGE AHEAD
	PUSHJ	P,UDXDDB	;SEE IF A UDX WAS SUPPLIED
	  JRST UOPE12		;ERROR - NO SUCH DEVICE
	JRST	UINIT2		;FOUND UDX-CHARGE AHEAD
UINIT7:
	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
	MOVEI	T3,ASSPRG	;FLAG THAT INIT'ED DEV UNACCEPTABLE
	PUSH	P,F		;SAVE DDB LOC
	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	UOPE1D		;NO - LOSE
UINIT1:	POP	P,(P)		;YES - WIN
UINIT2:	MOVE	T2,JBTSTS##(J)	;IS THIS JOB
	TLNE	T2,JLOG		; LOGGED IN?
	JRST	UINI2A		;YES, CONTINUE
	LDB	T2,PDVTYP##	;GET DEVICE TYPE
	CAIE	T2,.TYDSK	;IS IT A DISK?
	CAIN	T2,.TYTTY	;OR A TERMINAL
	JRST	UINI2A		;YES, ALWAYS ALLOWED
	CAIN	T2,.TYTSK	;IS IT A TASK?
	JRST	UINI2A		;YES, ALWAYS ALLOWED
	JRST	UOPE32		;ERROR - ILLEGAL IF NOT LOGGED IN
UINI2A:	MOVE	M,(P)		;RESTORE USER'S MODE SETTING
	TLNE	M,^-.OPALL&777770 ;ANY UNDEFINED OPEN BITS SET?
	JRST	UOPE54		;ERROR - UNKNOWN OPEN BITS
	PUSH	P,T1		;SAVE NAME USER SUPPLIED
	CAMN	T1,[SIXBIT /NUL/]	;ALL MODES ARE LEGAL FOR NUL:
	JRST	UINI2C		;SO DON'T EVEN BOTHER CHECKING

	PUSHJ	P,CHKMOD	;CHECK FOR LEGAL MODE
	 JRST	UOPE53		;ERROR - ILLEGAL DATA MODE
UINI2C:
	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, GET NO OF USER CHANS DEV INITED ON
	HRR	T3,T2		;SAVE OLD NUMBER
	AOS	T2		;INCREASE CHANNEL COUNT
	CAILE	T2,1		;MORE THAN ONE CHANNEL OPEN ON THIS DEVICE?
	JRST	[MOVEI	T4,DNAERR ;YES, GET AN ERROR CODE
		 JRST	UINIT6]	;DON'T ALLOW THIS
	DPB	T2,IADPTR##	;STORE UPDATED CHANNEL COUNT FOR THIS DEV(DTA)
UINITB:	MOVEI	T2,ASSPRG	;TRY TO ASSIGN IT BY PROGRAM
	SETZM	M
	MOVE	J,.CPJCH##	;ASSIGN BY JOB/CONTEXT HANDLE
	PUSHJ	P,ASSASD	;TRY TO GET THE DEVICE FOR I/O
	JRST	UINIT6		;NOT AVAILABLE, GIVE ERROR RETURN (POP T1)
	ANDI	J,JOBMSK##	;REDUCE TO JCH TO A JOB NUMBER
	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
	JRST	UINITX
	MOVE	T2,JBTPPN##(J)	;PROJ PROG NUMBER FOR CURRENT JOB
	CAME	T2,FFAPPN##	;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	;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	;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
	JRST	UINIB3
	MOVE	T2,DEVRRC##(F)
	TLZ	T2,DEPRRC##!DEPRHC##!DEPPHO##!DEPLBF##
	TLNE	M,.OPRRC	;REWRITE RIB ON CHANGE?
	TLO	T2,DEPRRC##	;YES
	SKIPGE	P1		;PHYSICAL ONLY?
	TLO	T2,DEPPHO##	;YES, REMEMBER THAT.
	TLNE	M,.OPLBF	;USE LARGE BUFFERS?
	TLO	T2,DEPLBF##	;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,.USCTA
	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:	TLZ	F,^-SYSDEV	;CLEAR LEFTOVER BITS FROM PREVIOUS CHANNEL
	SETZ	T1,		;CLEAR THE EXTENDED ERROR STATUS
	DPB	T1,PDVESE##	;
IFN FTXMON,<
	LDB	T1,[POINT 5,.USUPF,17] ;GET PCS
	MOVEM	T1,DEVISN(F)	;SAVE IT FOR SECTION RELATIVE I/O
>
	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
UOPE1D:	POP	P,(P)		;ADJUST STACK
UOPE12:	MOVEI	T4,NSDERR	;NO-SUCH-DEVICE ERROR
	JRST	UINITE		;ERROR RETURN

UOPE33:	PUSHJ	P,NQABRT	;SET I/O ERROR
	MOVEI	T4,ENQERR	;ENQ-LOCKS-OUTSTANDING ERROR
	POPJ	P,		;ERROR RETURN

UOPE32:	MOVEI	T4,NLIERR	;NOT-LOGGED-IN ERROR
	JRST	UINITE		;ERROR RETURN

UOPE53: MOVSI	T4,(UP.FIP)	;CALLED FROM
	TDNN	T4,.USBTS	; A FILOP.?
	JRST	ILLMOD##	;NO, STOMP ON USER JOB
	PUSHJ	P,TTYKLQ##	;KILL OFF TTY DDB IF NECESSARY
	MOVEI	T4,IDMERR	;ILLEGAL-DATA-MODE ERROR
	JRST	UINITD		;ERROR RETURN

UOPE54:	MOVEI	T4,UOBERR	;UNKNOWN-OPEN-BITS ERROR
	JRST	UINITE		;ERROR RETURN

UINIT6:	PUSH	P,T4		;PRESERVE ERROR CODE FROM ASSASD
	PUSHJ	P,TTYKLQ##	;IF IT WAS A FREE TTY, DISCARD DDB
	POP	P,T4		;RESTORE ERROR CODE
	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

	MOVSI	T3,(UP.FIP)	;GET FILOP BIT
	TDNN	T3,.USBTS	;CALLED 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
;DISPATCH TABLE
;DISPATCH TO DEVICE DEPENDENT SERVICE ROUTINE
;ENTER UUO - ENTER FILE NAME IN DIRECTORY

UDEN:	PUSHJ	P,SAVE4##
	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.
	MOVE	T4,DEVSER(F)	;RESTORE DISPATCH ADDRESS
	PUSHJ	P,DEN(T4)	;ATTEMPT AN ENTER
	  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##
	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
	  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)

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:	PUSH	P,M		;PRESERVE M FROM CORRUPTION
	PUSHJ	P,FCLERB	;CHECK LOOKUP/ENTER/RENAME BLOCK
	  JRST	ADRERR##	;ADDRESS CHECK
	JRST	MPOPJ##		;RESTORE M AND RETURN
;ROUTINE TO PRINT WATCH-FILE DATA
;CALL:	HRR 	M,UVA OF ERROR CODE (HRRI M,0 IF SUCCESS)
;	PUSHJ	P,WCHFIL
;	  CAI	'X'
WCHFIL::MOVEI	T1,UP.SWF	;ALREADY TYPED IT?
	TDNE	T1,.USBTS
	JRST	[ANDCAM T1,.USBTS ;YES, CLEAR THE FLAG
		 POPJ P,]
	MOVE	J,.CPJOB##	;GET J SET UP CORRECTLY
	MOVE	T1,JBTWCH##(J)	;GET WATCH BITS
	HRR	T1,JBTSTS##(J)	;AND SHADOW ACS AND OTHER FLAGS
	HRRZ	T2,.USMUO	;GET MUUO OPCODE
	TRNE	T1,JS.ASA	;REFERENCE TO SHADOW ACS?
	CAIN	T2,(ENTER)	;AND NOT ENTER (IMPLYING SAVE)?
	CAIA			;SAVE - WATCH IT
	POPJ	P,		;RUN/GET - DON'T WATCH
	TRNN	T1,JS.XO	;EXECUTE ONLY?
	TLNN	T1,JW.WFL	;NO, WANT TO SEE THIS?
	POPJ	P,		;NO, RETURN
	PUSH	P,U		;SAVE A BUNCH OF ACS
	PUSH	P,S
	PUSH	P,F
	PUSHJ	P,TTYFND##	;SET U TO LDB OF CONTROLLING TERMINAL
	POP	P,F
	JUMPE	U,WCHFI4	;SKIP OUTPUT IF DETACHED
	PUSHJ	P,PRLBK##	;PRINT LEFT BRACKET
	MOVE	T1,DEVJOB(F)	;CHECK IF FILOP. IN PROGRESS
	TLNN	T1,DEPFOP
	JRST	WCHFI1		;NOT FILOP., SKIP THE "F"
	PUSHJ	P,INLMES##
	ASCIZ	/F/
WCHFI1:	HRRZ	T3,@-2(P)	;GET CODE SUPPLIED BY CALLER
	PUSHJ	P,COMTYO##	;TYPE IT
	HLRZ	T1,.USCTA	;GET CURRENT CHANNEL
	PUSHJ	P,PRTDI8##	;TYPE IT
	PUSHJ	P,INLMES##	;SEPARATE
	ASCIZ	/: /
	PUSHJ	P,PRTDDB##	;PRINT DDB INFO
WCHPCP:	MOVEI	T1,[ASCIZ / exec/] ;GET BLURB
	MOVSI	T2,(XC.USR)	;SEE IF EXEC MODE UUO
	TDNN	T2,JOBPDO	;IDENTIFY EXEC MODE
	PUSHJ	P,CONMES##
	MOVE	T2,JOBPDO+1	;FETCH PC FROM JOBPDO
	SUBI	T2,1		;BACK OFF TO ACTUAL PC OF UUO
	PUSHJ	P,INLMES##	;MORE NOISE
	ASCIZ	/ PC:/
	PUSHJ	P,UDPCP##	;PRINT (ALLOWING SECTION NUMBER)
WCHFI2:	TRNN	M,-1		;ANY ERROR SET?
	JRST	WCHFI3		;NO, QUIT NOW
	PUSHJ	P,INLMES##	;APPEND SOME ERROR TEXT
	ASCIZ	/, error /
	PUSHJ	P,GETWDU##
	HRRZS	T1
	PUSHJ	P,PRTDI8##
WCHFI3:	PUSHJ	P,PRRBK##
	PUSHJ	P,PCRLF##
WCHFI4:	POP	P,S
	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
	MOVE	T4,DEVSER(F)	;RESTORE DISPATCH ADDRESS
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	JRST	RNMSEG##	;OLD FILE IS .SHR AND RENAME SUCCESSFUL.

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

;USETO UUO - SET NEXT OUTPUT BLOCK NUMBER(DECTAPE)
UDSO:
	HRRE	W,M		;BLOCK NUMBER
	CAME	W,[-1]		;IF NOT USETO TO BLOCK OF FILE
	TLZ	W,-1		;CLEAR HIGH ORDER BITS
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	PUSHJ	P,WAIT2		;WAIT FOR IO, FIX OUTPUT BUFFERS
	JRST	DSO(T4)

;USETI UUO - SET NEXT INPUT BLOCK NUMBER
UDSI:
	HRRE	W,M		;BLOCK NUMBER
	CAME	W,[-1]		;BLOCK-1 MEANS END OF FILE,IS IT?
	CAML	W,MUSTMX##	;TRYING TO READ EXTENDED RIB?
	CAIA			;YES
	TLZ	W,-1		;NO,CLEAR HIGH BITS FOR COMPATIBILITY
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	PUSHJ	P,WAIT2		;WAIT FOR IO, FIX OUTPUT BUFFERS
	JRST	DSI(T4)

;ENTER HERE FROM FILOP.
FOPGTF:	PUSHJ	P,FOPLP		;MUST HAVE LONG DISPATCH TABLE
	LDB	T1,PUUOAC##	;GET AC NUMBER
	HRR	M,T1		;WHERE TO STORE BLOCK NUMBER
;UGETF UUO - GET NEXT FREE BLOCK
UDGF:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	JRST	DGF(T4)

;HERE FROM FILOP.
FOPMTP:	HRRZ	T1,FOPFLG	;MUST HAVE AT LEAST TWO ARGS
	CAIGE	T1,2
	JRST	FOPILU
	PUSHJ	P,GETWD1##	;GET NEXT ARG
	HRR	M,T1		;STORE AS THE MTAPE BITS
	PUSHJ	P,FOPLP		;MUST HAVE LONG DISPATCH TABLE
;MTAPE UUO - MAGTAPE OPERATIONS
UMTAPE:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET CPU FOR FILE OPERATION
>
	JRST	DMT(T4)

;HERE FROM FILOP.
FOPUTP:	PUSHJ	P,FOPLP		;DO SPECIAL STUFF FOR FILOP.
;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:	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
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
>
	TLZ	S,IO		;INDICATE READING AGAIN
	MOVEM	S,DEVIOS(F)
UIN01:	TLO	F,INPB		;FOR THIS DEVICE.
	TLZ	F,ICLOSB
	PUSHJ	P,JDAADR	;IN LH OF CURRENT JOB DEVICE CHANNEL
	HLLM	F,(T1)
IFN FTMP,<
	PUSHJ	P,SETCPF##	;GET JOB ON RIGHT CPU TO DO IO
				; IF NON-QUEUED PROTOCOL
>
	LDB	T1,PIOMOD##	;IO MODE
	CAIL	T1,SD		;IS THE IO MODE DUMP(SD,D,DR)?
	JRST	INDMP		;YES
IN1:
	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
IFN FTMP&FTKL10,<
	SUBI	T1,1		;POINT AT S-WORD (SWEEP NUMBER)
	PUSHJ	P,UADRCK	;MAKE SURE IT IS IN
>
	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	INPT1A
IN1A:	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 FTMPXSER,<
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,.TYMPX
	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 FTMPXSER
	EXCTUX	<HRRZ T2,@U>	;RESTORE T2
IFN FTMP&FTKL10,<
	MOVE	T4,.CPCSN##	;GET CACH-SWEEP NUMBER
	HRL	T4,.CPCPN##	;SAVE CPU NUMBER
	TLO	T4,IO		;INSURE IO IS ON
	MOVEI	T1,-1(T2)	;SAVE IN BUFFER HEADER FOR FILLER
	EXCTXU	<MOVEM	T4,@T1>
	PUSHJ	P,OUCHE##	;GET IT BACK TO MEMORY
>
	MOVSI	T3,IOUSE
	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		;GET IT OUT OF CACHE
	PUSHJ	P,OUCHE##
	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	.USREL
	SKIPE	.USVRT	;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 FTMPXSER,<
	PUSHJ	P,CHKMPX##	;AN MPX DDB OR A DDB CONNECTED TO AN MPX?
	  JRST	INPT3A		;YES, LET MPXSER 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 FTMPXSER,<
	LDB	J,PDVTYP##	;GET THE DEVICE TYPE
	CAIE	J,.TYMPX	;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

INPT1A:
IFN FTMP&FTKL10,<
	HRRZ	T1,T2		;GET USE BIT OUT OF CACHE
	PUSHJ	P,OUCHE##	;CACHE MIGHT BE WRONG IF
	MOVSI	T1,IOUSE	;NON-BLOCKING I/O
	EXCTUX	<TDNE T1,@T2>	;TRY AGAIN
	JRST	IN1A		;CAHE WAS WRONG (RARE)
>
INPT1:	TRNN	S,IOACT		;IF DEVICE ISNT ALREADY GOING
	PUSHJ	P,CALIN		; START IT NOW
	JRST	INPT2		;BLOCK UNTIL BUFFER FILLED


INEOF:	MOVSI	T1,DEPSIE
	TDNE	T1,DEVJOB(F)	;SYNCH ON ERROR?
	TRNN	S,IODEND	;YES, AVOID KAF IF TAPE
	TDNE	S,[XWD IOEND,IODERR+IOBKTL+IODTER+IOIMPM]
	CAIA			; EOF OR ERROR BIT SET BY SERVICE ROUTINE
				; 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
IFN	FTMP,<
	HRRZ	T1,DEVIAD(F)
	HRRZ	T2,DEVEVM(F)	;GET EVM ADDRESS IF ANY
	SKIPE	T2		;STILL HAVE EVM?
	MOVEM	S,-1(T1)	;YES, PUT S-WORD BACK (BUFFER IN EVM)
	SKIPN	T2		;STILL HAVE EVM?
	EXCTXU	<MOVEM	S,-1(T1)> ;NO, PUT S-WORD BACK
>
	POPJ	P,		;RETURN TO USER'S PROGRAM
INEOF1:	MOVE	T1,DEVAIO(F)	;ASYNC?
	TRNN	T1,DEPAIO
IFE FTMP,<
	JRST	UUOER1##	;MONITOR ERROR
>
IFN FTMP,<
	JRST	INPT1		;START OVER
>
	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 & INBUF

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,CPFBOO##	;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 PROTOCOL?
	  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 FTMPXSER,<
	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
	MOVSI	T1,DEPSIE
	TDNE	T1,DEVJOB(F)
	TRNN	S,IOBKTL+IODTER+IODERR+IOIMPM+IODEND
	  SKIPA			;NO ERRORS OR DOESN'T CARE
	POPJ	P,		;WAIT FOR ERRORS TO CLEAR
	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:
	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 FTMPXSER,<
	LDB	T1,PDVTYP##	;GET THE DEVICE TYPE
	CAIN	T1,.TYMPX	;IS THIS MPX?
	PJRST	MSGOUT##	;YES--CALL MPXSER
> ;END FTMPXSER

;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:
IFN FTMP,<
	PUSHJ	P,SETCPF##	;SET JOB ON CPU OWNING DEVICE
				; IF NON-QUEUED PROTOCOL
>
	LDB	T1,PIOMOD##	;GET DATA MODE SET BY INIT OR SETSTS.
	CAIL	T1,SD		;IS IT DUMP MODE(SD,DR,D)?
	JRST	OUTDMP		;YES.
	PUSHJ	P,OUTA		;NO, CHECK FOR NON-ZERO ADDRESS(USER
				; CHANGING RING)
	TLO	S,IO		;INDICATE WRITING AGAIN
	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	OUT3A		;THEN JUST START THE DEVICE
	MOVE	T4,DEVMOD(F)	;GET CHARACTERISTICS
	EXCTUX	<HRRZ	T1,@U>	;GET RH OF BYTE POINTER.
	EXCTUX	<HLR T4,(T2)>	;GET FULL SIZE OF BUFFER
	TRNN	T4,-1		;VIRGIN RING?
	HRRI	T4,200		;YES, ASSUME 200 WORDS IN BUFFER
	TRZ	T4,400000	; FOR CHECK IF DTA OR DSK
	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.
	TRNN	S,IOWC		;WANT USER WORD COUNT
	JRST	OUT2B1		;NO
OUT2:	EXCTUX	<HRRZ T1,@T2>	;YES
	LDB	T3,PIOMOD##	;I/O MODE
	CAIE	T3,BYTMOD	;BYTE MODE?
	JRST	OUT2B1		;NO, DON'T NEED TO CONVERT
	PUSH	P,T2		;SAVE L(WRDCNT WORD)
	EXCTUX	<LDB T3,[POINT 6,@U,11]> ;GET BYTE SIZE
	MOVEI	T2,^D36		;# BITS IN WORD
	IDIVI	T2,(T3)		;BYTES PER WORD
	IDIVI	T1,(T2)		;BYTE COUNT BECOMES WORD COUNT
	SKIPE	T2		;ROUND UP FOR PARTIAL WORDS
	ADDI	T1,1		;T1 HAS WORD COUNT
	POP	P,T2
OUT2B1:	SKIPGE	T3,T1		;PRESERVE USER'S WORDCOUNT
	PJRST	ADRERR##	;NEGATIVE WORDCOUNTS ARE ILLEGAL
	TLNE	T4,DVDSK!DVDTA	;IF DISK OR DTA,
	MOVEI	T1,-1(T4)	; MAKE SURE WHOLE BUFFER IS THERE
	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?
	CAIN	T1,PIMMOD	;OR PACKED IMAGE MODE?
	JRST	OUT2B2		;YES, COMPUTE EXACT NUMBER OF BYTES
	CAIE	T1,A8		;ALSO EXACT IF 8-BIT ASCII
	JRST	OUT2A		;NO
OUT2B2:	JUMPE	T3,OUT2A	;DON'T COMPUTE IF = 0
	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
	JUMPGE	T2,OUT2A	;POSITIVE NUMBER OF WORDS
	TRNE	T3,-1		;NEGATIVE WORDS LEGAL ONLY IF RESOLVES TO 0 BYTES
	PJRST	ADRERR		;NEGATIVE NUMBER OF BYTES LOSE
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,UPDNBF	;UPDATE DEVNBF IF QUEUED PROTOCOL
>
OUT3:	MOVSI	T1,DEPADV	;DON'T DEADVANCE BUFFERS BIT
	ANDCAM	T1,DEVADV(F)	;CLEAR BEFORE RETRY. REPEAT OF ERRORS
				; WILL SET IT AGAIN.
	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
	TLZE	S,IOSTBL	;ERROR OCCURED?
	JRST	OUT3A		;YES
IFN FTMP,<
IFN FTKL10,<
	MOVE	T1,T2		;GET OLD USE BIT OUT OF CACHE
	PUSHJ	P,OUCHE##
>
	TRNN	S,IOBKTL+IODTER+IODERR+IOIMPM+IOTEND
	EXCTUX	<SKIPL @T2>	;BUFFER REALLY EMPTY?
>
	JRST	OUTS		;YES, RETURN TO USER
OUT3A:	HRL	W,S		;COPY IOACT TO W
IFN FTKL10&FTMP,<
	PUSHJ	P,ISITQ		;QUEUED PROTOCOL?
	  JRST	OUT3		;NO
	PUSHJ	P,CKNBF##	;YES UPDATE DEVNBF
>
	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

IFN FTKL10&FTMP,<
;ROUTINE TO UPDATE DEVNBF FOR OUTPUT
UPDNBF:	PUSHJ	P,ISITQ		;NON-TTY, QUEUED PROTOCOL
	  POPJ	P,		;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)
	PJRST	CKNBF##		;ADD IT TO LH IF ON RIGHT CPU
>
OUTF:	TLO	S,IO		;INDICATE OUTPUT FOR IOSETC
IFN FTKL10&FTMP,<
	PUSHJ	P,ISITQ		;QUEUED PROTOCOL
	  JRST	.+3		;NO, PRESS ON
	SETZM	DEVNBF(F)	;NO BUFFERS LEFT AROUND IF VIRGIN RING
	SETZM	DEVSBF(F)	;...
>
	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:	PUSHJ	P,OUTFCL	; TO ENSURE THAT A FAULT WONT HAPPEN
	  JRST	ADRERR##	; AFTER THE VIRGIN-RING BIT IS CLEARED
	HRLZI	T1,IOUSE
	EXCTUU	<ANDCAB	T1,@U>	;VIRGIN RING BIT:=0
	HRRM	T1,DEVOAD(F)
OUTS:	PUSHJ	P,OUTFCL	;MAYBE CLEAR THE BUFFER
	  JRST	ADRERR##	;ADDRESS CHECK
	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

;HERE TO CLEAR THE BUFFER POINTED TO BY THE RING HEADER (MAYBE)

OUTFCL:	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
	PJRST	BUFCLR		;NO, CLEAR BUFFER AND RETURN
	PUSHJ	P,UADRCK	;MAKE SURE FIRST WORD IS IN CORE
	PUSHJ	P,BRNGE##	;MAKE SURE BUFFER IS ALL IN CORE
	JRST	CPOPJ1##	;YES, SKIP CLEARING THE NEXT BUFFER
CALOUI:	TLNE	W,IOACT
	POPJ	P,
	MOVSI	S,IOSTBL	;CLEAR TROUBLE FLAG
	ANDCAB	S,DEVIOS(F)
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
	LDB	T2,PDVTYP##	;GET DEVICE TYPE
	CAIE	T2,.TYMTA
	  TRZ	T1,IOTEND	;NO, EOT IS NO GOOD HERE!
	TRNE	T1,IOBKTL+IODTER+IODERR+IOIMPM+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
	TLO	S,IO		;INDICATE OUTPUT

;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
	SKIPGE	DEVISN(F)	;DOING MULTI-SECTION I/O?
	JRST	PFHMSI##	;YES, LET PFH HANDLE DIFFERENT IOWD FORMAT
	JRST	PFHDMP##	;LET PFH HANDLE WHAT DMPEV USED TO DO
REPEAT 0,<
	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,.USCTA	;PUT CHANNEL #
				; (IN CASE OF TROUBLE AND CALL HNGSTP)
	PUSHJ	P,RELEA1	;RESET IT
	JRST	CPOPJ1##	;SKIP RETURN
	SUBTTL	RELEASE UUO

;HERE FROM FILOP.
FOPREL:	AOS	(P)		;GOOD RETURN

;RELEASE A DEVICE
URELEA::TRZ	M,-1		;CLOSE BOTH INPUT AND OUTPUT
	PUSHJ	P,CLOSE1
	PUSHJ	P,WAIT1##	;WAIT FOR DEVICE TO BECOME INACTIVE

;HERE TO RELEASE WITHOUT CLOSING DEVICE
RELEA1::LDB	T2,PJCHN##	;GET OWNING JOB/CONTEXT HANDLE
	CAME	T2,.CPJCH##	;SAME AS CURRENT JCH?
	POPJ	P,		;NO--DON'T LET GO
	HRRZ	T4,DEVSER(F)	;RESTORE T4
IFN FTMP,<
	PUSHJ	P,SETCPP##	;SKIP IF CPU IS ALIVE
	  SKIPA			;DETACHED
> ;END IFN FTMP
	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

RELEA2:	PUSHJ	P,NXTCH		;GET NEXT CHANNEL
	  JRST	RELEA3		;FINISHED
	CAIN	T1,(F)		;SAME DEVICE ON ANOTHER CHANNEL?
	JRST	P1POPJ##	;YES, EXIT
	JRST	RELEA2		;LOOP FOR THE NEXT OPEN CHANNEL

RELEA3:	POP	P,P1		;RESTORE P1

;HERE FROM ERROR STOP ROUTINES (SWAP READ ERROR, PARITY ERROR, ETC.)
RELEA4::LDB	T2,PJCHN##	;GET JOB/CONTEXT HANDLE
	TRZ	T2,CTXMSK##	;CLEAR OUT CONTEXT NUMBER
	DPB	T2,PJCHN##	;UPDATE
IFN FTXMON,<SETZM DEVISN(F)>	;CLEAR I/O SECTION NUMBER
	MOVEI	T3,0		;CLEAR USER ADDRESS
	PUSHJ	P,RTIEVM	;RETURN EVM FOR INPUT
	MOVEI	T3,0		;CLEAR USER ADDRESS
	PUSHJ	P,RTOEVM	;RETURN EVM FOR OUTPUT
	MOVEI	T1,DEPAIO	;ASYNCH BIT
	ANDCAM	T1,DEVAIO(F)	;CLEAR NON-BLOCKING I/O FLAG
	MOVEI	T2,ASSPRG	;CLEAR ASSIGNED BY PROGRAM BIT
RELEA6::MOVE	T1,DEVMOD(F)	;SAVE OLD DEVMOD
	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
	ANDI	T1,ASSCON	;KEEP JUST THE "ASSIGNED BY COMMAND" BIT
	PUSH	P,T1		;AND SAVE IT FOR LATER
	SETZM	DEVBUF(F)	;NO BUFFER HEADERS
	SKIPE	DEVPSI(F)	;SOMEONE PSI'ING ON THIS DEVICE
	PUSHJ	P,PSIRMV##	;YES, REMOVE FROM PSI CHAIN
IFN FTMDA,<
	PUSH	P,W		;SAVE FROM IPCSER
	MOVSI	T1,DVCMDA	;SEE IF MDA CONTROLS THIS DEVICE
	TDNE	T1,DEVCHR(F)	;DOES IT?
	PUSHJ	P,SNDFIN##	;TELL MDA
	  JFCL			;IGNORE ERROR
	POP	P,W		;RESTORE W
>;END FTMDA
	PUSHJ	P,TPMRES##	;RESET MAGTAPE DDB PARAMETERS
	MOVE	T2,DEVMOD(F)	;PUT DEVMOD IN T2
	TLNN	T2,DVTTY	;DON'T BE FOOLED BY NULL
	TLNN	T2,DVMTA	;A MAGTAPE?
	JRST	RELE6A		;NO
	SKIPE	(P)		;ASSIGNED BY COMMAND BEFORE?
	PUSHJ	P,TPSTAT##	;YES--REPORT TAPE STATS, CLEAR TUB COUNTERS
RELE6A:	POP	P,(P)		;TRIM STACK
	PUSHJ	P,CLRDVL	;DISCONNECT JOB FROM DDB
IFN FTNET,<
	MOVSI	T1,DVCNET	;CHECK FOR A NETWORK DEVICE
	TDNE	T1,DEVCHR(F)	;IS IT
	PJRST	ZAPNET##	;YES, DISCONNECT DEVICE IF NO LONGER NEEDED
> ;END IFN FTNET
	MOVE	T2,DEVMOD(F)	;GET DEVMOD
	SKIPL	DEVSPL(F)	;IS DEVICE A SPOOLED DISK
	TLNE	T2,DVDSK	;IS DEVICE A DSK
	PJRST	CLRDDB##	;YES-RETURN DDB TO STORAGE
	LDB	T2,PDVTYP##	;GET THE DEVICE TYPE
IFN FTMPXSER,<
	CAIN	T2,.TYMPX	;IS THIS AN MPX DDB?
	PJRST	ZAPMPX##	;YES--KILL IT OFF
> ;END FTMPXSER
IFN FTKS10,<
	CAIN	T2,.TYKDP	;IS THIS A KDP DDB?
	PJRST	ZAPKDP##	; IF SO, DELETE IT
	CAIN	T2,.TYDMR	;IS THIS A DMR DDB?
	 PJRST	ZAPDMR##	;YES, DELETE IT
>
IFN FTKL10,<
	CAIN	T2,.TYDTE
	PJRST	ZAPDTE##
>
	PJRST	XTKLDB##	;GO KILL XTC DDB IF NECESSARY
	SUBTTL	STATUS SETTING AND GETTING UUO'S


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


USTATO::
	PUSHJ	P,XTCIOS##	;GET S

	TRNE	S,(M)		;SKIP IF ANY INDICATED BITS ARE ONE
	AOS	(P)
	POPJ	P,		;RETURN TO USER

;HERE FROM FILOP.
FOPGST:	AOS	(P)		;GOOD RETURN
	LDB	T1,PUUOAC##
	HRR	M,T1

;CALLING SEQUENCE
;	STATUS D,ADR
;	EXIT		ALWAYS RETURNS HERE
;STORES I/O STATUS WORD OF DEVICE ON CHANNEL D IN LOCATION ADR.
USTATS::
	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::
	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
	LDB	T1,PDVTYP##	;GET THE DEVICE TYPE
	CAIE	T1,.TYMTA
	  TRZ	S,IOTEND	;EOT IS ONLY GOOD ON MAGTAPE
	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,

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



;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::PUSHJ	P,SVEUF##	;PUSH THE USER BASE REGISTER AND SETUP UBR
				; SO THAT CURRENT USER IS ADDRESSABLE
	PUSHJ	P,SPCS##	;SETUP PCS
	PUSHJ	P,ADVBFO	;ADVANCE OUTPUT BUFFER
	  POPJ	P,		;STOP
	PJRST	ADVSWP		;GO, UNLESS SWAPPER SAYS NO

ADVBFO::HRRZ	T1,DEVOAD(F)	;USER OR EXEC VIRTUAL ADDRESS OF CURRENT BUFFER
	TRNN	T1,-1		;HAS IT BEEN CLEARED BY A RELEASE?
	POPJ	P,		;YES, GIVE STOP I/O RETURN
IFN FTMPXSER,<
	MOVEI	T2,DEPMSG	;IS THIS DEVICE CONTROLLED BY
	TDNE	T2,DEVMSG(F)	; BY MPXSER
	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)
	  JFCL			;PAGE NOT IN CORE
	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
>
	HRRZS	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)
	  JFCL			;PAGE NOT IN CORE (UPDATE DEVOAD BUT STOP I/O)
	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::PUSHJ	P,SVEUF##	;PUSH THE USER BASE REGISTER AND SETUP UBR
				; SO THAT CURRENT USER IS ADDRESSABLE
	PUSHJ	P,SPCS##	;SETUP PCS
	PUSHJ	P,ADVBFI	;ADVANCE INPUT BUFFER
	  POPJ	P,		;STOP
	PJRST	ADVSWP		;GO, UNLESS SWAPPER SAYS NO

ADVBFI::HRRZ	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
	PUSH	P,T3		;ITS POSSIBLE THAT SOME DEVICE ROUTINES
				; DEPEND ON T3 BEING INTACT UPON RETURN
IFN FTMPXSER,<
	MOVEI	T2,DEPMSG	;IF THIS DEVICE IS CONTROLLED
	TDNE	T2,DEVMSG(F)	; VIA MPXSER. 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)
	  JFCL			;PAGE NOT IN CORE
	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
>
	HRRZS	T1,T3		;ADDRESS OF START OF BUFFER
	PUSHJ	P,IADCKL	;MAKE SURE ITS LEGAL (MIGHT BE PAGED OUT)
	  JRST	ADVBU3		;ILLEGAL ADDRESS (ADR CHECK)
	  JFCL			;PAGE NOT IN CORE (UPDATE DEVIAD BUT STOP IO)
	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 LET I/O CONTINUE
ADVBU1::AOS	-1(P)		;SET SKIP (CONTINUE I/O) RETURN
	JRST	ADVBU3
;HERE TO STOP EVM DEVICE
ADVBU2:	PUSH	P,T3		;SAVE ADDR OF BUFFER
	PUSHJ	P,RTNEVM	;SHUTTING DOWN I/O, GIVE BACK ANY EVM
	POP	P,T3
;HERE TO STOP NON-EVM DEVICE
ADVBU3:
IFN FTMP&FTKL10,<
	HRRZ	T1,T3
	PUSHJ	P,OUCHE##	;REMOVE LINE FROM CACHE
>
	JRST	T3POPJ##	;RESTORE T3

;HERE TO SEE IF I/O SHOULD BE STOPPED SO JOB CAN BE SHUFFLED,
; SWAPPED, LOCKED, OR THE USER HAS TYPED CONTROL C
;RETURNS CPOPJ IF WE SHOULD STOP I/O, CPOPJ1 TO CONTINUE I/O
;PRESERVES T3
ADVSWP::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	ADVSW2		; GIVE STOP I/O RETURN
	SKIPGE	T2,JBTSTS##(T2)	;IS THE JOB RUNNABLE?
	TLNE	T2,SHF!CMWB!CNTRLC
	JRST	ADVSW2		;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	ADVSW2		;YES, SHUT DOWN THE I/O
	JRST	CPOPJ1		;OK TO CONTINUE I/O

;HERE TO STOP DEVICE BECAUSE SWAPPER WANTS TO SWAP THE JOB
ADVSW2:	PUSH	P,T3		;SAVE T3
	PUSHJ	P,RTNEVM	;GIVE BACK ANY EVM
	JRST	T3POPJ##	;NOSKIP
;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,		;ILLEGAL
	  POPJ	P,		;NOT IN CORE
	EXCTUX	<HLRZ	T2,(T1)> ;SIZE
	ANDI	T2,IOSIZ
	JUMPE	T2,CPOPJ
	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 SAME 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::PUSHJ	P,IADRCK	;ADDRESS IN CORE AND LEGAL?
	  JRST	ADRERR##	;ILLEGAL, IN HI SEG, SPY PAGE, OR PROTECTED JOBDAT
	  JRST	UUOFLT##	;LEGAL, BUT PAGED OUT, ACCESS ALLOWED OFF, OR ABZ
	POPJ	P,		;IN CORE AND LEGAL
;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,.USHSS	;IS ADDRESS IN USER HIGH SEGMENT?
	CAMLE	T1,.USHSE	; . . .
	AOS	(P)		;LOW SEG ADDRESS, SUCCESSFUL RETURN
	POPJ	P,		;RETURN
> ;END REPEAT 0
;ROUTINE TO CHECK AN ADDRESS TO SEE IF ITS LEGAL AND IN CORE
;CALLING SEQUENCE:
;	MOVEI	T1,ADDRESS TO BE CHECKED
;	PUSHJ	P,IADRCK OR IADCKL
;	  ...	RETURN HERE IF ILLEGAL ADDRESS
;	  ...	RETURN HERE IF PAGE ADDRESS IS IN A PAGE PAGED OUT, ACCESS ALLOWED OFF, OR ABZ
;	...	RETURN HERE IF ADDRESS IS IN CORE AND LEGAL

IADCKL::
IADRCK::TLNE	T1,-1-MXSECN	;DON'T ALLOW CRUFT IN THE LEFT HALF
	POPJ	P,		;ILLEGAL ADDRESS
	SE1ENT			;MUST BE IN SECTION 1
	PUSH	P,T1		;SAVE WORKING ACS
	PUSH	P,T2
	XSFM	T2		;GET FLAGS AND PCS
	HLRZS	T1		;POSSIBLE SECTION NUMBER
	ADD	T2,T1		;ADD AS OFFSET PROM PCS SECTION
	ANDI	T2,MXSECN	;ISOLATE PCS
	CAIG	T2,MXSECN	;ADDRESS CHECK IF ILLEGAL SECTION NUMBER
	SKIPN	.UPMP+SECTAB(T2);SECTION EXIST?
	JRST	TTPOPJ##	;NO, THAT'S AN ADDRESS CHECK
	LSH	T2,P2WLSH	;POSITION SECTION NUMBER
	HRRZ	T1,-1(P)	;IGNORE JUNK WHICH MIGHT BE IN THE LEFT HALF
	SKIPL	USRHCU##	;IF SAVE IN PROGRESS, ITS OK
	CAILE	T1,JOBPFI##	;ADDRESS ABOVE PROTECTED JOB DATA AREA?
	JRST	IADCK1		;YES
	MOVE	T1,@[IW MS.MAP,UMAPS(T2)] ;POINTER FOR PAGE 0 OF PCS SECTION
	CAMN	T1,@[IW MS.MAP,UMAPS] ;SAME AS POINTER FOR PAGE 0 OF SECTION 0?
	JRST	TTPOPJ##	;YES, ATTEMPT TO DO I/O BELOW JOBPFI
IADCK1:	HRRZ	T1,-1(P)	;RESTORE ADDRESS WITHIN SECTION
	LSH	T1,W2PLSH	;PAGE NUMBER FROM ADDRESS
	IOR	T1,T2		;<SECTION NUMBER>B27+<PAGE NUMBER>B35
	SKIPN	T2,@[IW MS.MAP,UMAPS(T1)] ;GET POINTER WHICH MAPS ADDRESS
	JRST	TTPOPJ##	;ZERO IS ILLEGAL
	SKIPL	USRHCU##	;IF SAVE IS IN PROGRESS, DON'T CHECK PM.NIA
	TLNN	T2,(PM.NIA)	;IS I/O ALLOWED INTO THIS PAGE (NOT HI SEG)?
	CAIA			;SAVE OR NOT A HIGH SEGMENT PAGE
	JRST	TTPOPJ##	;I/O NOT ALLOWED, ADDRESS CHECK
	LDB	T2,[POINT 3,T2,2] ;EXTRACT POINTER TYPE
	JUMPE	T2,IADCK2	;JUMP IF PAGED OUT, ACCESS ALLOWED OFF, OR ABZ
	CAIE	T2,PM.DCD	;POINTER TYPE = DIRECT?
	JRST	TTPOPJ##	;NO, MUST BE INDIRECT OR SHARE, ADDRESS CHECK
	LSH	T1,S2PLSH	;BACK TO SECTION NUMBER
	HRR	T1,-1(P)	;ADDRESS WITHIN SECTION BEING CHECKED
	SKIPL	USRHCU##	;IF NOT A SAVE IN PROGRESS,
	PUSHJ	P,CHKWLP##	;MAKE SURE PAGE CONTAINING ADDRESS IS WRITABLE
	AOS	-2(P)		;PAGE IS IN CORE, LEGAL, AND ACCESSIBLE
IADCK2:	AOS	-2(P)		;PAGE EXISTS, BUT IS OUT, AA OFF, OR ABZ
	JRST	TTPOPJ##	;RESTORE ACS AND RETURN
	SUBTTL	EVM HANDLING ROUTINES

;ROUTINE TO DETERMINE WHETHER A DEVICE NEEDS THE USER AREA
;REPRESENTED IN THE CURRENT I/O OPERATION TO BE
;MAPPED IN EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;
;	MOVE	F,ADDRESSS OF DEVICE DATA BLOCK
;	PUSHJ	P,MAPDEV
;	RETURN HERE IF NO MAPPING REQUIRED
;	RETURN HERE IF BUFFERS OR IOWDS MUST BE MAPPED

MAPDEV::PUSH	P,T1		;SAVE P1
	MOVEI	T1,DEPEVM	;GET "DEVICE DOESN'T NEED EVM" BIT
	TDNN	T1,DEVTYP(F)	;SKIP IF MAPPING NOT REQUIRED
	PJRST	TPOPJ1##	;PTY, TTY, AND CHANNEL DEVICES ARE NOT
				; MAPPED IN EXEC VIRTUAL MEMORY
	PJRST	TPOPJ##		;ALL I/O BUS DEVICE REQUIRE MAPPING IN
				; EXEC VIRTUAL MEMORY
;ROUTINE TO MAP USER AREA IN THE EXEC MAP
;CALLING SEQUENCE:
;
;	MOVE	T1,PAGE NUMBER OF STARTING PAGE IN THE EXEC MAP
;	MOVE	T2,NUMBER OF PAGES
;	MOVE	T3,USER VIRTUAL ADDRESS
;	PUSHJ	P,MAPUEV
;OR
;	PUSHJ	P,MAPUEI IF AT INTERRUPT LEVEL SO EBR,UBR WILL BE
;		RESTORED SO DO NOT NEED TO PURGE ASSOCIATIVE MEMORY
;	RETURNS HERE - T1=PAGE NUMBER IN THE EXEC MAP, T3=EXEC VIRTUAL
;	ADDRESS WHICH CORRESPONDS TO USER VIRTUAL ADDRESS,
;	AND ASSOCIATIVE MEMORY IS PURGED

MAPUEV::PUSHJ	P,SAVE3##	;SAVE P1-P3
	PUSHJ	P,MAPUE1	;MAP THE USER IN EXEC VIRTUAL MEMORY
	CAIE	T2,1		;DO WE NEED TO DO MORE
	CLRPGT			;RESET THE EXEC BASE REGISTER SO
				; THE ASSOCIATIVE MEMORY WILL BE FLUSHED
				; AND THE NEW MAPPING WILL BE IN EFFECT
	POPJ	P,		;RETURN

MAPUEI::PUSHJ	P,SAVE3##	;SAVE P1-P3
MAPUE1:	SE1ENT
	MOVE	P2,T1
IFN FTXMON,<
	XSFM	P3		;GET PCS
	LSH	P3,S2PLSH	;CONVERT TO SECTION #
>
	HRLI	P2,(POINT 36,0)
	ADD	P2,.CPMAP##
	LDB	P1,[POINT 9,T3,26]
IFN FTXMON,<
	HRLI	P3,(MS.MAP)
	ADDI	P3,UMAPS-1(P1)
>
IFE FTXMON,<
	MOVEI	P3,.UPMAP-1(P1)
>
MAPUE2:	AOS	P3		;INCREMENT
	MOVE	P1,(P3)		;COPY A PORTION OF THE USER'S MAP TO
	ANDI	P1,17777	;CLEAR ALL ACCESS BITS
	HRLI	P1,(<PM.DCD>B2+PM.WRT+PM.PUB)
	IDPB	P1,P2		; THE EXEC MAP
	SOJG	T2,MAPUE2	;COPY AS MANY PAGES AS ARE TO BE MAPPED IN EVM
	DPB	T1,[POINT 9,T3,26]
				;FORM AN EXEC VIRTUAL ADDRESS FROM THE EXEC
				; PAGE NUMBER AND THE USER VIRTUAL ADDRESS
	POPJ	P,		;RETURN
;ROUTINE TO MAP A USER BUFFER IN EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;	MOVE	T1,BUFFER SIZE
;	MOVE	T3,USER VIRTUAL ADDRESS OF BUFFER
;	MOVE	F,ADDRESS OF THE DDB
;	PUSHJ	P,GTEVBF
;	RETURN HERE ONLY IF REQUEST COULD NEVER BE SATISFIED (THERE WILL
;	NEVER BE ENOUGH SLOTS AVAILABLE IN THE EXEC MAP)
;	RETURN HERE - T1=BYTE (18)0(9) EXEC VIRTUAL PAGE # (9) # OF EXEC PAGES
;	T3 = THE EXEC VIRTUAL ADDRESS OF THE BUFFER

GTEVBF::SUBI	T1,2		;COMPUTE THE UPPER BOUND ON THE NUMBER OF PAGES
	IDIVI	T1,PAGSIZ+2	; OF EXEC VIRTUAL MEMORY WHICH MIGHT BE
	ADDI	T1,2		; REQUIRED TO COVER THIS BUFFER OR IOWD
	CAMLE	T1,EVBMAX##	;WILL THAT NUMBER OF PAGES EVER BE AVAILABLE?
	POPJ	P,		;NO, ERROR RETURN
	PUSH	P,T1		;SAVE NUMBER OF PAGES BEING REQUESTED
GTEVB1:	PUSH	P,T3		;SAVE THE USER VIRTUAL ADDRESS
	PUSHJ	P,GETEVM	;ATTEMPT TO GET ENOUGH PAGES TO SATISFY THE REQUEST
	  JRST	GTEVBW		;NOT ENOUGH AVAILABLE (WAIT FOR SOME TO BE FREED UP)
	POP	P,T3		;RESTORE THE USER'S VIRTUAL ADDRESS
	MOVE	T2,(P)		; AND THE NUMBER OF PAGES
	PUSHJ	P,MAPUEV	;MAP THE BUFFER OR IOWD IN THE EXEC MAP
	MOVE	T1,T3		;T1 = EXEC VIRTUAL ADDRESS OF THE BUFFER OR IOWD
	POP	P,T2		;MAKE T1 = EXEC VIRTUAL ADDRESS OF SAME
	DPB	T2,[POINT 9,T1,35]
	JRST	CPOPJ1##	;GIVE OK RETURN
GTEVBW:	POP	P,T3		;RESTORE T3
	PUSHJ	P,EVWAIT##	;WAIT UNTIL SOME EVM IS FREED UP
	MOVE	T1,(P)		;RESTORE THE NUMBER OF PAGES REQUIRED
	JRST	GTEVB1		;TRY AGAIN
;SUBROUTINE TO GET EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;
;	MOVE	T1,NUMBER OF CONTIGOUS PAGES REQUIRED
;	PUSHJ	P,GETEVM
;	...	ERROR RETURN - NOT ENOUGH AVAILABLE, T1 = LARGEST NUMBER SEEN
;	...	OK RETURN - T1 = PAGE NUMBER OF FIRST AVAILABLE PAGE

GETEVM::MOVEI	T2,EVMPTR##	;POINT TO EXEC-MAP USAGE TABLE
	PUSHJ	P,GETBIT##	;GET, SET BITS IN THE TABLE FOR THESE PAGES
	  POPJ	P,		;NOT ENOUGH AVAILABLE, RETURN WITH T1= LARGEST HOLE
	JRST	CPOPJ1##	;AND GIVE SUCCESS RETURN



;ROUTINE TO GIVE BACK SLOTS IN THE EXEC MAP
;CALLING SEQUENCE:
;	MOVE	T1,NUMBER OF PAGES
;	MOVE	T2,EXEC VIRTUAL ADDRESS
;	PUSHJ	P,GIVEVM
;	ALWAYS RETURN HERE

GIVEVM::LDB	T2,[POINT 9,T2,26]
	IDIVI	T2,^D36		;WHICH WORD
	HRLS	T2		;PUT WORD NUMBER IN THE LEFT HALF
	ADD	T2,EVMPTR##	;MAKE AOBJN POINTER POINT TO THE WORD CONTAINING
				; THE FIRST BIT TO CLEAR
	PUSH	P,T4		;SETZRS CLOBBER T4
	PUSHJ	P,SETZRS##	;GIVE BACK THE EVM
	PUSHJ	P,EVFREE##	;WAKE UP ALL WAITERS FOR EVM
	SETZM	EVREQ##		;SO NEXT CALLER TO EVWAIT WILL WAIT (IMMEDIATELY)
	JRST	T4POPJ##	;RETURN
;SUBROUTINE TO GET EVM IF NEEDED FOR OUTPUT
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	PUSHJ	P,GTOEVM
;	RETURN HERE
;NEVER RETURN IF TO MUCH EVM IS REQUIRED

GTOEVM::SKIPA	T3,PDVOAD##	;POINTER TO UVA OF THE BUFFER
;	PJRST	GTBEVM		;MAP THE BUFFER IN EVM


;SUBROUTINE TO GET EVM IF NEEDED FOR INPUT
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	PUSHJ	P,GTIEVM
;	RETURN HERE
;NEVER RETURN IF TO MUCH EVM IS REQUIRED

GTIEVM::MOVE	T3,PDVIAD##	;POINTER TO UVA OF THE BUFFER
;	PJRST	GTBEVM		;MAP THE BUFFER IN EVM
;FALL INTO GTBEVM
;SUBROUTINE TO ACCOUNT FOR THE FACT THAT BUFFERS
; ARE TWO WORDS LONGER THAN THE NUMBER OF DATA
; WORDS IN THE BUFFER AND THE FACT THAT THE LINK
; WORD IS REALLY THE SECOND WORD OF THE BUFFER
;CALLING SEQUENCE:
;	MOVE	T3,POINTER TO THE CURRENT BUFFER (UVA)
;	PUSHJ	P,GTBEVM
;	RETURN HERE T1 = # OF PAGES + STARTING PAGE #, T3 = EVA OF BUFFER
;NEVER RETURN IF NOT ENOUGH EVM

GTBEVM:	PUSHJ	P,MAPDEV	;IS CURRENT DEVICE A PTY, TTY, OR ON A CHANNEL?
	POPJ	P,		;YES, DO NOT ALLOCATE ANY EVM
	PUSH	P,T3		;SAVE THE USER VIRTUAL ADDRESS OF THIS BUFFER
				; SO CAN RETURN EVM ON HUNG DEVICE, ETC.
	HRRZ	T3,@T3		;USER VIRTUAL ADDRESS OF THE BUFFER
	EXCTUX	<HLRZ T1,(T3)>	;SIZE OF THE BUFFER

	TRZ	T1,IOUSE	;T1 = NUMBER OF DATA WORDS - USE BIT
	SUBI	T3,1		;POINT TO ACTUAL FIRST WORD OF THE BUFFER
	ADDI	T1,2		;ACCOUNT FOR THE TWO OVERHEAD WORDS IN
				; THE BUFFER
	PUSHJ	P,GTEVBF	;MAP THE BUFFER IN EVM - WAIT UNTIL
				; SOME IS AVAILABLE IF NECESSARY
	  JRST	ADRERR##	;NEVER WILL BE ENOUGH EVM
	HRL	T1,@(P)		;SAVE USER VIRTUAL ADDRESS OF THE BUFFER
	ADDI	T3,1		;BUMP BUFFER ADDRESS TO THE LINK WORD
	PIOFF			;GUARD AGAINST INTERRUPTS
	MOVEM	T1,DEVEVM(F)	;SAVE THE STARTING PAGE NUMBER AND NUMBER
				; OF PAGES OF EVM FOR ADVANCING BUFFERS
				; AND RETURNING EVM
	DPB	T3,(P)		;STORE THE EVA OF THE BUFFER FOR THE DEVICE ROUTINE
	PION			;NOW, ALLOW INTERRUPTS AGAIN
	JRST	T2POPJ##	;RETURN

;SUBROUTINE TO RESTORE EVM AFTER GIVING IT
; UP ON A CALL TO THE SCHEDULER (CONTROL BUSY, HUNG DEVICE, ETC.)
;CALLING SEQUENCE:
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK
;	MOVE	S,DEVIOS(F)	;DEVICE STATUS
;	PUSHJ	P,RSTEVM
;	RETURN HERE IF NO ADDRESS CHECK WITH DEVEVM(F) SETUP

RSTEVM::LDB	T1,PIOMOD##	;GET DATA MODE
	CAIL	T1,SD		;DUMP MODE?
	PJRST	DMPEV		;YES, GET EVM DUMP MODE STYLE
	TLNE	S,IO		;BUFFERED MODE, INPUT OR OUTPUT?
	PJRST	GTOEVM		;OUTPUT, GET BUFFERED OUTPUT EVM
	PJRST	GTIEVM		;INPUT, GET BUFFERED INPUT EVM
;SUBROUTINE TO DETERMINE IF A DEVICE NEEDS EVM TO DO DUMP
; MODE I/O AND IF SO TO SCAN THE IOWD LIST TO FIND THE
; IOWD WHICH HAS THE LARGEST WORD COUNT AND ALLOCATE
; ENOUGH EVM TO COVER THAT IOWD.
;CALLING SEQUENCE:
;	MOVE	M,USER VIRTUAL ADDRESS OF IOWD LIST
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK
;	PUSHJ	P,DMPEV
;	RETURN HERE IF NO ADDRESS CHECK WITH DEVEVM(F) SETUP
;PRESERVES T1

DMPEV::	PUSHJ	P,SAVE4##	;SAVE P1-P4
	MOVE	P1,T1		;SAVE T1
IFN FTXMON,<
	HRRZ	T1,DEVISN(F)	;GET SECTION NUMBER FOR I/O
	PUSHJ	P,SVPCS##	;SAVE OLD PCS, SETUP PCS TO SEGMENT NUMBER FOR I/O
>
	PUSH	P,U		;SAVE U
	MOVEI	U,0		;ASSUME THE DEVICE DOES NOT REQUIRE EXEC VIRTUAL
				; MEMORY TO DO I/O (DSK, MTA, TTY, PTY)
	PUSHJ	P,MAPDEV	;NEED EVM TO DO I/O?
	  TLO	U,400000	;EVM NOT REQUIRED - SET U NEGATIVE
	PUSH	P,P1		;SAVE DISPATCH ADDRESS
	PUSH	P,M		;SAVE THE UUO FOR THE DEVICE ROUTINE
	SOS	M		;COMPENSATE FOR GETWD1
	MOVEI	P2,0		;LARGEST WORD COUNT SEEN SO FAR
	MOVEI	P3,1000		;GUARD AGAINST A LOOP (GOTO IOWDS)
DMPEV1:	PUSHJ	P,GETWD1##	;GET AN IOWD
	JUMPE	T1,DMPEV4	;JUMP IF LAST IOWD IN THE LIST
	HLRO	P1,T1		;THIS IOWD'S WORD COUNT
	TLNE	T1,-1		;A GOTO WORD?
	JRST	DMPEV2		;NO, A REAL IOWD
	HRRI	M,-1(T1)	;A GOTO WORD (POINTS TO THE NEXT IOWD)
	JRST	DMPEV3		;GET NEXT IOWD
DMPEV2:	MOVNS	P1		;P1 = POSITIVE WORD COUNT FOR THIS IOWD
	CAMLE	P1,P2		;GREATER THAN THE LARGEST WORD COUNT SEEN SO FAR?
	MOVE	P2,P1		;YES, REMEMBER IT AS LARGEST SEEN
	MOVEI	T1,1(T1)	;START ADR OF THE IOWD
	MOVE	T2,P1		;TOP ADR OF THE IOWD
	ADDI	T2,-1(T1)
	PUSHJ	P,TRNGE##	;MAKE SURE THE REQUIRED PAGES ARE IN CORE
DMPEV3:	SOJG	P3,DMPEV1	;GET NEXT IOWD IN THE LIST
	JRST	ADRERR##	;TOO MANY IOWDS (PROBABLY A GOTO WORD LOOP,
				; STOP THE JOB AND REPORT THE ERROR)
DMPEV4:	POP	P,M		;RESTORE THE UUO AND THE POINTER TO THE FIRST
				; IOWD IN THE LIST
	JUMPL	U,DMPEV5	;DONT ACTUALLY NEED EVM IF U NEGATIVE
	PUSHJ	P,GETWDU##	;GET THE FIRST IOWD IN THE LIST AGAIN
	MOVEI	T3,1(T1)	;USER VIRTUAL ADDRESS WHERE I/O WILL START
	MOVE	T1,P2		;NUMBER OF WORDS OF EXEC VIRTUAL MEMORY REQUIRED
				; TO COVER THE LARGEST IOWD FOUND IN THE IOWD
				; LIST
	PUSHJ	P,GTEVBF	;GET ENOUGH EVM TO COVER THE LARGEST WORD IN
				; THE LIST (WAIT UNTIL AVAILABLE IF NECESSARY)
	  JRST	ADRERR##	;WHOOPS! NEVER WILL BE ENOUGH
	MOVEM	T1,DEVEVM(F)	;DEVEVM = BYTE (18)0(9)EV PAGE #(9)# OF PAGES
DMPEV5:	POP	P,T1		;RESTORE DISPATCH ADDRESS
	JRST	UPOPJ##		;RESTORE U AND RETURN
;ROUTINE TO RETURN ANY EVM A DEVICE MAY HAVE WHEN A SHARABLE RESOURCE
; WHICH CURRENTLY BELONGS TO THE JOB WHICH HAS THE DEVICE IS GIVEN UP.
;CALLING SEQUENCE:
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK OR 0 IF NONE
;	PUSHJ	P,RTEVM
;ALL ACS ARE RESPECTED.

RTEVM::	SKIPE	F		;IS THIS A RESOURCE ASSOCIATED WITH I/O?
				; I.E., IS THERE A DEVICE DATA BLOCK?
	SKIPN	DEVEVM(F)	;DOES THE JOB HAVE EVM?
	POPJ	P,		;NO, JUST RETURN
	PUSHJ	P,SAVT##	;IT IS THE TRADITION NOT TO CLOBBER ACS HERE
	HRRZ	T1,P
	CAMLE	T1,SYSSIZ##	;DON'T CHANGE UBR IF P POINTS TO USER
	JRST	RTNEVM		;GIVE UP EVM FOR MAPPING I/O
	PUSHJ	P,SVEUF##	;SAVE THE UBR AND SET IT UP SO CAN ADDRESS CURRENT JOB
	PUSHJ	P,SPCS##	;ALSO, SETUP PCS
	PJRST	RTNEVM		;GIVE UP EVM FOR MAPPING I/O IF ANY

;HERE TO GIVE UP EVM THAT THIS DEVICE HAS FOR INPUT OPERATIONS

RTEVMI::HLRZ	T3,DEVEVM(F)	;USER VIRTUAL ADDRESS OF CURRENT BUFFER
	JUMPE	T3,CPOPJ##	;ZERO MEANS NO EVM REQUIRED FOR THE I/O
	PJRST	RTIEVM		;GIVE BACK THE EVM

;HERE TO GIVE UP EVM THAT THIS DEVICE HAS FOR OUTPUT OPERATIONS

RTEVMO::HLRZ	T3,DEVEVM(F)	;USER VIRTUAL ADDRESS OF CURRENT BUFFER
	JUMPE	T3,CPOPJ##	;ZERO MEANS NO EVM REQUIRED FOR THE I/O
	PJRST	RTOEVM		;GIVE BACK THE EVM
;ROUTINE TO RETURN SLOTS IN THE EXEC MAP USED TO MAP USER BUFFERS
;CALLING SEQUENCE:
;
;	MOVE	T3,USER VIRTUAL ADDRESS OF BUFFER
;	PUSHJ	P,RTNEVM
;	ALWAYS RETURN HERE

RTNEVM::MOVS	T3,DEVEVM(F)	;ANY EVM ALLOCATED TO THIS DEVICE?
	JUMPE	T3,CPOPJ##	;NO, JUST RETURN
	TRNN	T3,-1		;DUMP MODE I/O?
	JRST	RTNEV1		;YES, DON'T CLOBBER DEVXAD
	HRLI	T3,0
	TLNN	S,IO		;OUTPUT?
	JRST	RTIEVM		;NO, GO RETURN INPUT EVM
RTOEVM::DPB	T3,PDVOAD##	;STORE UVA IN DEVOAD
	JRST	RTNEV1		;RETURN EVM
RTIEVM::DPB	T3,PDVIAD##	;STORE UVA IN DEVIAD
RTNEV1:	HRRZ	T2,DEVEVM(F)	;PAGE NUMBER AND NUMBER OF PAGES OF EVM
	LDB	T1,[POINT 9,T2,35]
	SETZM	DEVEVM(F)	;FLAG NO LONGER ANY EVM
	PJUMPN	T1,GIVEVM	;RETURN THE EVM TO THE FREE POOL AND TELL
				; THE SCHEDULAR THAT EVM IS AVAILABLE IF ANY
				; JOB IS WAITING FOR SOME
	POPJ	P,		;RETURN


;ROUTINE TO CALL THE SCHEDULER AND REMEMBER IF A JOB HAS EVM OR NOT.
; IF SO, RESTORE THE EVM WHEN THE JOB BECOMES RUNNABLE AGAIN.
;PRESERVES ALL ACS

RMEVM::	SKIPE	F		;IS THERE A DDB?
	SKIPN	DEVEVM(F)	;AND DOES IT HAVE EVM?
	PJRST	WSCHD1##	;NO--JUST RESCHEDULE
	TRNE	S,IOACT		;DON'T RETURN EVM IF THE DDB
	JRST	WSCHD1##	; IS I/O ACTIVE
	PUSHJ	P,RTEVM		;YES--RETURN THE EVM SINCE JOB MAY GET SWAPPED
	PUSHJ	P,WSCHD1##	;RESCHEDULE
	PUSHJ	P,SAVT##	;SAVE T2-T4
	PJRST	RSTEVM		;RESTORE THE EVM
				;AND RETURN TO THE CALLER
;ROUTINE TO ADVANCE A BUFFER IN EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;
;	MOVE	T3,XWD NEXT BUFFER SIZE,NEXT USER VIRTUAL BUFFER ADDRESS
;	RETURN HERE IF NOT ENOUGH PAGES ALLOCATED IN EXEC MAP TO ADVANCE BUFFER
;	RETURN HERE - BUFFER ADVANCED
;			T1 = EXEC VIRTUAL ADDRESS OF BUFFER
;			T3 = USER VIRTUAL ADDRESS OF BUFFER

ADVEVM::PUSH	P,T3		;SAVE BUFFER SIZE,,BUFFER ADDRESS
	HRRZ	T1,DEVEVM(F)	;BYTE (18)0(9) EXEC VIRTUAL PAGE #(9)# OF EXEC PAGES
	HRLM	T3,DEVEVM(F)	;STORE UVA OF NEXT BUFFER
	HLRZ	T2,T3		;GET BUFFER SIZE
;DON'T NEED TO SUBTRACT 2 SINCE THE BUFFER IS ACTUALLY
; TWO WORDS LONGER THAN THE NUMBER OF DATA WORDS IT CONTAINS
;	SUBI	T2,2		;COMPUTE THE UPPER BOUND ON THE NUMBER
	IDIVI	T2,PAGSIZ+2	; OF PAGES WHICH MAY BE REQUIRED TO
	ADDI	T2,2		; MAP THIS BUFFER IN EXEC VIRTUAL MEMORY
	LDB	T3,[POINT 9,T1,35]
	CAMLE	T2,T3		;DOES THE DEVICE HAVE A ENOUGH EVM TO MAP THIS BUFFER?
	JRST	T3POPJ##	;NO, STOP THE I/O (ENOUGH PAGES WILL BE
				; AQUIRED THE NEXT TIME AROUND AT UUO LEVEL)
	LDB	T1,[POINT 9,T1,26]
	HRRZS	T3,(P)		;T3 = USER VIRTUAL ADDRESS OF THE NEXT BUFFER
	SOS	T3		;T3 = ADDRESS OF FIRST WORD OF THE BUFFER
	PUSHJ	P,MAPUEV	;MAP THE NEXT BUFFER IN THE EXEC MAP
	EXCH	T3,(P)		;RESTORE THE USER VIRTUAL ADDRESS OF THE
				; BUFFER IN CASE I/O MUST BE STOPPED FOR
				; SOME OTHER REASON
	AOS	(P)		;BUMP BUFFER POINTER TO THE LINK WORD
	PJRST	TPOPJ1##	;T1 = EXEC VIRTUAL ADDRESS OF THE BUFFER
;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::	PUSH	P,T2			;PRESERVE T2 AS ADVERTISED
	PUSHJ	P,CKSTRL		;ADDRESS CHECK THE STRING
	  JRST	T2POPJ##		;RETURN NON-SKIP
	AOS	-1(P)			;PROPAGATE SKIP RETURN
	JRST	T2POPJ##		;AFTER RESTORING T2


;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,CKSTRL
;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, T2=LENGTH OF STRING
;PRESERVES T3-T4

CKSTRL::PUSHJ	P,SAVE4##	;SAVE P1-P3
	SETZ	T2,		;INITIALIZE STRING LENGTH COUNTER
	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
	AOS	T2		;INCREMENT CHARACTER COUNT
	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,.USHVA	;HIGHEST VIRTUAL ADDR
NXCMR::	PUSHJ	P,SAVE4##	;SAVE P1-P4
	MOVEI	P4,0		;ZERO DEYISN
	DPB	P4,DEYISN##	; SINCE NOT MEANINGFUL FOR A NEW IOWD
	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
	PUSHJ	P,SPCS##	;ALSO SETUP PCS
	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,GETMWD##	;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:	JUMPL	J,NXCOK		;TRUST COMCON IF SAVE IN PROGRESS
	  			; DON'T ADDRESS-CHECK
	MOVEI	P2,1(T1)	;POINT TO REAL (SECTION-LOCAL) START
	HLRO	P3,T1		;SAVE ADDRESS POINTED TO AND NEGATIVE COUNT
	SKIPL	USRHCU##	;IF USER I/O,
	JRST	NXCHI2		;CHECK ANOTHER WAY
	CAMG	P2,T3		;IS START ABOVE PROTECTED AREA?
	JUMPN	P2,NXBAD	;NO. REPORT ERROR
	JRST	NXCHI3		;SKIP USER MODE CHECK
NXCHI2:	EXCH	T1,P2		;SAVE T1 AND SETUP TO CHECK ADDRESS
	PUSHJ	P,IADRCK	;IS THE START ADDRESS LEGAL?
	  JFCL			;NOT LEGAL AT ALL
	  JRST	NXBAD		;ILLEGAL FOR I/O
	EXCH	T1,P2		;RESTORE ACS
NXCHI3:	SETCA	P3,		;WORD COUNT MINUS ONE
	ADD	P2,P3		;END OF IO
	EXCH	P2,T1		;SAVE T1
	PUSHJ	P,IADRCK	;LEGAL?
	  JFCL			;BAD ADDRESS
	  JRST	NXBAD		;PAGE FAULT (SHOULDN'T HAPPEN SINCE LIST WAS CHECKED)
	MOVE	T2,T1		;TOP ADR FOR IO
	SKIPGE	USRHCU##	;SAVE IN PROGRESS?
	JRST	NXCHI1		;YES, IOWD LIST IS OK
	MOVEI	T1,1(P2)	;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)
NXCHI1:	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
	HRRM	T3,(P)		;STORE EXEC VIRTUAL ADDRESS IN IOWD
	POP	P,T1		;T1 = XWD -N,EXEC VIRTUAL ADDRESS FOR I/O
	TDZA	S,S		;FLAG CURRENT IOWD OK
NXOUT1:	MOVEI	T1,1		;SOJA WILL MAKE ZERO
	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::PUSH	P,T4		;PRESERVE CALLER'S T4
	PUSHJ	P,ASSASD	;DO THE WORK
	 JRST	T4POPJ##	;ERROR - RESTORE T4
	POP	P,T4		;RESTORE T4
	JRST	CPOPJ1		;SUCCESSFUL RETURN

ASSASD:
	PUSHJ	P,SAVE2##
	SETZB	P1,P2		;P1 WILL GET DEVMOD IF SPOOLING
	HRRZ	T3,SPLBIT##(F)	;POSSIBLE SPOOL-BIT
	MOVE	T4,J		;GET JCH
	ANDI	T4,JOBMSK##	;MASK DOWN TO A JOB NUMBER
	SKIPN	DEVCHR(F)	;FAKE (TABLE) DDB?
	JRST	ASSAS0		;YES, SPOOL IT
	LDB	T3,DEYSPL##	;SPOOL BIT FOR THE DEVICE
	SKIPL	DEVSPL(F)	;IS THIS A SPOOLED DISK DDB ?
	JRST	ASAS0A		;NO, GO ON
	TLO	T3,DEPSPL	;YES.  ENSURE COPY HAS DEPSPL ON
	SKIPA	P1,DEVMOD(F)	;GET THE SPOOLED MODES WORD
ASAS0A:	TDNN	T3,JBTSPL##(T4)	;JOB SPOOLING THIS DEVICE?
	JRST	ASSAS1		;NO
	MOVE	P2,T3		;SPOOL BIT
	LDB	T3,PJCHN##	;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:	SKIPGE	DEVSPL(F)	;SPOOLED?
	JRST	ASAS1B		;GENERATE A DDB
	MOVE	T4,DEVMOD(F)	;DEVMOD
	TLNE	T4,DVDSK	;DEVICE A DISK?
	JRST	ASAS1B		;YES
IFN FTNET,<
	TLNN	T4,DVTTY	;DEVICE A TTY?
	JRST	ASAS1A		;NO
	MOVE	T3,DDBLDB##(F)	;GET LDB POINTER
	JUMPE	T3,ASAS1A	;IF NONE, ALLOW THE ASSIGN
	SE1XCT	<SKIPGE LDBREM##(T3)> ;IF LOCAL LINE SET HOSTED AWAY
	JRST	ASSE11		;YES, ERROR - DEVICE NOT AVAILABLE
> ;END IFN FTNET
	JRST	ASSAS2		;SKIP DISK-ONLY STUFF
ASAS1B:	PUSHJ	P,SETDDB##	;YES, GENERATE A NEW DDB
	  JRST	ASSE16		;ERROR - NO MONITOR DDB SPACE
ASAS1A:
	HLLZS	T3		;LH(T3)=0 OR DEPSPL
	IORM	T3,DEVSPL(F)	;LIGHT SPOOL-BIT IF NEEDED
ASSAS2:	MOVEI	T3,DEPMSG
	TDNE	T3,DEVMSG(F)	;CONTROLLED BY MPX?
	JRST	ASSE55		;ERROR - DEVICE IN USE BY MPX
	NOSCHEDULE		;DISABLE SCHEDULING
	LDB	T1,PJCHN##	;GET JOB NUMBER IN DEV DATA BLOCK
	MOVEI	T4,ASSPRG	;BIT TO TEST
	TDNN	T4,DEVMOD(F)	;ASSIGNED BY PROGRAM?
	TRNN	T2,ASSCON	;ASSIGN COMMAND?
	SKIPA	T3,J		;NO--USE JCH FROM JOB DOING THE ASSIGN
	SKIPA	T3,T1		;COPY
	JRST	ASSA2Z		;SKIP SOME WORK IF CAN
	ANDI	T3,CTXMSK##	;KEEP ONLY THE JOB NUMBER
	MOVE	T4,J		;GET JCH
	ANDI	T4,JOBMSK##	;KEEP ONLY THE CONTEXT NUMBER
	IOR	T3,T4		;FORM JCH FROM DDB INFO
ASSA2Z:	TRNN	T1,CTXMSK##	;ANY CONTEXT SPECIFIED IN DDB?
	ANDI	T3,JOBMSK##	;NO, THEN ONLY COMPARE JOB #S
	CAMN	T1,T3		;IS IT ALREADY ASSIGNED TO THIS JOB
	JRST	ASSA2C		;YES--ASSIGN WINS
	MOVEI	T1,ASSPRG+ASSCON;NO, IS IT ASSIGNED TO ANOTHER JOB?
	TDNN	T1,DEVMOD(F)	;ARE EITHER ASSIGNED BITS SET?
	JRST	ASSA2Y		;PRESS ON
	LDB	T1,PJCHN##	;GET JOB/CONTEXT HANDLE
	TRZE	T1,CTXMSK##	;INITIED BY A CONTEXT?
	TRNE	T3,CTXMSK##	;AND INITING BY A CONTEXT?
	SKIPA			;NO GOOD
	CAIE	T1,(T3)		;SAME JOB NUMBER?
	JRST	ASSE47		;ASSIGNED TO ANOTHER JOB/CONTEXT
	LDB	J,PJCHN##	;FAKE OUT COMCON WITH JOB/CONTEXT HANDLE
ASSA2Y:	HRLZI	T1,DEPRAS	;GET RESTRICTED ASSIGNMENT BIT
	PUSH	P,J		;SAVE TARGET JCH
	TDNN	T1,DEVSTA(F)	;IS THIS DEVICE RESTRICTED?
	JRST	ASSA2A		;NO, PROCEED
	ANDI	J,JOBMSK##	;KEEP ONLY THE JOB NUMBER
	PUSHJ	P,PRVJ##	;THIS JOB PRIVILEDGED TO ASSIGN?
	  JRST	ASSA2A		;YES
	POP	P,J		;NO--RESTORE JCH
	JRST	ASSE50		;SET T2=-1 AS FLAG AND RETURN ERROR
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?
	TDNN	T1,DEVCHR(F)	;?
	JRST	ASSA2B		;NO--OK TO ASSIGN
	POP	P,J		;RESTORE JCH
	JRST	ASSE51		;ERROR - DEVICE CONTROLLED BY MDA
ASSA2B:
>;END IFN FTMDA
	POP	P,J		;RESTORE JCH
	DPB	J,PJCHN##	;STORE JCH IN DDB
	IORM	T2,DEVMOD(F)	;SET IN USE BITS
	JRST	ASSA2D		;ONWARD

ASSA2C:	DPB	J,PJOBN##	;STORE JOB IN THE DDB
	TRNN	T2,ASSCON	;ASSIGN COMMAND?
	DPB	J,PJCHN##	;STORE JCH IN THE DDB
ASSA2D:	TRNN	T2,ASSCON	;IF ASSIGN COMMAND,
	JRST	ASSAS3
	PUSH	P,T2		;SAVE FROM DESTRUCTION
	PUSHJ	P,TPMRES##	;RESET MAGTAPE DDB PARAMETERS
	POP	P,T2		;RESTORE ASSIGN BIT
ASSAS3:	IORM	T2,DEVMOD(F)	;SET IN USE BITS AGAIN IN CASE SAME JOB
	AOSA	(P)		;GIVE OK RETURN
ASSA4A:	HRREI	T2,-1		;FLAG AS RESTRICTED DEVICE
ASSAS4:	SCHEDULE		;TURN SCHEDULING ON
	POPJ	P,		;GIVE ERROR RETURN
ASSE11:	MOVEI	T4,DNAERR	;DEVICE-NOT-AVAILABLE ERROR
	POPJ	P,		;ERROR RETURN

ASSE16:	MOVEI	T4,NETERR	;NOT-ENOUGH-TABLE-SPACE ERROR
	POPJ	P,		;ERROR RETURN

ASSE47:	LDB	T1,PJCHN##	;REFETCH JOB NUMBER OWNING DESIRED DEVICE
	MOVEI	T4,DAJERR	;ASSUME IN USE BY ANOTHER JOB/CONTEXT
	JUMPN	T1,ASSAS4	;RETURN IF GUESSED RIGHT
	MOVEI	T4,DDUERR	;WRONG, JOB 0, DEVICE-DOWN (DETACHED) ERROR
	JRST	ASSAS4		;ERROR RETURN

ASSE50:	MOVEI	T4,DRSERR	;DEVICE-IS-RESTRICTED ERROR
	JRST	ASSA4A		;ERROR RETURN

ASSE51:	MOVEI	T4,DCMERR	;DEVICE-IS-MDA'ED ERROR
	JRST	ASSA4A		;ERROR RETURN

ASSE55:	MOVEI	T4,DUMERR	;DEVICE-IN-USE-BY-MPX ERROR
	POPJ	P,		;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,.USCTA
	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
;SUBROUTINE TO TERMINATE OWNERSHIP OF A DEVICE.  F POINTS TO THE
;  DDB.  PRESERVES J.

CLRDVL::LDB	T1,PJCHN##	;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,PJCHN##	;CLEAR JOB/CONTEXT HANDLE
	POPJ	P,		;EXIT.
;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
	CAIL	T1,FYSORG	;DDB LIVE WITHIN
	CAIL	T1,FYSORG+FYSSIZ ; FUNNY SPACE?
	SKIPN	.USJOB		;NO--IS A REAL JOB MAPPED?
	TRZA	F,-1		;NO MORE DDBS
	HLR	F,.USLST	;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 PHY,LOGNAMES,FLAG DEASSIGN

DEVDEA:	MOVEI	T2,DD%PHY+DD%LOG+DD%DEA
	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
;NOTE THAT ON SKIP-REUTURN, T2 IS SETUP WITH PREDECESSOR DDB ADDRESS.
;BE CAREFUL NOT TO BREAK THIS.

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

DEVPSN::MOVEI	T2,DD%PHY!DD%ALT ;SEARCH PHYSICAL AND SECONDARY UNITS
	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
	JRST	DVSRSP
DEVSRD::PUSHJ	P,DEVDEA	;SEARCH PHY,LOG,FLAG DEASSIGN
	TDZA	T3,T3		;NOT FOUND
	JRST	CPOPJ1##	;FOUND
;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)
	PJRST	DVASRC		;SEARCH FOR GENERIC, GIVE ERROR OR OK RETURN
;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
	S0PSHJ	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
	JUMPN	J,OPRFND	;IS J EQUAL TO 0?
	HLRZ	T2,LDBREM##(U)	;YES, GET NDB POINTER IF ANY
	SKIPE	T2		;IS HE LOCAL?
	HLRZ	T1,(T2)		;NO, GET NODE # FROM NDB.
	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!FTMPXSER,<
;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
	PUSH	P,T2		;SAVE IN LH OF CURRENT STACK WORD
	SKIPE	T1		;WHEN DONE - SKIP
	PUSHJ	P,CVTSB1	;RECURSIVELY DO ABOVE AGAIN
	POP	P,T1		;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
;KONUSN - RETURN USER TYPE (DD.XXX) GIVEN USER NAME (SIXBIT/XXX/)
;CALL IS:
;
;	MOVX	T1,<NAM>
;	PUSHJ	P,KONUSN
;	  ERROR RETURN
;	NORMAL RETURN
;
;WHERE <NAM> IS THE SIXBIT USER NAME (E.G., 'NOBODY', ETC.)
;
;ON ERROR RETURN, THE NAME IS UNKNOWN.
;
;ON NORMAL RETURN, T2 HAS THE USER TYPE (E.G., DD.NOB)
;
;USES T2.

KONUSN::MOVSI	T2,-DTNAML	;LENGTH OF TABLE OF NAMES TO SEARCH
	CAME	T1,DTNAME(T2)	;NAME MATCH?
	AOBJN	T2,.-1		;NO, SEARCH REST OF TABLE
	JUMPG	T2,CPOPJ##	;ERROR IF NO MATCH
	ANDI	T2,-1		;RETURN ONLY POSITIVE USER TYPE
	JRST	CPOPJ1##	;SUCCESSFUL RETURN


;DTNAMES - LINE "USER"S

DEFINE	X	(NAM),<
IFN .-DTNAME-DD.'NAM,<PRINTX ? DTNAME NAM entry out of order>
	SIXBIT\NAM\
> ;END DEFINE X

DTNAME::X	(NOBODY)
	X	(ANF)
	X	(DECNET)
	X	(PROGRA)
	X	(IBM)
DTNAML==.-DTNAME
;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 [ALLOW] PHYSICAL NAMES
;	DD%LOG		SEARCH FOR [ALLOW] LOGICAL NAMES
;	DD%CHN		DISALLOW DEVICES IN PER-PROCESS SPACE
;	DD%NDS		DISALLOW DISK-TYPE DEVICES
;
;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	;ALLOW LOGICAL NAMES
DD%PHY==:1B34	;ALLOW PHYSICAL NAMES
DD%CHN==:1B33	;DISALLOW PER-PROCESS DEVICES (DDBS)
DD%PHO==:1B32	;ON IF PHYSICAL ONLY
DD%DEA==:1B31	;DEASSIGN FLAG
DD%ALT==:1B30	;SEARCH ALTERNATE (SECONDARY) PORT FOR UNITS


DDBSRC:	TRNE	J,-1-JOBMSK##	;JCH?
	JRST	DDBSCC		;YES, GO SEARCH FOR DEVICE
	PUSH	P,T1		;SAVE DEVICE NAME
	PUSH	P,T2		;AND FLAGS
	PUSHJ	P,CTXJCJ##	;GET CURRENT CONTEXT FOR JOB NUMBER IN J
	  JUMPN	J,TTPOPJ##	;NO CONTEXT, NO DEVICES
	POP	P,T2		;RESTORE FLAGS
	EXCH	T1,(P)		;RESTORE DEVICE, SAVE JCH
	EXCH	J,(P)		;GET JCH, SAVE JOB NUMBER
	PUSHJ	P,DDBSCC	;SEARCH FOR DEVICE
	  JRST	JPOPJ##		;NO SUCH DEVICE
	JRST	JPOPJ1##	;FOUND RETURN

DDBSCC:	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
	MOVEI	F,.USLST-DEVSER ;SET PREDESSOR
DEVLP4:	HLRZ	F,DEVSER(F)	;GET A DDB ADDRESS
	JUMPE	F,NOLGST	;CONTINUE IF NO MORE
	PUSHJ	P,DDSCNM	;NAMES AND JCHS MATCH?
	  JRST	CPOPJ1##	;YES, FOUND RETURN
	JRST	DEVLP4		;GO CHECK OUT THE NEXT ONE
DEVLP7:	TRNN	P1,DD%PHY	;PHYSICAL?
	POPJ	P,		;NO, NOT FOUND
	TRZ	P1,DD%LOG	;YES, TURN OFF LOG
NOLGST:	PUSH	P,J		;SAVE JCH FOR COMPARISONS
	ANDI	J,JOBMSK##	;KEEP ONLY JOB NUMBER FOR TEST ROUTINES
	TLZ	P1,-1		;CLEAR PHONLY
	TRNN	P1,DD%PHY	;PHYSICAL SEARCH?
	JRST	DDSRC2		;NO DON'T SET UP
	TRNE	P1,DD%CHN	;DON'T LOOK AT DISKS IF SEARCHING ONLY DEVLST
	JRST	DDSRC0
	CAMN	T1,['SY    ']	;PDP-11 STYLE OF SYS:?
	MOVSI	T1,'SYS'	;YES, SUBSTITUTE HERE AS TSTDSK WON'T
				;(CK2CHR WOULD BUT WE DON'T WANT TO CALL IT HERE)
	PUSHJ	P,TSTDSK##	;IS THIS A DISK?
	  JRST	[TRNN	P1,DD%LOG  ;LOGICAL SEARCH?
		 JRST JPOPJ1##	 ;NO FOUND PHYSICAL
		 HRL	P1,F	;YES, SAVE DDB
		 JRST	.+1]	;AND CONTINUE
DDSRC0:	PUSHJ	P,TSTTSK##	;IS THIS A TSK DEVICE
	  CAIA			;NO, CONTINUE SEARCH
	JRST	JPOPJ1##	;YES, EXIT WITH F=DDB POINTER
	TDNN	T1,[77,,-1]	;IS THIS A 2-CHAR DEVICE NAME?
	PUSHJ	P,CK2CHR	;YES, CHECK FOR WEIRD NAMES
	PUSHJ	P,TSTOPR	;CHECK FOR "OPR"
	MOVSI	T3,DVDSK
DDSRC2:	DDBSRL
	HLR	F,DEVLST##	;GET START OF CHAIN
DDSC2A:	TRNN	P1,DD%LOG	;LOGICAL NAME SEARCH?
	JRST	GETPHY		;NO
	MOVE	J,(P)		;RETRIEVE JCH
	PUSHJ	P,DDSCNM	;YES, NAMES AND JCHS MATCH?
	  JRST	DDSRCV		;YES, CLEAR SYS BIT AND RETURN GOODNESS
	ANDI	J,JOBMSK##	;NO, BACK TO JOB NUMBER
GETPHY:	TRNN	P1,DD%PHY	;PHYSICAL SEARCH?
	JRST	DDSRC3		;NO, SKIP OVER THIS
	SKIPGE	DEVSPL(F)	;NO MATCH ON SPOOLED DDB'S
	JRST	DDSRC3		;IT IS A SPOOLED DDB

	TDNN	T3,DEVMOD(F)	;IF TSTDSK SAYS IT 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?
	JRST	JPOPJ##		;NO, AND WE DIDN'T FIND A LOGICAL MATCH
	HLRZ	F,P1		;YES, GET SAVED ADDRESS
IFN FTNET,<
	HLRZ	T2,DEVNAM(F)	;GET LH(NAME)
	TRNN	P1,DD%DEA	;UNLESS DEASSIGN,
	CAIE	T2,'TSK'	;DON'T MATCH AN OLD TSK DEVICE
> ;END IFN FTNET
	JUMPN	F,JPOPJ1##	;EXIT WITH PHYSICAL DDB MATCH IF THERE WAS ONE
IFN FTNET,<
	TRZE	P1,DD%LOG	;NO LONGER CARE ABOUT LOGICALS
	PUSHJ	P,TSTTSK##	;TRY THIS AGAIN
	  CAIA			;NO
	JRST	JPOPJ1##	;WIN WITH OUR TSK
	PUSHJ	P,TSTDDP##	;CHECK FOR DDP DEVICE
	  SKIPA			;NO
	JRST	JPOPJ1##	;YES
	PUSHJ	P,TSTRDX##	;CHECK FOR REMOTE DATA ENTRY ROUTINE
	  SKIPA			;NO
	JRST	JPOPJ1##	;YES,
	TRNN	T1,505050	;MUST BE NUMERIC RT HALF
	PUSHJ	P,TSTNET##	;YES CHECK FOR NETWORK DEVICE
	  SKIPA			;NOT A NETWORK DEVICE
	PJRST	JPOPJ1##	;YES, FOUND THE DEVICE ON THE NETWORK
>;END FTNET
IFN FTMPXSER,<
	PUSHJ	P,TSTMPX##	;NO, CHECK FOR MPX DDB
	  SKIPA			;NO--TRY FOR TTY
	JRST	JPOPJ1##	;YES--ALL DONE
>;END FTMPXSER
IFN FTKS10,<
	PUSHJ	P,TSTKDP##	;SEE IF IT'S A LEGAL KDP
	  SKIPA			;IT ISN'T
	JRST	JPOPJ1##	;IT IS. RETURN IT
	PUSHJ	P,TSTDMR##	;WELL, SEE IF A DMR
	 CAIA			;NO
	JRST	JPOPJ1##	;YES, SUCCESS
>;END FTKS10
IFN FTKL10,<
	PUSHJ	P,TSTDTE##	;DTE DEVICE?
	  SKIPA			;NO
	JRST	JPOPJ1##	;YES, ALL DONE
>
	CAME	T1,[SIXBIT /TTY/]	;IS THIS PUBLIC LOGICAL NAME TTY?
	JRST	GETDDB##	;SEE IF IT'S A TTY
	JUMPE	J,JPOPJ##	;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
	POP	P,U
	JRST	JPOPJ1##	;GOOD RETURN
DDSRCV:	TLZ	F,-1
DDSRCW:	DDBSRU
	JRST	JPOPJ1##
;SUBROUTINE TO SEE IF LOGICAL NAMES AND JCHS MATCH. ENTER F=DDB TO CHECK,
; EXIT CPOPJ IF THEY MATCH, CPOPJ1 IF THEY DON'T MATCH

DDSCNM:	JUMPE	F,CPOPJ1##	;NO MATCH IF F=0
	CAME	T1,DEVLOG(F)	;LOGICAL NAMES MATCH?
	JRST	CPOPJ1##	;NO
	LDB	T4,PJCHN##	;GET JCH
	CAMN	J,T4		;JCHS MATCH?
	POPJ	P,		;YES, WE HAVE A WINNER
	TRNN	T4,-1-JOBMSK##	;IF DDB DOESN'T CONTAIN A CONTEXT NUMBER (NOT
	XOR	T4,J		; INITED), MATCH ON JOB NUMBERS IS OK
	TRNE	T4,JOBMSK##	;DO THEY MATCH?
	AOS	(P)		;NO
	POPJ	P,		;RETURN
;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

;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##
;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
>
;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
IFN FTNET,<HLRZ	F,DEVLST>	;MAY ONLY BE A NETWORK DEVICE
IFE FTNET,<
	  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	;A PTY?
	JRST	DVST1		;YES, PTYS ARE AT THE CENTRAL SITE
	LDB	P1,PDVSTA##	;GET STA # FROM DDB
	CAME	P1,T2		;IS IT THE RIGHT STA?
	JUMPN	T2,DVSNXT	;NO - TRY NEXT DDB IF NOT 0 (REMSW=0)
DVST1:>
	HLLZ	P1,DEVNAM(F)	;MATCH ON LH OF NAME (GENERIC)
	TLNE	T1,77		;IS THIS A 2-CHAR NAME?
	JRST	DVST2
	PUSHJ	P,CKSPEC	;YES, CHECK FOR SPECIAL NAMES
	  JRST	DVST2A
	  JRST	DVST2		;NONE FOUND, CONTINUE
	PUSH	P,T3		;SAVE THIS
	CAMN	P1,[SIXBIT/LPT/]	;LL/LU
	JRST	DVLPTS		;IT'S A FUNNY LPT
	PUSHJ	P,TPMDVS##	;CONVERT 'MT' INTO 7 OR 9-TRACK EQUIVALENT
	  SETZ	T3,		;NOT A MAGTAPE?
	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 A 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		;NO - 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,PJCHN##	;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,FFAPPN##	;=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
;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 DEVICE 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
;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
	SETZ	F,		;DEVLG FAILED, CAN'T TRUST C(F)
	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
	PUSHJ	P,ALIASD##	;GENERIC DSK?
	  JRST	FPOPJ##		;YES, GIVE NON-SKIP RETURN
	TRNN	T1,-1		;DEV?
	JRST	GNRCD1		;CHECK GENTAB
	TRNN	T1,7700		;DEVN?
	JRST	FPOPJ1##	;CANNOT BE GENERIC IF 4 CHARACTERS LONG
	POP	P,F		;RESTORE F
	SKIPN	T1,DEVDRV(F)	;GET DRIVER DISPATCH
	POPJ	P,		;IF NO DISPATCH, ASSUME GENERIC
	MOVE	T1,DRVCNF(T1)	;GET INTERESTING BITS
	TRNN	T1,DR.NET	;DEVICE HAVE ENCODED ANF-10 STATION NUMBERS?
	AOS	(P)		;THEN 5 CHARACTER NAMES AREN'T GENERIC
	POPJ	P,		;RETURN

GNRCD1:	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
	HLRZS	P1		;PUT NAME IN RH
	DDBSRL			;INTERLOCK DDB SCANNING
	MOVE	P2,GENPTR##	;AOBJN POINTER TO GENERIC DDB TABLE
DVS2:	CAMN	P1,GENTAB##(P2)	;MATCH?
	JRST	DVS3		;YES, FOUND DEVICE
	AOBJN	P2,.+1		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	P2,DVS2		;KEEP SEARCHING
	JRST	DVS5		;NO, NONE ARE DEFINED
DVS3:	MOVE	F,GENTAB##+1(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
	DDBSRU			;RELEASE INTERLOCK
	HRLZS	P1		;RESTORE NAME TO LH
	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
;ATTACH UNIT RECORD DEVICE
DDBATT::SKIPN	DEVCHR(F)	;IS IT A "FAKE" DDB?
	POPJ	P,		;YES, CAN'T ATTACH SPOOLED DEVICE
	LDB	T1,PJOBN##	;GET JOB NUMBER
	MOVEI	T2,ASSCON	;BIT TO TEST
	TDNE	T2,DEVMOD(F)	;WAS DEVICE DETACHED?
	JUMPN	T1,RCNDAA	;IS IT JOB ZERO?
	ANDCAM	T2,DEVMOD(F)	;CLEAR ASSIGNED BY CONSOLE COMMAND BIT
	SETZM	DEVLOG(F)	;CLEAR LOGICAL NAME ASSIGNMENT
	DPB	T1,PJOBN##	;SET JOB NUMBER
	PUSHJ	P,TPMRES##	;RESET MAGTAPE DDB PARAMETERS
	JRST	CPOPJ1##	;RETURN SUCCESS


;DETACH A UNIT RECORD DEVICE
DDBDET::MOVEI	T2,ASSPRG	;BIT TO TEST
	TDNE	T2,DEVMOD(F)	;DEVICE IN USE?
	POPJ	P,		;CAN'T DETACH IT
	LDB	T3,PDVTYP##	;GET DEVICE TYPE
	CAIE	T3,.TYPTY	;IS IT A PTY?
	TLNE	T2,DVTTY	;IS IT A TTY?
	POPJ	P,		;YES, ILLEGAL DEVICE
	MOVEI	T2,ASSCON	;FOUND-SET UP ASSIGNED BY CONSOLE
	PUSHJ	P,ASSASG	;TRY TO ASSIGN
	  POPJ	P,		;CAN'T ASSIGN
	SKIPGE	DEVSPL(F)	;SPOOLED?
	PJRST	CLRDDB##	;ERROR WHEN DEVICE IS SPOOLED
	TLNE	F,SYSDEV	;IS THIS SYSTEM DEVICE?
	POPJ	P,		;YES, ILLEGAL DEVICE
	MOVEI	T1,0		;NO. SET JOB NUMBER TO ZERO
	DPB	T1,PJOBN##	; ..
	JRST	CPOPJ1##	;RETURN SUCCESSFUL
	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.
;ENTER AT BUFCLF WITH T1 = WHERE TO BUILD BUFFERS
;IF U IS NON-ZERO, SETUP BUFFERS (U) SIZE, IF U IS ZERO, USE DEFAULT BUFFER SIZE

BUFCLF:	PUSH	P,.JDAT+JOBFF##	;SAVE JOBFF
	HRRM	T1,.JDAT+JOBFF##;WHERE TO SETUP THE RING
	PUSHJ	P,BUFCLC	;SETUP THE RING
	POP	P,.JDAT+JOBFF##	;RESTORE JOBFF TO ORIGINAL VALUE
	POPJ	P,		;AND RETURN
;HERE TO ACTUALLY BUILD THE USER'S BUFFER RING STRUCTURE, ALLOCATING
;MEMORY AS NEEDED BASED ON USER'S .JBFF

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
	SKIPN	P3,U		;BUFFER SIZE SUPPLIED BY THE USER?
	LDB	P3,PBUFSZ##	;NO, P3=DEFAULT BUFFER SIZE
	HRRZ	P1,.JDAT+JOBFF##;P1:=FIRST FREE LOCATION
	ADDI	P1,1		;P1:=FIRST BUFFER'S LINK (.BFHDR) WORD
	HRRZ	P2,P1		;WORKING COPY FOR LINKING RING
	HRL	P2,P3		;P2:=BUFFER SIZE,FIRST FREE LOC + 1
	ADDI	P3,2		;P3:=BUFFER SIZE + 2 (INCLUDE .BFSTS & .BFHDR)
	HRRZ	T2,M		;T2:=N="E" FIELD OF AC UUO=COUNT OF BUFFERS
	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		;TIMES NO. OF BUFFERS
	ADDI	T1,0(P2)	;ADD LOCATION OF 1ST BUFFER
	SUBI	T1,1		;READJUST FOR USRREL COMPARISON
	TLZE	T1,-1		;CHECK IF HE WENT OVER 256K
	PJRST	ADRERR##	;BETTER NOT ALLOW THAT!
	MOVE	T2,T1		;SAVE HIGHEST ADDRESS IN THE RING
	MOVEI	T1,-1(P1)	;START ADDRESS OF RING INCLUDING FIRST "S WORD"
BUFCL0:	PUSHJ	P,IADRCK	;SEE IF PAGE EXISTS AND IS IN CORE
	  JRST	BUFCL4		;DOESN'T EXIST OR ILLEGAL
	  JRST	UUOFLT##	;PAGED OUT
	TRZ	T1,PG.BDY	;ROUND DOWN
	ADDI	T1,PAGSIZ	;NEXT PAGE
	CAMG	T1,T2		;CHECKED ALL THE NEEDED PAGES?
	JRST	BUFCL0		;NO, CHECK THE NEXT PAGE
	JRST	BUFCL5		;HAVE ENOUGH CORE, GO CREATE RING
;MUST ALLOCATE USER MEMORY TO HOLD THE RING

BUFCL4:	PUSH	P,M		;SAVE A BUNCH OF ACS USED IN CORE AND IO WAIT
	PUSH	P,F
	PUSH	P,T4
	PUSHJ	P,ALCORE	;TRY TO ASSIGN CORE
	POP	P,T4
	POP	P,F
	POP	P,M
	MOVE	S,DEVIOS(F)	;ALCORE MAY HAVE ALLOWED S TO BE CHANGED

;MEMORY ALLOCATED, BUILD THE RING STRUCTURE

BUFCL5:	HRRZ	T1,P2		;FIRST ADDRESS
	PUSHJ	P,LRNGE##	;MAKE SURE ALL PAGES ARE IN CORE
	HRRZ	T2,P2		;SAVE FIRST ADDRESS + 1
BUFCL6:	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,BUFCL6	;N:=N-1.  IS N GR 0?
	HRR	P2,T2
	MOVEI	T1,-2(P1)	;CHECK LAST ADR. OF HEADER
	PUSHJ	P,UADRCK
	SUB	P1,P3
IFN FTMPXSER,<MOVE T4,P1>	;T4 = ADDRESS OF LAST BUFFER
	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 ALLOCATE CORE TO BUILD A BUFFER RING
;CALL WITH T1=WHERE TO BEGIN ALLOCATION, T2=HIGHEST ADDRESS IN RING
;RETURNS T2=HIGHEST ADDRESS IN THE RING

ALCORE::PUSHJ	P,SAVE4##	;ACS MIGHT GET CLOBBERED BY THE UUO
	MOVE	P1,T1		;SAVE T1
	XSFM	T1		;SAVE PCS, SET IT TO CURRENT VALUE
IFN FTXMON,<PUSHJ P,SVPCS##>	;SAVE PCS AND SET IT TO ZERO
	MOVE	T1,P1		;RESTORE T1
	EXCTUX	<PUSH P,P1>	;SAVE USER ACS FOR UUO ARGUMENTS
	EXCTUX	<PUSH P,P2>
	EXCTUX	<PUSH P,P3>
	PUSH	P,T2		;SAVE HIGHEST ADDRESS
	PUSH	P,.USCTA	;THE PAGE UUO CLOBBERS THIS
	PUSH	P,.USMUO	; AND THIS ONE TOO
	LSH	T1,W2PLSH	;STARTING PAGE NUMBER
	LSH	T2,W2PLSH	;ENDING PAGE NUMBER
	SUBI	T2,-1(T1)	;T2:=NUMBER OF PAGES NEEDED
	EXCTXU	<MOVNM T2,P2>	;SET NEGATIVE/REPEAT PAGE. COUNT
	XSFM	T2		;GET FLAGS AND PCS
	ANDI	T2,MXSECN	;ISOLATE PCS
	LSH	T2,P2WLSH	;BIG PAGE NUMBER
	IOR	T2,T1		;<SECTION NUMBER>B27+<PAGE NUMBER>B35
	TLO	T2,(PG.IDC)	;DON'T CARE IF PAGES ALEREADY EXIST
	EXCTXU	<MOVEM T2,P3>	;STORE STARTING SECTION/PAGE NUMBER
ALCOR1:	MOVE	T1,[.PAGCD,,P2]	;CREATE A PAGE
	EXCTXU	<MOVEM T1,P1>	;STORE PAGE UUO ARGUMENT LIST
	PAGE.	P1,		;CREATE THE [PHYSICAL] PAGE(S)
	  CAIA			;OOPS, SEE IF NEED TO GO VIRTUAL
	JRST	ALCOR6		;NEW MEMORY ALLOCATED SUCCESSFULLY
	EXCTUX	<MOVE T1,P1>	;RETRIEVE PAGE. UUO ERROR CODE
	CAIE	T1,PAGLE%	;"CORE LIMIT EXCEEDED"?
	JRST	ALCOR6		;NOPE, FLICK IT IN
	MOVSI	T1,(PG.DSK+PG.IDC) ;PA.GCD - CREATE ON DISK ('VIRTUAL') FLAG
	EXCTXU	<IORM T1,P3>	;MODIFY ORIGINAL REQUEST
	MOVE	T1,[.PAGCD,,P2]	;PAGE. UUO ARGUMENT POINTER
	EXCTXU	<MOVEM T1,P1>	;STORE PAGE. UUO ARGUMENT LIST
	PAGE.	P1,		;CREATE THE [VIRTUAL] PAGE(S)
	  JFCL			;IGNORE ERROR,
				;  IF ILLEGAL PAGE NUMBER OR NOT ENOUGH CORE,
				;  AN ADDRESS CHECK WILL OCCUR
ALCOR6:	POP	P,.USMUO	;RESTORE PER-PROCESS INFO THAT
	POP	P,.USCTA	; THE PAGE. UUO CLOBBERED
	POP	P,T2		;RESTORE HIGHEST ADDRESS
	EXCTXU	<POP P,P3>	;RESTORE USER ACS
	EXCTXU	<POP P,P2>
	EXCTXU	<POP P,P1>
	POPJ	P,		;AND 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
	MOVSI	T4,DEPLBF##
	TDNE	T4,DEVLBF##(F)	;LARGE BUFFERS?
	SKIPA	T2,NUMLBF##	;YES, USE NUMLBF
	MOVE	T2,NUMBF##	;NO, USE NUMBF
	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##
	HRRZ	T1,T2
	POP	P,T2		;RESTORE FIRST ADR.
	NOSHUFF			;NO SHUFFLING
	EXCTXU	<SETZM 1(T2)>	;CLEAR THE THIRD WORD
	HRLI	T2,1(T2)
	ADDI	T2,2
	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,URELEA	;RELEASE ALL IO DEVICES

;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
	PUSHJ	P,SSEC0##	;DON'T REALLY NEED S0, BUT ROUTINE IN T1 IS
				;S0 BASED AND WE WANT TO RETURN TO S1 IF THAT
				;WHERE WE WERE CALLED FROM
	PUSH	P,T1		;SAVE ADR. OF SUB.
	PUSH	P,M		;SAVE M
	HLRZ	P3,.USCTA
	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
IOALL0:	MOVSI	M,FLMCOM	;DON'T RETURN ERROR CODES TO USER
	HRRZ	T1,.USCTA
	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,.USCTA
	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,.USCTA
	JUMPE	P2,IOALL2
	HRLI	P2,-HIGHXC+20
	MOVEI	P1,20
	JRST	IOALL0
IOALL2:	HRLM	P3,.USCTA
	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 FTMPXSER,<
	MOVEI	T1,DEPMSG	;LOAD UP THE MESSAGE BIT
	TDNN	T1,DEVMSG(F)	;CONTROLLED BY MPXSER?
	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 FTMPXSER
	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,
>
;ROUTINE TO PERFORM HUNG DEVICE CHECKING

DEVCHK::PUSHJ	P,SAVE1##	;SAVE P1
	MOVSI	P1,-TYPMAX-1	;AOBJN POINTER

DEVCK1:	SKIPN	F,DDBTAB##(P1)	;GET A DDB
	JRST	DEVCK4		;TRY NEXT DEVICE TYPE
	LDB	T1,PDVTIM##	;PROTOTYPE--GET POSSIBLE HUNG TIMER VALUE
	JUMPE	T1,DEVCK4	;THIS TYPE OF DDB DOESN'T QUALIFY
	SKIPE	DEVNAM(F)	;IF IT HAS A NAME,
	JRST	DEVCK3		;START HERE (AND ASSUME IT NEEDS THE TIMING)

DEVCK2:	HLRZ	F,DEVSER(F)	;LINK TO NEXT DDB
	JUMPE	F,CPOPJ##	;END OF CHAIN?
DEVCK3:	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIN	T1,(P1)		;SAME GROUP?
	JRST	DEVCK5		;YES

DEVCK4:	AOBJN	P1,DEVCK1	;ADVANCE TO NEXT DEVICE TYPE
	POPJ	P,		;DONE

DEVCK5:
IFN FTMP,<
	PUSHJ	P,CHKCPI##	;DEVICE ON THIS CPU?
	  JRST	DEVCK2		;NO, IGNORE IT
	CAME	T1,.CPBIT##	;THE ONLY CPU?
	PUSHJ	P,ISITQ		;NO, QUEUED PROTOCAL?
	  JRST	DEVCK6		;NO
	CAIN	T1,PCLCP0##	;YES, DID I/O START ON THIS CPU?
	MOVEI	T1,0
	CAME	T1,.CPCPN##
	JRST	DEVCK2		;NO, LET OTHER CPU HANDLE IT
> ;END IFN FTMP
DEVCK6:	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	DEVCK7		;IT IS
	MOVSI	T1,DVOFLN	;ITS ON-LINE, CLEAR THE OFF-LINE BIT
	ANDCAM	T1,DEVCHR(F)
	PUSHJ	P,PSIONL##	;TELL THE USER ITS ON-LINE IF HE'S INTERESTED

DEVCK7:	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		;YES
	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
	JRST	DEVCK2		;ON TO THE NEXT DEVICE
;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
	CAIN	T1,A8		;8-BIT ASCII 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 FTMPXSER,<
	MOVEI	T1,DEPMSG	;CONTROLLED BY MPXSER ?
	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,
;HERE FROM FILOP.
FOPSST:	HRRZ	T1,FOPFLG
	CAIGE	T1,2
	JRST	FOPILU
	PUSHJ	P,GETWD1##
	HRR	M,T1
	AOS	(P)		;GOOD RETURN

;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
	  JRST	ILLMOD##	;BOMB THE USER JOB
	TRZ	M,IOACT		;LET USER SET ALL BITS EXCEPT IOACT
	MOVE	T1,DEVMOD(F)	;GET DEVICE TYPE BITS
	TLNE	T1,DVDSK	;IF A DISK
	TRZ	M,IOSFA##	;DON'T LET USER SET IOSFA EITHER
	HRRM	M,DEVIOS(F)
	MOVE	S,DEVIOS(F)	;SET UP "S" SINCE WE JUST CHANGED DEVIOS
	TLNE	T1,DVTTY	;IS IT A TTY
	TLNE	T1,DVDSK	;  AND NOT A DISK (NUL)?
	POPJ	P,
	MOVE	U,DDBLDB##(F)	;YES, SET UP U
	JUMPE	U,CPOPJ##	;FORGET IT IF DETACHED
	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)
	TDNN	T1,DEVMOD(F)
	POPJ	P,		;ILL DATA MODE
	JRST	CPOPJ1##	;DATA MODE OK, SUCCESSFUL RETURN



;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

	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,1000		;ASSUME BYTE MODE
	LDB	T2,PIOMOD##	;GET MODE FROM S
	CAIE	T2,A8		;8-BIT OR BYTE MODE
	CAIN	T2,BYTMOD	;IS IT ?
	POPJ	P,		;YES, RETURN
	TRNN	S,14		;IS MODE LESS THAN 10?
	HRLI	T1,700		;YES,ASCII OR ASCII LINE
	TRNE	S,14		;10 OR GREATER?
	HRLI	T1,4400		;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	;PIM ON MPX
	CAIN	T2,.TYTTY	;TEST
	HRLI	T1,1000		;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
SUBTTL	SUPPORT FOR THE DDB SCANNING INTERLOCK


IFN FTMP,<

;INTERLOCK DDB SCANNING
DDBLOK::CONI	PI,.CPDBI##	;SAVE STATE OF INTERRUPT SYSTEM
	CONO	PI,DSKPIF##	;TURN OFF DISK PI CHANNEL
	SKIPGE	INTRDD##	;AVOID DMA OVERRUNS
	AOSE	INTRDD##	;BUSY
	JRST	.-2		;SPIN
	APRID	INTODD##	;REMEMBER INTERLOCK OWNER
	POPJ	P,		;RETURN


;RELEASE INTERLOCK
DDBULK::SETOM	INTRDD##	;RELEASE INTERLOCK
	SETOM	INTODD##	;RESET INTERLOCK OWNER
	EXCH	T1,.CPDBI##	;GET SAVED PI SYSTEM STATE
	ANDI	T1,177		;ISOLATE CHANNELS
	TRO	T1,PI.TNP	;TURN ON SELECTED PIS
	EXCH	T1,.CPDBI##	;RESTORE T1
	CONO	PI,@.CPDBI##	;RESTORE PI SYSTEM STATE
	POPJ	P,		;RETURN

> ;END IFN FTMP
	$CSUB

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

	$HIGH
	XLIST
	$LIT
	LIST
UUOEND::END