Google
 

Trailing-Edge - PDP-10 Archives - PCL_FOR_701 - psiser.mac
There are 7 other files named psiser.mac in the archive. Click here to see a list.
TITLE	PSISER -- PROGRAMMED SOFTWARE INTERRUPT SERVICE   V216
SUBTTL	C. D. O'TOOLE/CDO    08 JUL 79

	SEARCH	F,S
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

XP VPSISR,216
PSISER:	ENTRY	PSISER

	XP	PSIMPI,3	;MAXIMUM PRIORITY LEVEL

	IFL	PSIMPI,<PRINTX ? PSIMPI CANNOT BE NEGATIVE
				XP PSIMPI,0>
	IFG	<PSIMPI-3>,<PRINTX ? PSIMPI CANNOT BE .GT. 3
				XP PSIMPI,3>
	IFL	<^D35+C$MIN>,<PRINTX ? TOO MANY CONDITIONS FOR THIS EDIT
				XP C$MIN,-^D35>

	IFN	PSIMPI,<
		CNDSIZ==7	;SIZE OF BYTE FOR OFFSET
		PSIMVO==:^D127*4 ;MAX VECTOR OFFSET ( FOR GETTAB )
	>
	IFE	PSIMPI,<
		CNDSIZ==9	;SIZE OF BYTE FOR OFFSET
		PSIMVO==:^D511*4 ;MAX VECTOR OFFSET (FOR GETTAB )
	>
DEFINE	BITS(NAME,X),<NAME==0
		IRP X,<NAME==NAME!1B<-C$'X>>>

;REPRESENT ALL VALID PSI CONDITIONS (CAN REMOVE WHEN NO HOLES)

BITS(ZZ1,<TLE,CTLC,AUUO,IUUO,IMR,ADCK,ARIT,PLOV,APRC,UEIJ,XEIJ>)
BITS(ZZ2,<KSYS,DSET,DATT,WAKE,ADRB,IPC,QUE,NTC,NXM,JBI>)
VLDBIT==ZZ1!ZZ2


;THE FOLLOWING CONDITIONS ARE IGNORED WHEN IN PFH OR CANNOT BE
;	GRANTED IMMEDIATELY.  C$TLE IS INCLUDED AND IS SPECIAL CASED.
;	IF A CONDITION IS IGNORED, IT CAN BE FATAL TO THE JOB (C$IMR).

BITS(IMBITS,<AUUO,TLE,IUUO,IMR,ADCK,ARIT,PLOV,APRC,UEIJ,XEIJ,ADRB,NXM>)


;THE FOLLOWING IMMEDIATE CONDITIONS FIND THE USERS PC IN JOBPD1.
;	ALL OTHERS GET THE PC FROM .CPPC

BITS(PD1BIT,<AUUO,IUUO,ADCK,UEIJ>)


;THE FOLLOWING CONDITIONS HAVE A STANDARD MESSAGE ASSOCIATED WITH THEM
;	AND WILL BE DEFERRED UNTIL AFTER PRINTING IF THE USER REQUESTED
;	THE MESSAGE.  ALL CONDITIONS HERE MUST ALSO BE IN IMBITS.

BITS(MSGBIT,<TLE,IUUO,IMR,ADCK,PLOV,UEIJ,XEIJ,ADRB,NXM>)

IFN <<IMBITS&MSGBIT>-MSGBIT>,<
	IMBITS==IMBITS		;SHOW BITS IN LISTING
	MSGBIT==MSGBIT		;SHOW BITS IN LISTING
	PRINTX ? MESSAGE CONDITIONS MISSING FROM IMMEDIATE CONDITIONS>

;SOME BITS FOR EASY TESTS AGAINST ENABLED CONDITIONS FOR THE USER
	BITS(APRBIT,<ARIT>)
	BITS(AUUBIT,<AUUO>)
	BITS(TLEBIT,<TLE>)
	BITS(JBIBIT,<JBI>)
	BITS(QUEBIT,<QUE>)
	BITS(WAKBIT,<WAKE>)
	BITS(CTCBIT,<CTLC>)
SUBTTL	DATA STRUCTURES

;USER INTERRUPT BLOCK FORMAT

	PHASE	0
.PSVNP:! BLOCK	1		;USERS NEW PC
.PSVOP:! BLOCK	1		;USERS OLD PC
.PSVFL:! BLOCK	1		;INTERRUPT CONTROL FLAGS
				; 0-17 ARE CONTROL FLAGS
				;18-35 ARE REASONS FOR DEVICE INTERRUPTS
	PS.XXX==1B0		;*** RESERVED
	PS.VPO==1B1		;TURN OFF UNTIL PISYS. TURNS IT BACK ON
	PS.VTO==1B2		;TURN OFF HIGHER LEVELS UNTIL DEBRK.
	PS.XXX==1B3		;*** RESERVED
	PS.VDS==1B4		;DISMISS ANY OTHER PENDING AT DEBRK.
				;  FOR THE CONDITION IN PROGRESS
	PS.VPM==1B5		;PRINT APPROPRIATE MESSAGE FOR THIS CONDITION
	PS.XXX==1B6		;*** RESERVED
.PSVIS:! BLOCK	1		;INTERRUPT STATUS WORD
	DEPHASE

;THE FOLLOWING DATA BASE IS BUILT FOR EACH USER OF PSISER.
;JBTPIA(J) CONTAINS CONTROL FLAGS AND THE ADDRESS OF THE TABLE.

	PHASE	0
PITNPI:! BLOCK	1		;NUMBER OF PENDING INTERRUPTS (MUST BE FIRST)
PITSTS:! BLOCK	1		;  0   1 IF ^C FROM TI WAIT
				; 1-8  FREE
				; 9-17 WAKING JOB FOR C$WAKE
				;18-35 REQUEST ID FOR C$QUE
PITST2:! BLOCK	1		;ENTIRE WORD USED FOR PIJBI. UUO
PITIVA:! BLOCK	1		; 0-8  HIGHEST VECTOR IN USE
				; 9-17 MUST BE ZEROS
				;18-35 ADDRESS OF USERS BASE
IFN PSIMPI,<
PITHLP:! BLOCK	1		;HIGHEST LEVEL IN PROGRESS ( -1 IF NONE )
>
PITCIB:! BLOCK	<PSIMPI+1>	;RH = CURRENT INTERRUPT BLOCK
				;LH = CURRENT CONDITION
				;***** IF DDB ADDRESS GO BEYOND 377777,
				;       THIS WON'T WORK ANYMORE *****
PITCHN:! BLOCK	1		;LH = DEVICE CHAIN FOR "ADDED" DEVICES
				;RH = FLAG DURING PRINTING OF ERROR MESSAGE
PITENB:! BLOCK	1		;BIT MAP FOR ENABLED CONDITIONS (NON-DEVICE)
PITPND:! BLOCK	1		;BIT MAP FOR PENDING CONDITIONS (NON-DEVICE)
PITMSG:! BLOCK	1		;BIT MAP FOR WANTED MESSAGES (NON-DEVICE)
PITTAB:! BLOCK	<<-C$MIN+1>+3>/4 ;9 BITS FOR EACH NON-DEVICE CONDITION
				;  CONTAINS RELATIVE OFFSET INTO USERS VECTOR
PITSIZ::!			;SIZE OF THE DATA BASE IN WORDS
PIT4WD==<PITSIZ+3>/4		;SIZE IN 4 WORD BLOCKS
	IFN	PITNPI,<PRINTX ? PITNPI IS NOT FIRST IN THE DATA BASE>
	DEPHASE

	RELOC	PSISER
SUBTTL	UUOCON INTERFACE -- PIINI.

;CALL TO INIT THE PI SYSTEM
;CALL WITH:
;	MOVEI	AC,BASE-ADDRESS-OF-INTERRUPT-VECTOR
;	PIINI.	AC,
;	  HERE IF SYSTEM NOT AVAIL
;	NORMAL RETURN IS HERE

PIINI::	MOVEI	T1,(T1)		;ISOLATE THE BASE ADDRESS
	PUSH	P,T1		;SAVE USER ARGUMENT
	PUSHJ	P,CLRPSI	;CLEAR OLD DATA
	MOVEI	T2,PIT4WD	;NUMBER OF 4-WORD BLOCKS TO GET
	PUSHJ	P,GET4WD##	;GO GET THEM
	  JRST	TPOPJ##		;CAN'T
	HRLI	T2,(T1)		;PREPARE TO CLEAR THE DATA BASE
	HRRI	T2,1(T1)	;DESTINATION
	SETZM	0(T1)		;CLEAR THE BEGINNING
	BLT	T2,PITSIZ-1(T1)	;CLEAR THE REST
IFN PSIMPI,<SETOM PITHLP(T1)>	;SET INTERRUPT LEVEL TO -1
	POP	P,PITIVA(T1)	;BASE OF VECTOR
	HRRZM	T1,JBTPIA##(J)	;STORE ADDRESS IN HANDY PLACE
	JRST	CPOPJ1##	;GOOD RETURN

;SUBROUTINE TO CLEAR THE SOFTWARE INTERRUPT SYSTEM
;CALL WITH:
;	J = JOB #
;	PUSHJ	P,CLRPSI
;	RETURN HERE ALWAYS

CLRPSI::HRRZ	T2,JBTPIA##(J)	;GET ADDRESS OF PIT
	JUMPE	T2,CPOPJ##	;RETURN IF ZERO
	HLRZ	F,PITCHN(T2)	;GET START OF PSI DDBS
	SETZM	JBTPIA##(J)	;CLEAR USERS TABLE NOW
	MOVEI	T1,PIT4WD	;NUMBER OF 4-WORD BLOCKS WE HAVE
	PUSHJ	P,GIV4WD##	;RETURN THE CORE
CLRP.1:	JUMPE	F,CPOPJ##	;RETURN WHEN OUT OF DDBS
	SETZM	DEVPSI(F)	;CLEAR INTERRUPT BITS
	HLRZ	F,DEVESE(F)	;STEP TO NEXT DDB
	JRST	CLRP.1		;LOOP OVER ALL DDBS
SUBTTL	UUOCON INTERFACE -- PISYS.

;CALL TO MANIPULATE THE PI SYSTEM
;CALL WITH:
;	MOVE	AC,[XWD FLAGS,ADDRESS]
;	PISYS.	AC,
;	  HERE ON AN ERROR
;	HERE WHEN FUNCTION COMPLETE
;
;ADDR:	CONDITION-REQUESTED OR DEVICE-ENABLED (CHANNEL,DEVNAM,UDX)
;	OFFSET-FROM-BASE(PIINI.) ,, REASONS-IF-DEVICE
;	PRIORITY LEVEL ,, 0

