Google
 

Trailing-Edge - PDP-10 Archives - 7.01A_PCL20_KMCSRC_19830513 - ksser.mac
There are 6 other files named ksser.mac in the archive. Click here to see a list.
TITLE	KSSER - KS10 PROCESSOR DEPENDENT CODE  V1041
SUBTTL	DMCC/DBD	01 JUL 80
	SEARCH	F,S
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1978,1979,1980,1982 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;
;********************  DDS EDIT HISTORY  *******************************
;
;  APR83  [DDS]  ADDED PCL20 CODE.
;
;***********************************************************************
;

XP VKSSER,1041
;TRACKS VERSION 274 OF KLSER

	ENTRY	KSSER		;LOAD KSSER IF LIBRARY SEARCH
KSSER:

SUBTTL DEFINITIONS FOR NON-EXISTENT FEATURES ON KS10

;NO ADDRESS BREAK
	XP	SETBRK,COMERA##
	XP	SETABR,CPOPJ##
	XP	CLRBRK,CPOPJ##
SUBTTL TRAP HANDLING AND CONTEXT SWITCHING

;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##	;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::
SETAP1::PUSHJ	P,SETRP		;SETUP THE TRAP LOCATIONS (PAGE FAULT,
				; ARITHMETIC, PDL OVF)
	PJRST	SETCNA		;SET USER ENABLES FOR NXM AND CLOCK AND
				; SET THE APR PIA

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

SETRP:	TRNE	T1,AP.AOV+AP.FOV;IS HE?
	TDZA	T2,T2		;YES, SET TO FIELD TRAPS
	MOVSI	T2,(JFCL)	;IGNORE ARITHMETIC TRAPS IF USER NOT ENABLED
	HRRI	T2,UE.AOT	;SET DISPATCH ADDRESS
	MOVEM	T2,.UPMP+.UPAOT	;STORE IN UPT
	MOVEI	T2,UP.PDT	;IF USER NOT ENABLED FOR POV HANDLE LIKE EXEC POV
	TRNE	T1,AP.POV	;IS HE ENABLED?
	MOVEI	T2,UE.PDT	;YES, HANDLE DIFFERENTLY
	MOVEM	T2,.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-UE.NXM ;CLEAR ALL BUT CLOCK, NXM, AND PARITY
	HRR	T1,.CPEEB##	;SET MONITOR ENABLES
	MOVEI	T2,@.CPAPI##	;MOVE IN APR PIA
	WRPI	PI.OFF		;DISALLOW INTERRUPTS WHILE CHANGING APR BITS
	HLRM	T1,.CPCN1##	;USER'S ENABLE BITS
	HRRM	T1,.CPCON##	;MONITOR'S ENABLE BITS
	WRAPR	(T2)		;SET PIA
	WRPI	PI.ON		;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::	WRPI	PI.OFF		;PREVENT CLOCK INTERRUPT DURING STOP2 CODE
	SETOM	.CPCKF##	;SET FLAG TO INDICATE CLK INTERRUPT
				; EVEN THOUGH CLK INTERRUPT IS NOT A TIME INTERRUPT
	WRPI	PI.ON+PI.IIO+CLKBIT## ;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:	RDPI	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

;WARNING:  ANY CHANGES MADE TO TSTREL SHOULD ALSO BE REFLECTED IN GETWRD & PUTWRD

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
;HERE TO PROCESS USER ARITHMETIC OVERFLOW TRAPS
SAROVF::MOVE	T1,.UPMP+.UPMUP	;GET PC
	MOVE	T3,.JDAT+JOBENB## ;GET USER'S ENABLE BITS
	TRNN	T3,AP.AOV	;OVERFLOW - IS THE USER ENABLED?
	TLNE	T1,(XC.FOV)	;TRAP CAUSED BY FOV?
	CAIA			;YES,
	JRST	SAROV6		;NOT ENABLED, IGNORE IT
	HRRI	T3,AP.AOV+AP.FOV;ASSUME FLOATING OVERFLOW
	TLNN	T1,(XC.FOV)	;WAS IT A FLOATING OVERFLOW TRAP?
	TRZ	T3,AP.FOV	;NO, INTEGER OVERFLOW
;HERE WITH T1=PC, T3=APRENB BITS
SAROV3:	TLZ	T1,3637		;CLEAR BITS FOR COMPATABILITY
	MOVEM	T1,.JDAT+JOBTPC## ;SAVE OLD PC
	MOVEM	T3,.JDAT+JOBCNI## ;LIKE CONI ON THE KA-10
	MOVE	T3,.JDAT+JOBENB## ;GET USER'S ENABLE BITS
	TRNE	T3,XP.DDU	;USER WANT TRAPS REENABLED?
	JRST	SAROV5		;YES, LEAVE AS IS
	HLLZS	.JDAT+JOBENB##	;CLEAR USER'S ENABLE BITS SO MUST DO APRENB AGAIN
	MOVSI	T3,(JFCL)	;NOP
	MOVEM	T3,.UPMP+.UPAOT	;IGNORE ARITHMETIC TRAPS
	MOVEI	T3,UP.PDT
	MOVEM	T3,.UPMP+.UPPDT	;EXEC WILL FIELD PDL OVERFLOWS
	SETZM	.CPCN1##	;CLEAR POSSIBLE NXM OR CLOCK ENABLES
SAROV5:	MOVEI	T3,XP.CLK	;ALWAYS DISABLE CLOCK
	ANDCAM	T3,.CPCN1##
	HRRZ	T3,.JDAT+JOBAPR## ;PC IN TRAP ROUTINE?
	CAIE	T3,0(T1)
	CAIN	T3,-1(T1)
	JRST	SAROV7		;YES
	HRR	T1,.JDAT+JOBAPR## ;GET USER'S TRAP ADDRESS
	TLZ	T1,(XC.OVF+XC.FOV+XC.FUF+XC.NDV+IC.BIS)
	TLO	T1,(XC.USR)	;INSURE PUBLIC AND USER MODE IS SET
SAROV6:	MOVEM	T1,.UPMP+.UPMUO	;NEW PC WITH TRAP CAUSING BITS CLEARED
	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;SET UP A STACK
	PUSHJ	P,SCDCHK##	;CHECK IF WE SHOULD RESCHEDULE
	USERAC			;SET USER AC BLOCK
	JRSTF	@.UPMP+.UPMUO	;EXIT TO THE USER'S TRAP HANDLER
SAROV7:	MOVEM	T1,.CPAPC##	;SAVE OLD PC FOR THE ERROR MESSAGE
	MOVEI	T1,XP.LTH	;STUCK IN LOOP BIT
	HRRM	T1,.CPAEF##
	JRST	SEPDL3
;HERE TO PROCESS EXEC STACK OVERFLOW TRAPS

SEPDLO::EXCH	T1,.UPMP+.UPMUP	;GET THE PC
	MOVEM	T1,.CPAPC##	;SET AS ERROR PC FOR ERRCON
	HRRI	T1,AP.POV	;SET PUSH DOWN OVERFLOW FLAG
SEPDL1:	HRRM	T1,.CPAEF##	;IN .CPAEF SO ERRCON WILL GET CALLED
	MOVE	T1,.UPMP+.UPMUP	;RESTORE T1
SEPDL3:	SETOM	.CPSCF##	;SET FORCED RESCHEDULING FLAG
	SETOM	.CPCKF##	;AND CLOCK FLAG
	WRPI	CLKBIT##+PI.IIO	;REQUEST A CLOCK INTERRUPT AND TURN THE PI SYSTEM ON
	CONSO	PI,II.IPA	;ANY PIS 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) INSTEAD OF HERE
	MOVEM	P,PIPPDL	;SAVE OLD STACK POINTER
	MOVEI	P,PIPPDL	; AND GET NEW ONE
	STOPCD	.,STOP,PIP,	;++PI IN PROGRESS
	$LOW
PIPPDL:	EXP	0
	BLOCK	1
	$HIGH
;HERE TO PROCESS PAGE FAILURE TRAPS

SEILM::	RDPI	.CPTPI##	;SAVE THE PI STATE
	WRPI	PI.OFF		;NOW INSURE THAT PI'S ARE OFF
	RDUBR	.CPTCX##	;SAVE THE TRAP CONTEXT
	EXECAC			;WANT MONITOR'S AC BLOCK
	MOVEM	T1,.CPSTT##	;SAVE T1 TEMPORARILY
	LDB	T1,[POINT 5,.UPMP+.LMPFW,5] ;PICK UP PF CODE
	CAIGE	T1,20		;IS THIS A REAL PAGE FAULT?
	JRST	SEILMA		;YES--GO PROCESS IT
	CAIN	T1,PF.IOP	;IS IT A UBA FAILURE?
	STOPCD	(.,STOP,UAF)	;++UNIBUS ADDRESSING FAILURE
	CAIL	T1,PF.PAR	;IS IT A PARITY OR NXM TRAP?
	JRST	PRTRP		;YES--GO PROCESS
	CAIN	T1,PF.PTP	;IS IT PAGE TABLE PARITY?
	JRST	PTPAR		;YES--GO PROCESS
	STOPCD	(.,CPU,IPC)	;++ILLEGAL PAGE FAILURE TRAP CODE
;HERE ON A PARITY OR NXM TRAP

