Google
 

Trailing-Edge - PDP-10 Archives - dec-10-omona-u-mc9 - klser.mac
There are 5 other files named klser.mac in the archive. Click here to see a list.
TITLE	KLSER - KL10 PROCESSOR DEPENDENT CODE - FROM KISER V165 -V204
SUBTTL  J.M. FLEMMING/JMF & D.A. LEWINE/DAL/EVS  15 FEB 77
	SEARCH	F,S
	$RELOC
	$HIGH
;***COPYRIGHT 1973,1974,1975,1976,1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
XP VKLSER,204
		; PUT VERSION NUMBER IN GLOB LISTING AND LOADER STORAGE MAP
V1088==3		;1088 LIR VERSION NUMBER

;USER CACHE SCHEME #2
	ENTRY	KLSER		;LOAD KLSER IF LIBRARY SEARCH
KLSER:
REPEAT	0,<
	CLK==70		;MACRO 47 DOES NOT KNOW ABOUT CLK.
SUBTTL	CLOCK1 - INTERFACE TO JOB STARTUP, STOP, AND CONTEXT SWITCHING ROUTINES

;THIS IS THE DK10 HACK FOR CLOCK INTERRUPTS

DKXINT::CONSO	CLK,30		;INTERRUPT PENDING?
	JRST	.		;SEE SYSINI(IOG5)
	AOS	TIME##		;MAKE TIME BE LATER
	SKIPE	CRSHWD##	;TIME FOR CRASH DUMP?
	JRST	SYSTOP##	;YES.
	SOS	HNGTIM##	;REDUCE TIME TILL SECOND
	MOVEM	P4,SAVEP4	;PUT P4 IN A SAFE PLACE
	MOVEI	P4,.C0CDB##	;ASSUME CPU0
IFN FTMS,<
	SKPCPU	(0)		;SKIP IF CPU0
	MOVEI	P4,.C1CDB##	;NO--GET CPU1 POINTER
	SOS	.CPOK##(P4)	;I AM OK
	SOS	.CPOK##(P4)	; ..
	AOS	@.CPOK1##(P4)	;YOU ARE OK
>
	AOS	.CPUPT##(P4)	;COUNT UPTIME
	SETOM	.CPTMF##(P4)	;THE TIME HAS COME
	SETOM	.CPCKF##(P4)	;FLAG CHAN 7 INTERRUPT
	CONO	PI,XI.RQC##	;RING LOW PRIO CHIMES
	CONO	CLK,32		;CLEAR CLOCK FLAG
	MOVE	P4,SAVEP4	;RESTORE P4
	JEN	@CH2##		;EXIT INTERRUPT
	$LOW
SAVEP4:	0
	$HIGH
>
;HERE AT CLK INTERRUPT LEVEL

;THIS CODE IS DUPLICATED IN CP1SER FOR CPU1

