Google
 

Trailing-Edge - PDP-10 Archives - BB-X140B-BB_1986 - 10,7/703mon/errcon.mac
There are 13 other files named errcon.mac in the archive. Click here to see a list.
TITLE ERRCON - MONITOR DETECTED ERROR HANDLING ROUTINES - V1207
SUBTTL T. HASTINGS/TH/CHW/TW/RCC/DAL	27 JAN 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 CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.




;
XP VERRCN,1207	;THIS MACRO PUTS VERSION NO. IN STORAGE MAP AND GLOB

ENTRY	ERRCON		;ALWAYS LOAD ERRCON(IF LIB SEARCH)

ERRCON::
SUBTTL	CLOCK LEVEL APR ERROR HANDLING

;HERE ON PI 7 CLOCK INTERRUPT TO PROCESS APR ERRORS FOR INDIVIDUAL JOBS
;.CPAEF HOLDS COMMUNICATION FLAGS SET BY APR PI INTERRUPT LEVEL
;CALL:	MOVE	S,.CPAEF
;	JUMPN	S,APRILM	;COME HERE IF ANYTHING HAPPENED
;	RETURN TO RESCHEDULE NEW USER

APRILM::MOVEM	S,.CPSAC##	;HERE ON ANY APR ERROR OR MEM PARITY
	SKIPN	J,.CPJOB##	;CURRENT JOB ON THIS CPU
	SETOM	.CPNJE##	;MAKE SURE NULL JOBS AC'S ARE RESTORED
	JUMPGE	S,APRIL1	;REQUEST TO SCAN MEMORY FOR PARITY OR NXM?
	TLNN	S,(CP.PSX!CP.CSX) ;YES IS THIS JUST A PRINT JOB MESSAGES REQUEST?
	JRST	APRIL2		;YES--GO LOOP THRU JOBS AND PRINT MESSAGES TO TTY'S
	PUSHJ	P,PARSWP	;NO--SWEEP CORE (AND FLAG JOBS ON KI10)
APRIL2:	MOVE	J,HIGHJB##	;HIGHEST JOB NUMBER
	TRNE	S,UE.NXM	;NXM INSTEAD OF PARITY ERROR?
	JRST	NXMLOP		;YES--REPORT NXM TO ALL JOBS AFFECTED
				;NO--REPORT PARITY TO ALL JOBS AFFECTED
				; FALL INTO PARLOP
;;LOOP TO SCAN ALL JOBS, ZAP BAD ONES AND PRINT PARITY ERROR MESSAGE
PARLOP:	MOVEI	T1,JS.MPE	;MEM PARITY FOR JOB
	TDNN	T1,JBTSTS##(J)	;JOB HAVE MEM PAR IN LOW/HIGH SEG OR UPMP?
	JRST	PARLO1		;NO--KEEP LOOKING
	ANDCAM	T1,JBTSTS##(J)	;YES, CLEAR IN JOB STATUS WORD
	SKIPN	JBTADR##(J)	;IS LOW SEG STILL IN CORE? (NO IF SWAPOUT ERROR)
	JRST	PARLO1		;NO--KEEP LOOKING
	PUSHJ	P,ZAPHIM	;RETURN ALL HIS RESOURCES
	PUSHJ	P,PARSTP	;STOP JOB AND PRINT MESSAGE
PARLO1:	SOJG	J,PARLOP	;LOOP OVER ALL JOBS
IFN FTMP,<
	PUSHJ	P,GETMM##	;GET THE MM
	  JRST	.-1		;MUST WAIT
>
	PUSHJ	P,CPINXF	;FIX CORE TABLES, IF NEEDED
	  SKIPA			;CORMAX WAS DECREASED
	JRST	PARXIT		;ALL JOBS NOT ZAPPED CAN CONTINUE TO RUN
IFN FTMP,<
	PUSHJ	P,GIVMM##	;RETURN THE MM
>
;HERE IF CORMAX WAS DECREASED SO ALL JOBS MUST BE SCANNED AND ANY
; WHICH ARE TOO BIG TO BE SWAPPED IN MUST BE ZAPPED ALSO
	SETZ	J,		;FIRST CALL ARG. TO JBSTBG
PARLP2:	MOVE	T1,CORMAX##	;GET CURRENT VALUE OF CORMAX
	PUSHJ	P,JBSTBG	;SEE IF THIS JOB IS NOW TOO BIG TO RUN
	  JRST	PARXI1		;ALL JOBS HAVE BEEN LOOKED AT
	PUSHJ	P,PARSTP	;STOP THE JOB AND TELL THE USER
	JRST	PARLP2		;KEEP GOING

;EXIT FROM PARITY SWEEP AND PRINT ROUTINE
PARXIT:
IFN FTMP,<
	PUSHJ	P,GIVMM##	;RETURN THE MM
>
PARXI1:	HRROI	S,UE.PEF	;CLEAR PARITY ERROR FLAG
	ANDCAB	S,.CPAEF##	;OTHER APR ERRORS?
	JUMPN	S,APRILM	;YES, GO PROCESS THEM
	POPJ	P,		;RETURN
NXMLOP:	MOVEI	T1,JS.NXM	;JOB OVERLAPS NXM BIT
	TDNN	T1,JBTSTS##(J)	;DOES THIS JOB OVERLAP NXM?
	JRST	NXMLP1		;NO, KEEP LOOKING
	ANDCAM	T1,JBTSTS##(J)	;CLEAR THE BIT
	CAME	J,MOFLPG##	;IS THIS THE JOB THAT TYPED SET MEM ON?

	SKIPN	JBTADR##(J)	;DOES THIS JOB HAVE CORE IN CORE?
	JRST	NXMLP1		;IF NO TO EITHER, DO NOTHING
	PUSHJ	P,ZAPUSR	;ZAP THE PROGRAM
IFN FTLOCK,<
	PUSHJ	P,UNLOCK##	;UNLOCK IT IF LOCKED
>
	PUSHJ	P,NXMSTP	;STOP THE JOB AND TELL THE USER WHAT HAPPENED
NXMLP1:	SOJG	J,NXMLOP	;LOOP OVER ALL JOBS ON THE SYSTEM
	MOVE	J,.CPJOB##	;JOB CURRENTLY RUNNING ON THIS CPU
	CAMN	J,MOFLPG##	;JOB SETTING MEMORY ON-LINE?
	JRST	NXMXI1		;YES, IT CAUSED NXM, SET MEM ON WILL CALL CPINXF
IFN FTMP,<
	PUSHJ	P,GETMM##	;GET THE MM
	  JRST	.-1		;MUST WAIT
>
	PUSHJ	P,CPINXF	;FIX CORE ALLOCATION TABLES, ETC.
	  SKIPA			;CORMAX WAS DECREASED
	JRST	NXMXIT		;ALL JOBS NOT ZAPPED CAN CONTINUE TO RUN
IFN FTMP,<
	PUSHJ	P,GIVMM##
>
;HERE IF CORMAX WAS DECREASED SO ALL JOBS MUST BE SCANNED AND ANY
; WHICH ARE TOO BIG TOO BE SWAPPED IN MUST BE ZAPPED
	MOVEI	J,0		;STARTING WITH JOB 0,
NXMLP2:	MOVE	T1,CORMAX##	; AND THE CURRENT VALUE OF CORMAX
	PUSHJ	P,JBSTBG	;SEE IF THIS JOB IS NOW TO BIG TO BE RUN
	  JRST	NXMXI1		;ALL JOBS HAVE BEEN LOOKED AT
	PUSHJ	P,NXMSTP	;STOP THE JOB AND TELL THE USER
	JRST	NXMLP2		;SEE IF ANYMORE JOBS ARE TOO BIG
NXMXIT:
IFN FTMP,<
	PUSHJ	P,GIVMM##
>
NXMXI1:	HRROI	S,UE.NXM	;CLEAR SOFTWARE NXM FLAG
	ANDCAB	S,.CPAEF##	; ..
	JUMPN	S,APRILM	;GO PROCESS OTHER ERRORS IF THEY EXIST
	POPJ	P,		;OTHERWISE, RETURN
;SUBROUTINE TO PRINT MEM PAR ERROR FOR JOB N AND STOP JOB
;CALL:	MOVE	J,JOB NO
;	PUSHJ	P,PARSTP
;	ALWAYS RETURN
PARSTP:	PUSHJ	P,SVEUB##	;MAKE JOB ADDRESSABLE
	PUSHJ	P,ZAPPGM##	;"CORE 0"
	JSP	T1,ERRPNT	;PRINT STANDARD ERROR IN JOB MESSAGE
	ASCIZ	/Memory parity error/
	JRST	NXMST1		;PRINT MESSAGE AND STOP HIM

;SUBROUTINE TO PRINT NXM ERROR FOR JOB N AND STOP JOB
NXMSTP:	PUSHJ	P,SVEUB##	;MAKE JOB ADDRESSABLE
	PUSHJ	P,ZAPPGM##	;"CORE 0"
	JSP	T1,ERRPNT	;PRINT ERROR MESSAGE FOR THE USER
	ASCIZ /Non-existent memory error/
	AOS	.CPNJA##	;COUNT NUMBER OF JOBS ZAPPED BECAUSE OF NXM
NXMST1:	DMOVE	T1,.CPMDP##	;PC WHERE THE ERROR OCCURRED
	PJRST	DPCPNT		;PRINT INFO FOR USER AND STOP HIM
;SUBROUTINE CALLED TO HALT CPU ON SERIOUS ERROR IN MEMORY
PARHLT::CONO	PI,PI.OFF	;NO INTERRUPTS DURING TYPEOUT
	PUSHJ	P,PARHL1	;TYPE OUT APPROPRIATE MESSAGE ON CTY
	DIENLK			;GIVE DIE LOCK BACK
	STOPCD	.,HALT,FEM	;++FATAL ERROR IN MONITOR
PARHL1:	MOVEI	T1,CTYWAT##	;NON-PI CTY TYPEOUT ROUTINE ADDRESS
	MOVEM	T1,.CPTOA##	;MAKE IT THE ONE TO USE HERE
IFN FTKL10,<
	PUSHJ	P,SVPPC##	;MAKE SURE WE'RE IN SECONDARY PROTOCOL ON KL10
>
	SKIPN	.CPREP##	;A PARITY ERROR? (NOT NXM)
	JRST	NXMCTY		;NO, NXM REPORT NXM INSTEAD
	PUSHJ	P,INLMES##	;PRINT MESSAGE TO INFORM OPER OF HALT
	ASCIZ	/
?Non-recoverable memory parity error in monitor.

[CPU Halt]

/
	POPJ	P,		;RETURN AND HALT
NXMCTY:	PUSHJ	P,INLMES##	;INFORM OPR OF HALT
	ASCIZ	/
?Non-existent memory detected in monitor.

[CPU Halt]

/
	POPJ	P,		;RETURN AND HALT
;ROUTINE TO SCAN MEMORY FOR PARITY OR NXM ERRORS (APR PI OR PI 7)
;CALLED AT APR PI IF MAY BE A SERIOUS ERROR IN MONITOR AND PIS IN PROGRESS
;CALL:
;	MOVE	J,CURRENT JOB NO. ON THIS CPU
;	MOVE	S,.CPAEF SWEEP REQUEST BITS
;	PUSHJ	P,PARSWP
;	ALWAYS RETURNS - LH .CPMPC SET NEG. IF SERIOUS MONITOR PARITY
;	S PRESERVED

PARSWP::HRRZ	U,.CPCTN##	;GET CPU'S CTY LINE NUMBER
	MOVE	U,LINTAB##(U)	;NOW GET HIS LDB
	TRNN	S,UE.PEF	;PARITY ERROR?
	JRST	NXMSWP		;NO, SWEEP FOR NXM
	PUSHJ	P,ANNSWP##	;YES, TELL OPR THAT A SWEEP IS IN PROGRESS
	SETOM	.CPREP##	;TELL REPORTERS WHICH ERROR TYPE TO REPORT
	SETOM	.CPPAA##	;YES, SET PARITY AND OF BAD ADDRESSES TO -1
	SETOM	.CPPAC##	;SET PARITY AND OF BAD CONTENTS TO -1
	SETZM	.CPPOA##	;SET PARITY OR OF BAD ADDRESSES TO 0
	SETZM	.CPPOC##	;SET PARITY OR OF BAD CONTENTS TO 0
	AOS	.CPPSC##	;INCREMENT PARITY SWEEP COUNT
	SETZM	.CPPTS##	;SET NO OF PARITIES THIS SWEEP TO 0
IFN FTKL10,<
	PUSHJ	P,SVPPC##	;DON'T LET FE TIME US OUT WHILE SWEEPING
>
	PUSHJ	P,@.CPMPS##	;CALL CPU DEPENDENT CORE SWEEP ROUTINE
	SETZM	.CPLPP##	;CLEAR LAST PARITY ERROR PC
	SKIPE	.CPPTS##	;WERE SOME BAD WORDS FOUND ON SWEEP?
	SKIPA	T1,[EDELIM]	;YES--JUST GET END DELIMITER TEXT
	MOVEI	T1,[ASCIZ /Nothing was found.
***************
/]				;NO--TELL THEM THAT
	PUSHJ	P,CONMES##	;PRINT IT
	MOVEI	T1,.ERSPR	;GET CODE FOR DAEMON
	HRL	T1,.CPSLF##	;GET CPU CDB
	PUSHJ	P,DAEEIM##	;POKE DAEMON
	SKIPE	.CPPTS##	;IF SOME REAL ERRORS WERE FOUND
	POPJ	P,		; THEN JUST RETURN NOW
	TLNN	S,(CP.PSX)	;DID PROCESSOR DETECT PARITY?
	AOSA	.CPPCS##	;NO, COUNT CHANNEL SPURIOUS COUNT
	AOS	.CPSPE##	;YES, COUNT PROCESSOR SPURIOUS COUNT
	POPJ	P,		;RETURN
;ROUTINE TO PRINT WHO REQUESTED SCAN, WHERE, AND AT WHAT TIME
PRCHCP::TLNN	S,(CP.PSX)	;REQUESTED BY CPU?
	JRST	PRCHC1		;NO--BY CHANNEL
	MOVEI	T1,[ASCIZ /CPU/]
	PUSHJ	P,CONMES##	;APPEND "CPU"
	MOVEI	T1,5		;START WITH CPU 5
	MOVE	T2,S		;COPY OF S
PRCHC0:	LSH	T2,-1		;NEXT CPU
	TLNN	T2,(CP.PS5_-1)	;IS IT THIS CPU?
	SOJGE	T1,PRCHC0	;NO--TRY NEXT
	PUSHJ	P,RADX10	;YES--APPEND CPU NUMBER
	JRST	PRCHC3		;CONTINUE
PRCHC1:	MOVEI	T1,[ASCIZ /channel /]
	PUSHJ	P,CONMES##	;APPEND "CHANNEL"
	MOVEI	T1,7		;START WITH CHANNEL 7
	MOVE	T2,S		;COPY OF S
PRCHC2:	LSH	T2,-1		;NEXT CHANNEL
	TLNN	T2,(CP.CS7_-1)	;IS IT THIS CHANNEL?
	SOJGE	T1,PRCHC2	;NO--TRY NEXT
	PUSHJ	P,RADX10	;YES--APPEND CHANNEL NUMBER
PRCHC3:	MOVEI	T1,[ASCIZ / on /]
	PUSHJ	P,CONMES##	;APPEND "ON"
	MOVE	T2,.CPLOG##	;SCANNING CPU'S (THIS) NAME
	PUSHJ	P,PRNAME	;APPEND IT
	MOVEI	T1,[ASCIZ / on /]
	PUSHJ	P,CONMES##	;APPEND "ON"
	PUSHJ	P,DAYTIM##	;FINISH WITH DATE AND TIME
	POPJ	P,		;RETURN
;SUBROUTINE TO SWEEP CORE LOOKING FOR NON-EXISTENT MEMORY

NXMSWP:	PUSHJ	P,ANNSWP##	;ANNOUNCE SWEEP
	SETZM	.CPLNA##	;ZERO HIGHEST NXM SEEN
	SETZM	.CPREP##	;SET NXM FLAG
	SETOM	.CPNAA##	;CLEAR AND OF NON-EXISTENT ADDRESSES
	SETZM	.CPNOA##	; AND OR OF NON-EXISTENT ADDRESSES
	SETZM	.CPNJA##	;NO JOBS AFFECTED YET
	AOS	.CPNSC##	;INCREMENT THE NUMBER OF NXM SWEEPS DONE
	SETZM	.CPNTS##	;CLEAR THE COUNT OF NXMS SEEN THIS SWEEP
IFN FTKL10,<
	PUSHJ	P,SVPPC##	;DON'T LET FE TIME US OUT
>
	PUSHJ	P,@.CPMPS##	;SWEEP CORE
	SETZM	.CPLPP##	;CLEAR LAST ERROR PC
	SKIPE	T1,.CPNTS##	;ANY NON-EXISTANT MEMORY SEEN?
	JRST	[SOSE T1	;ANY SEEN?
		 PUSHJ P,PRTEMS	;YES, REPORT THEM
		 MOVEI T1,EDELIM;GET ENDING MESSAGE
		 JRST .+2]	;PRINT THAT
	MOVEI	T1,[ASCIZ /Nothing was found.
***************
/]				;NO--TELL THEM THAT
	PUSHJ	P,CONMES##	;PRINT IT
	MOVEI	T1,.ERSNX	;GET DAEMON CODE
	HRL	T1,.CPSLF##	;GET CPU CDB
	PUSHJ	P,DAEEIM##	;POKE DAEMON
	SKIPE	.CPNTS##	;IF SOME REAL ERRORS WERE FOUND
	POPJ	P,		; THEN JUST RETURN NOW
	TLNE	S,(CP.PSX)	;DID THE PROCESSOR SEE THE NXM?
	AOSA	.CPSNE##	;YES, COUNT PROCESSOR SPURIOUS COUNT
	AOS	.CPNCS##	;NO, COUNT SPURIOUS CHANNEL NXMS
	POPJ	P,		;RETURN

PRTEMS:	MOVEI	T1,[ASCIZ / to /]
	PUSHJ	P,CONMES##	;PRINT END OF RANGE TEXT
	MOVE	T1,.CPLNA##	;LAST NXM ADDRESS IN RANGE
	PUSHJ	P,PRTDI8	;PRINT HIGHEST NXM ADDRESS SEEN
	MOVEI	T1,[ASCIZ / (phys.)
/]
	PJRST	CONMES##	;PRINT THAT