PRTRP:	SKIPE	.CPPSP##	;CORE SWEEP IN PROGRESS?
	JRST	SWTRP		;YES, JUST SAVE LOCATION OF FAILURE AND DISMISS
	EXCH	T1,.CPSTT##	;RESTORE T1 AND SAVE TRAP CODE
	MOVEM	17,.CPA17##	;SAVE AC 17
	MOVEI	17,.CPA00##	;MAKE BLT POINTER
	BLT	17,.CPA17##-1	;SAVE AC'S IN CPU DATA BLOCK
	MOVE	P,.CPEPD##	;SET UP ERROR STACK
	MOVE	J,.CPJOB##	;SET UP J WITH CURRENT JOB RUNNING
	MOVE	T1,JBTPPN##(J)	;GET ITS PPN
	MOVEM	T1,.CPEJN##	; AND SAVE IT
	MOVE	T1,JBTNAM##(J)	;GET ITS PROGRAM NAME
	MOVEM	T1,.CPEPN##	; AND SAVE IT
	MOVE	P4,.CPSTT##	;GET THE TRAP CODE
	CAIE	P4,PF.NXM	;IS IT A NXM?
	SKIPA	P4,[UE.PEF]	;NO--SET UP PARITY ERROR FLAG
	MOVEI	P4,UE.NXM	;YES--SET UP NXM FLAG
	AOS	.CPNPT##	;COUNT TOTAL NUMBER OF PARITY/NXM TRAPS
	MOVE	T1,.UPMP+.LMPFP	;GET THE PAGE FAIL PC
	MOVEM	T1,.CPPPC##	;SAVE THE PC FOR DAEMON
	MOVEM	T1,.CPMPP##	;SAVE HERE IF NEEDED FOR PI 7 MESSAGES TO JOBS
	MOVE	T2,.UPMP+.LMPFW	;GET THE PAGE FAIL WORD
	MOVEM	T2,.CPPFW##	;SAVE THE PAGE FAIL WORD FOR DAEMON
	TRNE	P4,UE.NXM	;IS THIS A NXM?
	JRST	PRTRPC		;YES--THEN THERE'S NO DATA TO PICK UP
	WRUBR	[LG.LAB+7B11]	;NO--SET PREVIOUS ACS TO BLOCK 7
	PXCT	PX.MEM,[MOVE T3,0] ;PICK UP BAD DATA WORD FROM BLOCK 7
	EXECAC			;RESTORE MONITOR AC SETTINGS
	MOVEM	T3,.CPTBD##	;SAVE BAD DATA FOR DAEMON
PRTRPC:	MOVE	T4,[PXCT PX.MEM,[MAP P1,(T2)]] ;SET UP PXCT OF MAP INSTRUCTION
	SKIPL	.CPPFW##	;IS THIS A USER CONTEXT REFERENCE?
	TLZ	T4,(PX.MEM,)	;NO--THEN PXCT BECOMES REGULAR XCT
	XCT	T4		;DO A MAP TO TURN PF WORD INTO PHYS ADDR IN P1
	MOVEM	P1,.CPPBA##	;SAVE BAD PHYSICAL ADDR FOR DAEMON
	TLZ	P1,777760	;GET RID OF LEFT HALF STUFF
	ROT	P1,W2PLSH##	;TURN RH OF P1 INTO PAGE NUMBER OF BAD LOC
	MOVE	T3,.CPTOS##	;GET PAGE NUMBER OF EPMP FOR THIS CPU
	PUSH	P,.MERPL(T3)	;SAVE 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
	TRNE	P4,UE.NXM	;IS THIS A NXM?
	SKIPA	T1,[[ASCIZ / non-existent memory trap/]] ;YES
	MOVEI	T1,[ASCIZ / parity trap/] ;NO
	PUSHJ	P,PRMPC		;ANNOUNCE ERROR
	MOVEI	T1,[ASCIZ /Page fail word = /]
	MOVE	T2,.CPPFW##
	PUSHJ	P,PRMHW		;PRINT THE PAGE FAIL WORD
	MOVEI	T1,[ASCIZ /Mapped page fail address = /]
	MOVE	T2,.CPPBA##
	PUSHJ	P,PRMHW		;PRINT THE MAP WORD (PHYS. ADDRESS)
	MOVEI	T1,[ASCIZ /Incorrect contents = /]
	MOVE	T2,.CPTBD##
	TRNN	P4,UE.NXM	;IF A NXM, NO DATA TO PRINT
	PUSHJ	P,PRMHW		;PRINT THE BAD DATA
	MOVEI	T1,[ASCIZ /CONI PI, = /]
	MOVE	T2,.CPTPI##
	PUSHJ	P,PRMHW		;PRINT THE CONI PI BITS
	SETZ	P2,		;CLEAR FLAG REGISTER
;HERE TO START RETRIES
PRTRP3:	PUSHJ	P,PRTRY		;REFERENCE LOCATION
	 JRST	PRHMF		;RETRIES FAILED! HARD MEMORY FAILURE
;HERE WE KNOW WE CAN RECOVER THE USER
	MOVEM	T1,.CPTGD##	;SAVE THE GOOD DATA FOR ERROR REPORTING
	AOS	.CPSPT##	;UPDATE COUNTER OF SOFT PARITY ERRORS
;HERE IF RETRIES WERE SUCCESFUL, LOG SOFT ERROR AND DISMISS
PRTRP5:	TRO	P2,PFCPF0	;INDICATE WE'RE A KS10
	HRLM	P2,.CPPTR##	;SAVE STATUS FLAGS FOR ERROR REPORTING
	HRRM	T3,.CPPTR##	;SAVE RETRY COUNT FOR ERROR REPORTING
	MOVE	T3,.CPTOS##	;GET .EPMP FOR THIS CPU
	POP	P,.MERPL(T3)	;RESTORE TEMP MAP SLOT IN THIS EPMP
	MOVEI	T1,[ASCIZ /Retry successful! Correct contents = /]
	MOVE	T2,.CPTGD
	PUSHJ	P,PRMHW		;PRINT SUCCESS AND GOOD DATA
	MOVEI	T1,EDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,PRMSG		;PRINT END DELIMITER
	MOVEI	T1,.ERKPT	;ASSUME PARITY CODE FOR DAEMON
	TRNE	P4,UE.NXM	;IS THIS REALLY A NXM?
	MOVEI	T1,.ERKSN	;YES--GET NXM CODE
	HRL	T1,.CPSLF##	;THIS CPU'S CDB ADDRESS
	PUSHJ	P,DAEDIE##	;PUT THE ENTRY IN THE QUEUE
	JRST	PTXIT		;EXIT THE TRAP
	;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
	MOVE	T2,[EXP XC.UIO+TRYBAD] ;GET TEST TRAP ADDRESS
	EXCH	T2,.UPMP+.LMPFN	;EXCHANGE WITH WHAT'S THERE NOW
	PUSH	P,.UPMP+.LMPFP	;IF A TRAP HAPPENS, HOW WE GOT HERE IS LOST
PRTY1:	TRO	P2,PFCPF0	;NOTE THIS IS TEST REFERENCE
	WREBR	@.CPEBR##	;INVALIDATE CACHE
	MOVE	T1,0(P1)	;TRY THE REFERENCE
	TRZ	P2,PFCPF0	;CLEAR THE REFERENCE FLAG
	TRZN	P2,PFCPF2	;ERROR DURING REFERENCE?	
	 JRST	PRTY3		;NO--GIVE A GOOD RETURN
	CAIGE	T3,TRPTRY	;YES--RETRY COUNT EXHAUSTED?
	AOJA	T3,PRTY1	;NO--TRY AGAIN
	SKIPA			;YES--GIVE AN ERROR RETURN
PRTY3:	AOS	-1(P)		;SET FOR SKIP RETURN
	POP	P,.UPMP+.LMPFP	;RESTORE OLD CONTENTS
	EXCH	T2,.UPMP+.LMPFN	;RESTORE STANDARD TRAP ADDRESS
	POPJ	P,		;EXIT

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

;HERE WHEN RETRIES FROM MEMORY FAIL

PRHMF:	SETZM	.CPTGD##	;ZERO "GOOD DATA" SINCE WE DIDN'T GET ANY
	TRNN	P4,UE.NXM	;DON'T DO NEXT IF NXM
	SETZM	(P1)		;ZERO (AND RE-WRITE) THE ROTTEN LOCATION ALSO
	PUSH	P,P2		;SAVE P2
	PUSH	P,T3		;SAVE T3
	PUSHJ	P,PRTRY		;NOW SEE IF IT'S REALLY HARD (MEMORY BROKEN)
	  TDZA	P1,P1		;IT IS, SET P1 = 0
	SETO	P1,		;IT'S NOT, SET P1 = -1
	POP	P,T3		;RESTORE T3
	POP	P,P2		;RESTORE P2
	MOVE	T1,.CPTOS##	;GET .EPMP FOR THIS CPU
	POP	P,.MERPL(T1)	;RESTORE TEMP MAP SLOT IN THIS EPMP
	AOS	.CPHPT##	;BUMP HARD (AR/ARX) PARITY TRAP COUNT
	TRO	P2,PFCPF0!PFCPF1;SAY HARD ERROR AND KS10 FOR ERROR REPORTING
	HRLM	P2,.CPPTR##	;SAVE FLAGS
	HRRM	T3,.CPPTR##	;SAVE RETRY COUNT FOR ERROR REPORTING
	TRNE	P4,UE.NXM	;IF THIS IS A NXM, MESSAGE IS DIFFERENT
	SKIPA	T1,[[ASCIZ /Retry unsuccessful./]]
	MOVEI	T1,[ASCIZ /Retry unsuccessful. Offending location zeroed./]
	PUSHJ	P,PRMSG		;ANNOUNCE FAILURE
	MOVEI	T1,.ERKPT	;ASSUME PARITY CODE FOR DAEMON
	TRNE	P4,UE.NXM	;IS THIS REALLY A NXM?
	MOVEI	T1,.ERKSN	;YES--GET NXM CODE
	HRL	T1,.CPSLF##	;AND CDB ADDRESS
	PUSHJ	P,DAEDIE##	;CALL DAEMON TO LOG ERROR
	MOVE	T1,.CPPPC##	;GET THE TRAP PC
	TLNE	T1,(XC.USR)	;IS THE TRAP FROM USER MODE?
	JRST	PRHMF1		;YES--GO KILL USER
	HRRZ	T1,.CPPFW##	;GET THE PROBLEM ADDRESS
	SKIPGE	.CPPFW##	;IS THIS A USER CONTEXT REFERENCE?
	JRST	PRHMF0		;YES--GO CHECK IF AT SCHED OR PI LEVEL
	MOVE	T2,SYSLEN##	;NO--GET LENGTH OF MONITOR'S HIGH SEG
	ADDI	T2,MONORG##-1	;FORM EVA OF THE TOP OF THE HIGH SEG
	CAIL	T1,MONORG##	;IS THE ERROR IN THE
	CAILE	T1,(T2)		; MONITOR'S HIGH SEGMENT?
	JRST	PRHMF0		;NO--GO CHECK OTHER THINGS
	LSH	T1,W2PLSH##	;YES--FORM THE EXEC VIRTUAL PAGE NUMBER
	MOVE	T2,.CPPBA##	;GET THE MAPPED PHYSICAL ADDRESS
	TDZ	T2,[777760,,777] ;ONLY WANT BASE ADDRESS OF PAGE
	PUSHJ	P,PAGRPL##	;TRY TO REPLACE THIS CODE PAGE
	  JRST	PARHLT##	;IT DIDN'T WORK
	MOVEI	T1,[ASCIZ /Replaced monitor code page from disk./] ;GET TEXT
	PUSHJ	P,PRMSG		;PRINT IT
	MOVEI	T1,EDELIM##	;GET END DELIMITER
	PUSHJ	P,PRMSG		;PRINT IT
	PJRST	PTXIT		;EXIT THE TRAP
