Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93d-bb - 7,6/ap015/psiser.x15
There are 2 other files named psiser.x15 in the archive. Click here to see a list.
TITLE	PSISER -- PROGRAMMED SOFTWARE INTERRUPT SERVICE   V266
SUBTTL	C. D. O'TOOLE/CDO/RCB    22 JUL 86

	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.
;
.CPYRT<1973,1986>
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;ALL RIGHTS RESERVED.

;
;XP VPSISR,266
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>>>




;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>)
	BITS(TMRBIT,<TMR>)
	BITS(DTCBIT,<DTC>)
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   ON IF ^C FROM TI WAIT
	PITQAB==1B1		;  1   ON IF C$QUE IS ABORTING REQUEST
				; 2-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
PITST3:! BLOCK	1		;ENTIRE WORD USED FOR C$DTC
PITIVA:! BLOCK	1		; 0-8  HIGHEST VECTOR IN USE
				; 9-17 SECTION OF USER'S BASE
				;18-35 ADDRESS OF USER'S BASE
IFN PSIMPI,<
PITHLP:! BLOCK	1		;HIGHEST LEVEL IN PROGRESS ( -1 IF NONE )
>
PITCIB:! BLOCK	<PSIMPI+1>	;FULLWORD ADDRESS OF CURRENT INTERRUPT BLOCK
PITCIC:! BLOCK	<PSIMPI+1>	;LH = PC FLAGS IF EXTENDED ADDRESSING MODE
				;RH = CURRENT INTERRUPT CONDITION OR DDB
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
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		;SAVE SPACE

VECBAS:	POINT	23,PITIVA(P1),35	;GLOBAL ADDRESS OF USER'S VECTOR
VECBS2:	POINT	23,PITIVA(T1),35	;ANOTHER WAY OF ADDRESSING IT
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::	PUSHJ	P,SAVE1##	;SAVE AN AC
	TLNN	T1,(PS.IEA)	;USER REQUESTING EXTENDED ADDRESSING?
	HRRZS	T1		;NO, USE SECTION 0
	MOVE	P1,T1		;PRESERVE THE USER'S ARGUMENT
	TLZ	T1,(PS.IEA)	;CLEAR ILLEGAL ADDRESSING BIT
IFN FTXMON,<
	PUSHJ	P,SSPCS##	;SAVE PCS (FOR PIRST)
>
	PUSHJ	P,SXPCS##	;CHECK FOR VALID SECTION/BIT COMBINATION
	  JRST	ECOD1##		;(01) ILLEGAL SECTION NUMBER/BIT COMBINATION
	HRRZS	T1		;IADRCK ADDS IN PCS
	PUSHJ	P,IADRCK##	;CHECK ADDRESS VALIDITY
	  JRST	ECOD2##		;(02) BAD ADDRESS
	  JFCL			;PAGED OUT. ASSUME IT WILL COME IN.
IFN FTXMON,<
	XSFM	T1		;GET CURRENT PCS
	TLNE	P1,(PS.IEA)	;IF USER REQUESTED EXTENDED ADDRESSING,
	TRO	T1,(PS.IEA)	;PROPAGATE THE BIT
	HRL	P1,T1		;UPDATE LH OF ARGUMENT REGISTER
>
	PUSHJ	P,CLRPSI	;CLEAR OLD DATA
	MOVEI	T2,PIT4WD	;NUMBER OF 4-WORD BLOCKS TO GET
	PUSHJ	P,GET4WD##	;GO GET THEM
	  JRST	ECOD3##		;(03) INSUFFICIENT MONITOR FREE CORE
	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
	TLZE	P1,(PS.IEA)	;USING EXTENDED ADDRESSING?
	TLOA	T1,(SI.UEA)	;YES, MARK IT
	TLZA	P1,-1		;NO, CLEAR LH OF USER'S VECTOR ORIGIN
	TLZ	P1,^-<(SECMSK)>	;YES, LEAVE SECTION NUMBER ALONE
	MOVEM	P1,PITIVA(T1)	;STORE IN PIT
	MOVEM	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
	PUSHJ	P,CLRTMR	;REMOVE ANY TIMER QUEUE REQUESTS
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

;SUBROUTINE TO REMOVE ANY TIMER QUEUE ENTRIES FOR PITMR.

CLRTMR:	PUSHJ	P,CTXJCJ##	;GET INTERRUPT HANDLE FROM CTXSER
	  POPJ	P,		;OK IF NONE
	MOVE	T2,[PSITMR,,1]	;REQUEST TO CHANGE TO EXPIRE IN 1 TICK
	PUSHJ	P,CLKCHG##	;SEARCH FOR/MODIFY EXISTING ENTRY
	  POPJ	P,		;OK IF DIDN'T FIND ONE
	POPJ	P,		;DONE
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	ECOD0##		;(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-T2

PSIRMV::SETZM	DEVPSI(F)	;CLEAR ANY ENABLED BITS
	LDB	T1,PJCHN##	;GET OWNER
	PUSHJ	P,CTXPSI##	;GET PIT ADDRESS FROM CTXSER
	  POPJ	P,		;NO SUCH JOB?  UUOCON MESSED UP.
	JUMPE	T2,CPOPJ##	;NO PIT, HOW DID THOSE BITS GET LIT
	PUSHJ	P,SAVE2##	;SAVE A FEW REGS NOW
	MOVE	P1,T2		;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
	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
	TLNE	T2,(TMRBIT)	;IF THIS IS TIMER INTERRUPTS
	PUSHJ	P,CLRTMR	;REMOVE ANY CLOCK REQUEST QUEUE ENTRIES
	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,SAVUM##	;PRESERVE M FOR THE REST OF THE WORLD
	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 IS 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
	LDB	P2,VECBAS	;GET BASE OF VECTOR
	ADDI	P2,.PSVFL(T1)	;POINT TO CONTROL FLAGS
	MOVE	M,P2		;...
	MOVE	P2,T1		;SAVE OFFSET
	HLRZ	T1,M		;GET SECTION OF BLOCK
	PUSHJ	P,SVPCS##	;SET IT UP
	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
	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,.USAOT	;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:	PUSHJ	P,CTXJCJ##	;GET CURRENT JCH FOR JOB
	  POPJ	P,		;CONTEXT WENT AWAY
	MOVE	T4,T1		;SAVE JCH FOR COMPARES
	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,PJCHN##	;GET NAME OF OWNER
	TRNN	T2,CTXMSK##	;IF NO CONTEXT OWNS IT,
	TRZ	T4,CTXMSK##	;THEN DON'T COMPARE CONTEXT NUMBERS
	MOVEI	T3,ASSPRG	;SEE IF DEVICE IS
	TDNE	T3,DEVMOD(F)	; OPEN FOR 
	CAIE	T2,(T4)		; THIS JOB.
	PJRST	ECOD5##		;(5) OR NOT OPENED 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
	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
	LDB	T1,VECBAS	;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.
	TLNE	P1,(SI.UEA)	;EXTENDED USER?
	TLO	T1,(SI.UEA)	;YES, LIGHT BIT FOR PIRST.
	PUSHJ	P,PUTWDU##	;STORE IN BEGINNING OF USERS BLOCK
	JUMPL	P2,ECOD0##	;(0) 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
	TLNE	P4,(SI.UEA)	;IF EXTENDED USER
	TLO	T1,(PS.IEA)	;LIGHT UUO BIT
	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 ECOD0##]    ;(0) 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