PISYS::	PUSHJ	P,SAVE4##	;SAVE A FEW FIRST
	TRNE	T1,-1		;ANY ADDRESS GIVEN?
	TLNE	T1,(PS.CSI!PS.RDV!PS.ADV) ;IS ARGUMENT NEEDED?
	SKIPA			;YES
	PJRST	RTZER##		;(0) UNNECESSARY ARG SUPPLIED
	TLNN	T1,(PS.ALL)	;ANYTHING TO DO?
	PJRST	ECOD1##		;(1) NO FUNCTION GIVEN
	TLNE	T1,<-1-PS.ALL>_<-^D18> ;ANY UNUSED BITS SET?
	PJRST	ECOD2##		;(2) UNUSED BIT IS NOT = 0
	SKIPN	P1,JBTPIA##(J)	;PIINI. UUO DONE?
	JRST	ECOD13##	;(13) PIINI. UUO NOT DONE
	MOVE	P2,T1		;COPY ARGUMENT
	TLNE	P2,(PS.CPI)	;CLEAR PENDING INTERRUPTS?
	PUSHJ	P,CLRAPI	;YES, CLEAR ALL PENDING INTERRUPTS
	TLNE	P2,(PS.CSI)	;CLEAR FOR 1 CONDITION OR DEVICE?
	JRST	[PUSHJ P,CLRSPI	;YES, CLEAR PENDING INTERRUPT
		   POPJ P,	;ILLEGAL CONDITION OR DEVICE
		 JRST .+1]	;RESUME INLINE CODE
	MOVSI	T1,(SI.ON)	;PI SYSTEM ON BIT
	TLNE	P2,(PS.ON)	;WANT TO TURN ON?
	JRST	[TLNE P2,(PS.OFF) ;TURN SYSTEM OFF?
		 JRST ECOD3##	;(3) BOTH TURN OFF AND TURN ON
		 IORM T1,JBTPIA##(J) ;LIGHT THE BIT
		 JRST PISY.1]	;RESUME INLINE CODE
	TLNE	P2,(PS.OFF)	;WANT TO TURN OFF?
	ANDCAM	T1,JBTPIA##(J)	;CLEAR THE SYSTEM ON BIT
PISY.1:	TLNE	P2,(PS.RDV)	;WANT TO REMOVE DEVICE OR COND?
	PJRST	REMDEV		;YES, GO DO THAT
	TLNE	P2,(PS.ADV)	;WANT TO ADD?
	JRST	ADDDEV		;YES, GO DO THAT
	JRST	CPOPJ1##	;NO, ALL DONE
;SUBROUTINE CALLED BY UUOCON DURING RELEASE OF A DDB
;CALL
;	F = DDB BEING RELEASED
;	SKIPE	DEVPSI(F)
;	PUSHJ	P,PSIRMV
;ALWAYS CPOPJ RETURN
;WIPES T1

PSIRMV::SETZM	DEVPSI(F)	;CLEAR ANY ENABLED BITS
	LDB	T1,PJOBN##	;GET OWNER
	SKIPN	T1,JBTPIA##(T1)	;USING PSI
	POPJ	P,		;NO, HOW DID THOSE BITS GET LIT
	PUSHJ	P,SAVE2##	;SAVE A FEW REGS NOW
	MOVE	P1,T1		;COPY DATA BASE ADDRESS
UNLDDB:	HLRZ	P2,PITCHN(P1)	;GET FIRST DDB IN PSI CHAIN
	MOVEI	P1,<PITCHN-DEVESE>(P1) ;PRIME THE PUMP
UNLD.1:	JUMPE	P2,CPOPJ##	;RETURN WHEN OUT OF DDBS
	CAIN	P2,(F)		;ONE WE'VE BEEN LOOKING FOR
	JRST	[HLL P2,DEVESE(F) ;YES, GET POINTER TO NEXT
		 HLLM P2,DEVESE(P1) ;STORE IN PREVIOUS
		 POPJ P,]	;AND RETURN WITH CHAIN UNLINKED
	MOVE	P1,P2		;NO, REMEMBER HOW WE GOT HERE
	HLRZ	P2,DEVESE(P2)	;STEP TO NEXT PSI DDB
	JRST	UNLD.1		;CONTINUE SEARCH

;SUBROUTINE TO REMOVE A DEVICE OR CONDITION
;CALLED ONLY FROM PISYS UUO WITH:
;	P1 = ADDRESS OF PRIORITY INTERRUPT TABLE
;	P2 = USERS ARGUMENT
;	PUSHJ	P,REMDEV
;	  RETURN HERE ON ERROR
;	RETURN HERE IF OK
;
REMDEV:	TLNE	P2,(PS.ADV)	;ALSO WANT TO ADD DEVICE
	PJRST	ECOD14##	;(14) BOTH ADD AND REMOVE SELECTED
	PUSHJ	P,CHKCND	;CHECK THE CONDITION/DEVICE WORD
	  POPJ	P,0		;INVALID
	  JRST	REMD.1		;DEVICE CODE
	MOVSI	T2,(1B0)	;GET A BIT
	LSH	T2,(T1)		;POSITION IT CORRECTLY
	TDNN	T2,[VLDBIT]	;*** A VALID CONDITION
	PJRST	ECOD6##		;*** (6) ILLEGAL CONDITION
	ANDCAM	T2,PITENB(P1)	;CLEAR ENABLED BIT
	TRNE	T2,JBIBIT	;IF THIS IS CROSS JOB INTERRUPT
	SETZM	PITST2(P1)	;CLEAR PIJBI. UUO INTERLOCK
	ANDCAM	T2,PITPND(P1)	;AND DEFERRED PENDING BIT
	JRST	CPOPJ1##	;GOOD RETURN
REMD.1:	SETZM	DEVPSI(F)	;CLEAR INTERRUPT INFORMATION
	AOS	(P)		;GOING TO GIVE GOOD RETURN
	PJRST	UNLDDB		;UNLINK DDB AND RETURN
;SUBROUTINE TO ADD A DEVICE OR CONDITION
;CALLED FROM PISYS. UUO WITH:
;	P1 = ADDRESS OF PROGRAM INTERRUPT TABLE
;	P2 = USERS ARG POINTER
;	PUSHJ	P,ADDDEV
;	  RETURN HERE ON ERROR
;	RETURN HERE IF ALL IS OK
;
ADDDEV:	PUSHJ	P,CHKCND	;GO CHECK OUT ARGUMENT
	  POPJ	P,0		;INVALID DEVICE OR CONDITION
	  JRST	ADDD.1		;HE WANTS TO ADD A DDB
	MOVE	P3,T1		;COPY CONDITION WANTED
	PUSHJ	P,CNDPTR	;GET A CONDITION POINTER INTO P4
	TDZA	F,F		;INDICATE CONDITION ENABLE AND SKIP
ADDD.1:	MOVE	P4,[POINT CNDSIZ,DEVESE(F),26] ;GET POINTER FOR OFFSET
	HRRI	M,2(P2)		;GET PRIORITY INFORMATION
	PUSHJ	P,GETWDU##	;...
	TRNE	T1,-1		;IS RESERVED HALF WORD NON-ZERO
	PJRST	ECOD12##	;(12) RESERVED HALFWORD IN NON-ZERO
IFE PSIMPI,<PJUMPN T1,ECOD11##>	;(11) PRIORITY IS TOO BIG
IFN PSIMPI,<
	HLRZS	T1		;GET PRIORITY LEVEL
	CAILE	T1,PSIMPI	;CHECK IT
	PJRST	ECOD11##	;(11) PRIORITY IS TOO BIG
	HRL	P3,T1		;SAVE IN LH OF P3, RH = CONDITION
>
	HRRI	M,1(P2)		;GET THE VECTOR OFFSET WORD
	PUSHJ	P,GETWDU##	; ..
	MOVEI	T2,-1		;ASSUME CONDITION
	SKIPE	F		;ARE WE RIGHT?
	MOVEI	T2,-1-IR.ALL	;NO, LOAD BITS FOR INVALID REASONS
	TRNE	T1,(T2)		;ANY BITS SET
	PJRST	ECOD10##	;(10) UNIMPLEMENTED BIT IS ON
	LSHC	T1,-^D18	;T1 = 0,,OFFSET  T2 = REASONS,,0
	CAIG	T1,PSIMVO	;IS VALUE TOO BIG?
	TRNE	T1,3		;MUST BE MULTIPLE OF 4 WORDS (.PSVIS+1)
	PJRST	ECOD7##		;(7) BAD VECTOR OFFSET
	HRRZ	P2,PITIVA(P1)	;GET BASE OF VECTOR
	ADDI	P2,.PSVFL(T1)	;POINT TO CONTROL FLAGS
	HRRI	M,(P2)		;...
	MOVE	P2,T1		;SAVE OFFSET
	PUSHJ	P,GTWST2##	;GET CONTROL FLAGS ( GETWDU AND SAVE T2 )
	EXCH	P2,T1		;RESTORE, GET FLAGS
	JUMPE	F,ADDD.2	;DEVICE OR REGULAR CONDITION
	PJUMPE	T2,ECOD10##	;(10) DEVICE, NO ENABLED BITS IS AN ERROR
	TLNE	P2,(PS.VPM)	;USER WANT ANY MESSAGE PRINTED
	TLO	T2,(1B0)	;YES, LIGHT FLAG IN DDB
	EXCH	T2,DEVPSI(F)	;SET ENABLED, GET PREVIOUS STATE
	TLNE	T2,-1		;ANY PREVIOUS CONDITIONS
	JRST	ADDD.3		;YES, ALREADY IN DEVICE CHAIN
	HLL	T2,PITCHN(P1)	;GET FIRST IN CHAIN
	HLLM	T2,DEVESE(F)	;LINK THAT IN
	HRLM	F,PITCHN(P1)	;THIS IS NOW THE FIRST
	JRST	ADDD.3		;RESUME
ADDD.2:	MOVSI	T2,(1B0)	;GET A BIT
	LSH	T2,(P3)		;POSITION IT CORRECTLY
	TDNN	T2,[VLDBIT]	;*** A VALID CONDITION
	PJRST	ECOD6##		;*** (6) ILLEGAL CONDITION
	IORM	T2,PITENB(P1)	;NOT DEVICE, LIGHT ENABLED CONDITION
	TDNN	T2,[MSGBIT]	;THIS CONDITION HAVE A MESSAGE
	JRST	ADDD.3		;NO, SKIP TEST
	ANDCAM	T2,PITMSG(P1)	;CLEAR JUST IN CASE
	TLNE	P2,(PS.VPM)	;USER WANT IT PRINTED
	IORM	T2,PITMSG(P1)	;YES, LIGHT BIT FOR PSIIMM
ADDD.3:	LSH	T1,-2		;SHIFT OFF ZERO BITS
	DPB	T1,P4		;STORE OFFSET
	AOS	T1		;BUMP FOR PFH
	LDB	T2,[POINT 9,PITIVA(P1),8] ;GET MAX SO FAR
	CAIGE	T2,(T1)		;GREATER THAN THIS ONE?
	DPB	T1,[POINT 9,PITIVA(P1),8] ;SAVE THE GREATEST FOR PFH
IFN PSIMPI,<
	HRRE	T1,P3		;GET CONDITION TO ADD
	SKIPE	F		;DDB OR CONDITION
	SKIPA	P4,[POINT 2,DEVESE(F),19] ;DDB, GET POINTER TO PRIORITY
	PUSHJ	P,CNDLVL	;CONDITION, COMPUTE POINTER TO PRIORITY
	HLRZ	T1,P3		;RESTORE SAVED PRIORITY LEVEL
	DPB	T1,P4		;STORE IT
>
	AOS	(P)		;GOING TO GIVE GOOD RETURN