PRHMF0:	SETOM	.CPREP##	;SET PARITY MSG FLAG IN CASE THIS IS FATAL
	TRNE	P4,UE.NXM	;IS THIS A NXM?
	SETZM	.CPREP##	;YES--SET FLAG PROPERLY
	SKIPN	.CPISF##	;ARE WE IN THE SCHEDULER
	CONSZ	PI,PI.IPA	; OR ARE WE AT INTERRUPT LEVEL?
	JRST	PARHLT##	;YES--SORRY BUT WE CAN'T DO A THING
	SKIPGE	.CPPFW##	;WAS THIS A MONITOR REF TO USER SPACE AT UUO LVL?
	JRST	PRHMF2		;YES--TREAT AS USER ERROR
	CAIL	T1,340000	;IS THE ERROR IN THE
	CAILE	T1,377777	; USER PER PROCESS AREA?
	JRST	PARHLT##	;NO--IT'S IN THE MONITOR DATA BASE, FATAL!
	SETZ	P2,		;YES, CALL IT LOWSEG ERROR
	JRST	PRHMF3		;TREAT AS FATAL USER ERROR
PRHMF1:	TDNN	P4,.CPCN1##	;IS USER ENABLED TO HANDLE THIS HIMSELF?
	JRST	PRHMF2		;NO--GO ON
	MOVE	T2,JBTSTS##(J)	;YES--GET JOB STATUS WORD
	TLNE	T2,JACCT	;IS JOB PRIVILEGED?
	JRST	PRHF1A		;YES--TRAP TO HIM
	MOVE	T2,JBTPPN##(J)	;NO--GET HIS PPN
	CAME	T2,FSFPPN##	;IS IT THE OPERATOR PPN
	CAMN	T2,UMDPPN##	; OR THE USER MODE DIAG PPN?
	JRST	PRHF1A		;YES--LET'S TRAP TO HIM AS REQUESTED
	JRST	PRHMF2		;NO--THEN WE IGNORE HIS TRAP REQUEST
PRHF1A:	MOVEI	T1,EDELIM##	;GET END DELIMITER
	PUSHJ	P,PRMSG		;PRINT IT
	WRPI	PI.ON		;TURN PI'S BACK ON
	MOVE	T1,.CPPPC##	;GET THE PROBLEM PC
	HRRZ	T3,P4		;PUT PARITY/NXM BIT HERE
	JRST	SAROV3		;GO TRAP TO USER
PRHMF2:	SETZ	P2,		;SET FLAG ASSUMING LOW SEG ERROR
	MOVE	J,.CPJOB##	;GET THE OFFENDING JOB #
	SKIPG	J,JBTSGN##(J)	;DOES THIS JOB HAVE A HIGH SEG?
	JRST	PRHMF3		;NO--GO ON
	HRRZ	T1,.CPPFW##	;GET THE PROBLEM ADDRESS
	CAML	T1,.UPMP+.UPHSS	;IS ADDRESS IN THE USER HIGH SEGMENT?
	CAMLE	T1,.UPMP+.UPHSE
	JRST	PRHMF3		;NO--GO ON
	SETO	P2,		;YES--SET FLAG INDICATING HIGH SEG ERROR
	PUSHJ	P,HGHPAR##	;GO PROCESS OTHER JOBS USING THIS SEGMENT