CK0INT::SKIPN	.C0CKF##	;CLK INTERRUPT REQUEST?
	JRST	CK0INT		;NO, CHECK OTHER DEVICES
	DATAI	PAG,SVPG7	;SAVE STATUS OF PAG, MAKE SURE WE SELECT
				;PROPER AC SET AT INTERRUPT EXIT
	EXECAC			;SWITCH TO EXEC AC BLOCKS
	CONO	PI,II.CCI##	;CLEAR SOFTWARE INITIATED CLOCK INTERRUPT FLAG
	MOVEM	17,.C0S17##	;SAVE AC 17
	MOVE	17,CK0CHL##	;IS CURRENT JOB IN USER MODE?
	TLNE	17,(XC.USR)
	JRST	CK0IN1		;YES, DON'T NEED TO SAVE THE ACS
	MOVE	17,.C0S17##	;IN EXEC MODE, ASSUME NOT FORCED RESCHEDULE
	SKIPN	.C0SCF##	;SKIP IF THE FORCED RESCHEDULING FLAG IS ON
		JRST	[DATAO	PAG,SVPG7
		 JEN	@CK0CHL##] ;INTERRUPTED OUT OF A UUO, LEAVE CLOCK FLAG
				; SET AND DISMISS
	SKIPN	17,.C0ADR##	;CURRENT JOB DATA AREA, IS THERE ONE?
	MOVE	17,.C0NJD##	;NO, MUST BE KJOB OR CORE 0, RUNS AT UUO
				; LEVEL AND REQUESTS A CLOCK INTERRUPT TO STOP
	MOVEM	16,JOBD16##(17)	;SAVE AC 16 IN DUMP AREA OF JOB DATA AREA
	MOVEI	16,JOBDAC##(17)	;SOURCE = 0, DESTINATION = DUMP AC 0
	BLT	16,JOBD15##(17)	;SAVE ACS 0-15 IN DUMP AC AREA
	MOVE	T1,.C0S17##	;NOW SAVE 17 IN THE JOB DATA AREA
	MOVEM	T1,JOBD17##(17)	;ALONG WITH THE OTHER DUMP ACS
	MOVE	17,CK0CHL##	;RESTORE INTERRUPT PC
CK0IN1:	MOVEM	17,.C0PC##	;SAVE PC IN PROTECTED PART OF SYSTEM DATA
				; STORAGE FOR CURRENT JOB
CK0SPD::MOVE	P,.C0NPD##	;SETUP PUSH DOWN LIST IN NULL JOB DATA AREA
				;TURN ON USER IOT SO XCTP WORKS RIGHT
CK0IN2:	JRSTF	@[IC.UOU+CHKAPE##] ;CHECK FOR APR ERRORS, CALL THE COMMAND
				; DECODER, AND RESCHEDULE
CIP8B::	MOVE	T1,.C0PC##	;GET THE PC FOR THE CURRENT JOB
	TLNE	T1,(XC.USR)	;IS IT IN USER MODE?
	JRST	[USERAC		;RESET USER AC BLOCK #'S
		 JEN @.C0PC##]	;DISMISS INTERRUPT
	MOVSI	17,JOBDAC##(R)	;NO, RESTORE EXEC MODE ACS
	BLT	17,17		; FROM THE DUMP AC AREA
	JEN	@.C0PC##	;RETURN TO THE INTERRUPTED EXEC MODE PROGRAM

	$LOW
SVPG7:	0			;PLACE TO SAVE STATUS OF PAG
	$HIGH
;ROUTINE TO SAVE THE USER'S ACS IN AC BLOCK 1 IN THE SHADOW AC
; AREA IN THE JOB DATA AREA ON A CONTEXT SWITCH
;CALLING SEQUENCE:
;	SETUP THE USER BASE REGISTER TO POINT TO THE CURRENT JOB'S UPMP
;	PUSHJ	P,SAVUAC
;	ALWAYS RETURN HERE

SAVUAC::PUSH	P,J		;SAVE CURRENT JOB NUMBER
	MOVE	J,U		;J 2 JOB NUMBER OF THE LAST JOB RUN
	PUSHJ	P,SETUPR	;SETUP R TO POINT TO SHADOW AREA
	JRST	JPOPJ##		;NO CORE IN CORE
	MOVEI	T1,(R)		;SOURCE = USER AC 0,
				; DESTINATION = AC 0 IN SHADOW AREA
	EXCTUX	<BLT	T1,17(R)>
				;SAVE USER ACS 0-17
	JRST	JPOPJ##		;RETURN

;ROUTINE TO RESTORE THE USER'S ACS TO AC BLOCK 1 FROM THE SHADOW AC
; AREA IN THE JOB DATA AREA ON A CONTEXT SWITCH
;CALLING SEQUENCE:
;	SETUP THE USER BASE REGISTER TO POINT TO CURRENT JOB'S UPMP
;	PUSHJ	P,RESUAC
;	ALWAYS RETURN HERE

RESUAC::PUSHJ	P,SETUPR	;SETUP R TO POINT TO SHADOW AREA
	  POPJ	P,		;NO CORE IN CORE
	MOVSI	T1,(R)		;SOURCE = AC 0 IN THE SHADOW AREA,
				; DESTINATION = USER AC 0
	EXCTXU	<BLT T1,17>	;RESTORE USER ACS 0-17
	POPJ	P,		;RETURN

;SUBROUTINE TO SETUP R TO POINT TO SHADOW AC AREA FOR THE CURRENT JOB
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER OF CURRENT JOB
;	PUSHJ	P,SETUPR
;	RETURN HERE IF NOT THE NULL JOB BUT HAS NO CORE (CORE 0,KJOB)
;	RETURN HERE - R POINTS TO THE CURRENT JOBS SHADOW ACS

SETUPR:	MOVEI	T1,JS.ASA	;DON'T SAVE ACS IF THE SHADOW AREA ISN'T FREE
	TDNE	T1,JBTSTS##(J)	;IS IT?
	POPJ	P,		;NO
SETRUP:	SKIPN	R,JBTADR##(J)	;SETUP R - DOES THE JOB HAVE CORE IN CORE?
	JUMPN	J,CPOPJ##	;NO, IF J IS NON-ZERO (I.E., NOT THE NULL
				; JOB) GIVE NON-SKIP RETURN (JOB HAS NO ACS)
	JUMPN	R,CPOPJ1##	;IS IT THE NULL JOB?
	MOVE	R,.CPNJD##(P4)	;YES, RETURN ADDRESS OF NULL JOBS SHADOW AREA
	ADDI	R,JOBDAC##	; ..
	JRST	CPOPJ1##	;GIVE SKIP (THERE IS A PLACE TO STORE ACS) RETURN
;ROUTINE TO ENABLE/DISABLE APR FOR TRAPPING TO USER AND EXEC
;CALL:	MOVEI T1, APR CONSO FLAGS FOR USER TRAPPING
;	PUSHJ P,SETAPR
;	RETURN WITH APR RESET AND INTERRUPT LOCATION CONSO'S SET

SETAPR::PUSH	P,P4		;SAVE P4
	MOVEI	P4,.C0CDB##	;SET UP CDB INDEX FOR CPU0
SETAP1::PUSHJ	P,SETRP		;SETUP THE TRAP LOCATIONS (PAGE FAULT,
				; ARITHMETIC, PDL OVF)
SETAP2:	PUSHJ	P,SETCNA	;SET USER ENABLES FOR NXM AND CLOCK AND
				; SET THE APR PIA
	POP	P,P4		;RESTORE P4
	POPJ	P,		;EXIT

;ROUTINE TO SETUP USER TRAP LOCATIONS AS SPECIFIED BY USER ENABLE BITS
; PAGE FAULT (ILL. MEM. REF.), ARITHMETIC (INTEGER OVERFLOW, FLOATING
; POINT OVERFLOW OR UNDERFLOW, AND DIVIDE CHECK), PUSH DOWN LIST OVERFLOW
; TRAP 3 IS ALWAYS IGNORED IN USER MODE.
;CALLING SEQUENCE:
;	MOVE	T1,USER ENABLE BITS
;	PUSHJ	P,SETRP
;	ALWAYS RETURN HERE
;T1 IS PRESERVED.

SETRP:	TRNE	T1,AP.AOV+AP.FOV;IS HE?
	TDZA	T2,T2		;YES, SET TO FIELD TRAPS
	MOVSI	T2,(JFCL)	;IGNORE ARITHMETIC TRAPS IF USER NOT ENABLED
IFN FTPI,<
	HRRI	T2,SAROVF	;SET DISPATCH ADDRESS
	MOVEM	T2,.UPMP+.UPAOT	;STORE IN UPT
>
IFE FTPI,<
	HLLM	T2,.UPMP+.UPAOT	;FIELD OR IGNORE USER AOF TRAPS
>
	MOVEI	T2,SEPDLO	;IF USER NOT ENABLED FOR POV HANDLE LIKE EXEC POV
	TRNE	T1,AP.POV	;IS HE ENABLED?
	MOVEI	T2,SUPDLO	;YES, HANDLE DIFFERENTLY
	HRRM	T2,.UPMP+.UPPDT	;YES, SET FOR SEPDLO OR SUPDLO TO HANDLE PDL OV
IFE FTPI,<
	POPJ	P,		;RETURN
>
IFN FTPI,<
	PJRST	APPSI##	;SETUP TRAP LOCATIONS FOR ANY INTERRUPTS THE
				; USER IS ENABLED FOR
>
;SUBROUTINE TO SETUP USER'S APR CONSO MASK AND THE APR PIA
;CALLING SEQUENCE:
;	MOVE	T1,USER'S APR ENABLE BITS
;	PUSHJ	P,SETCNA
;	ALWAYS RETURN HERE

SETCNA::HRL	T1,T1		;COPY ENABLE BITS TO LEFT HALF
	TLZ	T1,-1-XP.CLK-UE.PEF ;CLEAR ALL BITS EXCEPT CLOCK FLAG
				; AND USER ENABLED MEM PARITY
	TRNE	T1,AP.NXM	;DOES USER WANT NXM ENABLED?
	TLO	T1,LP.NXM	;YES, ENABLE THAT FOR HIM
	HRR	T1,.CPEEB##(P4)	;SET MONITOR ENABLES
	MOVEI	T2,@.CPAPI##(P4) ;MOVE IN APR PIA
	CONO	PI,PIOFF##	;DISALLOW INTERRUPTS WHILE CHANGING APR BITS
	HLRM	T1,.CPCN1##(P4)	;USER'S ENABLE BITS
	HRRM	T1,.CPCON##(P4)	;MONITOR'S ENABLE BITS
	CONO	APR,(T2)	;SET PIA
	CONO	PI,PION##	;RESTORE PI
	POPJ	P,		;RETURN
;ROUTINE TO CAUSE CLK ROUTINE TO RESCHEDULE
;CALLED AT ANY LEVEL
;CALL:	PUSHJ P,STOP2	
;	RETURN IMMEDIATELY EXCEPT IF AT UUO LEVEL
;	IF AT UUO LEVEL, RETURN WHEN JOB IS RUNABLE AGAIN

STOP2::	CONO	PI,PIOFF##	;PREVENT CLOCK INTERRUPT DURING STOP2 CODE
	SETOM	.C0CKF##	;SET FLAG TO INDICATE CLK INTERRUPT
				; EVEN THOUGH CLK INTERRUPT IS NOT A TIME INTERRUPT
	CONO	PI,PICLK##	;TURN PI BACK ON AND REQUEST INTERRUPT TO
				; CLK PI CHANNEL(LOWEST PRIORITY CHANNEL)
	CONSZ	PI,II.IPA	;AT INTERRUPT LEVEL?
	POPJ	P,		;YES, RETURN IMMEDIATELY

	PUSH	P,T1		;NO, AT UUO LEVEL
STOP3:	CONI	PI,T1		; MAKE SURE CLOCK LEVEL PROCESSING
	TLNE	T1,CLKBIT##	; HAPPENS BEFORE DOING ANYTHING ELSE
	JRST	STOP3		; SINCE MAY NOT HAVE ANY CORE
	JRST	TPOPJ##		;RETURN

TSTREL::MOVEI	T1,JS.ASA	;WHAT DOES REFERENCE TO USER 0-17 REALLY MEAN BIT
	TRNN	M,777760	;IS THIS REFERENCE TO USER 0-17?
	TDNN	T1,JBTSTS##(J)	;YES, IS IT TO USER'S ACS OR THE SHADOW ACS?
	AOS	(P)		;USER'S ACS
	POPJ	P,		;GIVE SHADOW ACS OR USER AC SET RETURN
SAROVF::EXECAC
	MOVEI	P4,.C0CDB##	;ASSUME CPU0
IFN FTMS,<
	SKPCPU	(0)		;IS THIS CPU0?
	MOVEI	P4,.C1CDB##	;NO, POINT P4 AT CPU1'S CDB
>
	EXCH	R,.CPADR##(P4)	;GET ADDRESS OF USER'S JOB DATA AREA
	MOVEM	T1,.UPMP+.UPMUO	;SAVE A TEMPORARY
	HLLZ	T1,.UPMP+.UPMUP	;GET PC ERROR FLAGS
	HRR	T1,JOBENB##(R)	;GET USER'S ENABLE BITS
	TLZ	T1,3637		;CLEAR NON-EXISTANT KA10 BITS FOR COMPATABLITY
	TRNN	T1,AP.AOV	;OVERFLOW - IS THE USER ENABLED?
	TLNE	T1,(XC.FOV)	;TRAP CAUSED BY FOV?
	JRST	SAROV2		;YES, GO TRAP TO HIM
SAROV1:	MOVE	T1,.UPMP+.UPMUP	;USER IS NOT ENABLED FOR THIS EXCEPTION - RESTORE THE
	JRST	SAROV6		; TRAP PC AND DISMISS TO THE INTERRUPTED PROGRAM
SAROV2:	HRRI	T1,AP.AOV+AP.FOV;ASSUME FLOATING OVERFLOW
	TLNN	T1,(XC.FOV)	;WAS IT A FLOATING OVERFLOW TRAP?
	TRZ	T1,AP.FOV	;NO, INTEGER OVERFLOW
	HRRZM	T1,JOBCNI##(R)	;SIMULATE KA10 CONI APR,JOBCNI(R)
	HRR	T1,.UPMP+.UPMUP	;RESTORE TRAP PC
	MOVEM	T1,JOBTPC##(R)	;STORE IT FOR TRAP HANDLING ROUTINE
	JRST	SAROV4		;FINISH UP
SAROV3:	HRRZM	T1,JOBCNI##(R)	;LIKE CONI ON THE KA-10
SAROV4:	HRR	T1,JOBENB##(R)	;GET USER'S ENABLE BITS
	TRNE	T1,XP.DDU	;USER WANT TRAPS REENABLED?
	JRST	SAROV5		;YES, LEAVE AS IS
	HLLZS	JOBENB##(R)	;CLEAR USER'S ENABLE BITS SO MUST DO APRENB AGAIN
	HRRI	T1,(JFCL)	;NOP
	HRLM	T1,.UPMP+.UPAOT	;IGNORE ARITHMETIC TRAPS
	HRRI	T1,SEPDLO
	HRRM	T1,.UPMP+.UPPDT	;EXEC WILL FIELD PDL OVERFLOWS
	SETZM	.CPCN1##(P4)	;CLEAR POSSIBLE NXM OR CLOCK ENABLES
SAROV5:	HRR	T1,.CPCN1##(P4)	;CLEAR CLOCK ENABLE SO THAT WON'T INTERRUPT HIM
	TRZ	T1,XP.CLK
	HRRZM	T1,.CPCN1##(P4)	;NEW USER ENABLE BITS
	HRR	T1,JOBAPR##(R)	;GET USER'S TRAP ADDRESS
SAROV6:	TLZ	T1,(XC.OVF+XC.FOV+XC.FUF+XC.NDV)
	TLO	T1,(XC.PUB)	;INSURE PUBLIC IS SET
	EXCH	T1,.UPMP+.UPMUO	;NEW PC WITH TRAP CAUSING BITS CLEARED
	EXCH	R,.CPADR##(P4)	;RESTORE R
	USERAC
	JEN	@.UPMP+.UPMUO	;EXIT TO THE USER'S TRAP HANDLER
SEPDLO::EXECAC
	MOVEM	P4,.UPMP+.UPMUO	;SAVE P4
	MOVEI	P4,.C0CDB##	;ASSUME CPU0
IFN FTMS,<
	SKPCPU	(0)		;ON CPU1?
	MOVEI	P4,.C1CDB##	;YES, POINT P4 AT CPU1'S CDB
>
	EXCH	T1,.UPMP+.UPMUP	;GET THE PC
	MOVEM	T1,.CPAPC##(P4)	;SET AS ERROR PC FOR ERRCON
	HRRI	T1,AP.POV	;SET PUSH DOWN OVERFLOW FLAG
SEPDL1:	TLNN	T1,(XC.USR)	;WAS THE PDL OVF IN USER MODE?
	JRST	SEPDL2		;NO
	HRRZM	T1,.JDAT+JOBCNI## ;STORE THE PDL OVF BIT
	MOVE	T1,.CPAPC##(P4)	;GET THE USER'S PC
	MOVEM	T1,.JDAT+JOBTPC## ;STORE IT FOR LATER REPORTING
	MOVEI	T1,JS.APE	;APR ERROR IN JOB BIT
	EXCH	J,.CPJOB##(P4)	;GET THE CURRENT JOB'S JOB NUMBER
	IORM	T1,JBTSTS##(J)	;LIGHT APR ERROR BIT
IFN FTMS,<
	MOVE	P,[MJOBPD##,,.JDAT+JOBPDL##] ;SETUP A PUSH DOWN LIST
	PUSHJ	P,CP1APE##	;MAKE SURE THE JOB IS RUNNABLE ON CPU0
				; SO IT WILL GET STOPPED AND ERROR WILL BE REPORTED
>
	EXCH	J,.CPJOB##(P4)	;RESTORE J
	JRST	SEPDL3		;AND PROCEDE
SEPDL2:	HRRM	T1,.CPAEF##(P4)	;IN .CPAEF SO ERRCON WILL GET CALLED
SEPDL3:	MOVE	T1,.UPMP+.UPMUP	;RESTORE T1
	CONO	PI,PIOFF	;NO INTERRUPTS UNTIL P4 IS RESTORED
	SETOM	.CPSCF##(P4)	;SET FORCED RESCHEDULING FLAG
	SETOM	.CPCKF##(P4)	;AND CLOCK FLAG
	MOVE	P4,.UPMP+.UPMUO	;RESTORE P4
	CONO	PI,PICLK##	;REQUEST A CLOCK INTERRUPT AND TURN THE PI SYSTEM ON
	CONSZ	PI,II.IPA	;ANY PIS IN PROGRESS?
	STOPCD	.,STOP,PIP,	;++PI IN PROGRESS
	JRST	.		;WAIT UNTIL CLOCK LEVEL HAPPENS AND THE JOB
				; IS STOPPED IF IN USER MODE.  IF THE PC IS IN
				 ;EXEC MODE, ERRCON WILL CONTINUE AT
				; (.CPAPC(P4)) INSTEAD OF HERE
;HERE ON A PAGE FAULT (NO UUO DONE)
SEILM::	CONO	PI,PIOFF##	;NO INTERRUPTS PLEASE
	EXECAC
	MOVEM	P4,.UPMP+.UPMUO	;SAVE P4
	MOVEI	P4,.C0CDB##	;ASSUME ON CPU0
IFN FTMS,<
	SKPCPU	(0)		;ARE WE?
	MOVEI	P4,.C1CDB##	;NO, POINT P4 AT CPU1'S CDB
>
	MOVEM	T1,.UPMP+.UPMUP	;SAVE T1 TEMPORARILY
	LDB	T1,[POINT 5,.UPMP+.LMPFW,5]	;PICK UP PF CODE
	CAIN	T1,PF.PTP	;IS IT PAGE TABLE PARITY?
	JRST	PTPAR		;YES,GO PROCESS
	CAIE	T1,PF.ARP	;IS IT AR PARITY?
	CAIN	T1,PF.AXP	;OR ARX PARITY?
	CAIA			;YES, FALL THROUGH INTO PARTRP 
	JRST	SEILMA		;GO HANDLE PAGE FAULT


REPEAT 0,<

AR/ARX TRAP -MEMORY PARITY HANDLING FOR KL10

BACKGROUND:	BY DESIGN THE KL WILL FREEZE DATA WHICH PASSES INTO THE AR/ARX WITH BAD (EVEN) PARITY. INSTRUCTION EXECUTION IN THIS CASE
IS INTERRUPTED TO STOP PROPAGATION OF THE BAD DATA.  
	THE AR/ARX TRAP -MEMORY PARITY INTERRUPT HANDLING ALGORITHM
HAS THE FOLLOWING OBJECTIVES:
	1. TRY, IF POSSIBLE, TO CONTINUE THE USER, IF GOOD DATA CAN BE
	FOUND IN PHYSICAL MEMORY (INTERMITTENT CACHE FAILURE)
	2. STOP AFFLICTED USER, WHICH IS GOING TO USE BAD DATA AND INFORM HIM
	(BAD DATA ITEMS SET TO 0 TO AVOID RECURSIVE FAILURES DURING SWAPPING/PAGING)
	3.  STOP SYSTEM IF BAD DATA ITEM ORIGINATES OUT OF MONITOR DATA BASE.
	4.  LOG IN EACH INSTANCE PERTINENT INFORMATION VIA
	DAEMON TO BE REPORTED LATER VIA SYSERR
	5. SCAN ALL OF PHYSICAL CORE ON LINE FOR MORE BAD DATA TO GATHER
	AS MUCH STATISTICAL INFORMATION FOR ANALYSIS BY FIELD SERVICE
	AND HANDLE AFFECTED USERS AS IN 1 TO 4 ABOVE.

CODE IMPLEMENTATION:  THE CODE IS DISPERSED IN ITS MAJORITY THRU:

	KLSER - AR/ARX TRAP HANDLING AND CORE SWEEP
	CLOCK1 - MEMORY PARITY HANDLING  AT INTERRUPT
	ERRCON - CORE SWEEP CALLS AND ERROR-MESSAGE TYPEOUT
	COMMON - CPU DATA BLOCK DEFINITIONS
	S -    BIT DEFINITIONS FOR LOCAL FLAGS
	SYSINI - "UN CACHING" OF THE FIRST PORTION OF THE MEMORY PARITY
	 INTERRUPT HANDLING TO SHORTEN THE "WINDOW" OF REPETITIVE CACHE
	 WRITE-BACK AND OTHER RECURSIVE FAILURES
	  "UN CACHING" OF EDDT FOR DEBUGGING (THIS IS IN REPEAT 0 FOR STD MONITOR)
	
TO AVOID UNNECCESSARY FURTHER SPLIT AND DUPLICATION OF CODE, THE AR/ARX TRAP
ROUTINE USES THE MEMORY PARITY INTERRUPT CODE TO KILL AFFECTED USERS, EVEN
IF NO INTERRUPT WAS PENDING, BY SIMULATING ONE.  EXPECTED TRAPS/INTERRUPTS
DURING THE CORE SWEEP ARE CHECKED AGAINST THE PC OF BLT-INSTRUCTION
(MPI LABEL); A FAILURE FROM OTHER THAN THIS PC IS REGARDED AS FATAL
SINCE THE CODE IS NOT REENTRANT THE USED AC FOR THE BLT IS FIXED UP
TO ALLOW CONTINUATION OF THE BLT.

>;END REPEAT 0
;HERE ON AR OR ARX PARITY TRAP (PAGE FAIL CODE 36 OR 37)


PRTRP:	EXECAC
	SKIPE	.CPPSP##(P4)	;CORE SWEEP IN PROGRESS?
	JRST	SWTRP		;YES, JUST REMEMBER LOCATION OF FAILURE AND DISMISS
	CONSZ	APR,LP.NXM	;IS THIS REALLY A NON-EX-MEM?
	JRST	PTNXM		;YES, JUST IGNORE THE TRAP
	MOVEI	T1,@.CPEBR##(P4)	;NORMAL EBR
	TRZ	T1,LG.CSW	;TURN OFF CACHE LOAD BIT
	CONO	PAG,@T1		;TURN OFF CACHE LOAD AND CLEAR PAGE TABLE
	MOVE	T1,[EXP XC.UIO+TRYBAD]	;NEW LOCATION FOR PAGE TRAP
	MOVEM	T1,.UPMP+.LMPFN		;SAVE IN PAGE MAP
	AOS	.CPNPT##(P4)	;COUNT TOTAL NUMBER OF AR/ARX PARITY TRAPS
	MOVEM	16,.CPA17##-1(P4);SAVE 16
	MOVEI	16,.CPA00##(P4)	;GET BLT POINTER
	BLT	16,.CPA17##-2(P4) ;SAVE AC'S IN CPU DATA BLOCK
	SETZ	P2,		;CLEAR THE FLAG REGISTER
	MOVE	T1,.UPMP+.LMPFP	;GET THE PAGE FAIL PC
	MOVEM	T1,.CPPPC##(P4)	;SAVE THE PC FOR ERROR REPORTING
	MOVE	T2,.UPMP+.LMPFW	;GET THE PAGE FAIL WORD
	MOVEM	T2,.CPPFW##(P4)	;SAVE THE PAGE FAIL WORD FOR DAEMON
	LDB	T3,[POINT 5,T2,5]	;GET PAGE FAIL CODE INTO T3
	SUBI	T3,PF.ARP	;CONVERT TO INDEX INTO AC BLK 7
	DATAO	PAG,[LG.LAB+07B11]	;SET PREVIOUS CONTEXT AC'S TO 7
	PXCT	PX.MEM,[MOVE T3,(T3)]	;PICK UP BAD DATA WORD
	EXECAC			;SET PREVIOUS AC'S BACK
	PUSH	P,P1
	PUSH	P,P2		;SAVE P1 &P2
	MOVEM	T3,.CPTBD##(P4)	;SAVE BAD DATA FOR DAEMON
	RDERA	.CPAER##(P4)	;SAVE THE ERA FOR ERROR REPORTING
	CONI	APR,.CPPEF##(P4)	;AND THE APR STATUS
	PUSH	P,T2		;SAVE T2 TEMPORARILY
	MOVE	T1,[100000,,0]	;SBDIAG FUNCTION 0
	SBDIAG	T1		;DO IT
	DMOVEM	T1,.CPPSB##(P4)	;SAVE THESE 2 VALUES ALSO FOR ERROR REPORTING
	MOVE	T1,[100000,,1]	;NOW DO SBDIAG FUNCTION 1
	SBDIAG	T1
	DMOVEM	T1,.CPPSB##+2(P4)	;SAVE THE RESULTS OF FUNCTION  1
	MOVSI	T1,DMACLR		;NOW CLEAR THE ERROR BITS INT THE DMA
	SBDIAG	T1			;WITH FUNCTION 0
	SETOM	.CPTSD##(P4)		;TELL INTERRUPT WE HAVE SAVED THE DATA
	MOVE	T1,.CPAPI##(P4)		;GET APR PIA
	TRO	T1,LP.CSF!LP.SBE!LP.PAR	;CLEAR THE ERROR BITS
	CONO	APR,(T1)	;
	POP	P,T2		;RESTORE T2
	MOVE	T4,[PXCT PX.MEM,[MAP P1,(T2)]]	;SET UP XCT OF MAP IN T4
	MOVSI	T3,(PF.USR)	;GET BIT WHICH SAYS REF WAS USER/EXEC
	TDNN	T3,T2		;IF REF WAS EXEC,
	TLZ	T4,(PX.MEM,)	;TURN OFF PXCT BITS, SO WE JUST DO XCT OF MAP
	XCT	T4		;DO A MAP TO TURN PF WORD INTO PHYS ADDR IN P1
	MOVEM	P1,.CPPBA##(P4)	;SAVE BAD PHYSICAL ADDR FOR DAEMON
	HRRZS	P1		;GET RID OF LEFT HALF STUFF
	ROT	P1,W2PLSH	;TURN RH OF P1 INTO PAGE NUMBER OF BAD LOC
	MOVE	T3,.CPTOS##(P4)	;GET PAGE NUMBER OF EPMP FOR THIS CPU
	MOVE	T4,.MERPL(T3)	;PICK UP CONTENTS OF TEMP MAP SLOT WE WILL USE
	TRO	P1,PM.ACC+PM.WRT	;TURN ON ACCESS ALLOWED AND WRITE
	DPB	P1,[POINT 18,.MERPL(T3),17] ;PUT MAP ENTRY INTO APPROPRIATE SLOT
	LSH	P1,-^D27	;TURN P1 INTO WORD NUMBER WITHIN PAGE
	ADDI	P1,.ERPIL	;AND GET PAGE NUMBER CORRESPONDING TO MAP SLOT
	
	CONSO	PAG,LG.CSL	;IS THE CACHE ON?
	 JRST	PRTP1		;NO
	TRO	P2,PFCPF3	;REMEMBER ITS IN USE
	SWPVA			;SWEEP CACHE-VALIDATE CORE
				;BUT LEAVE CACHE VALID.
	CONSZ	APR,LP.CSB		;SWEEP BUSY?
	 JRST	.-1		;WAIT FOR DONE
	CONSZ	APR,LP.SBE!LP.PAR	;ERROR DURING SWEEP?
	 TRO	P2,PFCPF4	;REMEMBER THIS PROBLEM
	MOVEI	T1,@.CPEBR##(P4)	;NORMAL EBR
	TRZ	T1,LG.CSW!LG.CSL	;TURN OFF BOTH LOOK & LOAD
	CONO	PAG,@T1		;DISABLE CACHE
	MOVE	T1,.CPAPI##(P4)		;GET APR PIA
	TRO	T1,LP.CSF!LP.SBE!LP.PAR	;CLEAR THE ERROR BITS
	CONO	APR,(T1)	;
	MOVSI	T1,DMACLR		;NOW CLEAR THE ERROR BITS INT THE DMA
	SBDIAG	T1			;WITH FUNCTION 0


;HERE START RETRIES-FIRST WITH CACHE OFF
PRTP1:	PUSHJ	P,PRTRY	;REFERENCE LOCATION WITHOUT CACHE
	 JRST	PRHMF		;RETRIES FAILED! HARD MEMORY FAILURE
;HERE WE KNOW WE CAN RECOVER THE USER
	MOVEM	T1,.CPTGD##(P4)	;SAVE THE GOOD DATA FOR ERROR REPORTING
	AOS	.CPSPT##(P4)	;UPDATE COUNTER OFSOFT AR/ARX PARITY ERRORS
	LSH	T3,^D9		;MOVE RETRY COUNT TO BITS 18-27
	HRRZ	T3,T3		;CLEAR LEFT HALF
	IORM	T3,.CPPTR##(P4)	;STORE RETRY COUNT
;HERE RETRY WITH CACHE ON IF IT WAS IN USE
	TDNN	P2,PFCPF3	;WAS CACHE ON WHEN WE STARTED?
	 JRST	PRTP3		;NO
;HERE RESTORE GOOD DATA TO THE CACHE LOCATION
	PUSH	P,T1		;SAVE SOME LOCATIONS FOR OUT USE
	PUSH	P,T2
	PUSH	P,T3
	PUSH	P,T4
	PUSH	P,P2
	PUSH	P,P3
	PUSH	P,P4
	MOVEI	P2,@.CPEBR(P4)	;GET NORMAL EBR
	MOVE	P3,P2		;2 COPIES OF NORMA EBR
	TRZ	P3,LG.CSW!LG.CSL	;TURN OFF AFTER WRITING
	MOVE	P4,T1		;SETUP GOOD DATA TO WRITE BACK TO CACHE
	MOVE	T1,[CONO PAG,@P2]	;TURN ON CACHE LOOK & LOAD
	MOVE	T2,[MOVEM P4,0(P1)]	;REWRITE GOOD DATA TO CACHE
	MOVE	T3,[CONO PAG,@P3]	;TURN OFF CACHE LOAD
	MOVE	T4,[JRST PRTP2]	;GET BACK TO THIS CODE
;EXECUTING THE ABOVE 4 INSTRUCTIONS FROM THE AC'S ENSURES THE
;FOLLOWING INSTRUCTIONS DON'T ALSO GET INTO A POSSIBLY BAD CACHE.
	JRST	T1		;EXECUTE THE INSTRUCTIONS IN THE AC'S

PRTP2:	POP	P,P4
	POP	P,P3		;RESTORE THE LOCATIONS WE JUST USED
	POP	P,P2
	POP	P,T4
	POP	P,T3
	POP	P,T2
	POP	P,T1
	MOVEI	T1,@.CPEBR##(P4)	;GET NORMAL EBR
	TRZ	T1,LG.CSW		;TURN OFF LOAD BIT
	CONO	PAG,(T1)		;TURNLOOK BACK ON
;NOW RETRY REFERENCE WITH CACHE ON, CACHE STILL HAS LOOK BIT ON BUT LOAD OFF
	PUSHJ	P,PRTRY	;REFERENCE LOCATION
	 JRST	PRHCF		;RETRIES FAILED! HARD CACHE FAILURE
	SWPIA			;INVALIDATE CACHE BUT DON'T TOUCH CORE
	CONSZ	APR,LP.CSB
	JRST	.-1		;WAIT FOR "NOT BUSY"
	CONO	PAG,@.CPEBR##(P4)			;TURN ON CACHE LOOK & LOAD

;HERE IF RETRIES WERE SUCCESFUL, LOG SOFT ERROR AND DISMISS
PRTP3:	SETZM	.CPTSD##(P4)	;CLEAR THE FLAG NOW BECAUSE AN APR
				;INTERRUPT MAY OCCUR WITHOUT THE TRAP
				;IE, MEMORY WRITE CYCLE, AND THE INTERRUPT
				;ROUTINE WOULDN'T SAVE THE DATA AND
				;WOULD ALSO THINK THE ERROR WAS REALLY A USER FAILURE!!!
	HRLM	P2,.CPPTR##(P4)	;SAVE STATUS FLAGS IN LH OF RETRY WORD FOR ERROR REPORTING
	IORM	T3,.CPPTR##(P4)	;SAVE CACHE RETRY COUNT FOR ERROR REPORTING
	MOVE	T3,.CPTOS##(P4)		;GET .EPMP FOR THIS CPU
	MOVEM	T4,.MERPL(T3)	;RESTORE TEMP MAP SLOT IN THIS EPMP
	MOVSI	T1,(XC.USR)	;PAGE FAULT IN EXEC?
	TDNE	T1,.CPPPC##(P4)	;IF NOT,
	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##]	;SET UP A PDL
	MOVEI	T1,[ASCIZ"% RECOVERABLE AR/ARX PARITY ERROR"]
	PUSHJ	P,PRREP	;TELL OPR WHAT HAS HAPPENED
	MOVE	T1,.CPAPI##(P4)		;GET PIAS FOR THIS CPU
	TRO	T1,LP.CSF!LP.SBE!LP.PAR	;CLEAR APR ERRORS
	CONO	APR,(T1)
	MOVSI	T1,DMACLR		;NOW CLEAR THE ERROR BITS INT THE DMA
	SBDIAG	T1			;WITH FUNCTION 0
	CONO	PI,PION##	;RESTORE PI SYSTEM
	MOVEI	T1,.ERKDT	;CODE FOR DAEMON
	HRL	T1,P4		;THIS CPU'S CDB ADDRESS
	PUSHJ	P,DAEEIM##	;PUT THE ENTRY IN THE QUEUE
	PUSHJ	P,CALSW	;SET UP AND CALL SWEEPER AT PI7 LEVEL
	POP	P,P2
	POP	P,P1	;RESTORE P1&P2 JUST IN CASE
	MOVSI	16,.CPA00##(P4)	;BLT PNTR TO RESTORE AC'S
	BLT	16,15		;RESTORE AC'S
	MOVE	16,.CPA17##-1(P4)	;AC 16 ALSO
				;NOTE THAT MOVSI  T1, BLT  T1, SHOULD
				;NOT BE USED EVEN THOUGH PI IS OFF
				;BECAUSE OF PI0.
	JRST	PTPR2		;AND RETURN



;ROUTINE TO SET UP AND REQUEST A CORE SWEEP AT PI7 LEVEL
;CALL;  PUSHJ P,CALSW
;RETURNS +1 ALWAYS

CALSW:	EXCH	J,.CPJOB##(P4)	;GET CURRENT JOB FOR SWEEP
	EXCH	R,.CPADR##(P4)	;GET R SETUP
	HLLZ	T1,.CPMPS##(P4)	;GET SWEEP REQUEST BITS
	TRO	T1,UE.PEF	;SAY A PRITY ERROR OCCURED
	IORM	T1,.CPAEF##(P4)	;SET FLAGS FOR PI 7 SWEEP
	MOVEM	T1,.JBCNI##(R)	;STORE ERROR FLAGS
	MOVE	T1,.CPPPC##(P4)		;GET STORED PC
	MOVEM	T1,.CPMPP##(P4)		;STORE FOR PI7
	MOVEM	T1,.CPLPP##(P4)		;STORE FOR "LAST PC"
	MOVEM	T1,.CPAPC##(P4)		;STORE FOR SWEEP ERROR REPORTING
	MOVEM	T1,JOBTPC##(R)		;STORE FOR USER
	IFN	FTMS,<
	PUSHJ	P,CP1APE##		;MAKE SURE JOB WILL RUN ONCPU0
					;SO ERROR MSG WILL PRINT
	>;END IFN FTMS
	EXCH	R,.CPADR##(P4)		;RESTORE R
	EXCH	J,.CPJOB##(P4)	;RESTORE J
	SETOM	.CPPSP##(P4)		;SET SWEEPING FLAG NOW TO CLOSE DOWN
					;WINDOW WHICH ALLOWS RECURSIVE LOOPING
	SETOM	.CPSCF##(P4)		;FORCE NOSCHED
	MOVE	T1,[EXP XC.UIO+SEILM]	;GET ORIGINAL PAGE FAIL TRAP ADDR
	MOVEM	T1,.UPMP+.LMPFN		;AND RESTORE IT IN UPMP
	SETOM	.CPCKF##(P4)		;SET FLAG FOR PI7 INTERRUPT
	MOVEI	T1,PARDLY		;SET A STALL COUNTER
	CONO	PI,XI.RQC##	;CALL SWEEPER
	SOJGE	T1,.		;WAIT FOR THE INTERRUPT
	POPJ	P,0		;RETURN TO CALLER
	;LOCAL RETRY ROUTINE
	;RETURNS +1 IF RETRIES FAIL
	;RETRUNS +2 IF ANY RETRY WINS
	;   T1/GOOD DATA
	;   T3/RETRY WHICH SUCCEEDED (FIRST =1)

PRTRY:	MOVEI	T3,1		;INIT RETRY COUNTER
PRTY1:	TRO	P2,PFCPF0	;NOTE THIS IS TEST REFERENCE
	MOVE	T1,0(P1)	;TRY THE REFERENCE
	TRZ	P2,PFCPF0	;CLEAR THE REFERENCE FLAG
	TRZN	P2,PFCPF2	;ERROR DURING REFERENCE?	
	 PJRST	CPOPJ1		;NO-GIVE GOOD RETURN
	CAIGE	T3,TRPTRY	;RETRY COUNT EXHAUSTED?
	AOJA	T3,PRTY1	;NO-TRY AGAIN
	POPJ	P,0		;YES-GIVE ERROR RETURN

;HERE ON TRAPS OCCURING DURING REVOVERY ATTEMPTS
TRYBAD:	TRNN	P2,PFCPF0	;BECAUSE OF TEST REFERENCE?
	 STOPCD	(.,HALT,UPF)	;++UNEXPECTED PAGE FAIL
	LDB	T1,[POINT 5,.UPMP+.LMPFW,5]	;GET PAGE FAIL CODE
	CAIE	T1,PF.ARP	;AR PARITY ERROR?
	 STOPCD	(.,HALT,WPT)	;++WRONG PARITY TRAP
	TRO	P2,PFCPF2	;YES-INDICADE ERROR 
	AOS	.UPMP+.LMPFP	;RETURN TO TEST REFERENCE + 1
	JRSTF	@.UPMP+.LMPFP	;GO BACK FOR ANOTHER TRY

;CACHE HAS LOOK ON BUT NOT LOAD


;HERE IF CACHE RETRIES FAIL  WE MAY TURN OFF CACHE NOW

PRHCF:	SWPIA			;INVALIDATE CACHE BUT DON'T TOUCH CORE
	CONSZ	APR,LP.CSB
	JRST	.-1		;WAIT FOR "NOT BUSY"
	MOVEI	T1,@.CPEBR##(P4)	;INITIAL EBR
	TRZ	T1,LG.CSL	;TURN OFF THE LOOK BIT FOR SAFETY
	CONO	PAG,@T1	;MAY LEAVE IT OFF
	TRO	P2,PFCPF2	;SET THE CACHE FAILED BIT FOR ERROR REPORTING
	AOS	T1,.CPCEC##(P4)	;COUNT THIS FAILURE
	CAIGE	T1,CCHEMX	;EXCEEDED ALLOWABLE?
	 JRST	PRHC1		;NO-TURN IT BACK ON
	HRRZ	U,CTYLDB##	;TEL HIM WHERE TO PUT MESSAGE
	PUSHJ	P,INLMES
ASCIZ"
% 3 hard failures in cache - cache will be deselected"
	MOVE	T1,.CPEBR##(P4)	;GET NORMAL EBR
	TRZ	T1,LG.CSL!LG.CSW	;TURN OFF LOOK & LOAD BITS
	MOVEM	T1,.CPEBR##(P4)		;BITS NOW CLEARED SO OTHERS
					;CAN'T TURN IT ON BY ACCIDENT
;FIRST MESSAGE IS SENT TO OPR TO TELL HIM WE ARE ATTEMPTING TO TURN
;IT OFF, THE STOPCD WILL INDICATE IT IS OFF 
	STOPCD	(.+1,DEBUG,CTO)	;++CACHE TURNED OFF
				;STOPCD IS ALSO USED SO THAT ERROR
				;REPORTING GETS THE MESSAGE
	JRST	PRTP3		;NOW CLEAN UP AND RETURN TO USER

;HERE TO TURN THE CACHE BACK ON
PRHC1:	CONO	PAG,@.CPEBR##(P4)	;TURN IT ON
	JRST	PRTP3		;AND RETURN TO USER

;HERE WHEN RETRIES FROM MEMORY FAIL-COULD BE EITHER FROM MEMORY OR CACHE
;HOWEVER WE MUST NOW CRASH THE USER
; IF PFCPF4 IS SET, FAILURE 
;ORIGINATED IN CACHE

PRHMF:	SETZM	.CPTGD##(P4)	;CLEAR THE GOOD DATE FOR ERROR REPORTING SINCE WE NEVER GOT ANY
	MOVEI	T1,[ASCIZ "%NON-RECOVERABLE AR/ARX PARITY ERROR"]
	PUSHJ	P,PRREP	;CALL AR/ARX TYPEOUT ROUTINE
	AOS	.CPHPT##(P4)	;HARD (AR/ARX) PARITY TRAP COUNT
	MOVSI	T1,(XC.USR)	;TEST IF WE WERE IN USER MODE 
	TDNN	T1,.CPPPC##(P4)	;AT THE TIME OF THE TRAP
	STOPCD	.,HALT,PTH,	;PARITY TRAP HALT
	SWPIA			;INVALIDATE CACHE BUT DON'T TOUCH CORE
	CONSZ	APR,LP.CSB	;WAIT FOR
	JRST	.-1		;BUSY TO GO AWAY
	MOVE	T1,.CPAPI##(P4)	;GET APR PIA
	TRO	T1,LP.CSF!LP.SBE!LP.PAR	;CLEAR ERROR BITS
	CONO	APR,(T1)		;DO THE REAL CLEARING
	MOVSI	T1,DMACLR		;NOW CLEAR THE ERROR BITS INT THE DMA
	SBDIAG	T1			;WITH FUNCTION 0
;MONITOR IS OK, CRASH USER
	TRO	P2,PFCPF1	;SAY HARD ERROR FOR ERROR REPORTING
	HRLM	P2,.CPPTR##(P4)	;SAVE FLAGS
	LSH	T3,^D9		;MOVE RETRY COUNT TO BITS 18-26
	HRRZ	T3,T3		;CLEAR LEFT HALF
	IORM	T3,.CPPTR##(P4)	;SAVE RETRY COUNT FOR ERROR REPORTING
	MOVE	T1,[EXP XC.UIO+SEILM]	;GET ORIGINAL PAGE FAIL TRAP ADDR
	MOVEM	T1,.UPMP+.LMPFN		;AND RESTORE IT IN UPMP
	MOVEI	T1,.ERKDT	;SETUP ERROR CODE
	HRL	T1,P4		;AND CDB ADDRESS
	PUSHJ	P,DAEEIM##	;CALL DAEMON TO LOG ERROR
	CONO	PI,PIOFF##	;SINCE HE LEFT IT ON
	MOVE	T1,.CPAPI##(P4)		;GET APR PIA
	TRO	T1,LP.SSF!LP.SBE!LP.PAR	;SET THE ERROR BITS
	CONO	APR,(T1)	;
	MOVSI	T1,DMACLR		;NOW CLEAR THE ERROR BITS INT THE DMA
	SBDIAG	T1			;WITH FUNCTION 0
	POP	P,P2
	POP	P,P1		;RESTORE P1&P2
	CONO	PAG,@.CPEBR##(P4)	;TURN CACHE BACK ON
	MOVEI	T1,PARDLY		;SET STALL TIME
	CONO	PI,PION##	;RESTORE PI SYSTEM
	SOJG	T1,.		;AND WAIT FOR THE INTERRUPT TO SWEEP CORE AND KILL USER
	MOVE	J,.CPJOB(P4)	;GET THE OFFENDING JOB #
	JRST	ESTOP##		;AND STOP HIM, WITHOUT COMING BACK HERE.


;HERE ON TRAP DURING PARITY SWEEP - JUST FLAG THAT IT HAPPENED
SWTRP:	HRRZ	T1,.UPMP+.LMPFP	;GET PC OF TRAP
	CAIE	T1,MPI		;IF THIS IS DURING PARITY SWEEP, WE
				; HAD BETTER HAVE GOTTEN THE TRAP FROM
				; THE MPI INSTRUCTION
	STOPCD	(.,HALT,NPI)	;++NOT PARITY INSTRUCTION
;NOW SAVE BAD DATA AND SET NEW PAGE FAIL TRAP ADDRESS
	MOVE	T1,.UPMP+.LMPFP	;GET FLAGS & PC TO RETURN TO
	PUSH	P,P2	;SAVE P1&P2 FOR SWEEPER
	PUSH	P,T1		;SAVE THE PC WE MUST RETURN TO!!!
	PUSH	P,T2		;SAVE THE TEMP AC'S TO BE SAFE
	PUSH	P,T3
	PUSH	P,T4
	MOVE	T2,.UPMP+.LMPFW	;GET PAGE FAIL CODE
	LDB	T3,[POINT 5,T2,5]	;INTO T3
	SUBI	T3,PF.ARP		;CONVERT TO INDEX
	DATAO	PAG,[LG.LAB+07B11]	;SET PREVIOUS AC BLOCK TO 7
	PXCT	PX.MEM,[MOVE T3,(T3)]	;GET BAD DATA WORD FOR DAEMON
	EXECAC				;GO BACK TO OUR OWN AC'S
	MOVEM 	T3,.CPTBD##(P4)		;SAVE FOR SWEEP ROUTINE
	MOVE	T1,[EXP XC.UIO+TRYBAD]	;NEW LOCATION FOR TRAP ADDRESS
	MOVEM	T1,.UPMP+.LMPFN		;SAVE IN PAGE MAP
	PUSH	P,P1
;HERE DO RETRIES TO CORE, P1 ALREADY HOLDS ADDRESS TO REFERENCE
;FROM THE SWEEP INST
SWTP1:	PUSHJ	P,PRTRY		;TRY AGAIN 3 TIMES
	 JRST	SWTP2			;HARD FAILURE
;RETRIES WORKED, NOW CLEAR APR AND FAKE A SUCCESSFUL SWEEP INSTR.
	POP	P,P1		;GET P1 BACK FOR A LITTLE WHILE
	AOS	P1		;BUMP RIGHT HALF
	HRL	P1,P1		;AND LEFT HALF TO CORRECT THE BLT POINTER
	PUSH	P,P1		;THAT LITTLE WHILE FOR P1 HAS JUST EXPIRED!!
	SOS	.UPMP+.LMPFP		;-1 NOW SO AOS LATER HOLDS PC AT CURRENT MPI
					;AND THE BLT GETS "CONTINUED"
	MOVE	T1,.CPAPI##(P4)		;GET PIAS FOR THIS CPU
	TRO	T1,LP.CSF!LP.SBE!LP.PAR	;CLEAR APR ERRORS
	CONO	APR,(T1)
	SKIPA				;DON'T INDICATE AN ERROR TO SWEEPER
SWTP2:	SETOM	.CPPTH##(P4)	;INDICATE ERROR ON SWEEP INST
	POP	P,P1	;
	POP	P,T4		;RETURN THE TEMP AC'S
	POP	P,T3
	POP	P,T2
	POP	P,T1		;GET BACK THE PC TO RETURN TO
	POP	P,P2
	MOVEM	T1,.UPMP+.LMPFP	;AND STORE IT
	MOVE	T1,[EXP XC.UIO+SEILM]	;RESTORE ORIGINAL TRAP ADDRESS
	MOVEM	T1,.UPMP+.LMPFN	;INTO PAGE MAP
	AOS	.UPMP+.LMPFP	;IT'S OK, INCREMENT PC SO WE DON'T TRAP FOREVER
				;.CPPTH WILL TELL THE SWEEP SOMETHING
				; WENT WRONG
	JRST	PTPR1		;DISMISS BACK TO SWEEP ROUTINE


;ROUTINE TO PRINT A MESSAGE FOLLOWED BY "AT EXEC(USER) PC XXXXXX"
; MESSAGE FOLLOWS CALL TO THE ROUTINE, AS IN INLMES

PRREP:	PUSHJ	P,SAVE1##	;SAVE P1 TO REMEMBER ADDRESS OF MESSAGE
	MOVE	P1,T1		;SAVE
	PUSHJ	P,SVPPC##	;SWITCH TO SECONDARY PROTOCOL
	PUSH	P,COMTOA##	;SAVE COMMAND OUTPUT ADDRESS
	MOVEI	T2,CTYWAT##	;GET ONE THAT DOESN'T USE PI SYS
	MOVEM	T2,COMTOA##
	HRRZ	U,CTYLDB##	;GET CTY LDB IN U
	PUSHJ	P,CRLF##	;START WITH CRLF
	MOVE	T1,P1		;GET ADDRESS OF MESSAGE IN T1
	PUSHJ	P,CONMES##	;PRINT MESSAGE
	MOVE	T2,.CPPPC##(P4)	;GET SAVED PC
	PUSHJ	P,PCP##		;PRINT "AT EXEC/USER XXXXXX"
	PUSHJ	P,CRLF##	;END WITH A CRLF
	POP	P,COMTOA##	;RESTORE SCNSER ADDRESS
	POPJ	P,		;RETURN
;HERE ON PAGE TABLE PARITY TRAP (PF CODE 25)
PTPAR:	CONO	PI,PION##		;RESTORE PI SYSTEM
	CONO	PAG,@.CPEBR##(P4)	;CLEAR THE PAGE TABLE
	AOS	.CPPTP##(P4)		;COUNT A PAGE TABLE PARITY ERROR
	SKIPGE	T1,.CPPTF##(P4)		;PICK UP COUNT OF PAGE TABLE FAILURES
	MOVEI	T1,^D10			;NONE YET, INITIALIZE
	SOSG	T1			;COUNT DOWN
					;IF COUNT HASN'T EXPIRED,JUST RETRY
					; COUNTER IS RESET ON EVERY APR CLOCK
					; TICK- IF TOO MANY FAILURES IN
					; ONE TICK, WE HALT HERE
	STOPCD	.,HALT,PTP,		;PAGE TABLE PARITY
	MOVEM	T1,.CPPTF##(P4)		;REMEMBER COUNTER
	MOVE	T1,.UPMP+.LMPFP		;GET PAGE FAIL PC
	MOVEM	T1,.CPPPC##(P4)		;SAVE FOR PRINT ROUTINE
	MOVEI	T1,[ASCIZ "%PAGE TABLE PARITY ERROR"]
	PUSHJ	P,PRREP			;PRINT THE MESSAGE OUT
PTPR1:	MOVE	T1,.UPMP+.LMPFP		;GET PC
	JRST	PTRET			;RETURN TO TRAPPER
PTPR2:	MOVE	T1,.CPPPC##(P4)		;GET ORIGINAL PAGE FAIL OLD PC
	MOVEM	T1,.UPMP+.LMPFP		;WHICH IS CORRECT ADDRESS TO DISMISS TO
PTRET:	MOVE	P4,.UPMP+.UPMUO		;RESTORE P4
	TLNN	T1,(XC.USR)		;WERE WE IN EXEC MODE?
	SKIPA	T1,.UPMP+.UPMUP		;RESTORE T1
	USERAC				;NO, RESTORE US BACK TO USERS AC'S
					; CLOCK LEVEL WILL LOG SOFT ERROR
	JRSTF	@.UPMP+.LMPFP		;RESTORE FLAGS AND RETURN
					; IF WE EVER GET THERE


;HERE ON PRITY ERROR CAUSED BY NXM
PTNXM:	CONO	PI,PION##		;RESTORE PI SYSTEM
	JRST	PTPR1			;AND IGNORE THE TRAP
SEILMA:	CONO	PI,PION##		;RESTORE THE PI SYSTEM
	MOVE	T1,.UPMP+.UPMUP	;GET T1 BACK
	EXCH	T1,.UPMP+.LMPFP	;SAVE T1 AND GET THE PC
	MOVEM	T1,.CPAPC##(P4)	;STORE IT AS POTENTIAL ERROR PC
	MOVEM	T1,.UPMP+.UPMUP	;STORE WHERE KI WOULD PUT IT
	EXCH	T2,.UPMP+.LMPFW	;GET THE USER PAGE FAIL WORD
	MOVEM	T2,.CPPFW##(P4)	;SAVE PAGE FAULT WORD FOR CRASH
	DPB	T2,[POINT 18,T2,32] ;SHIFT VIRTUAL ADDRESS OVER 3 PLACES
	ROT	T2,6		;PLACE PAGE FAIL CODE AND VIRTUAL ADDRESS
				;WHERE IT WAS ON KI10
	TRZE	T2,40		;USER BIT ON?
	TLO	T2,(1B8)	;YES, SET IT WHERE KI10 USER BIT WAS
				;WE NOW HAVE KI10 STYLE PAGE FAIL WORD.
	AND	T2,[1777,,37]	;CLEAR UNUSED BITS
	TLNE	T2,(1B8)	;USER REF?
	TRNN	T2,10		;YES, ACCESS ALLOWED OFF?
	JRST	SEILMB		;NOT USER REF OR ACCESS ALLOWED OFF
	TRNN	T2,4		;USER REF, ACCESS ALLOWED ON. WRITE OFF?
	TRO	T2,1		;YES, DEDUCE THAT HE TRIED TO WRITE
SEILMB:	TLNE	T1,(XC.USR)	;PAGE FAULT IN EXEC MODE?
	JRST	SEILM0		;NO, PROCEED
	ANDI	T2,37		;CLEAR ALL BUT THE PAGE FAIL CODE
	CAIE	T2,PF.ABF	;WAS THE PAGE FAULT AN ADDRESS BREAK?
	STOPCD	.+1,JOB,IME,	;++ILL MEM REF FROM EXEC
	JRST	SEILM1		;YES, REMEMBER IT AND GO AWAY


SEILM0:	EXECAC
	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;SETUP A PUSH DOWN LIST
	MOVE	T3,T2		;FAULT WAS IN USER MODE, SAVE PFC FOR
				; POSSIBLE CALL TO USRFLT
	ANDI	T2,37		;CLEAR ALL BUT THE PAGE FAIL CODE
	CAIN	T2,PF.ABF	;ADDRESS BREAK?
	JRST	SEILM1		;YES, GO PROCESS
	MOVE	T4,.JDAT+JOBENB## ;GET APR ENABLE BITS
	TRNE	T4,AP.ILM	;IS USER ENABLED?
	JRST	SUILM		;YES--DO SUILM INSTEAD
IFN FTVM,<
	MOVE	T4,T1		;PC WORD INTO T4 FOR USRFLT
>
	HRRI	T1,AP.ILM	;ILLEGAL MEMORY REFERENCE
	CAIN	T2,PF.PRV	;WAS IT A PROPRIETARY VIOLATION?
IFE FTVM,<
	TRO	T1,AP.PPV	;YES, INDICATE THAT
>
IFN FTVM,<
	TROA	T1,AP.PPV	;INDICATE PROPRIETARY VIOLATION (AVOID CALL TO USRFLT)
	PUSHJ	P,USRFLT##	;SEE IF PAGE FAULT FOR A VM USER
				; WILL NOT RETURN IF SO (DISPATCH TO USER)
	MOVEM	T4,.CPAPC##(P4)	;STORE ERROR PC
>
	MOVE	T2,.UPMP+.LMPFW	;RESTORE T2
	JRST	SEPDL1		;GO SAY "ILL. MEM. REF."
SEILM1:	TLO	T1,(IC.AFI)	;INHIBIT ADDRESS BREAK WHEN INSTRUCTION IS
				; EXECUTED AGAIN
	EXCH	J,.CPJOB##(P4)	;GET JOB
	PUSH	P,W		;SAVE W IN CASE IN EXEC MODE
	PUSHJ	P,FNDPDS##	;FIND THE PDB
	LDB	T2,[POINT 9,.PDABS##(W),17]  ;GET THE PROCEED COUNT
	SOSL	T2		;DECREMENT
	DPB	T2,[POINT 9,.PDABS##(W),17]  ;STORE IT BACK IF POSITIVE
	POP	P,W		;RESTORE W
	JUMPG	T2,SEILM3	;DON'T BREAK IF PROCEED COUNT .GT. 0
	MOVE	T2,JBTSTS##(J)	;IS THIS A JACCT
	TLNE	T2,JACCT	;JOB
	JRST	SEILM3		;YES-IGNORE BREAK
	EXCH	J,.CPJOB##(P4)	;UNDO LAST EXCH
	TLNN	T1,(XC.USR)	;PC IN USER MODE?
	JRST	SEILM2		;NO, REMEMBER BREAK AND GO AWAY
	MOVE	R,.CPADR##(P4)	;SETUP R
	MOVEM	T1,.CPAPC##(P4)	;STORE THE PC WITH IFA ON
IFN FTPI,<
	MOVE	J,.CPJOB##(P4)	;JOB NUMBER FOR PSISER
	SIGNAL	C$ADRB		;SIGNAL THAT AN ADDRESS BREAK HAS OCCURED
	  JRST	[MOVE T1,.CPAPC##(P4) ;PC TO T1
		 JRST SEILM5]	;INTERRUPT TO THE USER
>	;END FTPI
	PUSH	P,.CPAPC##(P4)	;SAVE PC ON STACK
IFN FTMS,<
	PUSHJ	P,ONCPU0##	;MUST BE ON CPU0 TO REPORT THE BREAK
>
	PUSHJ	P,TTYFUW##	;FIND THE USER'S TTY
	PUSHJ	P,INLMES##	;REPORT THE ADDRESS BREAK
	ASCIZ	/
%Address break at user PC /
	HRRZ	T1,(P)		;GET THE USER'S PC
	PUSHJ	P,OCTPNT##	;TELL HIM WHERE THE BREAK OCCURED
IFN FTPI,<
	PUSHJ	P,PSIERR##	;PENDING INTERRUPT?
	  JFCL
	  PJRST	ERRGOU##	;YES, GIVE IT OT THE USER
>
	PJRST	HOLDW##		;STOP THE JOB IN A CONTINUABLE STATE
SEILM2:	MOVEI	T2,JS.ASA	;AC'S ARE IN THE SHADOW AREA BIT
	EXCH	J,.CPJOB##(P4)	;JOB NUMBER
	TDNE	T2,JBTSTS##(J)	;SAVE/GET IN PROGRESS?
	JRST	SEILM3		;YES, DON'T BOTHER THE USER WITH BREAKS ON THAT
	MOVEI	T2,JS.ABP	;ADDRESS BREAK HAPPENED DURING UUO PROCESSING BIT
	IORM	T2,JBTST2##(J)	;REMEMBER THAT THE BREAK HAPPENED
SEILM3:	EXCH	J,.CPJOB##(P4)	;RESTORE J
SEILM4:	TLNE	T1,(XC.USR)	;BREAK OUT OF USER MODE?
	JRST	SEILM5		;YES
	EXCH	T1,.UPMP+.LMPFP	; AND T1
	MOVE	T2,.UPMP+.LMPFW	; AND T2
	MOVE	P4,.UPMP+.UPMUO	; AND P4
	JRSTF	@.UPMP+.LMPFP	;GO AWAY AND TELL THE USER ABOUT THE BREAK
				; AT UUO EXIT
SEILM5:	MOVEM	T1,.UPMP+.LMPFP ;SAVE PC
	USERAC			;USER'S AC BLOCK
	JRSTF	@.UPMP+.LMPFP
EXCABK::ANDCAM	T1,JBTST2##(J)	;CLEAR BREAK HAPPENED IN EXEC MODE BIT
	PUSHJ	P,FNDPDS##	;FIND THIS JOB'S PDB
	MOVSI	T1,(OC.BCM)	;BREAK ON MUUO REFERENCES BIT
	TDNN	T1,.PDABS##(W)	;IS THE USER INTERESTED?
	POPJ	P,		;NO, GO AWAY
IFN FTPI,<
	PUSHJ	P,CPUCDB##	;SETUP P4 TO POINT TO THE CURRENT CPU'S CDB
	MOVE	T2,JOBPD1##(R)	;GET UUO PC
	MOVEM	T2,.CPAPC##(P4)	;STORE IT WHERE PSISER EXPECTS IT
	SIGNAL	C$ADRB		;SIGNAL THAT AN ADDRESS BREAK OCCURED
	  POPJ	P,		;USER IS ENABLED, UUO EXIT WILL INTERRUPT TO HIM
>
IFN FTMS,<
	PUSHJ	P,ONCPU0##	;MUST BE ON CPU0 TO WRITE A MESSAGE
>
	PUSHJ	P,TTYFUW##	;FIND THE USER'S TTY
	PUSHJ	P,INLMES##	;REPORT THE ADDRESS BREAK
	ASCIZ	/
%Address break at exec PC /
	HRRZ	T1,.UPMP+.UPMUP	;GET THE PC WHERE THE LAST BREAK OCCURED
	PUSHJ	P,OCTPNT##	;TELL HIM THAT
	MOVEI	T1,[ASCIZ/; UUO/]
	PUSHJ	P,CONMES##
	MOVE	T2,JOBPD1##(R)	;GET THE UUO PC
	PUSHJ	P,PCP##		;REPORT IT SO HE WILL KNOW WHAT UUO BROKE
IFN FTPI,<
	PUSHJ	P,PSIERR##	;PENDING INTERRUPT?
	  JFCL
	  POPJ	P,		;YES
>
	POP	P,(P)		;POP OFF THE PUSHJ TO EXCABK
	PJRST	HOLDW##		;AND STOP THE JOB IN A CONTINUABLE STATE
;HERE FROM SEILM IF PAGE FAULT IS IN USER MODE AND APRENB DONE
; T1=USER PC AND T3=PAGE FAULT WORD
SUILM:	MOVE	R,.CPADR##(P4)	;GET THE ADDRESS OF THE USER'S JOB DATA AREA
IFN FTVM,<
	MOVE	T4,T1		;MOVE THE PC TO T4 FOR USRFLT
	PUSHJ	P,USRFLT##	;SEE IF PAGE FAULT FOR VM USER
				; WILL NOT RETURN IF SO (DISPATCH TO PFH)
>
	TLZ	T1,3637		;CLEAR NON-EXISTANT KA-10 BITS FOR COMPATABILITY
	MOVEM	T1,JOBTPC##(R)	;SAVE ERROR PC FOR USER
	HRRI	T1,AP.ILM	;SET ILM BIT FOR USER
	JRST	SAROV3		;FINISH UP
SUPDLO:	EXECAC
	MOVEI	P4,.C0CDB##	;ASSUME ON CPU0
IFN FTMS,<
	SKPCPU	(0)		;ARE WE?
	MOVEI	P4,.C1CDB##	;NO, ON CPU1
>
	EXCH	R,.CPADR##(P4)	;GET ADDRESS OF USER'S JOB DATA AREA
	MOVEM	T1,.UPMP+.UPMUO	;SAVE A TEMPORARY
	MOVE	T1,.UPMP+.UPMUP	;GET ERROR PC
	TLZ	T1,3637
	MOVEM	T1,JOBTPC##(R)	;SAVE FOR USER TO LOOK AT
	HRRI	T1,AP.POV	;SET POV BIT FOR USER
	JRST	SAROV3		;FINISH UP
;ROUTINE TO SET HARDWARE AND SOFTWARE RELOCATION INFORMATION FOR CURRENT USER
;CALLING SEQUENCE:
;	PUSHJ	P,SETREL
;	...	RETURN HERE
;J = CURRENT JOB NUMBER
;R = PROTECTION,,RELOCATION FOR THE LOW SEGMENT

SETRLH::MOVE	J,.C0JOB##	;J=CURRENT JOB NUMBER
	MOVEI	T1,0
	DPB	T1,JBYHSS##	;FORCE MAP TO BE REDONE
SETREL::PUSH	P,P4		;SAVE P4
	MOVEI	P4,.C0CDB##	;SETUP P4 TO POINT TO CPU0 CDB
	SKIPA	J,.C0JOB##	;J = CURRENT JOB NUMBER
SETRL1::PUSH	P,P4		;SAVE P4
	MOVE	R,JBTADR##(J)	;R = XWD PROTECTION,,EXEC VIRTUAL ADDRESS
				; OF THE FIRST PAGE OF THE LOW SEGMENT
	MOVEM	R,.CPADR##(P4)	;SET .CPADR FOR QUICK ACCESS AT APR LEVEL
	HLRZM	R,.CPREL##(P4)	;SET .CPREL FOR ADDRESS CHECKING
IFN FTTRPSET,<
	SKIPE	.CPSTS##(P4)	;HAS TIME-SHARING BEEN STOPPED BY A TRPSET UUO?
	JRST	SETRLZ		;NO, DON'T CHANGE THE UBR
>
	SKIPE	J		;NULL JOB ALWAYS HAS A UPMP
	JUMPE	R,SETRLZ	;THERE IS NO UPMP IF THE JOB HAS NO CORE
	PUSHJ	P,STEUB		;NO, SET THE USER BASE REGISTER
	jumpe	r,setrlz	;done if null job
	LDB	T1,JBYLSS##	;GET THE PREVIOUS SIZE OF THE LOW SEGMENT
	LDB	T2,[POINT 9,R,8];GET THE CURRENT SIZE
	CAIE	T1,(T2)		;IS IT THE SAME SIZE AS IT WAS THE LAST
				; TIME THIS JOB WAS RUN?
	PUSHJ	P,MAPLOW	;NO, REDO THE MAP
IFE FTVM,<
	HLRZM	R,JOBREL##(R)	;SET THE SIZE OF THE LOW SEGMENT FOR THE USER
>
IFN FTVM,<
	SKIPN	T1,.UPMP+.UPREL	;HOLEY PROGRAM?
	HLR	T1,R
	HRRZM	T1,JOBREL##(R)	;STORE HIGHEST CORE-UUO ADDRESS IN JOBREL
>
IFN FT2REL,<
	SKIPL	T1,JBTSGN##(J)	;JOB HAVE A REAL HIGH SEGMENT?
	SKIPA	T1,JBTADR##(T1)	;YES
	HRLZS	T1		;SIZE OF SPY SEGMENT OR ZERO IF NOT SPY SEGMENT
	LDB	T2,[POINT 9,T1,8];CURRENT SIZE -1 OF THE HIGH SEGMENT
	SKIPE	T1		;IS THERE A SPY OR HIGH SEGEMNT?
	ADDI	T2,1		;YES, ITS ACTUALLY ONE PAGE BIGGER
	LDB	T1,JBYHSS##
	MOVSI	T3,REDOMP	;FORCING THE MAP TO BE REDONE?
	TDNN	T3,JBTSGN##(J)
	CAIE	T1,(T2)		;HAS THE HIGH SEGMENT SIZE CHANGED SINCE THE
				; LAST TIME THIS JOB WAS RUN?
	PUSHJ	P,MAPHGH	;YES, REDO THE HIGH SEGMENT PART OF THE MAP
	MOVSI	T1,REDOMP	;INDICATE MAP HAS BEEN REDONE NOW
	ANDCAM	T1,JBTSGN##(J)
>
SETRLZ:
IFN FTSET,<
	PUSHJ	P,FDNJP		;FIND THE NULL JOB'S PDB
	MOVE	T3,T1		;SAVE THE ADDRESS OF THE NULL JOB'S PDB
	PUSHJ	P,FNDPDS	;FIND THE CURRENT JOB'S PDB
>
	HRRZ	T1,JBTUPM##(J)	;PAGE NUMBER OF THE CURRENT JOB'S UPMP
	JUMPE	T1,SETRL2	;DON'T CHANGE ANYTHING IF THERE ISN'T ONE
	HRLI	T1,(LG.LUB)	;SET THE LOAD BIT
IFN FTRTTRP,<
	MOVEM	T1,.CPDTO##(P4)	;SAVE FOR RTTRP INTERRUPT LEVEL USE
>
IFN FTSET,<
	.SKIPE	T2,.PDABS##(W)	;DOES THE USER HAVE ADDRESS BREAK SETTINGS?
	TLNN	T2,(OC.ABE)	;YES, IS HE ENABLED FOR BREAKS
	MOVE	T2,[EXP OC.FEP+CURJOB##] ;NO, DISPLAY JOB NUMBERS
>
	DATAO	PAG,T1		;SETUP THE UBR
IFN FTSET,<
	TLZ	T2,777(OC.BSU)	;CLEAR PROCEED COUNTER AND SET BY UUO
	TLZE	T2,(1B0)	;CHANGE NEW HARDWARE INTO
	TLO	T2,(1B9)	; OLD. OR CHANGE OLD
	TLZE	T2,(1B1)	; SOFTWARE INTO NEW
	TLO	T2,(1B10)	; ..
	TLZE	T2,(1B2)	; ..
	TLO	T2,(1B11)	; ..
	TLZE	T2,(1B6)	; ..
	TLO	T2,(1B12)	; ..
	.SKIPL	.PDABS(T3)	;CAN USERS USE ADDRESS BREAK?
	DATAO	APR,T2		;YES, SETUP BREAK CONDITIONS AND BREAK ADDRESS
>
SETRL2:	SKIPN	R,JBTADR##(J)	;RESTORE R - JOB HAVE CORE IN CORE?
	TDZA	T1,T1		;NO, MUST BE THE NULL JOB OR CORE 0
	MOVE	T1,JOBENB##(R)	;JOB'S APR ENABLE BITS
	JRST	SETAP2		;SETUP APR ENABLE BITS FOR THE USER
				; NO ENABLES IF NULL JOB OR NO CORE IN CORE
;ROUTINE TO SETUP USER AND EXEC BASE REGISTERS FOR A JOB
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER
;	PUSHJ	P,STEUB

STEUB::	CAILE	J,JOBMAX##	;IS THIS A LOW SEGMENT?
	POPJ	P,		;NO, THE UBR MUST ALREADY BE SETUP
				; OR DOESN'T NEED TO BE (ADDRESSES WILL BE
				; MAPPED THROUGH THE EXEC MAP)
	PUSH	P,T1		;SAVE A TEMPORARY
	HRRZ	T1,JBTUPM##(J)	;T1 = THE PAGE NUMBER OF THE USER PAGE MAP PAGE
	TRNN	T1,17777	;IS THERE A UPMP
	JRST	TPOPJ##		;NO, DON'T CLOBBER UBR
	TLO	T1,(LG.LUB)	;REQUEST LOADING OF UBR
	DATAO	PAG,T1		;SET FOR CURRENT USER AND CLEAR THE AM
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
IFN FTEMRT,<
;ROUTINES TO HANDLE ACCOUNTING METERS

;RETURN EBOX COUNTS FROM CURRENT UPT IN T1 AND T2

GETEBT::RDEACT	T1		;READ EBOX COUNTS INTO T1,T2
	POPJ	P,		;RETURN

GETMBT::RDMACT	T1		;SAME FOR MBOX COUNTS
	POPJ	P,

;ROUTINE TO TURN ACCOUNTING METERS ON AND OFF
; CALLED BY CLOCK1 TO EXCLUDE MONITOR OVERHEAD FROM USER RUNTIME
; CALL WITH C(P4) = CPU DATA BLOCK. ACCMON AND ACCMOF PRESERVE ALL AC'S

ACCMON::PUSH	P,T1
	PUSH	P,T2		;SAVE T1,T2
	CONI	MTR,T1		;GET PI ASSIGNMENT, TIME BASE ON/OFF
	TRO	T1,MO.LAC!MO.AEN!MO.AIP!MO.AO  ;MAKE SURE LOAD ACCT, EXEC NO PI
				; PI, ACCT METER ON
	MOVE	T2,CNFST2##	;GET CNFST2
	TRNE	T2,ST%XPI	;EXCLUDE PI FROM USER RUNTIME?
	TRZ	T1,MO.AIP	;YES, THEN DON'T INCLUDE
	CONO	PI,PIOFF##	;TURN OFF PI'S SO ACCOUNTING METER AND PERF METER
				; WILL STAY IN SYNC
	CONO	MTR,(T1)	;SET STUFF, TURN METER ON
	SKIPE	.CPAPS##(P4)	;IF ACCT/PERF METER SYNC,
	PUSHJ	P,SCDPMR	;GO TURN PERFORMANCE METER ON IF NECESSARY
	CONO	PI,PION##	;BACK ON
	POP	P,T2		;RESTORE T2
	JRST	TPOPJ##		;T1 AND RETURN

;TURN OFF ACCOUNTING METER

ACCMOF::PUSH	P,T1		;SAVE AN AC
	CONI	MTR,T1		;GET PI ASSIGNMENT, OTHER STUFF
	ANDI	T1,7		;ONLY PI ASSIGNMENT
	TRO	T1,MO.LAC	;LOAD ACCOUNTING ENABLES - ZILCH
	CONO	PI,PIOFF##	;TURN OFF PI'S
	CONO	MTR,(T1)	;STOP THE CLOCK
	SKIPE	.CPAPS##(P4)	;ACCOUNTING/PERF SYNC?
	PUSHJ	P,STPPMR	;YES, TURN OFF PERFORMANCE METER
	CONO	PI,PION##	;PI BACK ON AGAIN
	PJRST	TPOPJ##		;RESTORE T1 AND RETURN

;STILL IN FTEMRT CONDITIONAL
;CLEAR EBOX, MBOX COUNT FOR CURRENT UPT
; THESE ROUTINES PRESERVE ALL AC'S

CLREBT::DATAI	PAG,1(P)		;WRITE OUT ALL THE BITS
	DATAO	PAG,1(P)
	SETZM	.UPMP+.LMEBL	;LOW ORDER BITS FIRST SO NO OVERFLOW
	SETZM	.UPMP+.LMEBH	;THEN HIGH ORDER
	POPJ	P,		;RETURN

CLRMBT::DATAI	PAG,1(P)	;SEE ABOVE
	DATAO	PAG,1(P)
	SETZM	.UPMP+.LMMBL	;LOW ORDER FIRST
	SETZM	.UPMP+.LMMBH	;THEN HIGH
	POPJ	P,		;RETURN
>;END IFN FTEMRT
SUBTTL	COMCON - INTERFACE TO COMMAND DECODER MODULE

;ROUTINE TO SETUP THE USER BASE REGISTER FOR COMMAND PROCESSING
;CALLING SEQUENCE:
;	PUSHJ	P,COMUBR
;	...	ALWAYS RETURN HERE - UBR POINTS TO THE UPMP OF THE
;		JOB THAT TYPED A COMMAND

COMUBR::MOVE	T1,.C0JOB##	;T1=JOB NUMBER OF CURRENTLY RUNNING JOB
	HRRZ	T1,JBTUPM##(T1)	;JOB HAVE A UPMP?  (NO, ONLY IF THE CURRENT
				; JOB DID  LOGOUT UUO GIVING BACK ALL
				; OF ITS CORE)?
	JUMPE	T1,STEUB	;NO, DON'T SAVE THE UBR SINCE IT POINTS
				; A UPMP WHICH HAS BEEN RETURNED
				; TO THE FREE CORE LIST - JUST POINT THE
				; UBR AT THE UPMP OF THE JOB THAT THE
				; COMMAND IS BEING DONE FOR
	JRST	SVEUB		;SAVE AND SETUP THE UBR
;HERE IF THE USER TYPED SET BREAK
IFN FTSET,<
SETBRK::PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSHJ	P,FNDPDS##	;FIND THE PDB FOR THIS USER
	PUSHJ	P,CTEXT##	;GET THE FIRST ARGUMENT
	JUMPE	T2,NOTENF##	;IF NONE, COMPLAIN
	PUSHJ	P,GETNUM	;SEE IF ARGUMENT TYPED IS A NUMBER
	  JRST	SETBR2		;NOT A NUMBER, LOOK FOR LEGAL TEXT
SETBR1:	CAIN	P1,-1		;DON'T ALLOW -1 FOR THE TIME BEING SINCE IT
				; CONFUSES THE HARDWARE
	JRST	COMERA##	;COMPLAIN
	.HRRM	P1,.PDABS##(W)	;STORE THE BREAK ADDRESS
	PUSHJ	P,CTEXT##	;GET THE NEXT ARGUMENT
	JUMPN	T2,SETBR2	;JUMP IF ONE WAS TYPED
	SKIPN	P2,P1		;BREAK ADDRESS ZERO?
	  JRST	SETB10		;YES, TREAT SET BREAK 0 WITH NO CONDITION LIKE NONE
	.HLLZ	P2,.PDABS##(W)	;GET PREVIOUS CONDITIONS IF ANY
SETB1A:	TLNN	P2,(OC.BCI+OC.BCD+OC.BCW+OC.BCM) ;WERE THERE ANY PREVIOUSLY?
	TLO	P2,(OC.BCI+OC.BCD+OC.BCW) ;NO, ASSUME ALL
	JRST	SETBR8		;ENABLE BREAK, STORE CONDITIONS, AND GO AWAY
SETBR2:	MOVE	T1,[-4,,BRKLS1]	;TABLE LENGTH,,ADDRESS OF THE TABLE
	PUSHJ	P,FNDNAM##	;RECOGNIZABLE TEXT ARGUMENT?
	  JRST	SETBR5		;NO, POSSIBLY IN ANOTHER CONTEXT
	MOVE	P2,T1		;INDEX INTO BRKTBL
	JUMPN	T1,SETBR3	;JUMP IF THE USER DIDN'T TYPE 'NONE'
;HERE WHEN THE USER TYPED 'NONE'
	JUMPGE	P1,COMERA##	;IF A NUMBER WAS TYPED WE SHOULDN'T BE HERE
	JRST	SETB10		;GO CLEAR BREAK CONDITIONS
SETBR3:	PUSHJ	P,CTEXT##	;GET THE NEXT TEXT ARGUMENT
	JUMPE	T2,NOTENF##	;IF WE'RE HERE THERE HAS TO BE ONE
	JRST	.(P2)		;DISPATCH TO THE APPROPRIATE PROCESSOR
	JRST	SETBR4		;USER TYPED 'AT'
	JRST	SETBR5		;USER TYPED 'ON'
	JRST	SETBR6		;USER TYPED 'NO'
;HERE WHEN THE USER TYPED 'AT'
SETBR4:	JUMPGE	P1,COMERA##	;NO PREVIOUS NUMBERS ALLOWED IF WE GET HERE
	PUSHJ	P,GETNUM	;CONVERT THE NUMBER FROM SIXBIT TO OCTAL
	  JRST	COMERA##	;IT MUST BE A NUMBER BUT ISN'T SO COMPLAIN
	JRST	SETBR1		;LOOK FOR THE NEXT TEXT ARGUMENT
;HERE WHEN THE USER TYPED 'ON'
SETBR5:	SKIPA	P1,[TDO P2,BRKTBL-1(T1)]
;HERE WHEN THE USER TYPED 'NO'
SETBR6:	MOVE	P1,[TDZ P2,BRKTBL-1(T1)]
	.HLLZ	P2,.PDABS##(W)	;GET CURRENT BREAK CONDITIONS
SETBR7:	MOVE	T1,[-7,,BRKLS2]	;TABLE LENGTH,,TABLE ADDRESS
	PUSHJ	P,FNDNAM##	;GET A BREAK CONDITION
	  JRST	COMERA##	;IT CAN'T BE ANYTHING ELSE
	JUMPE	T1,SETB11	;JUMP IF 'USERS'
	CAIN	T1,AFTERX
	JRST	SETB12
	XCT	P1		;SET OR CLEAR THE CONDITION
	PUSHJ	P,CTEXT##	;GET THE NEXT ARGUMENT
	JUMPN	T2,SETBR7	;LOOP BACK IF THERE WAS ONE
	TLZ	P2,(OC.ABE+OC.FUP)  ;ASSUME NO CONDITIONS
	TLNN	P2,(OC.BCI+OC.BCD+OC.BCW+OC.BCM) ;ANY CONDITIONS DESIRED?
	JRST	SETB10		;NO, DECREMENT NUMBER OF USERS USING ADDRESS BREAK
SETBR8:	PUSHJ	P,BRKAV		;SEE IF ADDRESS BREAK IS AVAILABLE AND INCREMENT
				; THE COUNT OF USERS USING IT IF SO
	  JRST	NOBRAK		;NOT AVAILABLE, COMPLAIN
SETBR9:	TLOA	P2,(OC.ABE+OC.FUP) ;ENABLE THE USER FOR ADDRESS BREAK
SETB10:	PUSHJ	P,BRKDEC	;DECREMENT THE COUNT OF USERS USING ADDRESS BREAK
	.HLLM	P2,.PDABS##(W)	;STORE THE NEW CONDITIONS
	POPJ	P,		;AND RETURN TO COMCON
;HERE WHEN THE USER TYPED 'USERS', MUST BE PRIVILEGED
SETB11:	PUSHJ	P,SETLGL##	;USER SUFFICIENTLY PRIVILEDGED TO MONOPOLIZE
				; ADDRESS BREAK?
	  JRST	COMERA##	;NO, COMPLAIN
	PUSHJ	P,FDNJP		;FIND THE NULL JOB'S PDB
	MOVSI	T2,400000	;SET TO TURN ON OR OFF ADDRESS BREAK
	CAME	P1,[TDZ P2,BRKTBL-1(T1)] ;WAS 'USERS' WITHOUT A 'NO' TYPED?
	JRST	[.ANCAM	T2,.PDABS##(T1) ;YES, ALLOW USERS TO USE ADDRESS BREAK
		POPJ	P,]	;RETURN
;HERE WHEN THE USER TYPED 'NO USERS'
	.SKPLE	.PDABS##(T1)	;IS ADDRESS BREAK CURRENTLY BEING USED?
	JRST	NOBRAK		;DON'T ALLOW HIM TO YANK IT OUT FROM UNDER THEM
	.IORM	T2,.PDABS##(T1)	;DON'T ALLOW USERS TO USE ADDRESS BRAEK
	POPJ	P,		;RETURN TO COMCON

;HERE WHEN THE USER TYPED 'AFTER'
SETB12:	PUSHJ	P,DECIN##	;GET THE NEXT ARGUMENT
	  PJRST	NOTENF##	;THERE MUST BE ONE
	  JRST	COMERA##	;NOTHING BUT A NUMBER IS LEGAL
	CAILE	T2,^D510	;IS IT TOO BIG?
	JRST	COMERA##	;YES
	ADDI	T2,1
	DPB	T2,[POINT 9,P2,17]  ;SAVE THE REPEAT COUNT
	JRST	SETB1A		;STORE IT AND GO AWAY
;HERE ON A SET ADDRESS BREAK UUO
SETABR::PUSHJ	P,SAVE2##	;SAVE P1,P2
	HRR	M,T2		;ADDRESS OF USER'S ARGUMENT
	PUSHJ	P,GETWDU##	;GET THE ARGUMENT
	HRRM	T1,.PDABS##(W)	;STORE THE BREAK ADDRESS
	MOVE	P2,T1		;P2 = BREAK CONDITIONS
	TLZ	P2,(OC.FEP)	;HE ISN'T ALLOWED TO SET FOLLOW EXEC PAGING
	TLO	P2,(OC.BSU)	;INDICATE SET BY UUO
	AOS	(P)		;PREPARE TO GIVE GOOD RETURN
	TLNN	P2,(OC.BCI+OC.BCD+OC.BCW+OC.BCM)
	JRST	[PUSHJ P,SETB10	;TURNING OFF BREAK
		 PJRST SETRL1]
	PUSHJ	P,BRKAV		;IS ADDRESS BREAK AVAILABLE?
	  SOSA	(P)		;NO, ERROR RETURN
	JRST	[PUSHJ P,SETBR9		;YES, SETUP BREAK CONDITIONS
		 PJRST SETRL1]
	POPJ	P,		;GIVE ERROR RETURN

;HERE ON RESET TO CLEAR BREAK ADDRESS AND CONDITIONS
; IF SET BY UUO
CLRBRK::SKIPE	T1,.PDABS##(W)	;BREAK IN USE AT ALL?
	TLNN	T1,(OC.BSU)	;AND SET BY UUO?
	POPJ	P,		;NO
	PUSHJ	P,BRKDEC	;YES, DECREMENT COUNT OF USERS
	SETZM	.PDABS##(W)	;CLEAR ADDRESS AND CONDITIONS
	POPJ	P,		;AND RETURN
;THE ORDER OF AND THE NUMBER OF ENTRIES
; IN THE FOLLOWING TABLES CANNOT BE CHANGED
; WITHOUT CHANGING THE CODE IN SETBRK

BRKLS1:	SIXBIT	/NONE/
	SIXBIT	/AT/
	SIXBIT	/ON/
	SIXBIT	/NO/
BRKLS2:	SIXBIT	/USERS/
	SIXBIT	/EXECUT/
	SIXBIT	/READ/
	SIXBIT	/WRITE/
	SIXBIT	/MUUO/
	SIXBIT	/ALL/
BRKLS3:	SIXBIT	/AFTER/
AFTERX==BRKLS3-BRKLS2
;THE ENTRIES IN THIS TABLE CORRESPOND IN ORDER
; TO THE ENTRIES IN THE ABOVE TABLE
BRKTBL:	EXP	OC.BCI
	EXP	OC.BCD
	EXP	OC.BCW
	EXP	OC.BCM
	EXP	OC.BCI+OC.BCD+OC.BCW

;SUBROUTINE TO DETERMINE IF THE SIXBIT STRING IN
; T2 IS A LEGAL OCTAL NUMBER
;CALLING SEQUENCE:
;
;	MOVE	T2,SIXBIT STRING
;	PUSHJ	P,GETNUM
;NON-SKIP RETURN IF T2 DOES NOT CONTAIN A
; NUMBER, P1.LT.0, AND T2 PRESERVED
;SKIP RETURN P1=NUMBER IF T2 CONTAINS A NUMBER
;NEVER RETURNS IF T2 CONTAINS A MALFORMED
; NUMBER
;N.B. P1 MUST BE SAVED BEFORE CALLING THIS
;SUBROUTINE

GETNUM:	MOVSI	P1,400000	;INDICATE NO NUMBER SEEN
	MOVEI	T3,0		;CLEAR RESULT SO FAR
	MOVE	T4,[POINT 6,T2]	;BYTE POINTER TO PICKUP CHARACTERS
GETNM1:	ILDB	T1,T4		;GET THE NEXT CHARACTER
	CAIL	T1,'0'		;IS THE CHARACTER .LT. ZERO?
	CAILE	T1,'7'		;OR G.GE. 7?
	JRST	GETNM2		;YES, ITS NOT AN OCTAL DIGIT
	LSH	P1,3		;MULTIPLY ACCUMULATED RESULT BY 8
	ADDI	P1,-'0'(T1)	;ADD IN THE CURRENT CHARACTER
	JRST	GETNM1		;AND GET THE NEXT DIGIT
GETNM2:	JUMPL	P1,CPOPJ##	;NON-SKIP RETURN IF NOT A NUMBER
	JUMPN	T1,COMERP##	;NUMBERS WHICH TERMINATE WITH NON-DIGITS ARE
				; NOT NUMBERS
	JRST	CPOPJ1##	;GIVE NUMBER FOUND RETURN
;SUBROUTINE TO DETERMINE WHETHER ADDRESS BREAK IS AVAILABLE TO USERS
;CALLING SEQUENCE:
;	PUSHJ	P,BRKAV
;NON-SKIP RETURN IF NOT AVAILABLE BECAUSE MEMORY
; INDICATORS ARE DISABLED OR ADDRESS BREAK IS BEING
; USED BY SYSTEM PROGRAMMERS FOR MONITOR DEBUGGING
;SKIP RETURN IF ADDRESS BREAK IS AVAILABLE TO USERS, COUNT OF THE NUMBER
;OF USERS USING ADDRESS BREAK HAS BEEN UPDATED
;PRESERVES T2

BRKAV:	PUSHJ	P,FDNJP		;FIND THE NULL JOB'S PDB
	PUSHJ	P,CP0RC##	;SEE IF THE JOB IS RUNNABLE ON CPU0
	  TLNN	P2,(OC.BCM)	;ITS NOT, BUT IF HE IS ENABLED FOR UUOS, SOME
				; MUST HAPPEN ON CPU0
	SKIPGE	.PDABS##(T1)	;HAS ADDRESS BREAK BEEN DISABGEED BY THE OPR?
	POPJ	P,		;YES, LOSE
	.MOVE	T3,.PDABS##(W)	;GET HIS CURRENT ADDRESS BREAK SETTINGS
	TLNN	T3,(OC.ABE)	;IS HE ALREADY BREAKING?
	.AOS	.PDABS##(T1)	;NO, COUNT UP THE NUMBER OF USERS USING ADDRESS BREAK
	JRST	CPOPJ1##	;AND GIVE THE HAPPY RETURN

;SUBROUTINE TO DECREMENT THE COUNT OF THE NUMBER
; OF USERS USING ADDRESS BREAK

BRKDEC:	.MOVE	T1,.PDABS##(W)	;GET HIS CURRENT BREAK SETTINGS
	TLNN	T1,(OC.ABE)	;IS HE ENABLED FOR ADDRESS BREAK?
	POPJ	P,		;NO, NOTHING TO DO
	PUSHJ	P,FDNJP		;FIND THE PDB FOR THE NULL JOB
	.SOS	.PDABS##(T1)	;DECREMENT THE COUNT OF USERS USING ADDRESS BREAK
	POPJ	P,		;AND RETURN

NOBRAK:	PJSP	T1,CONMES##	;SORRY FOLKS!
	ASCIZ	/?Not available
/

;SUBROUTINE TO RETURN THE ADDRESS OF THE NULL JOB'S PDB IN T1
;PRESERVES T2-T4

FDNJP:	MOVEI	T1,0		;NULL JOB'S JOB NUMBER
	PUSHJ	P,FPDBT1##	;FIND THE NULL JOB'S PDB, RETURN ITS ADDRESS IN T1
	  JFCL			;IT MUST HAVE ONE
	POPJ	P,		;RETURN TO THE CALLER
>	;END IFN FTSET
SUBTTL	IOCSS - I/O SERVICE SUBROUTINES (UUOCON AND DEVICE ROUTINES)

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

MAPDEV::PUSH	P,T1		;SAVE P1
	MOVEI	T1,DEPEVM	;GET "DEVICE DOESN'T NEED EVM" BIT
	TDNN	T1,DEVTYP(F)	;SKIP IF MAPPING NOT REQUIRED
	PJRST	TPOPJ1##	;PTY, TTY, AND CHANNEL DEVICES ARE NOT
				; MAPPED IN EXEC VIRTUAL MEMORY
	PJRST	TPOPJ##		;ALL I/O BUS DEVICE REQUIRE MAPPING IN
				; EXEC VIRTUAL MEMORY
;ROUTINE TO SAVE AND OPTIONALLY SET UP THE USER BASE REGISTER
; AND RESTORE IT ON A CPOPJ OR CPOPJ1 RETURN
;CALLING SEQUENCE:
;	PUSHJ	P,SVEUB		;TO SAVE USER BASE REGISTER
;OR
;	PUSHJ	P,SVEUB		;TO SAVE USER BASE REGISTER AND SETUP
;				;USER BASE REGISTER FOR JOB IN J
;ALWAYS RETURN HERE

SVEUF::	PUSH	P,T1		;SAVE A TEMPORARY
	DATAI	PAG,T1		;GET THE USER AND EXEC BASE REGISTERS
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;GET THE JOB NUMBER OF JOB CURRENTLY USING
				; THIS DEVICE
	PUSHJ	P,STEUB		;SETUP THE UBR SO CURRENT JOB IS ADDRESSABLE
	POP	P,J		;RESTORE J
	JRST	SSEU1		;SAVE THE PREVIOUS CONTENTS OF THE UBR AND EBR
SVEUB::	PUSH	P,T1		;SAVE A TEMPORARY
	DATAI	PAG,T1		;GET THE CONTENTS OF THE USER AND EXEC BASE REGISTERS
	PUSHJ	P,STEUB		;SETUP THE UBR FOR THE JOB WHOSE JOB NUMBER
				; IS IN J
	JRST	SSEU1		;SAVE THE PREVIOUS CONTENTS OF THE UBR AND THE EBR
SSEUB:	PUSH	P,T1		;SAVE A TEMPORARY
	DATAI	PAG,T1		;GET THE CONTENTS OF THE USER AND EXEC BASE REGISTERS
SSEU1:	EXCH	T1,-1(P)	;GET THE CALLER'S PC AND SAVE THE CONTENTS
				; OF THE UBR AND EBR
	MOVEM	T1,1(P)		;SAVE THE CALLER'S PC IN A TEMPORARY LOCATION
				; ON THE STACK
	POP	P,T1		;RESTORE T1 TO ITS CONTENTS ON ENTRY
	PUSHJ	P,@2(P)		;RETURN TO THE CALLER LEAVING .+1 ON THE
				; STACK SO WHEN THE CALLER DOES A POPJ OR
				; A CPOPJ1, CAN RESTORE THE PREVIOUS CONTENTS
				; OF THE UBR AND THE EBR
	  CAIA			;CPOPJ RETURN
	AOS	-1(P)		;CPOPJ1 RETURN - BUMP RETURN PC
	EXCH	T1,(P)		;GET THE PREVIOUS CONTENTS OF THE UBR
	DATAO	PAG,T1		;RESTORE THE UBR AND THE EBR
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
;ROUTINE TO MAP USER AREA IN THE EXEC MAP
;CALLING SEQUENCE:
;
;	MOVE	T1,PAGE NUMBER OF STARTING PAGE IN THE EXEC MAP
;	MOVE	T2,NUMBER OF PAGES
;	MOVE	T3,USER VIRTUAL ADDRESS
;	PUSHJ	P,MAPUEV
;OR
;	PUSHJ	P,MAPUEI IF AT INTERRUPT LEVEL SO EBR,UBR WILL BE
;		RESTORED SO DO NOT NEED TO PURGE ASSOCIATIVE MEMORY
;	RETURNS HERE - T1=PAGE NUMBER IN THE EXEC MAP, T3=EXEC VIRTUAL
;	ADDRESS WHICH CORRESPONDS TO USER VIRTUAL ADDRESS,
;	AND ASSOCIATIVE MEMORY IS PURGED

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

MAPUEI::PUSHJ	P,SAVE3##	;SAVE P1-P3
MAPUE1:	MOVE	P1,T1		;P1 = THE PAGE NUMBER OF THE FIRST PAGE
				; IN THE EVM THAT BELONGS TO THIS JOB
	SUBI	P1,400		;MAPPED ADDRESSES START AT 128K
	ROT	P1,-1		;DIVIDE BY 2 AND PUT THE REMAINDER IN HIGH ORDER BIT
	MOVEI	P2,.EPPM##(P1)	;FORM A BYTE POINTER TO THE EXEC MAP
	TLO	P2,442200	;ASSUME AN EVEN PAGE
	SKIPGE	P1		;WAS IT EVEN?
	HRLI	P2,222200	;NO, START WITH THE RIGHT HALF WORD
	LDB	P1,[POINT 9,T3,26]
	ROT	P1,-1		;DIVIDE BY 2 AND PUT THE REMAINDER IN HIGH ORDER BIT
	MOVEI	P3,.UPMP(P1)	;FORM A BYTE POINTER TO THE USER'S MAP
	SKIPL	P1		;FIRST PAGE EVEN
	TLOA	P3,442200	;YES, THE FIRST PAGE IS MAPPED BY THE LEFT HALF WORD
	HRLI	P3,222200	;NO, MAPPED BY THE RIGHT HALF WORD
MAPUE2:	ILDB	P1,P3		;COPY A PORTION OF THE USER'S MAP TO
	TRZ	P1,760000	;CLEAR ALL ACCESS BITS
	TRO	P1,PM.ACC+PM.WRT	;ACCESS ALLOWED, CONCEALED,  AND WRITEABLE
	IDPB	P1,P2		; THE EXEC MAP
	SOJG	T2,MAPUE2	;COPY AS MANY PAGES AS ARE TO BE MAPPED IN EVM
	DPB	T1,[POINT 9,T3,26]
				;FORM AN EXEC VIRTUAL ADDRESS FROM THE EXEC
				; PAGE NUMBER AND THE USER VIRTUAL ADDRESS
	POPJ	P,		;RETURN
;ROUTINE TO MAP A USER BUFFER IN EXEC VIRTUAL MEMORY
;CALLING SEQUENCE:
;	MOVE	T1,BUFFER SIZE
;	MOVE	T3,USER VIRTUAL ADDRESS OF BUFFER
;	MOVE	F,ADDRESS OF THE DDB
;	PUSHJ	P,GTEVBF
;	RETURN HERE ONLY IF REQUEST COULD NEVER BE SATISFIED (THERE WILL
;	NEVER BE ENOUGH SLOTS AVAILABLE IN THE EXEC MAP)
;	RETURN HERE - T1=BYTE (18)0(9) EXEC VIRTUAL PAGE # (9) # OF EXEC PAGES
;	T3 = THE EXEC VIRTUAL ADDRESS OF THE BUFFER

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

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



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

GIVEVM::LDB	T2,[POINT 9,T2,26]
	SUBI	T2,400		;CHANGE PAGE NUMBER INTO BIT POSITION
	IDIVI	T2,^D36		;WHICH WORD
	HRLS	T2		;PUT WORD NUMBER IN THE LEFT HALF
	ADD	T2,EVMPTR##	;MAKE AOBJN POINTER POINT TO THE WORD CONTAINING
				; THE FIRST BIT TO CLEAR
	PUSH	P,T4		;SETZRS CLOBBER T4
	PUSHJ	P,SETZRS##	;GIVE BACK THE EVM
	PUSHJ	P,EVFREE##	;WAKE UP ALL WAITERS FOR EVM
	SETZM	EVREQ##		;SO NEXT CALLER TO EVWAIT WILL WAIT (IMMEDIATELY)
	JRST	T4POPJ##	;RETURN
;ROUTINE TO CONVERT AN IOWD TO ABSOLUTE IOWDS
;FOLLOWING THE PAGING OF A JOB
;CALLING SEQUENCE:
;	MOVE	T2,IOWD
;	MOVEI	P1,0		;FIRST CALL
;	MOVE	P3,LOC OF CHANNEL DATA BLOCK
;	MOVE	P4,FRAME-COUNT,,CHARS/WD IF DX10 CHL
;	PUSHJ	P,MAPIOW
;	RETURN HERE IF NOT ENOUGH MONITOR FREE CORE
;	RETURN HERE - P2=ADDRESS OF FIRST IOWD
;	P1=WHERE NEXT IOWD WILL BE STORED

MAPIO::	TLNN	T2,-1		;0 OR CHANNEL JUMPS ARE ILLEGAL
	STOPCD	CPOPJ,DEBUG,IEZ,  ;++IOWD EQUALS ZERO
	PUSHJ	P,SVEUB		;SAVE AND SETUP UBR
	PUSH	P,U		;SAVE U
IFN FT22BIT,<
	HLLZ	U,CHB22B##(P3)	;GET CHANNEL-TYPE WORD
	TLNE	U,CP.RH2##	;RH20?
	TROA	U,4		;YES
	LDB	U,[POINT 2,U,1]	;NO, GET CHAN TYPE ELSEWHERE
	HLL	U,P4		;PRESERVE FRAMECOUNT
>
	PUSH	P,T1		;SAVE ALL ACS THAT ARE USED SINCE THEY
	PUSH	P,P4		; ARE PROBABLY IMPORTANT TO THE CALLERS
	PUSH	P,P3		; OF MAPIOW
	PUSH	P,T2		; ..
	PUSH	P,T3		; ..
	PUSH	P,T4		; ..
	JUMPN	P1,MAPIO1	;P1 IS NON-ZERO IF NOT THE FIRST CALL
	PUSHJ	P,GCH4WD	; ..
	  JRST	MAPIO8		;NONE AVAILABLE
	MOVE	P1,T1		;ADDRESS OF THE FOUR WORD BLOCK
	MOVE	P2,T1		;ADDRESS OF THE IOWD LIST
	HRLI	P1,-3		;THE NUMBER OF WORDS LEFT IN THIS BLOCK
	SETZM	3(P1)		;ZERO THE LAST WORD OF THE BLOCK
	MOVE	T3,CHB22B##(P3)
	TLNE	T3,CP.RH2##
	SETZM	CHNTCW##(P3)	;ACCUMULATE WORD-COUNT IN CHNTCW (FOR RH20)
MAPIO1:	PUSHJ	P,CHKMOR	;GET ANOTHER FOUR WORD BLOCK AND LINK IT
				; TO THE CURRENT BLOCK IF ABOUT TO USE
				; THE LAST WORD OF THE CURRENT BLOCK
	  JRST	MAPIO8		;NO MORE FOUR WORD BLOCKS
	MOVE	P4,-2(P)	;RESTORE THE IOWD TO P4
	HRRZ	T2,P4		;ADDRESS-1 WHERE I/O WILL START
	MOVE	T3,DEVMOD(F)
IFE FTSPL,<
	TLNN	T3,DVDSK	;IF A DSK
>
IFN FTSPL,<
	SKIPL	DEVSPL(F)	;SPOOLED DDBS ARE ALWAYS A DSK
	TLNE	T3,DVDSK		;IS A DSK
	CAIA
>
	JRST	MAPI1B
IFE FTVM<
	SKIPL	DEVSWP##(F)	;IF NOT THE SWAPPER
>
	JUMPL	S,MAPIO6	; DONT UNRELOCATE IF MONITOR IO
MAPI1B:	MOVE	R,JBTADR##(J)	;ADDRESS OF THE JOB DATA AREA
	PUSHJ	P,CHKHS		;SEE IF A HIGH SEGMENT SAVE IS IN PROGRESS
IFE FTVM,<
	CAIA
	SKIPLE	J,JBTSGN##(J)	;YES, J = HIGH SEGMENT NUMBER
	SKIPN	T1,JBTADR##(J)	;EXEC VIRTUAL ADDRESS OF THIS SEGMENT
				; (DEVICE ROUTINES THINK THEY ARE RELOCATING
				; THE IOWD BY ADDING THIS)
	STOPCD	.,JOB,IRE,	;++IOWD RELOCATION ERROR
	CAILE	J,JOBMAX##	;HIGH SEG?
	MOVEI	T1,342000	;YES, USE STD ADDR
	SUBI	T2,-1(T1)	;SUBTRACT OUT "RELOCATION" AND ACCOUNT
				; FOR THE FACT THAT IOWDS ARE ADDRESS-1
	HRRZS	T2		;IN CASE OF MORE THAN 437 PAGES
	LSH	T2,W2PLSH##	;CONVERT TO PAGE NUMBER
	PUSHJ	P,SNPAGS	;GET THE ABSOLUTE PAGE NUMBER OF THIS PAGE
	MOVE	P3,T1		;SAVE THAT IN P3
	MOVE	T2,P4		;T2 AND P4 = IOWD+1
	HLROS	P4		;P4 = -WORD COUNT
	ADDI	T2,1
MAPIO2:	SKIPN	T3,P3		;T3 = CURRENT ABSOLUTE PAGE NUMBER
	STOPCD	.,JOB,APE,	;++ABSOLUTE PAGE EXCEEDED
				; IOWD HAS BEEN ADDRESS CHECKED)
	MOVEI	T1,0		;T1 = AMOUNT ACCUMULATED SO FAR
	LSH	T3,P2WLSH##	;MOVE PAGE NUMBER TO THE HIGH ORDER THIRTEEN
				; BITS OF THE ADDRESS
	ANDI	T2,PG.BDY##	;GET THE STARTING WORD ADDRESS WITHIN THE PAGE
	ADD	T2,T3		;T2 = ABSOLUTE ADDRESS
	SUBI	T2,1		;MAKE T2 AN IOWD
	PUSH	P,T2		;SAVE THE ADDRESS
	ANDI	T2,PG.BDY##	;EXTRACT THE WORD NUMBER
	SUBI	T2,PAGSIZ##-1	;CALCULATE THE NUMBER OF WORDS TO DO INTO THIS PAGE
	SKIPN	T2		;IF ITS ZERO DO A WHOLE PAGE WORTH
MAPIO3:	MOVNI	T2,PAGSIZ##	; ..
	SUB	P4,T2		;ADD -NUMBER OF WORDS ON THIS PAGE TO 
				; IOWD WORD COUNT
	ADD	T1,T2		;ACCUMULATE IN TOTAL WORD COUNT
	JUMPGE	P4,MAPIO4	;JUMP IF THE ORIGIONAL WORD COUNT IS EXHAUSTED
IFN FT22BIT,<
	SETZ	T3,		;SET T3 SO TEST WILL FAIL IF 22-BIT CHAN AND
	SKIPE	U		; NO ROOM FOR ANOTHER PAGE IN THE IOWD
	CAML	T1,[EXP -37777+PAGSIZ##] ;OTHERWISE SET T3=CURRENT PAGE
>
	MOVE	T3,P3		;T3 = CURRENT PAGE NUMBER WITHIN SEGMENT
	HRRZ	P3,PAGTAB(P3)	;P3 = NEXT PAGE NUMBER WITHIN SEGMENT
	CAME	T1,[-600000+PAGSIZ##] ;DONT GENERATE AN IOWD WHOSE WRDCNT
	CAMN	T1,[-30000+PAGSIZ##]  ; LOOKS LIKE AN RH20 CHANNEL JUMP
	JRST	MAPI3A		      ; WORD
	CAIN	P3,1(T3)	;ARE THE TWO PAGES ADJACENT IN PHYSICAL MEMORY?
>	;END FTVM
IFN FTVM,<
	  JRST	MAPI1C		;NO, GET VIRT ADR THE NORMAL WAY
	MOVE	T1,P4		;YES, IOWD TO T1
	SUBI	T1,(R)		;UNRELOCATE IT
	PUSHJ	P,UVACK		;COMPUTE STARTING ADR FOR THIS PART
	AOJA	T2,MAPI1D	;AND CONTINUE
MAPI1C:	SKIPN	T1,JBTADR##(J)	;EXEC VIRTUAL ADDRESS OF THIS SEGMENT
				; (DEVICE ROUTINES THINK THEY ARE RELOCATING
				; THE IOWD BY ADDING THIS)
	STOPCD	.,JOB,IRE,	;++IOWD RELOCATION ERROR
	SUBI	T2,-1(T1)	;SUBTRACT OUT "RELOCATION" AND ACCOUNT
				; FOR THE FACT THAT IOWDS ARE ADDRESS-1
	HRRZS	T2		;NEEDED IF SEG GTR THAN 437 PAGES
MAPI1D:	LSH	T2,W2PLSH##	;CONVERT TO PAGE NUMBER
	ROT	T2,-1		;SET UP A BYTE POINTER TO THE PAGE IN THE UPMP
	ADDI	T2,.UPMP
	TLZE	T2,400000
	TLOA	T2,(<POINT 18,0,35>)
	TLO	T2,(<POINT 18,0,17>)
	MOVE	P3,T2		;SAVE POINTER IN P3
	MOVE	T2,P4		;T2 AND P4 = IOWD
	HLROS	P4		;P4 = -WORD COUNT
	ADDI	T2,1		;POINT AT REAL ADR
MAPIO2:	LDB	T3,P3		;T3 = CURRENT ABSOLUTE PAGE NUMBER
	TRNN	T3,PM.ACC
IFN FTEXE,<
	SKIPGE	USRHCU##	;IF A SAVE IS IN PROGRESS,
	SKIPA			; THEN, THIS IS OK
>;END OF INF FTEXE
	JRST	S..AAO		;ACCESS ALLOWED OFF
				; IOWD HAS BEEN ADDRESS CHECKED)
	MOVEI	T1,0		;T1 = AMOUNT ACCUMULATED SO FAR
	LSH	T3,P2WLSH##	;MOVE PAGE NUMBER TO THE HIGH ORDER THIRTEEN
				; BITS OF THE ADDRESS
	ANDI	T2,PG.BDY##	;GET THE STARTING WORD ADDDESS WITHIN THE PAGE
	ADD	T2,T3		;T2 = ABSOLUTE ADDRESS (IOWD STYLE)
	SUBI	T2,1		;MAKE AN IOWD
	PUSH	P,T2		;SAVE THE ADDRESS
	ANDI	T2,PG.BDY##	;EXTRACT THE WORD NUMBER
	SUBI	T2,PAGSIZ##-1	;CALCULATE THE NUMBER OF WORDS TO DO INTO THIS PAGE
	SKIPN	T2		;IF ITS ZERO DO A WHOLE PAGE WORTH
MAPIO3:	MOVNI	T2,PAGSIZ##	; ..
	SUB	P4,T2		;ADD -NUMBER OF WORDS ON THIS PAGE TO 
				; IOWD WORD COUNT
	ADD	T1,T2		;ACCUMULATE IN TOTAL WORD COUNT
	JUMPGE	P4,MAPIO4	;JUMP IF THE ORIGIONAL WORD COUNT IS EXHAUSTED
IFN FT22BIT,<
	SETZ	T3,		;SET T3 SO TEST WILL FAIL IF 22-BIT CHAN AND
	SKIPE	U		; NO ROOM FOR ANOTHER PAGE IN IOWD
	CAML	T1,[EXP -37777+PAGSIZ##] ;OTHERWISE SET T3=CURRENT PAGE
>
	LDB	T3,P3		;T3 = CURRENT PAGE NUMBER WITHIN SEGMENT
	ILDB	T4,P3		;T4 = NEXT PAGE NUMBER WITHIN SEGMENT
	TRNN	T4,PM.ACC	;ACCESS ALLOWED ON?
	STOPCD	.,JOB,AAO,	;++ACCESS ALLOWED IS OFF
	CAME	T1,[-600000+PAGSIZ##] ;DONT GENERATE AN IOWD WHOSE LH
	CAMN	T1,[-30000+PAGSIZ##]  ; LOOKS LIKE AN RH20 JUMP WORD
	JRST	MAPI3A
	TRZ	T3,760000	;CLEAR ACCESS BITS
	TRZ	T4,760000	;CLEAR OUT THE ACCESS BITS
	CAIN	T4,1(T3)	;ARE THE TWO PAGES ADJACENT IN PHYSICAL MEMORY?
>	;END IFN FTVM
	JRST	MAPIO3		;YES, CONTINUE ON CURRENT IOWD
MAPI3A:	MOVEI	T2,0		;T2 = FIRST ADDRESS
	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
IFE FT22BIT,<
	HRLM	T1,(P1)		;AND THE WORD COUNT (NUMBER OF WORDS MAPPED SO FAR)
>
IFN FT22BIT,<
	PUSHJ	P,DXFIX		;ADJUST IOWD IF A DX10
	  JRST	MAPIO8		;NO SPACE
	JUMPL	U,MAPIO7	;DONE IF FRAMECOUNT EXHAUSTED
>
	AOBJN	P1,MAPIO2	;CONTINUE IF THERE IS ROOM IN THE FOUR WORD BLOCK
	PUSHJ	P,GETMOR	;GET ANOTHER FOUR WORD BLOCK
	  JRST	MAPIO8		;WHOOPS! NONE AVAILABLE
	MOVEI	T2,0		;START AT WORD NUMBER ZERO ON THIS PAGE
	JRST	MAPIO2		;MAP THE REST OF THE IOWD
MAPIO4:	POP	P,(P1)		;STORE THE IOWD ABSOLUTE ADDRESS
	ADD	P4,T1		;ADD THE RESIDUAL WORD COUNT TO THE ACCUMULATED
				; WORD COUNT
IFE FT22BIT,<
	HRLM	P4,(P1)		;STORE WORD COUNT IN IOWD
>
IFN FT22BIT,<
	MOVE	T1,P4		;PUT WD CNT INTO T1
	PUSHJ	P,DXFIX		;PERFORM FIXUPS FOR DX10
	  JRST	MAPIO8		;OUT OF SPACE
>
	JRST	MAPIO7		;AND GIVE THE WIN RETURN
MAPIO6:
IFE FT22BIT,<
	MOVEM	P4,(P1)		;THE I/O IS INTO A MONITOR BUFFER SO STORE
>
IFN FT22BIT,<
	MOVEM	T2,0(P1)	;STORE ADDRESS
	HLRE	T1,P4		;GET WORD COUNT
	PUSHJ	P,DXFIX		;FIDDLE WITH DX10 IOWDS
	  JRST	MAPIO8		;NO ROOM
>
				; THE ALREADY ABSOLUTE IOWD AND RETURN
MAPIO7:	AOBJN	P1,.+1		;BUMP THE POINTER TO THE NEXT FREE WORD
	SETZM	(P1)		;ZERO IT SO THE LIST IS TERMINATED
	AOS	-7(P)		;SET FOR SKIP (WIN) RETURN
MAPIO8:
IFE FT22BIT,<
	HLRE	P4,-1(P1)	;GET NEG WORD CNT FROM LAST IOWD
	HRRZ	T1,-1(P1)	;GET START OF DATA FROM LAST IOWD
	SUB	T1,P4		;DETERMINE ENDING DATA ADDRESS
	HRL	T1,P1		;PUT ADDR OF END OF IOWD LIST
>
	SKIPGE	-3(P)		;IF WE WANT IT STORED,
	TRNE	U,5		;TYPE 0 OR 2 OR 4 CONTROLLER?
	JRST	MAPIO9		;NO, DON'T DO NEXT
IFN FT22BIT,<
	HRRZS	U		;CLEAR POSSIBLE FRAMECOUNT
	LSH	U,-1
	MOVE	T3,P1		;GET ADDR OF LAST IOWD FOR BYTE PTR'S
	LDB	T1,ADRPT2##(U)	;GET ADDR FIELD FROM LAST IOWD
	HLRO	P4,-1(T3)	;WORD COUNT
	ASH	P4,@ASH22B##(U)	;4 BITS DON'T COUNT IF 22-BIT
	SUB	T1,P4		;DETERMINE ENDING DATA ADDRESS
	DPB	P1,ADRPT4##(U)	;PUT ADDR OF END OF IOWD LIST
>
	MOVE	P3,-3(P)
	MOVEM	T1,CHNTCW##(P3)
MAPIO9:	POP	P,T4		;RESTORE ACS
	POP	P,T3		; ..
	POP	P,T2		; ..
	POP	P,P3		; ..
	POP	P,P4		; ..
	POP	P,T1		; ..
	PJRST	UPOPJ##		;GIVE WIN OR LOSE RETURN

;ROUTINE TO FINISH UP AN RH20 IO LIST
;PRESEVES T1
RH2ND::	PUSH	P,T1
	MOVEI	T3,177
	ANDB	T3,CHNTCW##(P3)	;NO SWEAT IF AN EVEN MULTIPLE OF 200 WORDS
	JUMPE	T3,RH2ND1
	TRNN	S,UDSX##	;ASSUME USER KNOWS IF HE'S FORMATTING
	PUSHJ	P,CHKMOR	;NOT EVEN MULTIPLE, HAVE TO INSERT A THROW-AWAY WORD
	  JRST	RH2ND1		;NO MORE ROOM, LET IT GO ANYWAY
	MOVN	T3,CHNTCW##(P3)	;COMMPUTE NO OF WORDS TO 0-FILL
	ADDI	T3,200+RH2TLS##	;NO OF WORDS AND LAST+TRA
	LSH	T3,^D22		;POSITION IT
	MOVEM	T3,(P1)		;STORE THE THROW-AWAY IOWD
	TLZ	T3,077777	;JUST LAST+TRA
	AOBJN	P1,RH2ND2	;STORE TCW AND EXIT (AOBJN ALWAYS JUMPS)
RH2ND1:	MOVSI	T3,RH2LST##	;LIGHT LAST-BIT IN IOWD
	IORB	T3,-1(P1)
	LDB	T2,[POINT 11,T3,13] ;GET WORDCOUNT
	TDNE	T3,[17,,-1]	;ADR = 0 IS SPECIAL
	ADD	T3,T2		;ADDR + N
	TLZ	T3,077760	;WDCNT SHOULD GO TO 0
RH2ND2:	MOVEM	T3,CHNTCW##(P3)	;SAVE EXPECTED TERM WORD
	PJRST	TPOPJ##		;AND RETURN TO CALLER
;SUBROUTINE TO CHECK TO SEE IF THE CURRENT FOUR WORD BLOCK IS EXHAUSTED
; AND IF SO GET ANOTHER ONE IF ANY ARE AVAILABLE.  IF THE NEXT FOUR WORD
; BLOCK IT OBTAINS IS ADJACENT TO THE CURRENT ONE, IT SIMPLY RETURNS.  IF
; IT IS NOT, A LINK WORD LINKING THE CURRENT FOUR WORD BLOCK TO THE
; NEW FOUR WORD BLOCK IS SETUP IN THE FOURTH WORD OF THE CURRENT BLOCK
;CALLING SEQUENCE:
;	MOVE	P1,AOBJN POINTER TO CURRENT BLOCK
;	PUSHJ	P,CHKMOR
;	...	RETURN HERE IF NO MORE FOUR WORD BLOCKS
;	...	RETURN HERE IF CURRENT FOUR WORD BLOCK NOT FILLED OR
;		NEXT FOUR WORD BLOCK OBTAINED 
;P1 = AOBJN POINTER TO CURRENT OR NEW BLOCK

CHKMOR::JUMPL	P1,CPOPJ1##	;CONTINUE IF ANY WORDS LEFT IN THIS BLOCK
GETMOR::PUSHJ	P,GCH4WD	;GET 1 CORE BLOCK
	  POPJ	P,		;NO MORE AVAILABLE
	CAIE	T1,1(P1)	;IS THIS BLOCK ADJACENT TO THE LAST BLOCK?
	JRST	GETMR1		;NO, ADD A LINK
	HRLI	P1,-4		;YES, FOUR WORDS LEFT TO GO (LAST WORD IN
				; THE LAST BLOCK AND THREE WORDS IN NEW BLOCK)
	JRST	CPOPJ1##	;RESTORE T2 AND GIVE OK RETURN
GETMR1:
IFN FT22BIT,<
	TRNE	U,4		;RH20?
	HRLI	T1,RH2JMP##	;YES, MAKE RIGHT STYLE JUMP-WORD
	TRC	U,3
	TRCN	U,3		;CHECK CHL TYPE
	HRLI	T1,CCHJGO##	;DX10 STYLE CHL JUMP
>
	MOVEM	T1,0(P1)	;LINK TO THE NEW BLOCK
	MOVE	P1,T1		;P1 = POINTER TO NEW BLOCK
	HRLI	P1,-3		;NUMBER OF WORDS LEFT TO GO IN THE CURRENT BLOCK
	JRST	CPOPJ1##	;AND SKIP RETURN
IFN FT22BIT,<
;ROUTINE USED TO HANDLE 22-BIT CHNLS AND PERFORM IOWD TRANSFORMATIONS
;FOR THE DX10 TAPE CHL. CALLING SEQUENCE:
;	MOVE T1,-WDS TO XFER
;	MOVE P1,ADDRS OF CURRENT IOWD
;	CHARS/WD WAS FOUND IN THE ORIGINAL CALL TO MAPIO
;	PUSHJ P,DXFIX
;	  ...		;RETURN HERE IF NO MORE FREE SPACE
;	  ...		;RETURN HERE IF OK

DXFIX:	TRNE	U,4		;RH20?
	JRST	RH2FIX		;YES, DO DIFFERENTLY
	HRRZ	T4,U
	CAIE	T4,3		;CHECK CHL TYPE
	JRST	[DPB T1,WDCPNT##(U)
		 JRST CPOPJ1##]	;HANDLE NON-DX10 CHLS
	MOVE	T4,-5(P)	;RESTORE CHAR/WD
	IMULI	T1,0(T4)	;CONVERT TO BYTE COUNT
	AOS	0(P1)		;DX10 LIKES ADDRS RATHER THAN ADDRS-1
	HLRZ	T3,U		;FRAME COUNT USER SET
	JUMPE	T3,DXFIX0	;NONE
	MOVNS	T3
	CAML	T3,T1		;MORE THAN HE WANTS?
	MOVE	T1,T3		;YES, GET WHAT WAS REQUESTED
	HRLZ	T3,T1		;FRAMECOUNT
	ADDB	T3,U		;UPDATE MAX LEFT
	TLNN	T3,-1		;ROOM FOR MORE?
	HRROS	U		;NO, INDICATE WE'RE DONE
DXFIX0:	CAML	T1,[-17777]	;ROOM FOR THIS
	JRST	DXFIX2		;YES - JUST STORE AND EXIT
	MOVE	T3,MCHTAB(T4)	;MAX CHARS / XFER CMD
	SUB	T1,T3		;SUBTRACT MAX FOR THIS ONE
	DPB	T3,WDCPNT##(U)	;STORE IN IOWD
	PUSH	P,0(P1)		;SAVE PNTR
	AOBJN	P1,DXFIX1	;SEE IF ROOM FOR MORE
	PUSH	P,T1		;NO -SAVE COUNT
	PUSHJ	P,GETMOR	;GET MORE SPACE
	  JRST	DXFIX3		;RAN OUT OF SPACE
	MOVEI	T2,0		;RESTORE T2
	POP	P,T1		;RESTORE COUNT
DXFIX1:	POP	P,T3		;GET LAST POINTER
	MOVE	T4,-5(P)	;RESTORE T4 (CHARS/WD)
	ADD	T3,MWDTAB(T4)	;ADD MAX WORDS OFFSER
	MOVEM	T3,0(P1)	;NEW PARTIAL PNTR
	JRST	DXFIX0		;5ROCEED

DXFIX2:	DPB	T1,WDCPNT##(U)	;STORE RESIDUE
	JRST	CPOPJ1##	;SUCCESS RETURN

DXFIX3:	POP	P,T1		;PRUNE PDL
	JRST	TPOPJ##		;PRUNE & EXIT (FAIL)
;THE BYTE PACKING MODES OF THE DX10 WILL ALLOW 4,5 & 6 BYTES / WORD
;THESE TABLES ARE USED TO TRANSLATE THIS INFO INTO 1) THE MAX CHARS
;THAT WILL EXACTLY FILL THE 2) MAX NO. OF WDS PER IOWD
;ALLOWING 2^13-1 BYTES / IOWD.
MCHTAB=.-4
	-<17777/4>*4		;4 BYTE/WD = 8188 BYTES
	-<17777/5>*5		;5 BYTE/WD = 8190 BYTES
	-<17777/6>*6		;6 BYTE/WD = 8190 BYTES

MWDTAB=.-4
	17777/4			;4 BYTE/WD = 2047 WDS
	17777/5			;5 BYTE/WD = 1638 WDS
	17777/6			;6 BYTE/WD = 1365 WDS

>	;END IFN FT22BIT

;ROUTINE TO HANDLE RH20 DEVICES
RH2FIX:	SKIPE	(P1)		;UNLESS THROW-AWAY IOWD
	AOS	(P1)		;RH20 LIKES ADDRESS
	MOVNS	T1		; AND POSITIVE WRDCNT
	MOVE	T3,-4(P)
	ADDM	T1,CHNTCW##(T3)	;ACCUMULATE WDCNT
RH2FX1:	CAIG	T1,3000		;IF LESS THAN 12 BITS,
	JRST	RH2FX3		; DONT HAVE TO FIDDLE WITH IT
	MOVEI	T3,3000+RH2TRX## ;ONLY CAN DO 11 BITS IN ONE IOWD
	DPB	T3,WDCPNT##+3	;SAVE THIS IOWD
	SUBI	T1,3000		;ACCUMULATE WHAT WE'VE DONE SO FAR
	PUSH	P,(P1)		;SAVE PARTIAL IOWD
	AOBJN	P1,RH2FX2	;GO IF ROOM FOR ANOTHER IOWD
	PUSH	P,T1		;SAVE WDCNT
	PUSHJ	P,GETMOR	;GET ANOTHER 4-WORD BLOCK
	  JRST	DXFIX3		;NO MORE - GIVE LOSE RETURN
	MOVEI	T2,0		;RESET T2 TO BEGINNING OF PAGE
	POP	P,T1		;RESTORE COUNT
RH2FX2:	POP	P,T3		;RESTORE PARTIAL IOWD
	ADDI	T3,3000		;UPDATE ADDR
	MOVEM	T3,(P1)		;SAVE NEW IOWD (ONLY ADR USED)
	JRST	RH2FX1		;AND SET WDCNT FOR NEXT PIECE
RH2FX3:	TRO	T1,RH2TRX##	;INDICATE THIS IS A DATA-IOWD
	DPB	T1,WDCPNT##+3	;STORE WDCNT AND TRA-BIT
	JRST	CPOPJ1##	;INDICATE WE WON
;ROUTINE TO RETURN FREE CORE USED FOR MAPPING IOWDS.
;CALLING SEQUENCE:
;	MOVE	T1,ADDRESS OF IOWD LIST
;	PUSHJ	P,RTNIOW
;	ALWAYS RETURN HERE

RTNIOW::PUSHJ	P,SAVE1##	;SAVE P1
	HRRZ	P1,T1		;P1 = ADDRESS OF THE IOWD LIST
RTNIO1:	MOVEI	T1,1		;GIVE BACK ONE FOUR WORD BLOCK
	HRRZ	T2,P1		;ADDRESS OF THE BLOCK
	MOVE	T3,3(P1)	;LAST WORD OF BLOCK
	TLNN	T3,577777	;AN IOWD?
	SKIPA	P1,T3		;NO, THEN THIS IS THE LAST BLOCK
				; OR A LINK TO THE NEXT BLOCK
	ADDI	P1,4		;ADDRESS OF THE NEXT BLOCK
				; (ITS ADJACENT TO THE CURRENT BLOCK)
	PUSHJ	P,RCH4WD	;RETURN BLOCK TO MONITOR FREE CORE
	JUMPE	P1,CPOPJ##	;JUMP IF THIS IS THE LAST BLOCK
	JRST	RTNIO1		;GIVE UP ALL THE BLOCKS


;ROUTINE TO OBTAIN A LOWER-CORE 4-WORD BLOCK
GCH4WD::MOVEI	T1,1		;JUST WANT 1 BLOCK
	MOVEI	T2,LOWPTR##	;POINT TO LOWER-CORE FREE-CORE TABLE
	PUSHJ	P,GETBIT##	;GET, SET THE BIT
	  POPJ	P,		;NONE AVAILABLE, LOSE
	LSH	T1,2		;CONVERT TO 4-WORD STYLE
	ADD	T1,LOWLOC##	;CONVERT TO ACTUAL ADDRESS
	SETZM	3(T1)		;ZERO THE LAST WORD OF THE CURRENT BLOCK
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN


;ROUTINE TO RETURN LOWER-CORE 4-WORD BLOCKS
RCH4WD::SUB	T2,LOWLOC##	;CONVERT TO RELATIVE ADDRESS
	LSH	T2,-2		;/4 TO CONVERT TO BITS
	IDIVI	T2,^D36		;COMPUTE WORD ADR, POSITION IN WORD
	HRLS	T2
	ADD	T2,LOWPTR##	;SET AOBJN POINTER FOR SETZRS
	PJRST	SETZRS##	;CLEAR THE BITS AND RETURN
;SUBROUTINE TO CHECK TO SEE IF THE CURRENT I/O OPERATION IS A
; HIGH SEGMENT SAVE
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	MOVE	R,LOW SEGMENT ADDRESS
;	PUSHJ	P,CHKHS
;	RETURN HERE IF NORMAL I/O
;	RETURN HERE IF HIGH SEGMENT SAVE

CHKHS:	PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,DEVMOD(F)	;DEVICE DESCRIPTORS
	TLNE	P1,DVDSK	;DSK I/O?
	SKIPL	DEVSWP##(F)	;YES, SWAPPING I/O?
	SKIPL	P1,JOBHCU##(R)	;NO, IS A SAVE OR GET IN PROGRESS?
	POPJ	P,		;NOT SAVE/GET
	TLNE	P1,3		;DOING THE I/O TO SAVE A HIGH SEGMENT?
	POPJ	P,		;NO, NORMAL I/O
IFN FTEXE,<
	PUSH	P,J		;SAVE J
	LDB	J,PJOBN##	;GET CURRENT JOB NUMBER
	PUSHJ	P,CHKEXE##	;IS THIS AN EXE FILE SAVE?
	JRST	JPOPJ##		;YES, EXIT AND DO NOTHING
	POP	P,J		;NO, RESTORE J
>;END OF IFN FTEXE
	PJRST	CPOPJ1##	;YES, GIVE HIGH SEGMENT SAVE IN PROGRESS RETURN

;SUBROUTINE TO RETURN THE USER VIRTUAL ADDRESS OF THE
; CHECKSUM WORD
;CALLING SEQUENCE:
;	MOVE	T1,IOWD TO BE USED IN THE FILE TRANSFER (UNRELOCATED)
;	MOVE	R,LOW SEGMENT PROTECTION,, RELOCATION
;	PUSHJ	P,UVACKS
;	ALWAYS RETURN HERE - T2 = UVA OF THE CHECKSUM
;PRESERVES T1

UVACK:
UVACKS::HRRZ	T2,T1		;ADDRESS I/O WILL BE DONE FROM OR TO
	PUSHJ	P,CHKHS		;SEE IF SAVING A HIGH SEGMENT
	  POPJ	P,		;NO, NORMAL I/O RETURN
	SUBI	T2,.VJDT-.JDAT	;T2=ADDRESS WITHIN THE HIGH SEGMENT WHERE
				; OUTPUT WILL START
	PUSH	P,T2		;SAVE THAT
	PUSH	P,J		;SAVE J
	PUSH	P,T1		;AND T1
	LDB	J,PJOBN##	;GET JOB NUMBER
	PUSHJ	P,HSVAD##	;GET THE STARTING VIRTUAL ADDRESS OF THE
				; HIGH SEGMENT
	POP	P,T1		;RESTORE T1
	POP	P,J		;AND J
	ADDM	T2,(P)		;(P)=UVA OF FIRST WORD -1 TO BE OUTPUT
	JRST	T2POPJ##	;T2=UVA, AND RETURN
;SUBROUTINE TO GET EVM IF NEEDED FOR OUTPUT
;CALLING SEQUENCE:
;	MOVE	F,DDB ADDRESS
;	PUSHJ	P,GTOEVM
;	RETURN HERE
;NEVER RETURN IF TO MUCH EVM IS REQUIRED

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


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

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

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

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

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

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

DMPEV::
	PUSHJ	P,SAVE4##	;SAVE P1-P4
IFN FTVM,<
	PUSH	P,U		;SAVE U
	MOVEI	U,0		;ASSUME THE DEVICE DOES NOT REQUIRE EXEC VIRTUAL
				; MEMORY TO DO I/O (DSK, MTA, TTY, PTY)
>
	PUSHJ	P,MAPDEV	;NOT A KA10, NEED EVM TO DO I/O?
IFE FTVM,<
	  POPJ	P,		;EVM NOT REQUIRED (KA10, CHANNEL DEVICE, TTY, OR PTY)
>
IFN FTVM,<
	TLO	U,400000	;EVM NOT REQUIRED - SET U NEGATIVE
>
	PUSH	P,T1		;SAVE DISPATCH ADDRESS
	PUSH	P,M		;SAVE THE UUO FOR THE DEVICE ROUTINE
	SOS	M		;COMPENSATE FOR GETWD1
	MOVEI	P2,0		;LARGEST WORD COUNT SEEN SO FAR
	MOVEI	P3,10000	;GUARD AGAINST A LOOP (GOTO IOWDS)
DMPEV1:	PUSHJ	P,GETWD1##	;GET AN IOWD
	JUMPE	T1,DMPEV4	;JUMP IF LAST IOWD IN THE LIST
	HLRO	P1,T1		;THIS IOWD'S WORD COUNT
	TLNE	T1,-1		;A GOTO WORD?
	JRST	DMPEV2		;NO, A REAL IOWD
	HRRI	M,-1(T1)	;A GOTO WORD (POINTS TO THE NEXT IOWD)
	JRST	DMPEV3		;GET NEXT IOWD
DMPEV2:	MOVNS	P1		;P1 = POSITIVE WORD COUNT FOR THIS IOWD
	CAMLE	P1,P2		;GREATER THAN THE LARGEST WORD COUNT SEEN SO FAR?
	MOVE	P2,P1		;YES, REMEMBER IT AS LARGEST SEEN
IFN FTVM,<
	PUSHJ	P,CHKHS		;HIGH SEGMENT SAVE?
	  JRST	DMPE2A		;NO
	PUSH	P,T1		;YES, SAVE IOWD
	PUSHJ	P,HSVAD##	;GET START ADR OF HI SEG
	POP	P,T1		;RESTORE START ADR OF IOWD
	ADDI	T1,-1000(T2)	;POINT TO START OF HIGH SEG
DMPE2A:	MOVEI	T1,1(T1)	;START ADR OF THE IOWD
	MOVE	T2,P1		;TOP ADR OF THE IOWD
	ADDI	T2,-1(T1)
	PUSHJ	P,TRNGE##	;MAKE SURE THE REQUIRED PAGES ARE IN CORE
>
DMPEV3:	SOJG	P3,DMPEV1	;GET NEXT IOWD IN THE LIST
	JRST	ADRERR##	;TOO MANY IOWDS (PROBABLY A GOTO WORD LOOP,
				; STOP THE JOB AND REPORT THE ERROR)

DMPEV4:	POP	P,M		;RESTORE THE UUO AND THE POINTER TO THE FIRST
				; IOWD IN THE LIST
IFN FTVM,<
	JUMPL	U,DMPEV5	;DONT ACTUALLY NEED EVM IF U NEGATIVE
>
	PUSHJ	P,GETWDU##	;GET THE FIRST IOWD IN THE LIST AGAIN
	HRRZ	T3,T1		;USER VIRTUAL ADDRESS WHERE I/O WILL START
	MOVE	T1,P2		;NUMBER OF WORDS OF EXEC VIRTUAL MEMORY REQUIRED
				; TO COVER THE LARGEST IOWD FOUND IN THE IOWD
				; LIST
	PUSHJ	P,GTEVBF	;GET ENOUGH EVM TO COVER THE LARGEST WORD IN
				; THE LIST (WAIT UNTIL AVAILABLE IF NECESSARY)
	JRST	ADRERR##	;WHOOPS! NEVER WILL BE ENOUGH
	MOVEM	T1,DEVEVM(F)	;DEVEVM = BYTE (18)0(9)EV PAGE #(9)# OF PAGES
IFE FTVM,<
	PJRST	TPOPJ##		;RESTORE T1 AND RETURN
>
IFN FTVM,<
DMPEV5:	POP	P,T1		;RESTORE DISPATCH ADDRESS
	JRST	UPOPJ##		;RESTORE U AND RETURN
>
;ROUTINE TO RETURN ANY EVM A DEVICE MAY HAVE WHEN A SHARABLE RESOURCE
; WHICH CURRENTLY BELONGS TO THE JOB WHICH HAS THE DEVICE IS GIVEN UP.
;CALLING SEQUENCE:
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK OR 0 IF NONE
;	PUSHJ	P,RTEVM
;ALL ACS ARE RESPECTED.

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

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

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

	HRLI	T3,R		;LITE R IN THE LEFT HALF TO SIGNAL USER
				; VIRTUAL ADDRESS
	PJRST	RTIEVM		;GIVE BACK THE EVM

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

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

	HRLI	T3,R		;LITE R IN THE LEFT HALF TO SIGNAL USER
				; VIRTUAL ADDRESS
	PJRST	RTOEVM		;GIVE BACK THE EVM
;ROUTINE TO RETURN SLOTS IN THE EXEC MAP USED TO MAP USER BUFFERS
;CALLING SEQUENCE:
;
;	MOVE	T3,USER VIRTUAL ADDRESS OF BUFFER
;	PUSHJ	P,RTNEVM
;	ALWAYS RETURN HERE

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


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

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

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


;ROUTINE TO INVALIDATE ENTIRE CACHE AND VALIDATE CORE
; ALWAYS RETURN CPOPJ, SAVING ALL T ACS.
; LOOP IN ACS WHILE WAITING FOR FLUSH COMPLETION TO MINIMIZE 
; MEMORY INTERFERENCE.

CSDMP::	PUSHJ	P,SAVT		;SAVE T ACCUMULATORS
	DMOVE	T1,CSHWAT	;CACHE WAITING INSTRUCTIONS
	MOVE	T3,CSHWT1
	SWPUA			;SWEEP - UPDATE ALL PAGES, INVALIDATE CACHE
	JSP	T4,T1		;WAIT IN ACS
IFN FTMS,<
	PUSHJ	P,SCPCDB##	;SAVE P4 AND SETUP CDB ADDRESS IN P4
	AOS	.CPCSN##(P4)	;COUNT A CACHE SWEEP
				; MUST BE INCREMENTED AFTER SWEEP
				; IS FINISHED IN ORDER FOR DUAL
				; CPU CACHE SWEEP SCHEME TO WORK.
				; (DON'T WANT ANOTHER CPU TO RUN A
				; JOB IF CACHE SWEEP IS ONLY HALF FINISHED)
>
	POPJ	P,		;RETURN


CSHWAT:	CONSZ	APR,LP.CSB	;WAIT FOR CACHE SWEEP TO HAPPEN
	JRST	T1
CSHWT1:	JRST	(T4)		;RETURN TO CALLER
SUBTTL	SEGCON - SEGMENT CONTROL MODULE

;ROUTINE TO SAVE THE ABSOLUTE ADDRESS OF A HIGH SEGMENT AND RETURN
; ITS VIRTUAL ADDRESS (CALLED FROM REMAP)
; J=HI SEG NUMBER
; T1=NEW HI SIZE
; T2=WHERE,, NEW LOW SIZE

NEWHGH::PUSHJ	P,SAVE3##	;SAVE P1-P3
	HRRZ	P2,T2		;SAVE WHERE,,NEW LOW SEGMENT SIZE
	HLRZS	T2		;WHERE TO PUT THE HIGH SEGMENT
	ANDI	T2,777000	;MAKE SURE ITS ON A PAGE BOUNDARY
	JUMPN	T2,NEWHG0	;JUMP IF HIGH SEGMENT STARTING ADDRESS SPECIFIED
	TRNE	P2,400000	;IS THE LOW SEGMENT BIGGER THAN 128K?
	SKIPA	T2,P2		;YES, HIGH SEGMENT ORIGIN IS FIRST PAGE ABOVE
				; THE LOW SEGMENT
	MOVEI	T2,377777	;NO, HIGH SEGMENT GOES AT 400000
	MOVEI	T2,1(T2)	;HIGH SEGMENT ORIGIN (ALSO CLEAR LEFT HALF OF T2)
NEWHG0:	MOVE	P3,.C0JOB##	;CURRENT JOB NUMBER
	MOVEM	R,JBTADR##(P3)	;STORE PREVIOUS PROTECTION,,JDAT IN CASE OF ERROR
IFN FTVM,<
	MOVEI	T3,1(T1)	;NUMBER OF WORDS IN NEW HIGH SEGMENT
	MOVEI	T1,1(P2)	;ADDRESS WHERE REMAP STARTS
	LSHC	T1,W2PLSH##	;T1=FROM PAGE, T2=TO PAGE
	LSH	T3,W2PLSH##	;NUMBER OF PAGES
	HLRZ	T4,SGAEXT##(R)	;FILE EXTENSION
	SUBI	T4,'SHR'	;T4=0 IF THE HIGH SEGMENT IS SHARABLE
	PJRST	NREMAP##	;REMAP IT
>
IFE FTVM,<
	JUMPLE	T2,CPOPJ##	;DON'T ALLOW HIGH SEGMENT AT PAGE ZERO
	HRRZ	P1,T1		;NEW HIGH SEGMENT SIZE
	ADDI	P1,(T2)		;HIGH SEGMENT SIZE PLUS WHERE IT STARTS
	TLNN	P1,-1		;WILL THE END OF THE HIGH SEGMENT BE OUTSIDE
				; OF THE USER'S ADDRESSING SPACE? (.GT. 256K)
	CAIG	T2,(P2)		;OR WILL THE LOW SEGMENT AND HIGH SEGMENT OVERLAP?
	POPJ	P,		;YES, LOSE
	HRLM	P2,JBTADR##(P3)	;STORE NEW HIGHEST ADDRESS IN THE LOW SEGMENT
	HRLI	T1,.VJDT	;EXEC VIRTUAL ADDRESS OF THE VESTIGUAL JOB
				; DATA AREA
	LSH	T2,W2PLSH##	;CONVERT HIGH SEGMENT ADDRESS TO PAGE NUMBER
	DPB	T2,JBYHSO##	;STORE ORIGIN OF THE HIGH SEGMENT
	ROT	P2,W2PLSH##-1	;CONVERT TO PAGE NUMBER AND ODD OR EVEN PAGE
				; IN THE HIGH ORDER BIT
	TRZ	P2,400000	;DON'T LET BIT 8 OF USER-SPECIFIED
				; HISEG ORIGIN SPILL OVER
	MOVEI	P1,.UPMP(P2)	;ADDRESS OF THE WORD IN THE MAP WHICH CONTAINS
				; THE ABSOLUTE PAGE NUMBER OF THE LAST PAGE
				; OF THE LOW SEGMENT
	HRLI	P1,222200	;ASSUME AN EVEN PAGE NUMBER (I.E., MAPPED BY THE
				; LEFT HALF WORD)

	SKIPGE	P2		;IS IT EVEN?
	HRLI	P1,002200	;NO, ODD - MAPPED BY THE RIGHT HALF WORD
	LDB	P2,P1		;GET ABSOLUTE PAGE NUMBER OF LAST PAGE IN
				; THE LOW SEGMENT
	TRZ	P2,760000	;CLEAR ACCESS BITS
	HLLZS	PAGTAB(P2)	;INDICATE LAST PAGE IN THE LOW SEGMENT IN PAGTAB
	ILDB	T2,P1		;GET THE ABSOLUTE PAGE NUMBER OF THE FIRST
				; PAGE IN THE HIGH SEGMENT
	DPB	T2,JBYHSA##	;STORE IT FOR MAPPING THIS HIGH SEGMENT INTO
				; FUTURE USER'S ADDRESSING SPACES
	TRO	T2,PM.ACC+PM.WRT+PM.CSH  ;ACCESS ALLOWED AND WRITABLE
	HRLM	T2,.UPMP+.MVJDT	;MAP .VJDT IN THE PER-PROCESS MAP
	JRST	CPOPJ1##	;GIVE OK RETURN (HIGH SEGMENT WON'T OVERLAP
				; LOW SEGMENT
>
;ROUTINE TO MAKE ANY WORD OF ANY JOB ADDRESSABLE
; (IN FACT WRITABLE) BY MAPPING IT THROUGH THE
; PER PROCESS MAP OF THE CURRENT JOB
;CALLING SEQUENCE:
;	MOVE	T2,USER VIRTUAL ADDRESS TO BE MAPPED
;	MOVE	J,JOB NUMBER OF JOB CONTAINING THE WORD
;	PUSHJ	P,MAPWRD
;OR	PUSHJ	P,MAPHC		;TO MAP JOBHCU
;	...	RETURN HERE
;ON RETURN FROM CALL TO MAPWRD T2=EVA OF WORD
;ON RETURN FROM CALL TO MAPHC R=JOBHCU
;MAPHC PRESERVES T2

MAPHC::	PUSH	P,T2		;SAVE T2
IFE FTVM,<
	MOVEI	T2,0		;JOB DATA AREA STARTS AT USER 0
>
IFN FTVM,<
	MOVSI	T2,1		;UVA OF THE UPMP
>
	PUSHJ	P,MAPWRD	;MAKE THE JOB DATA AREA ADDRESSABLE
IFE FTVM,<
	HRR	R,T2		;RH(R)=EVA OF JOB DATA AREA
>
IFN FTVM,<
	HRRI	R,.JDAT-.UPMP(T2)
>
	JRST	T2POPJ##	;RESTORE T2 AND RETURN

MAPWRD::
	PUSHJ	P,SCPCDB##	;POINT P4 AT THIS CPUSCDB
	PUSH	P,T2		;SAVE UVA
	ROT	T2,W2PLSH##-1	;CONVERT TO PAGE #/2 - REMAINDER IN HIGH BIT
	MOVEI	T1,.TEMP(T2)	;T1=ADDRESS OF TEMP. PP SLOT
	HRLI	T1,222200	;ASSUME WORD IN EVEN PAGE
	SKIPGE	T2		;IS IT?
	HRLI	T1,002200	;NO - ODD PAGE
	HRRZ	T2,JBTUPM##(J)	;ADDRESS OF TARGET JOB'S UPMP
	TRO	T2,PM.ACC+PM.WRT;INSURE ACCESS ALLOWED
	HRRM	T2,.UPMP+.MTEMP	;MAKE THE TARGET JOB'S UPMP ADDRESSABLE
	CLRPGT	(0,.TEMP)	;CLEAR THE AM SO MAP WILL BE LOOKED
				; AT NEXT.
	LDB	T2,T1		;GET MAPPING FOR PAGE CONTAINING WORD
	TRO	T2,PM.ACC+PM.WRT;MAKE SURE CAN WRITE
	HRRM	T2,.UPMP+.MTEMP	;MAKE THE WORD ADDRESSABLE
	CLRPGT	(0,.TEMP)	;CLEAR AM FOR THIS PAGE
	MOVEI	T1,.TEMP/1000	;PAGE # IN EV ADDRESSING SPACE
	DPB	T1,[POINT 9,(P),26] ;EVA OF WORD
	JRST	T2POPJ##	;RESTORE EVA AND RETURN
;ROUTINE TO MAKE AVAILABLE A PAGE MAP SLOT IN EVA SPACE
;MAY ONLY BE CALLED AT INTERUPT LEVEL
;CALLING SEQUENCE:
;	MOVE	P4,ADR OF CPU DATA BLOCK
;	PUSHJ	P,MAPLOC
;	RETURN HERE
;   C(T1) := BYTE PNTR TO EPMP SLOT
;   C(T3) := RELATIVE PAGE # IN EPMP

MAPLOC::CONI	PI,T1		;GET PIS IN PROGRESS
	ANDI	T1,II.IPA	;CLEAR ALL BITS EXCEPT PIS IN PROGRESS
	JFFO	T1,.+2		;FIND OUT THE HIGHEST PI IN PROGRESS, I.E.,
				; THE ONE THAT THIS CODE IS BEING EXECUTED AT
	STOPCD	.,STOP,NPP,	;++NO PI IN PROGRESS
				; NO PAGE IN THE EXEC MAP FOR MAPPING THE SCAN
	SUBI	T2,25		;T2=0-6 FOR PI 1-7 IN PROGRESS
	MOVE	T3,T2		;CALCULATE THE EXEC VIRTUAL ADDRESS FOR
	LSH	T3,P2WLSH##	; USE IN THE SWEEP RELATIVE TO PI TEMPORARIES.
	ROT	T2,-1		;DIVIDE BY 2 AND PUT THE REMAINDER IN HIGH ORDER BIT
	MOVEI	T1,.MERPL(T2)
	ADD	T1,.CPTOS##(P4)	;T1=ADDRESS IN THE MAP OF SLOT USED FOR SCAN
	HRLI	T1,(<POINT 18,0,17>) ;ASSUME LEFT HALF WORD
	SKIPGE	T2		;IS IT AN ODD PAGE?
	HRLI	T1,(<POINT 18,0,35>) ;YES, THEN ITS THE RIGHT HALF WORD
	POPJ	P,		;RETURN
SUBTTL	ERRCON - ERROR HANDLING MODULE

;SUBROUTINE TO SWEEP MEMORY TO FIND ADDRESS AND CONTENTS OF BAD WORDS
;IT CALLS CPU INDEPENDENT SUB.(PARERR##) TO RECORD DATA ON EACH BAD WORD
;CALL:	MOVE	P4,ADR OF CPU DATA BLOCK
;	PUSHJ	P,@.CPMPS##(P4)
;	ALWAYS RETURN WHEN SWEEP OVER (EVEN IF SERIOUS ERROR)
;SWEEP CORE IN ASCENDING ADDRESSES EVEN THOUGH SLOWER, SO DATA STORED ASCENDING
; FOR ERROR REPORTING WITH DAEMON

IFN FTMEMPAR,<			;MEMORY PARITY ANALYSIS
	XP	PARDLY,20	;NO. OF SOJ INSTR. TO DELAY SO PARITY CAN BE TESTED

CPLMPS::PUSHJ	P,SAVE4##	;SAVE P1-P4 FOR BAD ADR. CONTENTS AND WORKING ACS
	PUSHJ	P,MAPLOC	;GET EXEC MAP SLOT
	PUSH	P,T1		;SAVE BYTE POINTER TO EXEC MAP SLOT
	MOVEI	P1,0		;SCAN ALL OF MEMORY STARTING WITH FAST ACS
				; FOR CONVENIENCE (KI10 ALWAYS HAS FAST ACS)
	MOVEI	P3,PM.ACC+PM.WRT
				;START AT PAGE 0. PAGE ATTRIBUTES TO ALLOW
				; ACCESS AND WRITING (TO ATTEMPT REPAIR BELOW)
	SETOM	.CPPSP##(P4)		;FLAG THAT WE ARE IN A PARITY SWEEP (FOR TRAP ROUTINE)
	LDB	T4,[POINT 14,MEMSIZ##,26]
				;T4=NUMBER OF PAGES TO SCAN (AVOID NXM)
	SKIPA	U,[POINT 1,NXMTAB##] ;BYTE POINTER TO TABLE REFLECTING EXISTANT MEMORY
MPSLP1:	AOS	P3		;STEP TO NEXT PAGE
	SOJL	T4,MPSLP5	;RESTORE T1 AND RETURN IF SCANNED ALL OF MEMORY
	ILDB	T1,U		;DOES THIS PAGE EXIST?
	JUMPN	T1,MPSLP1	;JUMP IF NOT TO AVOID REFERENCING NON-EXISTANT
				; PAGE
	MOVEI	P1,.ERPIL(T3)	;START AT THE BEGINNING OF THE PAGE
	DPB	P3,(P)		;MAP THE CURRENT PAGE
	CLRPGT	(P4)		;CLEAR THE ASSOCIATIVE SO THE NEW
				; WILL BE USED

	MOVEI	T2,1		;1 BLT/PAGE
	MOVEI 	P2,.EPMPE##(P1)	;END OF BLT RANGE
	HRL	P1,P1		;BLT TO SELF
MPSLP2:
;SPECIAL INSTRUCTION ADDRESS - REFERENCE MEMORY TO SEE IF BAD
	XP	CPLMPI,MPI+3	;PC VALUE WHEN APR GETS PARITY INT.
				;USED BY APR PI ROUTINE TO MAKE INSTR. SKIP
	CONO	PI,PIOFF	;TURN OF THE PI SYSTEM
	MOVEI	T1,@.CPEBR##(P4)  ;GET EBR
	TRZ	T1,LG.CSL+LG.CSW  ;TURN OF LOOK + LOAD
	CONO	PAG,@T1		;SO WE CAN REFERENCE MEMORY WITHOUT THE CACHE
	SETOM	.CPPSP##(P4)	;SET SWEEPING FLAG IN MEMORY BECAUSE
				;TRAP OCCURS WITH CACHE OFF!
	CONSZ	PI,@.CPAPP##(P4)  ;APR PI IN PROGRESS (I.E. SCANNING
				; AT APR INTERRUPT LEVEL?
	TDZA	T1,T1		;YES, DON'T WAIT AT THE SOJG.
	MOVEI	T1,PARDLY	;NO. OF SOJ TO INSURE PARITY FLAG INT. OR ON
MPI:	BLT	P1,(P2)		;DOES THIS PAGE HAVE BAD PARITY? 
	CONO	PAG,@.CPEBR##(P4)	;TURN THE CACHE BACK ON
	CONO	PI,PION		;AND ALSO THE PI SYSTEM
	SOJG	T1,.		;DELAY HERE SO APR INT. WILL OCCUR WITH
				; PC AT A KNOWN PLACE IN MONITOR
	JRST	[IFN FTMEMNXM,<
		TRNN S,UE.PEF
		JRST	[CONSO APR,LP.NXM
			JRST MPSLP4
			CONO APR,LP.CSF!LP.NXM
			JRST MPSLP3]>
		CONSO APR,LP.PAR
		SKIPE .CPPTH##(P4)	;DID A PARITY TRAP HAPPEN?
		SKIPA			;EITHER TRAP OR INTERRUPT HAPPENED
		JRST MPSLP4
		CONO APR,LP.CSF!LP.PAR!LP.SBE
		JRST	.+1]

;HERE ON BAD WORD FOUND (NXM OR PARITY) - APR OR PI 7 (APR INTERRUPT ADDED 2 TO PC)

IFN FTMEMNXM,<
	TRNE	S,UE.PEF	;A PARITY ERROR?
>
	SETZM	(P1)		;FIX UP BAD PARITY, BUT DON'T ATTEMPT
				; TO STORE OLD CONTENTS, AS THE AR
				; PARITY TRAP MAKES IT IMPOSSIBLE FOR
				; THE SKIP INSTRUCTION TO COMPLETE
MPSLP3:	PUSH	P,T1

	PUSH	P,T2
	MOVSI	T1,DMACLR		;NOW CLEAR THE ERROR BITS INT THE DMA
	SBDIAG	T1			;WITH FUNCTION 0
	POP	P,T2
	POP	P,T1
	MAP	T1,(P1)		;GET THE ADDRESS WHICH
				; CORRESPONDS TO THE EXEC VIRTUAL ADDRESS IN P1
	PUSH	P,P2	;SAVE THE END OF PAGE AC
	PUSH	P,P1		;SAVE THE EVA
	PUSH	P,T3		;SAVE THE POSITION IN THE MAP
	PUSH	P,T2
	PUSH	P,T4		;SAVE # OF PAGES TO SCAN
	LDB	P1,[POINT 22,T1,35]
				; P1=ABSOLUTE ADDRESS OF THE WORD WITH BAD PARITY
	PUSHJ	P,CPLASN	;YES, CONVERT TO SEG NUMBER, (J), REL ADR (T1)
	  SETOM	T1		;FLAG ABS. ADR NEITHER IN MONITOR NOR A SEGMENT.
	MOVE	P2,.CPTBD##(P4)	;GET BAD DATA WORD STORED BY THE TRAP ROUTINE
				;FOR ERROR REPORTING
	PUSHJ	P,PARRBD##	;RECORD BAD DATA (T1=REL ADR, P1=BAD ADR,P2=
				; BAD CONTENTS)
	POP	P,T4		;RESTORE T4
	POP	P,T2		; AND T2
	POP	P,T3		; AND T3
	POP	P,P1		; AND P1
	POP	P,P2		; AND P2
	SETZM	.CPPTH##(P4)	;CLEAR FLAG THAT TRAP HAPPENED
	AOS	P1		;INCREMENT TO ADDR
	HRL	P1,P1		;AND THE FROM ADDR
	JRST	MPSLP2		;AND CONTINE THE BLT.
MPSLP4:	SOJLE	T2,MPSLP1	;IF CURRENT PAGE IS FINISHED, MAP THE NEXT PAGE

MPSLP5:	SETZM	.CPPSP##(P4)	;CLEAR FLAG THAT WE ARE IN SWEEP
	PUSHJ	P,CSDMP		;SWEEP THE CACHE TO FIX BAD PARITY IN MEMORY
	JRST	TPOPJ		;RESTORE T1 AND RETURN
>	;STILL IN FTMEMPAR CONDITIONAL
IFN FTMEMPAR!FTLOCK!FTMEMNXM,<
;SUBROUTINE - ABSOLUTE (ADDRESS TO) SEGMENT NUMBER
;CALL:	MOVE	P1,ABS.ADR(18 BIT FOR KA-10, 22 BIT FOR KI10)
;	TLO	P1,400000	;IF VIRTUAL ADDRESS IS NOT REQUIRED
;	PUSHJ	P,@CP.ASN(P4)
;	  ERROR RETURN IF NOT IN MONITOR OR A HIGH OR LOW SEGMENT,
;	OK RETURN J=0 IF IN MONITOR, OR HIGH OR LOW SEG, T1=REL. ADR
;CAN BE CALLED AT APR PI OR CLK PI(7).  CANNOT BE CALLED AT UUO LEVEL
;NOTE:  REL ADR. IS NOT VIRTUAL ADR ON HIGH SEGS
; SINCE THAT IS JOB DEPENDENT IF LOW SEG GR 400000

CPIASN::
CPLASN::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,PAGTAB(T1)
	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
	CAIE	T1,(T3)		;BAD WORD IN THIS UPMP?
	SOJG	T2,AUPLOP	;NO, SCAN ALL USER PAGE MAP PAGES
	JUMPG	T2,CPOPJ1##	;JUMP IF THE PARITY ERROR WAS IN A UPMP
	PUSHJ	P,SSEUB
;LOOP - SCAN ALL HIGH AND LOW SEGS
ASNLOP:	MOVEI	T1,0		;ASSUME PARITY ERROR IS IN PAGE 0 OF THIS SEGMENT
IFN FTVM,<
	MOVSI	T2,SHRSEG	;SHARABLE SEGMENT BIT
	CAILE	J,JOBMAX##	;A LOW SEGMENT?
	TDNE	T2,JBTSTS##(J)	;NO, IS IT SHARABLE
>
	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 SEGMENT
				; GET ITS STARTING PAGE NUMBER
	CAILE	J,JOBMAX##	;IS IT A HIGH SEGMENT?
	JRST	ASNHGH		;YES
	PUSHJ	P,STEUB		;NO, MAKE ITS FIRST PHYSICAL PAGE NUMBER ADDRESSABLE
				; LOW SEGMENT ADDRESS IN THE UPMP IS
				; VALID SINCE PARITY ERROR IS NOT IN A
				; UPMP (VERIFIED ABOVE)
	LDB	T2,JBYLSA##	;STARTING PAGE NUMBER OF LOW SEGMENT
ASNHGH:	CAIN	T2,(T3)		;IS THIS PAGE THE SAME PAGE WHICH CONTAINED AN ERROR?
	JRST	ASNFND		;YES, COMPUTE THE RELATIVE ADDRESS OF THE
				; WORD WITHIN THE SEGMENT WHICH CONTAINS THE ERROR
	HRRZ	T2,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
;HERE TO COMPUTE RELATIVE ADDRESS OF PARITY ERROR BY CONCATINATING RELATE
; PAGE NUMBER AND WORD NUMBER WITHIN THE PAGE
ASNFND:	JUMPL	P1,CPOPJ1##	;RETURN IF NOT INTERESTED IN VIRTUAL ADR
IFN FTVM,<
	CAIG	J,JOBMAX##	;A SHARABLE HIGH SEGMENT?
	PUSHJ	P,PHYPVP##	;NO, CONVERT FROM PHYSICAL TO VIRTUAL PAGE NUMBER
>
	LSH	T1,P2WLSH##	;MOVE PAGE NUMBER TO PAGE NUMBER FIELD
	DPB	P1,[POINT 9,T1,35]
				; AND WORD NUMBER
	JRST	CPOPJ1##	;AND GIVE OKAY RETURN
>	;END IFN FTMEMPAR!FTLOCK!FTMEMNXM
IFN FTMEMNXM,<

;SUBROUTINE TO FIX CORE ALLOCATION TABLES AFTER NON-EXISTANT MEMORY
; IS ENCOUNTERED
;CALLING SEQUENCE:
;	MAKE NXMTAB REFLECT CURRENT STATE OF MEMORY, GIVE BACK CORE
;	BELONGING TO ALL SEGMENTS WHICH OVERLAP NXM, AND
;	PUSHJ	P,CPINXF	;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.

CPINXF::
CPLNXF::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,PAGTAB(T1)	;PAGE ALREADY MARKED AS NON-EXISTANT?
	TDNN	T3,NXMTAB##(T2)	;NO, IS IT NON-EXISTANT NOW?
	JRST	CPINX2		;NO, FORGE AHEAD
	SKIPL	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
	HLLM	P1,PAGTAB(T1)	;AND MARK THIS PAGE AS NOW 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,PAGTAB(T1)	;IS THIS PAGE NOW NON-EXISTANT?
	JRST	CPINX5		;NO
	MOVE	T2,PAGTAB(T1)	;YES, LINK FREE CORE LIST AROUND THE PAGE
	HRRZM	T2,PAGPTR##	;STORE NEW FIRST PAGE ON THE 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:	MOVE	T1,T2		;CURRENT INDEX INTO PAGTAB
CPINX5:	HRRZ	T2,PAGTAB(T1)	;NEXT PAGE IN PAGTAB
	JUMPE	T2,CPINX6	;JUMP IF THIS IS THE END OF THE FREE CORE LIST
	TDNN	P1,PAGTAB(T2)	;IS THIS PAGE NOW NON-EXISTANT?
	JRST	CPINX4		;NO
	HRRZ	T2,PAGTAB(T2)	;YES, LINK THE FREE CORE LIST AROUND IT
	HRRM	T2,PAGTAB(T1)	; ..
	SOS	CORTAL##	;DECREMENT THE COUNT OF POTENTIALLY FREE PAGES
	SOS	BIGHOL##	;AND THE COUNT OF FREE PAGES
	JRST	CPINX5		;LOOP OVER THE ENTIRE FREE CORE LIST

; STILL IN FTMEMNXM
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,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
	HRRM	T2,CORLST##	;STORE THAT FOR CHKTAL
	LSH	T4,P2WLSH##	;HIGHEST EXISTANT ADDRESS + 1
	MOVEM	T4,MEMSIZ##	;STORE THAT AS THE SIZE OF MEMORY
	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 TO LARGE TO BE SWAPPED IN
	POPJ	P,		;RETURN

> ;END FTMEMNXM
IFN FTMONL,<

,;HERE TO SET MEMORY ON LINE, T1 = FIRST PAGE TO SET ON LINE, T2 = LAST
; PAGE + 1
MEMONL::HRLZ	S,T1		;STARTING PAGE TO SET ON LINE
	HRR	S,T2		;HIGHEST PAGE TO SET ON LINE
	PUSH	P,S		;SAVE THAT
	SKIPN	JBTADR##(J)	;DOES THIS JOB HAVE CORE?
	PUSHJ	P,GETMIN##	;NO, GET A MINIMUM AMOUNT FOR PDL, ETC.
	JUMPE	R,[POP	P,(P)	;COULDN'T GET IT THIS TICK
		   JRST	DLYCM##];GO AWAY AND TRY AGAIN NEXT TIME
	POP	P,S		;RESTORE RANGE OF ADDRESSES TO SET ON LINE
	PUSHJ	P,SAVCTX##	;SAVE THE JOB'S CONTEXT AND RETURN AT UUO LEVEL
				; (THE JOB'S CONTEXT MUST BE SAVED BECAUSE
				; IF SETTING THE MEMORY ON LINE CAUSES
				; A NXM, THE JOB'S CONTEXT WILL BE DESTROYED)
	HLRZ	T1,S		;RESTORE THE STARTING PAGE TO SET ON LINE
	HRRZ	T2,S		;AND THE HIGHEST PAGE TO SET ON LINE
	CAIG	T2,1000		;TRYING TO SET MEMORY ON LINE ABOVE 256K?
	JRST	MEMON5		;NO, CAN DO THAT WITHOUT CHECKING
IFN FT22BIT,<;HERE IF SETTING MEMORY ON LINE ABOVE 256K TO SEE IF ANY CHANNEL IS IN
; 18 BIT MODE
	HLRZ	T3,SYSUNI##	;ADDRESS OF THE FIRST UDB IN THE SYSTEM
MEMON1:	HRRZ	T4,UNICHN##(T3)	;ADDRESS OF THE CHANNEL DATA BLOCK FOR THIS UNIT
	SKIPL	CHB22B##(T4)	;IS THE CHANNEL IN 22 BIT MODE?
	JRST	MEMON4		;NO, CAN ONLY SET UP TO 256K ON LINE
	HLRZ	T3,UNISYS##(T3)	;ADDRESS OF THE NEXT UNIT DATA BLOCK
	JUMPN	T3,MEMON1	;JUMP IF NOT THE LAST
	SKIPN	T3,CNFMTA##	;ANY MAGTAPES?
	JRST	MEMON5		;NO
MEMON2:	HLRZ	U,TDVUDB##(T3)	;ADDRESS OF THE UDB FOR THIS DDB
	HRRZ	T4,TDVKDB##(T3)	;ADDRESS OF THE CONTROLLER DB FOR THIS UNIT
	HRRZ	T4,TKBCDB##(T4)	;ADDRESS OF THE CHANNEL DB FOR THIS CONTROLLER
	JUMPE	T4,MEMON3	;JUMP IF NOT A CHANNEL DEVICE
	SKIPL	CHB22B##(T4)	;IS IT IN 22 BIT MODE?
	JRST	MEMON4		;NO, CAN ONLY SET UP TO 256K ON LINE
MEMON3:	HLRZ	T3,DEVSER(T3)	;ADDRESS OF THE NEXT DDB
	JUMPE	T3,MEMON5	;ALL DONE IF THIS IS THE LAST DDB
	MOVE	T4,DEVMOD(T3)	;DEVICE CHARACTERISTICS
	TLNE	T4,DVMTA	;IS THIS A MTA DDB?
	JRST	MEMON2		;YES, MAKE SURE ALL CHANNELS ARE IN 22 BIT MODE
	JRST	MEMON5		;NO, ALL DONE
> ;END FT22BIT
MEMON4:	MOVEI	T2,1000		;REDUCE THE HIGHEST PAGE TO SET ON LINE
				; TO 256K SINCE SOME CHANNEL IS IN 18 BIT MODE

;STILL IN FTMONL
;HERE WHEN OPR IS REQUESTING .LE. 256K OR IF .GT. 256K, NO DF10 IN
; 18 BIT MODE WAS FOUND
MEMON5:	MOVE	T3,MEMSIZ##	;CURRENT HIGHEST ADDRESS IN THE MACHINE
	MOVE	T4,NWCORE##	;HIGHEST ADDRESS THAT CAN BE SET ON LINE
				; (CANNOT MAKE PAGTAB AND MEMTAB BIGGER)
	LSHC	T3,W2PLSH##	;CONVERT TO PAGES
	CAMG	T3,T4		;PICK THE BIGGER OF THE TWO AS THE
	MOVE	T3,T4		; HIGHEST ADDRESS THAT CAN BE SET ON LINE
	TRZE	T3,PG.BDY##	;ROUND UP TO A 256K BOUNDARY (IF NOT 
	ADDI	T3,PAGSIZ##	; ALREADY ON A 256K BOUNDARY
	CAMG	T3,T2		;IF ASKING FOR MEMORY ON LINE ABOVE THE
				; HIGHEST WHICH CAN BE DONE,
	MOVE	T2,T3		; SET ON UP TO THE HIGHEST THAT CAN BE DONE
	CAML	T1,T2		;LOWEST PAGE ABOVE THE HIGHEST PAGE?
	POPJ	P,		;YES, NOTHING TO SET ON LINE
	MOVE	P1,T1		;LOWEST PAGE TO SET ON LINE
	IDIVI	P1,^D36		;COMPUTE BIT POSITION AND WORD NUMBER WITHIN NXMTAB
	MOVNI	P2,-^D35(P2)	;BIT POSITION BYTE POINTER STYLE
	HRLI	P1,(POINT 1,0,0);FORM A 1 BIT BYTE POINTER TO NXMTAB
	DPB	P2,[POINT 6,P1,5]
	ADDI	P1,NXMTAB##	;BYTE POINTER TO BIT CORRESPONDING TO FIRST PAGE TO SET ON
	MOVSI	T3,NXMBIT	;BIT INDICATING NON-EXISTANT PAGE
	SETZB	T4,P2		;INITIALIZE FIRST AND HIGHEST NON-EXISTANT PAGES SEEN
	MOVEI	P3,PAGSIZ##	;TO UPDATE MAXMAX ON EACH PAGE SET ON LINE
MEMON6:	TDNN	T3,PAGTAB(T1)	;IS THIS PAGE NON-EXISTANT?
	JRST	MEMON8		;NO, ITS ALREADY ON LINE
	ADDM	P3,MAXMAX##	;INCREASE THE MAXIMUM VALUE FOR CORMAX
	DPB	T3,P1		;INDICATE THAT THIS PAGE EXISTS IN NXMTAB
	SKIPN	P2		;SKIP IF NOT THE FIRST PAGE SET ON LINE
	MOVE	P2,T1		;REMEMBER THE FIRST PAGE SET ON LINE
	JUMPE	T4,MEMON7	;JUMP IF FIRST PAGE
	HRRZM	T1,PAGTAB(T4)	;LINK PAGES BEING SET ON LINE TOGETHER
MEMON7:	MOVE	T4,T1		;REMEMBER LAST PAGE
MEMON8:	IBP	P1		;BUMP BYTE POINTER TO NEXT PAGE IN NXMTAB
	CAIE	T1,-1(T2)	;LOOKED AT THE ENTIRE RANGE OF PAGES TO SET ON LINE?
	AOJA	T1,MEMON6	;NO, LOOK AT THE NEXT PAGE
	JUMPE	P2,CPOPJ##	;RETURN DOING NOTHING IF ALL PAGES WERE ALREADY
				; ON LINE
	SETZM	PAGTAB(T4)	;INDICATE END OF THE LIST OF PAGES SET ON LINE

; STILL IN FTMONL
;HERE WHEN MEMORY HAS BEEN MARKED ON LINE TO ADD ALL PAGES WHICH
; WERE OFF LINE TO THE FREE CORE LIST
	MOVE	T1,P2		;FIRST PAGE IN THE LIST OF PAGES SET ON LINE
	MOVE	P1,T4		;LAST PAGE FREED
	LSH	T4,P2WLSH##	;HIGHEST ADDRESS SET ON LINE
	ADDI	T4,PAGSIZ##	;ADDRESS OF PAGE FOLLOWING HIGHEST SET ON LINE
	CAMLE	T4,MEMSIZ##	;IS THAT GREATER THAN CURRENT MEMORY SIZE?
	MOVEM	T4,MEMSIZ##	;YES, SAVE NEW HIGHEST ADDRESS IN MEMORY + 1
	MOVE	T4,MEMSIZ##	;HIGHEST ADDRESS IN MEMORY + 1
	LSH	T4,W2PLSH##	;CONVERT TO HIGHEST PAGE
	MOVEI	T4,PAGTAB-1(T4)	;BYTE POINTER TO HIGHEST PAGE IN MEMORY
	HRRM	T4,CORLST##	;STORE THAT FOR CHKTAL
	PUSHJ	P,GVPAGS	;ADD THE PAGES SET ON LINE TO THE FREE CORE LIST
;HERE TO REFERENCE PAGES ADDED TO THE FREE CORE LIST SO IF THEY ARE
; OFF LINE, IT WILL BE DETECTED BEFORE THEY ARE ATTEMPTED TO BE USED
MEMON9:	HRRZ	T1,P2		;FIRST PAGE SET ON LINE
	IDIVI	T1,^D36		;COMPUTE WORD AND BIT POSITION WITHIN NXMTAB
	MOVE	T2,BITTBL##(T2)	;MASK CORRESPONDING TO THAT BIT POSITION
	TDNE	T2,NXMTAB##(T1)	;IS THIS PAGE NOW ON LINE?
	JRST	MEMO11		;NO, FORGET IT
	HRRZ	T3,P2		;YES, GET PAGE NUMBER
	TRO	T3,PM.ACC+PM.WRT;ACCESS ALLOWED AND WRITEABLE
	HRLM	T3,.EPMP##+.MEUPM
	CLRPGT	(0,.EUPMP)	;FLUSH PAGE TABLE SO NEW MAPPING IS IN EFFECT
;WORRY ABOUT INTERLEAVED MEMORY
	XP	NXMDLY,PARDLY	;TIME TO WAIT FOR NXM FLAG TO COME UP
	MOVEI	T3,MEMITL##	;NUMBER OF WAYS MEMORY CAN BE INTERLEAVED
	MOVEI	T4,NXMDLY	;TIME TO WAIT FOR NXM FLAG TO CAUSE AN IRP.
	MOVEM	J,MOFLPG##	;FLAG THAT MEMORY BEING SET ON LINE
				; NXM AT THIS POINT ISN'T A SERIOUS ERROR
MEMO10:	MOVES	.EUPMP-1(T3)	;REFRENCE THE PAGE TO MAKE SURE ITS REALLY THERE
	SOJG	T4,.		;WAIT LONG ENOUGH FOR NXM INTERRUPT TO HAPPEN
				; IN CASE IT ISN'T THERE
	TDNN	T2,NXMTAB##(T1)	;IS THE PAGE STILL ON LINE?
	SOJG	T3,MEMO10	;YES, CHECK NEXT WORD OF THE PAGE
				; TO INSURE THAT THERE ISN'T AN INTERLEAVING PROBLEM
	SETZM	MOFLPG##	;NO LONGER CHECKING FOR OFF LINE PAGES
MEMO11:	CAIN	P2,(P1)		;REFERENCED ALL PAGES IN THE RANGE SET ON LINE?
IFN FTDAEM,<
	JRST	[MOVE T1,[10,,.ERCSC]
		 PJRST DAEEIM##];YES, TELL DAEMON CONFIGURATION HAS CHANGED AND RETURN
>
IFE FTDAEM,<
	POPJ	P,		;IF NO DAEMON, JUST RETURN
>
	HRRZ	P2,PAGTAB(P2)	;NO, GET THE NEXT PAGE SET ON LINE
	JRST	MEMON9		;AND REFERENCE IT TO MAKE SURE ITS THERE

> ;END FTMEMONL
SUBTTL	CORE1 - CORE ALLOCATION MODULE

;ROUTINE TO ALLOCATE PHYSICAL CORE IN CORE OR ON THE DISK
;CALLING SEQUENCE:
;	MOVE	R,XWD PROTECTION,RELOCATION
;	MOVE	T1,HIGHEST RELATIVE ADDRESS REQUESTED
;	PUSHJ	P,CORE1A
;ALWAYS SKIP RETURN - R = NEW PROTECTION,,RELOCATION
; R = 0 IF CORE IS ASSIGNED ON THE SWAPPING SPACE

CORE1A::JUMPE	R,CORGT0	;JUMP IF SEGMENT HAS NO CORE IN CORE
	HLRZ	T3,R		;T3 = CURRENT HIGHEST RELATIVE ADDRESS IN THE SEGMENT
	SKIPN	T1		;IS ZERO CORE BEING REQUESTED?
	MOVNI	T1,1		;YES, PRETEND -1 AND DEPEND ON BUG IN ASH
				; WHICH MAKES -1 = -1 WHEN SHIFTED
	SUB	T3,T1		;T3 = NUMBER OF WORDS OF INCREASE OR DECREASE IN
				; SEGMENT SIZE
	ASH	T3,W2PLSH##	;CONVERT TO NUMBER OF PAGES OF INCREASE OR DECREASE
	JUMPG	T3,CORE1B	;JUMP IF SEGMENT IS GETTING SMALLER
	MOVMS	T3		;T3 = NUMBER OF PAGES OF INCREASE
	PUSHJ	P,FRDCR##	;ARE THERE THAT MANY FREE PAGES AVAILABLE IN CORE?
	  JRST	CORGT7		;NO, MARK THE SEGMENT AS EXPANDING AND ALLOCATE
				; THE REQUIRED NUMBER OF PAGES ON SWAP-IN
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF INCREASE
	PUSHJ	P,SCPAGS	;FIND THE LAST PAGE WHICH IS CURRENTLY
				; ALLOCATED TO THE SEGMENT
	MOVE	T2,(P)		;T2 = NUMBER OF PAGES TO ADD TO THE SEGMENT
IFN FTVM,<
	ADDM	T2,JBTSWP##(J)	;INCREASE IMGIN BY THAT NUMBER OF PAGES
>
	PUSHJ	P,ADPAGS	;ALLOCATE ENOUGH PAGES TO SATISFY THE REQUEST
	POP	P,T2		;RESTORE THE NUMBER OF PAGES OF INCREASE
	LSH	T2,^D18+P2WLSH##;CONVERT TO NUMBER OF WORDS OF INCREASE IN
				; POSITION TO UPDATE CURRENT RELOCATION
	ADD	R,T2		;R = NEW PROTECTION,,RELOCATION
	JRST	CORGT2		;STORE NEW PROTECTION,,RELOCATION AND CLEAR
				; PAGES JUST ADDED TO INSURE SECURITY
CORE1B:	JUMPG	T1,CORE1C	;REQUESTING 0K CORE IN CORE?
IFN FTMS,<
	PUSHJ	P,CLCSN##	;YES, DON'T HAVE TO SWEEP BEFORE WE
				; RUN HIM AGAIN
>;END IFN FTMS
	PUSHJ	P,SVEUB		;YES, MAY BE FROM THE SWAPPER AND THE UPMP
				; IS NOT NECESSARILY ADDRESSABLE SO MAKE SURE IT IS
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF DECREASE
	MOVEI	T2,0		;FIND THE FIRST PAGE OF THE SEGMENT
	PUSHJ	P,SNPAGS	;T1 = FIRST PAGE TO RETURN TO FREE CORE LIST
	JRST	CORE1D		;GO RETURN PAGES
CORE1C:	LDB	T2,[POINT 9,R,8];T2 = THE CURRENT SIZE OF THE SEGMENT IN
				; PAGES - 1
	SUBI	T2,(T3)		;COMPUTE THE RELATIVE PAGE NUMBER OF THE FIRST
				; PAGE TO RETURN TO THE FREE CORE LIST
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF DECREASE
	PUSHJ	P,SNPAGS	;FIND THE ABSOLUTE PAGE NUMBER OF THE FIRST PAGE
				; TO RETURN TO THE FREE CORE LIST
	HRRZ	T2,PAGTAB(T1)	;T2 = THE LINK TO THE FIRST PAGE TO FREE
	HLLZS	PAGTAB(T1)	;INDICATE THAT THIS IS NOW THE LAST PAGE
				; OF THE SEGMENT
	MOVE	T1,T2		;T1 = THE ABSOLUTE PAGE NUMBER OF FIRST PAGE TO FREE
CORE1D:	PUSHJ	P,GVPAGS	;RETURN FREED PAGES TO THE FREE CORE LIST
IFN FTVM,<
	LDB	T2,IMGOUT##	;SWAPPER DEALLOCATION?
	JUMPN	T2,CORE1E	;JUMP IF YES
	MOVN	T2,(P)		;NUMBER OF PAGES BEING DEALLOCATED
	ADDM	T2,JBTSWP##(J)	;UPDATE IMGIN TO REFLECT NUMBER OF PAGES ALLOCATED
CORE1E:>
	POP	P,T2		;RESTORE THE NUMBER OF PAGES OF DECREASE
	LSH	T2,^D18+P2WLSH##;CONVERT TO NUMBER OF WORDS OF DECREASE AND
				; POSITION TO UPDATE CURRENT RELOCATION
	SUB	R,T2		;R = NEW PROTECTION,,RELOCATION
	SKIPG	R		;WERE ALL OF THE PAGES BELONGING TO THE SEGMENT
				; RETURNED TO FREE CORE
	SETZB	T1,R		;YES, INDICATE SEGMENT HAS NO CORE IN CORE
	CAILE	J,JOBMAX##	;IS THIS SEGMENT A HIGH SEGMENT?
	JUMPE	R,CORGT1	;YES, AND DOES IT STILL HAVE CORE IN CORE?
	JUMPN	R,CORGT2	;NO, DOES LOW SEGMENT HAVE CORE IN CORE?
	HRRZ	T1,JBTUPM##(J)	;NO, RETURN UPMP TO THE FREE CORE LIST
	SETZ	R,
	HLLZS	JBTUPM##(J)	;INDICATE NO UPMP OR CORE IN CORE
	PUSHJ	P,GVPAGS	;GIVE UP THE PAGE ALLOCATED TO THE UPMP
	JRST	CORGT6		;STORE R AND RETURN
;HERE WHEN THE SEGMENT IS EXPANDING FROM ZERO (CALLED BY THE SWAPPER AND ABOVE)
CORGET::PUSHJ	P,SVEUB		;SAVE UBR ON CALL FROM THE SWAPPER
CORGT0:	JUMPE	T1,CPOPJ1##	;RETURN IF MULTIPLE CALLS TO RETURN CORE
	AOS	T2,T1		;T2 = NUMBER OF WORDS OF CORE REQUIRED TO
				; SATISFY REQUEST
	LSH	T2,W2PLSH##	;T2 = NUMBER OF PAGES REQUIRED
	CAIG	J,JOBMAX##	;IS THIS A LOW SEGMENT?
	CAMGE	T2,BIGHOL##	;YES, MUST ALLOCATE A UPMP ALSO
	CAMLE	T2,BIGHOL##	;NO, IS THERE ENOUGH FREE CORE IN CORE TO
				; ACCOMODATE THE REQUEST?
	SOJA	T1,CORGT7	;NO, MARK THE SEGMENT AS EXPANDING AND ALLOCATE
				; THE REQUIRED NUMBER OF PAGES ON SWAP-IN
IFN FTVM,<
	DPB	T2,IMGIN##	;STORE THE NUMBER OF PAGES ALLOCATED IN CORE
>
	HRLI	R,-1(T1)	;R = NEW PROTECTION,,?
	PUSHJ	P,GTPAGS	;ALLOCATE THE PAGES TO SATIFY THE REQUEST
	MOVEI	T1,PM.ACC+PM.WRT(T1)
	CAILE	J,JOBMAX##	;IS THIS A LOW SEGMENT
	JRST	CORGT1		;NO, UPMP HAS ALREADY BEEN ALLOCATED
	PUSH	P,T1		;SAVE THE PAGE NUMBER OF FIRST PAGE OF THE LOW SEGMENT
	MOVEI	T2,1		;ALLOCATE ONE PAGE FOR THE UPMP
	PUSHJ	P,GTPAGS	;GET ONE PAGE OFF THE FREE CORE LIST
	HRRM	T1,JBTUPM##(J)	;STORE IT AS THE ADDRESS OF THE UPMP
	MOVEI	T1,PM.ACC+PM.WRT+PM.CSH(T1)
				;(CACHE UPMP)
	HRLM	T1,.EPMP##+.MEUPM
	CLRPGT	(0,.EUPMP)
	SETZM	.EUPMP
	MOVE	T2,[.EUPMP,,.EUPMP+1]
	BLT	T2,.EUPMP+PG.BDY## ;ZERO THE ENTIRE UPMP
	MOVSI	T2,NLUPMP##+.MUPMP ;NOW SETUP THE REST OF THE MAP FROM THE
	HRRI	T2,.EUPMP+.MUPMP ; PROTOTYPE MAP (NULL JOB'S UPMP)
	BLT	T2,.EUPMP+NUPMPL##-1
	HRLM	T1,.EUPMP+.MUPMP;MAP THE UPMP IN THE PER-PROCESS MAP
	POP	P,T1		;RESTORE THE MAPPING FOR THE FIRST PAGE OF THE
				; LOW SEGMENT
	PUSHJ	P,STEUB		;MAKE THE UPMP ADDRESSABLE (SET THE UBR TO
				; PONIT TO THIS PAGE)
	HRLM	T1,.UPMP	;STORE THE MAPPING FOR THE FIRST PAGE OF
				; THE LOW SEGMENT
	HRRM	T1,.UPMP+.MJDAT	;AND MAKE THE JOB DATA AREA ADDRESSABLE THROUGH
				; THE PER PROCESS MAP
	BLKO	PAG,.JDAT	;CLEAR OUT OLD ENTRY FOR .JDAT
	JRST	CORGT2		;CLEAR THE PAGES JUST ALLOCATED
CORGT1:	DPB	T1,JBYHSA##	;STORE THE STARTING PAGE NUMBER OF THE HIGH SEGMENT
CORGT2:	JUMPE	R,CORGT6	;ALL DONE IF THE SEGMENT HAS NO CORE AT THIS POINT
	HLRZ	T1,R		;T1 = HIGHEST RELATIVE ADDRESS SEGMENT CURRENTLY HAS
	HLRZ	T2,JBTADR##(J)	;T2 = HIGHEST RELATIVE ADDRESS SEGMENT PREVIOUSLY HAD
	JUMPN	T2,CORGT3	;JUMP IF SEGMENT HAD CORE IN CORE
	LDB	T2,IMGOUT##	;T2 = AMOUNT OF CORE SEGMENT HAD WHEN LAST IN CORE
	LSH	T2,P2WLSH##	;CONVERT TO NUMBER OF WORDS
	SOS	T2		;HIGHEST RELATIVE ADDRESS
CORGT3:	CAMG	T1,T2		;CURRENT SEGMENT SIZE GREATER THAN PREVIOUS SIZE?
	JRST	CORGT5		;NO, NOTHING TO CLEAR
	SUB	T1,T2		;T1 = NUMBER OF WORDS OF INCREASE
	ADDI	T2,1		;T2 = NUMBER OF WORDS PREVIOUSLY ALLOCATED THE SEGMENT
	LSH	T2,W2PLSH##	;CONVERT TO PAGE NUMBER OF LAST PAGE
				; PREVIOUSLY ALLOCATED TO THE SEGMENT
IFN FTVM,<
	PUSHJ	P,ZERHGH##	;IF JOB HAS A NON-SHARABLE HI-SEG
	  JRST	CORGT5		; ZERO THE CORE DIFFERENTLY
>
IFN FTTIME,<
	ADDM	T1,CLRWRD##	;INCREASE COUNT OF NUMBER OF WORDS CLEARED
>
	PUSHJ	P,SNPAGS	;GET THE ABSOLUTE PAGE NUMBER OF THE FIRST
				; NEW PAGE (PAGE TO BE CLEARED)
CORGT4:	MOVEI	T1,PM.ACC+PM.WRT+PM.CSH(T1)
	HRLM	T1,.EPMP##+.MEUPM
	CLRPGT	(0,.EUPMP)
	MOVEI	T2,.EUPMP+1	;MAKE A BLT POINTER
	HRLI	T2,.EUPMP	;SET TO ZERO THE PAGE
	SETZM	.EUPMP		;ZERO THE FIRST WORD OF THE PAGE
	BLT	T2,.EUPMP+PAGSIZ##-1
				;ZERO THE PAGE
	TRZ	T1,PM.ACC+PM.WRT+PM.CSH  ;CLEAR THE ACCESS BITS
	HRRZ	T1,PAGTAB(T1)	;GET THE ABSOLUTE PAGE NUMBER OF THE
				; NEXT PAGE OF THE SEGMENT
	JUMPN	T1,CORGT4	;IF NOT THE LAST PAGE ZERO IT
CORGT5:	HRRI	R,.VJDT		;ASSUME A HIGH SEGMENT,.I.E., RH(R) = EVA
				; OF THE VESTIGUAL JOB DATA AREA
	CAILE	J,JOBMAX##	;IS IT A HIGH SEGMENT?
	JRST	CORGT6		;NO
	HRRI	R,.JDAT		;LOW SEGMENT, RH(R) = EVA OF JOB DATA AREA
IFN FTVM,<
	MOVEM	J,.UPMP+.UPJOB	;SAVE THE JOB NUMBER FOR DEBUGGING AND
				; VIRCHK (FOR GIVING BACK HIGH SEG CORE)
>
	HLRZM	R,JOBREL##(R)	;STORE THE NEW SIZE OF THE LOW SEGMENT FOR THE
				; USER SO HE WON'T GET CONFUSED ON EXAMINE COMMAND
CORGT6:	MOVEM	R,JBTADR##(J)	;STORE NEW PROTECTION,,RELOCATION
IFN FTTRACK,<
	MOVEM	J,LASCOR##	;STORE SEGMENT NUMBER OF LAST SEGMENT CORE
				; ALLOCATION WAS DONE FOR FOR DEBUGGING
>
IFN FTVM,<
	LDB	T1,IMGOUT##	;CORE ALLOCATION FOR THE SWAPPER?
 	JUMPN	T1,CPOPJ1##	;YES, ALL DONE
>
	CAMN	J,.C0JOB##	;IS THIS THE CURRENT JOB (CORE UUO)?
	PUSHJ	P,SETREL	;YES, SETUP THE MAP AND SOFTWARE RELOCTATION INFO.
	AOS	(P)		;GIVE SKIP (OK) RETURN
	CAILE	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	PJRST	CURHGH##	;YES SEE IF CORE WAS ALLOCATED FOR THE HIGH
				; SEGMENT WHICH THE CURRENT JOB MIGHT BE SHARING
IFE FTVM,<
	CAME	J,.C0JOB##	;IS THIS THE CURRENT JOB?
	>
IFN FTVM,<
	CAMN	J,.C0JOB##	;CURRENT JOB?
	TLNN	R,MPGSIZ##	; OR ONLY ONE PAGE ALLOCATED TO THE CURRENT JOB?
				; IF ONLY 1 PAGE SETREL MIGHT NOT CALL MAPLOW
>
	PJRST	MAPLOW		;NO, SETUP THE MAP FOR E AND D COMMANDS
	POPJ	P,		;YES, MAP IS ALREADY SETUP
;HERE IF NOT ENOUGH FREE PAGES AVAILABLE IN CORE TO SATISFY REQUEST
; INDICATE JOB IS EXPANDING AND THE REQUIRED NUMBER OF PAGES WILL BE
; ALLOCATED WHEN THE SEGMENT IS NEXT SWAPPED IN
CORGT7:
	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	XPAND##		;AND MARK THE JOB AS EXPANDING
;ROUTINE TO SETUP THE PORTION OF THE MAP WHICH MAPS THE
; LOW SEGMENT
;CALLING SEQUENCE:
;	MOVE	R,LOW SEGMENT PROTECTION,,RELOCATION
;	PUSHJ	P,MAPLOW
;	...	ALWAYS RETURN HERE

MAPLOW::
IFN FTVM,<
	LDB	T1,JBYLSS##	;HIGHEST PAGE IN THE LOW SEGMENT
	ADDI	T1,1		;LOW SEGMENT SIZE
	PUSHJ	P,CLRWS##	;CLEAR WORKING SET BITS
	LDB	T1,[POINT 9,R,8];NEW HIGHEST PAGE IN THE LOW SEGMENT
	ADDI	T1,1		;NEW LOW SEGMENT SIZE
	PUSHJ	P,ADJWS##	;SET WORKING SET BITS FOR NEW SIZE
>	;END FTVM
	MOVE	T1,[POINT 18,.UPMP] ;START AT PAGE ZERO
	MOVEI	T2,PM.ACC+PM.WRT+PM.PUB+PM.CSH ;ACCESSABLE, WRITABLE, PUBLIC, AND CACHE
IFN FTLOCK,<
	MOVSI	T3,(JS.NCS)	;DON'T CACHE BIT
	TDNE	T3,JBTST2##(J)	;SHOULD CACHE BIT BE OFF IN THE MAP?
	PUSHJ	P,[TRZ T2,PM.CSH  ;YES, CLEAR IT
		   PJRST CSDMP]	;AND FLUSH THE CACHE
>
	LDB	T3,JBYLSA##	;FIRST PHYSICAL PAGE IN THE LOW SEGMENT
	PUSHJ	P,REMAP		;SETUP THE MAP FOR THE LOW SEGMENT
	LDB	T3,JBYLSS##	;PREVIOUS SIZE
	PUSHJ	P,ZERMAP	;CLEAR MAP SLOTS NO LONGER A PART OF THE LOW SEGMENT
	DPB	T2,JBYLSS##	;STORE NEW LOW SEGMENT SIZE
	pjrst	steub		;clear page table and return
;ROUTINE TO SETUP THE PORTION OF THE MAP WHICH MAPS THE HIGH SEGMENT
;CALLING SEQUENCE:
;	PUSHJ	P,MAPHGH
;	...	ALWAYS RETURN HERE - R = PROTECTION,,RELOCATION OF LOW SEGMENT

SETMAP::SKIPA	J,.C0JOB##	;CURRENT JOB NUMBER
REMHGH::TDZA	T3,T3		;NO HIGH SEGMENT NUMBER
MAPHGH::MOVE	T3,JBTSGN##(J)	;HIGH SEGMENT NUMBER
	PUSHJ	P,SVEUB		;MAKE SURE THE JOB IS ADDRESSABLE
	PUSHJ	P,HSVAD##	;COMPUTE HIGH SEGMENT STARTING AND ENDING ADDRESSES
	MOVE	T4,T2		;STARTING ADDRESS
	SKIPL	R,T3		;SPY SEGMENT?
	HLRZ	R,JBTADR##(T3)	;NO, SIZE OF THE REAL HIGH SEGMENT
	HRLZS	R		;HIGH SEGMENT SIZE,,0
	SKIPL	JOBHCU##+.JDAT	;SAVE IN PROGRESS?
	HRRM	T1,JOBHRL##+.JDAT ;YES, DON'T CLOBBER IOWD IN COMPRESSED LOW SEGMENT
IFN FTVM,<
	TLNN	T3,SHRSEG+SPYSEG  ;SHARABLE SEGMENT?
	JUMPN	T3,SCWEXO##	;YES, THE MAP IS RIGHT EXCEPT FOR W.E. AND PUBLIC BITS
>
	ROT	T4,W2PLSH##-1	;CONVERT STARTING ADDRESS TO PAGE NUMBER/2
	MOVEI	T1,.UPMP(T4)	;WORD IN THE UPMP WHERE HIGH SEGMENT MAPPING STARTS
	HRLI	T1,442200	;ASSUME HIGH SEGMENT STARTS AT AN EVEN PAGE NUMBER
	SKIPGE	T4		;DOES IT?
	HRLI	T1,222200	;NO, IT STARTS AT AN ODD PAGE NUMBER
	MOVEI	T2,PM.ACC+PM.WRT+PM.CSH ;ACCESS ALLOWED, WRITABLE AND CACHE
IFN FTLOCK!FTMS,<
	TLNE	T3,NCSH+NOCSH	;CACHE?
	PUSHJ	P,[TRZ T2,PM.CSH  ;NO, CLEAR THE BIT
		   PJRST CSDMP]	;AND FLUSH THE CACHE
>
	TLNN	T3,GTSSEG	;SEGMENT GETSEGED?
	JRST	SETM0A		;NO, ALWAYS PUBLIC
IFN FTFDAE,<
	MOVSI	T4,(JS.FXO)	;FILE DAEMON MADE IT EXECUTE ONLY BIT
	TDNE	T4,JBTST2##(J)	;IS IT EXECUTE ONLY?
	JRST	SETM0B		;YES, LEAVE IT CONCEALED
>
	MOVE	T4,JBTSTS##(J)	;JOB STATUS
	TRNE	T4,JS.XO	;EXECUTE ONLY?
	TLNE	T4,JACCT	;IF ALSO JACCT, FORGET ABOUT X.O.
SETM0A:	TRO	T2,PM.PUB	;JACCT OR NOT EXECUTE ONLY, SO MAKE PAGES PUBLIC
SETM0B:	TLNN	T3,UWPOFF	;USER WRITE PROTECT OFF?
	TRZ	T2,PM.WRT	;YES, MAKE THE SEGMENT WRITABLE
	JUMPL	T3,SETMP1	;JUMP IF A SPY SEGMENT
	LDB	T3,[POINT 13,JBTHSA##(T3),35] ;FIRST PHYSICAL PAGE OF THE HIGH SEGMENT
	MOVEI	T4,PM.ACC+PM.WRT(T3) ;ACCESS ALLOWED PLUS WRITABLE
	HRLM	T4,.UPMP+.MVJDT	;MAKE THE HIGH SEGMENT VESTIGUAL JOB DATA AREA
				; ADDRESSABLE VIA THE PER-PROCESS MAP
	PUSHJ	P,REMAP		;MAP THE HIGH SEGMENT INTO THE USER'S ADDRESS SPACE
	JRST	SETMP3		;CONTINUE
SETMP1:	TRZ	T2,PM.CSH	;DON'T ALLOW USERS TO GET THINGS
				;INTO THE CACHE THAT SHOULN'T BE THERE
	LDB	T3,[POINT 9,R,8];SIZE OF THE SPY SEGMENT
	TRO	T2,PM.PUB	;EXECUTE ONLY SPY SEG DOESN'T WORK
SETMP2:	IDPB	T2,T1		;MAP MONITOR ADDRESSES INTO USER'S ADDRESS SPACE
	AOS	T2		;STEP TO NEXT MONITOR PAGE
	SOJGE	T3,SETMP2	;MAP AS MANY PAGES AS THE USER REQUESTED
SETMP3:	LDB	T3,JBYHSS##	;PREVIOUS HIGH SEGMENT SIZE
	TLNE	R,-1		;IF THE HIGH SEGMENT SIZE ISN'T 0,
	SUBI	T3,1		;HIGHEST PAGE IN THE HIGH SEGMENT
	PUSHJ	P,ZERMAP	;ZERO MAP SLOTS NO LONGER A PART OF THE HIGH SEGMENT
	TLNE	R,-1		;IF THERE STILL IS A HIGH SEGMENT
	ADDI	T2,1		;COMPUTE NEW NUMBER OF PAGES IN THE HIGH SEGMENT
	DPB	T2,JBYHSS##	;STORE NEW NUMBER OF PAGES IN THE HIGH SEGMENT
	MOVE	R,JBTADR##(J)	;LOW SEGMENT SIZE,,VIRTUAL ADDRESS
	POPJ	P,		;AND RETURN TO THE CALLER
;SUBROUTINE TO SETUP THE USER PAGE MAP PAGE TO REFLECT THE LOCATION
; OF THE PAGES OF A SEGMENT IN PHYSICAL MEMORY
;CALLING SEQUENCE:
;	MOVE	T1,BYTE POINTER TO THE MAP
;	MOVE	T2,PAGE ATTRIBUTES
;	MOVE	T3,ABSOLUTE PAGE NUMBER OF FIRST PAGE OF THE SEGMENT
;	PUSHJ	P,REMAP
;	...	ALWAYS RETURN HERE

REMAP:	HLRZ	T4,R		;LENGTH - 1 OF THE SEGMENT
	JUMPE	T4,CPOPJ##	;IF THE SEGMENT IS ZERO LENGTH RETURN
	LSH	T4,W2PLSH##	;CONVERT TO NUMBER OF PAGES - 1
REMAP1:	TRO	T3,(T2)		;ABSOLUTE PAGE NUMBER PLUS ACCESS BITS
	IDPB	T3,T1		;STORE PHYSICAL LOCATION OF THE PAGE AND
				; THE ACCESS BITS IN THE MAP
	TRZ	T3,(T2)		;CLEAR ACCESS BITS
	MOVE	T3,PAGTAB(T3)	;GET THE ABSOLUTE PAGE NUMBER OF THE NEXT
				; PAGE IN THE SEGMENT
	SOJL	T4,CPOPJ##	;RETURN IF ALL THE PAGES IN THE SEGMENT
				; HAVE BEEN MAPPED
	JUMPG	T3,REMAP1	;MAP ALL THE PAGES IN THE SEGMENT
	STOPCD	.,STOP,PMU,	;++PAGTAB MESSED UP

;ROUTINE TO DETERMINE IF THE SIZE OF A SEGMENT HAS CHANGED SINCE THE LAST
; TIME THE JOB WHOSE ADDRESSING SPACE CONTAINS THIS SEGMENT WAS RUN.  IF THE
; SEGMENT IS SMALLER THAN THE IT PREVIOUSLY WAS, THE ROUTINE
; ZEROES THE LOCATIONS IN THE MAP WHICH CORRESPOND TO THE PAGES REMOVED FROM
; THE SEGMENT (OR ALL THE LOCATIONS IF THE SEGMENT WAS REMOVED) SO THE JOB
; WILL PAGE FAIL ON AN ILLEGAL MEMORY REFERENCE
;CALLING SEQUENCE:
;	MOVE	T3,PREVIOUS SEGMENT SIZE IN PAGES - 1
;	MOVE	R,JBTADR##(J)
;	PUSHJ	P,ZERMAP
;	...	ALWAYS RETURN HERE - T2 = CURRENT SEGMENT SIZE IN PAGES - 1

ZERMAP:	LDB	T2,[POINT 9,R,8];CURRENT SIZE OF THE SEGMENT - 1 IN PAGES
	SUBI	T3,(T2)		;NEW SIZE MINUS OLD SIZE
	JUMPLE	T3,CPOPJ##	;RETURN IF THE SEGMENT IS THE SAME
				; SIZE OR BIGGER THAN IT WAS THE LAST TIME
				; THE JOB WAS RUN
	MOVEI	T4,0		;ZERO THE MAP TO REFLECT THE NEW SMALLER
ZRMAP1:	IDPB	T4,T1		; SEGMENT SIZE SO JOB WILL PAGE FAIL ON AN
	SOJG	T3,ZRMAP1	; ILLEGAL MEMORY REFERENCE
	POPJ	P,		;RETURN
;SUBROUTINE TO RETURN PAGES TO THE LINKED LIST OF FREE PAGES AND UPDATE
; BIGHOL (THE TOTAL NUMBER OF FREE PAGES) AND CORTAL (THE TOTAL NUMBER
; OF FREE PAGES PLUS THE NUMBER OF PAGES OCCUPIED BY
; DORMANT OR IDLE SEGMENTS)
;CALLING SEQUENCE:
;	MOVE	T1,FIRST PAGE TO RETURN TO THE FREE CORE LIST
;	PUSHJ	P,GVPAGS
;	ALWAYS RETURN HERE

GVPAGS::HRRZS	T2,T1		;T2 = FIRST PAGE TO RETURN (CLEAR ANY JUNK IN LH)
	EXCH	T1,PAGPTR##	;STORE FIRST PAGE TO FREE AS FIRST PAGE ON THE
				; FREE CORE LIST AND GET FIRST PAGE ON CURRENT LIST
	MOVEI	T3,1		;AT LEAST ONE PAGE IS BEING RETURNED
GVPAG1:	MOVSI	T4,FREPAG	;THIS PAGE IS ON THE FREE CORE LIST BIT
	TDNE	T4,PAGTAB(T2)	;PAGE MUST NOT BE FREE ALREADY
	STOPCD	.,STOP,ARF,	;++ATTEMPT TO RETURN FREE PAGE
	IORB	T4,PAGTAB(T2)	;MARK THIS PAGE AS BEING ON THE FREE CORE LIST
				; AND GET THE NEXT PAGE TO BE RETURNED
	TRNN	T4,-1		;LAST PAGE TO BE RETURNED?
	JRST	GVPAG2		;YES, UPDATE BIGHOL AND CORTAL AND RETURN
	HRRZ	T2,T4		;INDEX TO NEXT PAGE TO FREE
	AOJA	T3,GVPAG1	;COUNT NUMBER OF PAGES FREED AND RETURN NEXT PAGE
GVPAG2:	HRRM	T1,PAGTAB(T2)	;LINK THE REST OF THE FREE CORE LIST TO THE PAGES
				; FREED
	ADDM	T3,BIGHOL##	;UPDATE THE AMOUNT OF FREE CORE BY THE NUMBER
				; OF PAGES FREED
	ADDM	T3,CORTAL##	;ALSO, UPDATE THE AMOUNT OF POTENTIALLY FREE CORE
	POPJ	P,		;AND RETURN
;SUBROUTINE TO FIND THE NTH PAGE FOR N.LT.THE NUMBER OF PAGES
; ASSIGNED TO THE JOB OR THE JOBS LAST PAGE
;CALLING SEQUENCE:
;	PUSHJ	P,SCPAGS	;TO FIND THE LAST PAGE OF THE JOB
;OR
;	PUSHJ	P,SNPAGS	;TO FIND THE NTH PAGE OF A JOB
;	RETURN HERE - T1 = PAGE NUMBER OF THE NTH PAGE

SCPAGS::MOVEI	T2,^D511	;STOP AFTER SCANNING 512 PAGES
SNPAGS::LDB	T3,JBYHSA##	;PHYSICAL PAGE NUMBER OF PAGE 0 IN THE LOW SEGMENT
	CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	LDB	T3,JBYLSA##	;YES, PHYSICAL PAGE NUMBER OF FIRST PAGE OF
				; THE HIGH SEGMENT
SNPAG1:	HRRZ	T1,T3		;CURRENT PAGE WITHIN THE SEGMENT
	SKIPGE	T3,PAGTAB(T1)	;GET NEXT PAGE IN THE SEGMENT
	STOPCD	.,STOP,PSF,	;++PAGE IN SEGMENT FREE
	TRNE	T3,-1		;IS THIS THE LAST PAGE IN THE SEGMENT?
	SOJGE	T2,SNPAG1	;NO, IS THIS THE NTH PAGE WITHIN THE SEGMENT?
	POPJ	P,		;YES, RETURN WITH T1 = NTH OR LAST PAGE
;SUBROUTINE TO GET PAGES FROM THE LINKED LIST OF FREE PAGES AND
; UPDATE CORTAL AND BIGHOL
;CALLING SEQUENCE:
;	MOVE	T1,WHERE TO BEGIN ALLOCATION IF ADDING PAGES
;	MOVE	T2,NUMBER OF PAGES TO ALLOCATE
;	PUSHJ	P,ADPAGS	;OR
;	PUSHJ	P,GTPAGS	;IF NO PAGES ARE CURRENTLY ALLOCATED
;	ALWAYS RETURN HERE - T1 = PAGE NUMBER OF FIRST PAGE ALLOCATED

ADPAGS::MOVE	T4,PAGPTR##	;FIRST FREE PAGE
	HRRM	T4,PAGTAB(T1)	;LINK IT TO THE PAGES CONTAINED IN THIS SEGMENT
GTPAGS:	SKIPN	T1,PAGPTR##	;GET FIRST FREE PAGE
	STOPCD	.,STOP,PEZ,	;++PAGPTR=0
	MOVNS	T2		;MINUS NUMBER OF PAGES BEING ALLOCATED
	ADDM	T2,BIGHOL##	;DECREASE THE NUMBER OF FREE PAGES BY THAT AMOUNT
	ADDM	T2,CORTAL##	;AND THE NUMBER OF POTENTIALLY FREE PAGES
	MOVE	T3,T1		;FIRST PAGE TO ADD OR GET
GTPAG1:	HRRZ	T4,T3		;ALLOCATE THIS PAGE
	MOVSI	T3,FREPAG	;PREPARE TO MARK THIS PAGE AS IN-USE
	SKIPN	T4		;END OF THE FREE CORE LIST?
	STOPCD	.,STOP,FPI,	;++FREE PAGE INUSE
	ANDCAB	T3,PAGTAB(T4)	;CLEAR THE BIT INDICATING A FREE PAGE AND GET
				; THE NEXT PAGE ON THE FREE CORE LIST
	AOJL	T2,GTPAG1	;LOOP UNTIL ALL PAGES REQUESTED ARE ALLOCATED
	HRRZM	T3,PAGPTR##	;STORE THE NEW FIRST PAGE IN THE FREE CORE LIST
	HLLZS	PAGTAB(T4)	;INDICATE THAT THIS IS THE LAST PAGE ALLOCATED
				; TO THIS SEGMENT
	POPJ	P,		;AND RETURN TO THE CALLER
SUBTTL	SWAP - USER PROGRAM SWAPPING ROUTINES

;SUBROUTINE TO SETUP THE MAP FOR A JOB WHICH WAS JUST SWAPPED IN
; THIS INCLUDES THE TRAP LOCATIONS AS WELL AS THE MAP ITSELF
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER OF JOB JUST SWAPPED IN
;	MOVE	R,XWD LOW SEGMENT SIZE, EVA OF THE JOB DATA AREA
;	SETUP THE USER BASE REGISTER TO POINT TO THIS JOB'S UPMP
;	PUSHJ	P,MAPUSR
;	ALWAYS RETURN HERE

MAPUSR::PUSHJ	P,SVEUB		;MAKE THE MAP ADDRESSABLE
	MOVE	R,JBTADR##(J)	;R=WXD LOW SEGMENT SIZE, ADDRESS OF JOB DATA AREA
	MOVE	T1,JOBPC##(R)	;JOBS PC
	TLNN	T1,(XC.USR)	;JOB IN EXEC MODE?
	MOVEM	R,JOBDPG##(R)	;YES, STORE POSSIBLY UPDATED R IN THE DUMP ACS
IFE FTVM,<
	PUSHJ	P,MAPLOW	;MAP THE LOW SEGMENT
>
	PUSHJ	P,MAPHGH	;MAP THE HIGH SEGMENT
	MOVE	T1,JOBENB##(R)	;GET THE JOBS ENABLE BITS
	PJRST	SETRP		;SETUP THE TRAP LOCATIONS
SUBTTL	SWPSER - SWAPPING SERVICE ROUTINE

;SUBROUTINE TO MAKE THE FIRST WORD OF A SEGMENT ADDRESSABLE FOR JBTCHK
; CALLING SEQUENCE:
;	MOVE	T1,IOWD USED FOR SWAPPING
;	MOVE	J,SEGMENT NUMBER OF SEGMENT SWAPPED IN OR OUT
;	PUSHJ	P,GETCHK
;	ALWAYS RETURN HERE
;T1 = EXEC VIRTUAL ADDRESS OF WORD 0 OF THE SEGMENT.  IF THIS IS A LOW
; SEGMENT, JUST SETUP THE UBR SINCE T1 CONTAINS THE ADDRESS OF WORD 0
; OF THE SEGMENT MAPPED THROUGH THE PER PROCESS MAP.  IF THIS IS A HIGH
; SEGMENT, MAP WORD 0 THROUGH THE EXEC MAP SINCE THE SEGMENT MAY BE
; DORMANT OR IDLE AND THUS NOT APPEAR IN ANY USERS MAP.

GETCHK::CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	JRST	SVEUB		;NO, JUST SETUP THE UBR SINCE THE LOW SEGMENT
				; IS ADDRESSABLE VIA THE PER PROCESS MAP
	LDB	T1,JBYHSA##	;GET THE ABSOLUTE PAGE NUMBER OF THE FIRST
				; PAGE OF THE HIGH SEGMENT
	TRO	T1,PM.ACC+PM.WRT;SET ACCESS BITS
	HRRM	T1,.EPMP##+.MECKS
				;MAP WORD 0 IN THE EXEC MAP
	CLRPGT	(0,.ECKSM)	;CLEAR THE AM ENTRY
	MOVEI	T1,.ECKSM	;T1 = EXEC VIRTUAL ADDRESS OF WORD 0 OF THE
				; HIGH SEGMENT
	POPJ	P,		;RETURN
SUBTTL	UUOCON - UUO HANDLING ROUTINES

IFN FTDAEM,<
;SUBROUTINE TO DO PROCESSOR DEPENDANT PORTION OF JOB PEEK UUO
;CALLING SEQUENCE:
;	HRRI	T4,0 IF SOURCE SEGMENT IS A SPY SEGMENT
;	MOVE	P1,FLAGS,,JOB NUMBER (FLAGS BIT0=0 IF READ, 1 IF WRITE)
;	MOVE	P2,NUMBER OF WORDS TO TRANSFER
;	PUSHJ	P,JOBPKD
;	ALWAYS RETURN HERE

JOBPKD::PUSHJ	P,GETWDU##	;GET SOURCE AND DESTINATION ADDRESSES
	MOVSI	T2,(PXCT 5,)	;ASSUME SOURCE AND TARGET ADDRESSES ARE IN JOB DOING
	CAIN	J,(P1)		; THE JOBPEK (IF SO BOTH ARE ADDRESSABLE). ARE THEY?
	JRST	JOBPK3		;YES, BLT FROM USER TO USER
	MOVSI	T2,(PXCT 4,)	;ASSUME THE SOURCE SEGMENT IS A SPY SEGMENT
	TRNN	T4,-1		; I.E., THE MONITOR. IS IT?
	JRST	JOBPK3		;YES, BLT FROM MONITOR TO USER
	HRRZ	T2,JBTUPM##(P1)	;ADDRESS OF THE TARGET JOB'S UPMP
	TRO	T2,PM.ACC+PM.WRT;ALLOW ACCESS AND WRITING
	HRRM	T2,.UPMP+.MTEMP	;MAKE THE TARGET JOB'S UPMP ADDRESSABLE
	CLRPGT	(0,.JBPK)	;CLEAR THE AM FOR THIS PAGE
	HRRZ	T3,T1		;DESTINATION ADDRESS IF WRITING
	TLNN	P1,400000	;WRITING?
	HLRZ	T3,T1		;NO, READING. GET SOURCE ADDRESS
	TLNE	P1,200000	;READING THE UPMP?
	MOVSI	T3,1		;YES, VIRTUAL PAGE NUMBER 1000
	MOVE	T2,T3		;GET ADDRESS IN TARGET JOB
	ANDI	T2,PG.BDY##	;KEEP ONLY REL WD IN PAGE
	ADDI	T2,PG.BDY##(P2)	;ADD AND ROUND NO. WDS TO TRANSFER
	LSH	T2,W2PLSH##	;MAKE NO. OF PAGES
	LSH	T3,W2PLSH##	;CONVERT TO VIRTUAL PAGE NUMBER
	MOVNS	T2		;MINUS NUMBER OF PAGES TO MAKE ADDRESSABLE
	HRL	T2,T3		;STARTING VIRTUAL PAGE NUMBER IN TARGET JOB
	MOVSS	T2		;MAKE AN AOBJN POINTER
	ROT	T3,-1		;INDEX INTO TARGET JOB'S MAP (REMAINDER IN HIGH BIT)
	MOVEI	T4,.TEMP(T3)	;FORM A BYTE POINTER TO THE TARGET JOB'S MAP
	HRLI	T4,442200	;ASSUME AN EVEN STARTING PAGE
	SKIPGE	T3		;IS IT AN EVEN PAGE?
	HRLI	T4,222200	;NO, ODD
	MOVEI	T3,.UPMP+.MJBPK	;ADDRESS OF JOBPEK TEMPORARY SLOTS IN THE
				; PER-PROCESS MAP
	HRLI	T3,442200	;STARTING IN THE LEFT HALF WORD
JOBPK0:	ILDB	P3,T4		;GET THE ENTRY FROM THE TARGET JOB'S MAP
IFN	FTVM,<
	TRNE	P3,PM.ACC	;ACCESS ALLOWED?
	JRST	JOBPK1		;YES, ZOOM ON
	JUMPE	P3,CPOPJ##	;ERROR RETURN IF PAGE DOESN'T EXIST
	CAIN	P3,PM.ZER	;ALLOCATED BUT ZERO PAGE?
	POPJ	P,		;YES, PAGE NOT IN CORE RETURN
	HRRZ	P3,T2		;VIRTUAL PAGE WHICH HAS ACCESS ALLOWED OFF
	IDIVI	P3,^D36		;WORD IN WSBTAB WHICH CONTAINS BIT FOR THIS PAGE
	MOVE	P4,BITTBL##(P4)	;BIT POSITION WITHIN THE WORD
	TDNN	P4,WSBTAB-.UPMP+.TEMP(P3) ;PAGE IN CORE WITH ACCESS ALLOWED OFF?
	POPJ	P,		;NO, JUST GIVE PAGE NOT IN CORE RETURN
	LDB	P3,T4		;GET MAP ENTRY AGAIN
JOBPK1:	TRO	P3,PM.ACC!PM.WRT  ;ALLOW ACCESS
>
	IDPB	P3,T3		;STORE IT IN THIS JOB'S PER-PROCESS MAP
	AOBJN	T2,JOBPK0	;MAP ENOUGH PAGES TO ALLOW THE TRANSFER
	CLRPGT	(0,.JBPK)	;CLEAR THE AM FOR THIS PAGE
	MOVEI	T2,.JBPK/1000	;PAGE NUMBER IN THE EXEC VIRTUAL ADDRESS SPACE
	TLNE	P1,400000	;READ OR WRITE?
	JRST	JOBPK2		;WRITE
	DPB	T2,[POINT 9,T1,8] ;READ, MAKE SOURCE ADDRESS AN EXEC VIRTUAL ADDRESS
	MOVSI	T2,(PXCT 4,)	;READ FROM EXEC, WRITE TO USER
	JRST	JOBPK3		;GO DO THE BLT
JOBPK2:	DPB	T2,[POINT 9,T1,26] ;WRITING, MAKE DESTINATION AN EXEC VIRTUAL ADDRESS
	MOVSI	T2,(PXCT 1,)	;READ FROM USER, WRITE TO EXEC
JOBPK3:	ADDI	P2,(T1)		;ENDING ADDRESS EQUALS NUMBER OF WORDS PLUS
				; STARTING ADDRESS
	HRRI	T2,[BLT T1,-1(P2)] ;XCT 1, 2, OR 3 OF A BLT
	XCT	T2		;MOVE THE DATA
IFN FTVM,<
	AOS	(P)		;INDICATE ALL PAGES WERE IN CORE AND THE DATA
				; WAS TRANSFERED
>
	POPJ	P,		;RETURN
>
SUBTTL PERF. UUO FUNCTIONS TO HANDLE KL10 PERFORMANCE METER

COMMENT &
THE KL10 PERFORMANCE METER IS ASSUMED TO BE AN INTEGRAL PART OF
 THE KL10 PROCESSOR, AND THUS ITS DATA BASE IS FOUND IN THE
 CDB.  FOR THE PURPOSES OF DOCUMENTATION AND IN THE EVENT THAT
 A FUTURE CPU CAN HAVE MORE THAN ONE TYPE OF PERFORMANCE METER,
 A LIST OF THE CDB LOCATIONS USED FOR THE PERFORMANCE METER
 FOLLOWS:

	.CPPJB - JOB WHICH OWNS PERFORMANCE METER ON THIS CPU, 0 IF FREE
	.CPMJB - JOB ENABLE CONDITION, SET BY UUO. -2 = NULL JOB, 0 = DONT CARE
	.CPMJ1 - JOB ENABLE CONDITION, ONLY SET IF METER IS RUNNING.
		  THIS IS THE VARIABLE WHICH CLOCK1 USES TO TURN THE
		  METER ON AND OFF TO SIMULATE A JOB ENABLE CONDITION.
		  THIS VARIABLE IS NEEDED BECAUSE THE METER CAN BE
		  STOPPED AND THEN STARTED WITH THE SAME JOB ENABLE

	.CPPMR - SET NONZERO WHENEVER THE PERFORMANCE METER IS RUNNING
		  USED IN CHECKING FOR STARTING METER TWICE

	.CPPAE - USED TO STORE THE PERFORMANCE ANALYSIS ENABLES FOR METER
	.CPPRQ - SEMAPHORE USED IN TESTING AND GIVING METER AWAY

	.CPAPS - FLAG THAT CAUSES THE PERFORMANCE METER TO BE TURNED
		  ON AND OFF WITH THE ACCOUNTING METER

	.CPMM0
	.CPMM1 - DOUBLE WORD LOCATION THAT CONTAINS THE NUMBER OF
		  MBOX REFERENCES WHILE METER WAS ON AND ENABLED
		  JOB CONDITION TERM WAS TRUE. USEFUL FOR MEASURING
		  CACHE HIT RATE.


THE FORMAT OF THESE METER FUNCTIONS WAS SETUP TO ACCOMODATE FUTURE
 METERS IF NECESSARY:  EVERY ENABLE CONDITION IS A SEPARATE WORD.
 THE ORDER OF THE ENABLES WERE SPECIALLY CHOSEN SUCH THAT THE
 MOST FREQUENTLY USED ENABLES ARE FIRST.  SINCE UNSPECIFIED ARGUMENTS
 ALWAYS DEFAULT TO ZERO, THIS SAVES SPACE IN THE USER PERFORMANCE
 PROGRAM.
 INSTEAD OF CHECKING FOR TERMINATION OF THE ARGUMENT LIST EVERY TIME
 A WORD IS FETCHED OR STORED IN THESE ROUTINES, THE SPECIAL ROUTINES
 PF?WDU, PF?WD1 (?=G, GET OR P,PUT) ARE USED, WHICH RETURN 0 (DONT CARE)
 ON GETTING AFTER ARGS ARE EXHAUSTED OR ARE NOOPS WHEN AN ATTEMPT IS MADE
 BY THE FUNCTION ROUTINES TO PLACE A VALUE BEYOND THE LIMIT OF WHAT
 THE CALLER ASKED FOR.
&;END OF COMMENT

;THE FOLLOWING PERF. UUO FUNCTIONS ARE IN KLSER:
	INTERN PMRSET,PMRSTR,PMRRED,PMRSTP,PMRREL

;THE FOLLOWING ERROR ROUTINES ARE CALLED BY PERF. UUO FUNCTIONS
; IN KLSER, AND ARE FOUND IN UUOCON
	EXTERN PREICT,PRENXC,PREIPM,PREMNS,PREMIU,PREMAS
	EXTERN PREBJN,PREMNR,PREFNI,PREBFN,PREMBP
;FUNCION 1 - GET METER AND SETUP METER CONDITIONS
;
;FORMAT OF ARGUMENT BLOCK:
;
;ADDR:		;NUMBER OF WORDS FOLLOWING
;ADDR+1:		;CPU TYPES (1B0=PDP6,1B1=KA10,ETC.)
;ADDR+2:		;CPU NUMBER,,MODE
;ADDR+3:		;CACHE ENABLES
;ADDR+4:		;PI CHANNEL ENABLES
;ADDR+5:		;PC ENABLES
;ADDR+6:		;MICROCODE ENABLES
;ADDR+7:		;PROBE ENABLES
;ADDR+10:		;JOB
;ADDR+11:		;RH20 CHANNEL ENABLES
;ZERO ALWAYS INDICATES DON'T CARE.  FOR DETAILS ON WHAT THE
; ENABLE BITS ARE, REFER TO KL10 INTERNAL CLOCK SUPPORT FUNCTIONAL SPEC.

PMRSET:	PUSHJ	P,CHKPMS	;CHECK CPU TYPE STUFF AND SETUP P4
	  POPJ	P,		;ERROR OF SOME SORT (SEE CHKPMS)
	PUSHJ	P,GETPMR	;GET METER
	  JRST	PREMIU		;**METER BUSY**
;	PUSHJ	P,ONCPP4	;RESCHEDULE TO CPU IN P4
	PUSHJ	P,STPPMJ	;STOP METER
	TRZE	T4,1B35		;T4 HAS EVENT/DURATION STATE.
				;TEST BORROWED BIT (CLEAR/DON'T CLEAR)
	PUSHJ	P,CLRPMR	;ZERO OUT PERFORMANCE COUNT

;CACHE ENABLES
	PUSHJ	P,PFGWD1	;GET CACHE ENABLES FROM USER
	SKIPN	T1		;DON'T CARE??
	TLO	T4,(PE.CCI)	;YES, SET CACHE DON'T CARE
	TLZE	T1,(1B4)	;ACCOUNTING METER/PERFORMANCE METER SYNC BIT?
	SETOM	.CPAPS##(P4)	;YES, SET THE FLAG
	LSH	T1,<-<^L<PE.CCR>>-<^D18>> ;SHIFT INTO POSITION
	TRC	T1,(PE.CCR!PE.CCF!PE.EWB!PE.SWB) ;ACCOUNT FOR THE FACT
				; THAT THESE BITS ARE ZERO WHEN THE
				;CONDITION IS ENABLED!
	ANDI	T1,(PE.CCR!PE.CCF!PE.EWB!PE.SWB) ;PREVENT OTHER BITS FROM SETTING
	TSO	T4,T1		;SET DESIRED BITS

;PI ENABLES
	PUSHJ	P,PFGWD1	;GET PI ENABLES
	SKIPN	T1		;DON'T CARE??
	TRO	T4,PE.PIN	;PI IGNORE IF ZERO ARG
	LSH	T1,<-<^L<PE.PP0>>>	;SHIFT INTO POSITION
	ANDI	T1,PE.PIN	;CLEAR OUT ERRONEOUS BITS
	TDO	T4,T1		;AND SET THEM IN T4

;PC ENABLES
	PUSHJ	P,PFGWD1	;GET THEM
	TLCE	T1,(1B0!1B1)	;IF ALL BITS ARE ZERO OR
	TLNN	T1,(1B0!1B1)	;IF BOTH ARE SET
	TRO	T4,PE.PCI	;SET PC IGNORE
	TLNN	T1,(1B1)		;IN ANY CASE, WANT USER PC?
	TRO	T4,PE.PCU	;YES,SET PC USER (NN BECAUSE BITS ARE COMP.)
;MICROCODE ENABLES
	PUSHJ	P,PFGWD1	;GET UCODE ENABLES
	TLNN	T1,(1B0)	;SKIP IF UCODE STATE ENABLED
	TLO	T4,(PE.UCI)	;NOT ENABLED, SET UCODE IGNORE BIT

;PROBE ENABLES
	PUSHJ	P,PFGWD1	;GET THEM
	TLCE	T1,(1B0!1B1)	;IF BOTH OFF OR
	TLNN	T1,(1B0!1B1)	;BOTH ON
	TLO	T4,(PE.PRI)	;IGNORE PROBE
	TLNN	T1,(1B0)	;IN ANY CASE, WANT PROBE LOW? (COMP)
	TLO	T4,(PE.PRL)	;YES, ENABLE PROBE LOW

;JOB ENABLE
	PUSHJ	P,PFGWD1	;JOB ENABLE
	JUMPE	T1,PMRST1	;IGNORE IS OK
	CAMN	T1,[-1]		;SELF?
	MOVE	T1,J		;YES
	CAMN	T1,[-2]		;NULL JOB?
	JRST	PMRST1		;YES, DON'T CALL LGLPRC
	PUSHJ	P,LGLPRC##	;IS THIS A LEGAL NUMBER?
	  JRST	PREBJN		;BAD JOB NUMBER
PMRST1:	MOVEM	T1,.CPMJB##(P4)	;EVERYTHING'S OK, STORE JOB ENABLE

;NOW FOR CHANNEL ENABLES
	PUSHJ	P,PFGWD1	;GET THEM
	SKIPN	T1		;DON'T CARE?
	TLO	T4,(PE.CPI)	;YES, SET ALL BITS FOR DON'T CARE
	LSH	T1,<-<^L<PE.CP0>-<^D18>>> ;POSITION (IN RH)
	ANDI	T1,(PE.CPI)	;CLEAR UNWANTED BITS
	TSO	T4,T1		;AND SET THE BITS

;ADD FURTHER ENABLE LOGIC HERE

	MOVEM	T4,.CPPAE##(P4)	;AT LAST
	JRST	CPOPJ1##	;BYE.
;FUNCTION 2 - START METER
;
;THE METER MUST BE OWNED BY THE CALLING JOB (CHECKED BY PRFCPU).
; SPECIAL CARE IS TAKEN NOT TO START THE METER IF THE CALLING JOB DOES NOT
;SATISFY THE JOB ENABLE CONDTION.  AFTER THE METER IS STARTED,
; THE FUNCTION RETURNS THE DOUBLE WORD TIME BASE AND PERFORMANCE COUNT
; IN THE ARGUMENT BLOCK, WHICH HAS THE FOLLOWING FORMAT:
;
;ADDR:			;COUNT OF WORDS FOLLOWING
;ADDR+1:		;CPU NUMBER
;ADDR+2:		;HIGH ORDER TIME BASE RETURNED HERE
;ADDR+3:		;LOW ORDER TIME BASE RETURNED HERE
;ADDR+4:		;HIGH ORDER PERFORMANCE METER VALUE
;ADDR+5:		;LOW ORDER "			"

PMRSTR:	PUSHJ	P,PRFCPU	;CHECK CPU SPEC, SETUP P4, MAKE SURE METER IS OWNED
	  POPJ	P,		;SORRY, SOMETHING WENT WRONG
	SKIPE	.CPPMR##(P4)	;SKIP IF METER IS NOT STARTED ALREADY
	JRST	PREMAS		;**METER ALREADY STARTED**
;	PUSHJ	P,ONCPP4	;MUST RESCHEDULE ON THE RIGHT CPU TO START METER
	CONO	PI,PIOFF	;TURN OFF PI SO WE CAN START AND READ
				;METER WITHOUT INTERRUPTIONS
	PUSHJ	P,STRPMJ	;START METER IF WE'RE SUPPOSED TO

;FALL INTO STORPT

STORPT:	PUSHJ	P,REDPMT	;READ TIME BASE AND PERF METER INTO T1-T4
	PUSH	P,.CPMM1##(P4)	;ALSO SAVE MEMORY REFERENCE COUNT BEFORE
	PUSH	P,.CPMM0##(P4)	; PI SYSTEM IS TURNED BACK ON
	CONO	PI,PION		;TURN PI BACK ON
	PUSHJ	P,PFPWD1	;STORE HIGH ORDER TIME BASE
	MOVE	T1,T2
	PUSHJ	P,PFPWD1	;STORE LOW ORDER TIME BASE
	MOVE	T1,T3
	PUSHJ	P,PFPWD1	;STORE HIGH ORDER PERFORMANCE COUNT
	MOVE	T1,T4
	PUSHJ	P,PFPWD1	;STORE LOW ORDER PERF COUNT
	POP	P,T1		;GET HIGH ORDER MEMORY REFERENCE COUNT BACK
	PUSHJ	P,PFPWD1	;GIVE THAT TO USER
	POP	P,T1		;NOW GET LOW ORDER MEM REF COUNT
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	PFPWD1		;STORE LOW ORDER MBOX COUNT AND RETURN
;FUNCTION 3 - READ PERFORMANCE METER
;
;FORMAT OF ARGUMENT LIST SAME AS FUNCTION 2, START METER

PMRRED:	PUSHJ	P,PRFCPU	;CHECK AND SETUP CPU STUFF, METER OWNER
	  POPJ	P,		;SOMETHING WENT WRONG
;	PUSHJ	P,ONCPP4	;RESCHEDULE ONTO PROPER CPU FOR THIS METER
	PJRST	STORPT		;STORE TIME BASE, PERF COUNT AND RETURN


;FUNCTION 4 - STOP METER
;
;FORMAT OF ARG LIST SAME AS START AND READ FUNCTIONS
;

PMRSTP:	PUSHJ	P,PRFCPU	;SETUP P4, CHECK METER OWNERSHIP
	  POPJ	P,		;OOOPS
;	PUSHJ	P,ONCPP4	;PUT OURSELVES ONTO PROPER CPU
	SKIPN	.CPPMR##(P4)	;IS METER RUNNING?
	JRST	PREMNR		;**METER NOT RUNNING** (SO WHY STOP IT?)
	PUSHJ	P,STPPMJ	;STOP METER
	PJRST	STORPT		;STORE GOOD STUFF AND RETURN
;FUNCTION 5 - RELEASE METER

;FORMAT OF ARGUMENT BLOCK:
;
;ADDR:			;NUMBER OF WORDS FOLLOWING
;ADDR+1:		;CPU NUMBER OF METER TO RELEASE


PMRREL:	PUSHJ	P,PRFCPU	;GOOD CPU? THEN SETUP P4 AFTER WE KNOW WE OWN METER
	  POPJ	P,		;SORRY CHARLIE
;	PUSHJ	P,ONCPP4	;RESCHEDULE ONTO PROPER CPU
	PUSHJ	P,STPPMJ	;STOP METER
	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	RELPMR		;AND RELEASE, RETURN
;ROUTINE TO CHECK INITAL CPU/METER SPECIFICATION
; CALL WITH M SETUP TO POINT TO ADDRESS BEFORE CPU TYPE WORD.
; SMASHES T1-T3, RETURNS T4 WITH EVENT MODE BIT EITHER SET OR CLEAR
; DEPENDING ON THE MODE ARGUMENT THE CALLER SUPPLIES.
; THIS ROUTINE ALSO BORROWS BIT 35 TO INDICATE WHETHER OR NOT THE
; PERFORMANCE METER COUNT SHOULD BE CLEARED OR NOT.  THIS BIT
; SHOULD BE CLEARED IMMEDIATELY AFTER CHECKING, SINCE IT MIGHT
; BE USED BY THE HARDWARE
;
;AN ERROR RETURN IS GIVEN FROM THIS ROUTINE IF THE CPU SPECIFICATION
; IS INCORRECT OR A CPU NUMBER CORRESPONDING TO A NON-EXISTANT CPU IS GIVEN.
; THE CALLER MUST ACTUALLY GET CONTROL OF THE METER.

CHKPMS:	PUSHJ	P,PFGWD1	;GET CPU TYPES ACCEPTABLE
	MOVE	T3,T1		;SAVE IN T3
	PUSHJ	P,PFGWD1	;GET CPU NUMBER,,MODE
	TLNE	T1,-1		;SKIP IF CPU0 (ONLY ONE LEGAL FOR NOW)
	JRST	PRENXC		;**NON EXISTANT CPU**
	TLNN	T3,(1B3)		;CPU TYPE MUST BE KL10 FOR THIS FUNCTION
	JRST PREICT		;**IMPROPER CPU TYPE**

	MOVEI	P4,.C0CDB	;SETUP P4 FOR EVERYONE
	SETZ	T4,		;START WITH ZERO FOR PERFORMANCE ENABLE WORD
	TRNN	T1,1B18		;SKIP IF NOT EVENT MODE
	MOVEI	T4,PE.EVM	;IS EVENT MODE, SET THE BIT
	TRNE	T1,1B19		;CLEAR METER COUNT?
	TRO	T4,1B35		;YES, BORROW A BIT TO TELL ABOUT IT
	PJRST	CPOPJ1##	;AND GIVE SKIP RETURN


;THIS ROUTINE IS USED IN THE START, READ, STOP, AND RELEASE ROUTINES.
; IT CHECKS THE CPU NUMBER FOR LEGALITY, AND GIVES ERROR RETURN IF
; CPU NUMBER IS BAD.  IT ALSO GIVES AN ERROR RETURN IF
; THE CALLER (WHOSE JOB IS IN AC J) DOES NOT OWN THE METER.
; THIS ROUTINE DISTINGUISHES BETWEEN THE CASES OF METER IN USE
; AND METER NOT SETUP WHEN IT DISCOVERS THAT THE CALLER DOES NOT
; OWN THE METER.  M SHOULD BE SETUP TO POINT TO THE ITEM COUNT
; OF THE ARG BLOCK. AC'S T3-T4 ARE PRESERVED. P4 IS SETUP TO BE
; THE CPU DATA BLOCK OF THE SPECIFIED CPU.

PRFCPU:	PUSHJ	P,PFGWD1	;GET CPU NUMBER
	JUMPN	T1,PRENXC	;**NON EXISTANT CPU**
	MOVEI	P4,.C0CDB	;SETUP P4
	PUSHJ	P,HAVPMR	;DO WE OWN THE METER??
	  CAIA			;NO, SEE WHAT'S WRONG
	JRST	CPOPJ1##	;YES, RETURN
	SKIPE	.CPPJB##(P4)	;IS METER OWNED BY SOMEONE ELSE??
	JRST	PREMIU		;**METER IN USE**
	JRST	PREMNS		;**METER NOT SETUP**

;SPECIAL ROUTINES TO PICK UP ARGUMENTS FOR PERFORMANCE METER FUNCTIONS.
; IF THE COUNT GIVEN BY THE CALLER (IN P2) IS EXHAUSTED, THE PUTTER
; ROUTINE DOES NOTHING AND THE GETTER ROUTINE RETURNS A ZERO
; (DON'T CARE).  THIS SAVES SOME CHECKING ELSEWHERE.

PFPWD1:	SOJL	P2,CPOPJ	;IF COUNT IS GONE, DO NOTHING
	PJRST	PUTWD1##	;ELSE DO PUTWD1

PFGWD1:	SETZ	T1,		;CLEAR T1 IN CASE COUNT IS GONE
	SOJL	P2,CPOPJ	;RETURN ZERO IF COUNT EXHAUSTED
	PJRST	GETWD1		;ELSE DO GETWD1

;ROUTINE TO READ IN TIME BASE AND PERFORMANCE METER COUNT AT THE
; SAME TIME, MAKING SURE NO INTERRUPTS INTERFERE.
;
;RETURNS TIME BASE HI AND LO IN T1,T2 AND PERF COUNT IN T3,T4
;
;MUST BE ON CPU OF TARGET METER - CALLER'S RESPONSIBILITY
;
;PRESERVES P AC'S, T1-T4 ARE DESTROYED

REDPMT::CONSO	PI,PION		;PI OFF ALREADY?
	JRST	REDPM1		;YES, DON'T TURN IT ON AGAIN
	PUSHJ	P,REDPM1	;NO, TURN IT ON AFTER WERE THROUGH
	PJRST	ONPOPJ##

REDPM1:	CONO	PI,PIOFF	;TURN OFF PI
	RDTIME	T1		;HI AND LO INTO T1,T2
	RDPERF	T3		;HI AND LO PERF INTO T3,T4
	POPJ	P,		;RETURN

;ROUTINE TO START PERFORMANCE METER USED BY PERF. UUO
; SETS UP JOB CONDITION FOR CLOCK1 AND THEN USES SCDPR1
; TO START THE METER IF THE JOB ENABLE CONDITION IS SATISFIED.
; PRESERVES ALL AC'S EXECPT T1. MUST BE CALLED ON CPU OF DESIRED METER, P4
; = CPU DATA BLOCK. PRESERVES STATE OF PI SYSTEM (ON,OFF)

STRPMJ::PUSH	P,.CPMJB##(P4)	;PUT METER ENABLE INTO
	POP	P,.CPMJ1##(P4)	;PROPER WORD
	SETOM	.CPPMR##(P4)	;SAY THAT METER IS RUNNING
	PJRST	SCDPR1		;START METER IF WE'RE SUPPOSED TO AND RETURN

;ROUTINE TO START PERFORMANCE METER USED BY CLOCK1, CALLED BY STRPMJ.
; THIS ROUTINE ACTUALLY STARTS THE PERFORMANCE METER ACCORDING TO
; THE CONDITIONS IN .CPPAE. PRESERVES ALL AC'S, STATE OF PI SYSTEM.
; CALL WITH P4 = CPU DATA BLOCK, MUST BE ON CPU OF TARGET METER.

STRPMR::WRPAE	.CPPAE##(P4)	;THIS IS ALL THAT'S NECESSARY
	POPJ	P,		;THERE, THAT WAS EASY

;ROUTINE TO STOP METER USED BY PERF UUO.
; STOPS METER AND CLEARS JOB ENABLE FLAG FOR CLOCK1 SO IT DOESN'T
; TURN THE METER ON. USES ACS T1,T2. PRESERVES STATE OF PI SYSTEM.
; CALL ON CPU OF TARGET METER WITH P4 = CPU DATA BLOCK

STPPMJ::PUSHJ	P,CHKPMJ	;WERE WE PART OF THE JOB ENABLE CONDITION?
	  JRST	STPPJ1		;NO, DON'T UPDATE MBOX REFERENCE COUNT
	PUSHJ	P,GETMBT	;GET MBOX REFERENCES IN T1,T2
	DADD	T1,.CPMM0##(P4)	;UPDATE COUNT
	DMOVEM	T1,.CPMM0##(P4)
STPPJ1:	SETZM	.CPMJ1##(P4)	;CLEAR JOB ENABLE THAT CLOCK1 LOOKS AT
	SETZM	.CPPMR##(P4)	;AND SAY THAT METER IS NOW STOPPED
;	PJRST	STPPMR		;STOP METER AND RETURN

;ROUTINE TO STOP PERF METER.  DOESN'T TOUCH JOB ENABLE, SO CLOCK1
; CAN CALL IT TO START AND STOP METER FOR JOB ENABLE LOGIC.
; PRESERVES ALL AC'S, STATE OF PI SYSTEM. CALL ON CPU OF TARGET METER
; WITH P4 SETUP ACCORDINGLY.

STPPMR::WRPAE	[0]		;ZERO STOPS THE METER
	POPJ	P,		;ANOTHER COMPLICATED ROUTINE
;ROUTINE TO GET THE PERFORMANCE METER USED BY PERF. UUO
; CALL WITH JOB NUMBER OF CALLER IN J, ADDRESS OF CPU DATA
; BLOCK OF CPU OF TARGET METER IN P4. NEED NOT BE ON THE
; CPU OF TARGET METER.  NON-SKIP RETURN IF METER IS ALREADY IN
; USE, SKIP RETURN IF ALREADY OWN METER OR METER WAS FREE.

GETPMR:	CAMN	J,.CPPJB##(P4)	;ALREADY OWN IT?
	JRST	CPOPJ1##	;YES, GOOD RETURN
	AOSE	.CPPRQ##(P4)	;AVAILABLE?
	POPJ	P,		;NO, NOT NOW.
	MOVEM	J,.CPPJB##(P4)	;YES, PUT OUR NAME ON THE METER
	JRST	CPOPJ1##	;GOOD RETURN


;ROUTINE TO RELEASE PERFORMANCE METER USED BY PERF. UUO AND 
; EMERGENCY ROUTINES (RESET, SWAP READ ERROR, ETC.)
; CALL WITH P4 = CPU DATA BLOCK OF TARGET PERF METER. NEED NOT
; BE RUNNING ON TARGET CPU (SO SWAPPER CAN CALL, RESET, ETC.)
; CLEARS AL METER VARIABLES FOR SPECIFIED CPU. 
; ALL AC'S PRESERVED.

RELPMR::SETZM	.CPAPS##(P4)	;CLEAR PERF/ACC METER SYNC FLAG
	SETZM	.CPMJB##(P4)	;CLEAR MEASURED JOB
	SETOM	.CPMJ1##(P4)	;-1 IS FLAG FOR CLOCK1 TO STOP METER
	SETZM	.CPPJB##(P4)	;CLEAR OWNING JOB
	SETZM	.CPPAE##(P4)	;AND PERFORMANCE ENABLES
	SETOM	.CPPRQ##(P4)	;NOW MAKE METER AVAILABLE
	POPJ	P,		;ONLY RETURN
				;(ALWAYS SUCCEEDS!)

;ROUTINE TO CHECK IF THE JOB IN J OWNS THE PERFORMANCE METER
; OF THE CPU WHOSE CPU DATA BLOCK ADDRESS IS IN P4.
; NEED NOT BE RUNNING ON THAT CPU.
; USED BY PERF. UUO ONLY - PRESERVES ALL AC'S.

HAVPMR::CAMN	J,.CPPJB##(P4)	;OWN METER?
	AOS	(P)		;YES, SKIP RETURN
	POPJ	P,		;OR ELSE NOT.

;ROUTINE TO CLEAR PERFORMANCE METER COUNT
; USED BY PERF. UUO AT METER SETUP TIME. CALLER SHOULD
; MAKE SURE THAT IT OWNS THE METER INVOLVED.
; CALLER MUST MAKE SURE HE IS RUNNING ON CPU OF TARGET
; METER. CALLER SHOULD ALSO MAKE SURE METER IS STOPPED.

CLRPMR:	WRPAE	[PE.CLR]	;CLEAR HARDWARE COUNTER
	SETZM	.EPHPA##	;CLEAR HI PERF COUNT
	SETZM	.EPLPA##	;AND LO
	SETZM	.CPMM0##(P4)	;CLEAR OUT MBOX COUNT ALSO
	SETZM	.CPMM1##(P4)	;HIGH AND LOW ORDERS
	POPJ	P,		;RETURN
;ROUTINE CALLED AFTER SCHEDULER IN CLOCK1 TO IMPLEMENT JOB ENABLE CONDITION.
; .CPMJ1 CONTAINS THE ENABLE CONDITION. -2 IS NULL JOB, -1 IS A SPECIAL
; CODE MEANING STOP THE METER (USED IF A RESET IS DONE BEFORE METER
; IS RELEASED), 0 MEANS THE JOB ENABLE IS DON'T CARE, AND NON-ZERO
; MEANS LEAVE THE METER RUNNING IF AND ONLY IF THE JOB NUMBER
; IN .CPMJ1 IS ABOUT TO BE RUN.  ALL ACS PRESERVED.


SCDPMR::PUSH	P,T1		;SAVE T1
	PUSHJ	P,SCDPR1	;CALL THE ROUTINE
	JRST	TPOPJ##		;RESTORE T1 AND RETURN

SCDPR1:	MOVE	T1,.CPMJ1##(P4)	;GET JOB ENABLE CONDITION
	AOJE	T1,STPPMR	;IT WAS A REQUEST TO STOP METER, DO IT.
	PUSHJ	P,CHKPMJ	;CHECK THE JOB ENABLE CONDITION.
	PJRST	STPPMR		;NOT SATISFIED, STOP THE CLOCK
	PJRST	STRPMR		;IS SATISFIED, START UP THE CLOCK, EVEN
				;THOUGH IT MAY BE STARTED ALREADY (SO WHAT)

;ROUTINE TO CHECK ON THE JOB ENABLE CONDITION.
; CALL WITH JOB NUMBER TO BE TESTED IN J, CPU DATA BLOCK ADDR IN P4.
; GIVES SKIP RETURN IF THE JOB IN J CAUSES THE CPU ENABLE CONDITION
; FOR THE PERFORMANCE METER TO BE SATISFIED, NON-SKIP IF THE CONDITION
; IS NOT SATISFIED OR SOMEONE IS TRYING TO STOP THE METER (-1 IN .CPMJ1).
;USES T1.

CHKPMJ::SKIPN	T1,.CPMJ1##(P4)	;GET JOB ENABLE. IS IT ZERO?
	JRST	CPOPJ1##	;YES, CONDITION IS DON'T CARE, GIVE SKIP RETURN
	CAMN	J,T1		;NO, DOES .CPMJ1 CONTAIN JOB NUMBER WHICH
				; IS IN J?
	JRST	CPOPJ1##	;YES, GIVE SKIP RETURN
	AOJGE	T1,CPOPJ##	;IF T1 = -1, SOMEONE WANTS METER STOPPED.
				; CALLER'S RESPONSIBILITY TO STOP IT
				; IF T1 WAS .GT. ZERO, CONDITION FOR JOB IS NOT MET, SO
				; GIVE NON-SKIP RETURN
	PJUMPE	J,CPOPJ1##	;JOB ENABLE MUST HAVE BEEN NULL JOB.
				; IF J .EQ. 0, ENABLE CONDITION IS SATISFIED.
	POPJ	P,		;SORRY, CONDITION NOT SATISFIED
	$LIT
KLEND:	END