;	PJRST	APPSI		;FALL INTO ENABLE HARDWARE TRAP CODE

;SUBROUTINE TO SET UP HARDWARE TRAP1 INTERCEPT
;FALLEN INTO BY ADDDEV ABOVE,  ALSO CALLED BY KISER/KLSER

APPSI::	HRRZ	T2,JBTPIA##(J)	;GET BASE OF TABLE
	JUMPE	T2,CPOPJ##	;RETURN IF NOT USING PSI
	MOVE	T2,PITENB(T2)	;GET ENABLED CONDITIONS
	TLNN	T2,(APRBIT)	;WANT APR TRAPS
	POPJ	P,		;NO, GET OUT NOW
	MOVEI	T2,UI.AOT	;YES, SET DISPATCH FOR PSIAPR
	MOVEM	T2,.UPMP+.UPAOT	;STORE FOR HARDWARE TRAP
	POPJ	P,		;RETURN
;SUBROUTINE TO CLEAR A SPECIFIC CONDITION FOR THE USER
;CALLED FROM PISYS UUO
;	P1 = ADDRESS OF DATA BASE
;	P2 = USERS ARGUMENT
;	PUSHJ	P,CLRSPI
;	  RETURN HERE IF ERROR
;	NORMAL RETURN

CLRSPI:	PUSHJ	P,CHKCND	;FETCH/CHECK CONDITION WORD
	  POPJ	P,		;BAD DEVICE OR CONDITION
	  JRST	[HLLZS DEVPSI(F) ;CLEAR DEVICE PENDING BITS
		 JRST CPOPJ1##]	;GOOD RETURN
	MOVSI	T2,(1B0)	;GET A BIT
	LSH	T2,(T1)		;POSITION IT CORRECTLY
	TRNE	T2,JBIBIT	;IF THIS IS CROSS JOB INTERRUPT
	SETZM	PITST2(P1)	;CLEAR PIJBI. UUO INTERLOCK
	ANDCAM	T2,PITPND(P1)	;CLEAR PENDING INTERRUPT
	JRST	CPOPJ1##	;AND GOOD RETURN

;SUBROUTINE TO CLEAR ALL PENDING INTERRUPTS FOR A JOB
;CALLED FROM PISYS UUO
;	P1 = ADDRESS OF DATA BASE

CLRAPI:	SETZM	PITNPI(P1)	;CLEAR PENDING COUNT
	SETZM	PITST2(P1)	;CLEAR PIJBI. UUO INTERLOCK
	SETZM	PITPND(P1)	;CLEAR PENDING CONDITIONS
	HLRZ	F,PITCHN(P1)	;POINT TO FIRST PSI'ED DDB
CLRA.1:	JUMPE	F,CPOPJ##	;RETURN WHEN OUT OF DDBS
	HLLZS	DEVPSI(F)	;CLEAR ANY PENDING INTERRUPTS
	HLRZ	F,DEVESE(F)	;STEP TO NEXT IN THE CHAIN
	JRST	CLRA.1		;LOOP OVER ALL DDBS
;SUBROUTINE TO FETCH AND VALIDATE THE DEVICE OR CONDITION GIVEN BY THE USER
;CALLED WITH:
;	P2 = USER ARGUMENT
;	PUSHJ	P,CHKCND
;	  RETURN HERE IF THE CONDITION IS INVALID
;	  RETURN HERE IF A DEVICE WAS SPECIFIED
;	RETURN HERE IF A CONDITION WAS SPECIFIED
;
;UPON RETURN F=ADDRESS OF DDB (IF DEVICE)
;	T1 = CONDITION NUMBER (IF CONDITION)

CHKCND:	HRR	M,P2		;ADDRESS OF WORD
	PUSHJ	P,GETWDU##	;GET THE WORD
	HLRE	T2,T1		;CHECK IF CONDITION OR DEVICE NAME
	AOJE	T2,CHKC.1	;GO IT CONDITION WAS SPECIFIED
	PUSHJ	P,DVCNSG##	;ELSE LOOK FOR A DEVICE
	  JRST	ECOD5##		;(5) NOT A DEVICE
CHKC.0:	HRRZ	T2,TTYTAB##(J)	;GET ADDRESS OF THIS JOBS TTY DDB
	CAIN	T2,(F)		;SKIP IF THIS IS NOT HIS TTY
	PJRST	CPOPJ1##	;GOOD RETURN
	LDB	T2,PJOBN##	;GET NAME OF OWNER
	MOVEI	T3,ASSPRG	;SEE IF DEVICE IS
	TDNE	T3,DEVMOD(F)	; OPEN FOR 
	CAIE	T2,(J)		; THIS JOB.
	PJRST	ECOD5##		;(5) OR NOT OPEND BY THIS JOB
	JRST	CPOPJ1##	;SKIP RETURN
CHKC.1:	CAML	T1,[C$MIN]	;SKIP IF CODE IS TOO SMALL
	JRST	CPOPJ2##	;DOUBLE SKIP RETURN

;HERE COULD BE "-1,,DDB" FROM PISAV., CHECK FOR THAT

	HLRZ	F,DEVLST##	;HEAD OF DDB CHAIN
CHKC.2:	CAIN	F,(T1)		;THE ONE WE WANT
	JRST	CHKC.0		;AND CHECK OWNERSHIP
CHKC.3:	PUSHJ	P,NXDDB##	;STEP TO NEXT DDB
	  JUMPE	F,ECOD6		;(6) OR CONDITION CODE TOO SMALL
	JRST	CHKC.2		;AND LOOK AT IT
SUBTTL	UUOCON INTERFACE -- PISAV.

;CALL TO SAVE THE CURRENT PSI SYSTEM
;CALL WITH:
;	MOVE	AC,[XWD LENGTH,ADDRESS]
;	PISAV.	AC,
;	  HERE ON AN ERROR
;	HERE OLD SYSTEM IS SAVED AND CLEARED
;
;ADDRESS	GETS	FLAG,,NUMBER OF WORDS STORED
;			(OR WOULD HAVE IF BLOCK WERE LONG ENOUGH)
;ADDRESS+1	GETS	BASE OF CURRENT INTERRUPT VECTOR
;
;ADDRESS+2 THROUGH
;ADDRESS+N	GETS	SAVED STATE, 3 WORD BLOCKS, SUITABLE FOR PIRST. (OR PISYS.)

PISAVE::PUSHJ	P,SAVE4##	;SAVE A FEW FIRST
	HRR	M,T1		;ADDRESS OF BLOCK
	HLRZ	P2,T1		;AND LENGTH OF IT
	SOJL	P2,ECOD1##	;(1) BLOCK SIZE ZERO
	MOVEI	P3,1		;ADJUST BOTH COUNTERS
	SKIPN	P1,JBTPIA##(J)	;GET DATA BASE
	JRST	PISA.5		;OK IF SAVING AN EMPTY SYSTEM
	PUSH	P,M		;REMEMBER ADDRESS OF FIRST WORD
	PUSH	P,F		;AND SAVE F
	HRRZ	T1,PITIVA(P1)	;GET BASE OF SYSTEM CURRENTLY IN USE
	PUSHJ	P,STORE		;STORE IN THE BLOCK
	HLRZ	P4,PITCHN(P1)	;GET START OF THE PSI DDBS
	JUMPE	P4,PISA.2	;NONE, GET NON-DEVICE CONDITIONS
PISA.1:	HRROI	T1,(P4)		;GET -1,,DDB ADDRESS
	PUSHJ	P,STORE		;STUFF THAT AWAY
	LDB	T1,[POINT CNDSIZ,DEVESE(P4),26] ;GET VECTOR OFFSET
	LSH	T1,^D20		;*4, WANT IT IN LEFT HALF
	HLR	T1,DEVPSI(P4)	;INSERT CONDITIONS ENABLED
	TRZ	T1,-1-IR.ALL	;CLEAR RESIDUE
	PUSHJ	P,STORE		;DROP IT IN
IFE PSIMPI,<SETZ T1,>		;CLEAR PRIORITY INFORMATION
IFN PSIMPI,<
	LDB	T1,[POINT 2,DEVESE(P4),19] ;GET PRIORITY LEVEL
	HRLZS	T1		;WANT IN LEFT HALF FOR UUO
>
	PUSHJ	P,STORE		;STORE PRIORITY INFORMATION
	HLRZ	P4,DEVESE(P4)	;STEP TO NEXT PSI'ED DDB
	JUMPN	P4,PISA.1	;CONTINUE UNTIL DONE

PISA.2:	SKIPN	F,PITENB(P1)	;ANY NON-DEVICE CONDITIONS ENABLED
	JRST	PISA.4		;NOPE, ALL DONE WITH THE SAVE
PISA.3:	MOVE	T1,F		;COPY CURRENT BITS
	JFFO	T1,.+1		;FIND ONE ENABLED
	MOVN	T1,T2		;WANT NEGATIVE CONDITION NUMBER
	TDZ	F,BITTBL##(T2)	;AND CLEAR WHAT WE FOUND ENABLED
IFN PSIMPI,<PUSH P,T1>		;SAVE CONDITION NUMBER
	PUSHJ	P,CNDPTR	;COMPUTE A CONDITION POINTER
	PUSHJ	P,STORE		;STORE CONDITION NUMBER
	LDB	T1,P4		;GET OFFSET PROPER
	LSH	T1,^D20		;*4 AND MOVE TO THE LEFT HALF
	PUSHJ	P,STORE		;STORE THAT
IFE PSIMPI,<SETZ T1,>		;CLEAR PRIORITY INFORMATION
IFN PSIMPI,<
	POP	P,T1		;RESTORE CONDITION NUMBER
	PUSHJ	P,CNDLVL	;GET PRIORITY LEVEL
	LDB	T1,P4		;GET IT
	HRLZS	T1		;WANT IN LEFT HALF FOR UUO
>
	PUSHJ	P,STORE		;STORE PRIORITY INFORMATION
	JUMPN	F,PISA.3	;CONTINUE UNTIL EXHAUSTED ENABLED CONDITIONS

PISA.4:	POP	P,F		;RESTORE F
	POP	P,M		;RESTORE ADDRESS OF FIRST WORD
PISA.5:	MOVE	T1,P3		;NUMBER OF WORDS STORED (OR TRIED TO)
	SKIPGE	P1		;IS THE PSI SYSTEM CURRENTLY TURNED ON
	TLO	T1,(SI.ON)	;YES, LIGHT BIT FOR PIRST.
	PUSHJ	P,PUTWDU##	;STORE IN BEGINNING OF USERS BLOCK
	JUMPL	P2,RTZER##	;WAS THIS TRIP REALLY WORTH IT
	PUSHJ	P,CLRPSI	;HAVING SAVED THE SYSTEM, CLEAR OLD DATA
	JRST	CPOPJ1##	;AND RETURN SUCCESS

;LOCAL ROUTINE FOR STORING DATA INTO THE BLOCK FOR PISAV.

STORE:	SOSL	P2		;ROOM LEFT IN THE BLOCK
	PUSHJ	P,PUTWD1##	;YES, STORE THIS VALUE
	AOJA	P3,CPOPJ##	;COUNT THE WORD AND RETURN
SUBTTL	UUOCON INTERFACE -- PIRST.

;CALL TO RESTORE THE PI SYSTEM FROM BLOCK SAVED BY PISAV.
;CALL WITH:
;	MOVEI	AC,BLOCK USED DURING PISAV.
;	PISAV.	AC,
;	  HERE ON AN ERROR
;	HERE PI SYSTEM SUCCESSFULLY RESTORED
;
;THIS UUO CAN ALSO BE USED TO BUILD AN ENTIRE PI SYSTEM AVOIDING PIINI AND
;	MULTIPLE PISYS. UUOS.

PIRST::	PUSHJ	P,SAVE4##	;SAVE A FEW FIRST
	HRRI	M,(T1)		;ADDRESS OF THE BLOCK
	PUSHJ	P,GETWDU##	;GET FLAG AND WORD COUNT
	HLL	P4,T1		;SAVE FLAG FOR NOW
	HRRZ	P3,T1		;COPY COUNT
	SOJLE	P3,[PUSHJ P,CLRPSI ;SAVED AN EMPTY SYSTEM
		    JRST CPOPJ1##] ;SO CLEAR OLD AND RETURN
	PUSHJ	P,GETWD1##	;GET BASE OF OLD SYSTEM
	PUSHJ	P,PIINI		;AND DO A PIINI. FOR IT
	  JRST	ECOD1##		;(1) NO MONITOR CORE
	SOS	P3		;ADJUST COUNTER
	MOVEI	P2,1(M)		;POINT TO FIRST BLOCK TO RESTORE
	MOVE	P1,JBTPIA##(J)	;BASE FROM PIINI.
	TLNE	P4,(SI.ON)	;WAS OLD SYSTEM ON
	TLO	P1,(SI.ON)	;YES, RESTORE STATE

PIRS.1:	SUBI	P3,3		;DEDUCT 1 BLOCK FROM COUNT
	JUMPL	P3,PIRS.2	;ALL DONE
	PUSHJ	P,[PUSHJ P,SAVE3## ;SAVE MY P REGS FIRST
		   JRST ADDDEV]    ;AND CALL PISYS. ADD ROUTINE
	  JRST	[PUSHJ P,CLRPSI    ;FAILED, CLEAR SO NOT HALF RESTORED
		 PJRST RTZER##]    ;AND GIVE FAIL RETURN TO UUO
	ADDI	P2,3		;POINT TO NEXT GROUP
	JRST	PIRS.1		;AND PROCESS THAT

PIRS.2:	MOVEM	P1,JBTPIA##(J)	;STORE BACK WITH "ON" FLAG
	JRST	CPOPJ1##	;AND GIVE GOOD RETURN
SUBTTL	UUOCON INTERFACE -- DEBRK.

DEBRK::	PUSHJ	P,SAVE4##	;SAVE A FEW FIRST
	SKIPE	P1,JBTPIA##(J)	;GET ADDRESS OF PI TABLE
IFN PSIMPI,<SKIPGE P4,PITHLP(P1)> ;GET HIGHEST LEVEL IN PROGRESS
IFE PSIMPI,<SKIPN P2,PITCIB(P1)> ;GET INT BLOCK ADDRESS
	JRST	CPOPJ1##	;NO PI IN PROGRESS
IFN PSIMPI,<
	ADDI	P4,PITCIB(P1)	;POINT TO CORRECT PITCIB FOR LEVEL IN PROGRESS
	MOVE	P2,0(P4)	;AND GET INT BLOCK ADDRESS
>
	HRRI	M,.PSVOP(P2)	;OLD PC
	PUSHJ	P,GETWDU##	;FETCH IT
	MOVE	P3,T1		;SAVE FOR NOW
	HRRI	M,.PSVFL(P2)	;FLAG WORD
	PUSHJ	P,GETWDU##	;GET THAT TOO
	MOVE	T4,.JDAT+JOBPD1## ;GET UUO PC
	TLNN	T4,(XC.UIO)	;DOES HE HAVE USER IOT SET
	TLZ	P3,(XC.UIO)	;NO, CLEAR FROM OLD PC
IFE FTKS10,<
	TLNE	T4,(XC.PUB)	;OLD PC PUBLIC
	TLO	P3,(XC.PUB)	;YES, NEW PC IS TOO
>
	TLO	P3,(XC.USR)	;SET USER MODE
	TLZ	P3,37		;CLEAR INDEX AND @
	MOVEM	P3,.JDAT+JOBPD1## ;STORE BACK FOR USER
IFE PSIMPI,<SETZM PITCIB(P1)>	;CLEAR INTERRUPT IN PROGRESS
IFN PSIMPI,<
	SETZM	0(P4)		;CLEAR INTERRUPT IN PROGRESS
DEBR.1:	SOSGE	PITHLP(P1)	;NOW FIND NEXT HIGHEST IN PROGRESS
	JRST	DEBR.2		;THIS WAS THE LAST, PITHLP IS NOW BACK TO -1
	SKIPN	-1(P4)		;IS THIS LEVEL IN PROGRESS
	SOJA	P4,DEBR.1	;NO, KEEP LOOKING
DEBR.2:	MOVSI	T3,(SI.DBK)	;SYSTEM OFF UNTIL DEBRK.
	ANDCAM	T3,JBTPIA##(J)	;THIS WAS THE DEBRK.
>
	TLNN	T1,(PS.VDS)	;DISMISS OTHERS
	POPJ	P,		;NO, RETURN, CATCH NEW INTERRUPTS AT UUOXIT
	HLRE	P2,P2		;GET CONDITION NUMBER OR DDB ADDRESS
	JUMPGE	P2,DEBR.3	;YES, GO IF A DEVICE CONDITION
	MOVSI	T1,(1B0)	;GET A BIT
	LSH	T1,(P2)		;POSITION IT CORRECTLY
	TRNE	T1,JBIBIT	;IF THIS IS CROSS JOB INTERRUPT
	SETZM	PITST2(P1)	;CLEAR PIJBI. UUO INTERLOCK
	ANDCAM	T1,PITPND(P1)	;CLEAR THE PENDING BIT
	POPJ	P,		;RETURN
DEBR.3:	HLRZ	F,PITCHN(P1)	;GET HEAD OF PSI DDBS
DEBR.4:	JUMPE	F,CPOPJ##	;RETURN WHEN OUT OF DDBS
	CAMN	P2,F		;THIS THE ONE WE'RE LOOKING FOR
	JRST	[HLLZS DEVPSI(F) ;YES, CLEAR PENDING BITS
		 POPJ P,]	;AND RETURN
	HLRZ	F,DEVESE(F)	;STEP TO THE NEXT ONE
	JRST	DEBR.4		;TRY THE NEXT
SUBTTL	UUOCON INTERFACE -- PIJBI.

;CALL TO INTERRUPT ANOTHER JOB AND GIVE STATUS
;CALL WITH:
;	MOVE	AC,[XWD JOB TO INTERRUPT,STATUS TO GIVE]
;	PIJBI.	AC,
;	  HERE ON AN ERROR
;	HERE WHEN INTERRUPT HAS BEEN POSTED FOR THE JOB
;
;JOB NUMBER OF -1 IS INTERRUPT YOURSELF, UUO WILL FAIL (ERROR 1) IF THE JOB
;	ALREADY HAS ONE PENDING, CALLER MUST TRY AGAIN, CAN'T JUST LET IT
;	STACK SINCE YOU WILL LOSE STATUS (ONLY 1 PLACE TO STORE IT)

PIJOB::	HLRZ	J,T1		;GET JOB TO INTERRUPT
	HRL	T1,.CPJOB##	;STATUS RETURNED IS JOB WHO DID IT,,STATUS
	CAIN	J,-1		;INTERRUPTING YOURSELF
	HLRZ	J,T1		;YES, SET BOTH JOB NUMBERS TO CURRENT
	CAILE	J,JOBMAX##	;GOOD JOB NUMBER
	JRST	ECOD0##		;(0) ILLEGAL JOB NUMBER
	MOVEI	T2,JBIBIT	;BIT FOR ENABLED THIS TYPE OF INTERRUPT
	SKIPE	T3,JBTPIA##(J)	;TARGET JOB USING PSISER
	TDNN	T2,PITENB(T3)	;YES, USER ENABLED FOR CROOS JOB INTERRUPTS
	JRST	ECOD0##		;(0) NOT ENABLED FOR INTERRUPT
	UUOLOK			;PREVENT RACES WITH OTHER CPUS
	SKIPN	T2,PITST2(T3)	;TARGET ALREADY HAVE ONE PENDING
	MOVEM	T1,PITST2(T3)	;NO, GIVE HIM THIS ONE
	UUONLK			;ALLOW OTHER CPUS BACK IN NOW
	JUMPN	T2,ECOD1##	;(1) TARGET IS BUSY, TRY LATER
	SIGNAL	C$JBI		;CAUSE THE INTERRUPT
	  JRST	ECOD0##		;REALLY OUGHT TO STOPCD HERE SINCE JUST CHECKED
	JRST	CPOPJ1##	;GIVE GOOD RETURN TO CALLER
SUBTTL	SUPPORT FOR THE SIGNAL MACRO  --  PSICND

;ROUTINE TO CAUSE A NON-DEVICE CONDITION
;CALL VIA THE SIGNAL MACRO
;	J  = JOB TO BE SIGNALLED
;	T1 = THE CONDITION ( NEGATIVE ) SET UP BY SIGNAL MACRO
;	T2 = STATUS IF NOT RECONSTRUCTABLE
;			C$WAKE = JOB NUMBER OF WAKER
;			C$QUE  = REQUEST ID
;			C$CTLC = 1B0 ON IF JOB WAS IN TI STATE
;RETURN	CPOPJ USER DOESN'T WANT THE TRAP
;	CPOPJ1 IF USER DOES (AND WE WOKE UP THE JOB)

PSICND::JUMPGE	T1,CPOPJ##	;ONLY NEGATIVE CONDITIONS HERE
	PUSHJ	P,SAVE4##	;SAVE A FEW FIRST
	CAML	T1,[C$MIN]	;CONDITION TOO SMALL
	SKIPN	P1,JBTPIA##(J)	;USER DOING PSISER
	POPJ	P,		;NOT USING PSISER OR BAD CONDITION
	MOVSI	P3,(1B0)	;GET A BIT
	LSH	P3,(T1)		;POSITION IT CORRECTLY
	TDNN	P3,PITENB(P1)	;USER ENABLE FOR THIS INTERRUPT
	POPJ	P,		;NO, QUIT NOW
	TDNE	P3,[IMBITS]	;IS THIS AN IMMEDIATE CONDITION
	JRST	PSIIMM		;YES, GO DIRECTLY TO GENERATOR
	TRNE	P3,QUEBIT	;ENQ/DEQ
	IORM	T2,PITSTS(P1)	;REMEMBER REQUEST ID
	TRNE	P3,WAKBIT	;WAKE UUO.
	DPB	T2,[POINT 9,PITSTS(P1),17] ;YES, REMEMBER WAKING JOB
	TLNN	P3,(CTCBIT)	;^C
	JRST	PSIAGN		;NO, GO POST INTERRUPT
	MOVSI	P2,(1B0)	;GET "FROM TI WAIT" BIT
	ANDCAM	P2,PITSTS(P1)	;CLEAR OLD STATUS
	IORM	T2,PITSTS(P1)	;SET NEW STATUS
	SKIPGE	T2		;FROM "TI" WAIT
	SKIPA	P2,.JDAT+JOBPD1## ;YES, GET UUO PC
	MOVE	P2,USRPC##	 ;NO, GET SAVED PC
	TLNN	P2,USRMOD	;BETTER BE A USER PC
	MOVE	P2,.JDAT+JOBPD1## ;GET LAST UUO PC
	PUSHJ	P,ISDDT		;USER IN DDT
	  POPJ	P,		;YES, LET CONTROL C STOP THE JOB
PSIAGN:	AOS	(P)		;USER WANTS INTERRUPT
PSIAG1:	TDNE	P3,PITPND(P1)	;ALREADY HAVE THIS ONE PENDING
	JRST	PSIAG2		;YES, JUST WAKE THE JOB
	IORM	P3,PITPND(P1)	;LIGHT ONE FOR THIS INTERRUPT
	AOS	PITNPI(P1)	;BUMP PENDING COUNT
PSIAG2:	JUMPGE	P1,CPOPJ##	;DON'T WAKE THE JOB IF PI OFF
	PJRST	WAKEJB##	;WAKE UP JOB AND RETURN
;HERE WHEN A CONDITION MUST BE GRANTED IMMEDIATELY (APR STUFF)

PSIIMM:	JUMPGE	P1,CPOPJ##	;CANNOT GRANT IF PS IS OFF
	TDNE	P3,[PD1BIT]	;WHERE IS THE CURRENT PC
	SKIPA	P2,.JDAT+JOBPD1## ;GET PC OF ALL UUOS
	MOVE	P2,.CPPC##	;ALL OTHERS ARE APR CONDITIONS
	TLNN	P2,(XC.USR)	;PC IN USER MODE
	JRST	PSITLE		;NO, SEE IF TIME LIMIT EXCEEDED
IFE PSIMPI,<SKIPN PITCIB(P1)>	;ONE ALREADY IN PROGRESS
IFN PSIMPI,<TLNN P1,(SI.DBK)>	;SYSTEM TURNED OFF
	PUSHJ	P,ISPFH		;CHECK FOR USERS PFH
	  JRST	PSITLE		;CAN'T GRANT IT NOW
IFN PSIMPI,<
	PUSHJ	P,CNDLVL	;GET POINTER TO PRIORITY INFORMATION
	LDB	P4,P4		;GET LEVEL FOR CONDITION
	CAMG	P4,PITHLP(P1)	;HIGHER THAN ONE IN PROGRESS
	JRST	PSITLE		;NO, CAN'T GRANT IT NOW
>
	TDNE	P3,PITMSG(P1)	;USER WANT STANDARD ERROR MESSAGE
	JRST	PSIMSG		;YES, REMEMBER THAT
	AOS	PITNPI(P1)	;KEEP THE COUNT STRAIGHT
	PJRST	GENCND		;EXIT, CAUSING THE INTERRUPT

PSITLE:	TLNN	P3,(TLEBIT)	;WAS THIS TIME LIMIT EXCEEDED
	POPJ	P,		;NO, IGNORE TRAP
	TDNN	P3,PITMSG(P1)	;CALLER STANDARD MESSAGE
	JRST	PSIAGN		;NO, JUST POST IT
PSIMSG:	HLLOS	PITCHN(P1)	;MARK PRINTING A MESSAGE
	JRST	PSIAG1		;GO POST BUT GIVE DOESN'T WANT RETURN
;SUBROUTINE CALLED AFTER PRINTING THE STANDARD MESSAGE FOR A USER
;	J = JOB
;	PUSHJ	P,PSIERR
;	  HERE IF AT CLOCK LEVEL AND WANTS THE INTERRUPT
;	  HERE IF AT UUO LEVEL AND WANTS THE INTERRUPT
;	HERE IF TIME TO STOP THE JOB

PSIERR::SKIPGE	T1,JBTPIA##(J)	;GET BASE OF DATA
	HRL	T1,PITCHN(T1)	;GET FLAG THAT WE WERE PRINTING
	JUMPGE	T1,CPOPJ2##	;QUIT IF NOT PSIING OR NOT PRINTING
	HLLZS	PITCHN(T1)	;CLEAR FLAG
	HRRZ	T1,P		;FIND OUT IF UUO OR CLOCK LEVEL
	CAMLE	T1,LOCORE##	;CHECK STACK ADDRESS
	AOS	(P)		;IN JOBDAT, GIVE CPOPJ1 RETURN
	POPJ	P,		;RETURN TO INTERRUPT USER

;SUBROUTINE CALLED TO GRANT USER INDUCED ERROR IN JOB, I.E. THINGS NOT COVERED
;	BY SPECIFIC CONDITIONS LIKE PDLOVERFLOW, ETC..
;
;	J = JOB NUMBER
;	PUSHJ P,USREIJ
;	  RETURN HERE TO GRANT INTERRUPT
;	RETURN HERE TO STOP JOB ( PRINT MSG, ANY MAYBE BACK THROUGH PSIERR )

USREIJ::MOVE	T1,[MSGBIT]	;GET CONDITIONS THAT HAVE ERROR MESSAGES
	SKIPE	T2,JBTPIA##(J)	;USER PSI'ING
	TDNE	T1,PITPND(T2)	;OR WERE WE JUST PRINTING A MESSAGE
	JRST	CPOPJ1##	;GO STOP THE JOB (OR RETURN THROUGH PSIERR)
	SIGNAL	C$UEIJ		;SIGNAL CONDITION
	  AOS	(P)		;DOESN'T WANT OR CAN'T GRANT, STOP THE JOB
	POPJ	P,		;RETURN
SUBTTL	SUPPORT FOR DEVICE RELEATED CONDITIONS

;HERE FOR DEVICE RELATED TRAPS ALSO IN .JBINT (AND SOME THAT AREN'T)
;	T4 = .JBINT TYPE
;	F = DDB INVOLVED
;	PUSHJ	P,PSIJBI
;	  HERE IF USER WANTS INTERRUPT (AVOID .JBINT)
;		T3 = POSITIVE IF USER WANTS ERROR MESSAGE AS WELL
;	HERE IF USER DOESN'T WANT THE TRAP (TRY .JBINT,T4 STILL OK)

PSIJBI::PUSHJ	P,SAVE3##	;SAVE A FEW
	LDB	P2,PJOBN##	;GET JOB NUMBER
	MOVE	P2,JBTSTS##(P2)	;THEN STATUS OF JOB
	TRNE	P2,JS.ASA	;EXEC UUO IN PROGRESS
	JRST	CPOPJ1##	;YES, NO USER TO GIVE IT TO
	SETZ	P2,		;CLEAR INTERRUPT BITS
	CAIE	T4,.EROFL	;DISK OFF-LINE
	CAIN	T4,.ERIDV	;INTERVENTION REQUIRED
	MOVEI	P2,IR.DOL	;YES, DEVICE OFF-LINE TRAP
	CAIN	T4,.ERFUL	;DISK FULL
	MOVEI	P2,IR.DFL	;YES, SET TRAP
	CAIN	T4,.ERQEX	;QUOTA EXCEEDED
	MOVEI	P2,IR.QTE	;YES, SET TRAP
	CAIN	T4,'IDC'	;I/O TO DETACHED CPU
	MOVEI	P2,IR.IER!IR.OER!IR.DOL ;ERROR CONDITION
	PUSHJ	P,PSIDEV	;CALL SIGNALLER
	JUMPE	P3,CPOPJ1##	;RETURN IF NOT PSIING
	MOVE	T3,DEVPSI(P3)	;GET BITS FROM CORRECT DDB
	TLC	T3,(1B0)	;FLIP SO NEGATIVE IS "NO MESSAGE"
	POPJ	P,		;GO CLEAN UP AND GIVE INTERRUPT

;HERE JUST BEFORE AN INPUT OR OUTPUT RETURNS TO THE USER

PSIEDN::TLNN	S,IO		;DETERMINE DIRECTION OF THE IO
PSIIDN::SKIPA	T1,[IR.IER]	;INPUT ERROR
PSIODN::MOVEI	T1,IR.OER	;OUTPUT ERROR
	TRNE	S,IODEND	;END OF FILE?
	TRO	T1,IR.EOF	;YES, FLAG THAT CONDITION
	TRNN	S,IOBKTL!IODTER!IODERR!IOIMPM!IOTEND ;AND ERRORS LIT
	TRZ	T1,IR.IER!IR.OER;NO, DO NOT SIGNAL ERROR
;	JRST	PSIDVB		;FALL INTO DEVICE BITS SET UP ROUTINE

;HERE WHEN CALLER ALREADY HAS DETERMINED WHAT TYPE OF INTERRUPT TO GIVE

PSIDVB::JUMPE	T1,CPOPJ##	;EXIT IF NOTHING HAPPENED
	PUSHJ	P,SAVE3##	;SAVE A FEW NOW
	HRRZ	P2,T1		;MOVE CONDITIONS
	JRST	PSIDEV		;ENTER COMMON CODE

;SUBROUTINE TO SIGNAL DOWN DEVICE

PSIDWN::PUSHJ	P,SAVE3##	;SAVE A FEW
	MOVEI	P2,IR.IER!IR.OER!IR.DOL ;SET INPUT ERR, OUTPUT ERR, OFF-LINE
	JRST	PSIDEV		;ENTER COMMON CODE
;SUBROUTINE TO SIGNAL DEVICE ON-LINE

PSIONL::PUSHJ	P,SAVE3##	;SAVE A FEW
	MOVEI	P2,IR.ONL	;DEVICE ON-LINE
	JRST	PSIDEV		;ENTER COMMON CODE

;SUBROUTINE TO SIGNAL INPUT/OUTPUT DONE INTERRUPTS
;CALLED BY SETIOD

PSIIOD::PUSHJ	P,SAVE3##	;SAVE A FEW
	TLNN	S,IO		;GET THE DIRECTION OF THE IO
	SKIPA	P2,[IR.IND]	;INPUT
	MOVEI	P2,IR.OUD	;OUTPUT
;	JRST	PSIDEV		;FALL INTO COMMON CODE

;ROUTINE CALLED BY THE ABOVE SIGNALLERS TO CAUSE A DEVICE RELEATED INTERRUPT
;RETURNS P3 = 0 OR DDB USED (USEFUL ONLY TO PSIJBI)

PSIDEV:	HLRZ	P3,DEVPSI(F)	;GET ENABLED FOR DEVICE
IFN FTMSGSER,<
	JUMPE	P3,[MOVEI P1,DEPMSG	;NOT USING THE DEVICE ITSELF
		    TDNN P1,DEVMSG(F)	;TRY THE MPX CONTROLLING
		    POPJ P,		;NOT MPX'ED, IGNORE INTERRUPT
		    PUSH P,F		;SAVE ORIGINAL F
		    HRRZ F,DEVXTR(F)	;STEP TO MPX DDB
		    HLRZ P3,DEVPSI(F)	;GET BITS FOR THE MPX
		    JUMPE P3,FPOPJ##	;IGNORE IF NOT PSI'ING
		    PUSH P,[CAIA FPOPJ##] ;STACK RESTORE RETURN
		    JRST .+1]		;RETURN INLINE
>; END FTMSGSER
	AND	P2,P3		;MASK DOWN TO ENABLED BITS
	SETZ	P3,		;CLEAR IN CASE WE RETURN
	JUMPE	P2,CPOPJ##	;RETURN IF NOT ENABLED
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;GET OWNER OF DEVICE
	SKIPN	P1,JBTPIA##(J)	;OWNER ENABLED
	JRST	JPOPJ##		;NO, IGNORE REQUEST
	SETCM	P3,DEVPSI(F)	;GET WHAT'S NOT LIT
	TRNN	P3,(P2)		;ALREADY HAVE THESE CONDITIONS
	JRST	PSIDV1		;YES, BITS AND COUNTS ARE RIGHT
	SETCMI	P3,(P2)		;P3=NOT WHAT WE ARE SETTING
	IORB	P2,DEVPSI(F)	;LIGHT NEW CONDITIONS, GET EVERYTHING
	TRNN	P2,(P3)		;ANY OTHERS ALREADY PENDING
	AOS	PITNPI(P1)	;NO, BUMP PENDING COUNT
PSIDV1:	MOVE	P3,F		;RETURN DDB ACTUALLY USED
	JUMPGE	P1,JPOPJ##	;DON'T WAKE IF PI OFF
	DMOVE	P1,T1		;SAVE T1,T2 IN P1,P2
	PUSHJ	P,WAKEJB##	;WAKEUP JOB
	DMOVE	T1,P1		;RESTORE CALLERS T1 AND T2
	JRST	JPOPJ##		;RESTORE J AND RETURN
SUBTTL	GRANT AN INTERRUPT TO A RUNNING USER

;CALLED BY UUOCON OR CLOCK1 TO GRANT AN INTERRUPT FOR A USER
;	J = JOB NUMBER
;	XCT	PINOJN		;SKIP IF CANNOT GRANT INTERRUPT
;	PUSHJ	P,PSIGEN##	;CAN, GIVE AN INTERRUPT
;
;ALWAYS CPOPJ RETURN

PSIGEN::SKIPG	@JBTPIA##(J)	;ARE THERE ANY PENDING INTERRUPTS
	POPJ	P,		;NO, GET OUT NOW
	PUSHJ	P,SAVE4##	;SAVE A FEW FIRST
	SKIPGE	P1,JBTPIA##(J)	;GET DATA BASE
IFN PSIMPI,<TLNE P1,(SI.DBK)>	;SYSTEM OFF UNTIL DEBRK.
IFE PSIMPI,<SKIPE PITCIB(P1)>	;ALREADY ONE IN PROGRESS
	POPJ	P,		;CANNOT GRANT INTERRUPT NOW
	HRRZ	P2,-5(P)	; ***** GET CALLERS PC
	CAIN	P2,CIPPSI##	;FROM CLOCK1
	SKIPA	P2,.CPPC##	;YES, GET CURRENT PC
	MOVE	P2,.JDAT+JOBPD1## ;NO, GET UUO RETURN PC
	TLNE	P2,(XC.USR)	;BETTER BE A USER MODE PC HERE
	PUSHJ	P,ISPFH		;CHECK IF IN PFH OR DDT
	  POPJ	P,		;DEFER UNTIL USER GETS OUT
	PUSHJ	P,GENINT	;CAUSE INT
	  JFCL			;NONE TO GIVE
	POPJ	P,		;RETURN
;SUBROUTINE TO ACTUALLY GRANT THE INTERRUPT, CALLED BY PSIGEN AND PSIIMM
;CALL WITH:
;	P1 = ADDRESS OF PSI DATA BASE
;	P2 = CURRENT USER MODE PC
;ENTER AT GENCND WITH T1 ALREADY SET UP AS CONDITION TO GIVE (PSIIMM)
;	CPOPJ	CAN'T GIVE THE INTERRUPT
;	CPOPJ1	DID, USER IS OFF AND RUNNING

GENINT:	PUSHJ	P,GENNXT	;HERE WHEN WE DON'T KNOW WHAT'S NEXT, GO FIND IT
	  POPJ	P,		;NONE TO GIVE OR LOWER LEVELS WAITING FOR DEBRK.
	SKIPL	T1		;DEVICE OR CONDITION INTERRUPT
	SKIPA	P4,[POINT CNDSIZ,DEVESE(P3),26] ;DEVICE, GET POINTER TO OFFSET
GENCND:	PUSHJ	P,CNDPTR	;GET POINTER FOR OFFSET
	LDB	P4,P4		;GET OFFSET PROPER
	LSH	P4,2		;BACK TO 4 WORD BLOCKS
	ADD	P4,PITIVA(P1)	;PLUS VECTOR BASE
	PUSHJ	P,VALVEC	;VALIDATE THE ADDRESS
	  POPJ	P,		;INVALID, GAVE ERROR
	EXCTUU	<MOVEM P2,.PSVOP(P4)> ;STORE INTERRUPTED PC FOR USER
	EXCTUU	<HRR P2,.PSVNP(P4)> ;GET NEW PC FOR INTERRUPT
	TLZ	P2,(<-1,,0>-<XC.USR!XC.UIO!IFE FTKS10,<XC.PUB>>) ;CLEAR ALL BUT THESE
	MOVSI	T2,(XC.USR)	;GET USER MODE BIT
	TDNE	T2,.JDAT+JOBPD1## ;A USER PC IN JOBDAT
	MOVEM	P2,.JDAT+JOBPD1## ;YES, STORE FOR UUO DISMISS
	MOVEM	P2,.CPPC##	;STORE FOR CLOCK1
	EXCTUU	<MOVE P2,.PSVFL(P4)> ;GET CONTROL FLAGS
	MOVSI	T2,(SI.ON)	;PI SYSTEM ON
	TLNE	P2,(PS.VPO)	;USER WANT IT TURNED OFF
	ANDCAM	T2,JBTPIA##(J)	;YES, TURN IT OFF TILL PISYS.
IFN PSIMPI,<
	MOVSI	T2,(SI.DBK)	;OFF UNTIL DEBRK
	TLNE	P2,(PS.VTO)	;USER WANT IT DONE
	IORM	T2,JBTPIA##(J)	;YES, MARK WAITING FOR DEBRK.
	PUSH	P,P4		;SAVE USERS ADDRESS A MOMENT
	SKIPL	T1		;DEVICE OR CONDITION
	SKIPA	P4,[POINT 2,DEVESE(P3),19] ;DEVICE, POINT TO PRIORITY INFORMATION
	PUSHJ	P,CNDLVL	;CONDITION, GET POINTER TO PRIORITY
	LDB	T2,P4		;GET IT
	POP	P,P4		;RESTORE USERS BLOCK ADDRESS
	MOVEM	T2,PITHLP(P1)	;STORE LEVEL IN PROGRESS
	ADDI	T2,PITCIB(P1)	;POINT TO CORRECT "IN PROGRESS" BLOCK
>
IFE PSIMPI,<MOVEI T2,PITCIB(P1)> ;POINT TO ONLY CURRENT BLOCK
	HRRM	P4,0(T2)	;STORE CURRENT INTERRUPT BLOCK
	HRLM	T1,0(T2)	;AND CURRENT CONDITION
	EXCTUU	<HRRM T1,.PSVFL(P4)> ;STORE REASONS OR CONDITION FOR USER
	JUMPGE	T1,[SETZ T1,	;CLEAR T1 FOR STATUS DISPATCH
		   HRLM P3,0(T2) ;STORE REAL CURRENT CONDITION
		   JRST .+1]	;RETURN INLINE
	XCT	LDSTS(T1)	;LOAD STATUS WORD FOR USER
	EXCTUU	<MOVEM T2,.PSVIS(P4)> ;STORE STATUS WORD
	MOVE	T2,[WTMASK+JERR+CNTRLC,,JS.MPE+JS.DPM+UTRP]
	ANDCAM	T2,JBTSTS##(J)	;CLEAR ALL ERROR CONDITIONS
	SOS	PITNPI(P1)	;ONE LESS PENDING INTERRUPT
	JRST	CPOPJ1##	;RETURN
;SUBROUTINE TO FIGURE OUT WHICH INTERRUPT TO GIVE NOW
;CALL WITH:
;	P1 = ADDRESS OF PSI DATA BASE
;	P2 = USERS PC ( FYI, WE REALLY LEAVE IT ALONE HERE )
;RETURNS:
;	CPOPJ IF NONE TO GIVE NOW (MAYBE PRIORITIES)
;	CPOPJ1 WITH THE FOLLOWING
;	T1 = CONDITION NUMBER OR DEVICE BITS TO CAUSE
;	P3 = DDB USED IF T1 IS DEVICE BITS, ELSE INDETERMINATE (READ WIPED)
;WIPES T2,T3,T4 AND P4

;*** OF SPECIAL NOTE, THERE ARE 2 COPIES OF THIS ROUTINE UNDER CONDITIONALS
;	FOR NUMBER OF PRIORITY LEVELS, ANY CHANGES TO ONE BETTER BE LOOKED AT
;	FOR THE OTHER LEAST SOMEBODY FLIPPING CONDITIONAL WILL GET IT.

IFE PSIMPI,<			;FIRST THE ONE FOR NO LEVELS, ITS EASIER
GENNXT:	SKIPN	T1,PITPND(P1)	;ANY NON-DEVICE PENDING
	JRST	GENDEV		;NO, TRY DEVICE CHAIN
	JFFO	T1,.+1		;YES, DETERMINE CONDITION
	MOVN	T1,T2		;GET CONDITION NUMBER
	MOVE	T2,BITTBL##(T2)	;GET BIT FOR THIS CONDITION
	ANDCAM	T2,PITPND(P1)	;NO LONGER PENDING
	JRST	CPOPJ1##	;AND RETURN WITH IT
GENDEV:	HLRZ	P3,PITCHN(P1)	;POINT TO FIRST DDB
GEND.1:	JUMPE	P3,[SOSG PITNPI(P1) ;COUNT WAS TOO HIGH
		   POPJ P,	;BUT IT'S RIGHT NOW
		   JRST GENNXT]	;LOOK AGAIN IF STILL UP
	HLLZ	T1,DEVPSI(P3)	;GET CURRENT ENABLED BITS
	EXCH	T1,DEVPSI(P3)	;GET PENDING CONDITIONS, CLEAR THEM
	TLZ	T1,-1		;CLEAR ENABLED BITS
	JUMPN	T1,CPOPJ1##	;USE IT IF ANY INTERRUPTS PENDING
	HLRZ	P3,DEVESE(P3)	;STEP TO NEXT DDB
	JRST	GEND.1		;LOOP FOR ALL PSI'ED DDBS
>

IFN PSIMPI,<			;NOW FOR MULTIPLE LEVELS, ITS HARDER
GENNXT:	MOVE	T4,PITHLP(P1)	;GET HIGHEST LEVEL IN PROGRESS
	CAIN	T4,PSIMPI	;QUICK CHECK FOR HIGHEST POSSIBLE
	POPJ	P,		;WOULDN'T FIND ONE HIGHER ANYWAY
	SETZ	P3,		;CLEAR BEST SO FAR
	MOVE	T3,PITPND(P1)	;GET NON-DEVICE PENDING
GENN.1:	SKIPN	T1,T3		;ANY WE HAVEN'T LOOKED AT YET
	JRST	GENDEV		;NO, TRY DEVICE CHAIN
	JFFO	T1,.+1		;YES, DETERMINE CONDITION
	MOVN	T1,T2		;GET CONDITION NUMBER
	TDZ	T3,BITTBL##(T2)	;DON'T LOOK AT THIS CONDITION AGAIN
	PUSHJ	P,CNDLVL	;COMPUTE LEVEL POINTER
	LDB	P4,P4		;GET PRIORITY OF THIS CONDITION
	CAMG	P4,T4		;HIGHER THAN BEST SO FAR
	JRST	GENN.1		;NO, LOOK SOME MORE
	MOVE	P3,T1		;WHICH ONE IT IS
	CAIN	P4,PSIMPI	;QUICK CHECK, HIGHEST POSSIBLE
	JRST	GENW.1		;CAN'T GET ANY BETTER, STOP NOW
	MOVE	T4,P4		;COPY HIGHEST PRIORITY FOUND SO FAR
	JUMPN	T3,GENN.1	;LOOK FOR MAYBE A BETTER ONE
GENDEV:	HLRZ	T1,PITCHN(P1)	;POINT TO FIRST DDB
	JUMPE	T1,GENWAT	;LAST DDB, FIGURE OUT WHAT HAPPENED
GEND.1:	HRRZ	T2,DEVPSI(T1)	;GET CURRENT PENDING BITS
	JUMPE	T2,GEND.2	;TRY ANOTHER IF NONE PENDING
	LDB	T3,[POINT 2,DEVESE(T1),19] ;GET PRIORITY OF THIS DDB
	CAMG	T3,T4		;BEST SO FAR
	JRST	GEND.2		;NO, TRY ANOTHER
	MOVE	P3,T1		;WHICH DDB HAS IT
	CAIN	T3,PSIMPI	;SAME QUICK CHECK AS ABOVE
	JRST	GENW.2		;...
	MOVE	T4,T3		;REMEMBER HIGHEST LEVEL SO FAR
GEND.2:	HLRZ	T1,DEVESE(T1)	;STEP TO NEXT PSI DDB
	JUMPN	T1,GEND.1	;AND TAKE A LOOK AT IT

;HERE WHEN ALL DONE LOOKING, P3=BEST SO FAR, T4=IMPORTANT ONLY IF P3 = 0

GENWAT:	JUMPE	P3,[JUMPGE T4,CPOPJ## ;NONE FOUND, OK IF BECAUSE OF PRIORITIES
		    SOSG PITNPI(P1) ;PENDING COUNT WAS TOO HIGH
		    POPJ P,	;BUT ITS OK NOW
		    JRST GENNXT] ;DO THIS ALL OVER AGAIN IF COUNT IS STILL UP
	SKIPL	T1,P3		;A DDB OR CONDITION FOUND
	JRST	GENW.2		;A DDB, GO CLEAR PENDING BITS
GENW.1:	MOVSI	T2,(1B0)	;GET A BIT
	LSH	T2,(T1)		;POSITION IT CORRECTLY
	ANDCAM	T2,PITPND(P1)	;NO LONGER PENDING
	JRST	CPOPJ1##	;AND RETURN TO GIVE THE INTERRUPT
GENW.2:	HLLZ	T1,DEVPSI(P3)	;GET ENABLED CONDITIONS FROM DDB
	EXCH	T1,DEVPSI(P3)	;LEAVE THEM ALONE, GET SIGNALLED CONDITIONS
	TLZ	T1,-1		;CLEAR JUNK FROM LEFT HALF
	JRST	CPOPJ1##	;RETURN WITH P3 = DDB, T1 = DEVICE BITS
>
;TABLE EXECUTED DURING PSIGEN TO FETCH THE CORRECT STATUS WORD
;	FOR THE CONDITION ABOUT TO BE GRANTED.
;	CONDITIONS ARE NEGATIVE.. THIS TABLE GOES BACKWARDS..

	PUSHJ	P,GETJBI	;(-30) CROSS JOB INTERRUPTS
	SETZ	T2,		;(-27) NETWORK TOPOLOGY CHANGE
	PUSHJ	P,GETQUE	;(-26) ENQ/DEQ
	SETZ	T2,		;(-25) ***RESERVED
	PUSHJ	P,STRSIG##	;(-24) IPCF
	SETZ	T2,		;(-23) ADDRESS BREAK
	LDB	T2,[POINT 9,PITSTS(P1),17] ;(-22) WAKE UUO
	PUSHJ	P,GETATC	;(-21) DETACH/ATTACH
	SETZ	T2,		;(-20) DATASET STATUS CHANGE
	MOVE	T2,SYSKTM##	;(-17) KSYS WARNING
	SETZ	T2,		;(-16) EXTERNAL ERROR IN JOB
	SETZ	T2,		;(-15) USER INDUCED ERROR IN JOB
	MOVE	T2,DATE##	;(-14) APR CLOCK TICK
	SETZ	T2,		;(-13) NON-EX MEM
	SETZ	T2,		;(-12) ***RESERVED
	SETZ	T2,		;(-11) PDL OVERFLOW
	SETZ	T2,		;(-10) APR CONDITIONS
	MOVE	T2,DEVNAM(F)	;(-7) ADDRESS CHECK
	SETZ	T2,		;(-6) ILL MEM REF
	MOVE	T2,.UPMP+.UPMUO	;(-5) ILLEGAL UUO
	MOVE	T2,.UPMP+.UPMUO	;(-4) ANY UUO
	PUSHJ	P,GETIOW	;(-3) ^C
	SETZ	T2,		;(-2) ***RESERVED
	PUSHJ	P,GETJRT	;(-1) TIME LIMIT EXCEEDED
LDSTS:	PUSHJ	P,GETUDX	;(0) DEVICE CONDITIONS COME HERE


;TABLE OF SIXBIT ABBREVIATIONS FOR NON-DEVICE CONDITIONS
;	USED FOR PRINTING ERROR MESSAGES.

	'NTC',,'JBI'	;(-27) NTWRK TOPOLOGY	(-30) CROSS JOB
	    0,,'QUE'	;(-25) ***RESERVED	(-26) ENQ/DEQ
	'ABK',,'IPC'	;(-23) ADR BREAK	(-24) IPCF
	'DAT',,'WAK'	;(-21) DET/ATTACH	(-22) WAKE UUO
	'KSY',,'DSC'	;(-17) KSYS WARNING	(-20) DATASET STATUS
	'UEJ',,'XEJ'	;(-15) USER ERROR	(-16) EXTERNAL ERROR
	'NXM',,'APC'	;(-13) NXM		(-14) CLOCK TICK
	'PDL',,0	;(-11) PDL OV		(-12) ***RESERVED
	'ACK',,'ARI'	;(- 7) ADR CHECK	(-10) ARITHMETIC EXC
	'ILU',,'IMR'	;(- 5) ILL UUO		(- 6) ILL MEM REF
	'STP',,'UUO'	;(- 3) ^C		(- 4) ANY UUO
	'TLE',,0	;(- 1) TIME LIMIT	(- 2) ***RESERVED
LDSIX:
;SUBROUTINES CALLED BY THE PRECEDING TABLE TO FETCH STATUS

GETUDX:	PUSH	P,U		;SAVE U
	PUSH	P,F		;SAVE F
	PUSH	P,P1		;SAVE P1 AROUND IONDF
	MOVE	F,P3		;MOVE DDB ADDRESS INTO F
	PUSHJ	P,IONDF##	;GET UDX FOR DEVICE
	  TDZA	T2,T2		;FAILED, NONE TO RETURN
	HRL	T2,T1		;INSERT IN RETURN AC
	HRR	T2,DEVIOS(F)	;INSERT DEVICE STATUS
	POP	P,P1		;RESTORE
	JRST	FUPOPJ##	;RESTORE F&U AND RETURN

GETQUE:	HRRZ	T2,PITSTS(P1)	;GET SAVED REQUEST ID
	ANDCAM	T2,PITSTS(P1)	;CLEAR WHAT WE ARE SIGNALLING
	POPJ	P,		;AND RETURN

GETATC:	HRRZ	T2,TTYTAB##(J)	;GET TTY DDB FOR JOB
	HRRZ	T2,DDBLDB##(T2)	;GET ATTACHED LDB
	SOJL	T2,CPOPJ##	;RETURN -1 IF DETACHED
	LDB	T2,[POINT 9,LDBDCH##+1(T2),35] ;GET LINE NO (T2 OFF BY 1)
	ADDI	T2,.UXTRM	;MAKE IT A UDX
	POPJ	P,		;AND RETURN

GETIOW:	HLLZ	T2,PITSTS(P1)	;GET SAVED STATUS
	TLZ	T2,377777	;WANT ONLY THE SIGN BIT
	POPJ	P,		;RETURN

GETJRT:	PUSH	P,W		;SAVE W
	MOVE	T1,J		;COPY JOB NUMBER
	PUSHJ	P,JOBTMM##	;DO "RUNTIME UUO"
	MOVE	T2,T1		;PUT RESULT IN RETURN AC
	JRST	WPOPJ##		;RESTORE W AND RETURN

GETJBI:	SETZ	T2,		;PITST2 INTERLOCKS PIJBI. UUO
	EXCH	T2,PITST2(P1)	;GET STATUS, ALLOW OTHERS NOW
	POPJ	P,		;RETURN
SUBTTL	PSISER SUBROUTINES

;SUBROUTINE TO RETURN PSI INFO FOR VMSER AND PFH

PSIIVA::SKIPE	T1,JBTPIA##(J)	;GET ADDR OF DATA BASE
	MOVE	T1,PITIVA(T1)	;USING, GET VECTOR INFORMATION
	POPJ	P,		;RETURN FOR STORE INTO PFH

;SUBROUTINE TO RETURN RANGE OF PAGES THAT INCLUDE THE USERS PSI VECTOR

PSIIVR::SKIPN	T1,JBTPIA##(J)	;GET ADDRESS OF DATA BASE
	POPJ	P,		;NONE, RETURN ZERO
	PUSH	P,J		;SAVE A WORK AC
	LDB	J,[POINT 9,PITIVA(T1),8] ;GET HIGHEST OFFSET IN USE
	JUMPE	J,PSIIV1	;RETURN ZERO IF NO CONDITIONS YET
	LSH	J,2		;TO WORDS FROM BASE
	ADD	J,PITIVA(T1)	;TO FIRST ADDRESS BEYOND VECTOR
	HRLI	J,-1(J)		;HIGHEST ADDRESS USED TO LEFT HALF
	HRR	J,PITIVA(T1)	;INSERT LOWEST ADDRESS
	TLZ	J,PG.BDY##	;ONLY WANT PAGE NUMBERS
	LSH	J,W2PLSH##	;SO CONVERT ADDRESSES
PSIIV1:	EXCH	J,(P)		;RESTORE J, STORE ANSWER
	JRST	TPOPJ##		;RETURN XWD LAST-PAGE,,FIRST-PAGE OF PSI VECTOR

;SUBROUTINE TO CHECK IF A USER IS ENABLED FOR A CONDITION
;CALL	T1 = CONDITION ( NEGATIVE ONES ONLY )
;	J  = JOB NUMBER INTERRESTED IN
;RETURN CPOPJ IF NOT ENABLED
;	CPOPJ1 IF SO
;USES T2 & T3

PSITST::JUMPGE	T1,CPOPJ##	;ONLY NEGATIVE CONDITIONS HERE
	CAML	T1,[C$MIN]	;AND THEN ONLY IN RANGE
	SKIPN	T2,JBTPIA##(J)	;AND ONLY IF USER IS PSI'ING
	POPJ	P,		;NONE OF THE ABOVE
	MOVSI	T3,(1B0)	;GET A BIT
	LSH	T3,(T1)		;POSITION IT CORRECTLY
	TDNE	T3,PITENB(T2)	;USER ENABLED FOR THIS TRAP
	AOS	(P)		;YES, GIVE SKIP RETURN
	POPJ	P,		;RETURN
;SUBROUTINE TO TELL ALL INTERESTED ABOUT NETWORK TOPOLOGY CHANGES
IFN FTNET,<
PSINTC::PUSH	P,J		;SAVE J FOR NETSER
	MOVE	J,HIGHJB##	;GET HIGHEST JOB NUMBER ASSIGNED
NTC.1:	SIGNAL	C$NTC		;SIGNAL FOR THAT JOB
	  JFCL			;DON'T CARE IF NOT ENABLED
	SOJG	J,NTC.1		;CONTINUE FOR ALL JOBS
	JRST	JPOPJ##		;RESTORE J AND RETURN
>; END FTNET

;SUBROUTINE TO INFORM JOBS OF KSYS TIMER
PSIKSY::PUSH	P,J		;SAVE J FOR COMCON
	MOVE	J,HIGHJB##	;GET HIGHEST JOB NUMBER ASSIGNED
KSY.1:	SIGNAL	C$KSYS		;SIGNAL FOR THAT JOB
	  JFCL			;DON'T CARE IF NOT ENABLED
	SOJG	J,KSY.1		;CONTINUE FOR ALL JOBS
	JRST	JPOPJ##		;RESTORE J AND RETURN
;HERE ON HARDWARE TRAP FOR ARITHMATIC INTERRUPTS

PSIAPR::MOVE	P,[MJOBPD##,,.JDAT+JOBPDL##] ;SET UP A PUSH DOWN LIST
	MOVE	J,.CPJOB##	;GET JOB NUMBER RUNNING
	MOVE	T1,.UPMP+.UPMUP	;GET PC OF INTERRUPT
	MOVEM	T1,.CPPC##	;STORE FOR SIGNALLER
	SIGNAL	C$ARIT		;SIGNAL TRAP
	  JFCL			;CANNOT GRANT IT
	MOVSI	T1,(XC.OVF+XC.FOV+XC.FUF+XC.NDV)
	ANDCAM	T1,.CPPC##	;CLEAR CONDITION THAT CAUSED TRAP
	USERAC			;BACK TO USERS ACS
	JEN	@.CPPC##	;BACK TO USER OR INTERRUPT

;SUBROUTINE CALLED TO SIGNAL ANY UUO
;CALLED BY UUOCON JUST BEFORE DISPATCHING
;	PUSHJ	P,ANYUUO
;	  HERE TO PROCESS THE UUO
;	HERE TO SKIP DISPATCH AND INTERRUPT USER

ANYUUO::SKIPL	T3,JBTPIA##(J)	;GET BASE OF PSI DATA
	POPJ	P,		;NOT USING PSI OR SYSTEM OFF
	MOVE	T3,PITENB(T3)	;GET ENABLED CONDITIONS
	TLNN	T3,(AUUBIT)	;USER WANT TO TRAP EVERY UUO
	POPJ	P,		;NO, RETURN NOW
	MOVE	T3,M		;GET UUO ISSUED
	TLZ	T3,777		;CLEAR OUT JUNK
	CAML	T3,[CALLI 135]	;PIINI.
	CAMLE	T3,[CALLI 141]	;PIRST.
	SKIPA			;OK IF NOT ONE THAT CHANGES THE STATE
	POPJ	P,		; OF THE PI SYSTEM
	PUSH	P,T1		;SAVE DISPATCH AC
	SIGNAL	C$AUUO		;SIGNAL A UUO IS DONE
	  JRST	TPOPJ##		;USER CANNOT TAKE IT, DO UUO
	JRST	TPOPJ1##	;SKIP DISPATCH, USER WANTS IT
;SUBROUTINE CALLED BY PSIGEN TO VALIDATE THE INTERRUPT VECTOR ADDRESS
;RETURNS CPOPJ IF INVALID
;	CPOPJ1 IF OK

VALVEC:	PUSH	P,T1		;SAVE CONDITION
	MOVEI	T1,(P4)		;POINT TO ADDRESS
	SETO	T2,		;LOOP COUNTER
VALV.1:	CAIG	T1,JOBPFI##	;ADDRESS TOO SMALL
	JRST	VALV.2		;YES, SAY ILLEGAL TO USER
	MOVEI	T4,(T1)		;COPY ADDRESS
	LSH	T4,W2PLSH##	;CONVERT TO PAGE NUMBER
	PUSHJ	P,GTPM4##	;GET PAGE MAP ENTRY FOR THIS PAGE
	JUMPE	T4,VALV.2	;SAY ILLEGAL IF NOT THERE
	PUSHJ	P,FLTST##	;CHECK IF PAGE CAUSES FAULT
	  JRST	VALV.3		;YES, SAY PAGED OUT
	TRNN	T4,PM.WRT	;IS THE PAGE WRITTABLE
	JRST	[MOVEI T2,[ASCIZ/, is write protected/]
		JRST  VALV.4]	;DIFFERENT ERROR IF VECTOR IN THE HIGH SEG
	ADDI	T1,.PSVIS	;STEP TO LAST WORD IN VECTOR
	AOJE	T2,VALV.1	;CHECK IT NOW
	JRST	TPOPJ1##	;RETURN IF PASSED BOTH TESTS
VALV.2:	SKIPA	T2,[[ASCIZ/, is illegal/]]
VALV.3:	MOVEI	T2,[ASCIZ/, is paged out/]
VALV.4:	PUSH	P,T2		;SAVE ADDRESS OF MESSAGE
	MOVSI	T1,JERR		;CAN'T CONTINUE BIT
	IORM	T1,JBTSTS##(J)	;PREVENT TRAPS
	PUSHJ	P,GIVRES##	;GIVE UP ANY RESOURCES
	JSP	T1,ERRPNT##	;FIRE UP AN ERROR MESSAGE
	  ASCIZ/PSI Interrupt Vector at /  ;**** ERRPNT WILL PUSH F & U
	MOVEI	T1,(P4)		;GET LOCATION OF VECTOR
	PUSHJ	P,PRTDI8##	;OUTPUT IT
	SKIPL	T2,-3(P)	;GET CONDITION NUMBER
	JRST	VALV.5		;ITS A DDB
	ROT	T2,-1		;DIVIDE TO GET TABLE ENTRY
	SKIPGE	T2		;WHICH HALF
	SKIPA	T2,LDSIX(T2)	;LEFT
	MOVS	T2,LDSIX(T2)	;RIGHT
	TRZA	T2,-1		;CLEAR OTHER
VALV.5:	SKIPA	T2,DEVNAM(P3)	;GET DEVICE NAME
	SKIPA	T1,[[ASCIZ/, for Condition /]]
	MOVEI	T1,[ASCIZ/, for Device /]
	MOVEM	T2,-3(P)	;STORE FOR SAFE KEEPING
	PUSHJ	P,CONMES##	;OUTPUT CORRECT STRING
	MOVE	T2,-3(P)	;RESTORE
	PUSHJ	P,PRNAME##	;OUTPUT SIXBIT DEVICE OR CONDITION
	MOVEI	T1,TPOPJ##	;FOR CLEANUP
	EXCH	T1,-2(P)	;GET CORRECT ENDING
	PUSHJ	P,CONMES##	;APPEND "ILLEGAL" OR "PAGED OUT"
	JRST	PCSTOP##	;AND STOP THE JOB, NON-CONTINUABLE
;SUBROUTINE TO BUILD A BYTE POINTER TO THE VECTOR OFFSET BYTE
;CALL WITH:
;	P1 = ADDRESS OF PSI DATA BASE
;	T1 = CONDITION NUMBER (ONLY NEGATIVE ONES HERE)
;	PUSHJ	P,CNDPTR
;	RETURN HERE POINTER IN P4
;PRESERVES T1 WIPES T2

CNDPTR:	PUSH	P,T1		;SAVE CONDITION
	MOVM	T1,T1		;GET POSITIVE CONDITION
	IDIVI	T1,4		;T1 := WORD AND T2 := QUARTER
	MOVE	P4,CNDP.A(T2)	;GET A GOOD POINTER
	ADDI	P4,(T1)		;ADD IN WORD OFFSET
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

CNDP.A:	POINT	CNDSIZ,PITTAB(P1),8	;BYTE 0
	POINT	CNDSIZ,PITTAB(P1),17	;BYTE 1
	POINT	CNDSIZ,PITTAB(P1),26	;BYTE 3
	POINT	CNDSIZ,PITTAB(P1),35	;BYTE 4

;SUBROUTINE TO BUILD A BYTE POINTER TO THE PRIORITY BYTE
;
;SAME CALL AND RETURN AS CNDPTR

IFN PSIMPI,<
CNDLVL:	PUSHJ	P,CNDPTR	;LET CNDPTR FIGURE OUT BYTE AND WORD OFFSETS
	HLL	P4,CNDP.B(T2)	;BUT INSERT DIFFERENT SIZE AND POSITION INFO
	POPJ	P,		;RETURN

CNDP.B:	POINT	2,0(P1),1	;BYTE 0
	POINT	2,0(P1),10	;BYTE 1
	POINT	2,0(P1),19	;BYTE 2
	POINT	2,0(P1),28	;BYTE 3
>
;SUBROUTINE TO SEE IF USER IS IN PFH OR DDT
;CALL WITH:
;	P2 = PC
;	PUSHJ	P,ISPFH
;	  HERE IF IN PFH OR DDT
;	HERE IF NOT
;WIPES T2

ISPFH:	MOVE	T2,P2		;MOVE PC FOR VMSER
	PUSH	P,T3		;SAVE T3 AROUND VMSER
	PUSHJ	P,INPFH##	;SEE IF WE ARE IN PFH
	  JRST	T3POPJ##	;YES, RESTORE T3 AND RETURN
	POP	P,T3		;RESTORE NOW
ISDDT:	HRRZ	T2,.JDAT+JOBDDT## ;GET START OF DDT
	SKIPE	.JDAT+JOBDDT##	;DDT LOADED?
	CAILE	T2,(P2)		;ABOVE START OF DDT?
	JRST	CPOPJ1##	;NO, ALL IS WELL
	HLRZ	T2,.JDAT+JOBDDT## ;GET END OF DDT
	CAIG	T2,(P2)		;ABOVE END?
	AOS	(P)		;YES, NOT IN DDT
	POPJ	P,0		;IN DDT


PSILIT::XLIST			;FORCED OUT LITERAL POOL HERE
	$LIT
	LIST
PSIEND::END