PRHMF3:	JUMPN	P1,PRHMF4	;IF MEMORY IS OK, DON'T MARK OUT PAGE
	LDB	T1,[POINT 13,.CPPBA##,26] ;GET THE PAGE NUMBER TO MARK OFF-LINE
	PUSH	P,T1		;SAVE PAGE NUMBER
	IDIVI	T1,^D36		;COMPUTE NXMTAB INDEX AND BITTBL INDEX
	MOVE	T2,BITTBL##(T2)	;GET CORRECT BIT TO SET
	IORM	T2,NXMTAB##(T1)	;MARK OUT PAGE IN NXMTAB
	MOVEI	T1,[ASCIZ /Location still bad after zeroing.
Setting off-line physical page /] ;GET TEXT
	POP	P,T2		; AND PAGE NUMBER
	PUSHJ	P,PRMOC		;TELL HIM WHAT WE DID
	MOVE	T1,[.CSCPO,,.ERCSC]
	PUSHJ	P,DAEDIE##	;LOG CONFIGURATION CHANGE
PRHMF4:	MOVEI	T1,EDELIM##	;GET END DELIMITER
	PUSHJ	P,PRMSG		;PRINT IT
	MOVE	J,.CPJOB##	;GET JOB NUMBER
	JUMPE	P2,PRHMF5	;GO STOP THIS JOB IF LOW SEG ERROR
	MOVEI	T1,JS.MPE	;DID HGHPAR SAY THAT THIS JOB
	TDNE	T1,JBTSTS##(J)	; COULDN'T BE SAVED?
	JRST	PRHMF5		;YES--JUST GO STOP IT
	WRPI	PI.ON		;NO--TURN PI'S BACK ON
	HLLZ	T1,.CPMPS##	;GET CPU REQUESTS MEMORY SCAN BITS
	HRRI	T1,(P4)		;SET PARITY OR NXM BIT
	IORM	T1,.CPAEF##	;SET REQUEST
	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;DUMMY STACK FOR WSCHED
	PUSH	P,.UPMP+.LMPFP	;STACK RETURN USER ADDRESS FOR WSCHED
	PJRST	WSCHED##	;RESCHEDULE THIS JOB TO RE-RUN WITH NEW HIGH SEG

PRHMF5:	MOVSI	T1,JACCT	;CLEAR JACCT SO DAMAGED PROGRAM
	ANDCAM	T1,JBTSTS##(J)	; WON'T HAVE PRIVILEGES
	MOVEI	T1,JS.MPE	;ASSUME PARITY ERROR IN JOB
	TRNE	P4,UE.NXM	;IS IT A NXM?
	MOVEI	T1,JS.NXM	;YES--GET NXM IN JOB STATE BIT
	IORM	T1,JBTSTS##(J)	;SET IN JOB STATUS WORD
	HLLZ	T1,.CPMPS##	;GET CPU REQUESTS MEMORY SCAN BITS
	HRRI	T1,(P4)		;SET PARITY OR NXM BIT
	IORM	T1,.CPAEF##	;SET REQUEST FOR PI 7
	SETOM	.CPSCF##	;FORCE RESCHEDULE
	SETOM	.CPCKF##	;SET FLAG FOR PI 7 INTERRUPT
	WRPI	XI.RQC##	;REQUEST PI 7
	WRPI	PI.ON		;ALLOW INTERRUPTS NOW (MAINLY PI 7)
	PJRST	ESTOP##		;GO STOP THIS JOB
;HERE ON TRAP DURING PARITY SWEEP
SWTRP:	EXCH	T1,.CPSTT##	;RESTORE T1, SAVE TRAP CODE
	PUSH	P,T1		;SAVE T1
	HRRZ	T1,.UPMP+.LMPFP	;GET PC OF TRAP
	CAIE	T1,CPSMPI	;BETTER MATCH THE SWEEP BLT ADDRESS
	STOPCD	(.,HALT,NPI)	;++NOT PARITY INSTRUCTION
	MOVE	T1,.UPMP+.LMPFW	;GET THE PAGE FAIL WORD
	MOVEM	T1,.CPPFW##	;AND SAVE IT
	WRUBR	[LG.LAB+07B11]	;SET PREVIOUS AC BLOCK TO 7
	PXCT	PX.MEM,[MOVE T1,0] ;GET BAD DATA WORD FOR DAEMON
	EXECAC			;RESTORE MONITOR'S AC BLOCK
	MOVEM 	T1,.CPTBD##	;SAVE BAD DATA
	SETOM	.CPPTH##	;INDICATE ERROR ON SWEEP
	MOVEI	T1,3		;BUMP RETURN PC BY 3 TO
	ADDM	T1,.UPMP+.LMPFP	; INDICATE A TRAP HAPPENED
	POP	P,T1		;RESTORE T1
	JRST	PTXIT1		;EXIT BACK TO SWEEP ROUTINE
;ROUTINE TO PRINT A MESSAGE PREFIXED BY "CPUx" AND
;FOLLOWED BY "AT EXEC(USER) PC XXXXXX"
;  T1=MESSAGE ADDRESS

PRMPC:	PUSHJ	P,SAVE1##	;SAVE P1 TO REMEMBER ADDRESS OF MESSAGE
	MOVE	P1,T1		;SAVE
	PUSH	P,.CPTOA##	;SAVE COMMAND OUTPUT ADDRESS
	MOVEI	T2,CTYWAT##	;GET ONE THAT DOESN'T USE PI SYS
	MOVEM	T2,.CPTOA##
	MOVEI	T1,SDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,CONMES##	;PRINT START DELIMITER
	MOVE	T2,.CPLOG##	;GET THIS CPU'S NAME
	PUSHJ	P,PRNAME##	;PRINT IT
	MOVE	T1,P1		;GET ADDRESS OF MESSAGE IN T1
	PUSHJ	P,CONMES##	;PRINT MESSAGE
	MOVE	T2,.CPPPC##	;GET SAVED PC
	PUSHJ	P,PCP##		;PRINT "AT EXEC/USER XXXXXX"
	MOVEI	T1,[ASCIZ / on /] ;SEPARATE FROM DATE/TIME
	PUSHJ	P,CONMES##	;PRINT IT
	PUSHJ	P,DAYTIM##	;PRINT DATE AND TIME
	MOVEI	T1,[ASCIZ /Job/];TELL THEM WHO WAS RUNNING
	PUSHJ	P,CONMES##	;PRINT "JOB"
	PUSHJ	P,PRJBNM##	;PRINT JOB INFO
	MOVEI	T1,[ASCIZ / was running
/]
	PUSHJ	P,CONMES##	;PRINT "WAS RUNNING"
PRMPC2:	POP	P,.CPTOA##	;RESTORE SCNSER ADDRESS
	POPJ	P,		;RETURN

;ROUTINES TO PRINT A MESSAGE FOLLOWED BY NUMBER IN HALFWORD OR OCTAL FORMAT
;  T1=MESSAGE ADDRESS, T2=NUMBER
PRMOC:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVEI	P3,OCTPNT##	;GET ADDRESS OF OCTAL PRINT ROUTINE
	JRST	PRMHW1		;GO TO COMMON CODE
PRMHW:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVEI	P3,HWDPNT##	;GET ADDRESS OF HALFWORD PRINT ROUTINE
PRMHW1:	MOVE	P1,T1		;SAVE
	MOVE	P2,T2		;SAVE
	PUSH	P,.CPTOA##	;SAVE COMMAND OUTPUT ADDRESS
	MOVEI	T2,CTYWAT##	;GET ONE THAT DOESN'T USE PI SYS
	MOVEM	T2,.CPTOA##
	MOVE	T1,P1		;GET ADDRESS OF MESSAGE IN T1
	PUSHJ	P,CONMES##	;PRINT MESSAGE
	MOVE	T1,P2		;GET NUMBER TO PRINT (IF ANY)
	PUSHJ	P,(P3)		;PRINT NUMBER IN DESIRED FORMAT
	PUSHJ	P,CRLF##	;END WITH CRLF
	PJRST	PRMPC2		;FINISH UP
;ROUTINE TO PRINT A MESSAGE
;  T1=MESSAGE ADDRESS

PRMSG:	PUSHJ	P,SAVE2##	;SAVE P1,P2 TO REMEMBER ADDRESS OF MESSAGE
	MOVE	P1,T1		;SAVE
	PUSH	P,.CPTOA##	;SAVE COMMAND OUTPUT ADDRESS
	MOVEI	T2,CTYWAT##	;GET ONE THAT DOESN'T USE PI SYS
	MOVEM	T2,.CPTOA##
	MOVE	T1,P1		;GET ADDRESS OF MESSAGE IN T1
	PUSHJ	P,CONMES##	;PRINT MESSAGE
	PUSHJ	P,CRLF##	;END WITH CRLF
	PJRST	PRMPC2		;FINISH UP
;HERE ON PAGE TABLE PARITY TRAP (PF CODE 25)
PTPAR:	WREBR	@.CPEBR##	;CLEAR THE PAGE TABLE
	AOS	.CPPTP##	;COUNT A PAGE TABLE PARITY ERROR
	MOVE	T1,.CPSTT##	;RESTORE T1
	MOVEM	T1,.CPA17##	;SAVE 17
	MOVEI	17,.CPA00##	;MAKE BLT POINTER
	BLT	17,.CPA17##-1	;SAVE ACS IN CPU DATA BLOCK
	MOVE	P,.CPEPD##	;SET UP ERROR STACK
	SKIPGE	T1,.CPPTF##	;PICK UP COUNT OF PAGE TABLE FAILURES
	MOVEI	T1,^D10		;NONE YET, INITIALIZE
	SOSG	T1		;IF COUNT HASN'T EXPIRED, JUST RETRY.
				; COUNTER IS RESET ON EVERY CLOCK TICK.
	STOPCD	.,HALT,PTP,	;++PAGE TABLE PARITY
	MOVEM	T1,.CPPTF##	;REMEMBER COUNTER
	MOVE	T1,.UPMP+.LMPFP	;GET PAGE FAIL PC
	MOVEM	T1,.CPPPC##	;SAVE FOR PRINT ROUTINE
	MOVE	J,.CPJOB##	;SET UP J WITH CURRENTLY RUNNING JOB
	MOVEI	T1,[ASCIZ / page table parity trap/]
	PUSHJ	P,PRMPC		;ANNOUNCE ERROR
	MOVEI	T1,[ASCIZ /Page fail word = /]
	MOVE	T2,.UPMP+.LMPFW
	PUSHJ	P,PRMHW		;PRINT THE PAGE FAIL WORD
	MOVEI	T1,[ASCIZ /CONI PI, = /]
	MOVE	T2,.CPTPI##
	PUSHJ	P,PRMHW		;PRINT THE CONI PI BITS
	MOVEI	T1,EDELIM##	;GET ADDRESS OF TEXT
	PUSHJ	P,PRMSG		;PRINT END DELIMITER
PTXIT:	MOVSI	17,.CPA00##	;BLT POINTER TO RESTORE ACS
	BLT	17,16		;RESTORE ACS
	MOVE	17,.CPA17##	;AC 17 ALSO
PTXIT1:	WRUBR	.CPTCX##		;RESTORE THE CONTEXT AT TIME OF TRAP
	EXCH	T1,.CPTPI##	;GET PI'S AT TRAP ENTRY, SAVE T1
	TRNE	T1,PI.ON	;WERE THE PI'S ON?
	WRPI	PI.ON		;YES--TURN PI'S BACK ON
	EXCH	T1,.CPTPI##	;RESTORE T1
	JRSTF	@.UPMP+.LMPFP	;RESTORE FLAGS AND RETURN
;HERE TO HANDLE A PAGE FAULT

SEILMA:	MOVE	T1,.CPSTT##	;RESTORE T1
	WRPI	PI.ON		;RESTORE THE PI SYSTEM
	SKIPN	.CPEJ1##	;SKIP NEXT IF EXEC PAGE FAULT IN PROGRESS
	DMOVEM	T1,.CPST1##	;SAVE T1 AND T2 IN CASE OF CRASH
	MOVE	T1,.UPMP+.LMPFP	;GET THE PC
	MOVEM	T1,.CPAPC##	;STORE IT AS POTENTIAL ERROR PC
	MOVEM	T1,.UPMP+.UPMUP	;STORE WHERE KI WOULD PUT IT
	MOVE	T2,.UPMP+.LMPFW	;GET THE USER PAGE FAIL WORD
	MOVEM	T2,.CPPFW##	;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
	JRST	SEILM7		;YES--EXEC ILL MEM REF, CHECK FOR ERJMP

SEILM0:	MOVE	P,[XWD MJOBPD##,.JDAT+JOBPDL##] ;SETUP A PUSH DOWN LIST
	SKIPN	.CPJOB##
	STOPCD	.,CPU,PFN	;++PAGE FAULT IN NULL JOB
	PUSH	P,T1		;SAVE USER'S PC
	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
	MOVE	T4,.JDAT+JOBENB## ;GET APR ENABLE BITS
	TRNE	T4,AP.ILM	;IS USER ENABLED?
	JRST	SUILM		;YES--DO SUILM INSTEAD
	MOVE	T4,T1		;PC WORD INTO T4 FOR USRFLT

	HRRI	T1,AP.ILM	;ILLEGAL MEMORY REFERENCE
	PUSHJ	P,USRFLT##	;SEE IF PAGE FAULT FOR A VM USER
				; WILL NOT RETURN IF SO (DISPATCH TO USER)
	MOVEM	T4,.CPAPC##	;STORE ERROR PC
	MOVE	T2,.CPST2##	;RESTORE T2
	JRST	SEPDL1		;GO SAY "ILL. MEM. REF."
;HERE IF AN ILL MEM REF OCCURED IN EXEC MODE, CHECK FOR ERJMP OR
;ERCAL BEFORE CALLING IT AN IME

SEILM7:	CONSO	PI,PI.IPA	;AT INTERRUPT LEVEL?
	JRST	SEJLM2		;NO, UUO LEVEL, OK
	CONSO	PI,PI.IPA-PI.IP7 ;YES - LEVEL 7?
	SKIPN	.CPISF##	;YES, FROM SCHEDULER?
	JRST	SEILME		;PI1 - PI6 OR NON-SCHEDULER PI7
SEJLM2:	SKIPE	.CPEJ1##	;NESTING?
	JRST	SEILM8		;YES, IT'S AN IME
	MOVE	T2,.CPPFW##	;NO, GET PAGE FAULT WORD
IFN FTPEEK,<
	SKIPG	T2		;USER REFERENCE?
	PUSHJ	P,[PUSHJ P,SAVT## ;YES, SAVE VOLATILE ACS
		   HRRZ T1,T2	;VIRTUAL ADDRESS
		   LSH T1,W2PLSH## ;PAGE NUMBER
		   PUSHJ P,TSSPT## ;FAULT ON A SPY PAGE?
		     POPJ P,	;NO
		   PJRST UADERR##] ;YES, BLAME THE USER
>
	DMOVEM	T1,.CPEJ1##	;"TOP LEVEL", REMEMBER IN CASE WE NEST
	MOVEM	T1,.CPEJ3##	;ALSO SAVE HERE FOR PSYCHOPATHIC CASES
	SKIP	(T1)		;TOUCH PAGE FAULT PC LOCATION AND
	LDB	T2,[POINT 13,1(T1),12]  ;GET INSTRUCTION FOLLOWING
				; IF THE PC JUMPED OFF INTO THE BOONIES
				; THEN THIS WILL PAGE FAULT AND WE WILL
				; KNOW WE HAVE A REAL IME
	CAIE	T2,<ERJMP>_-^D23	;IS IT AN ERJMP?
	JRST	SEILM8		;NO, THEN WE HAVE AN IME
	MOVE	T2,1(T1)	;GET ENTIRE ERJMP EXPRESSION
	MOVEM	T2,.CPEJ4##	;AND SAVE IT WHERE WE CAN FIND IT
	DMOVE	T1,.CPST1##	;RESTORE FULL AC SET
	MOVEI	T1,@.CPEJ4##	;GET "E" OF ERJMP
				; IF THIS IME'S (NOTE .CPEJ1 STILL
				; NON-ZERO) THEN .CPEJ3 HAS ORIGINAL
				; TRAP PC WHICH STARTED THIS MESS.
	HRRM	T1,.CPAPC##	;SET FROM WHENCE TO CONTINUE
	MOVE	T1,.CPST1##	;RESTORE T1 AGAIN
	SETZM	.CPEJ1##	;CLEAR NESTING FLAG
	JRSTF	@.CPAPC##	;AND GO PROCESS THE ERROR

;HERE ON NESTED IME, "RESTORE" THE FIRST IME AND STOPCD

SEILM8:	DMOVE	T1,.CPEJ1##	;PAGE FAULT PC AND REASON WORDS
	MOVEM	T1,.CPAPC##	;SET TRUE ERROR PC
	MOVEM	T1,.UPMP+.LMPFP	;ALSO MAKE UPMP LOOK RIGHT
	MOVEM	T2,.CPPFW##	;SET TRUE PAGE FAULT WORD
	MOVEM	T2,.UPMP+.LMPFW	;ALSO MAKE UPMP LOOK RIGHT
SEILME:	SETZM	.CPEJ1##	;CLEAR NESTING FLAG
	STOPCD	.+1,JOB,IME,	;++ILL MEM REF FROM EXEC
	DMOVE	T1,.CPST1##	;AND THE TEMP ACS USED
	JRSTF	@.CPAPC##	;RETURN
;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##	;GET THE ADDRESS OF THE USER'S JOB DATA AREA
	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)

	MOVEI	T3,AP.ILM	;SET ILM BIT FOR USER
	JRST	SAROV3		;FINISH UP
SUPDLO::MOVE	T1,.UPMP+.UPMUP	;GET ERROR PC
	MOVEI	T3,AP.POV	;SET POV BIT FOR USER
	JRST	SAROV3		;FINISH UP
;ONCE A SECOND TASKS FOR KS10'S
KSSEC::

;HERE ONCE A SECOND TO BE SURE UBA'S DIDN'T LOSE ASSIGNMENTS
	MOVEI	T2,UBA1PI##	;PI'S FOR UBA #1
	MOVEI	T1,UNBSTW	;UBA STATUS REGISTER ADDRESS
	HRLI	T1,1		;DO UBA #1
	PUSHJ	P,UBACHK	;CHECK IT
	MOVEI	T2,UBA3PI##	;PI'S FOR UBA #3
	HRLI	T1,3		;DO UBA #3
	PUSHJ	P,UBACHK	;CHECK IT
     	;***************************************************************
     	;PATCH TO CHECK PI ASSIGNMENT ON UBA #4 (PCL UBA)
     	;PART 1 OF 1
     	;INSTALLED BY JOHN FRANCIS 4-DEC-80 15:45
     	;THREE LINES OF CODE INSERTED
     		MOVEI	T2,UBA4PI##	;PI'S FOR UBA #4
     		HRLI	T1,4		;DO UBA #4
     		PUSHJ	P,UBACHK	;CHECK IT
     	;***************************************************************
	JRST	KSSEC2		;GO TO NEXT TASK
UBACHK:	PUSHJ	P,UBGOOD	;IS UBA ALIVE?
	  POPJ	P,		;NO--THEN DON'T TRY TO ACCESS IT
	RDIO	T3,(T1)		;YES--GET UBA STATUS
	ANDI	T3,UNBDTR!77	;MASK OFF EXTRA BITS
	IORI	T2,UNBDTR	;SET DISABLE XFER BIT FOR COMPARE/SET
	CAMN	T3,T2		;ARE ALL THE BITS RIGHT ?
	POPJ	P,		;ALL OK
	STOPCD	(.+1,DEBUG,ULP)	;++UBA LOST ITS PI ASSIGNMENT
	WRIO	T2,(T1)		;REASSIGN LEVELS
	POPJ	P,

;HERE ONCE/SECOND TO COUNT THE KEEP ALIVE COUNTER FOR THE 8080 FRONT END
KSSEC2:	LDB	T1,BKPALV	;GET THE CURRENT COUNT
	AOS	T1		;INCREMENT IT
	CAILE	T1,377		;WE COUNT IT MODULO 8-BITS
	SETZ	T1,
	DPB	T1,BKPALV	;PUT IT IN ITS PROPER PLACE
	POPJ	P,		;RETURN

BKPALV:	POINT	8,RLWORD,27	;BYTE POINTER TO KEEP ALIVE COUNT
;ROUTINES TO TURN KEEP ALIVE FUNCTION ON AND OFF WITH 8080 FRONT END
	$LOW
ENAKAL::PUSH	P,T1		;SAVE T1
	MOVSI	T1,(KPACT)	;KEEP ALIVE ACTIVE BIT
	IORM	T1,RLWORD	;SET IT
	PJRST	DISKA1		;RETURN

DISKAL::PUSH	P,T1		;SAVE T1
	MOVSI	T1,(KPACT)	;KEEP ALIVE ACTIVE BIT
	ANDCAM	T1,RLWORD	;CLEAR IT
DISKA1:	POP	P,T1		;CAN'T USE TPOPJ SINCE
	POPJ	P,		;  WE MAY NOT BE MAPPED
	$HIGH
;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,.CPJOB##	;J=CURRENT JOB NUMBER
	MOVEI	T1,0
	DPB	T1,JBYHSS##	;FORCE MAP TO BE REDONE
SETREL::MOVE	J,.CPJOB##	;J = CURRENT JOB NUMBER
SETRL1::MOVE	R,JBTADR##(J)	;R = XWD PROTECTION,,EXEC VIRTUAL ADDRESS
				; OF THE FIRST PAGE OF THE LOW SEGMENT
	MOVEM	R,.CPADR##	;SET .CPADR FOR QUICK ACCESS AT APR LEVEL
	HLRZM	R,.CPREL##	;SET .CPREL FOR ADDRESS CHECKING
IFN FTTRPSET,<
	SKIPE	T1,.CPSTS##	;HAS TIMESHARING BEEN STOPPED VIA TRPSET
	CAIE	T1,(J)		;YES, IS IT THIS JOB?
	JUMPN	T1,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
	HLRZM	R,.UPMP+.UPHVA	;SET .UPHVA FOR ADDRESS CHECKING AT IRP LEVEL
	LDB	T2,[POINT 9,R,8];GET THE CURRENT SIZE
	LDB	T1,JBYLSS##	;GET THE PREVIOUS SIZE OF THE LOW SEGMENT
	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
	SKIPN	T1,.UPMP+.UPREL	;HOLEY PROGRAM?
	HLR	T1,R
	HRRZM	T1,.JDAT+JOBREL##	;STORE HIGHEST CORE-UUO ADDRESS IN JOBREL

	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:	MOVE	T3,JBTPDB##+0	;NULL JOB PDB
	PUSHJ	P,FNDPDS##	;SET UP W
	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,(SG.LUB)	;SET THE LOAD BIT
IFN FTRTTRP,<
	MOVEM	T1,.CPDTO##	;SAVE FOR RTTRP INTERRUPT LEVEL USE
>
	WRUBR	T1		;SETUP THE UBR
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,.JDAT+JOBENB## ;JOB'S APR ENABLE BITS
	PJRST	SETCNA		;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
	TLO	T1,(SG.LUB)	;REQUEST LOADING OF UBR
	TRNE	T1,17777	;IS THERE A UPMP
	WRUBR	T1		;SET FOR CURRENT USER AND CLEAR THE AM
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
SUBTTL	IOCSS - I/O SERVICE SUBROUTINES (UUOCON AND DEVICE ROUTINES)

;HERE TO CHECK FOR EXISTENCE OF UBA DEVICES
; CALL	MOVE	T1,<ADR> OF DEVICE TO CHECK
;	PUSHJ	P,UBGOOD
;	LOSE RETURN
;	WIN RETURN
UBGOOD::PUSHJ	P,SAVT##	;RESPECT T REGS
	SETZ	T2,		;BITS FOR TIOE
	MOVE	T3,[EXP XC.UIO+UBNOGD] ;TEMP PAGE FAIL TRAP ADDR
	RDPI	T4		;SAVE STATE OF PI'S
	WRPI	PI.OFF		;DISABLE INTERRUPTS
	EXCH	T3,.UPMP+.LMPFN	;SET TEMPORARY PAGE FAIL TRAP ADR
	TIOE	T2,(T1)		;CHECK FOR DEVICE
	SKIPA			;FAILED
	AOS	(P)		;WIN
	MOVEI	T2,UNBNED!UNBTMO ;CLEAR NED IN UNIBUS ADAPTER
	HRRI	T1,UNBSTW	;GET BASIC ADDRESS OF UNIBUS
	BSIO	T2,(T1)		;CLEAR FLAGS
	MOVEM	T3,.UPMP+.LMPFN	;RESTORE TRAP VECTOR
	TRNE	T4,PI.ON	;WERE PI'S ON?
	WRPI	PI.ON		;YES--THEN ENABLE THEM
	POPJ	P,		;RETURN

;HERE WHEN ADDRESS IS BUM
UBNOGD:	AOS	.UPMP+.LMPFP	;SKIP LOSING INSTRUCTION
	JRST	@.UPMP+.LMPFP	;JUST RETURN(NONSKIP)
;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
	RDUBR	T1		;GET THE USER 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
	RDUBR	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
	RDUBR	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
	WRUBR	T1		;RESTORE THE UBR
	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,.EPRPM##(P1)	;FORM A BYTE POINTER TO THE EXEC MAP
	ADD	P2,.CPTOS##	;POINT AT CURRENT CPU'S MAP
	TLO	P2,(<POINT 18,0>) ;ASSUME AN EVEN PAGE
	SKIPGE	P1		;WAS IT EVEN?
	HRLI	P2,(<POINT 18,0,17>) ;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,(<POINT 18,0>) ;YES, THE FIRST PAGE IS MAPPED BY THE LEFT HALF WORD
	HRLI	P3,(<POINT 18,0,17>) ;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 SET UP UNIBUS ADAPTER MAPPING REGISTERS FOR A GIVEN
;IOWD FOLLOWING THE PAGING OF A JOB.  PRESERVES T1-T4, P3, P4.
;
;CALL	MOVE	T2,IOWD
;	MOVEI	P1,0		;FIRST CALL
;	MOVE	P3,LOC OF CHANNEL DATA BLOCK
;	MOVE	P4,FRAME-COUNT,,CHARS/WD IF TU45
;	PUSHJ	P,MAPIO
;RETURN	CPOPJ	IF IOWD EXCEEDS AVAILABLE PAGING REGISTERS
;	CPOPJ1	P2=ADDRESS OF FIRST PAGING REGISTER USED
;		P1=ADDRESS OF NEXT PAGING REGISTER TO BE USED

MAPIO::	TLNN	T2,-1		;0 OR CHANNEL JUMPS ARE ILLEGAL
	STOPCD	CPOPJ,DEBUG,IEZ,  ;++IOWD EQUALS ZERO
	PUSHJ	P,SVEUB		;SAVE AND SETUP UBR
	PUSHJ	P,SAVT##	;SAVE T REGS
	PUSH	P,U		;SAVE U
	MOVE	P1,CHNIMR##(P3)	;UBA #,,1ST ASSIGNED PAGING REGISTER
	HRRZI	T4,-UBAEXP(P1)	;OFFSET FROM BASE OF UBA PAGING REGISTERS
	LSH	T4,P2WLSH##	;CONVERT TO PAGES
	MOVE	U,T2		;SAVE IOWD IN U
	AOS	T2		;ACCOUNT FOR FACT THAT IOWD'S ARE ADDR-1
	ANDI	T2,PG.BDY##	;GET LOW 9 BITS OF STARTING ADDRESS
	ADD	T4,T2		;FORM STARTING "DOUBLE-WORD" -11 ADDRESS
	LSH	T4,2		;TURN INTO BYTE ADDRESS
	MOVEM	T4,CHNIEA##(P3)	;AND SAVE IN CHANNEL DATA BLOCK
	MOVE	T4,CHNMRC##(P3)	;GET MAPPING REGISTER COUNT
	HRRZ	T2,U		;ADDRESS-1 WHERE I/O WILL START
	MOVE	T3,DEVMOD(F)	;GET DEVMOD
IFE FTSPL,<
	TLNN	T3,DVDSK	;IF A DSK
>
IFN FTSPL,<
	SKIPL	DEVSPL(F)	;SPOOLED DDBS ARE ALWAYS A DSK
	TLNE	T3,DVDSK	;IF A DSK
	CAIA
>
	JUMPN	T3,MAPI1B	;PROCEED IF NOT READING A HOME BLOCK
	JUMPGE	S,MAPI1B	;PROCEED IF NOT I/O INTO MONITOR
	SKIPN	DINITF##	;IN ONCE ONLY CODE?
	CAIE	T2,@DEVMBF##(F)	;NO--IS THIS A MONITOR BUFFER?
	JRST	MAPIO4		;NO--CONTINUE
	ADDI	T2,<.MCFV-.FPMC>+1 ;YES--CONVERT PER PROCESS ADDRESS
	JRST	MAPI1C		; TO A FAKE USER VIRTUAL ADDRESS
MAPI1B:	TLNE	T3,DVLPT!DVCDR	;IF AN LP20 CD20
	JUMPL	S,MAPIO4	; SEE IF DOING MONITOR IO AND BRANCH
	MOVEI	T2,1(U)		;STARTING ADDRESS
MAPI1C:	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	P2,T2		;SAVE BYTE POINTER IN P2
	MOVE	T2,U		;T2 AND U = IOWD
	HLROS	U		;U = -WORD COUNT
	LDB	T3,P2		;T3 = CURRENT ABSOLUTE PAGE NUMBER
MAPIO2:	TRNN	T3,PM.ACC
IFN FTEXE,<
	SKIPGE	USRHCU##	;IF A SAVE IS IN PROGRESS,
	SKIPA			; THEN, THIS IS OK
>;END OF IFN FTEXE
	STOPCD	.,JOB,AAO,	;++ACCESS ALLOWED IS OFF
				; IOWD HAS BEEN ADDRESS CHECKED)
	TRZ	T3,760000	;MASK OUT ACCESS BITS
	PUSHJ	P,SETUBB	;GO SET PROPER UBA BITS IN T3
	WRIO	T3,(P1)		;AND LOAD THE PAGING RAM
	JUMPE	T2,MAPIO3	;IF ZERO, DO WHOLE PAGE
	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	U,T2		;ADD -NUMBER OF WORDS ON THIS PAGE
	ADD	T1,T2		;ACCUMULATE IN TOTAL WORD COUNT
	JUMPGE	U,MAPIO6	;JUMP IF THE ORIGIONAL WORD COUNT IS EXHAUSTED
	ILDB	T3,P2		;T3 = NEXT PAGE NUMBER WITHIN SEGMENT
	MOVEI	T2,0		;START NEXT PAGE AT ADDRESS 0
	ADDI	P1,1		;POINT TO NEXT MAPPING REGISTER
	SOJG	T4,MAPIO2	;CONTINUE IF THERE IS ROOM
	JRST	MAPI5A		;WHOOPS! OUT OF PAGING REGISTERS