;DELIMITER TEXT FOR CTY SYSTEM ERROR MESSAGES
SDELIM::ASCIZ	/
***************
/
EDELIM::ASCIZ	/***************
/
;SUBROUTINE TO RECORD MEM PARITY DATA FOR EACH BAD WORD
;CALL:	MOVE	T1,REL ADDR WITHIN HIGH OR LOW SEG,
;			-1 IF NEITHER IN MONITOR NOR HIGH NOR LOW SEG
;	MOVE	P1,ABS ADR OF BAD WORD (22 BITS)
;	MOVE	S,.CPAEF FLAG BITS
;	MOVE	P2,CONTENTS OF BAD WORD
;	PUSHJ	P,PARRBD	;RECORD BAD DATA
;	ALWAYS RETURN EVEN IF SERIOUS ERROR
;CALLED FROM CPU DPENDENT MEMORY SWEEP LOOP

PARRBD::TRNN	S,UE.PEF	;A PARITY ERROR?
	JRST	NXMRBD		;NO, RECORD NXM
	AOS	.CPTPE##	;INCREMENTATION NO OF MEM PARITY ERRORS FOR SYSTEM
	AOS	T2,.CPPTS##	;INCREMENT NO OF PARITY ERRORS THIS SWEEP
	SOJG	T2,PARSEC	;IS THIS THE FIRST ERROR THIS SWEEP?
	MOVEM	P1,.CPMPA##	;YES, SAVE BAD ADDRESS
	MOVEM	P2,.CPMPW##	;BAD CONTENTS
	MOVEI	T1,[ASCIZ /Parity errors detected:
/]
	PUSHJ	P,CONMES##	;ANNOUNCE ERRORS SEEN
PARSEC:	MOVEI	T1,[ASCIZ /  at /]
	PUSHJ	P,CONMES##	;PRINT "AT"
	MOVE	T1,P1		;BAD ADDRESS
	PUSHJ	P,PRTDI8	;PRINT IT
	MOVEI	T1,[ASCIZ / (phys.), Contents = /]
	PUSHJ	P,CONMES##	;PRINT MORE MESSAGE
	MOVE	T1,P2		;GET BAD CONTENTS
	PUSHJ	P,HWDPNT	;PRINT IT
IFN FTKL10,<
	MOVEI	T1,[ASCIZ /, ERA = /]
	PUSHJ	P,CONMES##	;CONTINUE MESSAGE
	MOVE	T1,.CPSTE##	;GET ERA FROM LAST SCAN TRAP
	PUSHJ	P,HWDPNT	;PRINT IT
>
	PUSHJ	P,CRLF##	;END WITH CRLF
	ANDM	P1,.CPPAA##	;ACCUM AND OF BAD ADDRESSES THIS SWEEP
	ANDM	P2,.CPPAC##	;ACCUM AND OF BAD CONTENTS THIS SWEEP
	IORM	P1,.CPPOA##	;ACCUM OR OF BAD ADDRESSES THIS SWEEP
	IORM	P2,.CPPOC##	;ACCUM OR OF BAD CONTENTS THIS SWEEP
	MOVE	T2,.CPPTS##	;PARITY ERRORS FOUND ON CURRENT SCAN
	CAIG	T2,M.CBAT##	;IS THERE ROOM FOR THIS BAD ADR IN TABLE?
	MOVEM	P1,.CPBAT##-1(T2) ;YES, STORE IN I-TH POSITION IN CDB
	MOVEM	P1,.CPLPA##	;ALWAYS STORE LAST PARITY ADDRESS
	POPJ	P,		;RETURN
;HERE TO RECORD NON-EXISTANT MEMORY FOUND ON THE SWEEP

NXMRBD:	PUSH	P,T1		;SAVE T1
	AOS	.CPTNE##	;COUNT TOTAL NUMBER OF NXMS SEEN
	AOS	T2,.CPNTS##	;COUNT UP THE NUMBER SEEN THIS SWEEP
	SOJG	T2,NXMSEC	;JUMP IF NOT THE FIRST NXM THIS SWEEP
	MOVEM	P1,.CPMNA##	;FIRST THIS SWEEP, RECORD BAD ADDRESS
	MOVEI	T1,[ASCIZ /Non-existent memory detected:
/]
	PUSHJ	P,CONMES##	;ANNOUNCE ERRORS
NXMSEC:	SKIPN	T2,.CPLNA##	;SEEN A NXM?
	JRST	NXMSE1		;NO
	AOS	T2		;CONTIGUOUS WITH PREVIOUS NON-EXISTANT WORD?
	CAMN	P1,T2		; ...
	JRST	NXMSE2		;NO, JUST RECORD
	PUSHJ	P,PRTEMS	;YES, REPORT THE NXM RANGE
NXMSE1:	MOVEI	T1,[ASCIZ /  at /]
	PUSHJ	P,CONMES##	;PRINT "AT"
	MOVE	T1,P1		;GET BAD ADDRESS
	PUSHJ	P,PRTDI8	;PRINT IT
	MOVEI	T1,[ASCIZ / (phys.)/]
	PUSHJ	P,CONMES##	;AND THIS
NXMSE2:	ANDM	P1,.CPNAA##	;AND OF BAD ADDRESSES
	IORM	P1,.CPNOA##	;OR OF BAD ADDRESSES
	MOVE	T2,.CPNTS##	;NUMBER OF NXM'S SEEN ON CURRENT SCAN
	CAIG	T2,M.CBAT##	;HAVE THE MAXIMUM NUMBER OF BAD ADDRESSES BEEN STORED?
	MOVEM	P1,.CPBAT##-1(T2) ;NO, STORE THIS ONE
 	MOVEM	P1,.CPLNA##	;ALWAYS STORE THE LAST BAD ADDRESS
	MOVE	T1,P1		;BAD ADDRESS TO T1
	LSH	T1,W2PLSH##	;CONVERT TO BAD PAGE
	IDIVI	T1,^D36		;36 BITS/WORD
	MOVE	T2,BITTBL##(T2)	;BIT POSITION WITHIN THE WORD
	IORM	T2,NXMTAB##(T1)	;MARK THIS PAGE AS NON-EXISTANT
	POP	P,T1		;RESTORE T1
	JUMPE	T1,CPOPJ##	;RETURN IF BAD ADDRESS NOT IN THE MONITOR OR A JOB
	JUMPN	J,NXMJHS	;JUMP IF BAD ADDRESS IN SOME SEGMENT
	HRROS	.CPMPC##	;BAD ADDRESS IS IN THE MONITOR,
				; FLAG THIS AS A SERIOUS ERROR
	POPJ	P,		;AND CONTINUE THE SWEEP
NXMJHS:	JUMPL	J,NXMJH2	;FLAG JOB IF IN UPMP
	CAILE	J,JOBMAX##	;BAD ADDRESS IN A HIGH SEGMENT?
	PJRST	HGHPAR##	;YES, FLAG HIGH SEGMENT AS IN NXM
NXMJH2:	MOVEI	T1,JS.NXM	;BAD ADDRESS IN A LOW SEGMENT, FLAG
	IORM	T1,JBTSTS##(J)	; THE JOB TO BE STOPPED
	POPJ	P,		;AND RETURN TO CONTINUE THE SWEEP
;SUBROUTINE TO FLAG JOB FOR MESSAGE - IF APR DETECTED (RATHER THAN CHANNEL)
;CALL:	MOVE	J,JOB NUMBER
;	MOVE	S.CPAEF	;CPU OR CHAN DETECTED PARITY
;	PUSHJ	P,PARJOB
;	ALWAYS RETURN
;CALLED ON CPU0 AND CPU1

PARJOB:	TLNN	S,(CP.PSX)	;PARITY FOUND BY ANY PROCESSOR?
	POPJ	P,		;NO, RETURN
				;YES, FALL INTO PARJB1
;SUBROUTINE TO FLAG JOB FOR MEM PAR MESSAGE - ALWAYS
;CALL:	MOVE	J,JOB NUMBER
;	PUSHJ	P,PARJB1
;	ALWAYS RETURN

PARJB1::MOVSI	T1,JACCT	;CLEAR JACCT SO THAT DAMAGED PROGRAM
	ANDCAM	T1,JBTSTS##(J)	; WILL NOT HAVE PRIVILEGES
	MOVEI	T1,JS.MPE	;MEMORY PARITY ERROR IN JOB FLAG
	IORM	T1,JBTSTS##(J)	;SET JOB STATUS WORD
	POPJ	P,		;RETURN

;SUBROUTINE TO RETURN ALL JOBS WHICH ARE OR WOULD BE TOO BIG TO RUN
; IF MEMORY HAS DROPPED OFF LINE OR WERE TO BE SET OFF LINE
;CALLING SEQUENCE:
;	MOVE	T1,NEW VALUE OF CORMAX
;	MOVEI	J,0	;FIRST CALL
;	PUSHJ	P,JBSTBG
;RETURN CPOPJ IF NO JOB OR NONE OF THE REMAINING JOBS ARE TOO BIG, CPOPJ1
; IF A JOB IS TOO BIG, J = JOB NUMBER OF THE JOB WHICH IS TOO BIG

JBSTBG::PUSH	P,T1		;SAVE THE NEW VALUE OF CORMAX
JBSTB1:	ADDI	J,1		;LOOK AT THE NEXT JOB
	CAMLE	J,HIGHJB##	;LOOKED AT ALL JOBS?
	JRST	TPOPJ##		;YES, GIVE ALL DONE RETURN
	PUSHJ	P,SEGSIZ##	;SIZE OF THIS JOBS LOW SEGMENT
	MOVE	T1,T2		;SAVE THAT
	PUSH	P,J		;SAVE THE JOB NUMBER
	MOVEI	T2,0		;ASSUME THAT THE JOB DOESN'T HAVE A HIGH SEGMENT
	SKIPLE	J,JBTSGN##(J)	;DOES IT?
	PUSHJ	P,SEGSIZ##	;YES, GET THE SIZE OF THE HIGH SEGMENT
	POP	P,J		;RESTORE THE JOB NUMBER
	ADD	T1,T2		;SIZE OF THE JOB IN PAGES
	LSH	T1,P2WLSH##	;SIZE OF THE JOB IN WORDS
	CAMLE	T1,(P)		;IS THE JOB TOO BIG TO CONTINUE TO RUN?
	JRST	TPOPJ1##	;YES, SKIP RETURN TO CALLER
	JRST	JBSTB1		;NO, LOOK AT THE NEXT JOB
;HERE IF NO MEM PARITY - MUST BE APR ERROR
APRIL1:	SETZM	.CPAEF##	;CLEAR APR ERROR FLAG (IN CASE OTHER APR ERRORS
				; OCCUR BEFORE EXIT THIS CODE)
	DMOVE	T1,.CPAPC##	;ERROR PC STORED BY APR PI LEVEL
				; (REAL PC MAY HAVE BEEN ZEROED TO DISMISS INT)
	HRR	T1,T2		;SINGLE WORD PC

	PUTPC	T1,.CPPC##	;STORE IN CURRENT USER PROTECTED PC
				; (SO DUMP WILL KNOW REAL PC)
	PUTPC	T1,.JDAT+JOBPD1##  ;STORE FOR POSSIBLE .JBINT

	TRNE	S,AP.PPV	;PROPRIETARY VIOLATION?
	JRST	APRPPV		;YES
	TRNN	S,AP.ILM	;ILLEGAL MEMORY?
	JRST	APRNXM		;NO
IFN FTPI,<
	SIGNAL	C$IMR		;SIGNAL ILL MEM REF CONDITION
	  SKIPA			;USER DOESN'T WANT TRAP
	POPJ	P,		;WANTS INTERCEPT GO TO USER
>
	MOVE	T1,.CPAPC##+1	;PC STORED BY APR INTERRUPT
	XOR	T1,.USPFW	;PAGE FAULT WORD
	TDNE	T1,[MXSECN*<HLGPNO+1>+<HLGPNO_P2WLSH##>+777]
	JRST	APRILR		;YES, GO PRINT ILL MEM REF
	JSP	T1,ERRPTU	;NO, PRINT PC EXCEEDS MEM BOUND
	ASCIZ	/PC out of bounds/
	JRST	APRSCD		;PRINT LOC, THEN STOP JOB

APRILR:	JSP	T1,ERRPTU
	ASCIZ	/Illegal memory reference/
	JRST	APRSCD		;PRINT LOC, THEN STOP JOB
APRNXM:	TRNN	S,AP.NXM	;NON-EX MEM?
	JRST	APRPDL		;NO
IFN FTPI,<
	SIGNAL	C$NXM		;SIGNAL JOB
	  SKIPA			;NOT INTERRESTED
	POPJ	P,		;TRAP TO USER
> ;END FTPI
	SKIPE	J,.CPJOB##	;JOB RUNNING WHEN NXM HAPPENED
	PUSHJ	P,GIVRES	;RETURN RESOURCES, ETC.
	JSP	T1,ERRPTU	;YES
NXMMES::ASCIZ	/Non-existent memory/
	JRST	APRSCD		;PRINT LOC, THEN STOP JOB
APRPPV:	JSP	T1,ERRPTU
	ASCIZ	/Proprietary violation/
	JRST	APRSCD
;SUBROUTINE TO PRINT JOB NUMBER AND PROG NAME ON OPR
;CALL:	MOVEI	T1,JOB STATUS BIT (JS.MPE OR JS.DPM)
;	MOVE	U,LINE DATA BLOCK FOR CTY OR OPR
;	PUSHJ	P,OPRPJN	;PRINT JOB NUMBERS
;	ALWAYS RETURN

OPRPJN:	PUSH	P,T1		;SAVE JOB STATUS BIT TO TEST FOR MESSAGE
	PUSHJ	P,INLMES##	;TELL HIM JOB NOS. SO HE WILL RESTART
				; SYSTEM JOBS IF THEY HAVE PROBLEM
	ASCIZ	/ for job/
	MOVE	J,HIGHJB##	;HIGHEST JOB NUMBER
;LOOP TO PRINT JOB NOS. AND PROGRAM NAME OF ALL JOBS WITH BAD PARITY
; OR DAEMON PROBLEM MESS
PARLP1:	MOVE	T1,JBTSTS##(J)	;JOB STATUS WORD
	TDNE	T1,(P)		;DOES THIS JOB HAVE BAD PARITY OR DAEMON
				; PROBLEM? (DEPENDING ON CALLERS ARG)
	PUSHJ	P,PRJBNM	;YES, PRINT JOB# AND PROGRAM NAME
	SOJG	J,PARLP1	;ANY MORE JOBS?
	POP	P,T1		;RESTORE STACK
	PJRST	CRLF##		;NO, PRINT CRLF AND RETURN

;SUBROUTINE TO PRINT SWAP OUT MEM PAR ERROR
;CALL:	MOVE	J,JOB USING HIGH SEG (WHETHER IN CORE OR NOT)
;	PUSHJ	P,SWOMES
;	ALWAYS RETURN JOB SWAPPED, DAEMON CALLED

SWOMES::MOVSI	T1,JERR		;SET JERR SO WE DO NOT
	IORM	T1,JBTSTS##(J)	;TRY TO INTERCEPT
	JSP	T1,ERRPNT	;PRINT MESSAGE
	ASCIZ	/Swap out channel memory parity error/
	PJRST	APRSCD		;PRINT PC AND STOP JOB

;SUBROUTINE TO PRINT <SPACE> JOB NO. [PROG. NAME]
;CALL:
;	MOVE	J,JOB NUMBER
;	MOVE	U,LDB FOR OPR OR CTY
;	PUSHJ	P,PRJBNM		;PRINT JOB NO. AND PROG. NAME
;	ALWAYS RETURN
PRJBNM::PUSHJ	P,PRSPC##	;YES, PRINT LEADING SPACE
	MOVE	T1,J		;PRINT JOB NO.
	PUSHJ	P,RADX10	;AS DECIMAL
	PUSHJ	P,PRLBK##	;PRINT LEFT BRACKET
	MOVE	T2,JBTPRG##(J)	;PROGRAM NAME
	PUSHJ	P,PRNAME	;PRINT SO OPER WILL RECOGNIZE HIS JOBS
	PUSHJ	P,PRRBK##	;PRINT RIGHT BRACKET
	POPJ	P,		;RETURN
;SUBROUTINE TO CHECK IF JOB HAS BEEN WAITING FOR TWO SUCCESSIVE
; MINUTE CHECKS FOR DAEMON.  CALLED ONCE A MINUTE FOR EACH JOB
;CALL:	MOVE	J,JOB NUMBER
;	PUSHJ	P,DPMJOB
;	  YES	RETURN - MESSAGE PRINTED ON JOB CONSOLE
;	NO RETURN

DPMJOB::MOVE	T1,JBTSTS##(J)	;JOB STATUS WORD
	TRNN	T1,JS.DPM	;THIS JOB BEEN WAITING FOR 2 CONSECUTIVE MIN?
	JRST	CPOPJ1##	;NO
	PUSHJ	P,STDAEM##	;START DAEMON
	  PJRST	DAEDON##	;NO DAEMON
	PUSHJ	P,TTYFND##	;YES, FIND CONTROLLING TTY
	JUMPE	U,CPOPJ##
	PUSHJ	P,DAEPRB	;PRINT PROBLEM WITH DAEMON
	PUSHJ	P,INLMES##	;TELL USER WHAT SYSTEM IS DOING ABOUT IT
	ASCIZ	/, operator action requested
/
	PJRST	TTYSTR##	;START TTY

;SUBROUTINE TO PRINT ON OPR PROBLEM WITH DAEMON
;CALLED ONCE A MIN ONLY IF A JOB IS STILL WAITING
;CALL:	PUSHJ	P,DPMOPR

DPMOPR::MOVE	U,OPRLDB##	;OPR LINE DATA BLOCK HDR
	PUSHJ	P,DAEPRB	;PRINT PROBLEM WITH DAEMON
	MOVEI	T1,JS.DPM	;JOB STATUS BIT - NEED DAEMON PROB MESS.
	PJRST	OPRPJN		;TELL OPR WHICH JOBS ARE STUCK

;SUBROUTINE TO PRINT PROBLEM WITH DAEMON
;CALL:	MOVE	U,LINE DATA BLOCK ADR
;	PUSHJ	P,DAEPRB

DAEPRB:	PJSP	T1,CONMES##	;PRINT MESSAGE AND RETURN
	ASCIZ	/
%Problem with DAEMON/
APRPDL:	TRNE	S,AP.POV	;PUSHDOWN OVERFLOW?
	JRST	PRTPOV		;YES - PRINT USER ERROR MESSAGE

APRLTH:	TRNN	S,XP.LTH	;LOOP IN TRAP HANDLER?
	STOPCD	CPOPJ##,DEBUG,SAC, ;++STRANGE APR CONDITION
	JSP	T1,ERRPTU	;TYPE MESSAGE
	ASCIZ	/Loop in trap handler/
	JRST	APRSCD		;AND PC OF ERROR

PRTPOV:
IFN FTPI,<
	SIGNAL	C$PLOV		;SEE IF USER CARES
	  SKIPA			;DOESN'T
	POPJ	P,		;HE DOES
>
	JSP	T1,ERRPTU	;PRINT ERROR MESSAGE
PDLMES::ASCIZ	/Push down list overflow/
APRSCD:	DMOVE	T1,.CPAPC##	;PRINT APR PC
	JRST	DPCPNT		;AS:
				; 1)"AT USER LOC XXX" OR
				; 2)"AT EXEC LOC XXX; EXEC CALLED FROM
				; EXEC/USER LOC YYY
SUBTTL	PDL OVERFLOW RECOVERY CODE

;THIS CODE WILL EXTEND A UUO LEVEL PDL; IT SHOULD BE JRSTD TO (IN SECTION 1
;FOR FTXMON MONITORS) FROM K?SER ON A PDL OVERFLOW TRAP.  THE PDL IS EXTENDED
;USING FUNNY SPACE.  THE FOLLOWING RESTRICTIONS APPLY:
;
;1)	IF SUFFICIENT FUNNY SPACE IS NOT AVAILABLE (INSUFFICIENT CONTIGUOUS
;	FREE SLOTS, NO SWAP SPACE, ETC.) THE PDLOVF STOPCODE WILL STILL OCCUR.
;
;2)	IF A PDL OVERFLOW OCCURS WHILE UP.EPL IS LIT IN .USBTS, THE CODE WILL
;	NOT ATTEMPT TO RECOVER AND A PDLOVF STOPCODE WILL RESULT.  THIS IS
;	CURRENTLY TRUE ONLY WHILE THE JOB IS IN THE RECOVERY CODE ITSELF.
;
;ADDITIONALLY, THERE IS A THIRD RESTRICTION WHICH COULD BE REMOVED IF IT IS
;DEEMED NECESSARY, AND THE APPROPRIATE CHECKS ARE MADE:
;
;3)	IF THE STACK IS ALREADY EXTENDED, WE WILL NOT ATTEMPT TO EXTEND THE
;	STACK AGAIN.  THE CODE CAN DO THIS, HOWEVER, IN ORDER TO DO THIS, IT
;	IS NECESSARY TO MOVE THE ORIGIN OF THE STACK.  PAGES ALLOCATED TO THE
;	OLD STACK WILL BE RECLAIMED AT THAT TIME.  CODE ELSEWHERE IN THE MONITOR
;	WHICH PASSES AROUND AN ADDRESS ON THE STACK WILL THEREFORE NO LONGER
;	POSSESS A VALID ADDRESS IN THAT POINTER.  ALTHOUGH THE STACK IS MOVED
;	FROM JOBPDO WHEN EXTENDED THE FIRST TIME, PAGES ARE NOT RECLAIMED SO
;	ANY POINTERS THUS SET UP ARE STILL VALID EVEN THOUGH THE STACK HAS
;	MOVED.  TRVAR AND OTHER T-20 MACROS USE ONE AC FOR THIS PURPOSE (FP),
;	THE ROUTINES AND MACROS WHICH SET UP AND CLEAR THE USE OF FP COULD
;	SET FLAGS SO THAT CODE COULD BE ADDED TO THIS ROUTINE TO GET FP ADJUSTED
;	IF THE STACK MOVES.  THERE ARE, HOWEVER, OTHER PLACES (AT LEAST ONE
;	IN FEDSER) WHICH ALSO WOULD NEED TO BE FIXED; THE EXISTENCE OF OTHER
;	PLACES NEEDS ALSO TO BE RESEARCHED FURTHER BEFORE ANY OF THIS CAN
;	BE IMPLEMENTED.
;
;TO REMOVE RESTRICTION THREE, REMOVE THE LINE OF CODE UNDER "REPEAT 1" AT
;EXTPDL+1 AND ADD THE APPROPRIATE CODE ENUMERATED IN RESTRICTION 3 ABOVE.

EXTPDL::
	MOVEI	P,UP.EPL	;ARE WE ALREADY TRYING TO RECOVER?
REPEAT 1,<			;UNTIL FRAME POINTERS EXIST,
	SKIPN	.USEPL		;WE CAN'T MOVE AN EXTENDED STACK
>				;(SEE COMMENTS ABOVE)
	TDNE	P,.USBTS	;?
	JRST	EPOSTP		;YES, ERROR
	IORM	P,.USBTS	;FLAG IN EMERGENCY PDL
	DMOVEM	T1,.CPSTT##	;SAVE A COUPLE OF ACS
	MOVE	T1,.CPAPC##+1	;GET PC
	MOVEM	T1,.USMUP	;PUT IT BACK IN CASE WE NEED IT LATER
	MOVE	T1,-1(T1)	;GET INSTRUCTION WHICH OVERFLOWED
	TLNN	T1,(<Z	<17^!P>,>) ;BE SURE IT'S P THAT OVERFLOWED
	TLNN	T1,(<Z	P,>)
	JRST	EPOSTP		;NO, ERROR
	MOVE	P,@.CPEPL##	;GET OVERFLOWED PDL
	HLRE	T1,P		;MAKE IT ONLY OVERFLOW BY 1 WORD (ADJSP)
	MOVNS	T1
	ADJSP	P,(T1)
	HRLI	P,-EPDLEN	;THEN SET UP FOR EMERGENCY AREA
	DMOVE	T1,.CPSTT
	PUSHJ	P,EXTPD2	;MUST DO THE FOLLOWING AS A SUBROUTINE
	MOVE	P,@.CPEPL##	;REAL PDL TO RESTART USER WITH
	AOS	EPOREC##	;INCREMENT # OF EPOS RECOVERED FROM
	XJRSTF	.USMUO		;RESTORE FLAGS AND RETURN
;HERE TO DO THE REAL WORK OF EXTENDING THE STACK

EXTPD2:	PUSHJ	P,SAVT##	;SAVE ALL TS
	MOVE	T1,@.CPEPL##	;IN CASE IT GETS CHANGED WHEN WE BLOCK
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN MM?
	  PUSHJ	P,GGVMM##	;NO, MUST HAVE IT FOR THE FOLLOWING
>
	PUSH	P,T1		;SAVE OVERFLOWED STACK POINTER
	HLRZ	T2,(P)		;MINIMUM # OF WORDS WE NEED -1
	SKIPN	T1,.USEPL	;IF MOVING FROM JOBPDO
	ADDI	T2,PDLLEN	;INCLUDE PDLLEN HERE (TAKEN CARE OF LATER
				;IF ALREADY EXTENDED)
	LSH	T2,W2PLSH##	;MINIMUM # OF PAGES WE NEED, -1
	AOS	T2		;# OF PAGES WE NEED
	JUMPE	T1,DOPDL2	;NOT ALREADY EXTENDED, PROCEED
	MOVE	T3,T2		;SAVE IT
	HRRZS	T1		;CLEAR LEFT HALF
	LSH	T1,W2PLSH##	;PAGE # PREVIOUS TO PAGE WHERE EPL STARTS
	SUBI	T1,FYSORG/PAGSIZ## ;PAGE # RELATIVE TO FUNNY SPACE
DOPDL0:	SKIPE	.UPMP+.UMORG(T1) ;IS PREVIOUS PAGE FREE?
	JRST	DOPDL1		;NO, MUST MOVE PDL AGAIN
	SOJLE	T2,DOPDL7	;YES, JUST USE PREVIOUS PAGE(S)
	SOJGE	T1,DOPDL0	;CHECK PREVIOUS PAGE IF THERE IS ONE
DOPDL1:	HLRE	T2,.USEPL	;# OF WORDS IN CURRENT EXTENDED STACK
	ASH	T2,W2PLSH##	;CONVERT TO PAGES
	SUBM	T3,T2		;# OF ADDITIONAL PAGES WE NEED
DOPDL2:	MOVNI	T2,(T2)
	MOVSI	T2,(T2)		;AOBJN COUNTER
	MOVEI	T1,.UMWSB-.UMORG-1 ;START LOOKING AT THE TOP OF FUNNY SPACE
DOPDL3:	SKIPN	.UPMP+.UMORG(T1) ;IS THIS SLOT FREE?
	JRST	DOPDL5		;YES
	TRNN	T2,-1		;ALREADY STARTED A CONTIGUOUS BLOCK?
	JRST	DOPDL4		;NO
	MOVEI	T3,(T2)		;RESET THE AOBJN POINTER
	HRLS	T3
	SUB	T2,T3
DOPDL4:	SOJGE	T1,DOPDL3	;NO, CHECK NEXT
	JRST	EPOSTP		;FAILED
DOPDL5:	AOBJN	T2,DOPDL4	;CONTINUE IF NEED MORE PAGES
	TLOA	T1,(1B0)	;FLAG WE ALREADY KNOW ENTIER PDL SIZE

;HERE WE HAVE FOUND ENOUGH PAGES TO EXTEND THE PDL.  T3=# OF PAGES, T1=FIRST
;PAGE NUMBER RELATIVE TO BEGINNING OF FUNNY SPACE
;(WE ALSO FALL INTO THIS CODE FROM ABOVE WITH T2=# OF PAGES AND IGNORE THE
;FIRST INSTR WHICH LOADS T2 FROM T3)

DOPDL7:	MOVEI	T2,(T3)		;GET # OF PAGES FROM T3
	SETZ	T3,		;CACHE IT
	PUSH	P,T1		;SAVE RELATIVE PAGE #+FLAG
	MOVEI	T1,.MCFV/PAGSIZ##(T1) ;PAGE # OF THE PAGE DESIRED
	PUSH	P,T2		;SAVE T2 (# OF PAGES REQUIRED)
	PUSHJ	P,GETMPG##	;GET PAGES FOR THE JOB'S PDL
	  JRST	EPOSTP		;LOSE IF CAN'T ALLOCATE IT
	POP	P,T2		;RESTORE T2 (# OF PAGES ADDED)
	POP	P,T1		;RESTORE STARTING ADDRESS
	TLZE	T1,(1B0)	;ADDED PAGES OR CREATED NEW SET?
	JRST	DOPD12		;CREATED NEW SET
	HLRE	T3,.USEPL	;-# OF WORDS IN OLD STACK
	MOVNS	T3		;# OF WORDS IN OLD STACK
	MOVEI	T3,PAGSIZ##-1(T3) ;FOR ROUNDING TO # OF PAGES
	LSH	T3,W2PLSH##	;PAGES
	ADD	T2,T3		;# OF PAGES IN NEW (EXTENDED) STACK
	TDZA	T3,T3		;FLAG NO DELETE OF OLD STACK
;HERE ON A NON-RECOVERABLE PDL OVERFLOW

EPOSTP::
	MOVE	P,.CPEPL##	;GET NEW PDL POINTER
	HRLI	P,-<EPLLEN##-1>
	STOPCD	.,JOB,PDLOVF,	;++EXEC PDL OVERFLOW
;HERE TO MOVE THE CURRENT PDL TO SOME NEW ADDRESS.  T1 CONTAINS THE
;PAGE # RELATIVE TO FYSORG/PAGSIZ WHERE NEW STACK WILL BE, T2 CONTAINS # OF PAGES

DOPD12:	SETO	T3,		;DELETE OLD STACK IF NOT JOBPDO
	MOVEI	T1,FYSORG/PAGSIZ##(T1) ;MAKE FIRST PAGE #
	LSHC	T1,P2WLSH##	;CONVERT TO WORDS
	PUSH	P,T3		;SAVE DELETE FLAG
	PUSH	P,T2		;SAVE # OF WORDS IN NEW STACK (INCLUDES EPDLEN)
	HRRZ	T3,P		;FINAL WORD TO MOVE FROM
	PUSH	P,T1		;SAVE WORD ADDR
	SKIPN	T4,.USEPL	;ALREADY EXTENDED?
	MOVEI	T4,.JDAT+JOBPDL## ;NO, MOVE FROM JOBPDL
	HRLI	T1,1(T4)	;MAKE BLT POINTER
	SUBI	T3,1(T4)	;# OF WORDS TO MOVE
	ADDI	T3,(T1)		;FINAL ADDRESS TO MOVE TO
	BLT	T1,(T3)		;MOVE THE STACK
	SUBI	T2,EPDLEN	;# OF WORDS IN NEW PDL (LEAVING EMERGENCY ROOM)
	MOVNS	T2		;-# OF WORDS
	POP	P,T4		;NEW STACK POINTER ORIGIN
	SOS	T4
	HRLI	T4,(T2)		;NEW STACK POINTER COUNT
	MOVEI	T1,(P)		;CURRENT ADDRESS OF OLD TOP OF STACK
	HRRI	P,(T3)		;NEW STACK POINTER
	SUBI	T3,(T1)		;NEW STACK-OLDSTACK
	ADDM	T3,-2(P)	;UPDATE OVERFLOWED POINTER
	POP	P,T1		;TOTAL # OF WORDS IN NEW STACK
	SUBI	T1,EPDLEN	;SUBTRACT OUT EMERGENCY ROOM
	SKIPN	T3,.USEPL	;# OF WORDS IN OLD STACK
	MOVSI	T3,MJOBPD##	;IF MOVING FROM JOBPDL
	HLLZS	T3		;-# WORDS IN OLD STACK,,0
	MOVNS	T1		;-# OF WORDS IN NEW STACK
	HRLZS	T1		;-# OF WORDS IN NEW STACK,,0
	SUB	T1,T3		;-NEW--OLD=OLD-NEW
	ADDM	T1,-1(P)	;-OLD+(OLD-NEW)=-NEW
	POP	P,T3		;NODELETE FLAG
	POP	P,@.CPEPL	;PUT IT FOR RECOVERY CODE TO FIND
	EXCH	T4,.USEPL	;SET NEW STACK POINTER
	JUMPE	T4,DOPD14	;NO OLD PAGES TO DELETE
	JUMPE	T3,DOPD14
	PUSHJ	P,SAVE2##
	AOS	P1,T4		;-# WORDS IN OLD STACK,,1ST PAGE
	ASH	P1,W2PLSH##	;-# PAGES IN OLD STACK,,JUNK(9)1ST PAGE(9)
	TRZ	P1,-1^!<PAGSIZ##-1> ;CLEAR JUNK
DOPD13:	MOVEI	P2,(P1)		;PAGE TO RETURN
	PUSHJ	P,DLTFSP##	;DELETE FUNNY PAGE
	AOBJN	P1,DOPD13
DOPD14:	MOVEI	T1,UP.EPL
	ANDCAM	T1,.USBTS
	POPJ	P,
;HERE TO GO BACK TO THE NORMAL STACK
;THIS MAY BE CALLED AT EITHER UUO OR CLOCK LEVEL, BUT IF CALLED
;AT CLOCK LEVEL THE CPU MUST POSSESS THE MM.

ZAPEPL::
	SKIPN	T1,.USEPL	;ANY EXTENDED STACK?
	POPJ	P,		;NO, NOTHING TO DO THEN
	PUSHJ	P,SAVE2##	;NEED TO USE THE PS
	MOVEI	T1,1(T1)	;ADDRESS OF STACK
	HRLI	P1,(T1)		;FIRST WORD TO MOVE FROM
	MOVEI	P2,(T1)		;ONE MORE COPY
	PUSHJ	P,INTLVL##	;IF AT UUO LEVEL,
	  JRST	ZAPEP0		;TAKE STACK FROM CURRENT P
	SKIPN	JBTADR##(J)	;IF THERE IS NO CORE FOR JOB
	JRST	ZAPEP1		;JUST GET RID OF THE PAGES
	HRRZ	T3,.JDAT+JOBDAC##+P	;GET P FROM JOB DATA AREA
	JRST	ZAPEP3
ZAPEP0:
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN THE MM?
	  PUSHJ	P,GGVMM##	;GET IT IF WE DON'T
>
	MOVEI	T3,(P)
ZAPEP3:	CAIL	T3,.JDAT+JOBPDL##+1 ;IS IT IN FUNNY SPACE OR .UUPMP?
	JRST	ZAPEP1		;.UUPMP, SOMEONE (COMCON) MUST HAVE PUT IT BACK
	SUBI	T1,(T3)		;-# OF WORDS IN CURRENT STACK
	MOVNS	T3,T1		;NEGATE AND SAVE (MAKE POSITIVE)
	CAILE	T1,PDLLEN	;ONLY GET RID OF EXTENDED STACK IF WHAT'S THERE FITS
	POPJ	P,
	ADDI	T1,.JDAT+JOBPDL##+1 ;LAST WORD TO MOVE TO
	HRRI	P1,.JDAT+JOBPDL##+1 ;FIRST WORD TO MOVE FROM
	BLT	P1,(T1)		;MOVE THE STACK
	MOVE	T1,[MJOBPD##,,.JDAT+JOBPDL##]
	ADJSP	T1,1(T3)	;MAKE CURRENT
	PUSHJ	P,INTLVL##	;AT UUO LEVEL?
	  SKIPA	P,T1		;YES, SET UP P
	MOVEM	T1,.JDAT+JOBDAC##+P	;NO, STORE NEW P
ZAPEP1:	HLRE	P1,.USEPL	;# OF WORDS IN EXTENDED PDL (NEGATIVE)
	SUBI	P1,EPDLEN	;INCLUDING EMERGENCY WORDS
	LSH	P1,^D18+W2PLSH	;-# OF PAGES
	LSH	P2,W2PLSH##	;1ST PAGE
	HRRI	P1,(P2)		;SAVE IN P1
	SE1ENT
ZAPEP2:	MOVEI	P2,(P1)		;PAGE #
	PUSHJ	P,DLTFSP##	;DELETE PAGE
	AOBJN	P1,ZAPEP2
	SETZM	.USEPL		;NO MORE EXTENDED PDL
	POPJ	P,
;ADDRESS CHECK ERROR AT ANY LEVEL
;F MUST BE SET UP TO POINT TO OFFENDING DEVICE

ADRERR::
IFN FTPI,<
	LDB	J,PJOBN##	;OFFENDING JOB'S JOB NUMBER
	SIGNAL	C$ADCK		;SEE IF USER ENABLED FOR ADDRESS CHECK
	  SKIPA			;USER DOESN'T WANT TRAP
	JRST	ERRGOU		;GO TO USER
>
	JSP	T1,ERRDEV	;GET JOB NO. FROM DEVICE DATA BLOCK
	ASCIZ	/Address check for /
	JRST	DEVEXC		;PRINT "DEVICE XXX; EXEC CALLED FROM
				; EXEC/USER LOC YYY"
				; THEN STOP JOB
;SUBROUTINE TO CLEAR ALL DDB'S, IO CHARS
;CALL WITH JOB NUMBER IN J
ZAPHIM:	PUSHJ	P,SVEUB##	;MAKE HIM ADDRESSABLE
ZAPHER::PUSHJ	P,SWPCLN##	;ZAP THE ACCESS TABLES
	PUSHJ	P,GIVRSC	;GIVE UP RESOURCES
	PJRST	ZAPUSC		;PITCH INITED DDB'S
ZAPUSR::JUMPE	J,CPOPJ##
	PUSHJ	P,GIVRSC	;GIVE UP ANY INTERLOCKS JOB MAY OWN
	NTGIVE			;RELEASE NETSER INTERLOCK TOO
	CAMN	J,.CPJOB##	;CURRENT JOB?
	POPJ	P,		;YES, GIVE UP INITED DDB'S ON RESET
				; (ALL SHARED RESOURCES ALREADY GIVEN UP)
ZAPUSC::PUSHJ	P,CTXJCJ##	;GET CURRENT CONTEXT NUMBER FOR TARGET JOB
	  MOVEI	T1,(J)		;???
	PUSH	P,T1		;SAVE
ZAPUS1:	HLRZ	F,DEVLST##	;LOC OF FIRST DDB
ZAPUS2:	LDB	T1,PJCHN##	;OWNER OF DDB
	JUMPE	T1,ZAPUS3	;DON'T TRY TO ZAP IT IF NOT OWNED (MPXDDB)
	MOVEI	T2,DEPMSG	;IS THIS DDB CONTROLLED BY MPX
	TDNN	T2,DEVMSG(F)	;IF SO, GIVE IT UP WHEN WE ZAP MPX
	CAME	T1,(P)		;RIGHT GUY OWN IT
	JRST	ZAPUS3		;NO, DON'T RELEASE
	CAIE	F,DSKDDB##	;NO, DON'T RELEASE IT (TRYING TO RELEASE DSKDDB
				; WILL CAUSE AN IME
	PUSHJ	P,RELEA4##	;YES, RELEASE IT
	JUMPE	F,ZAPUS1	;F=0 IF NETWORK DDB WAS RELEASED
ZAPUS3:	HLRZ	F,DEVSER(F)
	JUMPN	F,ZAPUS2
	JRST	TPOPJ##		;PRUNE STACK AND RETURN

;SUBROUTINE TO RESET A JOB WHOSE ASSOCIATED
;HISEG HAD A SWAP INPUT ERROR

ZAPHGH::SKIPN	JBTADR##(J)
	POPJ	P,
	PUSHJ	P,CLRJOB##
	PUSHJ	P,ZAPUSR
	PJRST	ERRSWP
;SUBROUTINE TO RETURN ALL RESOURCES
;CALL WITH J=JOB#
GIVRES::NTGIVE			;RETURN THE NETWORK INTERLOCK
	JUMPE	J,CPOPJ##
	CAMN	J,.CPJOB##	;NO DEVICES ACTIVE IF NOT CURRENT JOB
	PUSHJ	P,IOWAIT##	;WAIT FOR ANY ACTIVE DEVICES TO FINISH
GIVRSC::HLRZ	F,SWPDDB##+DEVSER ;START AT FIRST DSK
GIVRS0:	MOVE	T1,DEVMOD(F)	;IS THIS A DISK?
	TLNN	T1,DVDSK
IFN FTSPL,<
	SKIPGE	DEVSPL(F)	;NO, SPOOLED DDB?
	CAIA			;YES
>
	JRST	GIVRS3		;NO
	MOVE	S,DEVIOS(F)
	LDB	T1,PJOBN##	;YES, THIS JOB OWN IT?
	CAMN	T1,J
	PUSHJ	P,RETRES##	;YES, RETURN ANY RESOURCES IT OWNS
GIVRS3:	PUSHJ	P,NXDDB##	;AND TRY NEXT DDB
	  JRST	[JUMPE F,GIVRS1 ;DONE IF 0
		 CAMN J,.USJOB
		 JRST GIVRS0	;CONTINUE IF JOB IS ADDRESSABLE
		 JRST GIVRS1]	;NEXT ADDRESSABLE - DONE
	JRST	GIVRS0		;TRY NEXT
GIVRS1:	SETZ	T1,		;START WITH FIRST RESOURCE
	DPB	T1,PJBSTS##	;MAKE SURE THAT JOB DOESN'T APPEAR
				; TO HAVE ACTIVE DISK I/O
GIVRS2:	CAMN	J,USRTAB##(T1)	;OWNED BY JOB?
	PUSHJ	P,DVFREE##(T1)	;YES--FREE IT UP
	CAIGE	T1,AVLNUM##	;DONE YET?
	AOJA	T1,GIVRS2	;NO--CONTINUE
	PUSHJ	P,ADFREE##	;RETURN AU,DA IF OWNED
	PUSHJ	P,IPCULK##	;GIVE ANY IPCF INTERLOCK WE OWN
	PUSHJ	P,DTXFRE##	;AND ANY DECTAPE KONTROLLERS
	PUSHJ	P,DWNCX##	;CX IF OWNED
	PUSHJ	P,TPFREE##	;FREE UP TAPE KONTROLLERS
IFN FTKL10,<
	PUSHJ	P,GIVPMR##	;DOES THIS JOB HAVE THE PERFORMANCE METER?
				;NO, SO DON'T GIVE IT UP.
				;YES, GIVE IT BACK SO OTHERS MAY MEASURE
>;END IFN FTKL10
IFN	FTLOCK,<
	PUSHJ	P,UNLOCK##	;UNLOCK THE JOB IF LOCKED
>
	PUSH	P,W		;SAVE W
	PUSHJ	P,FNDPDB##	;FIND JOBS PDB
	 JRST	WPOPJ##		;RETURN IF NONE
	SKIPLE	.PDDVL##(W)	;ANY LOGICAL NAMES AROUND
	PUSHJ	P,SETDVF##	;YES,BLAST THEM
	JRST	WPOPJ##		;RESTORE W AND RETURN
NPDUFL::STOPCD	.,STOP,NPU,	;++NULL PUSH-DOWN-LIST UNDERFLOW

;JSR TO HERE FROM INTRPT LOC
	$LOW
PIERR::0
	EXCH	P,PIEPDL
	STOPCD	.,CPU,PIE,	;++PRIORITY INTERRUPT ERROR
PIEPDL::XWD	0,.
	BLOCK	1
	$HIGH
SUBTTL	COMMON ROUTINES FOR HANDLING ERRORS IN MEMORY

;SUBROUTINE - ABSOLUTE ADDRESS TO SEGMENT NUMBER
;CALL:	MOVE	P1,ABSOLUTE ADDRESS
;	PUSHJ	P,CPIASN
;	  ERROR RETURN IF NOT IN MONITOR OR A HIGH OR LOW SEGMENT OR A UPMP
;	OK RETURN J=0 IF IN MONITOR, OR HIGH OR LOW SEG NO., OR -J IF JOB'S UPMP

CPIASN::SE1ENT			;PAGTAB LIVES IN MS.MEM, HAVE TO RUN EXTENDED
	SETZB	T2,J		;ASSUME IN MONITOR (JOB 0 NOT A LEGAL JOB #)
	LDB	T1,[POINT 13,P1,26] ;SET REL. ADR. FROM ABS. ADR IN MONITOR
	MOVE	T1,@[IW MS.MEM,PAGTAB(T1)] ;GET PAGTAB ENTRY FOR THIS PAGE
	TLNE	T1,MONTRB	;IS THIS A MONITOR PAGE?
	JRST	CPOPJ1##	;YES, GIVE OK RETURN WITH J=0
	MOVE	T3,P1		;SET T3=ABSOLUTE ADDRESS OF ERROR WORD
	LSH	T3,W2PLSH##	;T3=ABSOLUTE PAGE NUMBER OF PAGE CONTAING BAD WORD
	MOVEI	T2,JOBMAX##	;SCAN TO SEE IF BAD ADDRESS IS IN A UPMP
AUPLOP:	HRRZ	T1,JBTUPM##(T2)	;T1=PAGE NUMBER OF THE UPMP
	HRRZ	T4,@[IW MS.MEM,PAGTAB(T1)] ;PAGE MAP
	CAIN	T4,(T3)		;WORD IN THAT PAGE?
	JRST	AUPLO1	;YES

	CAIE	T1,(T3)		;BAD WORD IN THIS UPMP?
	SOJG	T2,AUPLOP	;NO, SCAN ALL USER PAGE MAP PAGES
AUPLO1:	JUMPG	T2,[MOVN J,T2	;IF YES, NEGATIVE JOB NUMBER TO J
		PJRST CPOPJ1##] ;SKIP RETURN
	MOVEI	J,1		;NOW SCAN ALL HIGH/LOW SEGS. STARTING WITH JOB 1
ASNLOP:	MOVEI	T1,0		;ASSUME PARITY ERROR IS IN PAGE 0 OF THIS SEGMENT
	MOVSI	T2,SHRSEG	;SHARABLE SEGMENT BIT
	CAILE	J,JOBMAX##	;IS THIS A LOW SEGMENT?
	TDNE	T2,JBTSTS##(J)	;NO--THEN IT IS A SHARABLE HIGH SEG?
	SKIPN	JBTADR##(J)	;IS THIS JOB OR HIGH SEG IN CORE?
	JRST	ASNAOJ		;NO, LOOK AT THE NEXT SEGMENT
	LDB	T2,JBYHSA##	;ASSUME ITS A HIGH SEG, GET STARTING PAGE NO.
	CAIG	J,JOBMAX##	;IS IT A HIGH SEGMENT?
	LDB	T2,JBYLSA##	;NO--GET STARTING PAGE NUMBER OF LOW SEGMENT
ASNHGH:	CAIN	T2,(T3)		;IS THIS PAGE THE SAME PAGE WHICH CONTAINED AN ERROR?
	JRST	ASNMAP		;YES--SEE IF A MAP
	HRRZ	T2,@[IW MS.MEM,PAGTAB(T2)] ;T2=PAGE NO. OF NEXT PAGE IN THIS SEGMENT
	SKIPE	T2		;IS IT THE LAST PAGE IN THIS SEGMENT?
	AOJA	T1,ASNHGH	;NO, LOOK AT ALL THE PAGES IN THIS SEGMENT
ASNAOJ:	CAIG	J,JBTMAX##	;LOOKED AT ALL SEGMENTS?
	AOJA	J,ASNLOP	;NO, LOOK AT NEXT SEGMENT
	POPJ	P,		;NOT IN MONITOR OR ANY JOB

ASNMAP:	CAILE	J,JOBMAX	;A JOB?
	  JRST	CPOPJ1##	;NO, NOT A MAP IF A HIGH SEG
	PUSHJ	P,SVEUB##	;MAP THIS USER
	MOVE	T1,[-<MXSECN+1>,,.UPMVP/PAGSIZ##]
	AOBJP	T1,CPOPJ1##	;NOT A MAP; S0 CAUGHT ABOVE
	SE1ENT			;FOR PAGE MAP REFERENCES
	MOVEI	T4,(T1)		;FOR GMPTR
	PUSHJ	P,GMPTR##	;GET ENTRY
	CAIA
ASNMP1:	AOS	T4		;INCREMENT
	MOVE	T2,(T4)		;GET NEXT ENTRY
	TLZ	T2,(PM.NAD^!PM.COR)
	TLZE	T2,(PM.COR)	;IN-CORE POINTER?
	CAIE	T2,(T3)		;AND THE ONE WE WANT?
	AOBJN	T1,ASNMP1	;NO, LOOK ON
	SKIPGE	T1		;FIND IT?
	MOVNS	J		;YES, IS A MAP, NEGATIVE JOB #
	JRST	CPOPJ1##
;SUBROUTINE TO FIX CORE ALLOCATION TABLES AFTER PAGES HAVE BEEN
; MARKED OUT IN NXMTAB DUE TO PARITY ERRORS OR NXM'S
;CALLING SEQUENCE:
;	MAKE NXMTAB REFLECT CURRENT STATE OF MEMORY, GIVE BACK CORE
;	BELONGING TO ALL SEGMENTS WHICH OVERLAP NXM, AND
;	PUSHJ	P,CPLNXF	;FIX UP RELEVANT TABLES AND VARIABLES
;RETURNS CPOPJ IF NEW VALUE OF CORMAX .LE. OLD VALUE OF CORMAX (SOME
; JOB MAY BE TOO BIG TO SWAP IN), CPOPJ1 IF ALL IS OK.
;MUST HAVE THE MM RESOURCE-CALLER'S RESPONSIBILITY

CPINXF::SE1ENT			;PAGTAB AND MEMTAB ARE IN THE SKYSEG
	PUSHJ	P,SAVE2##	;SAVE WORKING ACS
	SETZB	T1,T2		;INITIALIZE INDEXS INTO PAGTAB AND NXMTAB
	MOVSI	T3,400000	;FIRST BIT TO LOOK AT IN NXMTAB
	LDB	T4,[POINT 14,MEMSIZ##,26]
	MOVSI	P1,NXMBIT	;LOOK FOR NON-EXISTANT PAGES
	HRROI	P2,MPGSIZ##	;DECREASE MAXMAX BY 1 PAGE FOR EACH NON-EXISTANT PAGE SEEN
CPINX1:	TDNN	P1,@[IW MS.MEM,PAGTAB(T1)] ;PAGE ALREADY MARKED AS NON-EXISTANT?
	TDNN	T3,NXMTAB##(T2)	;NO, IS IT NON-EXISTANT NOW?
	JRST	CPINX2		;NO, FORGE AHEAD
	SKIPL	@[IW MS.MEM,PAGTAB(T1)] ;IS THIS NON-EXISTANT PAGE ON THE FREE CORE LIST?
	STOPCD	.,STOP,NPN,	;++NON-EXISTANT PAGE NOT FREE
	ADDM	P2,MAXMAX##	;DECREASE MAXMAX BY 1 PAGE
	ADDM	P2,RMCMAX##	;AND REAL MAXIMUM CORMAX
	HLLM	P1,@[IW MS.MEM,PAGTAB(T1)] ;AND MARK THIS PAGE AS NON-EXISTANT
CPINX2:	ADDI	T1,1		;NEXT PAGE
	ROT	T3,-1		;NEXT BIT POSITION IN NXMTAB
	SKIPG	T3		;CROSSED A WORD BOUNDARY?
	ADDI	T2,1		;YES, BUMP TO NEXT WORD IN NXMTAB
	SOJG	T4,CPINX1	;LOOP OVER ALL PAGES
CPINX3:	MOVE	T1,PAGPTR##	;POINTER TO THE FREE CORE LIST
	JUMPE	T1,CPINX5	;JUMP IF THERE ARE CURRENTLY NO PAGES ON THE FREE LIST
	TDNN	P1,@[IW MS.MEM,PAGTAB(T1)] ;IS THIS PAGE NOW NON-EXISTANT?
	JRST	CPINX5		;NO
	MOVE	T2,@[IW MS.MEM,PAGTAB(T1)] ;YES, LINK FREE CORE LIST AROUND IT
	HRRZM	T2,PAGPTR##	;STORE NEW FIRST PAGE ON FREE CORE LIST
	SOS	CORTAL##	;DECREMENT COUNT OF POTENTIALLY FREE PAGES
	SOS	BIGHOL##	;DECREMENT COUNT OF FREE PAGES
	JRST	CPINX3		;CONTINUE TO LOOK AT PAGES AT THE BEGINNING
				; OF THE FREE CORE LIST
CPINX4:	HRRZ	T1,T2		;CURRENT INDEX INTO PAGTAB
CPINX5:	HRRZ	T2,@[IW MS.MEM,PAGTAB(T1)] ;NEXT PAGE IN PAGTAB
	JUMPE	T2,CPINX6	;JUMP IF THIS IS THE END OF THE FREE CORE LIST
CPNX5A:	TDNN	P1,@[IW MS.MEM,PAGTAB(T2)] ;IS THIS PAGE NOW NON-EXISTANT?
	JRST	CPINX4		;NO
	HRRZ	T2,@[IW MS.MEM,PAGTAB(T2)] ;YES, LINK FREE CORE LIST AROUND IT
	HRRM	T2,@[IW MS.MEM,PAGTAB(T1)] ; ..
	SOS	CORTAL##	;DECREMENT THE COUNT OF POTENTIALLY FREE PAGES
	SOS	BIGHOL##	;AND THE COUNT OF FREE PAGES
	SKIPE	T2
	HRRM	T1,@[IW MS.MEM,PT2TAB(T2)]
	JUMPN	T2,CPNX5A	;LOOP OVER THE ENTIER FREE CORE LIST
CPINX6:	MOVEI	T1,0		;INITIALIZE COUNT OF EXISTANT UNLOCKED PAGES
	MOVE	T2,MEMSIZ##	;PREVIOUS HIGHEST ADDRESS + 1
	SUB	T2,SYSSIZ##	;RANGE OF USERS CORE
	LSH	T2,W2PLSH##	;NUMBER OF PAGES FROM TOP OF THE MONITOR
				; TO THE PREVIOUS TOP OF MEMORY
	MOVE	T3,SYSSIZ##	;WHERE TO START LOOKING FOR UNLOCKED EXISTANT PAGES
	LSH	T3,W2PLSH##	;PAGE NUMBER TO START AT
CPINX7:	MOVE	P1,@[IW MS.MEM,PAGTAB(T3)] ;PAGE DESCRIPTOR BITS FROM PAGTAB
	TLNE	P1,LKBITS-MONTRB;IS THIS PAGE LOCKED OR NON-EXISTANT?
	JRST	CPINX8		;YES, DON'T CONSIDER IT IN COMPUTING NEW CORMAX
	MOVEI	T4,1(T3)	;HIGHEST EXISTANT PAGE + 1 THAT WAS SEEN
	TLNN	P1,MONTRB	;IS THIS A MONITOR PAGE?
	ADDI	T1,PAGSIZ##	;NO, INCREASE NEW CORMAX BY ONE PAGE
CPINX8:	ADDI	T3,1		;NEXT PAGE IN PAGTAB
	SOJG	T2,CPINX7	;LOOP OVER ALL PAGES
	MOVEI	T2,PAGTAB-1(T4)	;BYTE POINTER TO HIGHEST PAGE
	SSX	T2,MS.MEM	;SECTION NUMBER IN LEFT HALF
	MOVEM	T2,CORLST##	;STORE THAT FOR CHKTAL
	LSH	T4,P2WLSH##	;HIGHEST EXISTANT ADDRESS + 1
	MOVEM	T4,MEMSIZ##	;STORE THAT AS THE SIZE OF MEMORY
	MOVE	T2,RMCMAX##	;REAL MAXIMUM CORMAX INCLUDING FUNNY SPACE
	CAMLE	T1,T2		;ROOM FOR FUNNY PAGES?
	MOVE	T1,T2		;NO, MAKE ROOM
	CAML	T1,CORMAX##	;NEW CORMAX LESS THAN THE OLD CORMAX?
	AOSA	(P)		;NO, INDICATE ALL JOBS CAN STILL RUN
	MOVEM	T1,CORMAX##	;YES, STORE NEW VALUE OF CORMAX AND GIVE
				; A NON-SKIP RETURN TO INDICATE THAT SOME
				; JOBS MAY BE TOO LARGE TO BE SWAPPED IN
	POPJ	P,		;RETURN
SUBTTL	ERROR REPORTING FOR CHANNEL ERRORS
IFN FTKL10,<
;SUBROUTINE TO STORE CHANNEL DATA ON ALL HARD AND SOFT ERRORS
;CALL:	MOVE	F,DEVICE DATA BLOCK ADR
;	MOVE	U,UNIT DATA BLOCK ADR
;	MOVE	P1,CHANNEL DATA BLOCK ADDRESS(CHN'N'CB)
;	MOVE	T1,ADDRESS OF FIRST CCW IN CCW LIST
;	PUSHJ	P,CHNMPE OR CHNNXM (MEMORY PARITY OR NXM)
;	RETURN WILL ALL REGISTERS PRESERVED EXCEPT T1-T4

;SUBROUTINE FOR MEMORY PARITY
CHNMPE::AOS	.CHMPE(P1)	;INCREMENT NO. OF MEM PARITY ERRORS
	PUSHJ	P,SAVE4##	;SAVE P REGISTERS
	SETO	P4,		;INDICATE PARITY ERROR
	JRST	CHNCOM		;JOIN COMMON CODE

;SUBROUTINE FOR NXM
CHNNXM::AOS	.CHNXM(P1)	;INCREMENT NO. OF NXMS
	PUSHJ	P,SAVE4##	;SAVE P REGISTERS
	SETZ	P4,		;INDICATE NXM ERROR
CHNCOM:	SETOM	.CPCHE##	;FLAG CHANNEL ERROR CODE IS RUNNING
	HRRM	U,.CHLUE(P1)	;SAVE UNIT DATA BLOCK ADR
	HRRM	F,.CHLDE(P1)	;SAVE DEVICE DATA BLOCK ADR
	PUSH	P,U		;SAVE U
	HRRZ	U,.CPCTN##	;GET CPU'S CTY LINE NUMBER
	MOVE	U,LINTAB##(U)	;GET CTY'S LDB
	PUSHJ	P,CHNCCW	;COLLECT CCW DATA
	SKIPE	P4		;IS THIS A NXM ERROR?
	PUSHJ	P,CHNDAT	;NO--COLLECT DATA WORDS ALSO
	MOVEI	T1,SDELIM	;GET ADRESS OF TEXT
	PUSHJ	P,CONMES##	;PRINT START DELIMITER
	MOVE	T2,.CPLOG##	;GET THIS CPU'S NAME
	PUSHJ	P,PRNAME	;PRINT IT
	SKIPE	P4		;NXM ERROR?
	SKIPA	T1,[[ASCIZ / channel memory parity error on /]] ;NO--PARITY ERROR
	MOVEI	T1,[ASCIZ / channel non-existent memory error on /] ; YES--NXM
	PUSHJ	P,CONMES##	;PRINT ERROR TYPE
	PUSHJ	P,DAYTIM##	;APPEND DATE AND TIME
	MOVEI	T1,[ASCIZ /Device in use is /] ;GET TEXT
	PUSHJ	P,CONMES##	;PRINT DEVICE PREFIX MESSAGE
	MOVE	T2,DEVMOD(F)	;GET DEVICES CHARACTERISTICS
	HRR	T2,.CHLUE(P1)	;UDB OF DEVICE WHERE ERROR HAPPENED
	TLNE	T2,DVDSK	;IS THIS A DISK?
	SKIPA	T2,(T2)		;YES--GET NAME FROM UDB
	MOVE	T2,DEVNAM(F)	;NO--GET DEVICE NAME FROM DDB
	PUSHJ	P,PRNAME	;APPEND IT
	MOVEI	T1,[ASCIZ /
Channel type is /] ;GET TEXT
	PUSHJ	P,CONMES##	;PRINT CHANNEL TYPE PREFIX MESSAGE
	MOVE	T2,CHB22B##(P1)	;GET CHANNEL TYPE BITS
	TLNN	T2,CP.22B##	;22-BIT CHANNEL?
	SKIPA	T1,[[ASCIZ /DF10/]] ;NO--DEFINITELY A DF10
	MOVEI	T1,[ASCIZ /DF10-C/] ;YES--POSSIBLY A DF10-C
	TLNE	T2,CP.DX1##	;IS IT A DX10?
	MOVEI	T1,[ASCIZ /DX10/] ;YES--GET ITS TEXT
	TLNE	T2,CP.RH2##	;IS IT AN RH20?
	MOVEI	T1,[ASCIZ /RH20/] ;YES--GET ITS TEXT
	TLNE	T2,CP.KLP##	;IS IT A KLIPA?
	MOVEI	T1,[ASCIZ /CI20/] ;YES--GET ITS TEXT
	TLNE	T2,CP.KNI##	;IS IT A KLNI?
	MOVEI	T1,[ASCIZ /NIA20/] ;YES--GET ITS TEXT
	PUSHJ	P,CONMES##	;APPEND CHANNEL TYPE
	MOVEI	T1,[ASCIZ /
Termination channel program address = /] ;GET TEXT
	PUSHJ	P,CONMES##	;PRINT TERM. CCW ADDRESS MESSAGE
	HLRZ	T1,.CHFCW(P1)	;GET LH TERMINATION CCW
	SKIPGE	CHB22B##(P1)	;IS THIS A 22-BIT CHANNEL?
	LSH	T1,-4		;YES--THEN ONLY 14 BITS ARE CCW ADDRESS
	PUSHJ	P,OCTPNT	;PRINT IT
	MOVEI	T1,[ASCIZ /
Termination data transfer address = /] ;GET TEXT
	PUSHJ	P,CONMES##	;PRINT TERM. DATA ADDRESS MESSAGE
	MOVE	T1,.CHFCW(P1)	;GET RH TERMINATION CCW
	SKIPGE	CHB22B##(P1)	;IS THIS A 22-BIT CHANNEL?
	TLZA	T1,777760	;YES--GET JUST DATA ADDRESS (22 BITS)
	TLZ	T1,-1		;NO--GET JUST DATA ADDRESS (18 BITS)
	PUSHJ	P,PRT22A	;PRINT IT
	MOVEI	T1,[ASCIZ /
Last three channel commands executed are:
/]
	PUSHJ	P,CONMES##	;PRINT THIS
	MOVE	T1,.CHCW0(P1)	;ARE ALL CCW'S ZERO?
	IOR	T1,.CHCW1(P1)	;...
	IOR	T1,.CHCW2(P1)	;...
	SKIPE	T1		;...
	JRST	CHNCO1		;NO--GO PRINT THEM OUT
	PUSHJ	P,PR3SPC##	;YES--INDENT
	MOVEI	T1,[ASCIZ /** Indeterminate **
/]
	PUSHJ	P,CONMES##	;TELL THEM WE DON'T KNOW
	JRST	CHNCO3		;CONTINUE
CHNCO1:	MOVSI	P2,-3		;FORM AOBJN POINTER
	HRRI	P2,.CHCW2(P1)	; TO SAVED CCW'S
CHNCO2:	PUSHJ	P,PR3SPC##	;INDENT
	MOVE	T1,(P2)		;PICK UP CCW
	PUSHJ	P,HWDPNT	;PRINT IT
	PUSHJ	P,CRLF##	;PRINT CRLF
	AOBJN	P2,CHNCO2	;LOOP IF MORE
CHNCO3:	MOVEI	T1,EDELIM	;GET ENDING DELIMITER
	PUSHJ	P,CONMES##	;PRINT IT
	POP	P,U		;RESTORE U
	SETZM	.CPCHE##	;CLEAR CHANNEL ERROR IN PROGRESS FLAG
	MOVEI	T1,.ERCPE	;CHANNEL ERROR CODE
	HRL	T1,P1		;GET CDB ADDRESS
	PUSH	P,J		;SAVE J
	PUSHJ	P,DAEEIM##	;POKE DAEMON
	POP	P,J		;RESTORE J
	POPJ	P,		;RETURN
;ROUTINE TO STORE CCW DATA FOR CHANNEL ERRORS
CHNCCW:	MOVE	T3,CHB22B##(P1)	;PICK UP CHANNEL TYPE BITS
	MOVE	T2,0(T1)	;GET FIRST CCW IN LIST
	MOVEM	T2,.CHICW(P1)	;SAVE IN CDB FOR F.S.
	TLNN	T3,CP.RH2##	;IS THIS AN RH20?
	JRST	CHNCC1		;NO--PROCEED
	HRRZ	T2,1(T1)	;YES--GET LAST CCW ADDR + 1
	MOVE	P3,2(T1)	;GET TERMINATION CCW
	MOVEM	P3,.CHFCW(P1)	;SAVE IN CDB FOR F.S.
	JRST	CHNCC4		;CONTINUE
CHNCC1:	TLNN	T3,CP.DX1##	;IS THIS A DX10?
	JRST	CHNCC2		;NO--PROCEED
	DPB	P2,[POINT 14,P3,13] ;YES--COMBINE IN TERM. CHANNEL PROGRAM COUNTER
	JRST	CHNCC3		;CONTINUE
CHNCC2:	MOVE	P3,1(T1)	;GET TERMINATION CCW FOR DF10/DF10-C
CHNCC3:	MOVEM	P3,.CHFCW(P1)	;SAVE IN CDB FOR F.S.
	HLRZ	T2,P3		;GET ADDRESS OF LAST CCW
	TLNE	T3,CP.22B##	;IS THIS A 22-BIT CHANNEL?
	LSH	T2,-4		;YES--THEN ONLY 14 BITS ARE CCW ADDRESS
CHNCC4:	TLNE	T3,CP.RH2##	;IS THIS AN RH20?
	SOS	T2		;BACK UP LAST CCW ADDRESS BY 1
	MOVE	P2,T2		;SAVE REAL FINAL CCW ADDRESS HERE
	CAIL	T2,2		;IS FIRST SOURCE ABOVE LOC 0?
	CAML	T2,MEMSIZ##	;YES, IS LAST SOURCE ADR IN BOUNDS?
	JRST	CHNCC6		;NO--JUNK DATA, DON'T ATTEMPT RETRIEVAL
CHNCC5:	MOVE	P3,.CHCW0(P1)	;PUSH EVERYBODY DOWN ONE
	EXCH	P3,.CHCW1(P1)	;...
	MOVEM	P3,.CHCW2(P1)	;...
	MOVE	P3,(T1)		;GET THIS CCW
	MOVEM	P3,.CHCW0(P1)	; AND SAVE AS LAST CCW
	CAMN	P2,T1		;DOES ITS ADDRESS MATCH THE CHANNEL TERM ADDR?
	JRST	CHNCC7		;YES--WE'RE DONE, STOP CHASING LIST
	TLNE	P3,577777	;IS CCW A DATA TRANSFER?
	AOJA	T1,CHNCC5	;YES--BUMP CCW ADDRESS AND GO AROUND AGAIN
	JUMPE	P3,CHNCC6	;NO--IF IT'S A HALT, WE'VE RUN OUT UNEXPECTEDLY
	TLNE	T3,CP.DX1##	;IS THIS A DX10?
	TLNE	P3,200000	;YES--IS THIS A DX10 DEVICE COMMAND CCW?
	SKIPA			;NO--NOT DX10 OR IT'S A DX10 JUMP
	AOJA	T1,CHNCC5	;YES--BUMP CCW ADDRESS AND GO AROUND AGAIN
	MOVE	T1,(T1)		;IT'S A JUMP, GET NEXT CCW ADDRESS
	TLNE	T3,CP.22B##	;IS THIS A 22-BIT CHANNEL?
	TLZA	T1,777760	;YES--GET JUST ADDRESS (22-BITS)
	TLZ	T1,-1		;NO--GET JUST ADDRESS (18-BITS)
	JRST	CHNCC5		; AND GO AROUND AGAIN
CHNCC6:	SETZM	.CHCW2(P1)	;ZERO THE CCW LOCATIONS
	SETZM	.CHCW1(P1)	;...
	SETZM	.CHCW0(P1)	;...
CHNCC7:	MOVE	T2,CHNTCW##(P1)	;GET EXPECTED TERMINATION CCW
	MOVEM	T2,.CHTCW(P1)	;SAVE FOR F.S.
	POPJ	P,		;RETURN
;HERE TO COLLECT RELEVANT DATA WORDS ON PARITY ERROR
CHNDAT:	MOVE	T4,.CHFCW(P1)	;GET TERMINATION CCW
	SKIPGE	CHB22B##(P1)	;IS THIS A 22-BIT CHANNEL?
	TLZA	T4,777760	;YES--GET JUST ADDRESS (22-BITS)
	TLZ	T4,-1		;NO--GET JUST ADDRESS (18-BITS)
	CAIL	T4,2		;IS LAST DATA ADR ABOVE 0?
	CAML	T4,MEMSIZ##	;YES, IS IT IN BOUNDS?
	JRST	CHNDA2		;NO--JUNK DATA, DON'T ATTEMPT RETRIEVAL
	PUSHJ	P,MAPLOC	;GET EVA SLOT
	SUBI	T4,2		;BACK UP STARTING ADDRESS BY TWO
	MOVEI	P2,.CHDW2(P1)	;PLACE TO STORE DATA WORDS
	HRLI	P2,-3		;MAKE AOBJN PNTR
CHNDA1:	LDB	P3,[POINT 13,T4,26] ;GET PAGE NUMBER
	TLO	P3,(<PM.DCD>B2+PM.WRT+PM.PUB) ;BITS

	DPB	P3,T1		;MAP THIS PAGE
	CLRPGT	(0)		;CLEAR PAGING MEMORY
	DPB	T4,[POINT 9,T3,35] ;SET LINE # IN PAGE
	MOVE	P3,(T3)		;FETCH DATA WORD
	MOVEM	P3,(P2)		;STASH IN CDB
	ADDI	T4,1		;ADVANCE TO NEXT LOC
	AOBJN	P2,CHNDA1	;LOOP TILL DONE
	MOVEI	T2,^D50		;WAIT FOR ANY PARITY INTERRUPTS
	SOJG	T2,.		;TO HAPPEN (IF ANY)
	PUSHJ	P,UNMAP		;RESTORE EXEC MAP SLOT
	POPJ	P,		;AND RETURN
CHNDA2:	SETZM	.CHDW0(P1)	;ZERO THE DATA LOCATIONS
	SETZM	.CHDW1(P1)	;...
	SETZM	.CHDW2(P1)	;...
	POPJ	P,		;RETURN
>;END IFN FTKL10

IFN FTKS10,<
CHNMPE::
CHNNXM::POPJ	P,
>;END IFN FTKS10
;ROUTINE TO MAKE AVAILABLE A PAGE MAP SLOT IN EVA SPACE
;MAY BE CALLED AT UUO OR INTERRUPT LEVEL
;CALLING SEQUENCE:
;	PUSHJ	P,MAPLOC
;	RETURN HERE
;   C(T1) := BYTE PNTR TO EPMP SLOT
;   C(T3) := VIRTUAL ADDRESS OF START OF MAPPED PAGE
;CALL UNMAP TO RETORE PREVIOUS CONTENTS OF THE MAP SLOT

MAPLOC::MOVE	T3,.CPMAP##	;ADDRESS OF CURRENT CPU'S EXEC MAP
	MOVE	T1,[POINT 36,.ERPIL/PAGSIZ##,35]
	ADD	T1,T3
	MOVE	T2,.ERPIL/PAGSIZ##(T3) ;CURRENT CONTENTS OF THE MAP SLOT
	EXCH	T2,(P)		;SAVE CURRENT CONTENTS OF THE MAP SLOT
	MOVEI	T3,.ERPIL	;VIRTUAL ADDRESS OF THE PAGE TO BE RETURNED
	PJRST	(T2)		;AND RETURN

;ROUTINE TO RESTORE THE CONTENTS OF A MAP SLOT AFTER HAVING CALLED MAPLOC
;CALLING SEQUENCE:
;	PUSHJ	P,UNMAP
;	RETURNS HERE
;PRESERVES ALL ACS

UNMAP::	EXCH	T1,-1(P)	;GET PREVIOUS CONTENTS OF THE MAP
	PUSH	P,T2		;SAVE A WORKING AC
	MOVE	T2,.CPMAP##	;ADDRESS OF THIS CPU'S EXEC MAP
	MOVEM	T1,.ERPIL/PAGSIZ##(T2) ;RESTORE MAP SLOT CONTENTS
	POP	P,T2
	CLRPGT	(0,.ERPIL)	;MAKE OLD MAPPING VISABLE AGAIN
	POP	P,T1		;RETURN ADDRESS
	EXCH	T1,(P)		;RESTORE T1, STORE RETURN ADDRESS ON STACK
	POPJ	P,		;AND RETURN
	SUBTTL	SYSTEM ERROR BLOCK SUPPORT


;ROUTINE TO ALLOCATE A SYSTEM ERROR BLOCK.
;CALL:
;	T1/ LENGTH OF DATA SEGMENT (NOT INCLUDING HEADER)
;	PUSHJ	P,ALCSEB
;RETURN:
;	CPOPJ IF CAN'T ALLOCATE BLOCK
;	CPOPJ1 IF BLOCK ALLOCATED WITH:
;	T1/ ADDRESS OF ERROR BLOCK

ALCSEB::SKIPE	DINITF##	;OUT OF ONCE CODE YET?
	POPJ	P,		;NO, TAKE IMMEDIATE ERROR RETURN
IFN FTXMON,<
	PUSHJ	P,SSEC0##	;GET OUT OF SECTION 1 IF NECESSARY
>; END IFN FTXMON
	PUSH	P,T1		;SAVE THE LENGTH
	MOVEI	T2,.EBHDR(T1)	;LENGTH INCLUDING HEADER TO T2
	PUSHJ	P,GETWDS##	;GET SOME SECTION 0 SPACE
	  JRST	TPOPJ##		;ERROR, CLEAN STACK AND RETURN
	POP	P,T2		;GET LENGTH BACK
	HRRZM	T2,.EBTYP(T1)	;STORE IN TYPE WORD
	MOVEI	T2,.EBHDR-.EBTYP ;LENGTH OF HEADER
	DPB	T2,[POINT 3,.EBTYP(T1),26] ;STORE HEADER LENGTH
	MOVE	T2,DATE##	;GET NOW IN UNIVERSAL FORMAT
	MOVEM	T2,.EBDTM(T1)	;STORE
	MOVE	T2,SYSUPT##	;GET SYSTEM UPTIME
	SETZ	T3,		;CLEAR FOR ASHC
	ASHC	T2,-^D17	;JIFFIES*2**18 IN T3
	DIV	T2,[JIFSEC##*^D24*^D3600] ;DAYS IN LH, FRACTION IN RH
	MOVEM	T2,.EBUPT(T1)	;STORE
	MOVE	T2,.CPASN##	;GET APR SERIAL NUMBER OF THIS CPU
	MOVEM	T2,.EBASN(T1)	;STORE
	JRST	CPOPJ1##	;SKIP RETURN
;ROUTINE TO QUEUE A SYSTEM ERROR BLOCK TO DAEMON.
;CALL:
;	T1/ ADDRESS OF ERROR BLOCK
;	PUSHJ	P,QUESEB
;RETURN:
;	CPOPJ ALWAYS

QUESEB::CONI	PI,T2		;READ PI STATUS
	CONO	PI,PI.OFF	;TURN OFF INTERRUPTS
IFN FTMP,<
	SKIPGE	SEQLOK		;GIVE OTHER CPUS A CHANCE
	AOSE	SEQLOK		;GET THE INTERLOCK
	JRST	.-2		;WAIT
>; END IFN FTMP
	SETZM	.EBLNK(T1)	;MAKE SURE LINK TO NEXT BLOCK IS ZERO
	MOVEM	T1,@SEQBOT	;APPEND THIS ENTRY TO BOTTOM OF QUEUE
	MOVEM	T1,SEQBOT	;MAKE THIS THE NEW LAST ENTRY
IFN FTMP,<
	SETOM	SEQLOK		;RELEASE THE INTERLOCK
>; END IFN FTMP
	TRNE	T2,PI.ON	;WAS PI SYSTEM ON BEFORE?
	CONO	PI,PI.ON	;YES, TURN IT BACK ON
	CAME	T1,SEQTOP	;WAS THIS THE FIRST ENTRY IN THE QUEUE?
	POPJ	P,		;NO, DAEMON ALREADY KNOWS
	MOVEI	T1,.ERSEB	;CODE FOR DAEMON
	PUSH	P,J		;SAVE J AS DAEEIM STEPS ON IT
	S0PSHJ	DAEEIM##	;PROD DAEMON INTO ACTION
	JRST	JPOPJ##		;RESTORE J AND RETURN

	$LOW
SEQTOP::0			;POINTER TO FIRST ENTRY IN QUEUE
SEQBOT:	SEQTOP			;POINTER TO LAST ENTRY IN QUEUE
IFN FTMP,<
SEQLOK:	-1			;INTERLOCK
>; END IFN FTMP
	$HIGH
;SEBLK. UUO USED BY DAEMON TO RETURN THE NEXT ERROR BLOCK FROM THE
;SYSTEM ERROR BLOCK QUEUE.  THE BLOCK IS COPIED INTO THE CALLER'S
;ARGUMENT BLOCK, AND TRUNCATED IF NECESSARY.
;CALL:
;	MOVE	AC,[LENGTH,,ADDRESS]
;	SEBLK.	AC,
;	  ERROR RETURN, AC/ ZERO
;	NORMAL RETURN, AC/ LENGTH OF BLOCK

SEBLK.::PUSHJ	P,PRVJ##	;IS THIS GUY PRIVILEGED?
	  SKIPA			;YES
	JRST	RTZER##		;NO, RETURN A ZERO
	HLRE	T2,T1		;GET LENGTH OF CALLER'S ARGUMENT BLOCK
	CAIG	T2,.EBHDR	;ROOM FOR AT LEAST A ONE WORD ENTRY?
	JRST	UADERR		;NO, ZAP THE FOOL
	CONO	PI,PI.OFF	;PREVENT RACES
IFN FTMP,<
	SKIPGE	SEQLOK		;GIVE OTHER CPUS A CHANCE
	AOSE	SEQLOK		;GET THE INTERLOCK
	JRST	.-2		;WAIT
>; END IFN FTMP
	SKIPN	T2,SEQTOP	;IS THERE A FIRST ENTRY?
	JRST	SEBLK2		;NO
	MOVE	T2,.EBLNK(T2)	;GET LINK TO NEXT BLOCK
	JUMPN	T2,SEBLK1	;JUMP IF MORE ENTRIES IN QUEUE
	MOVEI	T3,SEQTOP	;QUEUE NOW EMPTY, RESET BOTTOM POINTER
	MOVEM	T3,SEQBOT	;...
SEBLK1:	EXCH	T2,SEQTOP	;SAVE NEW FIRST BLOCK ADDRESS, GET OLD
SEBLK2:
IFN FTMP,<
	SETOM	SEQLOK		;RELEASE INTERLOCK
>; END IFN FTMP
	CONO	PI,PI.ON	;ALLOW INTERRUPTS AGAIN
	JUMPE	T2,ECOD1##	;RETURN AN ERROR IF NO BLOCKS QUEUED
	HLRE	T4,T1		;GET LENGTH OF CALLER'S ARGUMENT BLOCK AGAIN
	LDB	T3,[POINT 9,.EBTYP(T2),35] ;GET LENGTH OF ERROR BLOCK BODY
	ADDI	T3,.EBHDR-.EBTYP ;INCLUDE HEADER LENGTH
	PUSH	P,T3		;SAVE LENGTH FOR RETURN TO USER
	CAMGE	T3,T4		;IF ERROR BLOCK LONGER THAN USER'S BLOCK,
	MOVE	T4,T3		; ONLY COPY AS MUCH AS THEY CAN HANDLE
	HRRZS	T1		;KEEP JUST CALLER'S ADDRESS
	ADD	T4,T1		;COMPUTE END ADDRESS
	HRLI	T1,.EBTYP(T2)	;SOURCE ADDRESS OF ERROR BLOCK HEADER
	EXCTXU	<BLT T1,-1(T4)>	;COPY THE ERROR BLOCK TO THE USER
	  ERJMP	SEBLK3		;ADDRESS CHECK, NAUGHTY USER
	LDB	T1,[POINT 9,.EBTYP(T2),35] ;GET LENGTH OF ERROR BLOCK BODY
	ADDI	T1,.EBHDR	;INCLUDE HEADER AND LINK WORD
	PUSHJ	P,GIVWDS##	;RETURN THE BLOCK TO FREE CORE
	POP	P,T1		;RESTORE THE LENGTH OF THE BLOCK
	PJRST	STOTC1##	;STORE IN USER'S AC AND SKIP RETURN

SEBLK3:	LDB	T1,[POINT 9,.EBTYP(T2),35] ;GET LENGTH OF ERROR BLOCK BODY
	ADDI	T1,.EBHDR	;INCLUDE HEADER AND LINK WORD
	PUSHJ	P,GIVWDS##	;RETURN THE BLOCK TO FREE CORE
	JRST	UADERR		;ZAP THE NAUGHTY USER
SUBTTL	STOPCODE PROCESSING

;ROUTINE TO RECOVER/RELOAD AFTER AN INTERNAL
; SYSTEM ERROR.  CALLED ONLY BY STOPCD MACRO
;DISPATCHED TO HERE BY DIE AND PERISH IN COMMON

;RUNNING IN SECTION 0

DIE0::	CONI	PI,.CPCPI##	;SAVE STATE OF MACHINE
	CONO	PI,PI.TFP+177	; ..
	JSR	.CPSVA##	;SAVE ALL AC SETS
	MOVSI	T1,^-MXSECN	;MASK OF EVERYTHING BUT PC COUNTER
	ANDCAB	T1,.CPSPC##+1	;CLEAR SPURIOUS BITS
IFN FTXMON,<
	TLNE	T1,MXSECN	;STOPCODE IN NON-ZERO SECTION?
	XJRST	[MCSEC1+DIE01]	;YES, ENTER SECTION 1 FOR STOPCODE PROCESSING
>; END IFN FTXMON
;RUNNING IN SECTION 1

DIE01:	HRLZ	T1,.USMUO	;GET MUUO OPCODE AND AC
	IOR	T1,.USMUE	;INCLUDE EFFECTIVE ADDRESS
	MOVEM	T1,.CPTRP##	;STORE
	SKIPN	T1,.CPSPC##+1	;GET PC OF STOPCD
	MOVEI	T1,DIEBPC+1	;POINT AT A GENERIC STOPCODE
	MOVEM	T1,.CPSUP##	;STORE IN CDB
	MOVE	M,-1(T1)	;GET XCT INSTRUCTION
	TLC	M,(XCT)		;CLEAR THE XCT OUT OF WORD
	TLNE	M,-1		;MAKE SURE NOTHING IS LEFT
	MOVEI	M,DIEBAD	;OOPS. SOMETHING BAD, POINT TO GENERIC RELOAD.
IFN FTXMON,<
	HLL	M,.CPSPC##+1	;GET SECTION OF STOPCODE
>; END IFN FTXMON
	MOVE	P,.CPEPD##	;SET UP ERROR STACK
	LDB	T1,[POINT 4,2(M),17]	;GET STOPCODE TYPE
	CAIL	T1,S$STOP	;IS IT IN RANGE?
	CAILE	T1,STPMAX	;BOTH WAYS?
	MOVEI	T1,S$STOP	;BAD--DON'T MAKE THINGS WORSE
	MOVEM	T1,.CPSTY##	;SAVE AS LAST STOPCODE TYPE
	MOVE	T1,PRCTAB(T1)	;GET CONTROL BITS
	TLNN	T1,(S%NCSB)	;SUPPRESS CPU/DEVICE STATUS BLOCK STUFF?
	S0PSHJ	RCDSTB##	;READ CPU AND DEVICE STATUS BLOCKS
IFN FTKL10,<
	PUSHJ	P,CSDMP##	;MAKE SURE IT'S ALL IN CORE
	PUSHJ	P,SKPMRN##	;SKIP IF MASTER -11 IS RUNNING
	STOPCD	.,HALT,MNR,	;++MASTER -11 NOT RUNNING
>
	PUSHJ	P,DIE1		;CALL MAIN PROCESSING ROUTINE AS A SUBROUTINE
	PUSHJ	P,DAEEST##	;TELL DAEMON OF STOPCD

	MOVEI	T1,177		;ALL PI BITS
	AND	T1,.CPCPI##	;TURN ON ONLY
	IORI	T1,PI.TNP	;ONES WHICH WERE ON
	MOVEM	T1,.CPCPI##	;SAVE FOR CONO
	HRLZ	17,.CPACA##	;WHERE TO RESTORE THE AC'S FROM
	BLT	17,17		;RESTORE THEM ALL
	PUSH	P,T1		;SAVE T1
	MOVE	T1,.CPSTY##	;GET STOPCODE TYPE
	CAIE	T1,S$INFO	;INFORMATIONAL?
	CAIN	T1,S$EVENT	;BUGINF IN DRAG?
	JRST	[POP	P,T1	;RESTORE T1
		 JRST	DIE02]	;FINISH UP
	POP	P,T1		;RESTORE T1
	SKIPGE	DEBUGF##	;WANT DDT?
		.CREF	DF.SBD	;(FLAG BIT TESTED)
	XCT	.CPDDT##	;YES
DIE02:	SETOM	.CPDWD##	;ALLOW STOPCD'S
	DIENLK			;NO LONGER THE OWNER OF THE INTERLOCK
;IF STACK IS TRASHED, THIS IS WHERE WE GENERATE ANOTHER STOPCODE.
;SINCE WE HAVE RETURNED THE INTERLOCKS, THIS IS REASONABLY SAFE.

DIECON::
GOBACK::PUSH	P,.CPSPC##	;SAVE RETURN FLAGS
	PUSH	P,.CPSPC##+1	;SAVE RETURN PC
	SETZM	.CPSPC##+1	;LEAVE RECOGNIZABLE TRASH
	CONO	PI,@.CPCPI##	;TURN ON PI SYSTEM
	SETZM	SYSSNP##	;THIS COULD BE WHY WE GOT HERE.
	ADJSP	P,-2		;LEAVE STACK THE WAY IT WAS
	SKIPE	2(P)		;MAKE SURE WE HAVE A REAL RETURN ADDRESS
	XJRSTF	1(P)		;RETURN TO CALLER

DIEBPC:	STOPCD	.,STOP,DIEBAD,	;++ BAD PC IN DIE
;RUNNING IN SECTION 1 IF STOPCODE WAS IN A NON-ZERO SECTION

DIE1:	MOVE	T1,.CPSTY##	;GET STOPCODE TYPE
	SKIPL	PRCTAB(T1)	;DO WE WANT SECONDARY PROTOCOL?
		.CREF	S%FAST	;NOTE BIT WE TESTED
	PUSHJ	P,SVPPC##	;YES, SAVE PROTOCOL & FORCE SECONDARY

IFN FTMP,<
DIE2:	SKIPE	CRSHWD##	;RELOADING?
	S0JRST	REBOOT##	;YES
	SKIPGE	INTDIE##	;IS INTERLOCK AVAILABLE?
	AOSE	INTDIE##	;YES, TRY TO GET IT
	JRST	DIE2		;COULDN'T, LOOP TO TRY AGAIN
IFN FTKL10,<
	APRID	INODIE##	;MAKE ME THE OWNER OF THE INTERLOCK
>
	SETZM	DIEFLG##	;CLEAR TYPE FLAG (JUST IN CASE)
	MOVE	T1,.CPSTY##	;GET STOPCODE TYPE AGAIN
	SKIPL	PRCTAB(T1)	;IS IT REAL?
		.CREF	S%FAST	;(FLAG BIT TESTED)
	SOSA	DIEFLG##	;YES, GO NEGATIVE
	AOS	DIEFLG##	;NO, GO POSITIVE
> ;END IFN FTMP

;THE FOLLOWING CODE IS EXPLICITLY TO MAKE IT EASIER TO AUTOMATICALLY MAP IN
;A CRASH. THE USUAL SEQUENCE WOULD BE TO USE A DDT FILE WHICH (FOR KL PAGING)
;WOULD SAY:
;	DIECDB[$Q+.CPEPT-.CPCDB[$Q'1000$U
;	SPTTAB$6U
;	.CPACA[$Q$5U

	MOVE	T1,.CPSLF##	;GET PHYSICAL POINTER TO THE CDB
	MOVEM	T1,DIECDB##	;SAVE WHERE FILDDT WILL BE ABLE TO FIND IT
	MOVE	T1,1(M)		;GET NAME OF STOPCODE
	MOVEM	T1,.CPSNM##	;SAVE NAME IN CDB
	MOVEM	T1,%SYSCD##	;AND IN SYSTEM WIDE LOCATION
	MOVE	T1,.CPSUP##	;GET STOPCODE PC
	MOVEM	T1,%SYSPC##	;STORE IN TRADITIONAL WORD
	MOVE	T1,.CPSTY##	;GET STOPCODE TYPE AGAIN
	MOVEM	T1,%SYSTY##	;STORE IN SYSTEM WIDE LOCATION
	MOVE	T1,DATE##	;GET UDT
	MOVEM	T1,.CPSDT##	;SAVE AS LAST STOPCD DATE-TIME
	MOVEM	T1,%SYSDT##	;BOTH PER-CPU AND SYSTEM-WIDE
	MOVE	T1,.CPCPN##	;GET OUR CPU NUMBER
	MOVEM	T1,%SYSCP##	;STORE AS LAST CPU THAT DID A STOPCD
	HRRZ	T1,2(M)		;GET CONTINUATION ADDRESS
	SKIPE	T1		;IS THERE ANY?
	HRRM	T1,.CPSPC##+1	;YES, SAVE AS SECTION LOCAL CONTINUATION
	PUSH	P,.CPTOA##	;SAVE ADDRESS OF TYPEOUT ROUTINE
	MOVE	T1,.CPSTY##	;RECOVER STOPCODE TYPE
	SKIPN	DINITF##	;UNLESS IN ONCE-ONLY,
	SKIPL	PRCTAB(T1)	;LEAVE IT ALONE FOR EVENTS
		.CREF	S%FAST	;(NOTE TESTED BIT)
	SKIPA	T2,[CTYWAT##]	;NOPE, REPLACE IT WITH ONE THAT DOESN'T USE PI'S
	MOVEI	T2,DIETYO	;YEP, USE OUR OWN HANDY TYPEOUT ROUTINE
	MOVEM	T2,.CPTOA##	;MODIFY SCNSER
	MOVE	T1,PRCTAB(T1)	;GET ITS CONTROL BITS
	TLNN	T1,(S%EVNT)	;IS IT AN EVENT?
	JRST	DIE3		;NO, IT'S A REAL STOPCODE
	PUSHJ	P,INLMES##	;YES, TYPE HEADER
	ASCIZ	/
%% Event /
	MOVE	T2,.CPSNM##	;GET STOPCODE NAME
	PUSHJ	P,PRNAME	;PRINT IT OUT
	JRST	DIE4		;RE-JOIN COMMON CODE
DIE3:	MOVEI	T2,^D10		;TYPE SOME BELLS
	PUSHJ	P,BELLEN	; ...
	PUSHJ	P,INLMES##	;PRINT MESSAGE
	ASCIZ	/
?Stopcode /
	MOVE	T2,.CPSNM##	;GET STOPCODE NAME
	PUSHJ	P,PRNAME	;PRINT IT OUT
	PUSHJ	P,INLMES##	;SAY WHICH KIND
	ASCIZ	/, type=/
	MOVE	T1,.CPSTY##	;GET STOPCODE TYPE AGAIN
	MOVE	T2,STPTYP(T1)	;GET STOPCODE TYPE NAME
	PUSHJ	P,PRNAME	;PRINT IT OUT
	MOVEI	T3,","		;A SEPARATOR
	PUSHJ	P,COMTYO##	;TYPE IT
DIE4:	PUSHJ	P,INLMES##	;SEPARATION
	ASCIZ	/ on /
	MOVE	T2,.CPLOG##
	PUSHJ	P,PRNAME
	PUSHJ	P,INLMES##	;SEPARATION
	ASCIZ	/ at /
	PUSHJ	P,DAYTIM##	;SAY WHEN
	MOVE	T1,.CPSTY##	;GET STOPCODE TYPE AGAIN
	MOVE	T1,PRCTAB(T1)	;GET ITS CONTROL BITS
	TLNE	T1,(S%NDDB)	;SUPPRESS JOB TYPEOUT?
	JRST	NODDB		;YES, SKIP THIS
	MOVE	J,.CPJOB##
	MOVEI	S,PI.IPA	;GET PI ON MASK
	AND	S,.CPCPI##	;MASK OUT ALL ELSE
	SKIPN	S		;INTERRUPT LEVEL?
	PUSHJ	P,WHATJB	;NO--GIVE INFO
	TLZ	F,-1		;CLEAR LH BITS
	PUSHJ	P,CHKDDB	;MAKE SURE THAT F POINTS TO A DDB
	  JRST	NODDB		;IT DOESN'T, DON'T PRINT THE INFORMATION
	LDB	T1,PJOBN##	;GET JOB #
	CAILE	T1,JOBMAX##	;TOO BIG?
	JRST	NODDB		;YES--NOT A DDB
	JUMPE	T1,NODDB	;WANT REAL JOB #
	PUSHJ	P,INLMES##
	ASCIZ	/File /
	PUSHJ	P,PRTDDB##	;PRINT DDB STUFF
	PUSHJ	P,CRLF##	;ADD CRLF
	JUMPE	S,NODDB		;UUO LEVEL-SAID THIS
	LDB	J,PJOBN##	;GET JOB #
	PUSHJ	P,WHATJB	;PRINT IT
NODDB:	MOVE	T1,2(M)		;GET BITS FIELD
	TLNE	T1,400000	;ADDITIONAL INFORMATION
	SKIPN	T1,3(M)		;TYPE OUT ROUTINE
	JRST	NOTYPE		;JUMP IF NO ADDITIONAL TYPEOUT
IFN FTXMON,<
	HLL	T1,.CPSPC##+1	;GET CALLER'S SECTION
>; END IFN FTXMON
	PUSH	P,T1		;PUT SOMEWHERE SO WE CAN GET AT IT
IFN P-1,<PRINTX ? DIE REQUIRES THAT P=1>
;NOTE AC VALUE ASSUMPTIONS HERE!!
	MOVE	17,.CPACA##	;POINT TO SAVED ACS
	MOVE	0,0(17)		;LOAD UP S
	MOVSI	17,2(17)	;SOURCE ADDRESS
	HRRI	17,2		;ONE PAST P
	BLT	17,17		;RESTORE ALL BUT P
	PUSHJ	P,@(P)		;CALL THE ROUTINE
	POP	P,T1		;BALANCE THE STACK
	PUSHJ	P,CRLF##	;TERMINATE LINE
NOTYPE: MOVSI	T1,(DF.RIP)	;IS A RELOAD IN PROGRESS?
	TDNE	T1,DEBUGF##
	JRST	NOCSB		;YES, DON'T TYPE OUT MEANINGLESS CSB
	MOVE	T1,.CPSTY##	;GET ERROR TYPE
	MOVE	T1,PRCTAB(T1)	;GET CONTROL BITS
	TLNE	T1,(S%NCSB)	;SUPPRESS CSB TYPEOUT?
	JRST	NOCSB		;YES, DON'T TYPE CSB FOR TRIVIAL ERRORS
	SKIPGE	DEBUGF##	;WANT DDT?
	JRST	DIERS0		;YES, DON'T BOTHER WITH EXTRA TYPEOUT
	PUSHJ	P,TYPCSB##	;TYPE CPU STATUS BLOCK INFO ON THE CTY
NOCSB:	MOVE	T1,.CPSTY##	;GET ERROR TYPE
	HRRZ	T1,PRCTAB(T1)	;GET PROCESSOR TO HANDLE THIS
	PUSHJ	P,(T1)		;CALL IT
DIERS0:	MOVE	T1,.CPSTY##	;GET STOPCODE TYPE AGAIN
	HRRZ	T2,SCTTAB(T1)	;GET COUNTER LOCATIONS
	AOS	(T2)		;COUNT UP PER-CPU LOCATION
	HLRZ	T2,SCTTAB(T1)	;CHANGE POINTER
	AOS	(T2)		;COUNT UP SYSTEM-WIDE LOCATION
	MOVE	T2,PRCTAB(T1)	;GET CONTROL BITS
	MOVEI	T1,BUGCON	;POINT AT CONTINUATION MESSAGE
	TLNN	T2,(S%EVNT)	;IF A STOPCODE,
	PUSHJ	P,CONMES##	;ANNOUNCE THAT THE SHOW WILL GO ON
	POP	P,.CPTOA##	;RESTORE SCNSER
	POPJ	P,		;RETURN TO RESTORE PROTOCOL LEVEL
;HERE TO TYPE OUT DURING S%FAST TYPE STOPCODES

DIETYO:	PUSH	P,U		;SAVE LDB ADDRESS
	HRRZ	U,.CPCTN##	;GET OUR CTY'S LINE NUMBER
	MOVE	U,LINTAB##(U)	;POINT TO ITS LDB
	PUSHJ	P,CCTYO##	;STUFF CHARACTER INTO A CHUNK
	JRST	UPOPJ##		;RESTORE AC AND RETURN
;HERE ON A DEBUG STOPCD

BUGCHK:	PUSHJ	P,STCLIM	;EXCEED STOPCD LIMIT?
	  JRST	SCLEXC		;YES
	MOVSI	T1,(DF.RDC)	;DO WE WANT TO
	TDNE	T1,DEBUGF##	; RELOAD?
	JRST	RELOAD		;YES--GO RELOAD
	MOVSI	T1,(DF.DDC)	;WANT TO DUMP ON
	TDNN	T1,DEBUGF##	;  THIS TYPE OF STOPCD?
	PUSHJ	P,CRSDMP	;DUMP SYSTEM AND RETURN
	POPJ	P,		;RETURN TO DIERS0

;HERE ON A BUGINF (NODUMP STOPCD)
INFSTP==CPOPJ##

;MESSAGE THAT SHOWS SYSTEM CONTINUATION
BUGCON:	ASCIZ	/[Continuing system]
/

;HERE ON A JOB ERROR STOPCD

ZAPJOB:	PUSHJ	P,STCLIM	;STOPCD LIMIT EXCEEDED?
	  JRST	SCLEXC		;YES
	MOVSI	T1,(DF.RJE)	;IS RELOAD ON JOB ERROR
	TDNN	T1,DEBUGF##	; REQUESTED?
	SKIPE	S		; OR PI LEVEL?
	JRST	RELOAD		;YES--GO RELOAD
	SKIPE	.USJOB		;CAN'T STOP THE NULL JOB
	SKIPE	.CPISF##	;IN SCHEDULER CONTEXT?
	JRST	RELOAD		;YES, CAN'T REALLY STOP A JOB
	MOVSI	T1,(DF.DJE)	;WANT TO DUMP ON
	TDNN	T1,DEBUGF##	;  THIS TYPE OF STOPCD?
	PUSHJ	P,CRSDMP	;DUMP SYSTEM AND RETURN
	PUSHJ	P,INLMES##	;NO--ZAP JOB
	ASCIZ	/[Aborting job]
/
	PUSHJ	P,GIVLOK##	;GIVE BACK LOCKS THIS CPU OWNS
	MOVEI	T1,BUGSTP	;ROUTINE TO KILL OFF JOB
	MOVEM	T1,.CPSPC##+1	;SAVE AS RETURN ADDRESS SO THIS JOB GETS NAILED
	POPJ	P,		;RETURN TO DIERS0
;HERE ON A CPU STOPCD

IFN FTMP,<
CPUSTP:	PUSHJ	P,STCLIM	;STOPCD LIMIT EXCEEDED?
	  JRST	SCLEXC		;YES
	MOVSI	T2,(DF.CP1)	;BIT FORCING CPU STOPCDS TO CAUSE RELOAD
	PUSHJ	P,LSTCPU##	;LAST OR ONLY CPU RUNNING IN SYSTEM?
	TDNE	T2,DEBUGF##	;NO, WANT TO RELOAD ON CPU STOPCDS?
	JRST	RELOAD		;YES, RELOAD THE SYSTEM
	MOVSI	T1,(DF.DCP)	;WANT TO DUMP ON
	TDNN	T1,DEBUGF##	;  THIS TYPE OF STOPCD?
	PUSHJ	P,CRSDMP	;DUMP SYSTEM AND RETURN
	PUSHJ	P,INLMES##	;TELL OF OUR ACTION
	ASCIZ	/[Stopping CPU]
/
	AOS	.CPSNC##	;COUNT UP NUMBER OF TIMES THIS CPU STOPPED
	AOS	%SYNCS##	;AND NUMBER OF TIMES ANY CPU STOPPED
	PUSHJ	P,KILUSR	;INSURE THAT THE CURRENT JOB IS STOPPED
				;  TO AVOID A REPEAT OF THE STOPCD IF
				;  HE STARTS TO RUN ON ANOTHER CPU
	MOVE	T1,-1(P)	;GET SAVED TYPEOUT ADDRESS
	MOVEM	T1,.CPTOA##	;RESTORE FOR SCNSER
	SKPCPU(1)		;SLAVE CPU?
	JRST	CPUST2		;NO, DO BOOT DEATH THINGS
	SKIPGE	.CPOK##		;DID EVERYONE THINK WE WERE DEAD?
	SETZM	.CPOK##		;NO, LET THEM KNOW (ESPECIALLY LSTCPU)
	HRRZ	T1,.CPSLF##	;POINT TO OURSELVES
	PUSHJ	P,BRKLOK##	;DECLARE OURSELVES DOWN (DOES A DIENLK)
CPUST1:	MOVEI	T1,SR.DIE	;TELL CP1CRS THAT WE WANT THE OPERATOR
	IORM	T1,.CPSBR##	;  TO MANUALLY RESTART THIS CPU
	S0JRST	REBOOT##	;SAVE STATE OF THE MACHINE
CPUST2:	SETOM	.CPOK##		;SINCE BOOT, MAKE SURE BECOM0 WILL BE CALLED
	DIENLK			;NO LONGER HAVE INTERLOCK
CPUST3:	MOVEI	T1,^D10000	;NUMBER OF TIMES TO LOOP WHILE WAITING
CPUST4:	SKPCPU(0)		;STILL THE POLICY CPU?
	PJRST	CPUST1		;NO, SAVE STATE OF THE MACHINE
	SOJG	T1,CPUST4	;YES, LOOP
	PUSHJ	P,LSTCPU##	;LOOP EXPIRED, DID ALL THE OTHERS GO AWAY?
	  JRST	CPUST3		;NO, LOOP SOME MORE
	MOVEI	T1,CTYWAT##	;REPLACE IT WITH ONE
	MOVEM	T1,.CPTOA##	;THAT DOESN'T NEED PI
	MOVSI	T1,(DF.RAD)	;RELOAD AFTER DUMP BIT
	IORM	T1,DEBUGF##	;LIGHT IT FOR MONBTS (DON'T DUMP TWICE)
	PJRST	RELOAD		;AND GO RELOAD THE SYSTEM
>
;HERE IF WE EXCEEDED ONE OF THE STOPCD-PER-UNIT-TIME LIMITS TO RELOAD
;THE SYSTEM.

SCLEXC:	PUSHJ	P,INLMES##	;TELL WHAT HAPPENED
	ASCIZ	/?Stopcode limit exceeded
/


;HERE TO RELOAD THE SYSTEM

IFE FTMP,<
CPUSTP:
>
RELOAD: MOVSI	T1,(DF.RLD)	;INDICATE RELOAD
	IORM	T1,DEBUGF##	;FOR CRSCPY
	MOVE	T1,.CPSNM##	;GET STOPCODE NAME
	MOVEM	T1,CRSWHY##	;SAVE REASON FOR ONCE AFTER RELOAD
	PUSHJ	P,INLMES##
	ASCIZ	/Reload monitor
/
	MOVEI	T2,^D20		;20 BELLS
	PUSHJ	P,BELLS		;..
	MOVE	T1,.CPSUP##	;GET CRASH PC
	MOVEM	T1,CRSHWD	;SAVE PC
	SOS	CRSHWD##	;FOR SYSTAT/X
	S0JRST	REBOOT##	;YES, RELOAD NOW
COMMENT @
"Recent findings have shown bugs that are adaptive and intelligent.
The study of such bugs has been hampered by the probablity that these
bugs themselves have bugs, producing erratic buglike behavior.  If
this is indeed true, it provides the first demonstration that Murphy's
Law is recursive, that it can invoke itself."

IEEE Spectrum, September 1984
@

;TABLES FOR DRIVING STOPCODE PROCESSING


S%FAST==1B0		;FLAG FOR STOPCODE VS. EVENT (SVPPC)
S%NDDB==1B1		;FLAG TO SUPPRESS DDB/JOB TYPEOUT
S%NCSB==1B2		;FLAG TO SUPPRESS CSB TYPEOUT
S%EVNT==1B3		;FLAG TO TYPE "EVENT" RATHER THAN "STOPCODE"

DEFINE	STPTAB,<
STP	HALT,RELOAD,0,0,
STP	STOP,RELOAD,0,0,
STP	JOB,ZAPJOB,.CPSNJ##,%SYNJS##,
STP	DEBUG,BUGCHK,.CPSND##,%SYNDS##,
STP	CPU,CPUSTP,.CPSNC##,%SYNCS##,
STP	INFO,INFSTP,.CPSNI##,%SYNIS##,<NDDB,NCSB,FAST>
STP	EVENT,INFSTP,.CPSNI##,%SYNIS##,<EVNT,NDDB,NCSB,FAST>
>

STPTYP:
	DEFINE	STP(TYP,RTN,CPLOC,SYLOC,FLAGS),<
	IFN <.-STPTYP>-S$'TYP,<PRINTX ? STOPCODE TYPE TYP IS OUT OF ORDER>
	EXP SIXBIT \TYP\
>
	STPTAB
  STPMAX==.-STPTYP-1	;MAXIMUM LEGAL STOPCODE TYPE

PRCTAB:
	DEFINE	STP(TYP,RTN,CPLOC,SYLOC,FLAGS),<
	ZZ==0
	IRP	FLAGS,<ZZ==ZZ!S%'FLAGS>
	EXP	ZZ ! RTN
	PURGE	ZZ
>
	STPTAB

SCTTAB:	DEFINE	STP(TYP,RTN,CPLOC,SYLOC,FLAGS),<XWD SYLOC,CPLOC>
	STPTAB
;HERE TO STOP AN ILL FATED USER
BUGSTP:	MOVE	J,.USJOB	;JOB NUMBER
	PUSHJ	P,ZAPUSR	;GIVE UP LOCKS AND DEVICES
	JSP	T1,ERRPTU	;PRINT MESSAGE
	ASCIZ	/Monitor error/
	PJRST	UUOPCP		;PRINT SOME PC'S


;ROUTINE TO KILL THE CURRENT JOB RUNNING ON THIS CPU TO MAKE SURE
;THAT IT DOESN'T CONTINUE TO CAUSE THE SAME CRASH OVER AND OVER AGAIN.
;MUST NOT BE CALLED WITH A UUO LEVEL STACK SINCE ZAPPGM WILL GIVE
;BACK THE PAGE MAP.

KILUSR:	PUSHJ	P,GIVLOK##	;RETURN INTERLOCKS OWNED BY THIS CPU
	SKIPN	J,.CPJOB##	;ANY JOB RUNNING ON THIS CPU?
	POPJ	P,		;NO, JUST RETURN
ZAPZAP::PUSHJ	P,ZAPHER	;GIVE UP LOCKS AND DEVICES
	PUSH	P,JBTSTS##(J)	;SAVE CURRENT STATE OF JBTSTS
	MOVSI	T1,JLOG		;CLEAR JLOG TEMPORARILY SO THAT
	ANDCAM	T1,JBTSTS##(J)	;  ZAPPGM WILL GIVE BACK ALL OF THE
	ANDM	T1,0(P)		;  USER'S CORE.  I KNOW IT'S UGLY BUT...
	PUSHJ	P,ZAPPGM##	;GIVE BACK ALL OF HIS CORE
	POP	P,T1		;GET BACK STATE OF JLOG BIT
	IORM	T1,JBTSTS##(J)	;SET IT IF IT WAS SET BEFORE
	POPJ	P,		;RETURN
;SUBROUTINE TO SEND C(T2) BELLS
;CLOBBERS T1, T2, T3, T4
BELLEN:	HRRZ	T1,.CPTOA##	;GET TYPEOUT ROUTINE
	CAIE	T1,DIETYO	;DOES IT BUFFER FOR US?
BELLS::	TDZA	T1,T1		;NO, FLAG IT
	MOVEI	T1,1		;YES, FLAG THAT
	PUSH	P,T1		;SAVE FLAG
	PUSH	P,T2		;NUMBER OF BELLS TO OUTPUT
BELOOP:	MOVEI	T3,"G"-100	;BELL
	PUSHJ	P,COMTYO##	;DING
	SOSG	(P)		;DECREMENT NUMBER OF BELLS TO OUTPUT
	JRST	TTPOPJ##	;DONE
	SKIPE	-1(P)		;CHECK FLAG
	JRST	BELOOP		;DON'T LOOP IF PI'S STILL ON
IFN FTKL10,MOVSI T1,1		;LOOP 2^18 TIMES ON A KL10
IFN FTKS10,MOVEI T1,200000	;LOOP 2^16 TIMES ON A KS10
	DMOVE	T2,BECODE	;PUT TIMING CODE IN ACS TO AVOID ERRATIC TIMING
	JRST	T2		;  DUE TO PRESENCE OR ABSENCE OF CACHE

BECODE:	SOJG	T1,T2		;(T2) DECREMENT T1 AND LOOP
	JRST	BELOOP		;(T3) OUTPUT ANOTHER BELL WHEN DONE

;ROUTINE TO CHECK A DDB ADDRESS BEFORE USING IT TO TYPE FILE INFORMATION
;DURING DIE PROCESSING.
;CALL:	MOVEI	F,ADDRESS
;	PUSHJ	P,CHKDDB
;	  RETURN HERE IF ADDRESS IS ILLEGAL FOR SOME REASON
;	RETURN HERE IF ADDRESS IS OK

CHKDDB:	CAMGE	F,SYSSIZ##	;LARGER THAN THE LOW SEG?
	CAIG	F,1000		;OR TOO SMALL?
	CAIA			;YES, MAY STILL BE IN FUNNY SPACE
	JRST	CPOPJ1##	;GIVE SKIP RETURN
	CAIL	F,.FPMC		;LEGAL ADDRESS IN
	CAIL	F,.FPMC+NWMCP	;  FUNNY SPACE?
	POPJ	P,		;NO, BAD DDB ADDRESS
	MAP	T1,(F)		;MAP THE ADDRESS
	PUSHJ	P,FLTCHK##	;WILL REFERENCE FAULT?
	  POPJ	P,		;YES, BAD ADDRESS
	MAP	T1,DEVSFD##(F)	;LAST ADDRESS IN DDB REFERENCED BY PRTDDB
	PJRST	FLTCHK##	;CHECK ADDRESS AND RETURN
;ROUTINE TO SEE IF THIS STOPCD HAS CAUSED US TO EXCEED ON OF THE
;STOPCDS-PER-UNIT-TIME LIMITS.
;CALL:	PUSHJ	P,STCLIM
;	  RETURN HERE IF A LIMIT HAS BEEN EXCEEDED
;	  RETURN HERE IF NOT

STCLIM:	SKIPGE	DEBUGF##	;IF DEBUGGING
	JRST	CPOPJ1##	;THEN NOSTOPCD LIMITS
	MOVSI	T1,-SCCTBL##	;BUILD AOBJN POINTER TO TABLE
STCLI1:	AOS	T2,SCCTAB##(T1)	;INCREMENT NEXT COUNT
	HRRZ	T3,SCLTAB##(T1)	;GET THE LIMIT
	CAIL	T2,(T3)		;EXCEED THE LIMIT?
	POPJ	P,		;YES
	AOBJN	T1,STCLI1	;NO, LOOP FOR NEXT
	HLRZ	T1,SCLTAB##+0	;GET PERIOD OF LOWEST ENTRY IN TABLE
	IMUL	T1,TICSEC##	;SETUP CLOCK REQUEST TO DECREMENT THE
	HRLI	T1,DECSCC	;  1 MINUTE STOPCD COUNT. DECSCC WILL,
	MOVEI	T2,0		;  IN TURN, PUT IN A CLOCK REQUEST TO DECREMENT
	IDPB	T1,CLOCK##	;  THE NEXT ONE, AND SO ON, UNTIL ALL
	IDPB	T2,CLOCK##	;  LEVELS OF COUNTS HAVE BEEN DECREMENTED.
	SETOM	CLKNEW##	;I REALIZE THE CLOCK QUEUE HASN'T BEEN
				;  INTERLOCKED WITH SYSPIF BUT BY THE
				;  TIME THE FIRST CHARACTER OF THE STOPCD
				;  MESSAGE HAS TYPED ON THE CTY, ALL OTHER
				;  CPU'S SHOULD HAVE SEEN INTDIE GO NON-ZERO
	JRST	CPOPJ1##	;GIVE SKIP RETURN


;ROUTINE TO DECREMENT A STOPCD COUNT AND RESUBMIT A CLOCK QUEUE REQUEST
;FOR THE NEXT HIGHER COUNT, IF ONE EXISTS.
;CALL:	MOVEI	T1,INDEX INTO SCCTAB
;	PUSHJ	P,DECSCC
;	  RETURN HERE ALWAYS


DECSCC::SOSGE	SCCTAB##(T1)	;DECREMENT COUNT
	SETZM	SCCTAB##(T1)	;LEAVE ZERO IF IT WAS ZERO
	AOS	T1		;INCREMENT LEVEL
	CAIL	T1,SCCTBL##	;DONE THE LAST LEVEL?
	POPJ	P,		;YES, RETURN NOW
	MOVE	T2,SCLTAB##(T1)	;GET WORD WITH NEW PERIOD
	SUB	T2,SCLTAB##-1(T1) ;SUBTRACT OLD PERIOD
	HLRZS	T2		;KEEP JUST DIFFERENCE IN PERIODS
	IMUL	T2,TICSEC##	;CONVERT TO TICKS
	HRLI	T2,DECSCC	;WANT TO COME BACK HERE
	SYSPIF			;INTERLOCK THE QUEUE
	IDPB	T2,CLOCK##	;STORE REQUEST
	IDPB	T1,CLOCK##	;  AND DATA
	SETOM	CLKNEW##	;FLAG A NEW REQUEST
	PJRST	ONPOPJ##	;RETURN INTERLOCK AND POPJ
;ROUTINES FOR STOPCODE MACRO TYPE OUT
;ALL ROUTINES WILL HAVE THE FORM DIE???::
;WHERE ??? ARE 3 LETTERS DESCRIPTIVE OF THE ROUTINE
;AN AUTOMATIC CARRIAGE RETURN/LINE FEED IS DONE BY CALLER

;ROUTINE TO TYPE OUT UNINAM(U) DURING STOPCD
DIEUNI::PUSHJ	P,INLMES##	;START THE OUTPUT
	ASCIZ	\Unit = \
	MOVE	T2,UNINAM##(U)	;GET UNIT NAME
	PJRST	PRNAME		;PRINT OUT SIXBIT AND RETURN


; ROUTINE TO TYPE OUT STRNAM(P2) DURING A STOPCODE
DIESTR::PUSHJ	P,INLMES##	;TYPE INTRODUCTION
	ASCIZ	|Structure = |
	MOVE	T2,STRNAM##(P2)	;GET STR NAME
	PJRST	PRNAME		;TYPE IT AND RETURN

;ROUTINE TO TYPE OUT ADDITIONAL DATA DURING BUGINF (OR BUGCHK OR ...)
;
;CALLED VIA JSP T1,BGCTYP
;DATA TO BE TYPED FOLLOWS
;DISPATCHED TO BY BGCTYP IN COMMON
;POINTER TO DATA IS IN P1

BUGTY1::MAP	T1,(P1)		;MAKE SURE LOCATION IS ACCESSIBLE
	PUSHJ	P,FLTCHK##	;MAKE SURE WON'T FAULT
	  POPJ	P,		;WILL FAULT, END LIST NOW
	SKIPN	(P1)		;HIT END OF DATA ITEMS?
	POPJ	P,		;YES, END LIST NOW
	PUSHJ	P,PR3SPC##	;A LITTLE SPACING
	MOVE	T2,(P1)		;GET ITEM NAME
	PUSHJ	P,PRNAME	;PRINT IT
	PUSHJ	P,INLMES##	;A LITTLE NOISE
	ASCIZ	/: /
	MAP	T1,1(P1)	;MAKE SURE THIS WON'T FAULT
	PUSHJ	P,FLTCHK##
	  POPJ	P,		;END OF LIST FORCED
	MOVE	T1,1(P1)	;GET ADDRESS OF ITEM
	MOVE	T2,.CPACA##	;GET ADDRESS OF SAVED AC'S
	ADD	T2,T1		;OFFSET TO SAVED ITEM IF IN CRASH AC'S
	CAIG	T1,17		;ITEM IN CRASH AC'S?
	SKIPA	T1,(T2)		;YES, FETCH FROM PROPER LOCATION
	MOVE	T1,(T1)		;NO, GET DIRECTLY
	PUSHJ	P,PRTXWD	;PRINT IT AS HALFWORDS
	ADDI	P1,1		;LOOP FOR NEXT ITEM
	AOJA	P1,BUGTY1	;UNTIL DONE


;ROUTINE TO CALL BUGDMP TO TAKE A CONTINUABLE STOPCD DUMP
;AND THEN SET DF.RQC IN DEBUGF WHICH WILL CAUSE CRSCPY
;TO BE CALLED BY THE BOOT CPU AT THE NEXT TICK.  WE
;CAN'T CALL CRSCPY DIRECTLY BECAUSE THE SCNSER INTERLOCK
;MAY NOT BE FREE.
;ENTER AT FRCCPY TO JUST SET DF.RQC (FROM ADDSDL)
;CALL:	PUSHJ	P,CRSDMP
;	RETURN HERE ALWAYS

CRSDMP:	SE1ENT			;ENTER SECTION 1
	PUSH	P,JOBSYM##	;KEEP DAEMON FROM THINKING THIS IS A
	SETZM	JOBSYM##	;RELOAD BY ZEROING THE FLAG THAT IT LOOKS AT
	PUSHJ	P,BTDUMP##	;TAKE DUMP
	  JFCL			;IGNORE ERROR RETURN
	POP	P,JOBSYM##	;RESTORE SYMBOL TABLE POINTER

FRCCPY::MOVSI	T1,(DF.RQC)	;IF THE CRSCPY REQUEST HAS NOT BEEN
	MOVSI	T2,(DF.DCC)	; DISABLED VIA THE /NOCOPY STARTUP
	TDNN	T2,DEBUGF##	; SWITCH, SET DF.RQC IN DEBUGF WHICH
	IORM	T1,DEBUGF##	; WILL CAUSE CRSCPY TO BE CALLED ON
	ANDCAM	T2,DEBUGF##	; THE NEXT CLOCK TICK
	POPJ	P,		;RETURN


;ROUTINE TO START UP THE CRASH COPY PROGRAM TO COPY
;A DUMP.
;CALL:	PUSHJ	P,CRSCPY
;	RETURN HERE ALWAYS

CRSCPY::SKIPGE	DEBUGF##	;DON'T DO ANYTHING
	POPJ	P,		; IF DEBUGGING
	PUSHJ	P,FRCSET##	;SETUP TO STORE CHARACTERS IN FRCLIN
	MOVE	T2,CCPNAM##	;GET NAME OF PROGRAM TO RUN
	PUSHJ	P,PRNAME	;STORE NAME
	PJRST	CRLF##		;ADD CRLF AND RETURN
WHATJB:	JUMPLE	J,CPOPJ##	;GET JOB NUMBER
	CAILE	J,JOBMAX##	;RANGE CHECK IT.
	POPJ	P,		;IGNORE IF FUNNY.
	PUSHJ	P,INLMES##	;GIVE THE JOB NUMBER
	ASCIZ	/Job /		; ..
	MOVE	T1,J		; ..
	MOVEM	T1,%SYSJN##
	MOVEM	T1,.CPSJN##
	PUSHJ	P,RADX10	;IN DECIMAL
	PUSHJ	P,INLMES##	;PRINT OUT THE
	ASCIZ	/ on /		; TTY NAME
	MOVE	T2,@TTYTAB##(J)	;GET TTY NAME
	MOVEM	T2,%SYSTN##
	MOVEM	T2,.CPSTN##
	PUSHJ	P,PRNAME	; AND PRINT IT.
	PUSHJ	P,INLMES##	;PRINT OUT
	ASCIZ	/ running /	; THE CUSP NAME
	MOVE	T2,JBTPRG##(J)	; SO OPERATOR
	MOVEM	T2,%SYSPN##
	MOVEM	T2,.CPSPN##
	PUSHJ	P,PRNAME	; CAN FIND HIS JOBS
	PUSHJ	P,INLMES##
	ASCIZ	/ User /
	MOVE	T2,JBTPPN##(J)	;GET USER'S PPN
	MOVEM	T2,%SYSPP##	;AND SAVE FOR DAEMON
	MOVEM	T2,.CPSPP##
	PUSHJ	P,PRTPPN##	;PRINT PPN
	JUMPN	S,CRLF##
	PUSHJ	P,INLMES##	;NEW LINE
	ASCIZ	/
UUO is /
	MOVE	T1,.CPTRP##	;PICK UP UUO
	MOVEM	T1,%SYSUU##
	MOVEM	T1,.CPSUU##
	PUSHJ	P,HWDPNT	;PRINT IN OCTAL
	DMOVE	T1,.JDAT+JOBPD1## ;GET PC FROM PUSH DOWN LIST
	MOVEM	T2,%SYSUP##
	MOVEM	T2,.CPSUP##
	PUSHJ	P,DPCP		;LIST THE LOCATION
	PJRST	CRLF##		;RETURN ON A NEW LINE
SUBTTL	UUO LEVEL ERROR ROUTINES

;INPUT UUO FOR OUTPUT DEVICE
;CALLED AT UUO LEVEL ONLY


ILLINP::JSP	T1,ERRPTU
	ASCIZ	/Output /
	PUSHJ	P,ERNAM		;PRINT "DEVICE XXX"
	JSP	T1,UUOMES	;PRINT MESSAGE,UUOPC,STOP JOB
	ASCIZ	/ cannot do input/

;OUTPUT UUO FOR INPUT DEVICE
;CALLED AT UUO LEVEL ONLY


ILLOUT::JSP	T1,ERRPTU
	ASCIZ	/Input /
	PUSHJ	P,ERNAM		;PRINT "DEVICE XXX"
	JSP	T1,UUOMES	;PRINT MESSAGE,UUOPC,STOP JOB
	ASCIZ	/ cannot do output/

;ILLEGAL DEVICE DATA MODE (INIT, OPEN, OR SETSTS UUOS)
;CALLED AT UUO LEVEL ONLY


ILLMOD::JSP	T1,ERRPTU
	ASCIZ	/Illegal data mode for /
	JRST	DEVEXC		;PRINT "DEVICE XXX",UUO PC

;ILLEGAL INBUF/OUTBUF (NON-ZERO SECTION)

ILLBUF::JSP	T1,ERRPTU
	ASCIZ	\Illegal INBUF/OUTBUF for \
	JRST	DEVEXC		;PRINT "DEVICE XXX", UUO PC

;IO UUO TO USER CHANNEL WITH NO PREVIOUS INIT OR OPEN
;CALLED AT UUO LEVEL ONLY


IOIERR::JSP	T1,ERRPTU
	ASCIZ	/IO to unassigned channel/
	JRST	UUOPCP		;PRINT UUO PC
;ILLEGAL UUO
;CALLED AT UUO LEVEL ONLY
;SERVES TWO PURPOSES - A) TO WARN WHEN MOVING FROM A LOCATION WITH SPECIAL INSTALLATION
;UUOS TO ONE WITH LACKS THEM
;B) TO WARN OF OLD UUO'S WITH NONSKIP "GOOD" RETURNS WHICH
;HAVE BEEN "DE-IMPLEMENTED"

UUOERR::EXCH	T1,.USMUO	;GET UUO PC FLAGS
	TLNN	T1,USRMOD	;FROM EXEC?
	JRST	EMUERR		;YES
	EXCH	T1,.USMUO	;PUT THINGS BACK
ILLUUO:	PUSH	P,.USMUO	;PC FLAGS
	PUSH	P,.USMUP	;NOW PUSH USER PC ON STACK JUST LIKE UUO
				; (LEAVE STACK UNTOUCHED BEFORE HALT)
				; (START PRESERVES PC FLAGS IN LH)
	PUSHJ	P,GIVRES	;GIVE UP INTERLOCKS
IFN FTPI,<
	SIGNAL	C$IUUO		;SIGNAL ILLEGAL UUO
	  SKIPA			;DOESN'T WANT THE TRAP
	JRST	ERRGOU		;INTERCEPT THE UUO
>	;END FTPI
	JSP	T1,ERRPTU
	ASCIZ	/Illegal UUO/
	DMOVE	T1,.USMUO	;GET UUO PC
	SOJA	T2,DPCPNT	;AND PRINT, PRINT USER UUO PC IF DIFF.
IFE FTMP,<
;UUO ERROR-MONITOR ERROR AT UUO LEVEL
;CALLED AT UUO LEVEL ONLY

UUOER1::JSP	T1,ERRPTU
	ASCIZ	/UUO error/
	JRST	UUOPCP
>
;HERE ON AN EXEC MODE UUO ERROR

EMUERR:	EXCH	T1,.USMUO
	CONSZ	PI,PI.IPA	;AT UUO LEVEL?
	STOPCD	.,STOP,UIL,DIEEMU, ;++UUO AT INTERRUPT LEVEL
	STOPCD	.+1,DEBUG,EUE,DIEEMU, ;++EXEC UUO ERROR
	PUSHJ	P,GIVLOK##	;RETURN SOFTWARE INTERLOCKS
	MOVE	J,.CPJOB##	;GET JOB NUMBER
	JRST	ILLUUO		;PRINT ERROR MESSAGE

DIEEMU:	PUSHJ	P,INLMES##
	ASCIZ	/MUUO Flags, Opcode, AC = /
	MOVE	T1,.USMUO	;GET FLAGS,OPCODE,AC
	PUSHJ	P,HWDPNT	;PRINT IT
	PUSHJ	P,INLMES##
	ASCIZ	/
MUUO PC = /
	MOVE	T2,.USMUP	;GET PC
	PUSHJ	P,UDPCP		;PRINT IT
	PUSHJ	P,INLMES##
	ASCIZ	/
MUUO EA = /
	MOVE	T2,.USMUE	;GET EA
	PJRST	UDPCP		;PRINT IT AND RETURN
;HERE IF THE USER DIES IN GETWRD OR PUTWRD

UADERR::MOVE	J,.CPJOB##
	PUSHJ	P,GIVRES	;RETURN INTERLOCKS
	JSP	T1,ERRPTU
	ASCIZ	/Illegal address in UUO/
	JRST	UUOPCP
;ILLEGAL INSTRUCTION
;HALT INSTRUCTION IS A SPECIAL CASE WHICH STOPS JOB BUT
;THE USER MAY CONTINUE FROM IT(EFFECTIVE ADR.)
;CALLED AT UUO LEVEL WITH A JRST


ILLINS::LDB	T1,[POINT 9,M,8] ;OPCODE
IFN FTKL10,<
	CAIN	T1,<<EXTEND>_-^D27> ;IS THIS AN EXTEND INSTRUCTION?
	JRST	OINKSR##	;YES, CHECK FOR GFLOAT EXTEND OPCODE.
>
	CAIL	T1,130		;WITHIN LONG FLOATING POINT RANGE?
	CAILE	T1,177
	JRST	ILLIN1		;NO, ILLEGAL INSTRUCTION
	CAIL	T1,133		;A BYTE INSTR?
	CAILE	T1,137
	CAIA			;NO
	JRST	ILLIN1		;YES
	MOVSI	T2,(JS.FPS)	;WANT SIMULATION BIT
	SKIPE	[M.FPS##]	;SIMULATION ROUTINE LOADED?
	TDNN	T2,JBTST2##(J)	;AND DOES THE USER WANT SIMULATION?
	CAIA			;NO
	JRST	KALFPS##	;YES, SIMULATE THE KA FP INSTRUCTIONS
IFN FTPI,<
	SIGNAL	C$IUUO		;SIGNAL ILL INSTRS
	  CAIA			;PROGRAM ISN'T INTERESTED
	JRST	ERRGOU		;GO TO THE USER
>
	JSP	T1,ERRPTU	;TELL THE USER TO FIX THE PROGRAM
	ASCIZ	/KA10 floating point instruction/
	JRST	UUOPCP
ILLIN1::
IFN FTPI,<
	SIGNAL	C$IUUO		;SIGNAL ILL UUO
	  SKIPA			;USER DOESN'T WANT THE TRAP
	JRST	ERRGOU		;GO TO THE USER
>
	HLRZ	T1,M		;ILLEGAL OPCODE
	TRZ	T1,(SECMSK)	;CLEAR POSSIBLE SECTION NUMBER
	CAIN	T1,(HALT)	;IS IT A HALT?
	JRST	HALTI		;YES, PRINT DIFFERENT MESSAGE
IFN FTKS10,<
	LSH	T1,-9		;MAKE T1=OPCODE
IFN FTKS10,<
KSIBEG==102
KSIEND==110
	MOVSI	T2,314000	;MASK FOR KL-ONLY INSTRS
	CAIG	T1,KSIEND	;IF TOO LARGE, DON'T SHIFT
	LSH	T2,-KSIBEG+1(T1)	;SHIFT MASK BY OPCODE
>
	JUMPGE	T2,ILLKAI	;KA10 ILL INST IF SIGN NOT 1
	JSP	T1,ERRPTU
	ASCIZ	/KL10 only instruction/
	JRST	UUOPCP
> ;END FTKI10!FTKS10
ILLKAI:	JSP	T1,ERRPTU
	ASCIZ	/Illegal instruction/
	JRST	UUOPCP		;PRINT UUO PC AND STOP JOB

HALTI:	JSP	T1,ERRPTU
	ASCIZ	/HALT/
	DMOVE	T1,.JDAT+JOBPD1##
	SOS	T2		;UUOPC=LOC OF HALT+1
	PUSHJ	P,DPCP		;PRINT "USER LOC XXX"
	HRR	M,.USMUO+2	;CHKINT CLOBBERS M
	HRRM	M,.JDAT+JOBPD1##+1 ;SAVE EFFECTIVE ADDRESS OF HALT
	PUSH	P,U
	PUSHJ	P,TTYSRC##	;GETTTY
	STOPCD	.,STOP,LNT,	;NONE?!
	JUMPE	U,HALTI1	;JUMP IF JOB DETACHED
	POP	P,U
	PUSHJ	P,TSETBI##	;CLEAR TYPE-AHEAD
	PUSHJ	P,HOLDW##	;START TTY WITH STANDARD RESPONSE,, STOP
				;JOB, LEAVE TTY IN MONITOR MODE
				;DO NOT SET ERROR BIT SO CAN CONTINUE
	JRST	ERRGOU		;RETURN TO USER
HALTI1:	POP	P,U
	PUSHJ	P,CRLF##	;HERE TO HANDLE HALT IN DET'D JOB
	PUSHJ	P,ESTOP3##	;STOP JOB WITH CONTINUABILITY
	PUSHJ	P,WSCHED##	;WAIT FOR USER
	JRST	ERRGOU		;RESUME NORMAL FLOW

;ILLEGAL TRAP INSTRUCTION
ILLTIN::MOVE	P,[MJOBPD##,,.JDAT+JOBPDL##]
	PUSH	P,.USMUO	;PC FLAGS

	PUSH	P,.USMUP
	JSP	T1,ERRPTU
	ASCIZ	/Illegal trap instruction/
	JRST	UUOPCP		;PRINT TRAP INSTR PC AND STOP THE JOB
SUBTTL	I/O ERROR HANDLING ROUTINES

;ROUTINE FOR HUNG IO DEVICE
;CALL	MOVE F,ADDRESS OF DEVICE DATA BLOCK
;	PUSHJ P,DEVHNG


DEVHNG::PUSHJ	P,SVEUF##	;MAKE SURE JOB DATA AREA IS ADDRESSABLE

	LDB	J,PJOBN##	;JOB NUMBER
	JUMPN	J,DEVHN0	;DON'T CLEAR IOW UNLESS JOB 0
	PUSHJ	P,CLRACT##	;TURN OFF IO DEVICE ACTIVE BIT IN
				;MEMORY AND S
	JRST	DEVHN2		;GO TYPE THE MESSAGE

DEVHN0:
IFN FTPI,<
	MOVEI	T1,IR.HNG	;HUNG CONDITION
	TSNN	T1,DEVPSI##(F)	;PROGRAM ENABLED?
	JRST	DEVHN1		;NO
	TRZ	S,IOACT		;CLEAR IOACT (LEAVE IOW ALONE)
	PUSHJ	P,STORS7##	;MAKE SURE IOS IS IN MEMORY
	PUSHJ	P,PSIDVB##	;SIGNAL HUNG DEVICE
	MOVE	S,DEVIOS(F)	;RESTORE S
	TRO	S,IOIMPM!IOBKTL!IODERR!IODTER ;ALL ERRORS
	PUSHJ	P,SETIOD##	;GET THE JOB GOING
	HLLZS	JBTDDB##(J)	;NOT IN IOWAIT NOW (FOR ^T'ERS)
	PJRST	STOIOS##	;STORE BITS AND RETURN
>
DEVHN1:	PUSHJ	P,CLRACT##	;BLOW AWAY IOACT AND IOW
	MOVSI	T1,JERR		;FLAG SO USER DOESN'T
	IORM	T1,JBTSTS(J)	;GET IF TRAP ENABLED
DVHN1A:
IFN FTMP,<
	CPLOCK	(SCD)		;GET SCHEDULER LOCK
>
	MOVEI	T1,STOPQ##
	DPB	T1,PJBSTS##
	PUSHJ	P,ANYCPU##	;IS HE RUNNING ANYWHERE NOW?
	  SKIPA			;YES MUST DELAY HANGING HIM
	JRST	DVHN1C		;NO, CAN STOP HIM NOW
	MOVEI	T2,1		;GET A WORD
	PUSHJ	P,GETWDS##	;OF FREE CORE
	  JRST	DVHN1C		;FAILED BLAST JOB ANYWAY
	MOVEM	F,(T1)		;STORE F
	HRLM	J,(T1)		;AND J
	MOVE	T2,.CPCPN##
	DPB	T2,[POINT 3,T1,3] ;CPU IS US
	TLO	T1,400000
	MOVEI	T2,1		;IN ATIC
	HRLI	T2,DVHN1B
	SYSPIF
	IDPB	T2,CLOCK##
	IDPB	T1,CLOCK##
	SETOM	CLKNEW##
	SYSPIN
IFN FTMP,<
	CPUNLK	(SCD)
>
	POPJ	P,		;AND RETURN FOR NOW
DVHN1B:	HLRZ	J,(T1)		;RESTORE J
	HRRZ	F,(T1)		;+F
	MOVEI	T2,(T1)		;RETURN FREE CORE
	MOVEI	T1,1
	PUSHJ	P,GIVWDS##
	PUSHJ	P,SVEUB##	;MAKE JOB ADDRESSABLE
	JRST	DVHN1A		;CHECK TO SEE IF HE'S STILL HERE
DVHN1C: PUSH	P,F		;GIVSRC CLOBBERS F
	PUSHJ	P,GIVRSC	;RETURN RESOURCES, COULD HAVE SOME, IF STR YANKED
	POP	P,F		;RESTORE F
	MOVEI	T1,STOPQ##
	DPB	T1,PJBSTS##
IFN	FTMP,<
	CPUNLK	(SCD)
>
DEVHN2:	JSP	T1,ERRDEV
	ASCIZ	/Hung /
	JRST	DEVEXC

;BAD DECTAPE DIRECTORY
;CALLED AT INTERRUPT AND UUO LEVELS WITH F AND J SETUP

BADDIR::PUSHJ	P,SVEUF##	;MAKE JOB DATA AREA ADDRESSABLE

	JSP	T1,ERRPNT
	ASCIZ	/Bad directory for /

;ROUTINE TO PRINT "DEVICE XXX; EXEC CALLED FOR EXEC/USER YYY"
;THEN STOP JOB
;TO BE USED BY DEVICE DEPENDENT ERROR MESSAGES AFTER JSP T1,DEVERR


DEVEXC::PUSHJ	P,ERNAM		;PRINT "DEVICE XXX"
	PUSHJ	P,TTYKLQ##	;KILL OFF TTY DDB IF NECESSARY
	SKIPE	JBTADR##(J)	;CHECK FOR JOB IN CORE
	JRST	EXCALP		;PRINT "EXEC CALLED FROM EXEC/USER LOC YYY"
	JRST	PCSTOP		;JUST STOP THE JOB

;ROUTINE TO HALT A JOB WHEN A DEVICE IS NOT READY FOR I/O
;CALLED FROM XXXSER AT UUO LEVEL
;CALL	MOVE F,ADDR. OF DEV. DDB
;	PUSHJ P,HNGSTP
;WILL DISPATCH TO USER'S AREA IF JOBINT IS NON-0


HNGSTP::PUSH	P,M
	PUSH	P,J
	PUSHJ	P,HNGSTX
	POP	P,J
	PJRST	MPOPJ##
HNGSTX:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	SKIPE	P3,DEVEVM(F)	;DOES DEVICE HAVE EVM?
	SETO	P3,		;NO
	PUSHJ	P,RTNEVM##	;RETURN ANY EVM DEVICE HAS FOR I/O
				; P3=-1 IF DEVICE HAD NO EVM, 0 IF IT DID
	SOS	.JDAT+JOBPD1##+1 ;BACK UP PC
	HRRZ	T4,DEVSER(F)	;DISK?
	CAIE	T4,DSKDSP##
	JRST	HNGSTZ		;NO
	MOVEI	T4,.EROFL	;ASSUME OFF-LINE
	HRRZ	P1,DEVUNI##(F)	;IS IT?
	MOVE	P1,UNIDES##(P1)
	TLNN	P1,UNPOFL##
HNGSTZ:	MOVEI	T4,.ERIDV	;PROBLEM ON DEVICE
IFN FTPI,<
	TLO	M,(1B0)
	PUSHJ	P,PSIJBI##	;CALL PSISER
	  PJSP	P1,HNGST1	;P1 NON-ZERO TO INDICATE INTERCEPTING
	TLZ	M,(1B0)
>
	SETO	T2,		;MAKE T2 NON-ZERO SO LATER CHECKS WILL WORK
	LDB	J,PJOBN##
	SKIPE	T3,JBTSTS##(J)
	TRNN	T3,JS.ASA
	PUSHJ	P,CHKINT	;SEE IF SET UP
	  SETZB	T2,T3		;NO
	MOVE	P1,T2		;SAVE LOCATION
	PUSHJ	P,DOINT		;PREPARE INTERCEPT
	JUMPN	T2,HNGST1	;IF NOT INTERCEPTING
	PUSHJ	P,INCPD1##
HNGST1:	JUMPL	T3,HNGST3	;YES, DOES HE WANT THE ERROR MESSAGE?
	PUSH	P,W
	PUSH	P,S
	PUSH	P,U
	PUSH	P,F		;SAVE DEV'S S WORD & DDB
	PUSHJ	P,FNDPDS##	;FIND PDB AND PUT IT'S ADDRESS IN W
				; IF NONE HALT.
	EXCH	F,0(P)		;GET F FROM DEVICE
	LDB	T1,PDVSTA##	;GET JOB'S LOCATION
	EXCH	F,0(P)		;GET F FOR TTY BACK
	JUMPE	T1,HNGST2	;CENTRAL SITE IF 0 (DISK)
IFN FTNET,<
	PUSHJ	P,STBOPR##	;GET OPR LINE
>
IFE FTNET,<
	MOVE	U,OPRLDB##
	SE1XCT	<LDB T1,LDPLNO##>
>
	SKIPA	U,LINTAB##(T1)	;GET LDB ADDR
HNGST2:	MOVE	U,OPRLDB##	;CENTRAL STA OPR
	PUSHJ	P,INLMES##	;OUTPUT START OF MESSAGE
	ASCIZ	/
%Problem on /
	PUSHJ	P,ERNAM		;PRINT PHYSICAL DEVICE NAME (USING -1(P))
	PUSHJ	P,INLMES##	;LOGICAL DEVICE OPR
	ASCIZ	/ for job /
	PUSHJ	P,PJOB##
	PUSHJ	P,CRLF##
	PUSHJ	P,DETJCK	;DETACHED?
	JRST	HNGST8		;YES,NO MESSAGES
	PUSHJ	P,TTYFUW##	;FIND CURRENT JOB'S TTY
	PUSHJ	P,CRLF##	;START A NEW LINE
	PUSHJ	P,ERNAM		;PRINT "DEVICE XXX"
	PUSHJ	P,INLMES##	;AND MSG.
	ASCIZ	/, OPR/
IFN FTNET,<
	EXCH	F,(P)		;GET POINTER DDB
	LDB	T1,PDVSTA##	;GET DEVICES LOCATION
	EXCH	F,(P)
	S0PSHJ	CVTSBT##	;CONVERT TO SIXBIT
	MOVE	T2,T1		;GET SIXBIT FOR PRNAME
	PUSHJ	P,PRNAME	;AND PRINT IT
>
	PUSHJ	P,INLMES##
	ASCIZ	/ action requested
/


	MOVEI	T1,TTYSTR##	;UNLESS ERROR INTERCEPTING
	SKIPN	P1		;CALL HOLD0 (STOP JOB,START TTY)
HNGST8:	MOVEI	T1,HNGST4	;SET UP ROUTINE TO CALL
	PUSHJ	P,(T1)		;START TTY TYPING ERR MESSAGE
				; LEAVE IN COMMAND MODE
				;DO NOT SET JOB ERROR SO CAN CONTINUE
	POP	P,F		;BRING BACK DEV DDB & S WORD
	POP	P,U
	POP	P,S
	POP	P,W
	JUMPN	P1,HNGST3	;DO INTERCEPT IF WANTED
	PUSHJ	P,WSCHED##	;RESCHEDULE
	HRRZ	T1,DEVSER(F)	;IS THIS A DISK?
	CAIE	T1,DSKDSP##
	 JRST	HNGST9		;NO, SKIP THIS
	PUSHJ	P,CHEKU##	;YES, WAS F/S YANKED?
	  PJRST	DEVHNG		;YES, SAY IT'S HUNG
HNGST9:	AOJN	P3,CPOPJ##	;DEVICE HAVE EVM WHEN THE ERROR OCCURRED?
	MOVE	M,-5(P)		;RESTORE M FOR ADDRESS CHECK
	PJRST	RSTEVM##	;YES, RESTORM EVM FOR I/O
HNGST3:	MOVEI	T1,DEPOND!DEPIND ;NON-BLOCKING I/O NOT DONE BITS
	ANDCAM	T1,DEVAIO(F)	;CLEAR THEM SO THAT IN/OUT UUOS WILL WIN
	MOVEI	P1,1(M)		;SAVE 1(INTERCEPT LOC)
	LDB	T1,PIOMOD##	;MODE
	MOVE	T4,DEVADV(F)
	TLNN	T4,DEPADV
	CAIL	T1,SD		;DUMP?
	JRST	HNGST7		;YES, NO BUFFERS TO FIX
	HRR	M,DEVBUF(F)	;BUFFERED, FIX UP BUFFER HDR
	TLNE	S,IO		; SO REPEATING THE UUO WILL WIN
	HLR	M,DEVBUF(F)	; (THEY WERE ALREADY ADVANCED)
	HRRZ	T4,M		;SAVE LOCATION OF THE HDR
	JUMPE	T4,HNGST7	;JUMP IF NO BUFFERS YET SET UP
	PUSHJ	P,GETWRD##	;GET LOCATION OF FIRST BUFFER
	JRST	HNGST7		;ADDRESS CHECK - CAN'T FIX THE RING
	MOVE	P2,T1		;P2=ADDRESS OF FIRST BUFFER
	MOVEI	T3,10000	;END OF LOOP INSURANCE
HNGST5:	HRR	M,T1		;M=ADDRESS OF THIS BUFFER
	PUSHJ	P,GETWRD##	;GET THE ADDRESS OF THE NEXT ONE
	  JRST	HNGST7		;ADDRESS CHECK, FORGET IT
	CAIE	P2,(T1)		;THE ONE WE WANT?
	SOJGE	T3,HNGST5	;NO, STEP TO NEXT
	JUMPL	T3,HNGST7	;YES, JUMP IF RING WAS NOT CLOSED
	HRR	P2,M		;P2=POINTER TO NEXT BUFFER
	TLO	T1,IOUSE	;INDICATE "FULL" FOR TEST AT INPUT
	PUSHJ	P,PUTWDU##	;STORE THAT
	HRR	M,T4		;RESTORE HEADER ADDRESS
	MOVE	T1,P2		;T1=DEADVANCED BUFFER POINTER
	PUSHJ	P,PUTWDU##	;STORE THAT IN THE HDR
HNGST7:	HRRI	M,(P1)		;M=ADDRESS OF THIRD WORD OF INT. BLOCK
	PUSHJ	P,GETWDU##	;FETCH IT
	HLR	T1,.USCTA
	SKIPL	M		;SKIP IF PSISER TRAP
	PUSHJ	P,PUTWDU##	;STORE FOR INTERRUPT ROUTINE
QKUSXT::
ERRGOU::HRRI	P,.JDAT+JOBPD1##+1 ;SET P FOR NORMAL EXIT
				;(POP P,UUO0 ; JRST @UUO0)
	SETZB	F,.CPISF##	;NO LONGER AT SCHEDULER LEVEL
	SETZM	.CPSCF##	;CLEAR FORCED RESCHEDULE FLAG
	NTGIVE			;RETURN NETWORK INTERLOCK
	PJRST	USRXIT##	;LET UUOCON RETURN TO USER
HNGST4:	MOVEI	T1,JDCON	;NO ERROR INTERCEPT
	IORM	T1,JBTSTS##(J)	; SO SET DEV CONT BIT

	MOVSI	T1,(UP.DST)	;MAKE THIS JOB LOOK DETACHED
	IORM	T1,.USBTS	; SO IT'S TERMINAL IS NOT PUT
				; AT COMMAND LEVEL.
	PJRST	STOP1C##	;STOP JOB-SETUP TO RESCHEDULE
				; BUT DO NOT CALL WSYNC

;ROUTINE TO SEE IF A JOB'S TTY IS DETACHED, CPOPJ1 IF ATTACHED
;CLOBBERS T1

DETJCK::PUSH	P,U		;SAVE SOME ACS
	PUSH	P,S
	PUSH	P,F
	PUSH	P,J
	PUSHJ	P,TTYSRC##	;FIND JOB'S TTY
	  CAIA			;NONE
	SKIPN	U		;OR DETACHED
	SOS	-4(P)		;DETACHED PRIV'ED JOB RETURN
	POP	P,J
	POP	P,F
	POP	P,S
	JRST	UPOPJ1##
;CHKINT -- ROUTINE TO SETUP FOR JOBINT USAGE
;CALL:	MOVEI	T4,ERROR TYPE (CLASS)
;	PUSHJ	P,,CHKINT
;SKIP RETURNS	M = RELATIVE BLOCK ADDRESS+2 (WHERE OLD PC IS STORED)
;		T1 = NEW PC
;		T3 = CONTENTS OF BITS,,CLASS
;STORES ERROR TYPE IN BLOCK+3.

CHKINT::SKIPN	JBTADR##(J)	;JOB HAVE CORE?
	POPJ	P,		;NO - THEN NO JOBINT
	MOVE	T1,JBTSTS##(J)	;JOB STATUS
	TLNN	T1,SWP		;IS JOB SWAPPED OR
	TRNE	T1,JS.ASA	;EXEC MODE UUO IN PROGRESS?
	POPJ	P,		;YES, DON'T TRAP
	HRR	M,.JDAT+JOBINT##  ;GET ERROR LOCATION
				; SET M FOR GETWRD/PUTWRD
	HRRZ	T1,M		;CHECK FIRST WORD OF INTERRUPT VECTOR
	PUSHJ	P,FLTST##	;IN-CORE?
	  POPJ	P,		;NO
	ADDI	T1,3		;LAST WORD OF VECTOR
	PUSHJ	P,FLTST##	;IN-CORE?
	  POPJ	P,		;NO
	TRNE	M,-1		;NO INTERRUPT IF JOBINT NOT SET
	PUSHJ	P,GETWRD##	;GET NEW PC
	  POPJ	P,		;ADDRESS CHECK - GIVE UP
	HRL	T4,T1		;SAVE NEW PC
	PUSHJ	P,GETWR1##	;GET BITS,,CLASS
	  POPJ	P,		;OUT OF BOUNDS
	MOVE	T3,T1		;SAVE THOSE
	PUSHJ	P,GETWR1##	;GET OLD PC
	  POPJ	P,		;ADDRESS CHECK - GIVE UP
	TRNE	T4,-1		;IF SPECIAL,
	TRNE	T3,(T4)		;  SEE IF USER OMITTED IT
	SKIPE	T1		;SEE IF IN USE ALREADY
	POPJ	P,		;YES - GIVE UP
	PUSHJ	P,GETWR1##	;GET THE OLD WORD
	  POPJ	P,0		; ADDRESS CHECK
	TLO	T1,(T4)		;TURN ON THE NEW BIT
	TRNE	T4,.ERQEX!.ERFUL!.EROFL!.ERIDV ;IS THERE A CHANNEL ASSOCIATED?
	HLR	T1,.USCTA	;YES, RETURN ASSOCIATED CHANNEL
	PUSHJ	P,PUTWRD##	;  STORE ERROR BITS
	  POPJ	P,		;ADDRESS CHECK - GIVE UP
	HLRZ	T1,T4		;GET NEW PC
	JUMPE	T1,CPOPJ##	;GIVE UP IF JUNK
	SOJA	M,CPOPJ1##	;OK RETURN

;DOINT -- ROUTINE TO PERFORM THE JOBINT
;CALL:	MOVE	T1,NEW PC
;	MOVEI	M,USER VIRTUAL ADDRESS OF INTERRUPT BLOCK + 2
;RETURN WITH JOBPD1 UPDATED

DOINT::	JUMPE	T2,CPOPJ##	;IF NO BLOCKS, GIVE UP
DOINT1:	PUSH	P,T1		;THIS COULD BE CHEAPER IF 2 ACS COULD BE USED, BUT?
	GETPC	T1,.JDAT+JOBPD1## ;GET UUO PC
	TLO	T1,(XC.USR)	;MAKE SURE USER MODE IS ON
	HLLM	T1,(P)		;COPY FLAGS FOR THE USER
	EXCH	T1,(P)		;PC TO TRAP TO
	PUTPC	T1,.JDAT+JOBPD1## ;STORE NEW PC
	POP	P,T1		;RESTORE OLD PC
	PJRST	PUTWDU##	;STORE OLD PC AND RETURN
;ROUTINE TO PRINT "SWAP READ ERROR"
;CALLED FROM SWAPPER AT CLOCK LEVEL (USUALLY)
;CALL:	MOVE J,JOB NUMBER
;	PUSHJ P,ERRSWP
;	ALWAYS RETURN TO SWAPPER


ERRSWP::PUSHJ	P,SVEUB##	;LOAD UBR
	MOVSI	T1,JERR		;SET JERR SO WE DO NOT
	IORM	T1,JBTSTS##(J)	;TRY TO INTERCEPT
	JSP	T1,ERRPNT	;PRINT MESSAGE
	ASCIZ	/Swap read error/
	PJRST	PCSTOP		;START TTY AND SET JERR BIT SO
				; JOB CANNOT CONTINUE. PI 7 WILL NOT
				; BE REQUESTED SINCE SWAPPING JOB CANNOT
				; BE CURRENT JOB.
				;ERRPNT PUSHED TWO AC'S. PCSTOP REMOVES THEM

SUBTTL	COMMON ERROR MESSAGE ROUTINES

;COMMON ERROR MESSAGE SETUP ROUTINES
;CALL:	JSP T1,ERRPTU, ERRDEV, OR ERRPNT
;	ASCIZ /message/
;	RETURNS HERE WITH F SAVED 0(P)
;	C(F)=TTYDDB, U TO TTY OUTPUT BUFFER POINTER
;	J=JOB NUMBER, W=ADDR OF PDB

;USE ERRPTU IF AT UUO LEVEL FOR SURE
;ERRDEV IF ERROR FOR AN ASSIGNED DEVICE AT ANY LEVEL
;ERRPNT WITH J ALREADY SET TO OFFENDING JOB NUMBER
;THE JSP CALL IS USED IN CASE PUSHDOWN SPACE BECOMES CRITICAL
;AGAIN AND ERRPNT HAS TO WIPE EXISTING LIST OUT


ERRPTU::SKIPA	J,.CPJOB##		;BLAME CURRENT JOB IF NOT 0.
ERRDEV::LDB	J,PJOBN##		;JOB NO. FROM DEVICE DATA BLOCK
ERRPNT::PUSHJ	P,FNDPDB##	;FIND PDB FOR THIS JOB
	  HRRZ	W,JBTPDB##	;USE NULL JOB'S PDB
	SKIPN	J		;ERROR IN NULL JOB?
	SETOM	.CPNJE##	;YES, SET FLAG FOR ERROR IN NULL JOB
				; SO STATE OF NULL JOB WILL BE REESTABLISHED
				; WHEN IS IT RUN AGAIN(SEE CLOCK1)

	CAILE	J,JBTMAX##	;JOB NUMBER OR SEGMENT NUMBER
	STOPCD	.,STOP,SOR,	;++SEG OUT OF RANGE


	PUSH	P,U		;SAVE CALL TO ERROR(JSP U,ERROR)
	PUSH	P,F		;SAVE ADR. OF DEV. DATA BLOCK
	PUSH	P,T1		;SAVE RETURN FROM ERRPNT
	MOVE	T1,JBTSTS##(J)
	TDNE	T1,[JERR,,JS.ASA]
	JRST	ERRPT1
IFN FTPI,<
	PUSHJ	P,USREIJ##	;SIGNAL USER ERROR
	JRST	ERRGOU
>
	MOVEI	T4,.EREIJ	;DOES THIS JOB WANT
	PUSHJ	P,CHKINT	; TRAP ALL ERRORS?
	  JRST	ERRPT1		;NO--BOMB HIM OUT
	JUMPGE	T3,ERRPT1	;JUMP IF HE WANTS MESSAGE
	MOVE	T2,M		;NO MESSAGE
	PUSHJ	P,DOINT		;PREPARE INTERCEPT
;***NEED TO STORE ERROR CODE***
	PJRST	QKUSXT		;BACK TO USER

ERRPT1:	PUSHJ	P,TTYERP##	;FIND TTY FOR THIS ERROR (VIA J)
	  PUSHJ	P,ERINDJ	;ERROR IN DETACHED JOB
	PUSHJ	P,INLMES##
	ASCIZ	/?
/
	PUSHJ	P,PRQM##	;PRINT QUESTION MARK ON NEXT LINE
				; FOR BATCH AND SCRIPT
	PJRST	INLMES##	;PRINT MESSAGE SPECIFIED BY CALLER
				; AND RETURN TO LOC. AFTER MESSAGE

ERINDJ::JUMPE	J,ERINNJ	;JUMP IF NULL JOB
	PUSHJ	P,INLMES##	;PRINT ERROR MESSAGE
	ASCIZ	/?Error in detached job/
	PUSHJ	P,PRJBNM	;PRINT JOB # AND PROGRAM NAME
	PJRST	CRLF##		;PRINT <CRLF> AND RETURN
ERINNJ:	PUSHJ	P,INLMESS##	;PRINT ERROR MESSAGE
	ASCIZ	/?Error in job 0 (null job)
/
	POPJ	P,
;ROUTINE TO PRINT UUO PC AND STOP JOB
;IF IN USER MODE PC WILL PRINT AS "AT USER LOC XXX"
;IF IN EXEC MODE "AT EXEC LOC XXX; EXEC CALLED FORM EXEC/USER/ LOC YYY


UUOMES::PUSHJ	P,CONMES##	;PRINT MESSAGE POINTED TO BY T1
UUOPCP::DMOVE	T1,.JDAT+JOBPD1## ;UUO PC STORED IN JOB DATA AREA
				; FIRST LOC ON PD LIST
	SOJA	T2,DPCPNT	;DECREMENT TO POINT TO UUO IN USER AREA


;ROUTINE TO PRINT ONE OF THREE MESSAGES AND STOP JOB
;1) "AT EXEC LOC XXX; EXEC CALLED FROM EXEC LOC YYY"
;2) "AT EXEC LOC XXX; EXEC CALLED FORM USER LOC YYY"
;3) "AT USER LOC YYY"

;CALL:	MOVE T2, XXX		;WITH PC FLAGS IN LH
;	PUSHJ P,PCPNT
;	NEVER RETURN IF AT UUO LEVEL


PCPNT::	TLNE	T2,USRMOD	;MAKE SURE CONTROL-T
	MOVEM	T2,JBTPC##(J)	; GIVES CORRECT ANSWER
	PUSHJ	P,PCP		;PRINT " AT EXEC XXX" OR " AT USER "
	TLNE	T2,USRMOD	;WAS PC IN USER MODE?
	JRST	PCSTOP		;YES, ENOUGH INFO.
	JRST	EXCALP		;NO, GIVE UUO INFO

;SAME AS PCPNT EXCEPT PRINTS A DOUBLE WORD PC IN T1 AND T2
DPCPNT::TLNE	T1,USRMOD	;MAKE SURE CONTROL-T
	MOVEM	T2,JBTPC##(J)	; GIVES CORRECT ANSWER
	PUSH	P,T1		;DPCP WIPES T1
	PUSHJ	P,DPCP		;PRINT " AT EXEC XXX" OR " AT USER "
	POP	P,T1		;GET FLAGS BACK
	TLNE	T1,USRMOD	;WAS PC IN USER MODE?
	JRST	PCSTOP		;YES, ENOUGH INFO.
;ROUTINE TO PRINT "; UUO AT [EXEC or USER] PC XXXXXX" AND STOP JOB
;CALL:	PUSHJ P,EXCALP
;	NEVER RETURNS IF AT UUO LEVEL
EXCALP::PUSHJ	P,INLMES##
	ASCIZ	/; UUO/
	DMOVE	T1,.JDAT+JOBPD1##	;UUO PC IN JOB DATA AREA
	SUBI	T2,1		;BACK IT UP TO POINT TO UUO
	PUSHJ	P,DPCP		;PRINT "EXEC LOC " OF USER LOC
PCSTOP::PUSH	P,U
	JUMPN	J,PCSTP5	;NULL JOB?
	PUSHJ	P,TTYERP	;YES--FIND THE OPR
	  JRST	PCSTP6		;WE HAVE A VALID LINE
	STOPCD	.,STOP,NJT,	;NULL JOB HAS TTY
PCSTP5:	PUSHJ	P,TTYSRC##	;SET TTY
	STOPCD	.,STOP,LN1,	;NONE?!
	JUMPE	U,PCSTP2	;IS IT DETACHED?
PCSTP6:	SKIPE	T1,F		;SKIP IF NO DDB
	LDB	T1,PJOBN##	;GET JOB #
	CAMN	T1,J		;IS THIS THE TTY OF THE LOOSER
	PUSHJ	P,TSETBI##	;CLEAR TYPE-AHEAD
PCSTP2:
IFN FTPI,<
	MOVE	T1,JBTSTS##(J)	;GET JOB STATUS
	TDNE	T1,[JERR,,JS.ASA]	;CAN WE INTERCEPT
	JRST	PCSTP1		;NO--STOP JOB
>
IFN FTPI,<
	PUSHJ	P,PSIERR##
	  JRST	PCSTP4		;AT CLOCK LEVEL, CATCH IT AT CIPXIT
	  JRST	ERRGOU		;AT UUO LEVEL, CATCH IT AT USRXIT
>
	MOVEI	T4,.EREIJ	;DOES THIS JOB WANT
	CAMN	J,.CPJOB##	;CANT INTERCEPT IF ON CLOCK LEVEL
	PUSHJ	P,CHKINT	; TRAP ALL ERRORS?
	  JRST	PCSTP1
	PUSHJ	P,DOINT1	;PREPARE INTERCEPT
	PJRST	QKUSXT		;BACK TO USER

PCSTP1:	JUMPN	U,PCSTP3	;IS JOB DET'D
	POP	P,U
	PUSHJ	P,CRLF##	;YES,
	PUSHJ	P,ESTOP##	;STOP JOB
	JRST	ECONT		;RESUME FLOW
PCSTP3:	PUSHJ	P,HOLD##	;STOP JOB SET ERROR BIT
PCSTP4:	POP	P,U
;HERE TO CONTINUE AFTER ERROR (IF AT PI LEVEL OR USER TYPES CONT)
ECONT:	POP	P,F		;RETURN ONLY IF AT INTERRUPT LEVEL
	JRST	TPOPJ##		;REMOVE ERROR CALL AND RETURN
				;ALTHOUGH U WAS PUSHED, POP INTO T1, PERSERVE LINE NUMBER

;ROUTINE TO TYPE A NUMBER AS HALFWORDS SEPARATED BY COMMAS.
;CALL:	MOVE	T1,NUMBER
;	PUSHJ	P,HWDPNT
;	RETURN

HWDPNT::PUSH	P,T1		;SAVE T1 FOR RH
	HLRZS	T1		;KEEP JUST LH
	PUSHJ	P,OCTPNT	;PRINT AS 6 OCTAL DIGITS
	PUSHJ	P,INLMES	;PRINT THE TWO COMMAS
	ASCIZ	/,,/		;...
	POP	P,T1		;RESTORE T1 FOR RH
	PJRST	OCTPNT		;PRINT RH AND RETURN

;ROUTINE TO TYPE A NUMBER AS HALFWORDS SEPARATED BY COMMAS.
;DIFFERES FROM HWDPNT IN THAT THE NUMBERS ARE NOT ZERO FILLED.
;CALL:	MOVE	T1,NUMBER
;	PUSHJ	P,PRTXWD
;	RETURN

PRTXWD::TLNN	T1,-1		;ANYTHING IN LH?
	PJRST	PRTDI8		;NO, THEN JUST LET PRTDI8 DO ITS THING
	PUSH	P,T1		;SAVE T1
	HLRZS	T1		;GET LEFT HALF
	PUSHJ	P,PRTDI8	;PRINT IT
	PUSHJ	P,INLMES##	;ADD SOME NOISE
	ASCIZ	/,,/		;...
	POP	P,T1		;RESTORE T1
	HRRZS	T1		;KEEP JUST RH
	PJRST	PRTDI8		;PRINT RH AND RETURN


;ROUTINE TO PRINT PC AS:
;1) "EXEC PC XXX" OR "USER PC XXX"
;CALL:	MOVE T2,PC TO PRINT(LH=PC FLAGS)
;	PUSHJ P,PCP


XMODE:	ASCIZ	/ at exec PC /
UMODE:	ASCIZ	/ at user PC /

PCP::	MOVEI	T1,XMODE	;ASSUME PC IN EXEC MODE
	TLNE	T2,USRMOD	;IS IT?
PCPU::	MOVEI	T1,UMODE	;NO, USER MODE
	PUSHJ	P,CONMES##	;PRINT ONE OR OTHER
	HRRZ	T1,T2		;PRINT RIGHT HALF IN OCTAL
				; FALL INTO OCTPNT


;ROUTINE TO PRINT 6 DIGIT OCTAL NUMBER
;CALL:	MOVEI LINE,LINE DATA BLOCK ADDRESS FOR TTY
;	HRR T1, OCTAL NUMBER
;	PUSHJ P,OCTPNT
;	RETURN T2,PRESERVED,T1 DESTROYED

OCTPNT::HRLZ	T1,T1		;MOVE TO LH FOR ROTATING
	TRO	T1,700000	;SETUP AN END FLAG
OCTP1:	ROT	T1,3		;GET NEXT OCTAL DIGIT
	TLNN	T1,777777	;WAS THAT FLAG?
	POPJ	P,		;YES, DO NOT PRINT IT
	PUSH	P,T1		;SAVE T1 OVER I/O ROUTINE
	PUSHJ	P,PRTNUM	;NO, PRINT OCTAL DIGIT
	POP	P,T1		;RESTORE T1
	HRRI	T1,0		;CLEAR RH
	JRST	OCTP1		;GET NEXT OCTAL DIGIT
;ROUTINE TO PRINT A DOUBLE WORD PC
;CALL:	MOVEI	U,LDB
;	DMOVE	T1,[EXP FLAGS,PC]
;	PUSHJ	P,DPCP

DPCP::	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	SKIPA	T1,[XMODE]	;NO, TYPE AT EXEC MUMBLE
	MOVEI	T1,UMODE	;YES, TYPE AT USER MUMBLE
	PUSHJ	P,CONMES##	;TYPE IT
UDPCP::	HRRZ	T1,T2		;ONLY EIGHTEEN BITS IF NOT AN XADR
	TLNN	T2,(SECMSK)	;NON-ZERO SECTION?
	PJRST	OCTPNT		;NO, PRINT IT IN THE TRADITIONAL WAY
	PUSH	P,T1		;SAVE LOW EIGHTEEN BITS
	HLRZ	T1,T2		;SECTION NUMBER
	PUSHJ	P,PRTDI8	;PRINT THAT
	MOVEI	T1,[ASCIZ /,,/]	;ZERO SUPPRESSED OCTAL PAIRS
	PUSHJ	P,CONMES##	;PRINT SEPERATER
	POP	P,T1		;LOW EIGHTEEN BITS OF PC
	PJRST	OCTPNT		;FINALLY PRINT THAT
;ROUTINE TO ADD 1 TO T1 AND PRINT DECIMAL
;SAME CALL AS OCTPNT

DECP1::	AOJA	T1,RADX10	;ADD 1 AND GO PRINT

;ROUTINE TO PRINT DECIMAL
;CALL:	SAME AS OCTPNT
;T2:	PRESERVED

RADX10::PUSH	P,T2		;SAVE T2
	PUSHJ	P,PRTDIG	;PRINT DECIMAL DIGITS
	PJRST	T2POPJ##	;RESTORE T2 AND RETURN

;RECURSIVE DECIMAL PRINT ROUTINE
;CALL:	MOVE T1,DECIMAL NO.
;	PUSHJ P,PRTDIG

PRTDIG::
IFN FTXMON,<
	PUSHJ	P,SSEC0##	;RUN IN SECTION 0
>
PRTDGX:	IDIVI	T1,12		;DIVIDE BY 10
	HRLM	T2,(P)		;RT ON PD LIST
	JUMPE	T1,.+2		;FINISHED?
	PUSHJ	P,PRTDGX	;NO, CALL S OR F
PRTNMM:	HLRZ	T1,(P)		;YES, GET LAST NUMBER
PRTNUM:	MOVEI	T3,"0"(T1)	;CONVERT TO ASCII
	PJRST	COMTYO##	;AND TYPE IT OUT

;RECURSIVE OCTAL PRINT ROUTINE
;CALL:	SAME AS PRTDIG

PRTDI8::
IFN FTXMON,<
	PUSHJ	P,SSEC0##	;RUN IN SECTION 0
>
PRTD8X:	IDIVI	T1,10		;DIVIDE BY 8
	HRLM	T2,(P)		;PUT ON STACK
	JUMPE	T1,PRTNMM	;FINISHED?
	PUSHJ	P,PRTD8X	;NO - LOOP
	PJRST	PRTNMM		;OUTPUT

;SUBROUTINE TO PRINT 22 BIT OCTAL ADDRESS
;CALL:	MOVE	T1,22 BIT ADDRESS
;	PUSHJ	P,PRT22A
;	ALWAYS RETURN

PRT22A::PUSH	P,T1		;SAVE 22 BIT ADDRESS
	HLRZ	T1,(P)		;GET HIGH ORDER HALF
	JUMPE	T1,PRT22B	;IS IT 0 (USUALLY EXCEPT BIG SYSTEMS)
	PUSHJ	P,PRTDI8	;NO, PRINT AS LEADING 0 SUPPRESSED OCTAL
PRT22B:	POP	P,T1		;GET LOW ORDER HALF
	PJRST	OCTPNT		;PRINT AS NON ZERO SUPPRESSED OCTAL (RH ONLY)
;ROUTINE TO PRINT "DEVICE XXX"
;CALL	MOVE U,ASCII OUTPUT BYTE POINTER
;	PUSH P,F
;	PUSHJ P,ERNAM


ERNAM::	PUSHJ	P,INLMES##
	ASCIZ	/device /
	SKIPN	T2,-1(P)	;IS F = 0?
	PJRST	PRNAM1		;YES, MESSAGE WITHOUT NAME
	HRRZ	T1,DEVSER(T2)	;IS THIS A DISK?
	CAIE	T1,DSKDSP##
	JRST	ERNAM1		;NOT DISK, GET PHYSICAL DEVICE NAME
	SKIPN	T1,DEVUNI##(T2)	;GET CURRENT UNIT DATA BLOCK ADDRESS
	SKIPE	T1,DEVFUN##(T2)	;IF UNIT REMOVED, GET SAVED ADDRESS
	SKIPA	T2,UNINAM##(T1)	;GET PHYSICAL UNIT NAME AND SKIP TO PRNAM1
ERNAM1:	MOVE	T2,DEVNAM(T2)	;NO, GET DEVICE NAME


;ROUTINE TO PRINT SIXBIT NAME
;CALL	MOVE U,ASCII OUTPUT BYTE POINTER
;	MOVE T2,NAME
;	PUSHJ P,PRNAME


PRNAM1:	MOVEI	T1,0
	LSHC	T1,6		;SHIFT IN NEXT CHAR.
	MOVEI	T3,40(T1)	;ASCII VERSION INTO CHREC FOR OUTCHS
	PUSHJ	P,COMTYO##	;OUTPUT CHARACTER
PRNAME::JUMPE	T2,CPOPJ##
	JRST	PRNAM1


;ROUTINE TO PRINT SIXBIT WORD WITH TRAILING SPACES
;CALL:	SAME AS PRNAME.
PRSIXB::MOVEI	T3,6
	PUSH	P,T3
PRSIX0:	SETZ	T3,
	ROTC	T2,6
	ADDI	T3,40
	PUSHJ	P,COMTYO##
	SOSLE	(P)
	  JRST	PRSIX0
	JRST	T3POPJ##


	LIT

ERREND:	END