>
	HLRZ	T1,P2		;GET SECTION NUMBER OF BLOCK
	PUSHJ	P,SVPCS##	;SET IT FOR FOLLOWING
	MOVEI	M,.PSVOP(P2)	;OLD PC
	PUSHJ	P,GETWDU##	;FETCH IT
	MOVE	P3,T1		;SAVE FOR NOW
	MOVEI	M,.PSVFL(P2)	;FLAG WORD
	PUSHJ	P,GETWDU##	;GET THAT TOO
	DMOVE	T3,.JDAT+JOBPD1## ;GET UUO PC
	PUSH	P,P4		;SAVE AC USED FOR PC
	PUSHJ	P,DEBRPC	;ADJUST PC FOR EXTENDED USER
	TLNN	T3,(XC.UIO)	;DOES HE HAVE USER IOT SET
	TLZ	P3,(XC.UIO)	;NO, CLEAR FROM OLD PC
IFE FTKS10,<
	TLNE	T3,(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 @
	DMOVEM	P3,.JDAT+JOBPD1## ;STORE BACK FOR USER
	POP	P,P4		;RESTORE PC REGISTER
IFE PSIMPI,<
	SETZM	PITCIB(P1)	;CLEAR INTERRUPT IN PROGRESS
	SETZ	P2,		;GET A ZERO
	EXCH	P2,PITCIC(P1)	;GET AND CLEAR CURRENT CONDITION/DEVICE
>
IFN PSIMPI,<
	SETZM	0(P4)		;CLEAR INTERRUPT IN PROGRESS
	SETZ	P2,		;GET A ZERO
	EXCH	P2,PITCIC-PITCIB(P4) ;GET AND CLEAR INTERRUPT REASON
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
	HRRZ	P2,P2		;GET CONDITION NUMBER OR DDB ADDRESS
	CAIGE	P2,C$MIN	;CONDITION OR DEVICE
	JRST	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

;HERE TO ADJUST PC FOR EXTENDED ADDRESSING
DEBRPC:
IFN PSIMPI,<
	PUSH	P,T1		;SAVE A BASE REGISTER
	MOVE	T1,P4		;BEFORE WE CLOBBER IT
>
	MOVE	P4,P3		;COPY PC FOR DOUBLEWORD
	TLNN	P1,(SI.UEA)	;EXTENDED USER?
	JRST	DEBRP1		;NO, HANDLE OTHER WAY
IFE PSIMPI,<
	HLLZ	P3,PITCIC(P1)	;GET FLAGS FROM STORAGE
	POPJ	P,		;AND RETURN ALL FIXED UP
>
IFN PSIMPI,<
	HLLZ	P3,PITCIC-PITCIB(T1)	;GET FLAGS FROM RIGHT LEVEL BLOCK
	JRST	TPOPJ##		;RETURN DOUBLEWORD PC
>
DEBRP1:	TRZ	P3,-1		;CLEAR JUNK
	HLL	P4,T4		;STAY IN SAME SECTION
IFE PSIMPI,<POPJ P,>		;RETURN DOUBLEWORD PC
IFN PSIMPI,<JRST TPOPJ##>	;RETURN DOUBLEWORD PC
SUBTTL	UUOCON INTERFACE -- PIJBI.

;CALL TO INTERRUPT ANOTHER JOB AND GIVE STATUS
;CALL WITH:
;	MOVE	AC,[XWD JCH 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::	PUSHJ	P,SAVE1##	;PLACE TO SAVE ARGUMENT
	MOVE	P1,T1		;SAVE IT
	HLRZ	T1,P1		;GET JUST HANDLE TO INTERRUPT
	CAIN	T1,-1		;SELF POINTER?
	MOVE	T1,J		;YES, USE JOB NUMBER
	MOVE	T4,T1		;SAVE CONTEXT TO INTERRUPT
	TRNE	T4,CTXMSK##	;CONTEXT NUMBER GIVEN?
	PUSHJ	P,CTXJCJ##	;YES, GET CURRENT HANDLE FROM CTXSER
	  MOVE	T1,J		;NO, DON'T INCLUDE IT IN STATUS
	HRL	P1,T1		;PUT HANDLE INTO STATUS WORD
	MOVE	T1,T4		;GET TARGET AGAIN
	PUSHJ	P,CTXPSI##	;GET PIT FROM CTXSER
	  JRST	ECOD0##		;(0) ILLEGAL JOB NUMBER
	JUMPE	T2,ECOD0##	;(0) NOT ENABLED FOR INTERRUPT
	MOVEI	T3,JBIBIT	;BIT FOR ENABLED THIS TYPE OF INTERRUPT
	TDNN	T3,PITENB(T2)	;YES, USER ENABLED FOR CROSS JOB INTERRUPTS
	JRST	ECOD0##		;(0) NOT ENABLED FOR INTERRUPT
	UUOLOK			;PREVENT RACES WITH OTHER CPUS
	SKIPN	T3,PITST2(T2)	;TARGET ALREADY HAVE ONE PENDING
	MOVEM	P1,PITST2(T2)	;NO, GIVE HIM THIS ONE
	UUONLK			;ALLOW OTHER CPUS BACK IN NOW
	JUMPN	T3,ECOD1##	;(1) TARGET IS BUSY, TRY LATER
	MOVE	J,T4		;GET HANDLE INTO J FOR SIGNAL
	SIGNAL	C$JBI		;CAUSE THE INTERRUPT
	  JRST	ECOD0##		;(0) REALLY OUGHT TO STOPCD HERE SINCE JUST CHECKED
	JRST	CPOPJ1##	;GIVE GOOD RETURN TO CALLER
SUBTTL	UUOCON INTERFACE -- PITMR.

;CALL TO INTERRUPT THE CURRENT JOB WHEN SPECIFIED TIMER EXPIRES
;CALL WITH:
;	MOVE	AC,[XWD FLAGS,INTERVAL]
;	PITMR.	AC,
;	  HERE ON AN ERROR
;	HERE WHEN TIMER REQUEST HAS BEEN ENTERED
;FLAG BITS:
;	1B0	ON =  INTERVAL IS IN MILLISECONDS (BETTER RESOLUTION)
;		OFF = INTERVAL IS IN SECONDS (LONGER REQUESTS AVAILABLE)

PITMR::	MOVSI	T2,(TMRBIT)	;BIT FOR ENABLED THIS TYPE OF INTERRUPT
	SKIPE	T3,JBTPIA##(J)	;JOB USING PSISER
	TDNN	T2,PITENB(T3)	;YES, USER ENABLED FOR TIMER INTERRUPTS
	JRST	ECOD0##		;(0) NOT ENABLED FOR INTERRUPT
	TLNE	T1,377777	;ONLY 1 FLAG BIT DEFINED AT THE MOMENT
	JRST	ECOD1##		;(1) UNIMPLEMENTED BIT IS SET
	TLZN	T1,(1B0)	;ALREADY IN MILLISECONDS
	IMULI	T1,^D1000	;NO, GET IT THERE
	IMUL	T1,TICSEC##	;CONVERT FROM MILISECONDS
	IDIVI	T1,^D1000	; TO JIFFIES
	SKIPE	T1		;REQUEST FOR 0 TIME BECOMES 1 TICK
	SKIPE	T2		;ANY REMAINDER
	AOS	T1		;YES, ROUND UP TO FULL JIFFY
	TLNE	T1,-1		;ONLY 18 BITS IN THE CLOCK REQUEST QUEUE
	MOVEI	T1,-1		;SO ROUND DOWN TO MAXIMUM TIMER
	HRLI	T1,PSITMR	;WHERE TO GO WHEN IT EXPIRES
	PUSH	P,T1		;SAVE FROM CTXSER
	PUSHJ	P,CTXJCJ##	;GET HANDLE TO INTERRUPT FROM CTXSER
	  JFCL			;CAN'T FAIL
	POP	P,T2		;CLKCHG WANTS STATUS IN T2
	PUSHJ	P,CLKCHG##	;FIND, MODIFY ANY PREVIOUS PITMR. CALLS
	  CAIA			;NONE, ADD A NEW ONE
	JRST	CPOPJ1##	;GIVE GOOD RETURN TO UUO
	PUSH	P,T1		;SAVE FROM CTXSER
	PUSHJ	P,CTXJCJ##	;GET HANDLE AGAIN
	  JFCL			;CAN'T FAIL
	POP	P,T2		;GET CLKCHG VALUE BACK
	SYSPIF			;2 WORDS PER ENTRY
	IDPB	T2,CLOCK##	;STORE ADDRESS AND INTERVAL
	IDPB	T1,CLOCK##	;DATA ITEM IS THE CONTEXT HANDLE
	SYSPIN			;DONE STORING
	SETOM	CLKNEW##	;MARK A NEW ENTRY IN THE SYSTEM QUEUE
	JRST	CPOPJ1##	;GIVE GOOD RETURN TO UUO

;HERE WHEN THE TIMER SET BY PITMR. EXPIRES, INTERRUPT THE JOB

PSITMR:	PUSHJ	P,CTXPSI##	;GET PIT FOR CONTEXT
	  POPJ	P,		;WENT AWAY
	JUMPE	T2,CPOPJ##	;GO AWAY IF NOT STILL USING PSISER
	PUSH	P,J		;SAVE FOR CALLER
	MOVE	J,T1		;GET JCH WHERE IT BELONGS
	SIGNAL	C$TMR		;CAUSE THE INTERRUPT
	  JFCL			;IGNORE FAIL RETURN
	JRST	JPOPJ##		;RETURN TO CLOCK1
SUBTTL UUOCON INTERFACE -- PIBLK.

;CALL TO RETURN USER INTERRUPT BLOCK ADDRESS FOR INTERRUPT IN PROGRESS
;CALL WITH:
;	PIBLK.	AC,
;	  HERE IF NOT INITIALIZED OR NONE IN PROGRESS
;	HERE WITH AC CONTAINING ADDRESS OF INTERRUPT BLOCK

PIBLK::	PUSHJ	P,SAVE2##	;SAVE A FEW FIRST
	SKIPN	P1,JBTPIA##(J)	;GET ADDRESS OF PI TABLE
	  PJRST	RTZER##		;ERROR RETURN, NOT INITIALIZED
IFN PSIMPI,<SKIPGE P2,PITHLP(P1)>;GET HIGHEST LEVEL IN PROGRESS
IFE PSIMPI,<SKIPN T1,PITCIB(P1)>;GET INT BLOCK ADDRESS
	  PJRST	ECOD1##		;ERROR RETURN, NO PI IN PROGRESS
IFN PSIMPI,<
	ADDI	P2,PITCIB(P1)	;POINT TO PITCIB FOR LEVEL IN PROGRESS
	MOVE	T1,0(P2)	;AND GET INT BLOCK ADDRESS
>;END IFN PSIMPI
	JRST	STOTC1##	;GIVE GOOD RETURN WITH BLOCK ADDRESS
SUBTTL	UUOCON INTERFACE -- PIFLG. UUO

;CALL TO SET OR READ FLAGS FOR INTERRUPTED PC FOR A USER TAKING INTERRUPTS
;	IN A MULTI-SECTION ENVIRONMENT
;CALL WITH:
;	SETZ	AC,		;TO READ FLAGS
;		-OR-
;	MOVE	AC,[FLAGS,,1]	;TO WRITE FLAGS
;		-THEN-
;	PIFLG.	AC,
;	  HERE IF NOT EXTENDED USER OR NO INTERRUPT IN PROGRESS
;	HERE WITH AC CONTAINING THE PC FLAGS

;PIFLG. ERROR CODES

PSFNI%==0	;PSI SYSTEM NOT INITIALIZED
PSFNP%==1	;NO INTERRUPT IN PROGRESS
PSFEA%==2	;NOT USING EXTENDED ADDRESSING FORMAT FOR PI SYSTEM
PSFIF%==3	;ILLEGAL FUNCTION CODE

ERCODE	ERRFNI,PSFNI%
ERCODE	ERRFNP,PSFNP%
ERCODE	ERRFEA,PSFEA%
ERCODE	ERRFIF,PSFIF%

PIFLG::	HRRZ	T4,T1		;EXTRACT FUNCTION CODE FROM USER'S ARGUMENT
	CAIL	T4,FLGTBL	;WITHIN RANGE OF DISPATCH TABLE?
	JRST	ERRFIF		;ILLEGAL FUNCTION CODE
	SKIPN	T2,JBTPIA##(J)	;GET PIT ADDRESS AND FLAGS
	JRST	ERRFNI		;NOT INITIALIZED
	TLNN	T2,(SI.UEA)	;EXTENDED USER?
	JRST	ERRFEA		;NOT INITIALIZED FOR EXTENDED ADDRESSING
IFE PSIMPI,<SKIPN PITCIB(T2)>	;SEE IF IN PROGRESS
IFN PSIMPI,<SKIPGE T3,PITHLP(T2)> ;GET HIGHEST LEVEL IN PROGRESS
	JRST	ERRFNP		;NO INTERRUPT IN PROGRESS
IFE PSIMPI,<MOVEI T3,PITCIC(T2)> ;POINT TO CURRENT FLAGS
IFN PSIMPI,<ADDI T3,PITCIC(T2)>	;POINT TO CURRENT FLAGS
	JRST	@FLGTAB(T4)	;FINISH BY FUNCTION-SPECIFIC ROUTINE

FLGTAB:	IFIW	FLGRED		;(0) READ FLAGS
	IFIW	FLGWRT		;(1) WRITE FLAGS
 FLGTBL==.-FLGTAB	;LENGTH OF TABLE

FLGWRT:	HLLM	T1,(T3)		;SET THE FLAGS AS REQUESTED
FLGRED:	HLLZ	T1,(T3)		;GET FLAGS,,0
	JRST	STOTC1##	;RETURN TO USER
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$DTC  = UNIVERSAL DATE/TIME OFFSET
;			C$WAKE = JOB NUMBER OF WAKER
;			C$QUE  = REQUEST ID (AND 1B0=1 IF ABORTING)
;			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
	CAMGE	T1,[C$MIN]	;CONDITION TOO SMALL
	POPJ	P,		;BAD CONDITION
IFN FTXMON,<
	PUSHJ	P,SSEC0##	;MUST BE IN SECTION 0 HERE
>
	PUSHJ	P,SAVE4##	;SAVE A FEW FIRST
	PUSHJ	P,SAVJW##	;SIMILARLY
	DMOVE	P1,T1		;PRESERVE CONDITION & STATUS
	MOVE	T1,J		;GET JCH IN RIGHT REGISTER
	PUSHJ	P,CTXPSI##	;GET PIT FROM CTXSER
	  POPJ	P,		;NO SUCH JOB
	JUMPE	T2,CPOPJ##	;NOT USING PSISER
	MOVE	J,T1		;PUT JCH WHERE IT BELONGS
	MOVE	T1,P1		;RESTORE CONDITION
	MOVE	P1,T2		;GET PIT WORD WHERE WE WANT IT
	MOVE	T2,P2		;RESTORE STATUS
	PUSH	P,F		;SAVE F FOR CALLER
	MOVSI	F,(1B0)		;GET A BIT
	LSH	F,(T1)		;POSITION IT CORRECTLY
	TDNN	F,PITENB(P1)	;USER ENABLE FOR THIS INTERRUPT
	JRST	FPOPJ##		;NO, QUIT NOW
	TDNE	F,[IMBITS]	;IS THIS AN IMMEDIATE CONDITION
	JRST	PSIIMM		;YES, GO DIRECTLY TO GENERATOR
	TRNE	F,DTCBIT	;SET DATE/DAYTIME?
	ADDM	T2,PITST3(P1)	;YES, ACCUMULATE TIME OFFSET
	TRNE	F,QUEBIT	;ENQ/DEQ
	JRST	[SKIPGE	T2		;WERE ANY REQUESTS ABORTED?
		HRLI	T2,(PITQAB)	;YES, REMEMBER FOR LATER
		IORM	T2,PITSTS(P1)	;REMEMBER REQUEST ID
		JRST	.+1]
	TRNE	F,WAKBIT	;WAKE UUO.
	DPB	T2,[POINT 9,PITSTS(P1),17] ;YES, REMEMBER WAKING JOB
	TLNN	F,(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
	JRST	[DMOVE	P2,.JDAT+JOBPD1##	;YES, GET UUO PC
		 JRST	.+2]		;AND SKIP SAVED PC
	DMOVE	P2,USRPC##	;NO, GET SAVED PC
	TLNN	P2,USRMOD	;BETTER BE A USER PC
	DMOVE	P2,.JDAT+JOBPD1## ;GET LAST UUO PC
	PUSHJ	P,ISDDT		;USER IN DDT
	  JRST	FPOPJ##		;YES, LET CONTROL C STOP THE JOB
PSIAGN:	AOS	-1(P)		;USER WANTS INTERRUPT
PSIAG1:	TDNE	F,PITPND(P1)	;ALREADY HAVE THIS ONE PENDING
	JRST	PSIAG2		;YES, JUST WAKE THE JOB
	IORM	F,PITPND(P1)	;LIGHT ONE FOR THIS INTERRUPT
	AOS	PITNPI(P1)	;BUMP PENDING COUNT
PSIAG2:	POP	P,F		;DON'T NEED THIS ANY MORE
	JUMPGE	P1,CPOPJ##	;DON'T WAKE THE JOB IF PI OFF
	MOVE	T1,J		;COPY JCH
	PUSHJ	P,CTXVAL##	;VALIDATE IT
	  POPJ	P,		;CONTEXT WENT AWAY
	  TRZA	J,CTXMSK##	;CURRENT, SET FOR UUOCON
	  POPJ	P,		;NOT CURRENT, WE'LL CATCH IT AT ITS RESTORE
	PJRST	WAKEJB##	;WAKE JOB AND RETURN
;HERE WHEN A CONDITION MUST BE GRANTED IMMEDIATELY (APR STUFF)

PSIIMM:	JUMPGE	P1,FPOPJ##	;CANNOT GRANT IF PS IS OFF
	DMOVE	P3,T1		;SAVE CONDITION AND STATUS AGAIN
	MOVE	T1,J		;COPY JCH
	PUSHJ	P,CTXVAL##	;SEE IF CURRENT
	  JRST	FPOPJ##		;CONTEXT WENT AWAY
	  TRNA			;CURRENT IS OK
	  JRST	PSITLE		;CANNOT GRANT IF NOT CURRENT
	DMOVE	T1,P3		;RESTORE CONDITION AND STATUS
	TDNE	F,[PD1BIT]	;WHERE IS THE CURRENT PC
	JRST	[DMOVE	P2,.JDAT+JOBPD1##	;GET PC OF ALL UUOS
		 JRST	.+2]	;AND SKIP APR CONDITION PC
	DMOVE	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	F,PITMSG(P1)	;USER WANT STANDARD ERROR MESSAGE
	JRST	PSIMSG		;YES, REMEMBER THAT
	AOS	PITNPI(P1)	;KEEP THE COUNT STRAIGHT
	POP	P,F		;BALANCE STACK FOR CALLER
	PJRST	GENCND		;EXIT, CAUSING THE INTERRUPT

PSITLE:	TLNN	F,(TLEBIT)	;WAS THIS TIME LIMIT EXCEEDED
	JRST	FPOPJ##		;NO, IGNORE TRAP
	TDNN	F,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, AND 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 RELATED 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		;GO SIGNAL CONDITION

; HERE WHEN A REEL SWITCH OCCURS

PSIRSW::MOVEI	T1,IR.RSW	;FLAG THAT CONDITION
;	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 AVAILABLE

PSIAVL::PUSHJ	P,SAVE3##	;SAVE A FEW
	MOVEI	P2,IR.IAL	;INPUT AVAILABLE
	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:
IFN FTXMON,<
	PUSHJ	P,SSEC0##		;MUST RUN ONLY IN SECTION 0
>
	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,T1		;SAVE SOME
	PUSH	P,T2		;VOLATILE REGISTERS
	LDB	T1,PJCHN##	;GET JCH OWNING DEVICE
	PUSHJ	P,CTXPSI##	;JOB USING PSISER?
	  JRST	TTPOPJ##	;NO SUCH JCH
	SKIPN	P1,T2		;GET JBTPIA IN RIGHT REGISTER
	JRST	TTPOPJ##	;NOT USING PI SYSTEM
	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,TTPOPJ##	;DON'T WAKE IF PI OFF
	PUSHJ	P,CTXVAL##	;IS THIS THE CURRENT CONTEXT FOR THE JOB?
	  JRST	TTPOPJ##	;CONTEXT WENT AWAY
	  TRNA			;YES, KEEP GOING
	  JRST	TTPOPJ##	;DON'T WAKE IT IF NOT CURRENT
	PUSH	P,J		;SAVE JOB FOR CALLER
	LDB	J,PJOBN##	;GET JOB OF DDB
	PUSHJ	P,WAKEJB##	;WAKE THE JOB
	POP	P,J		;RESTORE
	JRST	TTPOPJ##	;RESTORE CALLER'S T1 AND T2 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
	JRST	[DMOVE	P2,.CPPC## ;YES, GET CURRENT PC
		 JRST	.+2]	;AND SKIP
	DMOVE	P2,.JDAT+JOBPD1## ;NO, GET UUO RETURN PC
	TLNN	P2,(XC.USR)	;BETTER BE A USER MODE PC HERE
	POPJ	P,		;DEFER UNTIL USER GETS OUT
	PUSHJ	P,VALPC		;VALIDITY CHECK THE PC
	  POPJ	P,		;ILLEGAL (MESSAGE ALREADY TYPED)
PSIGN1:	PUSHJ	P,ISPFH		;CHECK IF IN PFH OR DDT
	  POPJ	P,		;DEFER UNTIL USER GETS OUT
	HLRZ	T1,PITIVA(P1)	;GET VECTOR EXTENT
	ANDI	T1,(SECMSK)	;JUST ITS SECTION NUMBER
	PUSHJ	P,SVPCS##	;DO THINGS TO THE RIGHT SECTION
	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-P3 = CURRENT USER MODE PC DOUBLEWORD
;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(F),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
	TLZ	P4,^-<(SECMSK)>	;CLEAR EXTRANEOUS BITS
IFN FTXMON,<
	PUSHJ	P,SAVR##	;NEED ANOTHER REGISTER
	MOVE	R,T1		;PRESERVE CONDITION
	HLRZ	T1,P4		;GET SECTION FOR VECTOR
	PUSHJ	P,SVPCS##	;SET FOR PXCT AND FLTST
	MOVE	T1,R		;RESTORE INTERRUPT REASON
> ;END OF IFN FTXMON
	PUSH	P,J		;SAVE J
	ANDI	J,JOBMSK##	;GET ONLY JOB #
	PUSHJ	P,VALVEC	;VALIDATE THE ADDRESS
	  JRST	JPOPJ##		;INVALID, GAVE ERROR
	PUSHJ	P,PCSTOR	;STORE INTERRUPTED PC FOR USER
	TLNE	P1,(SI.UEA)	;EXTENDED USER?
	EXCTUX	<SKIPA P3,.PSVNP(P4)> ;GET NEW PC FOR INTERRUPT (WITH SECTION)
	EXCTUX	<HRR P3,.PSVNP(P4)> ;GET NEW PC FOR INTERRUPT (IN SECTION)
	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
	DMOVEM	P2,.JDAT+JOBPD1## ;YES, STORE FOR UUO DISMISS
	DMOVEM	P2,.CPPC##	;STORE FOR CLOCK1
	EXCTUX	<MOVE P3,.PSVFL(P4)> ;GET CONTROL FLAGS
	MOVSI	T2,(SI.ON)	;PI SYSTEM ON
	TLNE	P3,(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	P3,(PS.VTO)	;USER WANT IT DONE
	IORM	T2,JBTPIA##(J)	;YES, MARK WAITING FOR DEBRK.
	PUSH	P,P4		;SAVE USERS ADDRESS A MOMENT
	CAML	T1,[C$MIN]	;DEVICE OR CONDITION
	SKIPL	T1		; ..
	SKIPA	P4,[POINT 2,DEVESE(F),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
	MOVEM	P4,0(T2)	;STORE CURRENT INTERRUPT BLOCK
	HRR	P2,T1		;GET PC FLAGS,,CONDITION
	MOVEM	P2,PITCIC-PITCIB(T2)	;STORE CONDITION AND FLAGS
	EXCTUU	<HRRM T1,.PSVFL(P4)> ;STORE REASONS OR CONDITION FOR USER
	CAML	T1,[C$MIN]	;DEVICE OR CONDITION
	SKIPL	T1		; ..
	JRST	[SETZ T1,	;CLEAR T1 FOR STATUS DISPATCH
		 HRRM F,PITCIC-PITCIB(T2)	;STORE REAL CURRENT CONDITION (DDB)
		 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	JPOPJ1##	;RETURN
;SUBROUTINE TO STORE THE INTERRUPT-FROM PC FOR GENINT
;CALL WITH:
;	P1 = PIT POINTER
;	P2-P3 = USER'S PC DOUBLEWORD
;	P4 = START OF BLOCK IN USER'S VECTOR FOR THIS CONDITION
;RETURNS:
;	CPOPJ ALWAYS, WITH THE PC STORED IN THE USER'S INTERRUPT VECTOR

PCSTOR:	TLNN	P1,(SI.UEA)	;EXTENDED USER?
	JRST	PCSTO1		;NO, DO IT THE OTHER WAY
	EXCTXU	<MOVEM P3,.PSVOP(P4)> ;STORE 30-BIT ADDRESS FROM PC FOR USER
	POPJ	P,		;RETURN TO GENINT
PCSTO1:	HRR	P2,P3		;GET SECTION-ZERO STYLE PC
	EXCTXU	<MOVEM P2,.PSVOP(P4)> ;STORE OLD-STYLE PC FOR USER
	TRZ	P2,-1		;CLEAR TRASH
	POPJ	P,		;RETURN TO GENINT
;SUBROUTINE TO FIGURE OUT WHICH INTERRUPT TO GIVE NOW
;CALL WITH:
;	P1 = ADDRESS OF PSI DATA BASE
;	P2-P3 = 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
;	F = 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	F,PITCHN(P1)	;POINT TO FIRST DDB
GEND.1:	JUMPE	F,[SOSG PITNPI(P1) ;COUNT WAS TOO HIGH
		   POPJ P,	;BUT IT'S RIGHT NOW
		   JRST GENNXT]	;LOOK AGAIN IF STILL UP
	HLLZ	T1,DEVPSI(F)	;GET CURRENT ENABLED BITS
	EXCH	T1,DEVPSI(F)	;GET PENDING CONDITIONS, CLEAR THEM
	TLZ	T1,-1		;CLEAR ENABLED BITS
	JUMPN	T1,CPOPJ1##	;USE IT IF ANY INTERRUPTS PENDING
	HLRZ	F,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	F,		;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	F,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	F,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, F=BEST SO FAR, T4=IMPORTANT ONLY IF F = 0

GENWAT:	JUMPE	F,[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,F		;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(F)	;GET ENABLED CONDITIONS FROM DDB
	EXCH	T1,DEVPSI(F)	;LEAVE THEM ALONE, GET SIGNALLED CONDITIONS
	TLZ	T1,-1		;CLEAR JUNK FROM LEFT HALF
	JRST	CPOPJ1##	;RETURN WITH F = 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,LLMPSI##	;(-37) LLMOP EVENT
	PUSHJ	P,ENTPSI##	;(-36) ETHERNET EVENT
	PUSHJ	P,SCSPSI##	;(-35) SCS EVENT
	SETZ	T2,		;(-34) RESERVED TO CUSTOMER
	SETZ	T2,		;(-33) RESERVED TO CUSTOMER
	PUSHJ	P,NXTOOB##	;(-32) OUT-OF-BAND CHARACTER
	PUSHJ	P,GETDTC	;(-31) DATE/TIME CHANGED
	PUSHJ	P,GETJBI	;(-30) CROSS JOB INTERRUPTS
	SETZ	T2,		;(-27) NETWORK TOPOLOGY CHANGE
	PUSHJ	P,GETQUE	;(-26) ENQ/DEQ
	MOVEI	T2,DR.EVT	;(-25) DECNET EVENT
	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
	PUSHJ	P,[IFE FTXMON,<DNCALL (SCTPSI##)>
		   IFN FTXMON,<SNCALL (SCTPSI##,MS.HGH)>
		   POPJ P,]	;(-12) DECNET NSP UUOS
	SETZ	T2,		;(-11) PDL OVERFLOW
	SETZ	T2,		;(-10) APR CONDITIONS
	MOVE	T2,DEVNAM(F)	;(-7) ADDRESS CHECK
	LDB	T2,[POINT 23,.USPFW,35] ;(-6) ILL MEM REF
	PUSHJ	P,GETUUO	;(-5) ILLEGAL UUO
	PUSHJ	P,GETUUO	;(-4) ANY UUO

	PUSHJ	P,GETIOW	;(-3) ^C
	MOVE	T2,DATE##	;(-2) TIMER REQUEST
	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.

	'LLM',,'   '	;(-37) LLMOP EVENT	(-40) UNUSED
	'SCS',,'ETH'	;(-35) SCS EVENT	(-36) ETHERNET EVENT
	'RC1',,'RC2'	;(-33) RSV'D FOR CUST	(-34) RSV'D FOR CUST
	'DTC',,'OOB'	;(-31) DATE/TIME CHANGE (-32) OUT-OF-BAND
	'NTC',,'JBI'	;(-27) NTWRK TOPOLOGY	(-30) CROSS JOB
	'DVT',,'QUE'	;(-25) DECNET EVENT	(-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',,'NSP'	;(-11) PDL OV		(-12) DECNET NSP INTERRUPTS
	'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',,'TMR'	;(- 1) TIME LIMIT	(- 2) TIMER REQUEST
LDSIX:
;SUBROUTINES CALLED BY THE PRECEDING TABLE TO FETCH STATUS

GETUDX:	PUSH	P,U		;SAVE U
	PUSH	P,P1		;SAVE P1 AROUND IONDF
	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	UPOPJ##		;RESTORE U AND RETURN

GETQUE:	MOVE	T2,PITSTS(P1)	;GET SAVED REQUEST ID
	TLZ	T2,(-1-PITQAB-777777)	;ZERO UNWANTED BITS
	ANDCAM	T2,PITSTS(P1)	;CLEAR WHAT WE ARE SIGNALLING
	TLZE	T2,(PITQAB)	;WERE ANY REQUESTS ABORTED?
	TLO	T2,(1B0)	;YES, LIGHT SIGN BIT
	POPJ	P,		;AND RETURN

GETATC:	MOVE	T2,J		;COPY JCH
	ANDI	T2,JOBMSK##	;KEEP ONLY JOB NUMBER
	HRRZ	T2,TTYTAB##(T2)	;GET TTY DDB FOR JOB
	MOVE	T2,DDBLDB##(T2)	;GET ATTACHED LDB
	SOJL	T2,CPOPJ##	;RETURN -1 IF DETACHED
	PUSH	P,U		;SAVE LDB REGISTER
	AOS	U,T2		;GET CORRECT ADDRESS IN U
	SE1XCT	<LDB T2,LDPLNO##>	;GET LINE NUMBER
	ADDI	T2,.UXTRM	;MAKE IT A UDX
	JRST	UPOPJ##		;RESTORE LDB REGISTER 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

GETUUO:	HRLZ	T2,.USMUO	;GET UUO OPCODE
	IOR	T2,.USMUE	;INCLUDE ADDRESS CALCULATION
	POPJ	P,		;RETURN UUO

GETDTC:	SETZ	T2,		;SET TO CLEAR STATUS
	EXCH	T2,PITST3(P1)	;GET THE DATE/TIME OFFSET
	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
	TLZ	J,^-<(SECMSK)>	;CLEAR EXTRANEOUS BITS
	LDB	T1,VECBS2	;GET LOWEST ADDRESS USED
	LSH	T1,W2PLSH##	;MAKE A PAGE NUMBER
	LSH	J,W2PLSH##	;SIMILARLY
	HRL	T1,J		;MAKE XWD LAST-PAGE,,FIRST-PAGE OF PSI VECTOR
	JRST	JPOPJ##		;RESTORE J AND RETURN ANSWER
PSIIV1:	EXCH	J,(P)		;RESTORE J, STORE ANSWER (ZERO)
	JRST	TPOPJ##		;RETURN ZERO WHEN NO CONDITIONS YET

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

PSITST::JUMPGE	T1,CPOPJ##	;ONLY NEGATIVE CONDITIONS HERE
	CAMGE	T1,[C$MIN]	;AND THEN ONLY IN RANGE
	POPJ	P,		;NONE OF THE ABOVE
	MOVE	T3,T1		;SAVE CONDITION
	MOVE	T1,J		;GET JOB NUMBER WHERE WE NEED IT
	PUSHJ	P,CTXPSI##	;GET JBTPIA FOR JCH
	  JRST	PSITS1		;RESTORE T1 AND SAY NO
	JUMPE	T2,PSITS1	;IF NO SUCH JCH OR NOT USING PSISER
	MOVSI	T1,(1B0)	;GET A BIT
	LSH	T1,(T3)		;POSITION IT CORRECTLY
	TDNE	T1,PITENB(T2)	;USER ENABLED FOR THIS TRAP
	AOS	(P)		;YES, GIVE SKIP RETURN
PSITS1:	MOVE	T1,T3		;RESTORE CONDITION (JUST IN CASE)
	POPJ	P,		;RETURN
;SUBROUTINE TO TELL ALL INTERESTED ABOUT NETWORK TOPOLOGY CHANGES
IFN FTNET,<
PSINTC::HRROI	T2,C$NTC	;GET CONDITION TO SIGNAL
	JRST	PSITEL		;GO TELL ALL JOBS AND CONTEXTS
>; END FTNET

;SUBROUTINE TO TELL ALL INTERESTED ABOUT DECNET EVENT
IFN FTDECNET,<
PSIDVT::HRROI	T2,C$DEVT	;GET CONDITION TO SIGNAL
	JRST	PSITEL		;TELL ALL JOBS AND CONTEXTS
>;END OF IFN FTDECNET

;SUBROUTINE TO INFORM JOBS OF KSYS TIMER
PSIKSY::HRROI	T2,C$KSYS	;GET CONDITION TO SIGNAL
	JRST	PSITEL		;GO TELL ALL JOBS AND CONTEXTS

;SUBROUTINE TO INFORM JOBS OF SET DATE/DAYTIME COMMAND
PSISDT::HRROI	T2,C$DTC	;GET CONDITION TO SIGNAL TO THE WORLD
PSITEL:
IFN FTXMON,<
	PUSHJ	P,SSEC0##	;NOT IN SECTION ONE YET
>
	PUSHJ	P,SAVE3##	;SAVE JOB LOOP INDEX AND SCRATCH REGISTERS
	PUSH	P,J		;SAVE J FOR COMCON
	MOVE	P2,T2		;SAVE CONDITION
	MOVE	P3,T1		;SAVE POSSIBLE STATUS (UDT OFFSET)
	MOVE	P1,HIGHJB##	;GET HIGHEST JOB NUMBER ASSIGNED
TELL.1:	MOVE	J,P1		;COPY JOB FOR JCH LOOP
	PUSHJ	P,TELLJB	;INFORM ALL JCHS FOR THIS JOB
	SOJG	P1,TELL.1	;CONTINUE FOR ALL JOBS
	MOVE	T1,P3		;RESTORE UDT OFFSET
	JRST	JPOPJ##		;RESTORE J AND RETURN

;SUBROUTINE TO INFORM ALL OF A JOB'S CONTEXTS ABOUT AN EVENT
;CALLED LIKE PSICND
;RETURNS NON-SKIP ALWAYS

PSIJOB::
IFN FTXMON,<
	PUSHJ	P,SSEC0##	;ALLOW CALLS FROM SECTION ONE
>
	PUSHJ	P,SAVE3##	;PRESERVE REGISTERS
	MOVE	P1,J		;RETURN SAME JOB NUMBER
	DMOVE	P2,T1		;SAVE CONDITION & STATUS
	PUSHJ	P,TELLJB	;TELL ALL JCHS FOR THE JOB
	MOVE	J,P1		;RESTORE THE JOB NUMBER
	DMOVE	T1,P2		;RESTORE STATUS
	POPJ	P,		;RETURN TO CALLER

;SUBROUTINE TO NOTIFY ALL JCHS FOR JOB IN J OF CONDITION & STATUS IN P1 & P2

TELLJB:	MOVE	T1,J		;GET JCH BACK
	TLO	T1,(1B0)	;SET STEP FLAG FOR CTXSER
	PUSHJ	P,CTXPSI##	;GET JCH AND PIT
	  POPJ	P,		;NO SUCH JOB
	MOVE	J,T1		;MOVE JCH FOR SIGNAL
	DMOVE	T1,P2		;GET CONDITION AND STATUS
	PUSHJ	P,PSICND	;SIGNAL THE CONDITION
	  JFCL			;DON'T CARE IF NOT ENABLED
	TRNE	J,CTXMSK##	;CTXSER LOADED?
	JRST	TELLJB		;YES, LOOP OVER ALL JOB'S CONTEXTS
	POPJ	P,		;NO, RETURN NOW
;HERE ON HARDWARE TRAP FOR ARITHMETIC INTERRUPTS

PSIAPR::MOVE	P,[MJOBPD##,,.JDAT+JOBPDL##] ;SET UP A PUSH DOWN LIST
	MOVE	J,.CPJOB##	;GET JOB NUMBER RUNNING
	DMOVE	T1,.USMUP-1	;GET PC OF INTERRUPT
	TRZ	T1,-1		;CLEAR JUNK
	DMOVEM	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
	XJEN	.CPPC##


;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
	HRLZ	T3,.USMUO	;GET UUO OPCODE
	IOR	T3,.USMUE	;INCLUDE EFFECTIVE ADDRESS

	TDZ	T3,[777,,200000] ;CLEAR OUT JUNK
	CAME	T3,[CALLI 216]	;PIFLG.
	CAMN 	T3,[CALLI 212]	;PIBLK.
	POPJ	P,		;DON'T WANT BLK ADDR FOR UUO INTERRUPTED
	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
	PUSH	P,T2
	SIGNAL	C$AUUO		;SIGNAL A UUO IS DONE
	  JRST	TTPOPJ##	;USER CANNOT TAKE IT, DO UUO
	POP	P,T2		;RESTORE REGISTER
	JRST	TPOPJ1##	;SKIP DISPATCH, USER WANTS IT
;SUBROUTINE CALLED BY PSIGEN TO VALIDATE THE INTERRUPT-FROM PC
;RETURNS CPOPJ IF INVALID
;	CPOPJ1 IF OK

VALPC:	TLNN	P1,(SI.UEA)	;EXTENDED USER?
	TLNN	P3,(SECMSK)	;OR SECTION 0 PC?
	JRST	CPOPJ1##	;PC OK, KEEP GOING
	HLRZ	T1,P3		;GET PC SECTION
	PUSHJ	P,SVPCS##	;SET UP FOR PXCTS
	HRRZ	T1,P3		;GET A COPY OF THE PC
	EXCTUX	<MAP T2,(T1)>	;IN-SECTION TRANSLATION
	EXCTUX	<MAP T1,@T1>	;SECTION-ZERO TRANSLATION
;	TLZ	T1,^-<(SECMSK)>	;GET JUST PHYSICAL ADDRESS IN SECTION ZERO
;	TLZ	T2,^-<(SECMSK)>	;AND IN PC SECTION
	CAMN	T1,T2		;IF THE SAME,
	JRST	CPOPJ1##	;THEN THIS IS LEGAL AFTER ALL
	MOVSI	T1,JERR		;JOB ERROR BIT
	IORM	T1,JBTSTS##(J)	;PREVENT TRAPS
	PUSHJ	P,GIVRES##	;GIVE UP ANY RESOURCES
	JSP	T1,ERRPNT##	;START UP AN ERROR MESSAGE (WILL PUSH F & U)
	  ASCIZ/Illegal non-zero section PSI interrupt/
	DMOVE	T1,P2		;COPY THE USER PC
	PUSHJ	P,DPCP##	;CALL PC TYPER
	JRST	PCSTOP##	;STOP JOB, NOT CONTINUABLE
;SUBROUTINE CALLED BY PSIGEN TO VALIDATE THE INTERRUPT VECTOR ADDRESS
;RETURNS CPOPJ IF INVALID
;	CPOPJ1 IF OK

VALVEC:	PUSH	P,T1		;SAVE CONDITION
	HRRZ	T1,P4		;POINT TO ADDRESS (IN-SECTION FOR IADRCK)
	SETO	T2,		;LOOP COUNTER
VALV.1:	PUSHJ	P,IADRCK##	;HAVE UUOCON SEE IF ABOVE JOBPFI
	  JRST	VALV.2		;YES, SAY ILLEGAL TO USER
	  JFCL			;CHECK OURSELVES ABOUT OTHER PROBLEMS
	HLLZ	T4,P4		;GET SECTION NUMBER OF VECTOR
	ADD	T4,T1		;GET GLOBAL ADDRESS
	LSH	T4,W2PLSH##	;CONVERT TO PAGE NUMBER
	SE1XCT	<MOVE T4,@[IW UMAPSN,UMAPS(T4)]>	;GET MAP ENTRY FOR PAGE
	PUSHJ	P,FLTST##	;CHECK IF PAGE CAUSES FAULT
	  JRST	VALV.3		;YES, SAY PAGED OUT
	TDNN	T4,[PM.WRT]	;IS THE PAGE WRITABLE
	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
	MOVE	T2,P4		;GET LOCATION OF VECTOR
	PUSHJ	P,UDPCP##	;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(F)	;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-P3 = PC DOUBLEWORD
;	PUSHJ	P,ISPFH
;	  HERE IF IN PFH OR DDT
;	HERE IF NOT
;WIPES T2

ISPFH:	TLNE	P3,(SECMSK)	;IN SECTION ZERO?
	JRST	ISDDT		;NO, NOT IN PFH
	MOVE	T2,P2		;MOVE PC FOR VMSER
	HRR	T2,P3		;GET REST OF PC
	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,(P3)		;ABOVE START OF DDT?
	JRST	CPOPJ1##	;NO, ALL IS WELL
	HLRZ	T2,.JDAT+JOBDDT## ;GET END OF DDT
	CAIG	T2,(P3)		;ABOVE END?
	AOS	(P)		;YES, NOT IN DDT
	POPJ	P,0		;IN DDT


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