;HERE IF MONITOR I/O, STILL MUST BE MAPPED
MAPIO4:	TRNE	T2,-1		;ZERO ADDRESS? (I.E. NO DATA XFER)
	JRST	MAPI4A		;NO--PROCEED
	MOVEI	T2,CHNDBF##-1(P3) ;YES--SET ADDRESS TO DUMMY 1-WORD AREA
	SETOM	CHNNXF##(P3)	;SET NO-XFER FLAG
MAPI4A:	HLROS	U		;U = -WORD COUNT
	MOVEI	T3,1(T2)	;ACCOUNT FOR FACT THAT IOWD'S ARE ADDRESS-1
	LSH	T3,W2PLSH##	;CONVERT TO PAGE NUMBER
	PUSHJ	P,SETUBB	;GO SET PROPER UBA BITS IN T3
	ANDI	T2,PG.BDY##	;GET STARTING ADDRESS WITHIN PAGE
	SUBI	T2,PAGSIZ##-1	;NUMBER OF WORDS TO DO IN THIS PAGE
	SKIPN	T2		;IF ZERO, DO WHOLE PAGE WORTH
MAPIO5:	MOVNI	T2,PAGSIZ##
	SUB	U,T2		;ACCOUNT FOR PORTION IN THIS PAGE
	WRIO	T3,(P1)		;LOAD UP THE MAPPING REGISTER
	JUMPGE	U,MAPIO6	;DONE?
	ADDI	T3,1		;NO, MONITOR PAGES ARE CONTIGOUS
	ADDI	P1,1		;POINT TO NEXT MAPPING REGISTER
	SOJG	T4,MAPIO5	;IF THERE IS ONE
MAPI5A:	SETZ	P1,		;NOPE--INDICATE NONE
	STOPCD	(UPOPJ##,JOB,OMR) ;++OUT OF MAPPING REGISTERS

MAPIO6:	HRRZ	P2,P1		;GET LAST USER REGISTER ADDRESS
	MOVNS	U		;NEGATE U
	ANDI	U,PG.BDY##	;WORDS INTO LAST PAGE TO TRANSFER
	SKIPN	U		;JUST CROSSED PAGE BOUNDARY?
	AOS	P2		;YES, ACCOUNT FOR IT
	LSH	U,2		;MAKE INTO AN ELEVEN STYLE ADDRESS
	HRRZI	P2,-UBAEXP(P2)	;GET OFFSET INTO MAPPING REGISTERS
	IMULI	P2,UBAMUL	;MAKE INTO 11 STYLE ADDRESSING
	ADDB	P2,U		;FORM ADDRESS OF LAST WORD TO TRANSFER
	SUB	U,CHNIEA##(P3)	;MINUS STARTING ADDRESS
	MOVEM	U,CHNBTC##(P3)	; AND SAVE THE TOTAL BYTE COUNT
	SKIPGE	CHNNXF##(P3)	;IS THIS A NO-XFER REQUEST?
	MOVE	P2,CHNIEA##(P3)	;YES--THEN ENDING ADDRESS WILL EQUAL STARTING ADDR
	SKIPGE	P3		;WANT TERMINATION EXPECTED?
	MOVEM	P2,CHNTCW##(P3)	;STORE FOR LATER CHECKING
	MOVE	P2,CHNIMR##(P3)	;GET ADDRESS OF INITIAL MAPPING REGISTER
	PJRST	UPOPJ1##	;SKIP RETURN
;ROUTINE TO SET THE PROPER BITS FOR A UBA PAGING RAM ENTRY WHICH IS IN T3.
;THE BIT SETTINGS DEPEND ON WHAT KIND OF A DEVICE IS BEING RUN THROUGH MAPIO.

SETUBB:	PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,DEVMOD(F)	;PICK UP DEVICE CLASSES
	TRO	T3,UNBVBT	;ALWAYS SET VALID
	SKIPE	CHNRRV##(P3)	;ARE WE DOING A READ REVERSE OPERATION?
	TRO	T3,UNBRRV	;YES--SET READ REVERSE
	SKIPL	DEVSPL(F)	;SPOOLED DDB'S ARE ALWAYS DISKS
	TLNE	P1,DVDSK	; OR IF A "REAL" DISK DDB
	TRO	T3,UNB36B	; SET FAST XFER MODE
	SKIPGE	DEVSPL(F)	;IF A SPOOLED DDB (I.E. DISK)
	POPJ	P,		; WE'RE DONE
	TLNE	P1,DVLPT!DVCDR	;IF AN LP20 OR CD20
	TRO	T3,UNBD18	; SET 18 BITS DISABLE (16 BIT MODE)
	POPJ	P,		;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
	WRPI	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
	WRPI	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
	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?
	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,1000		;GUARD AGAINST A LOOP (GOTO IOWDS)
DMPEV1:	PUSHJ	P,GETWD1##	;GET AN IOWD
	JUMPE	T1,DMPEV4	;JUMP IF LAST IOWD IN THE LIST
	HLRO	P1,T1		;THIS IOWD'S WORD COUNT
	TLNE	T1,-1		;A GOTO WORD?
	JRST	DMPEV2		;NO, A REAL IOWD
	HRRI	M,-1(T1)	;A GOTO WORD (POINTS TO THE NEXT IOWD)
	JRST	DMPEV3		;GET NEXT IOWD
DMPEV2:	MOVNS	P1		;P1 = POSITIVE WORD COUNT FOR THIS IOWD
	CAMLE	P1,P2		;GREATER THAN THE LARGEST WORD COUNT SEEN SO FAR?
	MOVE	P2,P1		;YES, REMEMBER IT AS LARGEST SEEN
	MOVEI	T1,1(T1)	;START ADR OF THE IOWD
	MOVE	T2,P1		;TOP ADR OF THE IOWD
	ADDI	T2,-1(T1)
	PUSHJ	P,TRNGE##	;MAKE SURE THE REQUIRED PAGES ARE IN CORE

DMPEV3:	SOJG	P3,DMPEV1	;GET NEXT IOWD IN THE LIST
	JRST	ADRERR##	;TOO MANY IOWDS (PROBABLY A GOTO WORD LOOP,
				; STOP THE JOB AND REPORT THE ERROR)

DMPEV4:	POP	P,M		;RESTORE THE UUO AND THE POINTER TO THE FIRST
				; IOWD IN THE LIST
	JUMPL	U,DMPEV5	;DONT ACTUALLY NEED EVM IF U NEGATIVE

	PUSHJ	P,GETWDU##	;GET THE FIRST IOWD IN THE LIST AGAIN
	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
DMPEV5:	POP	P,T1		;RESTORE DISPATCH ADDRESS
	JRST	UPOPJ##		;RESTORE U AND RETURN

;ROUTINE TO RETURN ANY EVM A DEVICE MAY HAVE WHEN A SHARABLE RESOURCE
; WHICH CURRENTLY BELONGS TO THE JOB WHICH HAS THE DEVICE IS GIVEN UP.
;CALLING SEQUENCE:
;	MOVE	F,ADDRESS OF DEVICE DATA BLOCK OR 0 IF NONE
;	PUSHJ	P,RTEVM
;ALL ACS ARE RESPECTED.

RTEVM::	SKIPE	F		;IS THIS A RESOURCE ASSOCIATED WITH I/O?
				; I.E., IS THERE A DEVICE DATA BLOCK?
	SKIPN	DEVEVM(F)	;DOES THE JOB HAVE EVM?
	POPJ	P,		;NO, JUST RETURN
	PUSHJ	P,SAVT##	;IT IS THE TRADITION NOT TO CLOBBER ACS HERE
	HRRZ	T1,P
	CAMG	T1,SYSSIZ##	;DON'T CHANGE UBR IF P POINTS TO USER
	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,0
	TLNN	S,IO		;OUTPUT?
	JRST	RTIEVM		;NO, GO RETURN INPUT EVM
RTOEVM::DPB	T3,PDVOAD##	;STORE UVA IN DEVOAD
	JRST	RTNEV1		;RETURN EVM
RTIEVM::DPB	T3,PDVIAD##	;STORE UVA IN DEVIAD
RTNEV1:	HRRZ	T2,DEVEVM(F)	;PAGE NUMBER AND NUMBER OF PAGES OF EVM
	LDB	T1,[POINT 9,T2,35]
	SETZM	DEVEVM(F)	;FLAG NO LONGER ANY EVM
	PJUMPN	T1,GIVEVM	;RETURN THE EVM TO THE FREE POOL AND TELL
				; THE SCHEDULAR THAT EVM IS AVAILABLE IF ANY
				; JOB IS WAITING FOR SOME
	POPJ	P,		;RETURN


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

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

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


;ROUTINE TO INVALIDATE ENTIRE CACHE AND VALIDATE CORE
; ALWAYS RETURN CPOPJ, SAVING ALL T ACS.

CSDMP::	WREBR	@.CPEBR		;CAUSE CACHE FLUSH
	AOS	.CPCSN##	;COUNT THE SWEEP
	POPJ	P,		;RETURN
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,.CPJOB##	;CURRENT JOB NUMBER
	MOVEM	R,JBTADR##(P3)	;STORE PREVIOUS PROTECTION,,JDAT IN CASE OF ERROR
	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,.JDAT+SGAEXT##	;FILE EXTENSION
	SUBI	T4,'SHR'	;T4=0 IF THE HIGH SEGMENT IS SHARABLE
	PJRST	NREMAP##	;REMAP IT

;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

MAPWRD::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,(<POINT 18,0,17>) ;ASSUME WORD IN EVEN PAGE
	SKIPGE	T2		;IS IT?
	HRLI	T1,(<POINT 18,0,35>) ;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/PAGSIZ## ;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:
;	PUSHJ	P,MAPLOC
;	RETURN HERE
;   C(T1) := BYTE PNTR TO EPMP SLOT
;   C(T3) := RELATIVE PAGE # IN EPMP

MAPLOC::RDPI	T1		;GET PIS IN PROGRESS
	ANDI	T1,II.IPA	;CLEAR ALL BITS EXCEPT PIS IN PROGRESS
	JFFO	T1,MAPLO1	;FIND OUT THE HIGHEST PI IN PROGRESS, I.E.,
				; THE ONE THAT THIS CODE IS BEING EXECUTED AT
	MOVEI	T2,34		;MUST BE UUO LEVEL, FAKE NUMBER
MAPLO1:	SUBI	T2,25		;T2=0-6 FOR PI 1-7 IN PROGRESS, 7 BY UUO LEVEL
	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##	;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:	PUSHJ	P,@.CPMPS##
;	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

CPSMPS::PUSHJ	P,MAPLOC	;GET EXEC MAP SLOT
	MOVE	W,T1		;SAVE BYTE POINTER TO EXEC MAP SLOT
	MOVEI	P3,PM.ACC+PM.WRT;START AT PAGE 0, ACCESSIBLE AND WRITEABLE
	LDB	T4,[POINT 14,MEMSIZ##,26] ;T4=NUMBER OF PAGES TO SCAN
	SKIPA	P4,[POINT 1,NXMTAB##] ;BYTE POINTER TO NXM TABLE
MPSLP1:	AOS	P3		;STEP TO NEXT PAGE
	SOJL	T4,MPSLP5	;RESTORE T1 AND RETURN IF SCANNED ALL OF MEMORY
	ILDB	T1,P4		;DOES THIS PAGE EXIST?
	JUMPN	T1,MPSLP1	;IF NOT, GO BACK FOR NEXT
	DPB	P3,W		;MAP THE CURRENT PAGE
	MOVEI	P1,.ERPIL(T3)	;EVA FOR BEGINNING OF PAGE
	CLRPT	(P1)		;CLEAR HDW PAGE TABLE FOR NEW MAPPING
	MOVEI	T2,PAGSIZ##	;NO. OF WORDS/PAGE TO SCAN
	WREBR	@.CPEBR##	;INVALIDATE CACHE
	SETOM	.CPPSP##	;SET SWEEPING FLAG
CPSMPI::MOVE	P2,(P1)		;TEST NEXT LOCATION
MPSLP2:	SOJLE	T2,MPSLP1	;IF CURRENT PAGE DONE, MAP NEXT
	AOJA	P1,CPSMPI	;GO TEST NEXT WORD IN PAGE

;HERE ON BAD WORD FOUND (NXM OR PARITY) - TRAP HAPPENED AND ADDED 3 TO PC
MPSLP3:	MAP	T1,(P1)		;GET THE PHYSICAL ADDRESS OF BAD WORD
	PUSH	P,P1		;SAVE THE EVA
	PUSH	P,T2		;SAVE THE WORD NUMBER IN CURRENT PAGE
	PUSH	P,T3		;SAVE THE POSITION IN THE MAP
	PUSH	P,T4		;SAVE # OF PAGES TO SCAN
	LDB	P1,[POINT 22,T1,35] ;GET JUST THE PHYSICAL ADDRESS OF BAD WORD
	PUSHJ	P,CPIASN##	;CONVERT TO SEG NUMBER IN J
	  TDZA	T1,T1		;INDICATE NO ERROR IN MONITOR OR JOB
	SETO	T1,		;INDICATE AN ERROR IN MONITOR OR JOB
	MOVE	P2,.CPTBD##	;GET BAD DATA WORD STORED BY THE TRAP ROUTINE
	PUSHJ	P,PARRBD##	;RECORD BAD DATA
	POP	P,T4		;RESTORE T4
	POP	P,T3		; AND T3
	POP	P,T2		; AND T2
	POP	P,P1		; AND P1
	SETZM	.CPPTH##	;CLEAR FLAG THAT TRAP HAPPENED
	JRST	MPSLP2		;GO CONTINUE THE SWEEP

MPSLP5:	SETZM	.CPPSP##	;CLEAR SWEEPING FLAG
	POPJ	P,		;RETURN
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
	JSP	T2,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

;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
	MOVE	T4,.CPTOS##
	HRLM	T3,.MEUPM(T4)
	CLRPGT	(0,.EUPMP)	;FLUSH PAGE TABLE SO NEW MAPPING IS IN EFFECT
;WORRY ABOUT INTERLEAVED MEMORY
	MOVEI	T3,MEMITL##	;NUMBER OF WAYS MEMORY CAN BE INTERLEAVED
	MOVEM	J,MOFLPG##	;FLAG THAT MEMORY BEING SET ON LINE
				; NXM AT THIS POINT ISN'T A SERIOUS ERROR
MEMO10:	MOVEI	T4,20		;TIME TO WAIT FOR NXM FLAG TO CAUSE AN IRP.
	SETZM	.EUPMP-1(T3)	;REFRENCE THE PAGE TO MAKE SURE ITS REALLY THERE
	SOJG	T4,.		;WAIT LONG ENOUGH FOR NXM INTERRUPT TO HAPPEN
	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,[.CSCMO,,.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
	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?
	CAMN	J,.CPJOB##	;CORE 0 ON THE CURRENT JOB?
	DATAO	PAG,NULDOP##	;YES, GIVE THE METERS SOMEPLACE ELSE TO WRITE
				; SINCE THIS PAGE COULD BE ALLOCATED TO SOMEONE ELSE
	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
	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
	PUSHJ	P,SAVE1##
	MOVE	P1,.CPTOS##
	AOS	T2,T1		;T2 = NUMBER OF WORDS OF CORE REQUIRED TO
				; SATISFY REQUEST
	LSH	T2,W2PLSH##	;T2 = NUMBER OF PAGES REQUIRED
	MOVE	T3,T2
	CAILE	J,JOBMAX##
	JRST	CORG0A		;NO
	LDB	T3,IMGOUT##
	JUMPE	T3,CORG0B
	LDB	T3,IFYPGS##
	JUMPE	T3,[LDB T3,NFYPGS##
		JRST CORG0C]
	MOVEI	T4,0
	DPB	T4,IFYPGS##
	CAIA
CORG0B:	MOVEI	T3,UPMPSZ##
	DPB	T3,NFYPGS##
CORG0C:	ADDM	T2,T3		;ADD THAT IN
CORG0A:	CAMLE	T3,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
	DPB	T2,IMGIN##	;STORE THE NUMBER OF PAGES ALLOCATED IN CORE
	HRLI	R,-1(T1)	;R = NEW PROTECTION,,?
	CAILE	J,JOBMAX##
	SKIPA	T2,T3
	MOVEI	T2,-UPMPSZ##(T3)
	PUSHJ	P,GTPAGS	;ALLOCATE THE PAGES TO SATISFY THE REQUEST
	MOVEI	T1,PM.ACC+PM.WRT+PM.CSH(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,UPMPSZ##	;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)
	MOVE	T2,.CPTOS##
	HRLM	T1,.MEUPM(T2)
	CLRPGT	(0,.EUPMP)	;THE UPMP IS NOW MAPPED THROUGH THE EXEC
	     	      		; MAP. CLEAR THE AM SO THE NEW MAPPING
				; WILL BE IN AFFECT
	SETZM	.EUPMP
	MOVE	T2,[.EUPMP,,.EUPMP+1]
	BLT	T2,.EUPMP+PG.BDY##	;ZERO THE ENTIRE UPMP
	MOVSI	T2,NUPPMT##	;NOW SETUP THE REST OF THE MAP FROM THE
	HRRI	T2,.EUPMP+.UPTVC ; 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
	CLRPT	.JDAT		;CLEAR OUT OLD ENTRY FOR .JDAT
	DPB	T1,JBYLSA##	;STORE FIRST PAGE OF LOW SEG IN JBTAD2
	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
	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)
	MOVE	T2,.CPTOS##
	HRLM	T1,.MEUPM(T2)
	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
	MOVEM	J,.UPMP+.UPJOB	;SAVE THE JOB NUMBER FOR DEBUGGING AND
				; VIRCHK (FOR GIVING BACK HIGH SEG CORE)

	HLRZM	R,.JDAT+JOBREL##	;STORE THE NEW SIZE OF THE LOW SEGMENT FOR THE
				; USER SO HE WON'T GET CONFUSED ON EXAMINE COMMAND
CORGT6:	SKIPE	R		;GETTING CORE?
	PUSHJ	P,IICLNK##	;YES--ADD TO IN-CORE LIST
	SKIPN	R		;GIVING UP CORE?
	PUSHJ	P,DICLNK##	;YES--REMOVE FROM IN-CORE LIST
	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
>
	LDB	T1,IMGOUT##	;CORE ALLOCATION FOR THE SWAPPER?
 	JUMPN	T1,CPOPJ1##	;YES, ALL DONE

	CAMN	J,.CPJOB##	;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
	CAMN	J,.CPJOB##	;CURRENT JOB?
	TLNN	R,MPGSIZ##	; OR ONLY ONE PAGE ALLOCATED TO THE CURRENT JOB?
				; IF ONLY 1 PAGE SETREL MIGHT NOT CALL MAPLOW

	JUMPN	R,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::
	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
	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,.CPJOB##	;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
	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,<
	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,USRPC##	;JOBS PC
	TLNN	T1,(XC.USR)	;JOB IN EXEC MODE?
	MOVEM	R,.JDAT+JOBDPG##;YES, STORE POSSIBLY UPDATED R IN THE DUMP ACS
	PJRST	MAPHGH		;MAP THE HIGH SEGMENT
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

;SUBROUTINE TO MAKE A PHYSICAL PAGE ADDRESSABLE FOR SWAPPER
;CALL SEQUENCE:
;	MOVEI	T1,PAGE NUMBER
;	PUSHJ	P,SWPAD
;	ALWAYS RETURNS HERE
;T1=EVA OF FIRST WORD IN PAGE
SWPAD::	PUSHJ	P,SAVE1##
	MOVE	P1,.CPTOS##
	TRO	T1,PM.ACC+PM.WRT;SET ACCESS BITS
	HRRM	T1,.MECKS(P1)
				;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 FROM UUO,,JOB NUMBER
;	MOVE	P2,NUMBER OF WORDS TO TRANSFER
;	PUSHJ	P,JOBPKD
;	  RETURN HERE IF PAGE NOT IN CORE
;	RETURN HERE IF DATA TRANSFERRED SUCCESSFULLY
JOBPKD::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
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?
	TLNE	P1,(JK.EVA!JK.UPM) ; AND NOT FUNNY SPACE ADDRESS
	CAIA			;NO, CONTINUE
	JRST	JOBPK3		;YES, BLT FROM USER 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,.TEMP)	;CLEAR THE AM FOR THIS PAGE
	HRRZ	T3,T1		;DESTINATION ADDRESS IF WRITING
	TLNN	P1,(JK.WRT)	;WRITING?
	HLRZ	T3,T1		;NO, READING. GET SOURCE ADDRESS
	TLNE	P1,(JK.EVA)	;ADDRESS IN EVM MAPPED THRU OTHER JOB?
	ADDI	T3,440000	;YES, ADD OFFSET THAT WILL CAUSE CALCULATIONS
				;BELOW TO POINT TO WORD 400 IN UPMP
	TLNE	P1,(JK.UPM)	;READING THE UPMP?
	MOVE	T3,[.UPMVP]	;YES, VIRTUAL PAGE NUMBER OF THE UPMP
	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,(POINT 18,0)	;ASSUME AN EVEN STARTING PAGE
	SKIPGE	T3		;IS IT AN EVEN PAGE?
	HRLI	T4,(POINT 18,0,17) ;NO, ODD
	MOVEI	T3,.UPMP+.MJBPK	;ADDRESS OF JOBPEK TEMPORARY SLOTS IN THE
				; PER-PROCESS MAP
	HRLI	T3,(POINT 18,0)	;STARTING IN THE LEFT HALF WORD
	HRRI	P1,.JBPK	;SETUP FIRST PAGE TO CLEAR
JOBPK0:	ILDB	P3,T4		;GET THE ENTRY FROM THE TARGET JOB'S MAP
	TRNE	P3,PM.ACC	;ACCESS ALLOWED?
	JRST	JOBPK1		;YES, ZOOM ON
	JUMPE	P3,JPKPNC	;ERROR RETURN IF PAGE DOESN'T EXIST
	TLNN	P1,(JK.EVA)	;PAGE MUST BE THERE IF EVM ADDRESS
	CAIN	P3,PM.ZER	;ALLOCATED BUT ZERO PAGE?
	JRST	JPKPNC		;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?
	JRST	JPKPNC		;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
	CLRPGT	(0,(P1))	;CLEAR PAGE TABLE
	ADDI	P1,PAGSIZ##	;STEP TO NEXT PAGE
	AOBJN	T2,JOBPK0	;MAP ENOUGH PAGES TO ALLOW THE TRANSFER
	MOVEI	T2,.JBPK/1000	;PAGE NUMBER IN THE EXEC VIRTUAL ADDRESS SPACE
	TLNE	P1,(JK.WRT)	;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
	JRST	CPOPJ1##	;INDICATE ALL PAGES WERE IN CORE AND THE DATA
				; WAS TRANSFERED AND RETURN


;ERROR CODES (MORE IN UUOCON)
	ERCODE	JPKPNC,JKPNC%	;PAGE NOT IN CORE
>
	$LIT
KSEND:	END