Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99m-bb - vmser.x19
There are no other files named vmser.x19 in the archive.
TITLE	VMSER - VIRTUAL MEMORY SERVICE ROUTINE  V4653
SUBTTL	J. FLEMMING, T. WACHS 30 JULY 86
	SEARCH	F,S
	SALL
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1973,1986>
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.


XP VVMSER,4653    ;ASSEMBLY INSTRUCTIONS: VMSER,VMSER/C=F,S,VMSER
	ENTRY	VMSER
VMSER::


OPDEF	PAGE.	[CALLI	145]
OPDEF	MERGE.	[CALLI	173]
	SUBTTL	BYTE POINTERS

;THESE WILL HAVE TO BE CHANGED IF 30-BIT ADDRESSING IS EVER A REALITY

NVPNP1:	POINT P2.SPN,PT2TAB(P1),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNP2:	POINT P2.SPN,PT2TAB(P2),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNP4:	POINT P2.SPN,PT2TAB(P4),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNT1:	POINT P2.SPN,PT2TAB(T1),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNT2:	POINT P2.SPN,PT2TAB(T2),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNT3:	POINT P2.SPN,PT2TAB(T3),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNF:	POINT P2.SPN,PT2TAB(F),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNR:	POINT P2.SPN,PT2TAB(R),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT

SUBTTL FILIO  INTERFACE WITH FILSER

;SUBROUTINE TO SCAN FOR THINGS TO DO FOR THE SWAPPER
;OPTIMIZES ALL SEEK REQUESTS, TRANSFER REQUESTS, STARTS SEEKS GOING
;STARTS DATA TRANSFER GOING IF ON UUO (CHAN 7) LEVEL
SWPSCN::
IFN FTMP,<
	SYSPIF
	SKIPL	T1,SCNOWN##	;IF NO CPU "OWNS" SCNCNT
	CAMN	T1,.CPCPN##	; OR IF THIS CPU "OWNS" IT
>
	AOSE	SCNCNT##	;SOMEONE ALREADY DOING THIS?
IFE FTMP,<
	PJRST	DOPOPJ##	;YES, GO AWAY (AT INTERRUPT LEVEL,
				; SWPSCN IS RUNNING AT UUO LEVEL)
>
IFN FTMP,<
	JRST	[SYSPIN
		 PJRST DOPOPJ##]
	MOVE	T1,.CPCPN##
	MOVEM	T1,SCNOWN##
	SYSPIN
>
	DSKON
	PUSHJ	P,SAVE3##	;NO, NOW WE ARE
	JUMPE	J,SWPSC1	;GO IF UUO LEVEL
	SOS	P3,CHNCFS##(P1)	;UPDATE CHANNEL FAIRNESS COUNT FOR SWAPPING
	HRR	P3,CHNQUE##(P1)	;RH NON-0 IF FILE TRANSFER WAITING
SWPSC1:	PUSH	P,J		;SAVE J
	PUSH	P,U		;SAVE U
SWPSC2:	SETZB	P1,T2		;INDICATE FIRST CALL TO NEXT
	HRLOI	T1,377777	;SET ALL UNITS IN A.S.L. TO HUGE
				; TIMES TO BLOCK OR TIMES TO CYLINDER
	MOVEI	T4,TWCOD##
SWPSC3:	SKIPG	T3,SWPTAB##(T2)	;UNIT IN ASL?
	JRST	SWPSC4
	CAME	T1,UNISWD##(T3)	;TIME ALREADY INFINITY?
	CAME	T4,UNISTS##(T3)	;NO, IS UNIT IN TRANSFER WAIT?
	SKIPA	U,T1		;NO, MAKE TIME = INFINITY
	MOVEI	U,-1		;YES, INSURE SWPPIK WILL FIND IT EVEN IF SWPSCN DOESN'T
	MOVEM	U,UNISWD##(T3)	;SAVE LARGE TIME-TO-BLOCK OR CYLINDER
IFN FTDUAL,<
	SKIPE	T3,UNI2ND##(T3)	;IN 2ND PORT TOO
	MOVEM	U,UNISWD##(T3)
>
SWPSC4:	CAIGE	T2,SWPMAX##	;END OF THE ACTIVE SWAPPING LIST?
	AOJA	T2,SWPSC3	;NO, LOOK AT ALL UNITS IN THE ASL
	DSKOFF
SWPSC5:	PUSHJ	P,NEXT		;GET NEXT REQUEST FROM SWPLST
	  JRST	SWPS22		;DONE
	JUMPL	U,SWPS10	;DISK (CPU) GONE, ERROR
	HRRZ	T2,UNICDA##(U)	;DDB UNIT IS ATTACHED TO
	CAIE	T2,SWPDDB##	;IF NOT THE SWAPPER
	JUMPN	T2,SWPSC5	;LET FILE IO HAPPEN
	HRR	J,UNIKON##(U)	;SET UP J POINTING TO  KONTROLLER
IFN FTDUAL,<
	PUSHJ	P,RHBP##	;NEED TO REREAD HOME BLOCKS?
	  JRST	SWPSC5		;YES, DON'T SWAP ON THIS UNIT
	CAME	J,-1(P)		;IGNORE BUSY IF INT ON THIS KON
	SKIPL	KONBSY##(J)	;KON BUSY?
	JRST	SWPSC6		;IDLE, USE PRIME PORT
	SKIPN	T3,UNI2ND##(U)	;BUSY, DUAL-PORTED DRIVE?
	JRST	SWPSC6		;NO, WAIT FOR PRIME PORT
	HRR	J,UNIKON##(T3)	;YES, GET 2ND KON
	CAME	J,-1(P)		;IGNORE BUSY IF INT ON THIS KON
	SKIPL	KONBSY##(J)	;KON BUSY?
	HRRZ	U,UNI2ND##(U)	;IDLE, USE 2ND PORT
	HRR	J,UNIKON##(U)	;GET (NEW) KON
SWPSC6:
IFN FTMP,<
	PUSHJ	P,SWPCP		;SET U IF OTHER CPU
	  JFCL
>>;END FTDUAL&FTMP
	CAMN	J,-1(P)		;IF NOT ON INTERRUPT LEVEL FOR THIS CHAN,
	JRST	SWPSC7
	HRRZ	T2,KONCHN##(J)
	SKIPE	DIADSK##
	CAME	T2,DIACHN##	;IGNORE REQUEST IF SHUTTING DOWN CHAN

	SKIPGE	KONBSY##(J)	;IS KONTROLLER IDLE?
	JRST	SWPSC5		;NO, TRY NEXT SWPLST ENTRY
	JRST	SWPSC8		;YES, THIS REQUEST IS OK
SWPSC7:	JUMPGE	P3,SWPSC8	;GO UNLESS BEING FAIR
IFN FTDUAL,<
	SKIPE	T4,UNI2ND##(U)	;POSITIONS WAITING ON SECOND PORT?
	SKIPN	UNIQUE##(T4)
>
	SKIPE	UNIQUE##(U)	;OR PRIME PORT?
	JRST	SWPSC5		;YES, DON'T DO THIS REQUEST
SWPSC8:	SKIPG	KONPOS##(J)	;CAN DO THINGS FOR THIS REQUEST
	JRST	SWPS12		;UNIT DOESNT POSITION
	MOVE	T4,T1		;POSITIONING UNIT - SAVE BLOCK NUMBER
	PUSHJ	P,@KONCCM##(J)	;COMPUTE DISTANCE TO BLOCK
	JUMPE	T1,SWPS11	;GO IF UNIT ON CYLINDER
	MOVMS	T1		;NOT ON CYL, GET + DISTANCE
	SKIPE	T2,UNISTS##(U)	;IS UNIT IDLE
	CAIN	T2,O2COD##	; OR OFF-LINE (NEED THIS TO GET TO BADUNI)
	JRST	SWPSC9		;YES, SAVE THIS REQUEST
	CAIN	T2,PWCOD##	;NO, IN POSITION WAIT?
	CAML	T1,UNISWD##(U)	;YES, IS THIS DISTANCE SHORTER?
	JRST	SWPSC5		;NO, TRY NEXT REQUEST
SWPSC9:	MOVEI	T2,PWCOD##	;MAKE SURE UNIT IS IN POSITION WAIT
	PUSHJ	P,SETUDB	;SET UNISWA, ETC.
	JRST	SWPSC5		;AND TEST NEXT SWPLST ENTRY
;HERE AFTER NUS STOPCD

SWPS10:	PUSHJ	P,SWPCD1	;GIVE SWAP READ ERROR
	JRST	SWPSC5		;AND PUSH ON
;HERE IF UNIT ON-CYLINDER
SWPS11:	MOVE	T1,T4		;RESTORE BLOCK NUMBER

;HERE IF UNIT DOESN'T POSITION OR ON CYLINDER
SWPS12:	CAMN	J,-1(P)		;INTERRUPT LEVEL FOR THIS KON?
	JRST	SWPS13		;YES
	SKIPL	KONBSY##(J)	;NO, IS KON BUSY?
	JRST	SWPS14		;NO, KON IDLE
	JRST	SWPSC5		;YES, KON BUSY
SWPS13:	TRNE	P3,-1		;TRANSFERS WAITING?
	JUMPL	P3,SWPSC5	;YES, IGNORE IF BEING FAIR
SWPS14:
IFN FTDUAL,<
	HRRZ	T2,UNICHN##(U)	;FILE TRANSFERS WAITING ON THIS CHAN?
	SKIPE	CHNQUE##(T2)
	SKIPN	T2,UNI2ND##(U)	;AND DUAL PORTED?
	JRST	SWPS16		;NO, OK LET IT HAPPEN
	HRR	J,UNIKON##(T2)	;YES, IS OTHER KON BUSY?
	CAME	J,-1(P)
	SKIPL	KONBSY##(J)
	JRST	SWPS15		;IDLE, LET SWAP HAPPEN
	HRRZ	T2,KONCUA##(J)	;BUSY, IS IT DOING A SWAP?
	MOVE	T3,UNISTS##(T2)
	HRRZ	T4,UNICDA##(T2)
	CAIN	T3,TCOD##
	CAIE	T4,SWPDDB##
	JRST	SWPS15		;NOT A SWAP
	JRST	SWPSC5		;DON'T TIE UP BOTH CHANNELS DOING SWAPS
				;LEAVE ONE CHANNEL OPEN FOR FILE I/O
SWPS15:	HRR	J,UNIKON##(U)	;GET KON BACK
SWPS16:>
IFN FTMP,<
	MOVE	T2,UNICAM##(U)
	TDNE	T2,.CPBIT##
>
	PUSHJ	P,@KONLTM##(J)	;COMPUTE TIME TO BLOCK
	  MOVEI	T1,0		;UNIT OFF-LINE
	SKIPE	T2,UNISTS##(U)	;IS UNIT IDLE
	CAIN	T2,PWCOD##	; OR POSITION WAIT?
	JRST	SWPS17		;YES, THIS IS THE BEST TIME TO BLOCK
	CAIN	T2,TWCOD##	;NO, TRANSFER WAIT?
	CAMLE	T1,UNISWD##(U)	;YES, IS THIS BEST?
	JRST	SWPSC5		;NO, TEST NEXT ENTRY
SWPS17:	MOVEI	T2,TWCOD##	;SET UNIT TO TRANSFER WAIT
	PUSHJ	P,SETUDB	;SET UNISWA, ETC.
IFN FTCIDSK,<
	SKIPL	KONMX##(J)	;MULTIPLE XFERS?
	JRST	SWPSC5		;NO
	PUSHJ	P,SWPCH		;PARANOIA
	  JRST	SWPSC5
	SKIPL	KONCNA##(J)	;CREDITS?
	PUSHJ	P,THSBLK	;YES, GET BLOCK NUMBER
	  JRST	SWPSC5		;MEMTAB MESSED UP
IFN FTMP,<
	PUSHJ	P,SWPCD		;ON THIS CPU?
	  JRST	SWPS18		;NO, SET SO DSKTIC WILL FIND IT
>
	MOVEM	T1,DEVBLK##(F)	;SAVE IN SWPDDB
	MOVEM	U,DEVUNI##(F)	;SAVE U IN DDB
	PUSH	P,P1		;SAVE OUR PLACE
	MOVE	P1,KONCHN##(J)	;CHAN LOC
	PUSHJ	P,STRTIO##	;GO CRANK UP THE IO
	POP	P,P1		;WHERE WERE WE?
	DSKOFF			;STRTIO ENABLED INTERRUPTS
IFN FTMP,<
	JRST	SWPSC5
SWPS18:	HRRZM	J,.C0SWP##(T4)	;WAKE UP THE OTHER CPU
>
>; END IFN FTCIDSK
	JRST	SWPSC5		;JUST RESCAN IF NO CI DISKS
IFN FTMP,<
SWPS20: SETOM	.C0SWP##(T4)	;COME BACK AT DSKTIC
>
SWPS21:	PUSHJ	P,IDLEPW##	;SET IDLE OR PW
	JRST	SWPS26
;HERE WHEN ALL OF SWPLST HAS BEEN SCANNED. START SEEKS GOING
SWPS22:	MOVEI	P2,0		;START AT 1ST UNIT IN ASL
SWPS23:	SKIPG	U,SWPTAB##(P2)	;GET UNIT
	JRST	SWPS26		;NOT THERE, TRY NEXT
	DSKOFF			;NO DISK INTERRUPTS HERE
	MOVE	T1,UNISTS##(U)	;STATE OF UNIT
	MOVE	T2,UNISWD##(U)	;DISTANCE OR TIME OF BEST
	CAME	T2,[377777,,-1];IS ANYTHING THERE?
	CAIE	T1,PWCOD##	;YES, POSITION WAIT?
	JRST	SWPS26		;NO
	HRR	J,UNIKON##(U)	;KONTROLLER
IFN FTCIDSK,<
	SKIPGE	KONMX##(J)	;IF IT'S PW, WE DIDN'T PUT IT THERE
	JRST	SWPS26
>
IFN FTDUAL,<
	CAME	J,-1(P)		;IGNORE BUSY IF INT ON THIS KON
	SKIPL	KONBSY##(J)	;KON BUSY?
	JRST	SWPS24		;IDLE, USE PRIME PORT
	SKIPN	T3,UNI2ND##(U)	;BUSY, DUAL-PORTED DRIVE?
	JRST	SWPS24		;NO, WAIT FOR PRIME PORT
	HRR	J,UNIKON##(T3)	;YES, GET 2ND KON
	CAME	J,-1(P)		;IGNORE BUSY IF INT ON THIS KON
	SKIPL	KONBSY##(J)	;KON BUSY?
	HRRZ	U,UNI2ND##(U)	;IDLE, USE 2ND PORT
	HRR	J,UNIKON##(U)	;GET (NEW) KON
SWPS24:>
	MOVE	P1,UNISWA##(U)	;GET SWPLST ENTRY
IFN FTMP,<
	PUSHJ	P,SWPCD		;UNIT ON THIS CPU?
	  JRST	SWPS20		;NO,COME BACK AT DSKTIC
>
	CAMN	J,-1(P)		;ON INTERRUPT LEVEL?
	JRST	SWPS25		;YES, KONTROLLER ISNT REALLY BUSY
	MOVSI	T2,KOPPWX##
	AND	T2,KONPOS##(J)	;T2 NON-0 IF KON CAN START SEEKS WHILE BUSY
	SKIPE	DIADSK##	;IF DIAG IS GOING
	SETZ	T2,		;REQUIRE KDB TO BE IDLE

	SKIPGE	KONBSY##(J)	;IS KONTROLLER NOW BUSY?
	JUMPE	T2,SWPS21	;YES, TOUGH LUCK
SWPS25:
IFN FTDUAL,<
	HRL	P1,U		;SAVE U (2ND PORT OF DUAL-PORTED DRIVE)
>
	PUSHJ	P,THSBLK	;NO, GET BLOCK AND UNIT AGAIN
	  JRST	SWPS26		;MEMTAB IS MESSED UP
IFN FTDUAL,<
	HLRZ	U,P1		;RESTORE U
>
	MOVEM	T1,DEVBLK##(F)	;SAVE BLOCK IN SWPDDB FOR UNIPOS
	MOVEM	U,DEVUNI##(F)	;SAVE UNIT IN SWPDDB
	MOVE	P1,KONCHN##(J)	;IN CASE STRPOS CALLS STRTIO
IFN FTDUAL,<
	SKIPE	T1,UNI2ND##(U)	;TO DETECT SPURIOUS INTERRUPTS
	SETZM	UNICDA##(T1)
	SETOM	UNICDA##(U)	;SAVE F IN ACTIVE UDB
>
	PUSHJ	P,STRPOS##	;GO START THE SEEK
SWPS26:	CAIGE	P2,SWPMAX##	;AT END OF SWPTAB?
	AOJA	P2,SWPS23	;NO, TEST NEXT UNIT IN ASL

;HERE WHEN ALL UNITS HAVE BEEN STARTED SEEKING
	DSKON
	SKIPN	-1(P)		;INTERRUPT LEVEL?
	JRST	SWPPI1		;NO, START IO IF A UNIT IN TW
	PJRST	SWPPI6		;YES, EXIT HOLDING SCNLOK (SWPPIK
				;WILL BE CALLED SOON)

;ROUTINE TO SAVE STUFF IN UDB
;ENTER T1=UNISWD, T2=UNISTS, P1=UNISWA
SETUDB:	MOVEM	T1,UNISWD##(U)	;SAVE TIME
	MOVEM	P1,UNISWA##(U)	;SAVE SWPLST POSITION
IFN FTCIDSK,<
	SKIPL	KONMX##(J)
>
	MOVEM	T2,UNISTS##(U)	;SAVE PW/TW
IFN FTDUAL,<
	SKIPN	T3,UNI2ND##(U)	;IS THERE A SECOND PORT?
	POPJ	P,		;NO
	MOVEM	T1,UNISWD##(T3)	;YES, SET UP THAT UDB TOO
	MOVEM	P1,UNISWA##(T3)
IFN FTCIDSK,<
	SKIPL	KONMX##(J)
>
	MOVEM	T2,UNISTS##(T3)
>
	POPJ	P,
;SUBROUTINE TO SCAN ALL UNITS IN A.S.L., START TRANSFER ON BEST
SWPPIK::
IFN FTMP,<
	SKIPL	T1,SCNOWN##
	CAMN	T1,.CPCPN##	;IF THIS CPU "OWNS" SCNCNT
>
	SKIPE	SCNCNT##	;SOMEONE ALREADY HERE?
	POPJ	P,		;YES, WAIT A WHILE
	PUSHJ	P,SAVE2##	;SAVE P1,P2
	PUSH	P,J		;SAVE J
	PUSH	P,U
	HRRZ	P2,P1		;SAVE LOC OF CHAN DB
	MOVSI	T1,KOPBSY##	;SET EVERYTHING IDLE SO FILIO WILL DO SOMETHING
	ANDCAM	T1,KONBSY##(J)	; (THEY REALLY ARE, HAVEN'T YET BEEN MARKED)
SWPPI1:	SETZB	T1,P1		;INITIALIZE
	HRLOI	T2,377777	;INITIALIZE BEST-SO-FAR
	DSKOFF
SWPPI2:	SKIPG	U,SWPTAB##(T1)	;GET ASL ENTRY
	JRST	SWPPI4
	HRR	J,UNIKON##(U)	;SET KONTROLLER
IFN FTDUAL,<
	CAIE	P2,@KONCHN##(J)	;IGNORE BUSY IF INT ON THIS CHAN
	SKIPGE	@KONCHN##(J)	;CHAN BUSY?
	JRST	SWPPI3		;IDLE, USE PRIME PORT
	SKIPN	T3,UNI2ND##(U)	;BUSY, DUAL-PORTED DRIVE?
	JRST	SWPPI3		;NO, WAIT FOR PRIME PORT
	HRR	J,UNIKON##(T3)	;YES, GET 2ND KON
	CAIE	P2,@KONCHN##(J)	;IGNORE BUSY IF INT ON THIS CHAN
	SKIPGE	@KONCHN##(J)	;CHAN BUSY?
	HRRZ	U,UNI2ND##(U)	;IDLE, USE 2ND PORT
	HRR	J,UNIKON##(U)	;GET (NEW) KON
SWPPI3:>
IFN FTMP,<
	PUSHJ	P,SWPCP		;ON THIS CPU?
	  JRST	[SKIPLE .C0SWP##(T4) ;NO, ALREADY QUEUED AN IO ON OTHER CPU?
		 JRST SWPPI4	 ;YES, IGNORE THIS UNIT
		 JRST .+1]	 ;NO, GET 1 TO START ON OTHER CPU
>
IFE FTMP&FTDUAL,<
	MOVE	T3,UNISTS##(U)	;STATE OF UNIT
>
IFN FTMP&FTDUAL,<
	SKIPG	T3,SWPTAB##(T1)	;GET UNISTS FROM THE UNIT WHICH IS IN
	JRST	SWPPI4		;?
	MOVE	T3,UNISTS##(T3)	; SWPTAB (MIGHT HAVE CHANGED U TO 2ND PORT)
>
	CAIE	P2,@KONCHN##(J)
	SKIPGE	@KONCHN##(J)	;IS CHANNEL IDLE?
	CAIE	T3,TWCOD##	;YES, UNIT IN TRANSFER WAIT?
	JRST	SWPPI4		;NO, TEST NEXT UNIT
	CAMLE	T2,UNISWD##(U)	;YES, IS THIS BEST SO FAR?
	PUSHJ	P,SWPCH		;YES, CAN WE DO THIS IO (FRAG'D LIST)?
	  JRST	SWPPI4		;NO, TRY NEXT
	MOVE	T2,UNISWD##(U)	;YES, SAVE TIME
	MOVE	P1,UNISWA##(U)	;SAVE SWPLST POSITION
IFN FTDUAL,<
	HRL	P1,U		;SAVE ACTUAL UNIT
>
SWPPI4:	CAIGE	T1,SWPMAX##	;END OF ASL?
	AOJA	T1,SWPPI2	;NO, TRY NEXT UNIT
	JUMPE	P1,SWPPI5	;RETURN IF NOTHING TO DO

;HERE WHEN BEST TRANSFER HAS BEEN FOUND FOR SOME CHANNEL
	PUSHJ	P,THSBLK	;GET BLOCK NUMBER
	  JRST	[SETZM (P1)	;MEMTAB MESSED UP
		 JRST SWPPI5]
IFN FTDUAL,<
	HLRZ	U,P1		;GET ACTUAL UNIT BACK
>
	HRR	J,UNIKON##(U)	;SET UP KONTROLLER
IFN FTMP,<
	PUSHJ	P,SWPCD		;ON THIS CPU?
	  JRST	SWPPI7		;NO, SET SO DSKTIC WILL FIND IT
>
	MOVEM	T1,DEVBLK##(F)	;SAVE IN SWPDDB
	MOVEM	U,DEVUNI##(F)	;SAVE U IN DDB
	MOVE	P1,KONCHN##(J)	;AND CHAN LOC
	SKIPGE	KONBSY##(J)	;IS KONTROLLER BUSY?
	JRST	SWPPI8		;YES, CANT USE IT NOW
	SETZM	(P1)		;CHAN IS BUSY
IFN FTDUAL,<
	SKIPE	T1,UNI2ND##(U)
	SETZM	UNICDA##(T1)
	SETOM	UNICDA##(U)
>
	PUSHJ	P,STRTIO##	;GO CRANK UP THE IO
	CAIN	P2,@KONCHN##(J)	;YES, INT ON THIS CHAN?
	TLO	P2,-1		;YES, FLAG THAT CHAN IS NOW BUSY
	JRST	SWPPI1		;LOOK FOR OTHER CHAN
;HERE WHEN THROUGH
SWPPI5:	DSKON
	SOSL	SCNCNT##	;DECREMENT SCNCNT. DID INTERRUPT LEVEL TRY?
	JUMPGE	P2,SWPSC2	;YES, SCAN AGAIN (UNIT IN ASL MAY HAVE CHANGED STATE)
				;DON'T RETRY IF STARTED XFER. COULDN'T TELL
				;IF KON WAS REALLY BUSY.
	SKIPGE	P2		;STARTED XFER ON THIS CHAN?
	AOS	-2(P)		;YES, TELL FILSER SOMETHING HAPPENED
IFN FTCIDSK,<
;NOTE THAT FOR A CI TYPE DISK WE END UP LYING TO FILIO.
;WE TELL HIM THAT WE DIDN'T START A TRANSFER WHEN ACTUALLY WE DID.
;THIS WILL CONVINCE HIM THAT IT'S OK TO START A FILE.
>
IFN FTMP,<
	SETOM	SCNOWN##
>
	MOVE	J,-1(P)		;RESTORE J
	JUMPE	J,SWPPI6	;IF ON INTERRUPT LEVEL,
	MOVE	P1,KONCHN##(J)	;GET CHAN LOC
	SKIPGE	T1,CHNCFS##(P1);RESTORE CHNCFT IF IT COUNTED
	MOVE	T1,CHNIFS##(P1); BELOW 0
	MOVEM	T1,CHNCFS##(P1)

SWPPI6:	POP	P,U		;RESTORE U
	PJRST	JPOPJ##		;AND EXIT

IFN FTMP,<
SWPPI7:	HRRZM	J,.C0SWP##(T4)	;.CPSWP GREATER THAN 0
>
SWPPI8:	DSKON
	JRST	SWPPI1

;SUBROUTINE TO SEE IF A SWAP REQUEST MAY BE STARTED
;CALLED AT INTERRUPT LEVEL BY FILIO ON A POSITION-DONE INTERRUPT AND BY SWPPIK
;NON-SKIP RETURN IF CAN'T START IT NOW (FRAGMENTED, ANOTHER FRAGMENT IN PROGRESS)
;SKIP RETURN IF IO CAN BE STARTED
;PRESERVES T1,T2
SWPCH:
SWPCHK::HLRZ	T3,UNISWA##(U)	;FRAGMENTED?
	JUMPE	T3,CPOPJ1##	;NO, OK TO START
	HRL	T3,(T3)
	MOVSS	T3		;YES, GET START OF CHAIN
SWPCH1:	SKIPN	T4,(T3)		;GET FRAGMENT POINTER
	PJRST	CPOPJ1##	;DONE - OK TO START
	JUMPL	T4,[HRR T3,T4
		    JRST SWPCH1]
	TLNE	T4,(SL.IOP)	;IN PROGRESS?
	CAMN	T3,UNISWA##(U)	;YES, IS IT THE ONE WE WANT TO START?
	AOJA	T3,SWPCH1	;THIS ONE IS OK, CHECK NEXT
	POPJ	P,		;IO ALREADY HAPPENING - QUEUE THIS TILL LATER


IFN FTMP,<
;RETURNS CPOPJ IF ON OTHER CPU, CAUSES SWAP READ ERROR IF OTHER CPU IS DEAD
; RETURN CPOPJ1 IF ON THIS CPU
;PRESERVES T1,T2
SWPCD:	PUSHJ	P,SWPCP		;ON THIS CPU?
	  CAIA			;NO
	JRST	CPOPJ1##	;YES, ON THIS CPU RETURN
	MOVSI	T3,(CR.DET)	;CPU IS DETACHED BIT
	TDNN	T3,.C0RUN##(T4)	;CPU DETACHED?
	POPJ	P,
>
SWPCD1:	PUSHJ	P,SAVT##	;PRESERVE T1,T2 - SAVE T4
	PUSHJ	P,SW2LC		;INDEX INTO SW2LST
	MOVE	T4,SW2LST##(T1)	;ORIGINAL SWPLST ENTRY
	TLO	T4,(SL.ERR+SL.IOP) ;ERROR + I/O IN PROGRESS
	PJRST	DONE1		;SET IT DONE
IFN FTMP,<
;RETURNS CPOPJ IF ON OTHER CPU, CPOPJ1 IF ON THIS
;PRESERVES T1,T2
SWPCP:	MOVE	T4,UNICAM##(U)	;CPU THAT THIS KONTROLLER IS ON
	TDNE	T4,.CPBIT##	;THIS CPU?
	JRST	CPOPJ1##	;YES, DO THE I/O NOW
IFN FTDUAL,<
	SKIPN	T3,UNI2ND##(U)	;SECOND PORT
	JRST	SWPCP1
	MOVE	T3,UNICAM##(T3)	;2ND PORT ON THIS CPU?
	TDNN	T3,.CPBIT##
	JRST	SWPCP1		;NO
	HRRZ	U,UNI2ND##(U)	;SWITCH TO OTHER PORT
	HRR	J,UNIKON##(U)	;KONTROLLER FOR SECOND PORT
	JRST	CPOPJ1##	;DO I/O NOW RETURN
SWPCP1:
>
	PUSH	P,T1		;SAVE AC
	PUSH	P,T2
	PUSHJ	P,GETCAM##	;BUILD COMBINED CPU BIT MASK
	PUSHJ	P,CAMCPU##	;PICK BEST CPU
	JRST	TTPOPJ##
> ;END IFN FTMP
;SUBROUTINE TO GET THE NEXT ENTRY FROM SWPLST
;CALL WITH P1=0 ON FIRST ENTRY
;SUBSEQUENTLY CALL WITH P1,P2=NUMBERS RETURNED FROM THE LAST CALL
;RETURNS CPOPJ IF NO MORE ENTRIES
;RETURNS CPOPJ1 WITH P1 POINTING AT NEXT ENTRY,
; U=LOC OF UNIT DATA BLOCK, T1=PHYSICAL DSK BLOCK NUMBER
NEXT:	JUMPN	P1,NEXT2	;FIRST CALL?
	PUSHJ	P,UUOLVL##	;IF AT UUO LEVEL
	  JRST	NEXT1		;AVOID CHANGING THE UBR
	HRRZ	P1,.USSLX	;BY FINDING ONLY THE ENTRY FOR THIS JOB
	MOVE	T1,SWPLST##(P1)
	TLNE	T1,(SL.IOP!SL.IOD) ;ALREADY STARTED?
	POPJ	P,		;YES, GO AWAY
	MOVEI	P2,1
	MOVEI	P1,SWPLST##-1(P1)
	JUMPL	T1,NEXT9	;IF FRAGMENTED
	JRST	NEXT7
NEXT1:	MOVEI	P1,SWPLST##-1	;YES, INITIALIZE P1
	SKIPN	P2,SPRCNT##	;ONLY LOOK AT SWAPS IF THERE ARE ANY
	SKIPA	P2,SLECNT##	;P2=NUMBER OF ENTRIES IN SWPLST
	ADD	P2,SWPCNT##
NEXT2:	JUMPE	P2,CPOPJ##	;NON-SKIP RETURN IF NO MORE ENTRIES
NEXT3:	SKIPA	T2,[TLNN T1,(SL.IOP)]	;ASSUME NOT A FRAGMENTED ENTRY
NEXT4:	MOVE	T2,[TLNE T1,(SL.IOP)]	;IF IT IS A FRAGMENTED ENTRY
NEXT5:	SKIPN	T1,1(P1)	;IS THERE ANOTHER ENTRY IN SWPLST?
	JRST	NEXT11		;MAYBE (IF WE'RE IN A FRAGMENT CHAIN)
	SKIPE	SPRCNT##	;IF ANY SWAPS WAITING,
	TLNE	T1,(SL.SIO)	;IF THIS IS A SWAP REQUEST
	SKIPA	T4,SINCNT##	; TEST IT
	JRST	NEXT11		;PAGE REQUEST - IGNORE FOR NOW
	JUMPL	T1,NEXT9	;SWAP, IS IT A FRAGMENT POINTER?
	JUMPE	P2,NEXT6	;IGNORE SINCNT IF FRAGMENT IN PROGRESS
	TLNE	T1,(SL.DIO)	;NO, IF AN OUTPUT REQUEST
	JUMPG	T4,NEXT11	; IGNORE IT IF ANY INPUT REQUESTS WAITING
NEXT6:	XCT	T2		;IS IT USABLE?(SL.IOP=0 IF NOT IN A FRAGMENT CHAIN
				; , SL.IOP=1 IF IN A FRAGMENT CHAIN)
	TLNE	T1,(SL.IOD)	; AND SL.IOD=0
	AOJA	P1,NEXT13	;NO, TRY NEXT
	TLZN	P1,400000	;FIRST TIME FOR THIS ENTRY?
	TLNN	P1,-1		;NO, IN A FRAGMENT?
	JRST	NEXT7		;NO, USE THIS ENTRY
	MOVSI	T4,(SL.MAP)	;MAP INFO IN THIS ENTRY BIT
	TLNN	T1,(SL.DIO)	;YES, SWAPPING OUT?
	JRST	NEXT7		;NO, ALL IS WELL
	SKIPE	2(P1)		;YES, LAST ENTRY IN THE FRAGMENT?
	TDNE	T4,1(P1)	;MAP INFO THIS ENTRY AS BAD AS LAST
	JRST	NEXT11		;YES, CANT USE IT (CANT WRITE UPMP TILL ALL
				; DSK ADDRESSES ARE FILLED IN)
NEXT7:
IFN FTMP&FTKL10,<
	TLNE	T1,(SL.DIO)	;IF PAGING OUT
	TLNE	T1,(SL.SIO)	;(NOT SWAPPING)
	JRST	NEXT8
	PUSHJ	P,SW2LC
	TLNE	P1,-1
	SUBI	T1,1
	HRR	J,SW3LST##+1(T1) ;GET JOB NUMBER
	PUSHJ	P,SBCCSH##	;IS IT RIGHT WRT CACHE?
	  SKIPA	T1,1(P1)	;YES, DO IT
	JRST	NEXT11		;NO, TRY SOMEONE ELSE
>
NEXT8:	PUSHJ	P,SWPMEM	;YES, GET DSK ADR, UNIT
	  JRST	NEXT11		;SWPLST IS ZERO!
	TLNN	P1,-1		;A MAIN ENTRY?
	SUBI	P2,1		;YES, DECREMENT NO OF ENTRIES LEFT
	AOJA	P1,CPOPJ1##	;AND SKIP-RETURN
;HERE ON A POINTER TO A FRAGMENT
NEXT9:	HLRZ	T3,P1		;T3 NON-0 IF NOT FIRST LINK (FATHER NOT SWPLST ENTRY)
	JUMPN	T3,NEXT10	;GO IF NOT FIRST TIME IN THIS FRAGMENT
	TLNE	T1,(SL.IOD!SL.IOP) ;I/O ALREADY STARTED OR DONE?
	JRST	NEXT11		;DONE, ERROR, OR ACTIVE, NEXT ENTRY
	MOVE	T4,T1		;SAVE THIS PIECE
	PUSHJ	P,SW2LC		;WE THINK WE FOUND A USABLE ENTRY
	MOVE	T4,SW2LST##+1(T1) ;TO SEE WHAT WE MUST LOOK FOR
	MOVE	T1,1(P1)	;OK - RESTORE SWPLST ENTRY TO T1
	MOVSI	P1,400001(P1)	;SAVE POINT IN SWPLST WHERE WE TURNED DOWN
	SOJL	P2,CPOPJ##	;COUNT THE ENTRY
NEXT10:	HRRI	P1,-1(T1)	;SET RH(P1) FOR 1ST THING IN CHAIN
	JUMPN	T3,NEXT5	;T2 SET UP RIGHT IF NOT 1ST LINK
	JUMPE	T4,NEXT3	;IF ANOTHER FRAG THIS ENTRY NOT
				;BEING DONE, ANY PART IS OK
	SETZ	P2,		;MAKE SURE THIS ENTRY IS PICKED
	JRST	NEXT4


;HERE WHEN AT END OF CHAIN
NEXT11:	JUMPLE	P2,CPOPJ##	;RETURN IF ALL ITEMS IN SWPLST SCANNED
	TLNN	P1,-1		;NOT END, IN A FRAGMENT?
	AOJA	P1,NEXT12	;NO, TRY NEXT SWPLST ENTRY
	HLRZS	P1		;RESTORE MAIN LOC IN SWPLST IF FRAGMENT
	TRZ	P1,400000	;BIT IS ON IF FOUND NOTHING
NEXT12:	CAIL	P1,SW2LST##	;REACHED END?
	POPJ	P,		;YES (DUAL CPU, OTHER CPU IN ZERSLE)
	JRST	NEXT3

NEXT13:	TLNE	P1,-1		;FRAGMENT?
	JRST	NEXT5		;YES, P2 ALREADY DECREMENTED
	SOJG	P2,NEXT5	;NO, DECR P2 AND TRY NEXT
	POPJ	P,		;ALL DONE - RETURN

;SUBROUTINE TO GET THE BLOCK NUMBER FOR THIS SWPLST ENTRY
;CALL P1= LOC OF ENTRY
;RETURNS CPOPJ1 WITH U SET UP, T1= BLOCK NUMBER
;RETURNS CPOPJ IF THINGS ARE MESSED UP
THSBLK:	SKIPN	T1,(P1)		;GET SWPLST ENTRY
	STOPCD	CPOPJ##,DEBUG,NSE,	;++NO SWPLST ENTRY
;	PJRST	SWPMEM		;FALL INTO SWPMEM

;SUBROUTINE TO OBTAIN THE DISK ADDRESS FROM MEMTAB
;ENTER WITH T1=SWPLST ENTRY
;RETURN CPOPJ1 WITH U, T1 SET TO DISK ADDRESS
;RETURNS CPOPJ IF THINGS ARE MESSED UP
SWPMEM:	SE1ENT			;MUST BE IN SECTION 1 TO REFERENCE MEMTAB
	LDB	T1,[POINT 13,T1,26]  ;GET PHYSICAL PAGE NUMBER
	SSX	T1,MS.MEM	;MEMTAB SECTION
	SKIPN	T1,MEMTAB(T1)	;GET DSK ADDRESS
	STOPCD	CPOPJ##,DEBUG,MIZ,	;++MEMTAB IS ZERO
SWPADR::LDB	U,SSUNT1##	;GET SWAP UNIT
	MOVE	U,SWPTAB##(U)
	JUMPL	U,CPOPJ1##	;UNIT GONE, BUT WE EXPECTED IT
	SKIPE	U
	SKIPG	UNISLB##(U)
	STOPCD	.,STOP,SBZ,	;++SWAP BLOCK ZERO
	LDB	T1,SLKNT1##	;1ST LOGICAL K
	ROT	T1,BLKSPP##	;CONVERT TO BLOCKS
	ADD	T1,UNISLB##(U)	;PLUS STARTING BLOCK NUMBER
	JRST	CPOPJ1##	;RETURN
;SUBROUTINE TO BE CALLED WHEN IO IS FINISHED. ENTERED AT INTERRUPT LEVEL FROM FILIO
;CALLED WITH P1=LOC OF SWPLST ENTRY, T1= NUMBER OF BLOCKS TRANSFERRED, P2=ERROR BITS
DONE::	MOVE	T2,(P1)		;SWPLST ENTRY
	MOVEI	T3,UNIICT##(U)	;SET CORRECT UNIT WORD TO
	TLNN	T2,(SL.IPC)	;IPC AND PAGE QUEUES ARE PAGING I/O
	TLNN	T2,(SL.SIO)	; COUNT THE IO (SWAP OR PAGE, IN OR OUT)
	MOVEI	T3,UNIPCI##(U)
	TLNE	T2,(SL.DIO)
	ADDI	T3,1
	ADDM	T1,(T3)
	PUSHJ	P,SW2LC		;GET INDEX INTO 2ND TABLE
	MOVE	T4,SW2LST##(T1)	;ORIGINAL SWPLST ENTRY
	TRNE	S,IODERR+IODTER+IOIMPM	;IO ERROR?
	TLO	T4,(SL.ERR)	;YES, SET BIT
	TRNE	P2,IOCHMP+IOCHNX ;CHAN-DETECTED ERROR?
	TLO	T4,(SL.CHN)	;YES
DONE1:	HLRZ	T3,P1		;ORIGINAL SWPLST ENTRY IF A FRAGMENT
	LDB	T2,[POINT 9,(P1),35] ;NUMBER OF PAGES LEFT IN ENTRY
	TLNN	T4,(SL.ERR+SL.CHN) ;ABORT IF ERROR
	JUMPN	T2,DONE7
	JUMPE	T3,DONE2	;NO, GO IF NOT IN A FRAGMENT
	MOVSI	T2,(SL.IOP)	;IN A FRAGMENT - CLEAR THE IOP BIT
	ANDCAM	T2,(T3)		; IN THE SWPLST ENTRY ITSELF
DONE2:	TLZE	T4,(SL.IOP)	;CLEAR IN-PROGRESS BIT
	TLOE	T4,(SL.IOD+SL.DFM) ;SET DONE BIT
	STOPCD	.+1,DEBUG,SBW,	;++SWPLST BITS WRONG
	SETZM	SW2LST##(T1)
	MOVEM	T4,(P1)		;SAVE UPDATED SWPLST ENTRY
	TLNE	T4,(SL.CHN+SL.ERR)
	HRRZM	U,SWPEUJ##	;SAVE ADR OF UNIT
	JUMPE	T3,DONE6	;FINISHED IF NONE
	TLNE	T4,(SL.ERR+SL.CHN)  ;IF AN ERROR,
	JRST	DONE5		; DONT WASTE TIME BY CONTINUING
	SKIPL	T1,(T3)		;GET ADR OF START OF CHAIN
	STOPCD	DONE5,DEBUG,NRF,	;++SWPLST NOT REALLY FRAGMENTED
DONE3:	SKIPN	T2,(T1)		;LOOK AT NEXT ENTRY IN FRAGMENT CHAIN
	JRST	DONE5		;WHOLE CHAIN DONE IF AT END
	JUMPGE	T2,DONE4	;CHECK IT IF NOT ANOTHER POINTER
	MOVE	T1,T2		;GO TO NEXT PART OF CHAIN
	JRST	DONE3
DONE4:	TLNN	T2,(SL.IOD)	;THIS FRAGMENT DONE?
	POPJ	P,		;NO, DONT WAKE UP SWAPPER
	AOJA	T1,DONE3	;YES, TEST NEXT ENTRY OF FRAGMENT CHAIN
;HERE IF THE ENTIRE SWPLST FRAGMENT CHAIN IS FINISHED
DONE5:	HLLZS	T4		;INDICATE DONE, ERROR BIT IF ON
	IORB	T4,(T3)
	HLRZS	P1		;POINT TO SWPLST
DONE6:	HRLOI	T1,377777	;SET UNISWD HUGE
IFN FTDUAL,<
	SKIPE	T2,UNI2ND##(U)
	MOVEM	T1,UNISWD##(T2)
>
	MOVEM	T1,UNISWD##(U)
	TLNE	T4,(SL.IPC)	;IF IPC PAGING
	TLNN	T4,(SL.DIO)	; OUT
	JRST	SWPINT##
	TLNN	T4,(SL.SIO)	;DON'T IF REALLY SWAPPING REPLACABLE QUEUE
	AOS	IPCCNT##	;BUMP A COUNT
	PJRST	SWPINT##	;KICK THE SWAPPER
;HERE IF THE SWPLST ENTRY WASN'T ENTIRELY PROCESSED
DONE7:	SKIPN	T3		;IN A FRAGMENT?
	MOVEI	T3,(P1)		;NO, PICK UP ADDR OF ENTRY
	MOVSI	T1,(SL.IOP)	;CLEAR THE IO IN PROGRESS BIT
	ANDCAM	T1,(T3)		; SO NEXT WILL CONSIDER THIS ENTRY AGAIN
	POPJ	P,		;AND RETURN
;SUBROUTINE TO SET UP AN IOLIST FOR A SWAP/PAGE OPERATION
;ENTER P1=LOC OF SWPLST ENTRY, T3= MAX NUMBER OF BLOCKS TO DO
;EXIT P3=LOC OF 1ST IOWD, T1= NUMBER OF BLOCKS IN LIST
THIS::	PUSHJ	P,GETSWJ	;GET JOB NUMBER
	  PUSHJ	P,SVEUB##	;SAVE MAPPING IN EFFECT
	PUSHJ	P,SAVE4##	;SAVE P'S
	LSH	T3,-2		;CONVERT BLOCKS TO PAGES
	MOVE	P4,(P1)		;GET SWPLST ENTRY
	LDB	P2,[POINT SL.SCT,P4,<^L<SL.CNT>+SL.SCT-1>] ;NUMBER OF PAGES REQUIRED
	MOVE	T2,P2
	CAMLE	P2,T3		;NEED MORE THAN WE CAN DO?
	MOVE	P2,T3		;YES, SETTLE FOR LESSER AMOUNT
	SUB	T2,P2		;AMOUNT LEFT AFTER THIS OPERATION FINISHED
	SKIPN	P2		;REALLY ANYTHING TO DO?
	STOPCD	.,STOP,ZPS,	;++ZERO PAGE SWAP
	PUSH	P,T2
	TLO	P4,(SL.IOP)	;INDICATE IO IN PROGRESS
	PUSHJ	P,SW2LC
	SKIPN	SW2LST##(T1)	;IF THE FIRST TIME,
	MOVEM	P4,SW2LST##(T1)	; SAVE THE SWPLST ENTRY IN DUPLICATE TABLE
	DPB	T2,[POINT SL.SCT,P4,<^L<SL.CNT>+SL.SCT-1>] ;UPDATE SWPLST ENTRY WITH NEW COUNT
	MOVEM	P4,(P1)
	MOVE	T2,P2		;NUMBER OF PAGES WE'LL DO
	LSH	T2,2		;CONVERT TO BLOCKS
	EXCH	T2,(P)
	PUSH	P,T2		;SAVE (RETURN NUMBER TO FILIO)
	DSKOFF			;PROTECT AGAINST S BEING CHANGED AT
				; INTERRUPT LEVEL
	TLNE	P4,(SL.DIO)	;INPUT OR OUTPUT?
	TLOA	S,IO		;OUTPUT
	TLZ	S,IO		;INPUT
	TRZ	S,IODTER+IODERR+IOIMPM
	MOVEM	S,DEVIOS(F)	;SAVE UPDATED S
IFN FTKL10,<
	SETZ	P1,		;WE NEED AN IOWD
	PUSHJ	P,GCH4WD##	;GET A LOW-CORE BLOCK FOR THE IOLIST
	  JRST	THIS21		;CANT GET ONE!
	MOVE	P1,T1		;ADR IN P1
	HRLI	P1,-3		;CAN SAVE 3 IOWD'S WITH NO HASSLE
	MOVEM	T1,-5(P)	;RETURN INITIAL IOWD LOC IN P2

>
	PUSH	P,U		;SAVE U
IFN FTKS10,<
	MOVE	P1,CHNIMR##(P3)	;GET ADDRESS OF INITIAL MAPPING REGISTER
	MOVEI	T4,UBAEXP	;GET INITIAL MAPPING REGISTER ADDRESS
	SUBM	P1,T4		;DISPLACEMENT OF THIS DEVICES FIRST
	IMULI	T4,UBAMUL	;MAKE INTO AN ELEVEN STYLE ADDRESS
	MOVEM	T4,CHNIEA##(P3)	;AND SAVE AS INITIAL ELEVEN ADDRESS
	HLL	P1,CHNUBA##(P3)	;GET UBA NUMBER
	PUSH	P,CHNMRC##(P3)	;SAVE FOR LATER
>
	MOVEI	U,0		;U=0 FOR 18-BIT CHAN
IFN FTKL10,<
	SKIPGE	T2,CHB22B##(P3)
	MOVEI	U,1		;22-BIT CHAN
	TLNE	T2,CP.RH2##!CP.KLP##	;RH20 OR KLIPA?
	MOVEI	U,2		;YES
>
	TLNN	P4,(SL.SIO)	;SWAPPING?
	TLO	U,1		;NO, PAGING, REMEMBER THAT (SEC # FROM MEMTAB)
IFN FTIPCF,<
	TLNN	P4,(SL.IPC)	;IPCF?
>
	CAILE	J,JOBMAX##	;HIGH SEG?
	TLOA	U,400000	;INDICATE BY U NEGATIVE
	PUSHJ	P,[EXCH	P1,<-10-IFN FTKS10,<1>>(P)
		   PUSHJ P,GETVPN
		   EXCH	P1,<-10-IFN FTKS10,<1>>(P)
		   POPJ	P,	]
	LDB	P4,[POINT 13,P4,26]	;PHYSICAL PAGE TO START IO AT
	JUMPL	U,THIS3		;PROCEED IF HIGH SEG, IPCF, OR PAGING QUEUE
	HRRZ	T2,JBTUPM##(J)	;SWAPPING THE UPMP?
	CAIE	T2,(P4)
	JRST	THIS4		;NO
	TLO	U,500000	;YES, NO NEXT PAGE+"THIS IS UPT" BIT
	TLNN	S,IO		;INPUT?
	TLO	U,200000	;YES, FLAG INPUT OF UPT
	SKIPGE	U
THIS3:	SETO	P3,		;BE SURE NON-ZERO AT THIS15 IF WE WANT IT TO BE

;HERE WITH P4=PAGE NUMBER OF THE BEGINNING PAGE OF THE IO
;AND P3=POINTER TO VIRTUAL SLOT IF SWAPOUT
THIS4:
IFN FTKL10,<
	MOVE	T2,[400000+T1,,1] ;SET TO COUNT CONTIGUOUS PAGES (IOWD FOR KL)
>
IFN FTKS10,<
	POP	P,T2		;RESTORE SAVED UMR COUNT
>
THIS5:
IFN FTXMON,<
	XJRST	 [MCSEC1+.+1]	;ENTER SECTION 1 FOR PAGTAB/MEMTAB REFERENCES
>
	MOVE	T1,P4		;STARTING PAGE
THIS6:	SSX	P4,MS.MEM	;SET SECTION INDEX FOR PAGTAB/MEMTAB
	SKIPGE	MEMTAB(P4)	;IS THIS LAST PAGE IN FRAGMENT?
	SOJN	P2,@[0,,THIS27]	;YES, SOMEONE IS CONFUSED IF NOT LAST PAGE
	JUMPL	U,THIS10	;GO IF HI-SEG
	LDB	T4,[POINT MT.SAD,MEMTAB(P4),<^L<MT.DAD>+MT.SAD-1>] ;DSK ADR OF THIS PAGE
	TLNN	S,IO		;IF SWAPPING OUT,
	JRST	THIS7		;NO, DON'T CHANGE PAGE MAP
	MOVE	T3,(P3)		;GET CURRENT MAP CONTENTS
	AND	T3,[PM.BTS-PM.COR]	;SAVE THE BITS
	IOR	T4,T3
	MOVEM	T4,(P3)		;SAVE ADDR IN UPMP
THIS7:	JUMPE	P2,THIS11	;GO IF LAST PAGE
	LDB	T4,NVPNP4			;GET NEXT VIRTUAL PAGE #
	CAIN	T4,.UPMVP/PAGSIZ## ;UPMP?
	TLO	U,500000	;YES, DONT WIPE OUT SLOT IN MAP
THIS9:	TLNN	S,IO		;INPUT?
	TLZ	U,400000	;YES, STOP ON COUNT EXHAUSTED
	PUSHJ	P,GMPTR		;GET POINTER
	MOVE	P4,(T4)		;GET POINTER
	TLZ	P4,(PM.NAD)	;CLEAR BITS
	SKIPA	P3,T4		;POINTER FOR NEXT DEPOSIT
THIS10:	HRRZ	P4,PAGTAB(P4)	;HI-SEG GETS NEXT PAGE FROM PAGTAB
IFN FTKL10,<
	HRRZ	T4,U		;LEFT HALF = 0 FOR INDEXING
	CAIN	P4,@T2		;PAGES CONTIGUOUS?
	CAML	T2,MAXCNT(T4)	;YES, BELOW MAX SIZE OF AN IOWD?
	SOJA	P2,THIS11	;NO, MAKE THE IOWD
	CAMN	T2,[400000+T1,,27] ;DON'T BUILD AN IOWD
	SOJA	P2,THIS11	; THAT LOOKS LIKE AN RH20 GOTO WORD
	SOJLE	P2,THIS11	;MAKE THE IOWD IF DONE
	AOJA	T2,THIS6	;PAGE IN IOWD - COUNT AND TRY NEXT PAGE
>
;HERE TO FINISH THE IOWD/MAPPING REGISTER
THIS11:
IFN FTXMON,<
	JRST	@[0,,.+1]	;RETURN TO SECTION 0
>
IFN FTKL10,<
	IMULI	T2,-1000	;COMPUTE WORDCOUNT
	LSH	T1,P2WLSH##	;CONVERT BEGINNING PAGE NUMBER TO ADDRESS
	TRNN	U,2		;IF NOT AN RH20,
	SOJA	T1,THIS12	; ADDR-1
	MOVNS	T2		;RH20 - ADDR RATHER THAN ADR-1
	TRO	T2,RH2TRX##	; +WDCNT, TRA BIT
THIS12:	DPB	T2,PNTCNT(U)
	MOVEM	T1,(P1)		;SAVE IOWD IN LOCORE BLOCK
	ADDI	T1,1		;ADDRESS OF 1ST WORD TO TRANSFER
	AND	T1,MSK22B##(U)	;GET ADDRESS
	JUMPLE	P2,THIS13	;DONE IF P2=0
	AOBJN	P1,THIS4	;MORE TO DO, GET NEXT CHUNK
	TRNE	U,2		;IF AN RH20
	TRO	U,4		; TELL KLSER
	PUSHJ	P,GETMOR##	;NEED ANOTHER 4-WORD BLOCK
	  JRST	THIS20		;NONE AVAILABLE
	TRZ	U,4		;CLEAR KLSER'S RH20-BIT
	JRST	THIS4		;GOT IT, DO NEXT CHUNK
>; END FTKL10

IFN FTKS10,<
	TRO	T1,UNB36B!UNBVBT ;SET 36 BIT MODE AND VALID BIT
	WRIO	T1,(P1)		;LOAD THE MAPPING REGISTER
	ADDI	P1,1		;POINT TO NEXT MAPPING REGISTER
	SOJLE	P2,THIS13	;DONE IF P2=0
	SOJG	T2,THIS5	;IF UMR AVAILABLE, CONTINUE
	MOVE	T2,-7(P)	;OOPS, RAN OUT OF MAPPING REGISTERS
	ADDM	P2,(T2)		;INCREASE # PAGES LEFT TO DO
	LSH	P2,2
	ADDM	P2,-1(P)	;UPDATE # BLOCKS LEFT AFTER THIS IO
	MOVNS	P2
	ADDM	P2,-2(P)	;UPDATE # BLOCKS DONE THIS OPERATION
	SOJA	P1,THIS13	;FINISH UP, START THE IO
>; END FTKS10


;HERE WHEN ALL REQUIRED IOWDS HAVE BEEN BUILT
THIS13:
IFN FTKL10,<
	SETZM	1(P1)		;TERMINATE THE LIST
	AOS	T3,P1		;POINT AT TERMINATION WORD
	TRNN	U,2		;RH20?
	JRST	THIS14		;NO
	MOVSI	T1,RH2LST##	;YES, INDICATE LAST IOWD
	IORB	T1,-1(P1)
	LDB	T2,[POINT 11,T1,13]	;WORDCOUNT
	TLZ	T1,077760	;CLEAR WDCNT FIELD
	ADD	T1,T2		;ADDR + N
	JRST	THIS15		;STORE IN CHNTCW AND CONTINUE
THIS14:	HLRO	T1,-1(P1)	;WORD COUNT OF LAST IOWD
	LDB	T2,ADRPT2##(U)	;WHERE DATA ASSOCIATED WITH LAST IOWD
	ASH	T1,@ASH22B##(U)	; WILL START
	SUBM	T2,T1		;WHERE LAST DATA ITEM WILL GO
	DPB	P1,ADRPT4##(U)	;WHERE TERMINATION WORD WILL BE FETCHED FROM
THIS15:	MOVE	T2,-5(P)	;ADDRESS OF THE CHANNEL DATA BLOCK
	MOVEM	T1,CHNTCW##(T2)	;STORE WHAT CHANNEL TERMINATION WORD SHOULD LOOK LIKE
>
IFN FTKS10,<
	MOVE	T2,-5(P)	;ADDRESS OF THE CHANNEL DATA BLOCK
	HLL	P1,CHNIMR##(T2)	;RESTORE LEFT HALF
	SUB	P1,CHNIMR##(T2)	;GET NUMBER OF MAPPING REGISTERS USED
	LSH	P1,P2WLSH##+2	;MAKE INTO WORDS, 11 STYLE
	MOVEM	P1,CHNTCW##(T2)	;STORE ADDRESS OF LAST WORD TO BE TRANSFERRED
	SUB	P1,CHNIEA##(T2)	;COMPUTE TOTAL NUMBER OF BYTES IN TRANSFER
	MOVEM	P1,CHNBTC##(T2)	; AND PUT IT HERE
>
	SKIPN	-1(P)		;WILL THIS BE THE LAST IO?
	SETZB	P3,P4		;YES
	TLNE	U,200000	;UPMP SWAP IN?
	JRST	THIS16		;YES
	MOVE	P1,-7(P)	;ORIGINAL SWPLST ENTRY ADDRESS
	MOVSI	T1,(SL.IPC)	;PAGING QUEUE BIT
	TLNE	S,IO		;INPUT?
	TDNE	T1,(P1)		;NO, PAGING QUEUE
	JRST	THIS16		;NO
	CAIG	J,JOBMAX##	;JOB?
	PUSHJ	P,SETVPN	;YES, SET VPN IN .USLPS OR TABLE
THIS16:	JUMPE	P3,THIS18	;GO IF NO MORE TO DO
	DPB	P4,[POINT SL.SPN,(P1),<^L<SL.PPN>+SL.SPN-1>]
	JUMPL	J,THIS17	;IF SWAPPING "IP" QUEUE
	TLNN	U,200000	;OR THIS IS UPMP SWAP IN
	CAILE	J,JOBMAX##	; OR A HIGH SEGMENT,
	JRST	THIS17		;DON'T STORE SINCE A RANDOM JOB IS ADDRESSABLE
THIS17:	HLRZS	P1		;SWPLST ENTRY FOR MAIN WORD
	JUMPE	P1,THIS18	;GO IF NOT IN A FRAGMENT
	MOVSI	T1,(SL.IOP)
	IORM	T1,(P1)		;INDICATE IN A FRAGMENT FOR NEXT
				; (SO WILL ONLY PICK THIS PIECE)
THIS18:	TLNE	S,IO		;IN OR OUT?
	TLZN	U,100000	;;OUT, JUST SWAP THE UPT?
	JRST	THIS19		;NO
	SKIPE	.USLPS		;DID WE STOP JUST BEFORE THE UPT?
	JRST	THIS19		;YES, WE'LL GET IT NEXT TIME THEN
	MOVE	T1,NLUPMP##+.UMUPT	;YES,GET POINTER TO NULL UPMP
	MOVEM	T1,.UPMP+.UMUPT
THIS19:	POP	P,U		;RESTORE U
	POP	P,(P)		;FIX STACK
	POP	P,T1		;NO OF BLOCKS TO TRANSFER
	SKIPE	DINITF##
	POPJ	P,
	TLNN	S,IO
	ADDM	T1,.CPSBI##	;COUNT TOTAL SWAPPING BLOCKS
	TLNE	S,IO
	ADDM	T1,.CPSBO##
	POPJ	P,		;AND RETURN
;HERE IF WE RAN OUT OF LOWER CORE BLOCKS
THIS20:	HRRZ	T1,-7(P)
	ADDM	P2,(T1)		;INCREASE # PAGES LEFT TO DO
	LSH	P2,2
	ADDM	P2,-1(P)	;UPDATE # BLOCKS LEFT AFTER THIS IO
	MOVNS	P2
	ADDM	P2,-2(P)	;UPDATE # BLOCKS DONE THIS OPERATION
	SOJA	P1,THIS13	;FINISH UP, START THE IO

;HERE IF THERE WASNT A LOWER-CORE BLOCK TO START AT
THIS21:	ADD	P4,P2		;MAKE P4 THE SWPLST ENTRY AGAIN
	TLZ	P4,(SL.IOP)
	HRRZ	P1,-6(P)	;RESET P1
	MOVEM	P4,(P1)		;SAVE BACK IN SWPLST
	POP	P,(P)		;CLEAR GARBAGE OFF LIST
	SETZB	T1,-4(P)	;INDICATE 0 BLOCKS TRANSFERRED
	PJRST	T2POPJ##	;RETURN TO FILIO

;HERE ON VARIOUS ERRORS

THIS27:	STOPCD	THIS13,DEBUG,IPM, ;++ILLEGAL POINTER IN MEMTAB
;SUBROUTINES TO MANIPULATE VIRTUAL PAGE NUMBERS FOR SWAPOUT

;GET/SETVPN:
;		MOVE	P1,SWPLST-POINTER	;SWPLST,,FRAG OR 0,,SWPLST
;		PUSHJ	P,{GET|SET}VPN		;CALL ROUTINE
;		<ONLY RETURN, FOR GETVPN - P3 CONTAINS VIRTUAL POINTER>

GETVPN:	MOVE	P3,.USLPS	;NO, GET POINTER FROM CURRENT UPT
	TLNN	P1,-1		;FRAGMENTED SWPLST ENTRY?
	POPJ	P,		;NO, ALL IS WELL
	PUSHJ	P,FRGIDX	;GET FRAGMENT INDEX
	ADDI	P3,(T1)		;POINTER INTO TABLE
	MOVE	P3,(P3)		;AND ENTRY
	POPJ	P,

SETVPN:	MOVEI	T2,.USLPS	;NO, STORE FOR CURRENT JOB
	TLNN	P1,-1		;FRAGMENTED?
	JRST	SETVP5		;NO
	PUSHJ	P,FRGIDX	;COMPUTE A FRAGMENT INDEX
	MOVE	T2,(T2)		;RELOCATE
	ADD	T2,T1		;PLACE TO STORE
SETVP5:	MOVEM	P3,(T2)		;STORE
	POPJ	P,

;ROUTINE TO COMPUTE FRAGMENT TABLE OFFSET
;CALL WITH P1=SWPLST POINTER (SW2LC FORMAT)
;EXIT WITH T1=OFFSET INTO FRAGMENT VIRTUAL TABLE

FRGIDX:	PUSH	P,T2		;GET AN AC
	SETZ	T1,		;COUNTER
	HLRZ	T2,P1		;GET START OF CHAIN
	HRRZ	T2,(T2)		;FIRST FRAGMENT
FRGID2:	CAIN	T2,(P1)		;IS THIS THE RIGHT ENTRY?
	JRST	T2POPJ##	;YES, RETURN
	AOS	T1		;NO, SET FOR NEXT
	SKIPL	1(T2)		;POINTER TO NEXT
	AOJA	T2,FRGID2	;NO
	HRRZ	T2,1(T2)	;GET NEXT BLOCK
	JRST	FRGID2		;START LOOKING THERE

;SUBROUTINE TO GET SUFFICIENT FREE CORE TO BUILD THE VPN TABLE
;CALL:
;	MOVE	T1,FRAGMENT TABLE
;	PUSHJ	P,BLDVPN
;	  <NOT ENOUGH FREE CORE>
;	<NORMAL RETURN, POINTER TO TABLE IN T2>

BLDVPN::
	SETZ	T2,		;T2 COUNTS WORDS
	JUMPGE	T1,CPOPJ1##	;NOT REALLY FRAG'D?
	HRRZS	T1
BLDVP1:	SKIPN	T3,(T1)		;DONE?
	JRST	BLDVP4		;YES
	JUMPL	T3,[HRRZ T1,T3	;POINTER TO ANOTHER ENTRY
		    JRST BLDVP1] ;LOOP BACK
	AOS	T2		;ONE MORE WORD WE NEED
	AOJA	T1,BLDVP1	;LOOP

BLDVP4:	AOS	T2		;ONE MORE WORD FOR COUNT
	PUSH	P,T2		;SAVE # OF WORDS
	PUSHJ	P,GETWDS##	;GET THE CORE
	  JRST	T2POPJ##	;NOT THERE
	POP	P,(T1)		;REMEMBER THE COUNT
	AOS	T2,T1		;AND RETURN +1 AS THE ADDRESS
	MOVE	T1,-1(T2)	;GET COUNT AGAIN
	TRZE	T1,3		;ROUND TO NEAREST MULTIPLE OF 4
	ADDI	T1,4		;TO ENSURE LINK WORD IS ZERO IN CASE
	ADDI	T1,-1(T2)	;THIS EVER GETS USED FOR SWPLST ENTRY
	SETZM	-1(T1)		;ZAP IT
	JRST	CPOPJ1##	;GOOD RETURN

;SUBROUTINE TO RETURN THE VPN TABLE POINTED TO BY C(T1)

RTNVPN::
	MOVE	T1,-1(T2)	;GET COUNT
	SOS	T2		;ADDRESS
	PJRST	GIVWDS##
;SUBROUTINE TO SET UP J FROM SWPLST ENTRY
;ENTER P1 POINTING TO SWPLST
;EXIT CPOPJ1 IF A HIGH SEG, CPOPJ IF LOW
GETSWJ:	PUSHJ	P,SW2LC		;GET INDEX OF SWPLST ENTRY
	HRRZ	J,SW3LST##(T1)	;GET JOB NUMBER
	MOVE	T1,SWPLST##(T1)	;GET MAIN SWPLST ENTRY
	TLC	T1,(SL.SIO+SL.IPC) ;SWAPPING OUT THE REPLACABLE QUEUE?
	TLNN	T1,(SL.SIO+SL.IPC)
	TLOA	J,-1		;YES, INDICATE THAT BY SETTING J NEGATIVE
	CAILE	J,JOBMAX##	;HIGH SEG?
	AOS	(P)		;HIGH SEG OR PAGING QUEUE RETURN
	POPJ	P,		;BACK


;SUBROUTINE TO COMPUTE INDEX INTO SW2LST TABLE
;ENTER P1=ADDRESS IN SWPLST (OR FRAGMENT, ADR IN LH)
;EXIT T1=INDEX
;PRESERVES T2-T4
SW2LC::	TLNN	P1,-1		;POINTER TO A FRAGMENT?
	SKIPA	T1,P1		;NO, USE MAIN ADDRESS
	HLRZ	T1,P1		;YES, GET SWPLST LOCATION
	TRZ	T1,400000	;SIGN BIT OF P1 MIGHT BE ON
	SUBI	T1,SWPLST##	;MAKE INTO AN INDEX
	POPJ	P,		;AND RETURN
SUBTTL SWPSER INTERFACE WITH THE SWAPPER

;SUBROUTINE TO SETUP SWPLST FOR SWAP OUT
BOSLST::PUSHJ	P,SAVE4##	;SAVE ACS
	CAILE	J,JOBMAX##	;HI SEG?
	JRST	BOSLS5		;YES, DO IT DIFFERENTLY
	PUSHJ	P,SVEUB##	;LOW SEG, MAKE JOB ADDRESSABLE
	MOVEM	T2,.USLPS	;VPN POINTER
	SKIPL	.USBTS		;GET BITS
	TDZA	T2,T2		;NOT EXTENDED
	MOVEI	T2,MXSECN	;MAX SECTION TO TRY
	MOVEM	T2,.USSPT	;SECTION TO DO
	MOVE	T1,JBTADR##(J)	;SAVE JBTADR
	HLLM	T1,.USREL	; FOR SWAP-IN
	MOVE	T2,JBTSTS##(J)
	TLNE	T2,JXPN
	MOVEM	T1,.JDAT+JOBDPG##
	MOVE	T1,.JDAT+.JBPFH## ;GET JOBPFH
	MOVEM	T1,.USPFH	;AND SAVE IN UPMP FOR BISLST (MIGRATING JOB)
	SKIPGE	U,JBTSWP##(J)	;FRAGMENTED?
	JRST	BOSLS1		;YES
	LDB	T1,IMGOUT##	;NO, GET SIZE TO SWAP OUT
	LDB	T2,NFYPGS##	;ADD 1 PAGE FOR UPMP
	ADD	T1,T2
	LDB	J,NZSSCN##	;GET NUMBER OF NZS MAPS
	ADDI	J,(T1)
	PUSHJ	P,SETOMT	;SETOMT WILL SET UP MEMTAB
	MOVE	J,.USJOB	;RESTORE JOB #
	MOVEI	T1,(P3)		;FIRST PHYSICAL PAGE
	LSH	T1,SL.SCT	;POSITION IT
	LDB	T2,IMGOUT##	;NUMBER OF PAGES
	LDB	T3,NFYPGS##	;PLUS 1 FOR UPMP
	ADD	T2,T3
	LDB	T3,NZSSCN##	;# OF MAPS AGAIN
	ADDI	T2,(T3)		;ADD IN
	DPB	T2,[POINT SL.SCT,T1,<^L<SL.CNT>+SL.SCT-1>]	;IN T1
	HLRZ	T4,P3		;VIRTUAL PAGE #
	PUSHJ	P,GMPTR		;GET POINTER
	MOVEM	T4,.USLPS	;NOT FRAGMENTED
	JRST	BOSLS4		;SET LH BITS AND STORE T1 IN SWPLST
;HERE IF LOW SEG SWAP OUT AND DISK SPACE IS FRAGMENTED
BOSLS1:	MOVE	P1,JBTSWP##(J)
;	TLZ	P1,FRGSEG
	PUSH	P,.USLPS	;INITIALIZE POINTER TO VPN TABLE
	MOVSI	P2,(SL.DIO+SL.SIO)	;SWPLST DESCRIPTORS
	PUSHJ	P,NXTFRG	;SET UP U FOR THIS FRAGMENT
	  STOPCD	.+1,DEBUG,O1F,	;++ONLY 1 FRAGMENT
	PUSHJ	P,SETOMT	;SET UP MEMTAB
BOSLS2:	DPB	P3,[POINT SL.SPN,P2,<^L<SL.PPN>+SL.SPN-1>] ;STORE 1ST PAGE NUMBER OF FRAG
	HLRZ	T4,P3		;VPN OF FIRST VIRTUAL PAGE
	PUSHJ	P,GMPTR		;GENERATE A POINTER
	MOVEM	T4,@(P)		;STORE
	AOS	(P)		;INCREMENT
	MOVEM	P2,-1(P1)	;STORE THE SWPLST FRAGMENT IN TABLE
	PUSHJ	P,NXTFRG	;GET U FOR NEXT FRAG
	  JRST	BOSLS3		;LAST FRAGMENT
	MOVEI	P3,0		;P3=0 0N CALL TO SETOMT
	PUSHJ	P,[SE1ENT	;DO THIS IN SECTION 1
		JRST SETOM8]	;SET UP MEMTAB FOR THIS FRAG
	JRST	BOSLS2		;AND TRY NEXT
BOSLS3:	POP	P,(P)		;FIX STACK
	PUSHJ	P,[SE1ENT	;DO THIS IN SECTION 1
		SSX F,MS.MEM	;MAKE A REAL POINTER TO MEMTAB
		LDB  U,[POINT MT.SAD,MEMTAB(F),<^L<MT.DAD>+MT.SAD-1>]
		POPJ P,]
	MOVE	J,.USJOB	;RESTORE J
	MOVE	T1,JBTSWP##(J)	;ADDRESS OF FRAGMENT/SWPLST TABLE
;HERE WHEN DONE, T1=SWPLST ENTRY, U=DSK ADR OF UPMP
BOSLS4:	HRRZS	M		;IS THE UPMP THE LAST PAGE?
	CAIE	M,.UPMVP/PAGSIZ##
	STOPCD	.,STOP,UNL	;++UPMP NOT LAST
	MOVEM	U,JBTSWP##(J)	;SAVE UPMP ADDR IN JBTSWP
	TLO	T1,(SL.DIO+SL.SIO) ;INDICATE SWAP OUT
	MOVSI	T2,(UP.PGB)	;INDICATE PAGES WILL BE GIVEN BACK
	ANDCAM	T2,.USBTS
	PJRST	MAKSLE		;STORE IN SWPLST AND RETURN

;HERE IF HIGH SEG SWAP OUT
BOSLS5:	LDB	P1,IMGOUT##	;SIZE OF OUTPUT IMAGE (NO PAGES TO SWAP)
	HRLI	P1,(SL.SIO+SL.DIO) ;SWPLST DESCRIPTORS
	PJRST	BHSLST		;GO DO IT
;SUBROUTINE TO SETUP SWPLST FOR SWAP IN OF UPMP
BUSLST::SE1ENT			;ENTER SECTION 1
	CAILE	J,JOBMAX##	;HI SEG?
	JRST	BISL11		;YES, DO DIFFERENTLY
	PUSHJ	P,SVEUB##	;MAKE THE JOB ADDRESSABLE
	MOVE	U,JBTSWP##(J)	;NO, GET DSK ADDR OF UPMP
	HRRZ	T1,JBTUPM##(J)	;PAGE NUMBER OF UPMP
	TLO	U,(MT.LEF)	;INDICATE ONLY 1 FRAGMENT
	SSX	T1,MS.MEM	;MAKE MEMTAB ADDRESSABLE
	MOVEM	U,MEMTAB(T1)	;MEMTAB FOR UPMP
	LDB	T2,JBYMAP##	;ADDRESS OF THE MAP
	EXCH	U,T2		;PUT IN U
	TLZ	T2,(PM.NAD)	;CLEAR BITS
	SOS	T2
	CAME	U,T2		;CONTIGUOUS?
	JRST	BUSLS2		;NO, ALAS
	HRR	T1,PAGTAB(T1)
	MOVEI	T2,.UPMVP/PAGSIZ##
	DPB	T2,NVPNT1	;STORE POINTER TO NEXT WHICH IS UPT
	MOVEM	U,MEMTAB(T1)
	HRRZS	T1		;CLEAR SECTION NUMBER FROM LEFT HALF
	LSH	T1,11
	ADDI	T1,2		;NUMBER OF PAGES
	TLO	T1,(SL.SIO)	;SWAPPING UPMP IO (PREVENT FNDSLE FROM FINDING IT)
BUSLS1:	LDB	T2,JBYLSA##	;NUMBER OF 1ST PAGE FOR JOB
	MOVEM	T2,JBTSWP##(J)	;SAVE IN JBTSWP
	AOS	(P)		;GOOD RETURN
	JRST	MAKSLE		;SET UP SWPLST AND RETURN
BUSLS2:	PUSH	P,T1		;SAVE PAGTAB/MEMTAB POINTER
	HRLI	T1,(<SL.SIO_-SL.SCT>) ;CLEAR SECTION #, SET BIT
	LSH	T1,SL.SCT	;POSITION
	AOS	T1		;ONE PAGE
	PUSH	P,T1		;SAVE IT
	MOVEI	T2,1		;GET A CORE BLOCK
	PUSHJ	P,GET4WD##	;FOR THE SWPLST ENTRY
	  JRST	TPOPJ##		;OOPS
	POP	P,1(T1)		;STORE THE ENTRY
	TLO	U,(MT.LEF)	;TURN ON
	POP	P,T2		;PAGTAB POINTER
	HRR	T2,PAGTAB(T2)	;NEXT PAGE IN CHAIN
	MOVEM	U,MEMTAB(T2)	;STORE DISK ADDR IN MEMTAB
	HRLI	T2,(<SL.SIO_-SL.SCT>) ;CLEAR SECTION #, SET BIT
	LSH	T2,SL.SCT	;AND MAKE THE FRAGMENT ENTRY
	AOS	T2
	MOVEM	T2,(T1)		;MAP ENTRY
	SETZM	2(T1)		;NO MORE
	SETZM	3(T1)
	HRLI	T1,(SL.SIO!SL.FRG) ;SET FRAGMENTED ENTRY
	JRST	BUSLS1
;SUBROUTINE TO SET UP SWPLST FOR SWAP IN OF JOB
BISLST::PUSHJ	P,SAVE4##	;SAVE SOME ACS
	SETZB	P3,.USLPS	;CLEAR SLOT IF LEFT FROM FRAGMENTED SWAPOUT
	SKIPL	JBTSWP##(J)	;IF NOT FRAGMENTED,
	JRST	BISLS1		;GO DIRECTLY TO SETIMT
	MOVSI	T1,FRGSEG	;FRAG'D
	ANDCAM	T1,JBTSWP##(J)	;CLEAR BIT IN JBTSWP
	DMOVE	T1,.USHSE
	LSH	T1,W2PLSH##
	LSH	T2,W2PLSH##
	EXCH	T1,.USTMP
	EXCH	T2,.USTMP+1
	DMOVE	T3,.USTMP+2	; TO SETIMT
	MOVE	M,.USTMP+4
	MOVE	F,.USTMP+5
	MOVEI	U,SETIMX	;WE'LL CALL SETIMX THIS TIME
	JRST	BISLS2

BISLS1:	SKIPGE	P1,.USBTS	;EXTENDED USER (UP.BIG=1B0)
	TLNN	P1,(UP.NZS)	;BIG USER, TIME TO DO NON-ZERO SECTIONS?
	TDZA	P1,P1		;SECTION 0, DO IT
	MOVEI	P1,MXSECN	;START WITH SECTION 37 OTHERWISE
	MOVEM	P1,.USSPT	;SAVE AS SECTION TO START I/O AT
	MOVEI	U,SETIMT	;WHERE TO GO
BISLS2:	SETZ	P1,		;FIRST CALL
	PUSHJ	P,(U)		;SET UP UPMP FOR THIS FRAG, OR WHOLE JOB
BISLS3:	  SKIPA	T1,P1		;DONE - GET 1ST VIRT,,1ST PHYS
	JRST	BISLS4		;ANOTHER FRAG TO DO
	TLZ	T1,-1		;1ST PHYSICAL PAGE
	LSH	T1,SL.SCT	;POSITION IT
	TLO	T1,(SL.SIO)	;SWAPPING IO
	DPB	P3,[POINT SL.SCT,T1,<^L<SL.CNT>+SL.SCT-1>]	;NUMBER OF PAGES TO DO
	JRST	BISLS7		;SET UP JBTADR AND CALL MAKSLE
;HERE WHEN FRAGMENTED
BISLS4:	MOVEI	P4,0		;INDICATE 1ST CALL
	PUSHJ	P,GT4MR		;GET A 4-WORD BLOCK
	  JRST	BISL12		;CANT GET ONE
	HRRZ	P2,P4		;SAVE 1ST ADR OF 4-WD BLOCKS
BISLS5:	HRLI	P3,(SL.SIO)	;SWAPPING IO
	DPB	P1,[POINT SL.SPN,P3,<^L<SL.PPN>+SL.SPN-1>]	;1ST PHY PAGE
	MOVEM	P3,(P4)		;SAVE SWPLST ENTRY IN 4-WD BLOCK
	JUMPL	P2,BISLS6	;GO IF LAST FRAG
	SETZB	P1,P3		;NOT LAST, SETIMX WANTS P1,P3=0
	PUSHJ	P,SETIMX	;SET UP UPMP FOR THIS FRAG
	  TLO	P2,400000	;LAST FRAGMENT - P2 NEGATIVE
	AOBJN	P4,BISLS5	;GO DO NEXT IF 4-WD BLOCK NOT EXHAUSTED
	PUSHJ	P,GT4MR		;GET ANOTHER BLOCK
	  JRST	BISL12		;NONE AVAILABLE
	JRST	BISLS5		;GET ONE - CONTINUE

;HERE WHEN LAST FRAGMENT DONE
BISLS6:	SETZM	1(P4)		;TERMINATE LIST
	HRRZ	T1,P2		;ADR OF START OF 4-WD BLOCKS
	TLO	T1,FRGSEG(SL.SIO)	;FRAGMENTED SWAP
;HERE AT END OF FRAG (OR WHOLE JOB)
BISLS7:	HLRZ	M,.USREL	;LH (JBTADR) ON SWAP-OUT
	JUMPE	M,BISLS8	;ALREADY STORED
	HRRZS	.USREL		;CLEAR LH (.UPREL)
	HRLM	M,JBTADR##(J)	;RESTORE (NON-SHARABLE HS CASE)
BISLS8:	MOVE	R,JBTADR##(J)	;MAKE SURE R IS RIGHT
	SKIPGE	JBTSWP##(J)	;FRAGMENT END?
	JRST	BISLS9		;YES, RAN OUT OF STUFF ON FRAGMENTED SWAP
	MOVSI	T2,(UP.NZS)	;BIT TO CHECK
	XORB	T2,.USBTS	;CHANGE STATE
	JUMPGE	T2,BISLS9	;NORMAL USER
	TLNE	T2,(UP.NZS)	;BIT JUST GO ON?
	HRRZM	F,.USTMP+5	;SAVE POINTER TO NEXT
	MOVEM	T2,.USBTS	;SAVE STATE OF BIT
BISLS9:	SKIPLE	T2,JBTSGN##(J)	;IS THERE A NON-SHARABLE HI-SEG?
	TLNE	T2,SHRSEG
	JRST	BISL10		;NO, GO MAKE THE SWPLST ENTRY
IFN FTXMON,<
	HRRZS	T2		;CLEAR JUNK
>
	LDB	T3,[POINT 9,JBTADR##(T2),8]	;YES
	SKIPE	JBTADR##(T2)	;HIGHEST ADR IN HIGH SEG
	ADDI	T3,1
	DPB	T3,JBYHSS##	;SAVE AS HI SEG SIZE
	LDB	T4,[POINT 9,JBTUPM##(T2),8]	;HI-SEG OFFSET
	PUSHJ	P,MAPHI
BISL10:	JUMPG	P3,MAKSLE		;MAKE SWPLST ENTRY (NORMAL)

;HERE IF REALLY DON'T NEED TO SWAP ANYTHING.  NOTE THAT THIS CAN ONLY
;HAPPEN ON THE THIRD SWAP OPERATION OF AN NZS PROGRAM AS SECTION 0 ALWAYS
;HAS PAGE 0 TO SWAP IN.

	MOVSI	P2,(SL.IOD)
	IORB	P2,T1		;MARK AS DONE
	PUSHJ	P,MAKSLE	;MAKE NEW SWPLST ENTRY
	MOVEI	P1,(T2)		;INDEX TO SWXLST
	AOS	(P)		;SKIP AOS OF SWAPPER COUNT
	SOS	SPRCNT##	;FIX COUNTS UP
	SOS	SINCNT##
	MOVEI	F,SWPDDB##	;RESTORE F
	PJRST	SWPINA##	;AND CONTINUE

;HERE FOR HI SEG
BISL11:	PUSHJ	P,SAVE2##	;SAVE ACS
	LDB	P1,IMGOUT##	;NO OF PAGES TO SWAP IN
	HRLI	P1,(SL.SIO)	;SWAPPING IO
	MOVE	T1,JBTSWP##(J)	;GET DISK ADDR
	PUSHJ	P,BLDVPN	;GET CORE FOR TABLE, IF NECESSARY
	  POPJ	P,		;OOPS
	AOS	(P)		;GOOD RETURN
	PJRST	BHSLST		;SET UP SWPLST FOR HI SEG

;HERE WHEN NOT ENOUGH 4-WD BLOCKS ARE AVAILABLE
BISL12:	DMOVEM	T1,.USTMP	;SAVE WORKING ACS IN  UPMP
	DMOVEM	T3,.USTMP+2
	MOVEM	M,.USTMP+4
	HRRZM	F,.USTMP+5
	MOVSI	T1,FRGSEG	;INDICATE HAVE DONE A PART OF WHAT WE NEED
	IORM	T1,JBTSWP##(J)
	JUMPE	P4,BISLS3	;FINISH UP THIS PART AND CALL MAKSLE
	SOJA	P4,BISLS6	;FINISH UP
;SUBROUTINE TO SETUP SWPLST FOR HIGH SEGMENT SWAP IN OR OUT
;CALLING SEQUENCE:
;
;	MOVE	P1,HIGH SEGMENT SIZE
;	HRLI	P1,SWPLST ATTRIBUTES (I.E. DIRECTION OF I/O)
;	MOVEI	T2,ADDR+1 OF CORE BLOCK FOR FRAGMENT TABLE COPY (IF FRAG'D)
;	PUSHJ	P,BHSLST
;ALWAYS RETURNS CPOPJ
BHSLST:	MOVE	T3,T2		;SAVE CORE FOR FRAG COPY (IF ANY)
	LDB	T2,JBYHSA##	;1ST PAGE
	SKIPGE	T1,JBTSWP##(J)	;DSK ADR OF 1ST PAGE
	JRST	BHSLS1		;FRAGMENTED
	HRRZ	T3,P1		;SIZE
	MOVEI	T4,STOHDA	;ROUTINE TO STORE DISK ADDRESS IN MEMTAB
	PUSHJ	P,SETXMT	;SET UP FOR SWAP
	LDB	T1,JBYHSA##	;1ST PAGE
	LSH	T1,SL.SCT	;POSITION IT FOR SWPLST
	IOR	T1,P1		;ADD ATTRIBUTES, SIZE
	JRST	MAKSLE		;SET UP SWPLST AND RETURN
BHSLS1:	PUSHJ	P,SAVE4##	;SAVE ACS
	SOS	P4,T3		;GET CORE ADDRESS (WE DON'T NEED COUNT,
				;BUT DO NEED EXTRA WORD FOR TERMINATING ZERO)
	MOVE	P2,T1		;ADDRESS OF DISK ADDRESS FRAGMENT TABLE
	MOVEI	P3,STOHDA	;ROUTINE TO STORE DISK ADDRESS IN MEMTAB
	PUSHJ	P,BFSLST	;SETUP SWPLST FRAGMENT TABLE, MAKE SWPLST ENTRY, AND RETURN
	HRRM	P4,JBTSWP##(J)	;STORE NEW SWPLST TABLE
	POPJ	P,
;SUBROUTINE TO STORE DISK ADDRESS IN MEMTAB, CALL WITH T1=DISK ADDRESS,
; T2=MEMTAB INDEX, ALWAYS RETURNS CPOPJ
STOHDA:	MOVEM	T1,MEMTAB(T2)	;STORE DISK ADDRESS
	POPJ	P,		;AND RETURN
;SUBROUTINE TO SETUP SWPLST TO SWAP OUT PAGES ON "IN" QUEUE
;CALLING SEQUENCE:
;	PUSHJ	P,BPSLST
;ALWAYS RETURNS CPOPJ, I/O STARTED IF POSSIBLE

BMSLST::SKIPA	T4,[STODAU]	;SPECIAL ENTRY FOR UUO LEVEL CALLS
BPSLST::MOVEI	T4,STODA	;NORMAL ROUTINE TO CHANGE DSK ADDRS
	SKIPE	PAGIPQ##	;CAN'T DO ANYTHING IF I/O IS IN PROGRESS
	POPJ	P,		;RETURN DOING NOTHING IF I/O IS IN PROGRESS
	PUSHJ	P,SAVE1##	;SAVE AN AC
	SKIPN	U,PAGSNC##	;ANYTHING ON THE SLOW SWAPPING SPACE "IN" QUEUE?
	JRST	BPSLS1		;NO, TRY "IN" QUEUE
	MOVEI	P1,PAGSNQ##	;YES, OUTPUT IT FIRST
	TLO	U,(PG.SLO)	;ALLOCATE FROM SLOW SWAPPING SPACE
	JRST	BPSLS2		;GO START THE I/O
BPSLS1:	SKIPN	U,PAGINC##	;ANYTHING ON THE "IN" QUEUE?
	POPJ	P,		;NOTHING TO DO
	MOVEI	P1,PAGINQ##	;OUTPUT "IN" QUEUE
BPSLS2:	PUSHJ	P,SAVJW##	;SAVE J,W
	MOVE	W,T4		;SAVE T4 (DON'T NEED W ANYWAY)
	SETZ	J,		;USE JOB 0
	PUSHJ	P,SWPSPC##	;GET SWAPPING SPACE
	  POPJ	P,		;NONE AVAILABLE, TRY AGAIN LATER
	MOVE	J,-2(P)		;RESTORE J
	DMOVE	T2,(P1)		;"IN" QUEUE HEADER
	DMOVEM	T2,PAGIPQ##	;BECOMES "IP" QUEUE HEADER
	CAIE	P1,PAGIPQ##	;ARE WE RE-DOING THE IP QUEUE?
	SETZB	T3,(P1)		;"IN" QUEUE IS EMPTY
	EXCH	T3,1(P1)	;GET NUMBER OF PAGES ON "IP" QUEUE
	MOVE	T4,W		;RESTORE T4
	JUMPL	T1,BPSLS3	;JUMP IF SWAPPING SPACE IS FRAGMENTED
	.CREF	FRGSEG
	PUSHJ	P,SETXMT	;SETUP MEMTAB AND COPY DISK ADDRESSES TO MAPS
	MOVE	T1,PAGIPQ##	;FIRST PAGE
	LSH	T1,SL.SCT	;POSITION FOR SWPLST ENTRY
	IOR	T1,PAGIPC##	;COUNT
	TLO	T1,(SL.SIO+SL.DIO+SL.IPC)
	PUSHJ	P,MAKSLE	;MAKE A SWPLST ENTRY
	JRST	BPSLS4		;START I/O AND RETURN
;HERE WHEN SWAPPING SPACE IS FRAGMENTED
BPSLS3:	PUSHJ	P,SAVE4##	;SAVE ACS
	MOVE	P1,T3		;COUNT TO P1
	HRLI	P1,(SL.SIO+SL.DIO+SL.IPC)
	MOVE	P2,T1		;ADDRESS OF FRAGMENT TABLE
	MOVEI	P3,(T4)		;ADDRESS OF ROUTINE TO STORE IN MEMTAB
	SETZ	P4,		;NO FRAG TABLE COPY
	PUSHJ	P,BFSLST	;SETUP SWPLST
BPSLS4:	PUSHJ	P,INTLVL##	;AT INTERRUPT LEVEL?
	  HRRM	T2,.USSLX	;NO, BE SURE WE FIND THIS SWPLST ENTRY
	AOS	SPRCNT##	;ONE MORE SWAP IN PROGRESS
	PJRST	SQOUT##		;START THE OUTPUT
;SUBROUTINE TO STORE DISK ADDRESS IN MEMTAB AND IN MAP THAT THE PAGE BELONGS TO
; CALL WITH T1=DISK ADDRESS, T2=MEMTAB INDEX, RETURNS CPOPJ, T1 AND T2 INTACT

STODA:	PUSHJ	P,SAVE3##	;SAVE ACS
	MOVE	P1,J		;SAVE J
	DMOVE	P2,T1		;SAVE DISK ADDRESS AND MEMTAB INDEX
	DPB	T1,[POINT MT.SAD,MEMTAB(P3),<^L<MT.DAD>+MT.SAD-1>] ;SET DISK ADDR
	MOVSI	T1,(MT.IPC)	;IS THIS AN IPCF PAGE?
	TDNE	T1,MEMTAB(P3)	;?
	JRST	STODIP		;YES, HANDLE IT
	LDB	J,[POINT MT.SJB,MEMTAB(P3),<^L<MT.JOB>+MT.SJB-1>] ;GET JOB NUMBER OF JOB PAGE BELONGS TO
	PUSHJ	P,SVEUB##	;MAKE MAPS ADDRESSABLE
	LDB	T1,NVPNT2	;PAGE #
	.CREF	P2.MBZ		;(ZERO BIT SHOULD BE ZERO HERE)
	PUSHJ	P,GTPME		;GET MAP CONTENTS
	AND	T2,[PM.BTS]	;EXTRACT ACCESS BITS
	IOR	T2,P2		;ADD IN DISK ADDR
	MOVEM	T2,(T4)		;STORE IT IN THE MAP
STODA1:	MOVE	J,P1		;RESTORE J
STODA2:	DMOVE	T1,P2		;AND T1, T2
	POPJ	P,		;AND RETURN

;HERE FOR IPCF PAGE

STODIP:	LDB	T1,NVPNT2	;GET LOW ORDER BITS
	LDB	T2,[POINT MT.SJB,MEMTAB(T2),<^L<MT.JOB>+MT.SJB-1>]
				;HIGH ORDER BITS
	LSH	T2,P2.SPN	;POSITION
	IORI	T1,(T2)		;GET FULL ADDR
	MOVSI	T2,<1000_<^D36-^D18-IP.PLN##-1>> ;THIS IS A PAGE
	IOR	T2,P2		;YES, GET DISK ADDRESS BACK
	TLO	T2,IP.DSK##_-^D18 ;MARK IT AS A DISK ADDRESS FOR IPCSER
	MOVEM	T2,(T1)		;STORE IT IN THE PACKET
	JRST	STODA1		;AND EXIT
;SUBROUTINE TO DO THE SAME THING AS STODA, BUT CAN BE CALLED AT
;UUO LEVEL.  IS SLOWER, BUT DOESN'T CALL SVEUB.  CANNOT BE CALLED
;AT NON-UUO LEVEL

STODAU::PUSHJ	P,SAVE3##	;SAVE WORLD
	DMOVE	P2,T1		;MOVE TO A BETTER PLACE
	DPB	T1,[POINT MT.SAD,MEMTAB(P3),<^L<MT.DAD>+MT.SAD-1>] ;SET DISK ADDR
	MOVSI	T1,(MT.IPC)	;IPCF PAGE?
	TDNE	T1,MEMTAB(P3)	;YES, PROCESS AS SUCH
	JRST	STODIP		;YES, DO THAT
	LDB	T1,[POINT MT.SJB,MEMTAB(P3),<^L<MT.JOB>+MT.SJB-1>] ;JOB IT GOES IN
	HRRZ	T2,JBTUPM##(T1)	;UPMP FOR THAT JOB
	HRLI	T2,(<PM.DCD>B2+PM.WRT+PM.PUB) ;DON'T BOTHER CACHING IT
	MOVEM	T2,.UPMP+.UMTMP
	PUSHJ	P,CLPTZO	;SET UP THE MAPPING
	EXP	.TEMP
	LDB	T1,[POINT P2.SSN,PT2TAB(P3),<^L<P2.VSN>+P2.SSN-1>] ;SECTION # PAGE IS IN
	HRR	T2,.TEMP+SECTAB(T1) ;SECTION MAP POINTER FOR THAT SECTION
	MOVEM	T2,.UPMP+.UMTMP ;MAP THAT
	PUSHJ	P,CLPTZO
	EXP	.TEMP		;CLEAR PAGING
	LDB	T1,[POINT P2.SRN,PT2TAB(P3),<^L<P2.RPN>+P2.SRN-1>] ;PAGE TO CHANGE
	MOVSI	T2,(PM.BTS)	;GET BITS
	ANDM	T2,.TEMP(T1)	;SAVE ONLY THEM
	IORM	P2,.TEMP(T1)	;AND PUT DSK ADDR IN
	DMOVE	T1,P2
	POPJ	P,
;SUBROUTINE TO BUILD A FRAGMENTED SWPLST ENTRY
; CALL WITH P1=ATTRIBUTES,,SIZE, P2=ADDRESS OF DISK ADDRESS FRAGMENT TABLE,
; P3=ROUTINE TO CALL TO SETUP MEMTAB FOR A FRAGMENT, ALWAYS RETURNS CPOPJ

; P4=ADDRESS TO COPY ORIGINAL FRAGMENT TABLE TO (CONTIGUOUS BLOCK)
; OR ZERO IF NONE (COPY IS USED FOR HIGH SEG)
BFSLST:	PUSHJ	P,SAVE4##	;SAVE ACS
	PUSH	P,J		;NXTFRG CLOBBERS J
	EXCH	P2,P1		;ATTRIBUTES,,SIZE
	PUSH	P,P1		;SAVE LOC OF BLOCK
	HLLM	P2,(P)		;AND BITS
BFSLS1:	DPB	T2,[POINT SL.SPN,P2,<^L<SL.PPN>+SL.SPN-1>] ;SAVE PAGE NUMBER IN P2
	PUSHJ	P,NXTFRG	;SET U FOR THIS FRAGMENT
	  JRST	BFSLS2		;DONE
	JUMPE	P4,BFSLS4	;NO COPYING TO DO
	MOVE	T1,-1(P1)	;GET ORIGINAL ENTRY
	MOVEM	T1,(P4)		;COPY IT
	AOS	P4
BFSLS4:	MOVEM	P2,-1(P1)	;SAVE SWPLST ENTRY
	LDB	T3,[POINT SL.SCT,P2,<^L<SL.CNT>+SL.SCT-1>] ;SIZE
	MOVE	T1,U		;1ST DSK ADR
	MOVE	T4,P3		;ROUTINE TO CALL TO STORE IN MEMTAB
	PUSHJ	P,SETXMT	;SET UP FOR THIS FRAG
	JRST	BFSLS1		;OK, DO NEXT FRAG
BFSLS2:	POP	P,T1		;RESTORE 1ST ADR OF 4-WD BLOCKS
	TLO	T1,FRGSEG	;INDICATE FRAGMENTED
	POP	P,J		;RESTORE J
	SKIPE	P4		;IF COPY OF FRAGMENT LIST
	SETZM	(P4)		;THEN TERMINATE COPY
	JRST	MAKSLE		;CALL MAKSLE AND RETURN
;SUBROUTINE TO SET UP MEMTAB FOR A SWAP
;CALL WITH T1=1ST DSK ADR, T2=1ST PAGE NUMBER, T3=NUMBER OF PAGES, T4=ROUTINE
; TO CALL TO STORE DISK ADDRESSES
;ALWAYS RETURNS CPOPJ
SETXMT:	SE1ENT			;ENTER SECTION 1
	PUSHJ	P,SAVE2##
	SETZ	P1,		;NEED ZERO FOR SECTION #
	MOVE	P2,T4		;ADDRESS OF ROUTINE TO CALL TO STORE DISK ADDRESS
SETXM1:	SSX	T2,MS.MEM	;SECTION NUMBER FOR PAGTAB/MEMTAB
	PUSHJ	P,(P2)		;SAVE DISK ADDRESS (CLEARING REST)
	MOVE	T4,T2		;GET NEXT PAGE OF SEGMENT
	TRNE	T4,-1		;LEGAL PREDESESSOR?
	SKIPGE	T2,PAGTAB(T2)
	STOPCD	.,STOP,PFC,	;++PAGE ON FREE CORE LIST
	ADDI	T1,1		;INCR. DSK ADR BY 1
	SOJG	T3,SETXM1	;GO DO NEXT PAGE
	MOVSI	T1,(MT.LEF)
	IORM	T1,MEMTAB(T4)	;INDICATE LAST PAGE IN MEMTAB
	POPJ	P,		;AND RETURN
;SUBROUTINE TO MOVE PAGES FROM "IP" QUEUE TO "OUT" QUEUE.
;CALL WITH P1=LOC OF SWPLST ENTRY,  P2=SWPLST ENTRY

IP2OUT::SE1ENT			;MUST BE IN SECTION 1 TO LOOK AT PAGTAB/MEMTAB
	PUSHJ	P,SAVE2##	;SAVE ACS
IP2OU1:	SKIPN	P1,PAGIPQ##	;GET FIRST PAGE ON "IP" QUEUE
	STOPCD	IP2OU6,DEBUG,IPE, ;++IN PROGRESS QUEUE EMPTY
	TLNE	P2,(SL.ERR!SL.CHN!SL.CHK) ;ANY ERRORS?
	JRST	IP2ERR		;YES, PUT THE QUEUE BACK
IP2OU2:	SSX	P1,MS.MEM	;PAGTAB SECTION
	MOVE	P2,P1		;SAVE PREDECESSOR
	LDB	T1,[POINT PT.SJB,PAGTAB(P1),<^L<PT.JOB>+PT.SJB-1>] ;GET POSSIBLE WAITING JOB NUMBER
	JUMPE	T1,IP2OU3	;JUMP IF THERE IS NONE
	S0PSHJ	STPIOD##	;GET THE JOB STARTED AGAIN
	HRRZS	PAGTAB(P1)	;AND CLEAR JOB NUMBER
IP2OU3:	MOVE	T3,MEMTAB(P1)	;MEMTAB ENTRY
	TLNN	T3,(MT.GPB)	;DOES THE PAGE NEED TO BE GIVEN BACK?
	JRST	IP2OU4		;NO, NEXT PAGE
	LDB	T2,[POINT MT.SAD,T3,<^L<MT.DAD>+MT.SAD-1>]
	PUSHJ	P,DLTDSP	;DELETE PAGE FROM DISK
	HRRZ	T2,P2		;PHYSICAL PAGE NUMBER
	MOVEI	T3,PAGIPQ##	;"IP" QUEUE HEADER
	PUSHJ	P,RMVPFQ	;REMOVE THE PAGE FROM THE "IP" QUEUE
	PUSHJ	P,DLTPGC	;DELETE THE PAGE FROM CORE
	SKIPE	PAGIPQ##	;EMPTIED THE ENTIRE QUEUE?
	JRST	IP2OU1		;NO, START OVER
	JRST	IP2OU5		;YES, DELETE SWPLST ENTRY AND RETURN
IP2OU4:	SKIPE	P1,PAGTAB(P1)	;NEXT PAGE, EQUAL LAST PAGE?
	JRST	IP2OU2		;YES, FINISH UP
	DMOVE	T1,PAGIPQ##	;GET FIRST PAGE, COUNT
	EXCH	T1,PAGOUQ##	;MAKE IT FIRST PAGE ON "OUT" QUEUE
	MOVEM	T1,PAGTAB(P2)	;LINK FORMER "OUT" QUEUE AT END OF FORMER "IP" QUEUE
	SKIPE	T1
	HRRM	P2,@[IW MS.MEM,PT2TAB(T1)]
	ADDM	T2,PAGOUC##	;UPDATE NUMBER OF PAGES ON "OUT" QUEUE
	SETZM	PAGIPQ##	;"IP" QUEUE IS NOW EMPTY
	SETZM	PAGIPC##	; ...
IP2OU5:	MOVE	P1,-2(P)	;GET SWPLST INDEX BACK
	PUSHJ	P,DLTSLX	;DELETE SWPLST ENTRY
IP2OU6:
IFN FTMP,<
	PUSHJ	P,SBSCD##	;MUST HAVE THE SCHEDULER INTERLOCK HERE
>
	MOVEI	P1,1		;FLAG
	HRRE	J,JBTCQ##-PQIOQ## ;TAKE EVERYONE OUT OF PQIOW
	JUMPLE	J,IP2OU9	;DONE HERE
IP2OU7:	PUSHJ	P,SSEC0##
IP2OU8:	MOVEI	T1,RNQ##	;REQUEUE HIM
	SYSPIF
	PUSHJ	P,WAKOKE##	;PUT HIM IN THE RUN QUEUE
	  JFCL
	HRRE	J,JBTCQ##(J)	;NEXT JOB
	JUMPG	J,IP2OU8
IP2OU9:	SOJL	P1,CPOPJ##	;DONE IF LOOKED AT BOTH QUEUES
	HRRE	J,JBTCQ##-PQIOQ##-MXQUE##
	JUMPG	J,IP2OU7
	POPJ	P,

;HERE IF ERRORS IN THE SWPLST ENTRY

IP2ERR:	SSX	P1,MS.MEM		;SET RIGHT SECTION
	HRRZ	P2,PAGTAB(P1)		;NEXT PAGE (IF ANY)
	MOVSI	T3,(MT.GPB)		;REALLY NEED THIS PAGE?
	TDNN	T3,MEMTAB(P1)		;?
	JRST	IP2ERX
	MOVEI	T3,PAGIPQ##		;NO, JUST FLUSH IT
	HRRZ	T2,P1			;...
	PUSHJ	P,RMVPFQ		;REMOVE THE PAGE
	PUSHJ	P,DLTPGC		;RETURN PAGE
IP2ERX:	SKIPE	P1,P2			;SUCCESSOR (IF ANY)
	JRST	IP2ERR			;ONE EXISTS, CONTINUE
	MOVE	P1,-2(P)		;DELETE THIS ENTRY
	PUSHJ	P,DLTSLX
	MOVEI	P1,PAGIPQ##		;HEADER TO "TRANSFER"
	MOVE	U,PAGIPC##		;AMOUNT OF SWPSPC TO GET
	MOVEI	T4,STODA		;ROUTINE
	PJRST	BPSLS2			;TRY, TRY AGAIN

;SUBROUTINE TO MAKE AN ENTRY IN SWPLST
;CALLING SEQUENCE:
;
;	MOVE	T1,SWPLST ENTRY
;	PUSHJ	P,MAKSLE
;ALWAYS RETURNS CPOPJ, T2 HAS SWPLST INDEX

MAKSLE::MOVSI	T2,MJBTMX##	;MAX NUMBER OF SWPLST ENTRIES
	DSKOFF
IFN FTMP,<
	SYSPIF
>
MAKSL1:	SKIPE	SWPLST##(T2)	;THIS SLOT AVAILABLE?
	AOBJN	T2,MAKSL1	;NO
	JUMPL	T2,MAKSL2	;FOUND A SLOT IF T2 NEG
	STOPCD	CPOPJ##,DEBUG,SLF,	;++SWPLST FULL
MAKSL2:	MOVEM	J,SW3LST##(T2)	;SAVE J
	MOVEM	T1,SWPLST##(T2)	;SAVE SWPLST ENTRY
	TLC	T1,(SL.SIO+SL.IPC) ;SWAPPING OUT THE "IN" QUEUE?
	TLCN	T1,(SL.SIO+SL.IPC) ;SKIP IF NOT
	HLLOS	SW3LST##(T2)	;YES, ZAP SEGMENT NUMBER SO IT CAN'T BE FOUND
	MOVE	T1,SWPOUT##	;SWPOUT (SCHED1) HAS TO BE SAVED
	HRLM	T1,SW3LST##(T2)	; IN CASE OF MULTIPLE SWAP-OUTS
	AOS	SLECNT##	;INCREMENT SWAP-LIST-ENTRY COUNT
MAKSL3:
IFN FTMP,<
	SYSPIN
>
	POPJ	P,		;AND RETURN

;SUBROUTINE TO FIND A SWPLST ENTRY
;RETURNS CPOPJ IF NO ENTRIES (EVERYTHING IN SWPLST IS FOR PAGING)
;RETURNS CPOPJ1 IF FOUND, P1=INDEX , J=JOB NUMBER, T1=1ST PAGE, P2=ENTRY
FNDSLE::
IFN FTMP,<
	SYSPIF			;MAKE SURE SOME OTHER CPU DOESN'T MAKE A SWPLST ENTRY
				; AT INTERRUPT LEVEL
>
	SKIPN	P3,SLECNT##	;GET COUNT OF SWPLST ENTRIES
	STOPCD	MAKSL3,DEBUG,SLZ,	;++SLECNT IS ZERO
	MOVEI	P1,0		;START AT 1ST THING IN SWPLST
FNDSL1:	SKIPN	P2,SWPLST##(P1);GET THE ENTRY
FNDSL2:	AOJA	P1,FNDSL1	;NOT HERE - TRY NEXT
	TLNE	P2,(SL.DFM)	;DON'T FIND A UPMP ENTRY
	JRST	FNDSL3		;IT WILL BE HANDLED AT INTERRUPT LEVEL
	TLNE	P2,(SL.SIO)	;SWAPPER ENTRY?
	TLNN	P2,(SL.IOD)	;YES, DONE?
FNDSL3:	SOJG	P3,FNDSL2	;NO, TRY NEXT
	JUMPE	P3,ONPOPJ##	;DIDNT FIND ONE IF T1=0
	MOVE	T1,SW3LST##(P1)	;SWPOUT,,JOB NUMBER
	TLNE	P2,(SL.DIO)	;DON'T CHANGE SWPOUT IF INPUT
	HLRZM	T1,SWPOUT##	;RESTORE SWPOUT FOR SCHED1
	HRRZ	J,T1		;SET UP J
	LDB	T1,[POINT 13,P2,26]	;1ST PHYSICAL PAGE
IFN FTMP,<
	SYSPIN			;SLECNT AND SWPLST ARE CONSISTANT
>
	PJRST	CPOPJ1##	;TAKE SKIP-RETURN
;SUBROUTINE TO DELETE THE SWPLST ENTRY
;ENTER WITH P1=INDEX
;ALWAYS RETURNS CPOPJ
DLTSLX::
IFN FTMP,<
	PUSH	P,F		;PROBABLY NOT NECESSARY
	MOVEI	F,SWPDDB##	;FOR PIOFF
	PIOFF			;GUARD AGAINST INTERPROCESSOR RACE
	PUSHJ	P,DLTSLE	;DELETE SWPLST ENTRY AND DECREMENT SLECNT
	PION
	JRST	FPOPJ##		;RESTORE F AND RETURN
>
DLTSLE::SKIPN	T1,SWPLST##(P1)	;GET ENTRY
	STOPCD	CPOPJ##,DEBUG,SIE, ;++SWPLST IS EMPTY
	TLNE	T1,(SL.IOD)	;IO DONE FOR THIS ENTRY?
	TLNN	T1,(SL.SIO)	;SWAPPER?
	JRST	DLTSL1		;PAGER - LEAVE SWPCNT ALONE
	SOSGE	SWPCNT##	;DECREMENT SWPCNT
	STOPCD	DLTSL2,DEBUG,SIN, ;++SWPCNT IS NEGATIVE
DLTSL1:	SOS	SLECNT##	;DECREMENT NUMBER OF ITEMS IN SWPLST
	SETZM	SWPLST##(P1)	;CLEAR OUT THE OLD ENTRY
	JUMPGE	T1,CPOPJ##	;DONE IF NOT FRAGMENTED
				;FALL INTO RTNBLK

;SUBROUTINE TO RETURN 4-WORD CORE BLOCKS USED IN SWPLST
;ENTER WITH T1=SWPLST ENTRY
RTNBLK:	PUSHJ	P,SAVE1##	;SAVE AC
	MOVE	P1,T1		;ORIGINAL ENTRY
RTNBL1:	HRRZ	T2,P1		;ADR OF 4-WD BLOCK
	SKIPG	T1,3(P1)	;NEXT BLOCK CONTIGUOUS WITH THIS?
	SKIPA	P1,T1		;NO, SAVE ITS ADR
	ADDI	P1,4		;YES
	MOVEI	T1,1		;DELETE 1 BLOCK
	PUSHJ	P,GIV4WD##
	JUMPE	P1,CPOPJ##	;DONE IF LINK=0
	JRST	RTNBL1		;NOT DONE, RETURN NEXT BLOCK


DLTSL2:	SETZM	SWPCNT##	;ZERO SWPCNT SO WONT KEEP GETTING HERE
	POPJ	P,		;AND RETURN
;SUBROUTINE TO GET 4 WORDS OF MONITOR FREE CORE
;ENTER P4=0 1ST TIME, P4=PREVIOUS P4 ON FOLLOWING CALLS
;RETURNS CPOPJ IF NO BLOCKS AVAILABLE
;RETURNS CPOPJ1 IF GOT ONE, P4=AOBJN WORD FOR BLOCK
GT4MR:	PUSHJ	P,SAVT##	;SAVE A BUNCH OF ACS
	MOVEI	T2,1		;GET 1 BLOCK
	PUSHJ	P,GET4WD##
	  POPJ	P,SETOMT	;CANT GET IT - POPJ
	SETZM	3(T1)		;GOT IT, ZERO THE LINK
	JUMPE	P4,GT4M2	;IF NOT 1ST CALL,
	CAIE	T1,1(P4)	;BLOCK CONTIGUOUS WITH PREVIOUS?
	JRST	GT4M1		;NO
	HRLI	P4,-4		;YES, CAN USE 4 WDS
	JRST	CPOPJ1##	; (LINK OF LAST, FIRST 3 OF THIS)
GT4M1:	HRROM	T1,(P4)		;POINT LAST WD OF PREVIOUS BLOCK AT THIS
GT4M2:	MOVE	P4,T1		;ADR OF THIS BLOCK
	HRLI	P4,-3		;CAN USE 3 WORDS
	JRST	CPOPJ1##	;TAKE GOOD RETURN

;SUBROUTINE TO SET UP BITS IN S FROM SWPLST
GETIOS::MOVEI	S,0
	TLNE	P2,(SL.ERR)	;ERROR?
	TRO	S,IODERR	;YES
	TLNE	P2,(SL.CHN)	;CHAN ERROR?
	TRO	S,IOCHMP	;YES
	TLNE	P2,(SL.CHK)	;CHECKSUM ERRORS
	TRO	S,IOIMPM	;YES
	TLNE	P2,(SL.DIO)	;OUTPUT?
	TLO	S,IO		;YES
	POPJ	P,		;RETURN
;ROUTINE TO RETURN NEXT PAGE
;RETURNS RH(M)=VIRT PAGE, T4=POINTER TO MAP SLOT
;PRESERVE T1-T3,M ACCROSS CALLS (AFTER FIRST, CALL NXTSW2)
;BITS 3-17 OF M ARE PRESERVED FOR USE BY THE CALLER
;AND BITS 0-2 OF M (AS WELL AS RH(M) ARE FOR USE BY THIS ROUTINE

NXTWSB::SKIPGE	.USBTS		;NOT A BIG USER?
	SKIPG	T2,.USSPT	;SECTION ZERO?
	JRST	[MOVEI	T2,WSBTAB ;YES
		 JRST	NXTWS1	] ;DO THE OLD WAY
	HRRZS	T2		;CLEAR LEFT HALF
	IMULI	T2,WSBTBL	;COMPUTE WHICH WSBTAB TO USE
	MOVEI	T2,.WSBNZ-WSBTBL(T2)
NXTWS1:	AND	M,[77777,,0]	;CLEAR ALL BITS WE USE
NXTWS2::MOVEI	T1,^D36		;36 BITS PER WORD
	SKIPE	T3,(T2)		;GET THE WSBTAB ENTRY
NXTWS3::JFFO	T3,NXTWS4	;FIND FIRST BIT
	ADDI	M,(T1)		;REST OF WORD 0 - COUNT VIRT PAGE IN M
	HRRZ	T3,M		;GET VPN
	TLNN	M,200000	;TRANSLATED FUNNY SPACE #S YET?
	CAIG	T3,HLGPNO+1+<FYSSIZ/PAGSIZ##>+MXSECN
	CAIL	T3,.UPMVP/PAGSIZ##+MXSECN
	SKIPA	T3,[<.UPMVP/PAGSIZ##>+MXSECN+1] ;RETURN INVALID #
	AOJA	T2,NXTWS2	;AND TRY NEXT WSBTAB WORD
	HRRI	M,(T3)		;M RETURNS PAGE #, NOT T3
	POPJ	P,
NXTWS4:	LSH	T3,1(T4)	;SHIFT OUT BITS THROUGH BIT JUST FOUND
	SUBI	T1,1(T4)	;ACCOUNT FOR NO OF BITS SCANNED
	ADDI	M,1(T4)		;INCR VIRTUAL PAGE
	TLON	M,400000	;1ST TIME?
	SUBI	M,1		;YES, WE'RE 1 TOO HIGH
	HRRZ	T4,M		;GET VIRTUAL PAGE IN T4
	CAIG	T4,HLGPNO	;STILL IN USER SPACE?
	JRST	[MOVE	T4,.USSPT ;GET SECTION #
		 LSH	T4,S2PLSH## ;MAKE FULL PAGE #
		 TRO	T4,(M)
		 JRST	GMPTR ]
	TLOE	M,200000	;NO, TRANSLATE ALREADY?
	JRST	GMPTR		;ALREADY TRANSLATED, GO TO GMPTR
	HRRI	M,<.MCFV/PAGSIZ##>-<HLGPNO+1>(M) ;TRANSLATE #
	HRRZ	T4,M		;RESET T4
				;FALL INTO GTMPTR
;SUBROUTINE TO SETUP A BYTE POINTER TO A HALF WORD IN THE MAP
;ENTER WITH T4=VIRTUAL PAGE NUMBER FOR WHICH THE BYTE PNTR IS TO BE COMPUTED
;PRESERVES T1-T3
GMPTR::	CAIGE	T4,<.MCFV/PAGSIZ##>
	JRST	[ADD T4,[UMAPSN+UMAPS]
		 POPJ P,]
	ADDI	T4,.UPMP-<.MCFV/PAGSIZ##>+.UMORG
	CAILE	T4,.UPMP+.UMUPT		;SECTION MAP?
	MOVEI	T4,SECTAB-.UMORG-<<.UPMVP/PAGSIZ##>-<.MCFV/PAGSIZ##>>(T4)
	POPJ	P,
;SUBROUTINE TO SETUP MEMTAB FOR A SWAP OUT FROM THE WORKING SET TABLE
; AND THE UPMP
;CALLING SEQUENCE:
;
;	MOVSI	J,NUMBER OF PAGES ALLOCATED CONTIGUOUSLY ON THE DISK
;	HRRI	U,STARTING PAGE NUMBER ON THE DISK
;	PUSHJ	P,SETOMT	;FIRST CALL
;	PUSHJ	P,SETOM8	;ALL SUBSEQUENT CALLS
;ALWAYS RETURNS CPOPJ, T1-T3,M,F,P4,R MUST BE PRESERVED FOR SUBSEQUENT CALLS

SETOMT:	SE1ENT			;ENTER SECTION 1
	SETZB	P3,F		;FIRST TIME FOR ANYTHING
	MOVSI	P4,(UP.MAP)	;CLEAR BIT IN
	ANDCAM	P4,.USBTS	;.USBTS INDICATING MAP INFO
	SKIPE	R,.USSPT	;EXTENDED SECTION
	JRST	SETO18		;YES
SETOM1:	SETZB	R,.USSPT	;BE SURE THAT'S WHAT WE'RE DOING
SETOM2:	MOVEI	P4,.UPMVP/PAGSIZ##	;MAX PAGE HERE IS THE UPMP
SETOM3:	PUSHJ	P,NXTWSB	;GET 1ST PAGE OF WORKING SET
SETOM4:	CAIGE	P4,(M)		;LEGAL PAGE #?
	JRST	SETO16		;NO, GO TO NEXT SECTION
	JUMPN	F,SETO10	;MUST BE JUST A SECTION CYCLE
	MOVE	F,(T4)		;GET MAP ENTRY
	TLZE	F,(<PM.DCD>B2)	;ACCESS ALLOWED ON?
	TLZA	F,(PM.NAD)	;YES, CLEAR BITS
	TLZA	F,(<PM.NAD^!<PM.COR!PM.AAB>>) ;ACCESS ALLOWED OFF, SEE IF EXPAND
	JUMPN	F,SETOM5	;PROCEED WITH PARANOIA IF DCD IS ON
	TLZN	F,(PM.AAB)	;AAB ON?
	TLZN	F,(PM.COR)	;NO, COR MUST BE ON TOO IF NOT EXPANSION
	CAIA			;AAB ON OR COR OF, EXPANSION
	JUMPN	F,SETOM5	;FOUND A PAGE TO START AT
	PUSHJ	P,NXTWS3	;MUST BE A NZS SECTION W/O P0
	JRST	SETOM4		;AND COMPARE MORE
SETOM5:	SKIPGE	P3,.USSPT	;GET SECTION
	TDZA	P3,P3		;MAPS
	LSH	P3,^D18+S2PLSH## ;LEFT HALF PAGE #
	TLO	P3,(M)		;VPN
	HRR	P3,F		;P3=1ST VIRT,,1ST PHYS
SETOM6:	SSX	F,MS.MEM	;SET SECTION NUMBER
	MOVEM	U,MEMTAB(F)	;SAVE DISK ADDRESS IN MEMTAB
	MOVEI	T4,(M)
	CAIE	T4,<.UPMVP-1>/PAGSIZ##
	JRST	SETOM7
	MOVE	T4,.USJOB
	DPB	U,JBYMT4##	;SET MAP
SETOM7:	SOJLE	J,SETO15	;DONE
	AOS	U
SETOM8:	JUMPE	P4,SETO22	;JUST DID A MAP
SETOM9:	PUSHJ	P,NXTWS3	;NOT LAST, GET NEXT WS BIT
	CAIGE	P4,(M)		;LEGAL PAGE?
	JRST	SETO16		;NO, NEXT SECTION
SETO10:	MOVE	T4,(T4)		;PHYSICAL PAGE
	TDNN	T4,[PM.ADR]	;ANY DISK ADDRESS?
	JRST	SETOM8		;NO, IGNORE PAGE
	TLZN	T4,(<PM.DCD>B2)
	JRST	SETO14		;NO
SETO11:	JUMPN	P3,SETO12	;IF 1ST TIME,
	SKIPGE	P3,.USSPT
	TDZA	P3,P3
	LSH	P3,^D18+S2PLSH##
	TLO	P3,(M)
	TRO	P3,(T4)		; AND PHYS PAGE IN P3
	JRST	SETO13
SETO12:	TRNE	M,-1^!HLGPNO	;FUNNY PAGE?
	SKIPA	R,M		;YES
	DPB	M,[POINT 9,R,35] ;ELSE R HAS SECTION, MAKE VPN
	DPB	R,NVPNF		;AND SET NEXT VPN
SETO13:	MOVE	F,T4		;F=PHYS PAGE
	JRST	SETOM6		;AND CONTINUE

;HERE IF PM.ACC OFF - EITHER EXPANDING (INSDSK) OR IT REALLY SHOULD BE OFF
SETO14:	TLNN	T4,(PM.AAB)	;IS AAB OFF?
	TLNN	T4,(PM.COR)	;YES, IS COR ON?
	JRST	SETOM8		;SOME FLAVOUR OF EXPANSION, IGNORE
	JRST	SETO11


;HERE AT FRAGMENT'S END
SETO15:	PUSH	P,T1		;SAVE T1
	HLRZ	T1,P3		;FIRST PAGE
	DPB	T1,NVPNF	;POINT LAST TO IT
	MOVSI	T1,(MT.LEF)
	IORM	T1,MEMTAB(F)	;SET LAST
	MOVSI	T1,(UP.MAP)	;MAP INFO THIS FRAGMENT?
	TDNE	T1,.USBTS	;?
	TLO	P2,(SL.MAP)	;YES, SET SWPLST BIT TOO
	ANDCAM	T1,.USBTS	;CLEAR BIT
	JRST	TPOPJ##		;RETURN

;HERE AT THE END OF A SECTION
SETO16:	SKIPG	.USSPT		;SECTION 0 OR MAPS?
	JRST	SETO19		;YES, DO MAPS THEN OR RETURN
SETO17:	SOSGE	R,.USSPT	;COUNT DOWN TO DO NEXT SECTION
	JRST	SETO20		;TIME TO START DOING MAPS
SETO18:	SKIPN	P4,.UPMP+SECTAB(R)
	JRST	SETO17
	TRNN	R,-1		;SECTION 0?
	SKIPA	P4,[.UPMVP/PAGSIZ##-1-1] ;YES, STOP AT MAP THEN
	MOVEI	P4,HLGPNO	;MAX FOR NON-ZERO SECTIONS
	LSH	R,S2PLSH##	;MAKE IT A SECTION # WITH NO PAGE #
	JRST	SETOM3		;START THE SECTION

;HERE WHEN DOING MAPS

SETO19:	JUMPE	P4,SETO21	;DOING MAPS
	CAIN	P4,.UPMVP/PAGSIZ## ;JUST DO UPMP?
	POPJ	P,		;HUH? PROBABLY A UNL THEN
SETO20:
SETO21:	MOVEM	T4,.USTMP	;SAVE RELEVANT VARIABLES
	MOVEM	M,.USTMP+1	;WHICH WILL BE DESTROYED
SETO22:	MOVSI	P4,(UP.MAP)	;SET WE'RE DOING MAPS
	IORM	P4,.USBTS	;SET IT FOR BOSLST
	SKIPL	P4,.USSPT	;FIRST TIME?
	MOVSI	P4,-<MXSECN+1>	;YES
	AOBJP	P4,SETO24	;TIME TO DO SECTION 0
SETO23:	SKIPE	T4,.UPMP+SECTAB(P4);SAVE A LITTLE TIME IN THIS
	TLNE	T4,(<PM.ACD^!PM.DCD>B2) ;INDIRECT POINTER?
	AOBJN	P4,SETO23
	JUMPGE	P4,SETO24	;DONE
	MOVEM	P4,.USSPT	;SAVE POINTER TO CURRENT MAP
	MOVEI	M,.UPMVP/PAGSIZ##(P4)	;PAGE # OF MAP
	MOVEI	T4,(M)		;POINTER
	PUSHJ	P,GMPTR		;GET MAP
	SETZ	P4,		;FLAG TO COME BACK HERE
	HRRZS	R		;AND THE SECTION #
	JRST	SETO10

;HERE TO DO MAP AND UPMP (FINISH SECTION 0)

SETO24:	MOVE	T4,.USTMP	;RESTORE RELEVANT VARIABLES
	MOVE	M,.USTMP+1
	MOVEI	P4,.UPMVP/PAGSIZ## ;NOW UPMP IS LAST
	SETZM	.USSPT		;REALLY SECTION 0 NOW
	JRST	SETO10
;SUBROUTINE TO SETUP THE UPMP WITH PHYSICAL CORE ADDRESSES FROM PAGTAB,
; THE UPMP, THE WORKING SET TABLE, AND THE ACCESS ALLOWED TABLE AND SETUP
; MEMTAB FOR A SWAP IN
;CALLING SEQUENCE:
;
;	PUSHJ	P,SETIMT	;FIRST CALL
;	PUSHJ	P,SETIMX	;ALL SUBSEQUENT CALLS
;RETURNS CPOPJ1 WHEN A NON-CONTIGUOUS DISK ADDRESS IS FOUND. RETURNS
; CPOPJ WHEN THE ENTIRE UPMP HAS BEEN PROCESSED.
;RETURNS P3=# OF PAGES, P1=1ST VIRT,,1ST PHYS
;PRESERVE T1-T4,M,F OVER CALLS TO SETIMX
;BITS IN THE LEFT HALF OF P3 IN BELOW (USED ONLY LOCALLY):
;	1B0	JUST CHANGED SECTION, STILL CONTIGUOUS)
;	1B14	SECTION CHANGE REQUIRED ON NEXT MEMTAB ENTRY
;	1B15	NO I/O TO DO YET
;	1B16	NEED TO ADVANCE PHYSICAL PAGE FOR STORE INTO P1
;	1B17	MAY BE NO PAGES IN REQUEST

SETIMT:	SE1ENT			;ENTER SECTION 1
	PUSH	P,J		;SAVE J
	SKIPE	T1,.USSPT	;SECTION ZERO?
	JRST	SETI20		;SET UP FOR FIRST CALL IN NZS
	LDB	F,JBYLSA##	;FIRST PHYSICAL ADDRESS
SETIM1:	PUSHJ	P,NXTWSB	;GET 1ST PAGE IN WORKING SET
	HRRZ	R,M
	CAILE	R,.UPMVP/PAGSIZ##+MXSECN
	JRST	SETI13
	TLZ	P3,4		;ACTUALLY DOING SOMETHING I/OWISE
	TLZE	P3,400000	;CYCLING THROUGH SECTIONS?
	JRST	SETIM5		;YES, THIS WAS A LOGICAL CALL TO NXTNW3
	MOVE	U,(T4)		;GET MAP WORD
	TLZ	U,(PM.NAD)	;CLEAR EXTRANEOUS BITS
	JUMPE	U,SETI11	;CONTINUE
	JUMPN	P1,SETIM3	;IF JUST CYCLING THROUGH SECTIONS
	SKIPGE	P1,.USSPT
	TDZA	P1,P1
	LSH	P1,S2PLSH##+^D18
	TLO	P1,(M)
	HRR	P1,F		;1ST VIRTUAL,,1ST PHYSICAL
	JRST	SETIM3		;PROCEED
SETIM2:	MOVE	U,(T4)		;GET DSK ADR
	TLZ	U,(PM.NAD)	;MAKE SURE EXTRANEOUS BITS ARE 0
	JUMPE	U,SETIM8	;MAY NOT BE ANY PAGES IN THIS SECTION
SETIM3:	MOVE	J,(T4)		;GET OLD PAGE MAP ENTRY
	AND	J,[PM.BTS]	;KEEP ONLY ACCESSIBILITY BITS
	TLNN	J,(PM.AAB)	;IN AABTAB?
	TRNE	M,<-1^!HLGPGS>	;OR IS IT A MONITOR PAGE?
	TLOA	J,(<PM.DCD>B2)
	TLZ	J,(<PM.ACD>B2)	;NO ACCESS ALLOWED
	TLO	J,(PM.COR)	;NOW A CORE ADDRESS
	ADDI	J,(F)
	MOVE	R,F
	SSX	R,MS.MEM	;SET SECTION NUMBER FOR MEMTAB
	TLNN	F,-1		;THIS PAGE HAVE A DISK ADDRESS?
	MOVEM	U,MEMTAB(R)	;YES, SAVE IN MEMTAB
	MOVEM	J,(T4)		;SAVE IN MAP
SETIM4:	PUSHJ	P,NXTWS3	;GET NEXT PAGE, M=VIRT, T4=MAP POINTER
	HRRZ	R,M
	CAILE	R,.UPMVP/PAGSIZ##+MXSECN
	JRST	SETI12
	CAIE	R,.UPMVP/PAGSIZ##;UPT?
	CAIN	R,.UPMVP/PAGSIZ##-1 ;MAP?
	JRST	SETIM4		;YES
SETIM5:	MOVE	J,(T4)		;DISK ADDR OF NEXT PAGE
	TLZ	J,(PM.NAD)	;CLEAR ACCESS BITS ETC.
	JUMPE	J,SETIM8	;GO IF NO DISK ADDR
	JUMPN	P1,SETIM6	;IF 1ST CALL,
	SKIPGE	P1,.USSPT	;SECTION #
	TDZA	P1,P1
	LSH	P1,S2PLSH##+^D18
	TLNN	P3,2		;NEED TO ADVANCE PHYSICAL PAGE?
	HRR	P1,F		;NO, GET CURRENT 1ST PHYS
SETIM6:	SKIPN	U		;FIND FIRST PAGE YET?
	SOSA	U		;NO, BE SURE WE THINK IT'S CONTIGUOUS
	SUB	U,J
	HLRZ	J,F		;PAGE NUMBER OF LAST PAGE WITH A DSK ADR
	TLZN	F,-1		;IF IT WAS LAST PAGE,
	MOVE	J,F		;GET IT FROM F
	AOJN	U,SETI15	;GO IF NOT CONTIGUOUS
	MOVEI	R,(P3)		;CHECK ONLY RIGHT HALF
	CAIL	R,776		;CAN ONLY STORE NINE BITS
	SOJA	U,SETI15	;FRAGMENT; BE SURE THAT U'S NON-ZERO
SETIM7:	SKIPGE	U,.USSPT	;CURRENT SECTION
	TDZA	U,U
	LSH	U,S2PLSH##	;MAKE SECTION #
	TRO	U,(M)		;SET PART OTHER THAN SECTION
	HRRZ	R,J
	SSX	R,MS.MEM	;MAKE PAGTAB/MEMTAB ADDRESSBLE
	DPB	U,NVPNR		;STORE
	HRR	R,F		;FOR INDEXING INTO PAGTAB
	HRR	F,PAGTAB(R)	;NEXT PHYSICAL PAGE
	TLZE	P3,2		;NEED TO STORE "ADVANCED" PHYSICAL IN P1?
	HRRI	P1,(F)		;YES, DO IT NOW
	AOJA	P3,SETIM2	;COUNT THE PAGE, TEST NEXT
;HERE IF NEXT PAGE HAS NO DISK ADDRESS
SETIM8:	PUSH	P,T2		;SAVE T2 FOR NXTWSB
	MOVE	T2,F		;FOR INDEXING INTO PAGTAB
	SSX	T2,MS.MEM	;SET SECTION NUMBER
	HRRZ	T2,PAGTAB(T2)	;THIS PHYSICAL PAGE
	PUSHJ	P,ZPAGE		;ZERO THE PAGE
	POP	P,T2		;RESTORE T2
	TLNN	F,-1		;FIRST SUCH PAGE?
	HRLS	F		;YES, SAVE IN LH(F)
SETIM9:	MOVE	R,F		;TO GET PAGTAB ENTRY
	SSX	R,MS.MEM	;SET SECTION
	HRR	F,PAGTAB(R)	;STEP TO NEXT PHYSICAL PAGE
SETI10:	JUMPN	P1,SETIM3	;CONTINUE, U=DSK ADR IF NOT 1ST CALL TO SETIMX
	JUMPE	U,SETIM3	;ALSO IF FIRST PAGE OF SECTION IS ABZ,
				;THEN AVOID KAF
	JRST	SETIM2		;1ST CALL TO SETIMX - GET U FROM BYTE PNTR

;HERE SAME AS SETIM8, BUT FOR FIRST TIME THROUGH MAIN SETIM LOOP

SETI11:	TRNN	P3,-1		;ANY PAGES ALREADY IN REQUEST?
	TLO	P3,3		;NO, THERE MAY BE NONE, FLAG PHYSICAL ADVANCE
	PUSH	P,T2		;SAVE T2 FOR NXTWSB
	HRRZI	T2,(F)		;PAGE TO ZAP
	PUSHJ	P,ZPAGE		;ZERO THE PAGE
	POP	P,T2		;RESTORE T2
	JRST	SETI10
;HERE FOR UPMP
SETI12:	TLO	P3,400010	;FLAG A POSSIBLE SECTION CYCLE
SETI13:	SKIPE	.USSPT		;DOING SECTION 0?
	JRST	SETI16		;NO, INCREMENT SECTION #
SETI14:	SOS	-1(P)		;RETURN CPOPJ
	PUSHJ	P,SETHSA	;UPDATE JBTHSA IF NECESSARY
	TLNE	F,-1		;ENDING ON EXPANDING PAGES?
	HLRZ	J,F		;YES, LOAD J WITH LAST PAGE WE DID I/O TO

;HERE AT END OF THIS FRAGMENT
SETI15:	HLRZ	U,P1		;NEXT VPN
	MOVE	R,J		;USE LAST PAGE I/O WAS DONE TO
	SSX	R,MS.MEM	;SET SECTION
	DPB	U,NVPNR		;SET NEXT VIRTUAL PAGE
	MOVSI	U,(MT.LEF)
	IORM	U,MEMTAB(R)
	TLZ	P3,400012	;BE SURE THEY'RE CLEAR
	TLZN	P3,5		;WENT THROUGH SETI11 (COUNT OFF BY ONE)?
				;OR NOT DONE ANY I/O?
	AOJA	P3,JPOPJ1##	;NO, COUNT THE PAGE AND RETURN
	JRST	JPOPJ1##	;NO PAGES IN REQUEST


;HERE IF CONTIGUITY CROSSES A SECTION BOUNDARY
SETI16:
SETI17:	SOSG	T1,.USSPT	;DECREMENT SECTION WORKING ON
	JRST	SETI19		;DONE IF THIS WAS LAST
SETI18:	SKIPN	.UPMP+SECTAB(T1) ;SECTION EXIST?
	JRST	SETI17		;NO, TRY NEXT
	JRST	SETIM1		;CONTINUE FRAGMENT

SETI19:	SETZ	T1,		;RESTORE SECTION 0
	MOVEM	T1,.USSPT
	JRST	SETI14

;HERE ON CALL TO SETIMT FOR NON-ZERO SECTIONS

SETI20:	MOVE	F,.USTMP+5	;WHERE TO START
	SSX	F,MS.MEM	;PAGTAB SECTION
	HRRZ	F,PAGTAB(F)	;GET POINTER TO NEXT PHYSICAL PAGE
				;(AND FLAG TO STORE U IN MEMTAB)
	TLO	P3,4		;IN CASE WE DON'T DO ANY I/O
	JRST	SETI18		;FIND FIRST REAL SECTION

;HERE FOR SUBSEQUENT CALLS
SETIMX:	SE1ENT			;ENTER SECTION 1
	PUSH	P,J		;SAVE J
	SSX	F,MS.MEM	;SET SECTION
	HRRZ	F,PAGTAB(F)	;STEP TO NEXT PHYSICAL PAGE
				;(AND STORE INTO MEMTAB AT SETIM2)
;	JUMPN	P1,SETIM3	;CONTINUE, U=DSK ADR IF NOT 1ST CALL TO SETIMX
				;(THE ABOVE JUMPN CAN'T EVER HAPPEN ANY MORE)
	SKIPGE	P1,.USSPT	;SECTION #
	TDZA	P1,P1
	LSH	P1,S2PLSH##+^D18
	TLO	P1,(M)		;..
	HRR	P1,F
	JRST	SETIM2
;SUBROUTINE TO SETUP AN AOBJN POINTER TO BE USED TO SETUP MEMTAB -
; I.E. XWD -NUMBER OF CONTIGUOUS PAGES ON THE DISK, STARTING
; PAGE ON THE DISK, FROM THE FRAGMENT TABLE POINTED TO BY JBTSWP.
; IT ALSO SETS UP THE JOB NUMBER AND NUMBER OF PAGES
; ENTRIES IN THE SWPLST ENTRY WHICH IS BEING BUILT.
;CALLING SEQUENCE:
;
;	MOVE	P1,POINTER TO THE FRAGMENT TABLE (1ST CALL)
;	MOVEI	P2,SWPLST DESCRIPTORS
;	PUSHJ	P,NXTFRG
;RETURNS CPOPJ IF THIS IS THE LAST ENTRY IN THE FRAGMENT TABLE, CPOPJ1
; IF NOT, P1 POINTS TO THE NEXT ENTRY

NXTFR1:	HRRZ	P1,(P1)		;GET NEXT FRAG TABLE ENTRY
NXTFRG:	SKIPN	J,(P1)		;GET NO OF DSK PAGES
	POPJ	P,		;DONE IF 0
	JUMPL	J,NXTFR1	;POINTER TO ANOTHER ADR IF NEG
	LDB	J,FRGCP1##	;FRAGMENT COUNT
	DPB	J,[POINT SL.SCT,P2,<^L<SL.CNT>+SL.SCT-1>]	;SAVE NUMBER OF PAGES
	LDB	U,FRGAP1##	;FRAGMENT ADDRESS
	AOJA	P1,CPOPJ1##	;GOOD RETURN
;SUBROUTINE TO FIX THINGS UP AFTER A SWAP-WRITE ERROR
MAPBAK::TDZA T1,T1		;NORMAL ENTRY (DON'T CALL XPANDH WHEN DONE)
MAPBAX::MOVEI	T1,UP.JXP	;CALL XPANDH WHEN DONE
	CAILE	J,JOBMAX##
	JRST	DLTSLX
	PUSHJ	P,FNDPDS##	;GET PDB
	HRRZ	S,.PDSCX##(W)	;GET OLD SAVCTX POINTER (IF THERE IS)
	HLLZS	.PDSCX##(W)	;..
	MOVE	T3,.CPMAP##	
	HRRZ	T2,JBTUPM##(J)	;POINT UPT BACK AT ITSELF
	TLO	T2,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.COR+IFE FTMP,<PM.CSH>)
	CONO	PI,PI.OFF	;DON'T LET INTERRUPT LEVEL CHANGE THIS
	MOVEM	T2,.ECKSM/PAGSIZ##(T3)	;SINCE IT POINTED AT NLUPMP
	CLRPT	.ECKSM		
	MOVEM	T2,.ECKSM+.UMUPT	;POINT IT BACK AT ITSELF
	CONO	PI,PI.ON	;OK TO TURN THE PIS ON
	PUSHJ	P,SVEUB##	;MAKE SURE RIGHT STUFF GETS SAVED
	IORM	T1,.USBTS	;SET FLAG FOR WHEN DONE
	PUSHJ	P,SAVCTS##	;SAVE CONTEXT
	  STOPCD .,STOP,OOC	;++OUT OF CORE BLOCKS
	JRST	MAPB12
;HERE AT UUO LEVEL
	PUSHJ	P,MAPBK0	;DO THE REAL WORK
	PJRST	USCHE1##	;CONTINUE NOW
MAPBK0:	PUSHJ	P,SAVE4##	;SAVE ACS
	MOVE	P3,.UPMP+SECTAB+0 ;MAKE SURE REAL SECTION 0 PTR (NOT DISK)
IFN FTMP,<
	PUSHJ	P,MLSCSH##	;CACHED?
	  TLZ	P3,(PM.CSH)	;NO
>
	MOVEM	P3,.UPMP+.UMUPM
	PUSHJ	P,CLPTZO	;FIX PAGING MEMORY
	EXP	.UPMAP
	SE1ENT			;MUST BE IN SECTION 1
	MOVE	J,.USJOB	;DON'T TRUST J
	LDB	P3,JBYLSA##	;YES, SET TO SCAN MEMTAB CHAIN
	ADJSP	P,1		;ALLOCATE STACK SPACE TO REM LAST PAGE
	MOVEI	J,200		;BEFORE CALLING SCDCHK
	SETZM	.USSPT
MAPBK1:	PUSHJ	P,NXTWSB	;GET 1ST PAGE IN WORKING SET
MAPBK2:	HRRZ	P4,M		;UPMP?
	SKIPE	.USSPT		;SECTION 0?
	CAIG	P4,HLGPNO	;NO, THIS IS MAX
	CAILE	P4,.UPMVP/PAGSIZ##+MXSECN
	JRST	MAPBK7		;END THIS SECTION
	MOVE	P2,(T4)		;GET DSK ADR
	TRNE	P2,-1		;EVEN IF PM.COR WILL BE OFF, COULD BE ABZ
	TLNE	P2,(PM.COR)	;IS IT A DISK ADDRESS?
	JRST	MAPBK4		;NO, LOOK AT NEXT PAGE
	HLRZ	P1,P2		;SAVE ACCESS AND SOFTWARE BITS
	TLZ	P2,(PM.NAD)	;KEEP ONLY ADDR IN P2
	ANDI	P1,(PM.BTS)	;AND ONLY BITS IN P1
	HRRZM	P3,(P)		;SAVE PAGE WE START AT
MAPBK3:	SSX	P3,MS.MEM	;MAKE GLOBAL INDEX
	MOVE	P4,MEMTAB(P3)	;MEMTAB FOR THIS PAGE
	TLZ	P4,(<-1^!MT.DAD>)
	CAME	P2,P4		;DSK ADR THE SAME?
	JRST	MAPBK5		;NO
	HRLI	P3,<(PM.COR)>(P1)
	TLNN	P3,(PM.AAB)	;IN AABTAB?
	TRNE	M,<-1^!HLGPGS>	;OR IS IT A MONITOR PAGE?
	TLO	P3,(<PM.DCD>B2)
	MOVEM	P3,(T4)		;SAVE MAP ENTRY IN UPMP
MAPBK4:	PUSHJ	P,NXTWS3	;GET NEXT PAGE IN WORKING SET
	JRST	MAPBK2		;DO SO NOW
MAPBK5:	HRRZ	P3,PAGTAB(P3)	;STEP TO NEXT PAGE OF JOB
	CAMN	P3,(P)		;BEEN HERE BEFORE?
	JRST	MAPBK4		;YES, MUST BE EXPANDING INTO THIS PAGE
	JUMPN	P3,MAPB10	;CONTINUE
	MOVE	P3,J		;SAVE COUNT
	MOVE	J,.USJOB	;RESTORE JOB #
	LDB	J,JBYLSA##	;FIRST PAGE
	EXCH	J,P3		;CONTINUE
MAPB10:	SOJG	J,MAPBK3	;CONTINUE
	MOVE	J,.USJOB	;WAIT
	PUSHJ	P,SCDCHK##	;CHECK
	MOVEI	J,200
	JRST	MAPBK3
;HERE FOR NEXT SECTION

MAPBK7:	SKIPL	.USBTS		;EXTENDED?
	JRST	MAPBK9		;RESTORE INDEX AND FINISH UP
MAPBK8:	AOS	T1,.USSPT	;NEXT SECTION
	CAILE	T1,MXSECN	;MAX?
	JRST	MAPBK9		;RESTORE INDEX AND FINISH UP
	SKIPE	P2,.UPMP+SECTAB(T1) ;SECTION EXIST?
	TLNE	P2,(<PM.ACD^!PM.DCD>B2) ;IMMEDIATE POINTER?
	JRST	MAPBK8		;NO
	JRST	MAPBK1		;DO THIS SECTION
MAPBK9:	HRRZS	.USREL
	MOVE	J,.USJOB	;RESTORE JOB #
	PUSHJ	P,FNDPDS##	;GET PDB
	HRRZ	P1,.PDSCX##(W)	;GET CONTEXT BLOCK POINTER
	HRRZ	P1,.SCCIT##(P1)	;AND OLD POINTER (IF ANY)
	PUSHJ	P,RESCTS##	;GET RID OF THIS SAVCTX BLOCK
	DMOVEM	T1,.CPPC##	;SAVE PC
	MOVSI	T1,NSWP!NSHF	;RESTORE STATE OF NSWP,NSHF
	AND	T3,T1
	ANDCAM	T1,JBTSTS##(J)
	IORM	T3,JBTSTS##(J)
	HRRM	P1,.PDSCX##(W)
	MOVEI	P1,UP.JXP	;CALL XPANDH FOR SWAPPER?
	TDNE	P1,.USBTS	;?
	PUSHJ	P,XPANDH##	;YES, FORCE JOB OUT NOW
	ANDCAM	P1,.USBTS
	JRST	TPOPJ##		;FIX STACK AND RETURN

;HERE AFTER SETTING UP AT CLOCK LEVEL TO RUN MAPBAK AT UUO LEVEL

MAPB12:	MOVSI	T1,NSHF		;MAKE SURE SWAPPER DOESN'T FIDDLE WITH US
	IORM	T1,JBTSTS##(J)	;(SET NSHF BUT NOT NSWP)
	MOVSI	T1,SWP!SHF!JXPN!NSWP	;SO JOB WILL RUN
	ANDCAM	T1,JBTSTS##(J)	;CLEAR SO THE SCHEDULER KNOWS IT
	PUSHJ	P,REQUE##	;PUT INTO A QUEUE
	S0JRST	DLTSLX		;RETURN SWPLST ENTRY
;SUBROUTINE TO SET/CLEAR IO IN S FOR SWAPPER
;CALLED IN ERROR RECOVERY SINCE DEVIOS CAN CHANGE IN SWPDDB
;CALL WITH U SET UP

SWPINS::MOVE	T1,UNISWA##(U)	;POINTER TO SWPLST
	MOVE	T1,(T1)		;GET SWPLST ENTRY
	TLNN	T1,(SL.DIO)	;INPUT?
	TLZA	S,IO		;YES
	TLO	S,IO		;NO
	POPJ	P,

;SUBROUTINE TO DETERMINE IF A JOB HAS A PAGE OR PAGES ON EITHER THE "IN" QUEUE
; OR THE "SN" QUEUE. CALL WITH J=JOB NUMBER, SKIPS IF JOB ISN'T ON EITHER QUEUE
;PRESERVES ALL ACS (SINCE CALLED FROM THE SWAPPER, THAT'S THE ONLY SAFE THING TO DO)

JOBNQ::	PUSHJ	P,SVEUB##	;SEE IF JOB IS VIRTUAL
	SKIPN	.USVRT		;IS HE?
	  JRST	CPOPJ1##	;NO, CAN'T HAVE PAGES ON ANY QUEUE
	PUSHJ	P,SAVT##	;SAVE ALL ACS
	MOVEI	T1,PAGINQ##	;LOOK AT "IN" QUEUE FIRST
	PUSHJ	P,JOBNPQ	;SEE IF JOB HAS PAGES ON THAT QUEUE
	  POPJ	P,		;YES
	MOVEI	T1,PAGSNQ##	;NOW LOOK AT "SN" QUEUE
	PUSHJ	P,JOBNPQ
	  POPJ	P,		;ON THE SN QUEUE
	MOVEI	T1,PAGIPQ##	;CHECK THE IP QUEUE AS WELL
;FALL INTO JOBNPQ

;SUBROUTINE TO SEE IF A JOB HAS ANY PAGES ON A PAGE QUEUE
;CALL WITH T1 = ADDRESS OF QUEUE, SKIPS IF JOB ISN'T ON THE QUEUE

JOBNPQ:	SKIPN	T1,(T1)		;NOT ON QUEUE IF QUEUE IS EMPTY
	JRST	CPOPJ1##	;NOT ON QUEUE RETURN
	SE1ENT			;MUST BE IN SECTION 1 TO REFERENCE PAGTAB/MEMTAB
JOBNP1: SSX	T1,MS.MEM
	LDB	T2,[POINT MT.SJB,MEMTAB(T1),<^L<MT.JOB>+MT.SJB-1>] ;GET JOB NUMBER FROM QUEUE
	HLL	T2,MEMTAB(T1)	;AND BITS
	TLNN	T2,(MT.IPC)	;IF THIS IS AN IPCF PAGE, DON'T WORRY
	CAIE	J,(T2)
	SKIPA	T1,PAGTAB(T1)	;GET NEXT PAGE
	POPJ	P,		;YES, INDICATE THAT TO CALLER
	TRNN	T1,-1
	AOSA	(P)		;SKIP RETURN IF NO MORE PAGES
	JRST	JOBNP1		;LOOP IF MORE PAGES ON QUEUE
	POPJ	P,
;SUBROUTINE TO CLEAR A JOB'S PAGES IN ANY PAGING QUEUE (ANY IN QUEUE OR
;THE IP QUEUE).  CALLED BY CORE 0 PROCESSING
JOBFNQ::
	PUSHJ	P,SVEUB##	;NEED TO MAP JOB
	SE1ENT			;MUST BE IN SECTION 1
JOBFN2:	SKIPN	.USVRT		;IS JOB VIRTUAL?
	POPJ	P,		;NO, NOTHING TO DO
	SKIPN	PAGINC##	;ANYTHING ON THE FAST "IN" QUEUE?
	JRST	JOBFN3		;NO
	MOVEI	T1,PAGINQ##	;POINT THERE
	PUSHJ	P,JOBNPQ	;SEE IF ANY PAGES ON THAT QUEUE FOR THIS JOB
	  SKIPA	T1,PT2TAB(T1)	;YES, MUST PROCESS IT
	JRST	JOBFN3		;NO PAGES ON IN QUEUE, PROCEED
	LSH	T1,<^D35-<^L<P2.VPN>+P2.SPN-1>>
	ANDI	T1,HLGPGS	;JUST SAVE PAGE #
	PUSHJ	P,DLTPAG	;GET RID OF THE PAG
	JRST	JOBFN2		;AND LOOK FOR MORE
JOBFN3:	SKIPN	PAGSNC##	;ANYTHING ON THE SLOW QUEUE?
	JRST	JOBFN6		;NO
	SKIPN	.USVRT		;ONLY CONTINUE IF STILL VIRTUAL
	POPJ	P,		;DONE IF NOT
	MOVEI	T1,PAGSNQ##	;SLOW QUEUE
	PUSHJ	P,JOBNPQ	;FIND ANYTHING THERE
	  SKIPA	T1,PT2TAB(T1)	;YES, MUST PROCESS IT
	JRST	JOBFN6		;NO MORE HERE
	LSH	T1,<^D35-<^L<P2.VPN>+P2.SPN-1>>
	ANDI	T1,HLGPGS	;JUST SAVE PAGE #
	PUSHJ	P,DLTPAG	;GET RID OF IT
	JRST	JOBFN3		;CONTINUE LOOKING
JOBFN6:	SKIPE	PAGIPC##	;ANY PAGES ON IN PROGRESS QUEUE?
	SKIPN	.USVRT		;AND IS JOB STILL VIRTUAL?
	POPJ	P,		;NO TO ONE; ALL DONE
	MOVEI	T1,PAGIPQ##	;POINT TO IP QUEUE
	PUSHJ	P,JOBNPQ	;FIND PAGE THERE
	  CAIA			;FOUND ONE
	POPJ	P,		;DONE
	MOVSI	T2,(MT.GPB)	;GIVE PAGE BACK
	IORM	T2,MEMTAB(T1)
	JRST	JOBFN6
;SUBROUTINE TO REMOVE ALL DISK PAGES FOR JOB.  CALLS SCDCHK, SO
;MUST BE RUN AT UUO LEVEL
DSKFLS::
	SKIPN	.USVRT		;VIRTUAL
	POPJ	P,		;NO, CAN'T HAVE ANY OF THESE THEN
	SE1ENT
	SETZM	.USSPT		;START AT S0
DSKFL0:	PUSHJ	P,NXTNWS	;GET FIRST NON-WORKING SET PAGE
DSKFL1:	TRNE	M,-1^!HLGPNO	;DONE THIS SECTION?
	JRST	DSKFL6		;YES
	PUSHJ	P,DSKFLX	;REMOVE PAGE
	PUSHJ	P,NXTNW3	;CONTINUE LOOKING
	JRST	DSKFL1
DSKFL6:	SKIPL	.USBTS		;EXTENDED USER?
	POPJ	P,		;NO, DONE
	PUSH	P,.USSPT	;IN CASE SOMETHING HAPPENS
	PUSHJ	P,SCDCHK##
	POP	P,.USSPT
	AOS	T1,.USSPT	;NEXT SECTION
DSKFL7:	CAILE	T1,MXSECN	;AT TOP
	POPJ	P,		;YES, DONE
	SKIPE	T2,.UPMP+SECTAB(T1) ;YES, DOES SECTION EXIST?
	TLNE	T2,(<PM.ACD^!PM.DCD>B2) ;AND INDIRECT
	AOJA	T1,DSKFL7
	MOVEM	T1,.USSPT	;SAVE
	JRST	DSKFL0
;HERE TO DELETE PAGE WE FOUND
DSKFLX:	PUSHJ	P,SAVT##	;SAVE TS FOR NXTNWS
	MOVE	T1,.USSPT	;GET SECTION
	LSH	T1,S2PLSH##
	IORI	T1,(M)
	JRST	DLTPAG
;SUBROUTINE TO RETURN THE NEXT PAGE NOT IN THE WORKING SET
;RETURNS CPOPJ, WITH RH(M)=VIRT PAGE, T4=CONTENTS OF MAP SLOT
;ZERO PAGES AND PM.ZER PAGES ARE IGNORED
;NOTE THAT THIS ROUTINE ASSUMES ALL PER-PROCESS PAGES ARE IN THE WORKING SET
;PRESERVE T1-T3, M ACROSS CALLS (CALL NXTNW3 AFTER FIRST CALL)
;LIKE NXTWSB, BITS 3-17 OF M ARE PRESERVED FOR USE BY THE CALLER
;AND BITS 0-2 OF M (AS WELL AS RH(M) ARE FOR USE BY THIS ROUTINE
NXTNWS::
	SKIPGE	.USBTS		;NOT A BIG USER?
	SKIPG	T2,.USSPT	;SECTION POINTER
	JRST	[MOVEI	T2,WSBTAB
		 JRST	NXTNW1	] ;SECTION ZERO; OLD WAY
	HRRZS	T2
	IMULI	T2,WSBTBL
	MOVEI	T2,.WSBNZ-WSBTBL(T2)
NXTNW1:	AND	M,[77777,,0]	;CLEAR ALL BITS WE USE
NXTNW2:	MOVEI	T1,^D36		;36 BITS IN A WORD
	SETCM	T3,(T2)		;BITS FOR EVERY NON-WS PAGE
NXTNW3::
	JFFO	T3,NXTNW4	;FIND A 1-BIT
	ADDI	M,(T1)		;REST OF WORD 0, STEP TO NEXT
	MOVEI	T4,(M)		;GET PAGE #
	CAILE	T4,HLGPNO	;IN USER SPACE?
	TDZA	T4,T4		;NO, OFF THE END (SEE NOTE TOP OF THIS ROUTINE)
	AOJA	T2,NXTNW2
	POPJ	P,
NXTNW4:	LSH	T3,1(T4)	;CLEAR THE BIT
	SUBI	T1,1(T4)	;COUNT THE BIT
	ADDI	M,1(T4)		;...
	TLON	M,400000	;FIRST TIME?
	SUBI	M,1		;YES, WE'RE 1 TOO HIGH
	MOVEI	T4,(M)		;VIRTUAL PAGE #
	CAILE	T4,HLGPNO	;IN USER SPACE?
	TDZA	T4,T4		;NO, RETURN ZERO
	SKIPA	T4,.USSPT
	POPJ	P,
	LSH	T4,S2PLSH##
	TRO	T4,(M)
NXTNW5:	PUSHJ	P,GTPM4		;GET MAP CONTENTS
	JUMPE	T4,NXTNW3	;UNALLOCATED PAGE
	TDNE	T4,[PM.ADR^!PM.ZER] ;ABZ PAGE?
	PUSHJ	P,NXTHS		;SEE IF 0 OR HIGH SEG PAGE
	  JRST	NXTNW3		;0 OR PM.ZER, TRY NEXT
	TLNN	T4,(PM.SSP!PM.OIQ) ;QUEUE PAGE?
IFN FTPEEKSPY,<
	TLNE	T4,(PM.SPY) ;SPY PAGE?
	JRST	NXTNW3		;YES, DON'T FIND IT
>
	POPJ	P,		;"REAL" PAGE, RETURN IT

;SUBROUTINE TO SEE IF MAP CONTENTS IS 0 OR IN A HIGH SEG
;PRESERVES ALL ACS
NXTHS:	JUMPE	T4,CPOPJ##	;IF MAP IS NON-0
	PUSHJ	P,SAVT##	;SAVE ALL ACS
	HRRZ	T1,M		;PAGE TO TEST
	PJRST	TPNSHS		;GO SEE IF IT IS IN A HIGH SEG
;SUBROUTINE TO TEST IF A DISK ADDRESS IS ON A UNIT BEING REMOVED
;ENTER T4=C(MAP SLOT)  -  DSK ADR
;EXIT CPOPJ IF UNIT GOING DOWN, CPOPJ1 IF NOT
;PRESERVES T1-T3
TSTUN::
IFN FTPEEKSPY,<
	TLNE	T4,(PM.SPY)	;SPY PAGE?
	JRST	CPOPJ1##	;YES, IT'S NOT ON A BAD UNIT
>
	LDB	T4,SSUNT4##	;GET SWAP UNIT
	SKIPLE	T4,SWPTAB##(T4)	;UNIT DATA BLOCK LOC
	SKIPGE	UNIFKS##(T4)	;IF NEGATIVE, GOING DOWN TOO
	JRST	CPOPJ##		;UNIT ALREADY DOWN
	MOVE	T4,UNIUST##(T4)	;STATUS
	TLNN	T4,UNPNNA##+UNPRSS## ;UNIT GOING DOWN?
	AOS	(P)		;NO, SKIP RETURN
	POPJ	P,		;RETURN

;SUBROUTINE TO COMPLEMENT A BIT IN WSBTAB
;ENTER RH(M) = VIRTUAL PAGE NUMBER
;PRESERVES T1-T3
;NOTE THAT .USSPT MUST NOT BE AN INDIRECT SECTION
BTCOM::
	PUSH	P,T1		;SAVE T1
	PUSH	P,T2		;AND T2
	SKIPG	T1,.USSPT	;CURRENT SECTION
	TDZA	T1,T1		;IS REALLY S0
	LSH	T1,S2PLSH##	;CONVERT TO PAGE #
	ADDI	T1,(M)
	PUSHJ	P,TSWST		;COMPUTE WSBTAB BIT, POSITION
	  JFCL
	XORM	T2,(T4)		;FLIP THE BIT IN WSBTAB
	JRST	TTPOPJ##	;NO
;SUBROUTINE TO ALLOCATE MONITOR PAGES
;CALLING SEQUENCE:
;	MOVE	T1,FIRST PAGE TO ALLOCATE
;	MOVE	T2,NUMBER OF PAGES TO ALLOCATE
;	MOVE	T3,SIGN BIT=FLAG 0=CACHED,NON-ZERO=UNCACHED (KL ONLY)
;	PUSHJ	P,CREMPG
;	  RETURNS HERE IF NO VIRTUAL CORE
;	RETURNS HERE WHEN THE PAGES HAVE BEEN ALLOCATED
;STOPS IF THE PAGES ALREADY EXIST, CALLERS RESPONSIBILITY TO
; CHECK TO SEE THAT THE PROGRAM ISN'T GETTING TO BIG

CREMPG:
IFN FTMP,<
	PUSHJ	P,GGVMM##	;GET THE MM
>
GETMPG::
	PUSHJ	P,SAVE3##	;SAVE P1-P3
IFN FTKL10,<
	MOVE	P3,T3		;SAVE CACHED/UNCACHED FLAG
>
	CAMLE	T2,VIRTAL##	;MAKE SURE THERE'S ENOUGH SPACE
	POPJ	P,		;FAIL
	DMOVEM	T1,P1		;SAVE STARTING PAGE NUMBER, NUMBER OF PAGES
	MOVN	T3,T2		;MINUS THE NUMBER OF PAGES OF INCREASE
	ADDM	T3,VIRTAL##	;DECREMENT TOTAL SYSTEM VIRTUAL MEMORY AVAILABLE
CREMP1:	MOVE	T3,P2		;NUMBER OF PAGES TO ALLOCATE
	PUSHJ	P,FRDCRW##	;ENOUGH CORE IN CORE TO SATISFY REQUEST?
	  JRST	CREMP5		;NO, ALLOCATE CORE ON THE DISK
	SE1ENT			;ENTER SECTION 1 TO ADDRESS PAGTAB
	PUSH	P,J		;SAVE J, COULD POINT AT A KDB
	MOVE	J,.CPJOB##	;CURRENT JOB
	MOVE	T3,[MCPCNT]	;ONE IN COUNT OF FUNNY PAGES BYTE
	IMULI	T3,(P2)		;TIMES THE NUMBER OF FUNNY PAGES TO ALLOCATE
	ADDM	T3,JBTPDB##(J)	;UPDATE NUMBER OF FUNNY PAGES OWNED BY THIS JOB
	MOVE	T2,P2		;NUMBER OF PAGES REQUESTED
	LDB	T1,JBYLSA##	;FIRST PAGE OF JOB
	PUSHJ	P,ADPAGS##	;ALLOCATE THAT NUMBER
	EXCH	P1,T1		;P1 = FIRST PHYSICAL PAGE ALLOCATED, T1 = VIRTUAL PAGE
IFN FTLOCK,<
	LDB	T2,JBYLSA##	;PAGE 0
	SSX	T2,MS.MEM	;PAGTAB SECTION NUMBER
	HLR	P3,PAGTAB(T2)	;LOCK BITS
>
	SSX	P1,MS.MEM	;PAGTAB SECTION
	JRST	CREMP3		;GO ADD THE PAGES TO THE JOB'S MAP
CREMP2:	SSX	P1,MS.MEM	;SET PAGTAB SECTION NUMBER
	HRRZ	P1,PAGTAB(P1)	;NEXT PHYSICAL PAGE
CREMP3:
IFN FTLOCK,<
	HRLM	P3,PAGTAB(P1)	;LOCK BITS
>
IFN FTKL10,<
	JUMPGE	P3,CREMP4	;JUMP IF CACHED PAGE
	PUSHJ	P,WSBIT		;SETUP FOR CALL TO INSMPU
	MOVE	T3,P1
	HRLI	T3,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.COR)

	PUSHJ	P,INSMPU	;PUST THE PAGE IN THE JOB'S MAP
	CAIA			;SKIP
CREMP4:>
	PUSHJ	P,INSMPC	;INSERT THE PAGE IN THE JOB'S MAP CACHED
	ADDI	T1,1		;NEXT VIRTUAL PAGE
	SOJG	P2,CREMP2	;LOOP OVER ALL PAGES ALLOCATED
	CLRPGT	(0)		;CLEAR MEMORY OF PREVIOUS MAP
	JRST	JPOPJ1##	;RESTORE J AND RETURN
CREMP5:	PUSH	P,J		;SAVE J, COULD POINT AT A KDB
	MOVE	J,.CPJOB##	;CURRENT JOB
IFN FTLOCK,<
	MOVSI	T2,NSHF!NSWP	;JOB IS LOCKED BITS
	TDNN	T2,JBTSTS##(J)	;IS THE JOB LOCKED?
	JRST	CREMP6		;NO
IFN FTMP,<
	PUSHJ	P,DWNMM##	;RETURN THE MEMORY MANAGEMENT RESOURCE
>
	PUSH	P,T1		;YES, SAVE STARTING PAGE NUMBER
	MOVEI	T1,1		;SLEEP 1 SECOND SINCE CANNOT SWAP OUT JOB TO ALLOCATE CORE
	PUSHJ	P,SLEEPF##	;ZZZZZZ
	POP	P,T1		;RESTORE STARTING PAGE NUMBER
IFN FTMP,<
	PUSHJ	P,UPMM##	;RE-GET THE MM RESOURCE
>
	POP	P,J
	JRST	CREMP1		;AND START OVER FROM SCRATCH
>
IFE FTLOCK,<
	SETZ	T2,		;FOR CALL TO IOWAT BELOW
>
CREMP6:	PUSH	P,S		;SAVE S (FILSER IS PARTICULAR ABOUT THAT)
	PUSH	P,F		;AND F
	PUSHJ	P,IOWAT		;WAIT FOR ALL I/O TO STOP SINCE JOB WILL BE SWAPPED
	POP	P,F		;RESTORE F
	POP	P,S		;AND S
	LDB	T2,NFYPGS##	;NUMBER OF FUNNY PAGES CURRENTLY ALLOCATED TO THE JOB
	ADD	T2,P2		;PLUS NUMBER OF PAGES OF INCREASE
	DPB	T2,IFYPGS##	;NUMBER OF PAGES REQUIRED WHEN SWAPPED BACK IN
CREMP7:
IFN FTKL10,<
	PUSHJ	P,[JUMPG P3,INSDMC ;IF CACHED
		   JRST   INSDMU   ] ;IF NOT
>
IFN FTKS10,<
	PUSHJ	P,INSDMU	;INSERT PAGE (NEEDN'T WORRY ABOUT CACHE)
>
	ADDI	T1,1		;NEXT VIRTUAL PAGE
	SOJG	P2,CREMP7	;NEXT PAGE
	PUSHJ	P,XPANDH##	;MARK JOB AS EXPANDING
	POP	P,J		;RESTORE J
IFN FTMP,<
	PUSHJ	P,REMMM##	;GIVE UP MM NOW THAT XJOB AND JXPN AGREE
>
	AOS	(P)		;EVERYTHING IS OK
	PJRST	WSCHED##	;AND WAIT UNTIL THE JOB IS BACK IN CORE
;ROUTINE TO REQUEST ALLOCATION OF MONITOR PAGES AT CLOCK LEVEL.
;WHEN ALLOCATION IS COMPLETE (MAY TAKE A WHILE) THE CALLER WILL
;BE CALLED AT THE ADDRESS THEY SPECIFIED.  THIS ROUTINE CAN BE
;CALLED ON ANY CPU BUT WILL ONLY RECALL ON THE BOOT CPU.
;CALL:
;	T1/ SECTION #,,# PAGES REQUIRED
;	T2/ ADDRESS OF ROUTINE TO CALL WHEN ALLOCATION COMPLETE
;	T3-T4/ ARGUMENTS FOR CALLED ROUTINE (RETURNED IN T3-T4)
;	PUSHJ	P,GETCLP
;RETURN:
;	CPOPJ ALWAYS

	CLPLNK==0		;LINK TO NEXT REQUEST IN CHAIN
	CLPPGS==1		;SECTION NUMBER,,NUMBER OF PAGES TO ALLOCATE
	CLPRTN==2		;ROUTINE TO CALL WHEN ALLOCATION COMPLETE
	CLPARG==3		;ARGUMENTS TO ROUTINE
	CLPADR==5		;VIRTUAL ADDRESS OF PAGES ALLOCATED

	CLP4WD==2		;NUMBER OF 4 WORD BLOCKS FOR REQUEST

GETCLP::PUSHJ	P,SAVE4##	;SAVE P1-P4
	DMOVE	P1,T1		;SAVE CALLER'S ARGUMENTS
	DMOVE	P3,T3		;...
	MOVEI	T2,CLP4WD	;GET MEMORY FOR REQUEST BLOCK
	S0PSHJ	GET4WD##	;ASK
	  STOPCD .,STOP,CAC,	;++CAN'T ALLOCATE CLOCK LEVEL PAGES
	SETZM	CLPLNK(T1)	;CLEAR LINK WORD
	DMOVEM	P1,CLPPGS(T1)	;SAVE ARGUMENTS
	DMOVEM	P3,CLPARG(T1)	;...
	SYSPIF			;PREVENT RACES
	MOVEM	T1,@CLPBOT##	;LINK NEW ENTRY ONTO END OF LIST
	MOVEM	T1,CLPBOT##	;MAKE THIS ENTRY THE NEW END
	JRST	ONPOPJ##	;RESTORE PI'S AND RETURN
;ROUTINE TO LOOP THROUGH THE CLP LIST AND ALLOCATE PAGES.
;CAN ONLY BE CALLED ON THE BOOT CPU.

CRECLP::SE1ENT			;MUST RUN IN NZS
	PUSHJ	P,SAVE1##	;SAVE P1
	MOVE	P1,CLPTOP##	;GET FIRST ENTRY IN LIST
	MOVE	T1,CLPPGS(P1)	;GET NUMBER OF PAGES REQUESTED
IFN FTMP,<
	JUMPL	T1,CRECL1	;JUMP IF WAITING FOR THE CACHE OR DATAO PAG,
	PUSHJ	P,GETMM##	;MUST HAVE THE MM
	  POPJ	P,		;CAN'T GET IT, TRY AGAIN LATER
>; END IFN FTMP
	HRRZ	T3,T1		;NUMBER OF PAGES TO ALLOCATE
	PUSHJ	P,FRDCR##	;SEE IF THE CORE IS AVAILABLE IN CORE
IFE FTMP,<
	  POPJ	P,		;NOT NOW, WAIT A WHILE
>; END IFE FTMP
IFN FTMP,<
	  PJRST	GIVMM##		;NOT NOW, WAIT A WHILE (GIVE UP MM)
>; END IFN FTMP
	PUSHJ	P,SAVR##	;SAVE R (JUST SUPERSTITION I HOPE)
	HLRZ	R,CLPPGS(P1)	;SECTION TO ALLOCATE FROM
	HRRZ	T2,T1		;NUMBER OF PAGES TO ALLOCATE
	PUSHJ	P,CREMNS	;ALLOCATE PAGES, SETUP MAPS
IFE FTMP,<
	  STOPCD CPOPJ##,DEBUG,FDL, ;++FRDCR LIED
>; END IFE FTMP
IFN FTMP,<
	  STOPCD GIVMM##,DEBUG,FDL, ;++FRDCR LIED
	PUSHJ	P,GIVMM##	;NOW OK TO RETURN THE MM
>; END IFN FTMP
	MOVEM	T1,CLPADR(P1)	;SAVE VIRTUAL ADDRESS OF PAGES JUST ALLOCATED
IFN FTMP,<
	HRROS	CLPPGS(P1)	;INDICATE WAITING ON CACHE AND PAGING MEMORY
				; ON OTHER CPUS
	HRROI	T1,[MOVE  T2,.CPCSN##-.CPCDB##(P1) ;BUMP CACHE SWEEP NUMBER
		    ADDI  T2,2	; ON ALL OTHER CPUS
		    MOVEM T2,.CPCSW##-.CPCDB##(P1) ;...
		    POPJ  P,]	;RETURN FROM CPUAPP
	PUSHJ	P,CPUAPP##	;CAUSE ALL CPUS TO SWEEP CACHE AND DO A DATAO PAG,
CRECL1:	PUSHJ	P,MLSCSH##	;SEE IF MONITOR LOW SEGMENT CACHED (ONLY 1 CPU RUNNING)
	  CAIA			;NO
	JRST	CRECL2		;YES, DON'T HAVE TO WORRY ABOUT OTHER CPUS
	HRROI	T1,[SKIPGE .CPOK##-.CPCDB##(P1) ; (ONLY CHECK IF CPU ALIVE AND WELL)
		    SKIPN  .CPCSW##-.CPCDB##(P1) ;HAVE WE SWEPT YET?
		    CAIA	;HAVE SWEPT OR CAN'T BECAUSE CPU HAS DIED
		    SETO   T3,	;FLAG SOMEONE STILL NEEDS TO SWEEP
		    POPJ   P,]	;RETURN FROM CPUAPP
	SETZ	T3,		;ASSUME ALL CPUS ARE DONE
	PUSHJ	P,CPUAPP##	;HAVE ALL CPUS SWEPT AND CLEARED PAGING MEMORY?
	JUMPN	T3,CPOPJ##	;NO, STILL HAVE TO WAIT A WHILE
>; END IFN FTMP
CRECL2:	MOVE	T1,CLPADR(P1)	;GET VIRTUAL ADDRESS OF MEMORY ALLOCATED
	HRRZ	T2,CLPPGS(P1)	;GET NUMBER OF PAGES REQUESTED
	DMOVE	T3,CLPARG(P1)	;GET ARGUMENTS FOR ROUTINE
	PUSHJ	P,@CLPRTN(P1)	;CALL THE NOTIFICATION ROUTINE
	SYSPIF			;PREVENT RACES
	MOVE	T1,CLPLNK(P1)	;GET LINK TO NEXT BLOCK
	JUMPN	T1,CRECL3	;JUMP IF THERE IS ONE
	MOVEI	T2,CLPTOP##	;NOTHING, RESET EMPTY QUEUE
	MOVEM	T2,CLPBOT##	;...
CRECL3:	MOVEM	T1,CLPTOP##	;MAKE NEXT NEW FIRST
	SYSPIN			;OK TO INTERRUPT AGAIN
	MOVEI	T1,CLP4WD	;NUMBER OF 4-WORD CHUNKS
	MOVE	T2,P1		;ADDRESS OF THEM
	S0JRST	GIV4WD##	;RETURN THE CHUNK AND RETURN
;SUBROUTINE TO ALLOCATE AND MAKE ADDRESSABLE PAGES IN A NON-ZERO SECTION
;CALLING SEQUENCE:
;	MOVEI	R,SECTION NUMBER PAGES ARE TO BE ALLOCATED IN
;		  IF (R) = 0, ALLOCATE IN FUNNY SPACE
;	MOVEI	T2,NUMBER OF PAGES TO BE ALLOCATED
;	PUSHJ	P,CREMNS
;	  ...			;RETURNS HERE IF NOT POSSIBLE TO ALLOCATE PAGES
;	...			;RETURNS HERE WITH T1 = VIRTUAL ADDRESS OF PAGES ALLOCATED
;MUST BE CALLED IN SECTION 1 IF ALLOCATING NZS SPACE

CREMNS::
	JUMPE	R,CREFSP	;IF (R) = 0, ALLOCATE A PAGE OF FUNNY SPACE
	PUSHJ	P,SAVE4##	;SAVE WORKING ACS
	MOVE	P1,T2		;SAVE NUMBER OF PAGES REQUESTED
;VERIFY THAT ALLOCATING A PHYSICAL PAGE WON'T PREVENT ANY JOB FROM BEING SWAPPED
; IN AND ADJUST CORMAX IF NEED BE TO KEEP ANY JOB FROM GETTING TO BIG AFTER A PAGE
; IS ALLOCATED. ACCOUNT FOR SECTION MAP IF IT MUST BE ALLOCATED.
;	INSERT CODE HERE
IFN FTXMON,<
	MOVE	T1,R		;SECTION TO ALLOCATE FROM
	ADD	T1,.CPEPT##	;ADDRESS OF THE EPT
	SKIPE	T2,SECTAB(T1)	;SECTION ALREADY EXIST?
	JRST	CREMN1		;YES, JUST FIND THE FREE PAGES
;HERE WHEN A PAGE MUST BE ALLOCATED FOR A SECTION MAP
	MOVEI	T3,1		;ALLOCATE 1 PAGE
	PUSHJ	P,GETPHP	;GET A PAGE OF PHYSICAL MEMORY
	MOVE	T2,T1		;PAGE NUMBER
	MOVE	T1,R		;SECTION NUMBER
	MOVEM	T2,SPTCOM##-<(MS.FMD)>(T1)	;STORE IN SPT SLOT
	ADDI	T1,SECTAB	;WHERE TO STORE
	PUSHJ	P,STMAPS	;STORE PAGE NUMBER IN THE SECTION MAP
>;END IFN FTXMON
IFE FTXMON,<
	MOVE	T2,.CPEPT##	;EPT FOR THIS CPU
	MOVE	T2,SECTAB+0(T2)	;CURRENT S0 MAP
>;END IFE FTXMON
CREMN1:	HRLI	T2,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.COR)
	MOVEM	T2,.UPMP+.UMTMP
	CLRPGT	(0)
	PUSH	P,T2		;SAVE FOR LATER
	MOVSI	T1,-<HLGPNO+2>	;MAX # OF SLOTS+1 (FOR PRE-INCREMENT)
CREMN2:	HRRZ	P2,T1		;FIRST FREE SLOT SEEN
	MOVEI	T3,0		;NUMBER OF CONTIGUOUS FREE SLOTS SEEN SO FAR
CREMN3:	CAIL	T3,(P1)		;FOUND ENOUGH FREE SLOTS YET?
	JRST	CREMN4		;YES
	AOBJP	T1,TPOPJ##	;SECTION FULL, CAN'T ALLOCATE HERE
	SKIPE	.TEMP-1(T1)	;NEXT SLOT FREE?
	JRST	CREMN2		;NO, LOOK HIGHER UP
	AOJA	T3,CREMN3	;YES, SEE IF ENOUGH SLOTS HAVE BEEN FOUND
CREMN4:	MOVE	T3,P1		;NUMBER OF PAGES TO ALLOCATE
	PUSHJ	P,GETPHP	;GET THE PAGES
	POP	P,.UPMP+.UMTMP ;MAKE THE SECTION MAP ADDRESSABLE
	CLRPGT	(0)		;FLUSH PAGING MEMORY
	MOVE	P3,P2		;STARTING MAP SLOT (NEEDED FOR VIRTUAL ADDRESS)
	HRRZ	P4,T1		;FIRST PHYSICAL PAGE ALLOCATED
CREMN5:	MOVE	T2,P4		;PAGE NUMBER TO T2
	MOVEI	T1,.TEMP(P2)	;WHERE TO STORE IN THE SECTION MAP
	PUSHJ	P,STMAPE	;MAKE THE MAP ENTRY
	SSX	P4,MS.MEM	;PAGTAB SECTION
	HRRZ	P4,PAGTAB(P4)	;NEXT PAGTAB ENTRY
	TRNE	P4,-1		;LAST PAGE?
	AOJA	P2,CREMN5	;NO, LOOP MAKING ENTRIES FOR EVERY PAGE ALLOCATED
	CLRPGT	(0)		;CLEAR PAGING MEMORY
	MOVE	T1,P3		;FIRST SLOT ALLOCATED
	LSH	T1,P2WLSH##	;ADDRESS WITHIN THE SECTION
	SSXE	T1,(R)		;FULL VIRTUAL ADDRESS OF CORE ALLOCATED
	JRST	CPOPJ1##	;GIVE WON RETURN
;ROUTINE TO CREATE A PAGE IN FUNNY SPACE
; CALL WITH T1=BITS,,HEADER
;RETURNS CPOPJ IF NONE AVAILABLE, CPOPJ1 IF AVAILABLE, T1 = VIRTUAL ADDRESS OF PAGE

CREFSP::
	PUSH	P,T1		;SAVE BITS,,HEADER
	MOVEI	T1,.MCFV/PAGSIZ## ;VIRTUAL PAGE NUMBER OF FIRST FUNNY PAGE
CREFS1:	PUSHJ	P,TSWST		;DOES IT EXIST
	  JRST	[MOVE T2,-1(P)	;NO, CHECK IF RESTRICTED PAGE
		 CAIN T1,<<.MCFV+NWMCP>/PAGSIZ##>-1 ;THE NEXT TO THE LAST FUNNY PAGE
		 TLNE T2,200000	;YES, ARE WE ALLOWED TO GIVE IT OUT
		 JRST CREFS2	;OK TO CREATE THIS PAGE
		 AOJA T1,.+1]	;CANNOT GIVE IT OUT, STOP LOOP
	CAIGE	T1,<.MCFV+NWMCP>/PAGSIZ## ;OFF THE END OF FUNNY SPACE
	AOJA	T1,CREFS1	;LOOK FOR A NON-EXISTANT PAGE
	JRST	TPOPJ##		;NONE AVAILABLE
CREFS2:	MOVEI	T2,1		;NUMBER OF PAGES TO CREATE
	PUSH	P,T1		;SAVE VIRTUAL PAGE NUMBER
IFN FTKL10,<
	MOVE	T3,-1(P)	;GET SIGN BIT FOR UNCACHED
>
	PUSHJ	P,CREMPG	;CREATE THE PAGE
	  JRST	TTPOPJ##	;FAIL IF NO VIRTUAL SPACE
	POP	P,T1		;RESTORE VIRTUAL PAGE NUMBER
	SUBI	T1,<.MCFV-.FPMC>/PAGSIZ## ;CONVERT TO PER-PROCESS ADDRESS
	LSH	T1,P2WLSH##	;...
	JRST	T2POJ1##	;POP OFF JUNK AND GIVE GOTIT RETURN
;SUBROUTINE TO GET PHYSICAL PAGES OF MEMORY
; CALL WITH T3 = NUMBER OF PAGES TO ALLOCATE
; CALLERS RESPONSABILITY TO CHECK TO SEE IF ALLOCATING PAGES REQUESTED WILL
; LEAVE ENOUGH ROOM FOR THE BIGGEST JOB TO SWAP IN
; RETURNS WITH T1 = FIRST PAGE ALLOCATED
; MUST OWN THE MM BEFORE CALL

GETPHP::PUSHJ	P,FRDCR##	;MAKE ROOM IF POSSIBLE
	  CAIA			;DIDN'T MAKE IT, WAIT A WHILE
	JRST	GETPH1		;PAGES ARE AVAILABLE, ALLOCATE THEM
	PUSHJ	P,UUOLVL##	;IF NOT AT UUO LEVEL, STOP (CALLER IS CONFUSED)
	  STOPCD CPOPJ##,DEBUG,NUL ;++NOT AT UUO LEVEL
IFN FTMP,<
	PUSHJ	P,DWNMM##	;RETURN MM BEFORE SLEEPING
>
	PUSH	P,T3		;SAVE NUMBER OF PAGES REQUESTED
	MOVEI	T1,1		;SLEEP A TIC
IFN FTXMON,<
	PUSHJ	P,SLEEPF##	;ZZZZZZ
>
IFE FTXMON,<
	RGCALL	SLEEPF##
>
IFN FTMP,<
	PUSHJ	P,UPMM##	;GET THE MM BACK
>
	POP	P,T3		;RESTORE SIZE OF REQUEST
	JRST	GETPHP		;AND TRY AGAIN
GETPH1:	SE1ENT			;ENTER SECTION 1
	MOVE	T2,T3		;NUMBER OF PAGES TO GET
	LSH	T3,P2WLSH##	;NUMBER OF WORDS BEING ALLOCATED
	MOVNS	T3		;MAKE NEGATIVE
	ADDM	T3,MAXMAX##	;DECREASE MAX CORMAX
	ADDB	T3,RMCMAX##	;ADJUST REAL CORMAX
	CAMGE	T3,CORMAX##	;LOWER THAN CORMAX?
	MOVEM	T3,CORMAX##	;YES, DECREASE CORMAX AS WELL
	PUSHJ	P,GTPAGS##	;GET THE NEEDED PAGES
	MOVE	T3,T1		;RETURN FIRST PAGE ALLOCATED IN T1
	SSX	T3,MS.MEM	;PAGTAB SECTION
GETPH2:	HRRZ	T2,T3		;PAGE NUMBER OF PAGE TO BE ZEROED
	PUSHJ	P,ZPAGE		;ZERO THE PAGE
	MOVSI	T2,MONTRB+TNCSHB;MARK THIS PAGE AS A MONITOR PAGE
	IORB	T2,PAGTAB(T3)	;LITE THE BIT AND GET NEXT PAGE NUMBER
	TRNN	T2,-1		;LAST PAGE ALLOCATED?
	JRST	GETPH3		;SET UP PT2TAB AND RETURN
	HRR	T3,T2		;NO, NEXT PAGE NUMBER
	JRST	GETPH2		;LOOP TO MARK AND ZERO ALL PAGES ALLOCATED
GETPH3:	HRRZ	T2,LMPAG##	;GET LAST ALLOCATED MONITOR PAGE
	HRRZM	T3,LMPAG##	;SET LAST PAGE ALLOCATED
	SSX	T2,MS.MEM	;PAGTAB SECTION
	HRRM	T1,PAGTAB(T2)	;SET FORWARD LINK
	HRRZM	T2,@[IW MS.MEM,PT2TAB(T1)] ;SET BACK LINK
	POPJ	P,
;SUBROUTINE TO STORE A PAGE NUMBER IN A MAP (CAUSES ALL CPUS TO SEE NEW MAPPING)
; ENTER AT STMAPS TO STORE IN SECTION TABLE, STMAPE TO STORE IN SECTION MAP
;CALL WITH T1= MAP OFFSET, T2 = NEW PHYSICAL PAGE # (OR ZERO IF
;CLEARING)

IFN FTXMON,<
STMAPS:	TLOA	T1,400000	;REMEMBER ENTRY POINT
>
STMAPE:	TLZ	T1,400000	;REMEMBER ENTRY POINT
	PUSHJ	P,SAVE4##	;SAVE ACS
IFN FTXMON,<
	SKIPGE	T1		;STORING SECTION POINTER?
	SKIPA	P2,[<POINT 36,(P4),35>] ;YES, BYTE POINTER TO EPT INDEXED BY .CPEPT
>
	MOVSI	P2,(POINT 36,0,35) ;BYTE POINTER TO STORE IN SECTION MAP
	SKIPN	P3,T2		;IF ZERO, STORE A ZERO
	JRST	STMAP1
	HRLI	P3,(<PM.DCD>B2+PM.WRT+PM.CSH) ;ACCESSIBLE, WRITABLE, CACHED
	SKIPL	T1		;IF NOT STORING SECTION POINTER,
	TLOA	P3,(PM.KPM)	; ALWAYS LIGHT "KEEP ME"
	IOR	P3,.CPKPM##	;ALSO LITE "KEEP ME" IF THERE IS AN MCA25

IFN FTPEEKSPY,<
	SKIPL	T1		;SECTION POINTER?
	TLO	P3,(PM.PUB)	;NO, PAGES MUST BE PUBLIC FOR SPYING
>
IFN FTMP,<
	JUMPL	T1,STMAP1	;SECTION POINTERS ALWAYS HAVE CACHE BIT ON
	PUSHJ	P,MLSCSH##	;MONITOR LOW SEGMENT CACHED?
	  TLZ	P3,(PM.CSH)	;NO, CACHE MUST BE OFF
>
STMAP1:	HRRI	P2,(T1)		;OFFSET INTO SECTION TABLE OR MAP
	MOVEI	T1,STMPEC##	;ROUTINE TO STORE ENTRY IN ALL CPU'S MAPS
	PUSHJ	P,UUOLVL##	;MM AND SLEEPING (WAITING) ARE THE CALLER'S
	 S0JRST	CPUAPP##	; RESPONSIBILITY IF NOT AT UUO LEVEL
IFN FTMP,<
	PUSHJ	P,DIFMM##	;GIVE UP THE MM IF OWNED SINCE STMPEC MAY SLEEP
>
	S0PSHJ	CPUAPP##	; AND INSURE THAT ALL CPUS SEE THE NEW MAPPING
				; DO IT
IFN FTMP,<
	PJRST	UIFMM##		;RESTORE THE MM IF OWNED UPON ENTRY
>
IFE FTMP,<
	POPJ	P,		;RETURN
>
;SUBROUTINE TO ALLOCATE FUNNY SPACE IN WORDS RATHER THAT CHUNKS
;	T2/ NUMBER OF WORDS DESIRED
;	PUSHJ	P,GTFWDC	;GET FUNNY WORDS, CACHED
;	  -OR-
;	PUSHJ	P,GTFWDU	;GET FUNNY WORDS, UNCACHED
;RETURN CPOPJ IF SPACE IS NOT AVAILABLE
;	CPOPJ1 IF IT IS, T1 = ADDRESS

GFWDCH::HRRZS	.USFCU		;CLEAR LARGEST HOLE
	PUSHJ	P,GTFWDC	;GET THE SPACE
	  CAIA			;NOT AVAILABLE
	JRST	CPOPJ1##	;GOT IT
	HLRZ	T2,.USFCU	;GET SIZE OF BIGGEST HOLE
	POPJ	P,		; AND FAIL

IFN FTKL10,<
GFWDUD::SKIPA	T1,[GTFWDU]	;TRY REGULAR ENTRY POINTS FIRST
GFWDCD::MOVEI	T1,GTFWDC	;...
	PUSHJ	P,(T1)		;CALL CORRECT ROUTINE
>
IFE FTKL10,<
GFWDUD::
GFWDCD::PUSHJ	P,GTFWDC	;ALL THE SAME ON KI/KS
>
	  CAIA			;NO FUNNY SPACE AVAILABLE
	JRST	CPOPJ1##	;GIVE GOOD RETURN
	MOVE	T1,[600000,,.USFCD] ;TRY RESTRICTED SPACE
	JRST	GTFWD1		;AND HOPE THAT THERE IS SOME

GTFWDU::
IFN FTKL10,<
	SKIPE	[CPUN##-1]	;ALL SPACE IS CACHED IF ONLY 1
	SKIPA	T1,[400000,,.USFCU] ;ELSE GET UNCACHED HEADER
>
GTFWDC::MOVEI	T1,.USFCC	;POINT TO CACHED LIST HEAD
GTFWD1:	PUSHJ	P,SAVR##	;SAVE R
	MOVEI	R,(MDSEC0)	;SECTION 0 SPACE (REALLY FUNNY SPACE)
	JRST	GTFWD2		;JOIN COMMON CODE
IFE FTXMON,<
GFWNZD::			;DECNET USES "ONCE-ONLY" CORE
GFWNZO::MOVE	T1,[400000,,0]	;"ONCE-ONLY" CORE FOR THE KS
>
IFN FTXMON,<
GFWNZ2::SKIPA	T1,[400000,,(MS.SAT)]	;SECTION 2 CORE
GFWNZD::			;(NAME FOR DECNET TO CALL)
GFWNZS::MOVE	T1,[400000,,(MS.MEM)]	;GENERAL NZS SPACE
	SE1ENT			;MUST BE IN SECTION 1 TO ALLOCATE NZS SPACE
>
IFN FTMP,<
	PUSHJ	P,MMOWN##	;WE OWN MM ALREADY?
	  PUSHJ	P,GGVMM##	;NO--MUST HAVE THE MM TO LINK THROUGH FREE CORE CHAINS
>
	PUSHJ	P,SAVR##	;SAVE R
	MOVE	R,T1		;COPY SECTION # TO R
	MOVE	T1,NZSFCH##(R)	;HEADER FOR SPACE (ALWAYS UNCACHED)
GTFWD2:	PUSH	P,T1		;SAVE HEAD (FLAG ACTUALLY)
GTFWD3:
IFE	FTXMON,<
	MOVEI	T3,(T1)		;REMEMBER LINK
>
IFN FTXMON,<
	MOVE	T3,T1		;REMEMBER LINK
	SKIPE	R		;SECTION ZERO ALWAYS STORES SECTION
	CAME	T3,NZSFCH##(R)	;IF NOT THE FIRST TIME IN NON-ZERO SECTION
	SSXE	T1,(R)		; SET SECTION INDEX TO FUNNY SPACE SECTION
>
	HLL	T3,T1		;SET PREDECESSOR SECTION
	JUMPE	R,GTFWD4	;NON-ZERO SECTION HAS END POINTER
	CAMN	T1,NZSFCE##(R)	;THIS LAST BLOCK?
	  JRST	GTFWD7		;YES
	HRRZ	T1,(T1)		;POINT TO NEXT BLOCK
	JRST	GTFWD5
GTFWD4:	HRRZ	T1,0(T1)	;T1 = CURRENT CHUNK ADDRESS
	JUMPE	T1,GTFWD7	;IF 0, NO HOLE AVAILABLE, GET SOME MORE
GTFWD5:	SSXE	T1,(R)		;ADDRESS CORRECT SECTION
	HLRZ	T4,0(T1)	;SIZE OF THIS HOLE
	CAIGE	T4,(T2)		;LARGE ENOUGH FOR REQUEST
	JRST	[JUMPN R,GTFWD3	;NO BIGGEST HOLE IN NZS SPACE
		 HRLZ T4,T4	;NO, MOVE SIZE OF THIS HOLE
		 CAMLE T4,.USFCU ;BIGGEST YET
		 HLLM T4,.USFCU ;YES, REMEMBER FOR TMPCOR
		 JRST	GTFWD3]	; AND LOOK AT THE NEXT
	MOVEM	T1,(P)		;SAVE CHUNK ADDRESS
	CAIN	T4,(T2)		;AN EXACT SIZE MATCH
	JRST	[HRR T4,0(T1)	;YES, GET POINTER TO NEXT
		 HRRM T4,0(T3)	;RE-LINK PREVIOUS
		 JUMPE	R,TPOPJ1##
		 JRST	GTFWD6]	;CHECK IF THIS WAS LAST
	HRL	T4,0(T1)	;GET LINK TO NEXT CHUNK
	ADDI	T1,(T2)		;ADDRESS OF REMAINDER THIS CHUNK
	HRRM	T1,0(T3)	;STORE LINK TO REMAINDER
	SUBI	T4,(T2)		;SIZE OF REMAINDER
	MOVSM	T4,0(T1)	;STORE NEW LENGTH,OLD LINK IN REMAINDER
	JUMPE	R,TPOPJ1##	;SECTION ZERO, WE ARE DONE
	MOVE	T3,T1		;NEW LAST BLOCK
GTFWD6:	POP	P,T1		;RESTORE ADDRESS
	CAMN	T1,NZSFCE##(R)	;JUST ALLOCATE LAST BLOCK?
	  MOVEM	T3,NZSFCE##(R)	;STORE IT
	JRST	CPOPJ1##	;DONE
GTFWD7:	PUSH	P,T2		;SAVE AMOUNT REQUESTED
	MOVE	T1,-1(P)	;BITS,,HEADER
	MOVEI	T2,1		;ALWAYS CREATE ONLY 1 PAGE
	PUSH	P,R		;SAVE R
	PUSHJ	P,CREMNS	;CREATE A PAGE IN FUNNY SPACE OR NON-ZERO SECTION
	  JRST	GTFWD8
	POP	P,R
	JRST	GTFWD9		;A WINNER
GTFWD8:	POP	P,R
IFN FTKL10,<
	POP	P,T2		;RESTORE AMOUNT REQUESTED
	POP	P,T1		;RESTORE HEADER USED
	SKIPE	[CPUN##-1]	;ONLY ONE TRY IF ALL IS CACHED
	JUMPGE	T1,GTFWDU	;TRY FOR UNCACHED SPACE IF NO CACHED
	POPJ	P,		;ELSE OUT OF FUNNY SPACE
>
IFE FTKL10,<JRST TTPOPJ##>	;ONLY 1 TRY ON KI/KS
GTFWD9:	POP	P,T4		;RESTORE AMOUNT REQUESTED
	POP	P,T3		;RESTORE FREE SPACE HEADER AND FLAG
	MOVEI	T2,PAGSIZ##	;AMOUNT JUST ACQUIRED
	CAILE	T4,PAGSIZ##	;REQUESTING MORE THAN 1 PAGE
	JRST	GTFW10		;YES, MERGE THIS PAGE AND TRY AGAIN
	SUB	T2,T4		;AMOUNT LEFT OVER AFTER SATISFYING REQUEST
	JUMPE	T2,CPOPJ1##	;EXACT AMOUNT, RETURN NOW
	PUSH	P,T1		;SAVE ADDRESS OF NEWLY ACQUIRED CHUNK
	ADD	T1,T4		;ADDRESS OF RESIDUE
	EXCH	T1,T2		;WANT ARGS IN OTHER ORDER
	PUSHJ	P,GVFWD3	;GIVE IT BACK (T3 ALREADY SET UP)
	JRST	TPOPJ1##	;AND GIVE GOOD RETURN TO CALLER
GTFW10:	PUSH	P,T3		;SAVE HEADER AND FLAGS
	PUSH	P,T4		;SAVE ORIGINAL AMOUNT REQUESTED
	TLO	T3,100000	;LIGHT BIT SAYING NOT TO RETURN FULL PAGES
	EXCH	T1,T2		;WANT LENGTH AND ADDRESS IN THE OTHER ORDER
	PUSHJ	P,GVFWD3	;RETURN FULL PAGE TO THE FREE LIST
	POP	P,T2		;RESTORE ORIGINAL WORDS REQUESTED
	POP	P,T1		;RESTORE FREE SPACE HEADER AND FLAGS
	JRST	GTFWD2		;AND TRY TO SATISFY THE REQUEST NOW
;SUBROUTINE TO RETURN WORDS ACQUIRED BY GTFWDC, GTFWDU, OR GFWNZS
;CALL:	T1/ WORDS TO RETURN
;	T2/ ADDRESS
;	PUSHJ	P,GVFWDS

GVFNZD::
GVFWDS::PUSHJ	P,SAVR##	;SAVE TEMP USED FOR SECTION INDEX
GVFWD1:
IFN FTXMON,<
	MOVEI	R,(MDSEC0)	;ASSUME WE ARE TALKING ABOUT SECTION 0 SPACE
	HLRZ	T4,T2		;SECTION NUMBER
>
IFE FTXMON,<
	SETZB	R,T4		;ONCE ONLY OR FUNNY SPACE IS SECTION 0
>
	CAML	T2,LOCORE##	;ONCE-ONLY CORE?
IFN FTXMON,<
	TLZE	T2,-1		;NZS SPACE?
	TRNA			;ONCE ONLY OR NZS
>
	JRST	GVFWD2		;NO, SECTION ZERO FUNNY SPACE
GVFWDC:	CAIGE	T4,NZSFCL##	;KNOW ABOUT THIS SECTION?
	SKIPN	T3,NZSFCH##(T4)	;?
	STOPCD	CPOPJ##,DEBUG,RWS, ;++RETURNING SPACE TO WRONG SECTION
IFN FTXMON,<
	SKIPE	R,T4		;GET SECTION #
	SE1ENT			;IF RETURNING NZS CORE
	TLO	R,400000	;FLAG NOT FUNNY SPACE
>
IFE FTXMON,<
	MOVSI	R,400000	;FLAG NOT FUNNY SPACE BUT STILL SECTION ZERO
>
IFN FTMP,<
	PUSHJ	P,MMOWN##	;WE OWN MM ALREADY?
	  PUSHJ	P,GGVMM##	;NO--MUST INTERLOCK CHAIN CHASING
>
	MOVE	T3,NZSFCH##(R)	;GET PROPER HEADER
	JRST	GVFWD3		;JOIN COMMON CODE
GVFWD2:	MOVE	T4,T2		;COPY ADDRESS OF PIECE
	LSH	T4,W2PLSH##	;CONVERT TO PAGE NUMBER
	CAIGE	T4,.LPMC/PAGSIZ## ;RANGE CHECK IT
	CAIGE	T4,.FPMC/PAGSIZ## ;...
	STOPCD	CPOPJ##,DEBUG,PFR, ;++PIECE OUT OF FREE RANGE
	CAIN	T4,<.LPMC/PAGSIZ##>-1 ;IS THIS THE RESTRICTED PAGE
	JRST	[MOVE T3,[600000,,.USFCD] ;YES, USE THIS HEADER
		 JRST GVFWD3]	;ENTER COMMON CODE
	ADDI	T4,<.MCFV-.FPMC>/PAGSIZ## ;CONVERT TO VIRTUAL ADDRESS
	PUSHJ	P,GTPM4		;GET PAGE MAP ENTRY
	SKIPN	T4
	STOPCD	CPOPJ##,DEBUG,FPE, ;++FUNNY PAGE MUST EXIST
IFN FTKL10,<
	TLNN	T4,(PM.CSH)	;A CACHED PAGE
	SKIPA	T3,[400000,,.USFCU] ;GET UNCACHED LIST HEADER
>
	MOVEI	T3,.USFCC	;GET CACHED LIST HEADER
GVFWD3:	SPUSH	T3		;PUSH LEFT HALF
	TLZ	T3,100000	;CLEAR POSSIBLE FLAG.
	TLNE	R,400000	;FUNNY SPACE?
	CAME	T3,NZSFCH##(R)	;IF NOT THE FIRST TIME
IFN FTXMON,<
	SSXE	T3,(R)		; RELOCATE TO DATA SECTION
>
IFE FTXMON,<
	HRRZS	T3		;ALL IS REALLY S0
>
	JUMPE	R,GVFWD4	;ZERO TERMINATION FOR SECTION ZERO
	CAMN	T3,NZSFCE##(R)	;ELSE IS THIS LAST?
	  JRST	[SPOP	T3
		 JRST	GVFWD5]	;YES
GVFWD4:	HRRZ	T4,0(T3)	;GET FIRST CHUNK IN FREE LIST
	SPOP	T3		;RESTORE LEFT HALF
	TLNN	R,400000	;FUNNY SPACE?
	  JUMPE	T4,GVFWD5	;SECTION ZERO IS ZERO TERMINATED
	CAIN	T4,(T2)		;ALREADY IN FREE LIST
	STOPCD	CPOPJ##,DEBUG,PFL	;++PIECE ON FREE LIST
	CAIL	T4,(T2)		;KEEP CHUNKS IN ADDRESS ORDER
	JRST	GVFWD5		;IT GOES HERE
	HRR	T3,T4		;REMEMBER LINK
	JRST	GVFWD3		;AND LOOK AT THE NEXT
GVFWD5:	PUSH	P,T3		;SAVE PREVIOUS (AND FLAGS)
	TLZ	T3,100000	;BE SURE FLAG IS CLEAR
	MOVEI	T4,(T3)		;ADDRESS OF PREVIOUS
	JUMPL	R,GVFWD6	;ALWAYS COMBINE NZS
	CAIE	T4,.USFCD	;RESTRICTED SPACE HEADER
	CAIN	T4,.USFCC	;OR CACHED HEADER THE PREVIOUS?
	JRST	GVFWD8		;YES, CANNOT COMBINE (LH OF HDR IS NOT A LENGTH)
	JUMPE	R,GVFWD7	;SKIP SOME IF FUNNY SPACE
GVFWD6:	HLL	T4,NZSFCH##(R)	;COMPARE WITH NZS HEADER FOR RIGHT SECTION
IFN FTKL10,<
	CAME	T4,NZSFCH##(R)
	TLZA	T4,-1		;CLEAR LEFT HALF, PRESERVE NON-SKIP
	TLZA	T4,-1		;CLEAR LEFT HALF PRESERVE SKIP
GVFWD7:	CAIN	T4,.USFCU	;UNCACHED HEADER
>
IFE FTKL10,<
	CAMN	T4,NZSFCH##(R)
	TLZA	T4,-1		;CLEAR LEFT HALF, PRESERVE NON-SKIP
	TLZA	T4,-1		;CLEAR LEFT HALF PRESERVE SKIP
>
	JRST	GVFWD8		;IF NZS HEADER, CANNOT COMBINE
IFE FTKL10,<
GVFWD7:
>
IFE FTXMON,<
	TLZ	T3,-1		;CLEAR JUNK
>
IFN FTXMON,<
	SSXE	T3,(R)		;PROPER SECTION FOR REFERENCES BELOW
>
	HLRZ	T4,0(T3)	;LENGTH OF PREVIOUS PIECE
	ADDI	T4,(T3)		;FIRST WORD NOT IN PREVIOUS CHUNK
	CAILE	T4,(T2)		;BETTER BE
	STOPCD	TPOPJ##,DEBUG,FOP, ;++FUNNY ADDRESS OVERLAPS PREVIOUS
	CAIE	T4,(T2)		;PIECES CONTIGUOUS
	JRST	GVFWD8		;NO, CANNOT COMBINE
	MOVEI	T2,(T3)		;YES, ADDRESS OF LARGER CHUNK
	HLRZ	T4,0(T3)	;SIZE OF PREVIOUS
	ADD	T1,T4		;SIZE OF COMBINED PIECES
GVFWD8:
IFN FTXMON,<
	SSXE	T2,(R)		;SET FOR PROPER SECTION ADDRESSING
>
IFE FTXMON,<
	HRRZS	T2
>
	HRLM	T1,0(T2)	;SIZE OF THIS CHUNK
	HRRZ	T4,0(T3)	;PREVIOUS LINK TO NEXT
	HRRM	T4,0(T2)	;LINK THIS TO NEXT
	CAME	T2,T3		;PREV=THIS (CONCATENATION)
	HRRM	T2,0(T3)	;NO, LINK PREV TO THIS
	JUMPE	R,GVFWD9
	CAMN	T3,NZSFCE##(R)	;LAST?
	MOVEM	T2,NZSFCE##(R)	;WE ARE NOW LAST
GVFWD9:	HRRZ	T3,T2		;ADDRESS OF CURRENT
	ADD	T3,T1		;+SIZE OF CURRENT
	SKIPN	T4		;WAS LAST ADDRESS ZERO?
	JUMPE	R,GVFW10	;YES, END OF LIST IF SECTION ZERO
	CAMN	T2,NZSFCE##(R)	;ARE WE NOW LAST?
	JRST	GVFW10		;YES, THERE IS NO NEXT
	CAILE	T3,(T4)		;BETTER  BE
	STOPCD	.,JOB,FON,	;++FUNNY ADDRESS OVERLAPS NEXT
	CAIE	T3,(T4)		;BUTT UP AGAINST NEXT ONE
	JRST	GVFW10		;NO, CANNOT COMBINE THAT SIDE
	HRLZS	T1		;SIZE OF CURRENT,,0
IFN FTXMON,<
	SSXE	T4,(R)		;PROPER SECTION (STILL CLEAR IF IFE FTXMON)
>
	ADD	T1,0(T4)	;COMBINED SIZE,,NEXT'S LINK
	MOVEM	T1,0(T2)	;STORE NEW INFO
	HLRZS	T1		;ISOLATE SIZE OF NEW, LARGER PIECE
	JUMPE	R,GVFW10	;NOTHING MORE IF SECTION 0
	CAMN	T4,NZSFCE##(R)	;WAS THIS LAST?
	MOVEM	T2,NZSFCE##(R)	;WE ARE LAST NOW
GVFW10:	POP	P,T3		;RESTORE ORIGINAL PREVIOUS (AND FLAGS)
	TLNE	T3,100000	;SUPRESS RECLAMATION OF FULL PAGES
	POPJ	P,		;YES, ALL DONE NOW
	TLCE	R,400000	;FUNNY SPACE?
	JUMPE	R,CPOPJ		;NO, CAN'T RECLAIM ONCE-ONLY CORE
	TLC	R,400000	;PUT BIT BACK RIGHT
	PUSHJ	P,INTLVL##	;ONLY RECLAIM AT UUO LEVEL
	  CAIGE	T1,PAGSIZ##	;CAN WE RECLAIM A FULL CHUNK
	POPJ	P,		;NO, RETURN NOW
	PUSHJ	P,SAVE4##	;YES, SAVE SOME REGS
	DMOVE	P1,T1		;SAVE LENGTH, ADDRESS OF PIECE
	TRZ	T1,PAGSIZ##-1	;MAX WORDS THAT CAN BE RETURNED
	ADDI	T2,PAGSIZ##-1	;AND ROUND ADDRESS TO CHUNK BOUNDRY
	TRZ	T2,PAGSIZ##-1	;...
	MOVE	P4,P2		;ORIGINAL ADDRESS
	ADD	P4,P1		;P4 = FIRST WORD NOT IN PIECE
	MOVE	T4,T2		;START OF CHUNK THAT CAN BE RETURNED
	ADD	T4,T1		;T4 = FIRST WORD THAT WON'T BE RETURNED
GVFW11:	CAMGE	P4,T4		;RETURNABLE SPACE COMPLETELY CONTAINED
	JRST	[SUBI T1,PAGSIZ## ;NO, LESS WORDS TO RETURN
		 JUMPE T1,CPOPJ## ;"AND THEN THERE WERE NONE"
		 SUBI T4,PAGSIZ## ;ADJUST ENDING ADDRESS ( +1 )
		 JRST GVFW11]	;AND LOOK AT THE SMALLER PIECE
	MOVEI	P3,(P2)		;GET RIGHT HALF
	CAIE	P3,(T3)		;CURRENT = PREVIOUS (CONCATENTATION)
	JRST	[JUMPE	R,GVFW15	;GO IF FUNNY SPACE
		 CAME	T3,NZSFCH##(R)	;AT BEGINNING?
IFN FTXMON,<	 SSXE	T3,(R)>		;NO, RELOCATE
IFE FTXMON,<	 HRRZS	T3>
		 JRST	GVFW15]		;AND UNLINK PIECE
	JUMPE	R,GVFW12	;SECTION ZERO
	HRR	T3,NZSFCH##(R)	;ASSUME NZS CORE BEING RETURNED
	JRST	GVFW14		;NON-ZERO SECTION
GVFW12:	HRRI	T3,.USFCC	;YES, MUST FIND NEW PREVIOUS
IFN FTKL10,<
	SKIPGE	T3		;CACHED OR UNCACHED HEADER NEEDED
	HRRI	T3,.USFCU	;UNCACHED
>
	TLNE	T3,200000	;RESTRICTED SPACE
	HRRI	T3,.USFCD	;YES
GVFW13:
IFN FTXMON,<
	SSXE	T3,(R)		;SET TO ADDRESS PROPER SECTION
>
IFE FTXMON,<
	HRRZS	T3
>
GVFW14:	HRRZ	P3,0(T3)	;GET LINK TO NEXT
	CAIN	P3,(P2)		;POINT TO THIS ONE
	JRST	GVFW15		;YES, T3 = NEW PREVIOUS
	HRR	T3,P3		;COPY PREVIOUS
	JRST	GVFW13		;AND GO LOOK AGAIN
GVFW15:	SPUSH	P2		;SAVE LEFT HALF
IFN FTXMON,<
	SSXE	P2,(R)		;SET PROPER SECTION
>
IFE FTXMON,<
	HRRZS	P2
>
	HRRZ	P3,0(P2)	;GET ADDRESS OF NEXT CHUNK
	JUMPE	R,GVFW16	;SECTION ZERO
	CAMN	P2,NZSFCE##(R)	;WERE WE THE LAST?
	MOVEM	T3,NZSFCE##(R)	;PREDECESSOR NOW IS
GVFW16:	SPOP	P2		;RESTORE LEFT HALF
	HRRM	P3,0(T3)	;DE-LINK THE LARGER PIECE
	MOVE	P1,T2		;START OF REMOVED PIECE
	SUB	P1,P2		;COMPUTE LENGTH OF L.H. EXCESS
	MOVE	P3,P4		;1ST WORD NOT IN THE PIECE
	SUB	P3,T4		;COMPUTE LENGTH OF R.H. EXCESS
	MOVE	P4,T4		;AND WHERE IT STARTS
	PUSH	P,P1		;SAVE REMAINDER INFORMATION
	PUSH	P,P2		;...
	DMOVE	P1,T1		;COPY AMOUNT TO RETURN
	LSHC	P1,W2PLSH##	;P1 = NUMBER TO RETURN, P2 = PAGE NUMBER OF FIRST
GVFW17:	MOVE	J,.USJOB	;GET JOB NUMBER WHO OWNS THESE PAGES
	PUSHJ	P,DLTMPG	;DELTETE THIS PAGE
	AOS	P2		;STEP TO NEXT PAGE TO RETURN
	SOJG	P1,GVFW17	;GET THEM ALL
	CLRPGT	(0)		;WE HAVE CHANGED THE MAP
	POP	P,T2		;RESTORE LEFT HAND REMAINDER INFORMATION
	POP	P,T1		;...
	SKIPE	T1		;WAS THERE ANY
	PUSHJ	P,GVFWD1	;YES, GIVE IT BACK
	JUMPE	P3,CPOPJ##	;DONE IF NO RIGHT HAND REMAINDER
	DMOVE	T1,P3		;GET LENGTH AND ADDRESS OF IT
	JRST	GVFWD1		;GIVE IT BACK AND RETURN
;SUBROUTINE TO RETURN A FUNNY PAGE, MUST BE A SUBROUTINE SO THAT
; IT CAN CALL THE COROUTINE GGVMM
; CALL WITH P2 = VIRTUAL PAGE NUMBER

DLTMPG:	MOVE	T1,P2		;IN CASE A NZS PAGE
	PJUMPN	R,DNZSPG	;JUMP IF A NZS PAGE
IFN FTMP,<
	PUSHJ	P,GGVMM##	;GET MM RESOURCE SINCE DIDDLING CORE ALLOCATION TABLES
				; WILL BE RETURNED UPON EXIT
>
DLTFSP::
	MOVN	T1,[MCPCNT]	;DECREMENT COUNT OF FUNNY PAGES OWNED
	ADDM	T1,JBTPDB##(J)	;...
	MOVEI	T1,<.MCFV-.FPMC>/PAGSIZ##(P2) ;CONVERT TO VIRTUAL PAGE NUMBER
	PUSHJ	P,TSWST		;GET BIT FOR WSBTAB
	  STOPCD .+1,DEBUG,PNW,	;++PAGE NOT IN WORKING SET
	ANDCAM	T2,(T4)		;NO LONGER IN WORKING SET
	PUSHJ	P,GTPME		;GET PAGE MAP ENTRY FOR IT
	SETZM	(T4)		;ZAP THE PAGE MAP ENTRY
	TLZ	T2,(PM.NAD)	;DOWN TO PHYSICAL PAGE NUMBER
	PUSHJ	P,LKPSF		;FIX UP PAGTAB
	PJRST	DLTPGC		;AND DELETE THE PAGE,
				; RETURN MM RESOURCE AND RETURN TO CALLER

;SUBROUTINE TO RETURN A PAGE IN A NON-ZERO SECTION TO FREE CORE OR ONCE-ONLY CORE
; CALL WITH T1 = VIRTUAL PAGE NUMBER (MUST OWN THE MM RESOURCE)
;MUST BE IN SECTION 1

DNZSPG:	LSHC	T1,-^D9		;ISOLATE SECTION NUMBER
	LSH	T2,-^D27	;RIGHT JUSTIFY PAGE NUMBER
IFE FTXMON,<
	MOVEI	T1,0		;MAKE SURE SECTION IS RIGHT
>	ADD	T1,.CPEPT##	;ADDRESS OF EPT + SECTION NUMBER
	SKIPN	T3,SECTAB(T1)	;GET ENTRY FROM SECTION MAP
	STOPCD	CPOPJ##,DEBUG,NXS, ;++NON-EXISTANT SECTION
	MOVEM	T3,.UPMP+.UMTMP ;MAKE THE SECTION MAP ADDRESSABLE
	CLRPGT	(0)		;MAKE NEW MAPPING VISABLE
	MOVEI	T1,.TEMP(T2)	;ADDRESS OF THE POINTER SLOT (FOR STMAPE)
	SKIPN	T2,.TEMP(T2)	;GET PAGE POINTER
	STOPCD	CPOPJ##,DEBUG,RNP, ;++RETURNING NON-EXISTANT PAGE
	TLZ	T2,(PM.NAD)	;ISOLATE PHYSICAL PAGE NUMBER
;	SE1ENT			;(RIGHT NOW, DNZSPG IS ALWAYS CALLED HERE)
	PUSH	P,T1		;SAVE MAP OFFSET
	HRRZ	T1,@[IW MS.MEM,PT2TAB(T2)]
	CAMN	T2,LMPAG##	;IS THIS THE LAST MONITOR PAGE?
	HRRZM	T1,LMPAG##	;YES, NEW LAST PAGE
	PUSHJ	P,LKPSF		;REMOVE PAGE FROM MONITOR'S CHAIN
	PUSHJ	P,DLTPGC	;RETURN THE PAGE TO FREE CORE
	MOVEI	T1,PAGSIZ##	;NUMBER OF WORDS BEING FREED
	ADDM	T1,MAXMAX##	;UPDATE MAXMAX TO REFLECT THAT
	ADDM	T1,RMCMAX##	;UPDATE REAL MAXIMUM FOR CORMAX
	POP	P,T1		;RESTORE PAGE OFFSET
	MOVEI	T2,0		;SET TO ZERO THE MAP SLOT
	PJRST	STMAPE		;ZERO THE MAP SLOT AND RETURN
	SUBTTL	COMCON	INTERFACE WITH COMMAND DECODER

;PRIVILEGED COMMAND/UUO TO SET THE SYSTEM-WIDE VM LIMIT
SETVMX::PUSHJ	P,CORLGL##	;GET CORE ARGUMENT
	ADDI	T2,1
	LSH	T2,W2PLSH##	;CONVERT TO PAGES
SETVM1::CAMLE	T2,VIRTAL##	;BIGGER THAN VIRTAL?
	MOVE	T2,VIRTAL##	;YES, USE VIRTAL
	CAMGE	T2,VMTOTL##	;BIGGER THAN TOTAL VM NOW IN USE?
	MOVE	T2,VMTOTL##	;YES, USE CURRENT AMOUNT IN USE
	MOVEM	T2,VMCMAX##	;SAVE SYSTEM WIDE VM LIMIT
	PJRST	CPOPJ1##	;AND RETURN

;PRIVILEGED UUO TO SET THE ABSOLUTE PER-USER MAXIMA
SETUVL::HRR	M,T2		;LOC OF ARGUMENT
	TLZ	M,MXSECN	;(SETUUO IS LOCAL)
	PUSHJ	P,FLTSX		;MAKE SURE WONT FAULT
	  JRST	ECOD0##		;PAGE-FAULT AT NON-UUO LEVEL????!!??
	PUSHJ	P,GETWDU##	;GET ARG
	PUSHJ	P,CHKLIM	;MAKE SURE VALUES ARE OK
	  JRST	ECOD0##		;NOT - NON SKIP
SETVLM::
	MOVEM	T1,.PDMVL##(W)	;MVPL,,MPPL
	SKIPN	.PDCVL##(W)	;IF NOT ALREADY SET,
	JRST	SETUV2		;SAVE AS CURRENT LIMITS TOO
	PJRST	CPOPJ1##	;AND GOOD RETURN

;NON-PRIVILEGED UUO TO SET INTERVAL FOR VIRTUAL-TIME INTERRUPT
SETVTM::PUSHJ	P,FNDPDB##	;GET PDB FOR TARGET JOB
	  JRST	ECOD0##		;CAN'T SET IF NO PDB
	IMUL	T2,TICSEC##	;CONVERT TO TICS-PER-INTERRUPT
	IDIVI	T2,^D1000
	HRRZM	T2,.PDTMC##(W)	;SAVE IN UPMP
	HRRM	T2,.PDTMI##(W)
	PJRST	CPOPJ1##	;AND RETURN

;SUBROUTINE TO CHECK CORE LIMITS
;ENTER T1=LIMITS
;EXIT CPOPJ IF TOO BIG, CPOPJ1 IF OK
;RETURNS T3=RH(T1) WITHOUT GUIDELINE BIT
CHKLIM:	HLRZ	T2,T1
	HRRZ	T3,T1
	TRZ	T3,400000	;CLEAR LIMIT BIT
	CAIG	T2,<MXSECN+1>*<HLGPNO+1>	;OK?
	CAILE	T3,<MXSECN+1>*<HLGPNO+1>
	POPJ	P,		;NO, NON-SKIP
	JUMPE	T3,CPOPJ1##	;0 IS ALWAYS OK
	CAIL	T3,4		;AT LEAST 4 PAGES?
	PJRST	CPOPJ1##	;YES, SKIP
	TRZ	T3,377777	;CLEAR
	TRO	T3,4		;MAKE IT FOUR PAGES
	JRST	CPOPJ1##	;SKIP RETURN
;NON-PRIVILEGED COMMAND TO SET CURRENT PER-USER LIMITS
SETUVC::SKIPA	T1,[POINT 18,.PDMVL##(W),17]
SETUPC::MOVE	T1,[POINT 18,.PDMVL##(W),35]
	PUSHJ	P,SAVE2##	;SAVE AN AC
	MOVE	P1,T1		;SAVE POINTER TO MAX VALUE FOR THIS ARG
	PUSHJ	P,FNDPDB##	;GET PDB LOC
	  POPJ	P,		;NONE-RETURN
	MOVE	T1,[-2,,[SIXBIT /GUIDEL/
			 SIXBIT /LIMIT/]]
	PUSHJ	P,TXTARG##
	  TDZA	P2,P2
	MOVE	P2,T1
	PUSHJ	P,CORARG##	;GET THE CORE ARGUMENT
	  PJRST	NOTENF##
	ADDI	T1,1		;CONVERT TO PAGES
	LSH	T1,W2PLSH##
	PUSHJ	P,CHKLIM	;LEGAL?
	  PJRST	COMERA##
	LDB	T2,P1		;YES, GET MAX VALUE FOR THIS ARG
	CAILE	T1,(T2)		;TRYING TO SET IT TOO HIGH?
	JRST	COMERA##	;YES
	HRRI	P1,.PDCVL##	;NO, SET TO STORE NEW VALUE
	DPB	T1,P1		;SAVE CURRENT LIMIT
	TRNN	T1,-1		;SETTING LIMIT/GUIDELINE TO ZERO?
	MOVEI	P2,0		;YES, CLEAR LIMIT BIT
	TLNN	P1,770000	;PHYSICAL?
	DPB	P2,[POINT 1,.PDCVL##(W),18]
	PJRST	CPOPJ1##	;AND TAKE GOOD RETURN


;NON-PRIVILEGED UUO TO SET PER-USER CURRENT LIMITS
SETUV1::HRR	M,T2		;ADR OF ARGUMENT
	TLZ	M,MXSECN	;(SETUUO IS LOCAL)
	PUSHJ	P,FLTSX
	  POPJ	P,		;PAGE-FAULT AT NON-UUO LEVEL???!!!
	PUSHJ	P,GETWDU##	;GET ARGUMENT
	PUSHJ	P,CHKLIM	;LEGAL?
	  POPJ	P,		;NO, RETURN
	MOVE	T2,.PDMVL##(W)	;YES, GET MAX LIMIT
	HRRZ	T4,T2		;MAKE SURE ARGUMENTS ARE BELOW MAX LIMITS
	CAILE	T2,<MXSECN+1>*<HLGPNO+1>
	HRLI	T2,<MXSECN+1>*<HLGPNO+1>
	TRO	T2,-1		;PUT LARGE NUMBER IN IRRELEVANT RIGHT-HALF
	CAMG	T1,T2
	CAMLE	T3,T4
	POPJ	P,		;TRYING TO SET THEM TOO BIG
SETUV2:	TLNE	T1,-1		;OK, SAVE WHAT HE ASKED FOR
	.HLLM	T1,.PDCVL##(W)	;CVPL
	TRNE	T1,-1
	.HRRM	T1,.PDCVL##(W)	;CPPL
	SKIPN	T1		;IF WHOLE THING ZERO,
	.MOVEM	T1,.PDCVL##(W)	;  DO IT ANYWAY
	PJRST	CPOPJ1##
;ROUTINE TO DETERMINE IF A PAGE EXISTS AND IF SO IF REFERENCING IT
; WILL CAUSE A PAGE FAULT. ENTER T2 = VIRTUAL ADDRESS
; EXIT CPOPJ IF PAGE DOESN'T EXIST
; CPOPJ1 IF PAGE EXISTS BUT IS PAGED OUT OR HAS ACCESS ALLOWED OFF,
; CPOPJ2 IF PAGE EXISTS AND IS IN CORE,  OR IS ALLOCATED BUT ZERO
;RETURNS MAP CONTENTS FOR THE ADR IN T4
;PRESERVES T2.

FLTTC::	TLZ	T2,-1-MXSECN	;CLEAR CRUFT
	MOVE	T4,T2		;GET ADR
	LSH	T4,W2PLSH##+P2SLSH## ;GET SECTION
	JUMPE	T4,FLTTC1	;CONTINUE IF S0
	PUSH	P,T2		;SAVE T2
	PUSHJ	P,RSECT4	;GET REAL SECTION #
	  JUMPN	T4,T2POPJ##	;DOESN'T EXIST
	POP	P,T2		;RESTORE T2
FLTTC1:	MOVE	T4,T2		;GET WORD ADDRESS AGAIN
	LSH	T4,W2PLSH##	;PAGE #
	SE1ENT
	SKIPN	T4,@[IW UMAPSN,UMAPS(T4)] ;GET ENTRY (SECTION EXISTS SO CAN'T FAULT)
	POPJ	P,		;TOO BAD PAGE DOESN'T
	TLNE	T4,(<PM.ACD>B2)	;IN CORE?
	  JRST	CPOPJ2##	;YES
	TLZ	T4,(PM.NAD)	;KEEP ONLY ADDRESS
	CAMN	T4,[PM.ZER]	;ABZ PAGE?
	AOS	(P)		;YES, ACCESS ALLOWED IS ON
	JRST	CPOPJ1##	;DONE
;HERE TO DEPOSIT IN AN ALLOCATED BUT ZERO PAGE
; S = WHAT TO DEPOSIT, JOBEXM = WHERE
CREPAG::PUSHJ	P,CLRASA##	;CLEAR JS.ASA IN CASE OF ERROR AND SO USER'S
				; ACS WILL GET RESTORED WHEN MONITOR JOB IS STARTED
	JUMPL	P4,CREPA2	;IF RUNNING, REQUIRE A CONTROL C
	JSP	T2,SAVCTX##
;RETURN HERE AT UUO LEVEL
	MOVEM	S,.JDAT+JOBFDV## ;SAVE WHAT TO DEPOSIT
	MOVE	T2,.JDAT+JOBEXM## ;WHERE TO DEPOSIT
	TLZ	T2,400000	;CLEAR EXAMINE LAST FLAG
	MOVEI	T3,1		;NUMBER OF PAGES TO CREATE FOR THE DEPOSIT
	PUSHJ	P,MAKPGS	;CREATE THE PAGE FOR THE DEPOSIT
	  JRST	CREPA1		;LOST, PHYSICAL LIMIT IS SET TOO LOW
	MOVE	T1,.JDAT+JOBFDV## ;WHAT
	MOVE	T2,.JDAT+JOBEXM## ;WHERE
	TLZ	T2,400000	;CLEAR EXAMINE LAST FLAG
	EXCTXU	<MOVEM T1,(T2)>	;STORE IT AWAY FOR HIM
	POPJ	P,
CREPA1:	PUSHJ	P,TTYFUW##	;FIND HIS TTY AND RESTORE J
	PUSHJ	P,PRQM##	;"?"
	MOVEI	T1,OUTBMS##	;"OUT OF BOUNDS"
	PJRST	CONMES##	;PRINT THAT
CREPA2:	SKIPGE	.JDAT+JOBEXM##	;EXAMINE LAST FLAG ON?
	TLO	T2,400000	;YES, SET IT AGAIN
	MOVEM	T2,.JDAT+JOBEXM## ;STORE WHAT USER TYPED SINCE CAN'T DO IT NOW
	MOVEI	T1,RUNERR##	;"PLEASE TYPE CONTROL C FIRST"
	PJRST	ERRMES##	;PRINT THAT AND RETURN TO COMCON
;SUBROUTINE TO RETURN # OF VIRTUAL PAGES ALLOCATED TO A USER'S JOB
;CALL WITH:
;	UBR SETUP TO USER PAGE MAP PAGE
;	MOVEI	J,JOB #
;	PUSHJ	P,VMSIZE
;	RETURNS HERE WITH LOWSEG SIZE IN T1 AND HISEG SIZE IN T2
;
;	JOB'S UPMP IS IN CORE WHEN VMSIZE IS CALLED. LOWSEG SIZE
;	  INCLUDES THE JOB'S PAGE MAP PAGE.
;
VMSIZE::SETZB	T1,T2		;ASSUME USER DID CORE 0
	SKIPN	JBTADR##(J)	;ANY CORE ASSIGNED?
	POPJ	P,		;NO, RETURN ZEROS
	PUSHJ	P,LOSIZ		;GET THE LOW SEG SIZE
	MOVEI	T1,UPMPSZ##(T3)	; +1 FOR UPMP
	ADD	T1,.USMEM	; + NO OF NON-CONTIGUOUS PAGES
	SKIPLE	T3,JBTSGN##(J)	;HAVE A HI SEG?
	TLOA	T3,(1B0)	;MAKE A USABLE INDEX OUT OF COPY OF JBTSGN
	TRNA			;NO HISEG
	HLRZ	T2,JBTADR##(T3)	;YES, GET ITS SIZE
	ADDI	T2,1
	LSH	T2,W2PLSH##	;CONVERT TO PAGES
	POPJ	P,		;AND RETURN
;SUBROUTINE TO COMPUTE THE LOW SEG SIZE
;ENTER J=JOB NUMBER
;EXIT T3= LOW SEG SIZE IN PAGES
;PRESERVES ALL ACS (EXCEPT T3)

;CALL HISIZ TO COMPUTE HI SEG SIZE, ALWAYS RETURNS CPOPJ1
HISIZ:	HLRZ	T3,JBTADR##(J)	;USE JBTADR
	AOS	T3		;ROUND UP
	LSH	T3,W2PLSH##	;MAKE PAGES
	JRST	CPOPJ1##	;AND RETURN

LOSIZ:	SKIPN	T3,.USREL	;VIRTUAL?
	HLRZ	T3,JBTADR##(J)	;NO, USE JBTADR
	ADDI	T3,1
	LSH	T3,W2PLSH##	;CONVERT TO PAGES
	ADD	T3,.USNCR	;ADD # OF NZS PAGES
	POPJ	P,		;AND RETURN
	SUBTTL	ERRCON	ERROR HANDLING MODULE

;SUBROUTINE TO COMPUTE A VIRTUAL PAGE NUMBER WITHIN A JOB'S
; ADDRESS SPACE BASED ON AN ABSOLUTE PAGE NUMBER KNOWN TO BE IN THE
; JOB'S MAP
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER
;	MOVE	T3,PHYSICAL PAGE NUMBER TO BE USED IN VIRTUAL PAGE CALCULATION
;	MAKE THE JOB'S MAP ADDRESSABLE
;	PUSHJ	P,PHYPVP	;CONVERT PHYSICAL PAGE NUMBER TO VIRTUAL PAGE NUMBER
;ALWAYS RETURNS POPJ,T1=VIRTUAL PAGE NUMBER WITHIN THE
; LOW SEGMENT OR RELATIVE PAGE NUMBER WITHIN HIGH SEGMENT

PHYPVP::SE1ENT		;TO TOUCH MAPS
	SETZB	T1,T4		;START AT VIRTUAL PAGE 0
	PUSHJ	P,GMPTR		;GET A BYTE POINTER TO THE MAP
PHYPV1:	MOVE	T2,(T4)		;GET MAP CONTENTS
	AOS	T4		;INCREMENT
	TLZ	T2,(PM.NAD)	;KEEP ONLY PAGE #
	CAME	T3,T2		;IS THIS THE ABSOLUTE PAGE IN QUESTION?
	AOJA	T1,PHYPV1	;NO, LOOK AT THE NEXT PAGE IN THE MAP
	PUSHJ	P,TSWST		;IN THE WORKING SET?
	CAIA			;NO, SEE IF IN THE HIGH SEG
	POPJ	P,		;IT'S IN THE WORKING SET
	PUSHJ	P,TPNHS		;YES, IS THIS PAGE IN THE HIGH SEGMENT?
	  SKIPA	J,JBTSGN##(J)	;YES, GET HIGH SEGMENT NUMBER
	AOJA	P1,PHYPV1	;NO, NOT A REAL PAGE THEN (DISK ADDR?)
	LDB	T2,JBYHSO##	;GET ORIGIN PAGE OF THE HIGH SEGMENT
	SUBI	T1,(T2)		;COMPUTE RELATIVE PAGE WITHIN HIGH SEGMENT
	POPJ	P,		; AND RETURN
	SUBTTL	CORE1	INTERFACE WITH THE CORE ROUTINES

;SUBROUTINE TO TURN ON BITS IN WSBTAB WHEN A JOB IS EXPANDING
;ENTER T1=HIGHEST RELATIVE PAGE DESIRED
;PRESERVES T1
CLRWS::	PUSHJ	P,SAVE2##	;SAVE P1 & P2
	MOVSI	P1,(ANDCAM T1,(T4)) ;SET ARGUMENT FOR ADJWS1
	JRST	ADJWS1		;CLEAR BITS IN WSBTAB

ADJWS::	PUSHJ	P,SAVE2##	;SAVE P1 & P2
	MOVSI	P1,(IORM T1,(T4)) ;SET ARG  FOR ADJWS1
	MOVEI	T3,30		;MAKE SURE UPMP BIT ON IN WSBTAB
	IORM	T3,WSBTAB+16
ADJWS1:	PUSHJ	P,SAVT##
	MOVEI	T3,(T1)		;GET ARG SET
	ANDI	T3,HLGPNO	;ONLY KEEP PAGE NUMBER
ADJWS2:	MOVEI	P2,MXSECN_S2PLSH## ;ISOLATE SECTION #
	AND	P2,T1
	LSH	P2,P2SLSH##
ADJWS3:	SKIPGE	.USBTS		;NOT A BIG USER
	SKIPN	T4,P2		;SECTION BEING DONE
	SKIPA	T4,[WSBTAB-.WSBNZ+WSBTBL]
	IMULI	T4,WSBTBL
	ADDI	T4,.WSBNZ-WSBTBL
DOBIT:	MOVEI	T1,^D36		;SET UP FIRST PART OF MASK
	PUSHJ	P,BITMSK##
DOBIT1:	XCT	P1		;SET OR CLEAR BITS
	JUMPLE	T3,DOBIT2	;GO IF THROUGH
	PUSHJ	P,BITMS2##	;SET MASK FOR NEXT PART
	JRST	DOBIT1		;AND CONTINUE
DOBIT2:	SOSGE	T1,P2		;ANOTHER SECTION TO DO?
	POPJ	P,		;NO, DONE
	SKIPN	.UPMP+SECTAB(T1);SECTION EXIST?
	JRST	DOBIT2		;NO, KEEP LOOKING (SEC 0 MUST EXIST FOR NOW)
	MOVEI	T3,HLGPNO	;DO ALL PAGES IN PRECEDING SECTIONS
	JRST	ADJWS3

;SUBROUTINE TO COMPUTE THE TOTAL VIRTUAL SIZE OF A JOB
;ENTER WITH JOB ADDRESSABLE
;EXIT T2= JOB SIZE IN PAGES (EXCLUDES UPMP SIZE)
;PRESERVES ALL ACS BUT T2
VRTSZ:	PUSH	P,T1		;SAVE T1
	MOVE	T1,.USJOB	;JOB NUMBER
	SKIPN	T2,.USREL	;NON-CONTIGUOUS?
	HLRZ	T2,JBTADR##(T1)	;NO, GET JBTADR
	SKIPLE	T1,JBTSGN##(T1)	;IS THERE A NON-SHARABLE HI-SEG?
	TLNE	T1,SHRSEG
	JRST	VRTSZ1		;NO
	HRRZS	T1
	HLRZ	T1,JBTADR##(T1)	;YES, GET ITS SIZE
	ADD	T2,T1		;LOW+HIGH SIZES
VRTSZ1:	LSH	T2,W2PLSH##
	ADD	T2,.USNCR	;AND NZS PAGES
	ADD	T2,.USMEM	;+NO OF NON-CONTIG PAGES
	AOJA	T2,TPOPJ##	;AND RETURN
;SUBROUTINE CALLED BY CORE1 ON A CORE UUO/COMMAND
;ALLOCATES SPACE (ALLOCATED BUT ZERO) IF A JOB IS ALREADY VIRTUAL
; OR IS GOING VIRTUAL BY THIS CORE OPERATION
;ENTER T3=AMOUNT OF INCREASE -1 ; T1=NEW HIGHEST ADDRESS
;EXIT CPOPJ IF ASKING FOR TOO MUCH
;EXIT CPOPJ1 IF ALLOCATED ON DSK
;EXIT CPOPJ2 OTHERWISE, T1=HIGHEST ADR, T3=AMOUNT OF INCREASE-1
VIRCHK::CAIG	J,JOBMAX##	;LOW SEGS MUST CALL KISER TO
	JUMPE	R,CPOPJ2##	; GET INITIAL CORE (GETMIN)
	TLNE	J,SHRSEG	;A SHARABLE HIGH SEGMENT?
	JRST	CPOPJ2##	;YES, LET KISER HANDLE CORE ALLOCATION
	PUSHJ	P,UUOLVL##	;UUO LEVEL?
	  TDZA	T3,T3		;NO, MUST BE SECTION 0 THEN
	XSFM	T3		;GET THE SECTION #
	TRNE	T3,MXSECN	;NON-ZERO SECTION?
	JRST	VIRCH6		;YES, HANDLE DIFFERENTLY
	CAIG	J,JOBMAX##	;A HIGH SEGMENT?
	SKIPN	T2,.USREL	;NO, HIGHEST CONTIGUOUS ADDRESS IN THE LOW SEGMENT
	HLRZ	T2,R		;HIGHEST ADDRESS IN THE SEGMENT
	MOVE	T4,T1		;HIGHEST ADDRESS REQUESTED
	SUB	T4,T2		;MINUS CURRENT HIGHEST ADDRESS
	JUMPLE	T4,VIRCH9	;DEALLOCATING
	LSH	T4,W2PLSH##	;CONVERT TO NUMBER OF PAGES OF INCREASE
	DMOVEM	T1,.USTMP	;SAVE REQUESTED SIZE, CURRENT SIZE
	CAIG	J,JOBMAX##	;A HIGH SEGMENT?
	JRST	VIRCH1		;NO
	EXCH	J,.USJOB	;JOB NUMBER
	PUSHJ	P,HSVAD##	;COMPUTE THE EXTENT OF THE HIGH SEGMENT
	EXCH	J,.USJOB	;RESTORE HIGH SEGMENT NUMBER
	MOVE	T1,T2		;UVA OF HIGH SEGMENT
	ADD	T1,.USTMP	;CURRENT HIGEST ADDRESS IN THE HIGH SEGMENT
	ADD	T2,.USTMP+1
VIRCH1:	CAMG	T4,VIRTAL##	;IS ENOUGH SWAPPING SPACE AVAILABLE?
	PUSHJ	P,CKNZ1		; AND ARE ALL PAGES REQUESTED NOT IN-USE?
	  POPJ	P,		;NO, ERROR RETURN
	MOVE	T1,.USTMP	;RESTORE THE HIGEST ADDRESS REQUESTED
	MOVEM	T4,.USTMP	;SAVE THE NUMBER OF PAGES OF INCREASE
	CAIG	J,JOBMAX##	;A HIGH SEGMENT?
	PUSHJ	P,FNDPDS##	;NO, FIND THE PDB FOR THIS JOB
	PUSHJ	P,GSIZT		;DOES IT FIT (PHSYCIALLY, VIRTUALY, NOT AT ALL)?
	  JRST	VIRCH2		;MAYBE VIRTUALLY
	  SKIPGE P1		;VIRTUALLY IF NOT PHYSICAL ONLY
	JRST	VIRCH3		;PHYSICALLY
;HERE IF JOB ALREADY VIRTUAL OR HAS TO GO VIRTUAL
VIRCH2:	JUMPL	P1,CPOPJ##	;PHYSICAL-ONLY IF P1 NEGATIVE
	JRST	VIRCH5		;NO, LOW SEG VIRTUAL CORE
;HERE IF CAN GET PHYSICAL CORE
VIRCH3:	CAIG	J,JOBMAX##	;HIGH SEG?
	JRST	VIRCH4		;NO
	SKIPN	T2,.USHSE	;CREATING?
	MOVE	T2,.USHSS	;YES, THEN START AT THE VERY BEGINNING
	ADD	T1,.USHSS	;HIGHEST PAGE DESIRED
	TRO	T1,PG.BDY	;WORD ADDRESS
VIRCH4:	TDZA	T3,T3		;CLEAR
VIRCH5:	MOVSI	T3,(PG.SLO)	;ON DISK
	SUBI	T1,(T2)		;# OF PAGES TO EFFECT
	SKIPN	R		;IF CREATING FROM NOTHING,
	AOSA	T1		;INCLUDE 0TH PAGE
	AOS	T2		;ELSE START AT FIRST NON-EX PAGE
	LSHC	T1,W2PLSH##	;CONVERT TO PAGES
	HLL	T2,T3
	MOVNM	T1,.JDAT+JOBUAL##
	MOVEM	T2,.JDAT+JOBUAL##+1
	SETZM	.JDAT+JOBUAL##+6 ;NO SECOND UUO
	CAIG	J,JOBMAX##	;LOW SEG?
	JRST	VIRC14		;DO THE UUOS
;HERE TO SET UP THE REMAP FOR A NON-SHARABLE HIGH SEG
	HRRZM	T2,.JDAT+JOBUAL##+4 ;SOURCE PAGE
	HRRZM	T2,.JDAT+JOBUAL##+5 ;NEW HS ORIGIN (APPEND)=IN PLACE
	MOVE	J,.USJOB	;POINT TO LOW SEG
	MOVNM	T1,.JDAT+JOBUAL##+3 ;(NEGATIVE INDICATES APPEND)
	MOVEI	T1,3		;# OF ARGS
	MOVEM	T1,.JDAT+JOBUAL##+2 ;SET IN ARG BLOCK
	MOVE	T1,[.PAGRM,,JOBUAL##+2] ;SET ARG POINTER
	MOVEM	T1,.JDAT+JOBUAL##+6
	JRST	VIRC20
;HERE TO DO CORE UUO FOR A NON-ZERO SECTION

VIRCH6:	CAILE	J,JOBMAX##	;JOB OR HIGH SEG?
	JRST	VIRCH7		;HIGH SEG
	LSH	T1,W2PLSH##	;CONVERT TO HIGHEST PAGE DESIRED
	AOS	T1		;INCLUDE P0
	MOVNM	T1,.JDAT+JOBUAL##	;# OF PAGES TO "CREATE"
	LSH	T3,S2PLSH##	;CHANGE SECTION # TO PAGE 0 IN THAT SECTION
	HRLI	T3,(PG.IDC)	;DON'T CARE ABOUT PAGES THAT ALREADY EXIST
	MOVEM	T3,.JDAT+JOBUAL##+1 ;ARG
	SETZM	.JDAT+JOBUAL##+6 ;NO SECOND UUO
	PJRST	VIRC14		;FINISH UP

;HERE FOR HIGH SEG

VIRCH7:	MOVE	T3,[.PAGRM,,JOBUAL##+2] ;A REMAP WILL BE DONE
	MOVEM	T3,.JDAT+JOBUAL##+6 ;POINTER TO BLOCK
	MOVE	J,.USJOB
	LDB	T3,JBYSG2##
	XSFM	T4
	CAIN	T3,(T4)		;IS HIGH SEG IN THIS SECTION?
	SKIPN	R		;YES, DOES IT ALREADY EXIST?
	SKIPA	T2,[377000]	;DOESN'T EXIST OR WRONG SECTION, CREATE
	SKIPA	T2,.USHSE	;APPENDING, CURRENT END OF HIGH SEG
	SKIPA	T3,[400000]
	MOVE	T3,.USHSS
	ADDI	T1,(T3)
	LDB	T3,JBYSG2##	;RESTORE SECTION #
	HRLI	T1,(T4)		;SECTION #
	HRLI	T2,(T4)		;HERE ALSO
	LSHC	T1,W2PLSH##	;PAGES
	TLZN	T2,-1		;"CORE 0"
	SOS	T1		;YES, ONE MORE PAGE TO DELETE
	SUBM	T2,T1		;-# OF PAGES TO CREATE/REMAP
	JUMPL	T1,VIRCH8	;NEGATIVE, ALL IS WELL
	SETZM	.JDAT+JOBUAL##	;NO FIRST UUO FOR DELETE
	MOVEI	T2,1		;ONLY ONE ARG FOR DELETE REMAP
	MOVEM	T2,.JDAT+JOBUAL##+2 ;# OF ARGS
	MOVEM	T1,.JDAT+JOBUAL##+3 ;SET # OF PAGES (APPEND)
	PJRST	VIRC20
VIRCH8:	MOVEM	T1,.JDAT+JOBUAL##
	CAIN	T3,(T4)		;IS HIGH SEG IN THIS SECTION?
	SKIPN	R		;YES, DOES IT ALREADY EXIST?
	MOVNS	T1		;CREATE
	AOS	T2
	MOVEM	T2,.JDAT+JOBUAL##+1 ;CREATE ARG TOO
	HRRZS	T2		;INCASE DELETE
	MOVEM	T2,.JDAT+JOBUAL##+4 ;"FROM" REMAP PAGE
	MOVEM	T2,.JDAT+JOBUAL##+5 ;"TO" REMAP PAGE
	MOVEI	T2,3
	MOVEM	T2,.JDAT+JOBUAL##+2 ;# OF ARGS
	MOVEM	T1,.JDAT+JOBUAL##+3 ;SET # OF PAGES (APPEND)
	JRST	VIRC20
;HERE TO DEALLOCATE STORAGE
VIRCH9:	CAIG	J,JOBMAX##	;JOB?
	JRST	VIRC10		;YES, DO AS LOW SEG STUFF
	ASH	T4,W2PLSH##	;CONVERT TO PAGES
	JUMPE	T4,VIRC18	;NOTHING TO DO
	MOVNM	T4,.JDAT+JOBUAL+3 ;SET # OF PAGES TO DELETE FROM HS
	MOVEI	T4,1
	MOVEM	T4,.JDAT+JOBUAL+2 ;# OF ARGS
	MOVE	T1,[.PAGRM,,JOBUAL##+2]
	MOVEM	T1,.JDAT+JOBUAL##+6
	SETZM	.JDAT+JOBUAL##
	JRST	VIRC19
;HERE TO DEALLOCATE FROM LOW SEG WITH PAGE UUOS
VIRC10:	LSH	T1,W2PLSH##	;NEW HIGHEST DESIRED PAGE
	AOS	T1		;FIRST PAGE DON'T WANT
	HRLI	T1,(PG.IDC!PG.GAF)
	MOVEM	T1,.JDAT+JOBUAL+1 ;SET WHERE TO START
	SKIPG	T2,JBTSGN##(J)	;JOB HAVE HIGH SEG?
	JRST	VIRC11		;NO
	EXCH	T2,J		;PUT WHERE IT'S USEFUL
	LDB	T4,PCORSZ##	;HIGHEST ADDR IN SEGMENT
	LDB	J,JBYHSO##	;LOWEST PAGE IN SEGMENT
	EXCH	T2,J		;BACK TO NORMAL
	ADDI	T4,1(T2)	;FIRST NOT IN HS
	SKIPN	.USMEM		;YES, CAN HE HAVE PAGES ABOVE HS?
	JRST	VIRC12		;NO, JUST HAVE TO DELETE BELOW HS
	LDB	T3,PCORSZ##	;HIGHEST PAGE IN LOW SEG
	CAIGE	T3,(T4)		;IS IT ABOVE HIGH SEG?
	JRST	VIRC12		;NO
	SUBI	T3,-1(T4)
	MOVNS	T3		;RIGHT SIGN (NEGATIVE)
	HRLI	T4,(PG.GAF!PG.IDC) ;RIGHT FUNCTION
	DMOVEM	T3,.JDAT+JOBUAL##+2 ;MUST DELETE THOSE TOO
	MOVE	T3,[.PAGCD,,JOBUAL##+2] ;SET SECOND UUO ARG POINTER
	MOVEM	T3,.JDAT+JOBUAL##+6
	JRST	VIRC13		;CONTINUE
;HERE IF NO NON-SHARABLE HI SEG TO WORRY ABOUT
VIRC11:	LDB	T2,PCORSZ##	;DELETE TO HIGHEST PAGE
	AOS	T2		;GET THOSE OFF-BY-ONES
VIRC12:	SETZM	.JDAT+JOBUAL##+6 ;NO SECOND PAGE UUO
VIRC13:	SUBI	T2,(T1)	;# OF PAGES TO DELETE
	MOVNM	T2,.JDAT+JOBUAL##
;HERE TO ALLOCATE OR DEALLOCATE CORE VIA PAGE UUO (LOW SEG)

VIRC14:	MOVE	R,JBTADR##(J)
	SKIPN	.JDAT+JOBUAL##	;ANYTHING AT ALL TO DO?
	SKIPE	.JDAT+JOBUAL##+6;?
	CAIA			;YES
	JRST	 VIRC18
	SETZ	T1,
	PUSHJ	P,SVPCS##	;JOBUAL IS IN S0
IFN FTMP,<
	PUSHJ	P,INTLVL##	;INTERRUPT LEVEL?
	  PUSHJ	P,REMMM##	;NO, GIVE UP THE MM
>
	MOVEI	T2,JS.ASA
	TDNE	T2,JBTSTS##(J)	;SHADOW ACS?
	SKIPA	T2,[EXCH T1,.JDAT+0] ;YES, USE AC 0 THERE
	MOVE	T2,[EXCTUU <EXCH	T1,0>] ;ELSE USE USER AC 0
	SKIPN	.JDAT+JOBUAL##	;ANYTHING TO DO IN FIRST UUO?
	SKIPA	T1,.JDAT+JOBUAL##+6 ;NO, MUST BE IN SECOND THEN
	MOVE	T1,[.PAGCD,,JOBUAL##] ;YES, WHERE ARG IS
	XCT	T2		;STORE
	PUSH	P,M		;SAVE M
	PUSH	P,T1		;USER'S AC 0
	PUSH	P,T2		;AND INSTRUCTION TO PUT IT BACK
	SKIPN	.JDAT+JOBUAL##	;ANY FIRST UUO TO DO?
	JRST	VIRC15		;NO, JUST DO SECOND THEN
	MOVE	T1,[.PAGCD,,JOBUAL##]
	SETZ	M,		;ARG LIST POINTER
	PUSHJ	P,UPAGE.	;DO THE UUO
	  JRST	VIRC17		;OH WELL
	SKIPN	T1,.JDAT+JOBUAL##+6 ;SECOND UUO TO DO?
	JRST	VIRC16		;NO, JUST SUCCEED THEN
	XCT	(P)		;SET UP USER AC
VIRC15:	SETZ	M,
	MOVE	T1,.JDAT+JOBUAL##+6 ;ARG POINTER
	PUSHJ	P,UPAGE.	;DO IT
	  CAIA			;OOPS
VIRC16:	AOS	-3(P)
VIRC17:	POP	P,T2		;INSTR
	POP	P,T1		;USER AC 0
	POP	P,M
	XCT	T2
	SKIPA	R,JBTADR##(J)
VIRC18:	SKIPA	R,JBTADR##(J)
	POPJ	P,
	AOS	(P)
	POPJ	P,
;HERE FOR HIGH SEGMENT STUFF - PRESERVE J AS HIGH SEG #+BITS

VIRC19:	MOVE	J,.USJOB
VIRC20:	PUSHJ	P,VIRC14
	  CAIA
	AOS	(P)
	MOVE	J,JBTSGN##(J)	;INCLUDE BITS IN RETURN
	MOVE	R,JBTADR##(J)
	POPJ	P,

;SUBROUTINE TO SET UP .UPVRT ACCORDING TO THE PAGE INVOLVED
;ENTER J=LOW SEG NUMBER, T1=PAGE
JSTVRT::PUSHJ	P,TPAHS		;HIGH-SEG PAGE?
	  SKIPG	T2,JBTSGN##(J)	;YES, IS THERE A HI SEG?(SHOULD SKIP)
	PJRST	SETVRT		;LOW SEG- CALL SETVRT
	PUSH	P,J		;HIGH SEG - SAVE J
	MOVE	J,T2		;SET J TO HI SEG NUMBER
	PUSHJ	P,SETVRT	;CALL SETVRT
	PJRST	JPOPJ##		;RESTORE J AND RETURN

;SUBROUTINE TO SET UP .UPVRT
;ENTER J=SEGMENT NUMBER
SETVRT:	PUSHJ	P,SEGSIZ##	;GET PHYSICAL SIZE OF THIS SEG
	CAIG	J,JOBMAX##
	JRST	STVRT1
	LDB	T1,PCORSZ##
	MOVSI	T3,(HRROS)
	JRST	STVRT3
STVRT1:	SKIPN	T1,.USREL	;NUMBER OF CONTIGUOUS PAGES
	HLRZ	T1,R		;IF .UPREL = 0, ALL PAGES ARE CONTIGUOUS
	LSH	T1,W2PLSH##	;CONVERT TO NUMBER OF PAGES
	ADD	T1,.USMEM	;TOTAL NUMBER OF PAGES, BOTH PHYSICAL AND VIRTUAL
	ADD	T1,.USNCR	;IN-CORE NZS PAGES
	ADDI	T1,UPMPSZ##	;LOW SEG, ACCOUNT FOR UPMP
STVRT2:	MOVSI	T3,(HLLOS)	;WORK WITH RH(UPVRT)
STVRT3:	SKIPE	R
	CAIN	T2,1(T1)	;PHYS SIZE = VIRTUAL SIZE?
	TLC	T3,30000	;YES, CONVERT HXXOS TO HXXZS
	HRRI	T3,.USVRT
	MOVE	T1,.USVRT	;SAVE CURRENT UPVRT
	TRZ	T1,777		;CLEAR .UPANA BITS FROM .UPVRT
	XCT	T3		;SET/CLEAR HALF OF .UPVRT
	SKIPE	T3,.USANA	;ANY ANA PAGES?
	MOVEI	T3,777		;YES, SET THAT PART OF .USVRT
	DPB	T3,[POINT 9,.USVRT,35]
	MOVE	T3,.USVRT	;GET CURRENT VALUE OF .USVRT
	TRZ	T3,777
	SKIPE	T3		;IF .UPVRT DIDN'T CHANGE
	JUMPN	T1,STVSIZ	; FROM 0 TO NON-0 OR VICE-VERSA
	SKIPN	T3
	JUMPE	T1,STVSIZ	;RETURN
	PUSHJ	P,VRTSZ		;YES, GET CURRENT TOTAL VIRT SIZE OF JOB
	SKIPE	T3		;IF WENT FROM 0 TI NON-0
	MOVNS	T2		; DECREASE VMCMAX
	ADDM	T2,VMCMAX##	;INCR/DECR VMCMAX
	MOVNS	T2
	ADDM	T2,VMTOTL##
STVSIZ::PUSH	P,J
	MOVE	J,.USJOB
	PUSHJ	P,VMSIZE
	CAIE	T1,0		;"CORE 0?"
	SUBI	T1,UPMPSZ##	;NO, DISCOUNT UPMPSZ
	DPB	T2,HIVSIZ##	;STORE NEW HIGH SEGMENT SIZE
	DPB	T1,LOVSIZ##	;AND LOW SEGMENT SIZE
	JRST	JPOPJ##		;AND RETURN
;SUBROUTINE TO ENSURE THAT THERE ARE NO MAP ENTRIES
;ENTER T1=NEW HIGHEST ADR, T2=CURRENT HIGHEST ADR
;EXITS CPOPJ IF SOME PAGE EXISTS IN THE RANGE, CPOPJ1 IF OK
;PRESERVES ALL ACS
;NOTE THAT THIS ROUTINE CANT BE CALLED FOR STARTING ADR AT PAGE 0
CKNZ1::	PUSHJ	P,SAVT##	;SAVE T1-T4
	ADDI	T1,1		;CONVERT TO HIGHEST PAGE
	ADDI	T2,1		; ..
	TRZ	T1,777		;DON'T SHIFT JUNK TO LH(T2)
	LSHC	T1,W2PLSH##	; ..
	JRST	CKNZ2		;CHECK THAT RANGE OF PAGES

;ENTER HERE IF THE ARGS ARE IN PAGES
CKNZP::	PUSHJ	P,SAVT##	;SAVE T1-T4
CKNZ2:	PUSHJ	P,SAVE1##	;SAVE A P
	SE1ENT
	MOVEI	T4,-1(T2)	;STARTING PAGE NUMBER - 1 FOR ILDB
	SUB	T1,T2		;NUMBER OF PAGES TO CHECK
CKNZ3:	EXCH	T1,T4		;REQUIRED FOR NZS MAPPING ROUTINES
	MOVE	T3,T2		;SAVE ORIGINAL STARTING PAGE IN T3
	LSHC	T1,P2SLSH##	;GET SECTION #
CKNZ4:	CAILE	T1,MXSECN
	STOPCD	.,STOP,EMS	;++EXCEEDING MAXIMUM SECTION
	SKIPE	.UPMP+SECTAB(T1) ;DOES SECTION EXIST?
	JRST	[MOVE	P1,T1
		 JRST	CKNZ5	] ;YES, MAP IT AND START
	ANDI	T3,HLGPNO	;SAVE ONLY PAGE #
	SUBI	T3,HLGPNO	;# OF PAGES TO THE BOUNDARY
	ADD	T4,T3		;THAT MANY PAGES LESS TO CHECK
	JUMPLE	T4,CPOPJ1##	;DONE
	SETZB	T3,T2		;STARTING AT PAGE 0 OF NEW SECTION
	AOJA	T1,CKNZ4	;LOOK AGAIN
CKNZ5:	LSHC	T1,S2PLSH##	;RESTORE STARTING PAGE #
	EXCH	T1,T4		;AND SET ACS UP AGAIN
	PUSHJ	P,GMPTR		;GET A BYTE POINTER TO THE MAP
CKNZ6:	AOS	T4
	MOVE	T2,(T4)		;GET CONTENTS OF MAP SLOT
	JUMPN	T2,CPOPJ##	;LOSE IF NON-ZERO
	TRC	T4,777		;ABOUT TO GO OVER SECTION BOUNDARY?
	TRCN	T4,777		;(EASIER TO TEST ZEROES)
	JRST	[SOJLE T1,CPOPJ1##	;NOTHING TO CHECK ANYWAY
		 SETZB	T3,T2	;YES, CYCLE FOR NEXT SECTION
		 MOVE	T4,P1 ;CURRENT SECTION MAPPED
		 AOS	T4	 ;NEXT SECTION TO CHECK
		 LSH	T4,S2PLSH## ;STARTING ADDRESS
		 JRST	CKNZ3	] ;AND MAP IT
	SOJG	T1,CKNZ6	;LOOP OVER ALL NEW PAGES
	PJRST	CPOPJ1##	;ALL ARE ZERO, WIN RETURN
;SUBROUTINE TO DETERMINE IF A RANGE OF ADDRESSES OVERLAP THE HIGH
;SEGMENT CALLING SEQUENCE:
;	MOVE	T3,HIGHEST ADDRESS,,STARTING ADDRESS
;	MOVE	T1,SECTION #	;IF CALLING CKHSZ, THEN SECTION # IS ZERO
;				;AND THIS IS NOT REQUIRED
;				;(ONLY RH OF T1 NEED BE SET UP)
;	PUSHJ	P,CKHSO/Z	;SEE IF ADDRESSES OVERLAP THE HIGH SEGMENT
;RETURNS CPOPJ IF THE ADDRESSES OVERLAP THE HIGH SEGMENT,CPOPJ1 IF THEY
;DON'T . PRESERVES ALL AC'S

CKHSZ:	PUSH	P,T1	;SAVE T1
	SETZ	T1,		;SECTION TO CHECK IN
	PUSHJ	P,CKHSO
	  JRST	TPOPJ##		;..
	JRST	TPOPJ1##

CKHSO:	PUSHJ	P,SAVE2##	;SAVE WORKING AC'S
	PUSH	P,J		;SAVE J
	MOVE	J,.USJOB	;LOAD JOB #
	LDB	P1,JBYSG2##	;SECTION HIGH SEG IS IN
	CAIE	P1,(T1)		;SECTION DESIRED?
	JRST	JPOPJ1##	;NO, NO OVERLAP THEN
	POP	P,J		;RESTORE J
	HLRZ	P1,T3		;HIGHEST ADDRESS IN THE RANGE
	HRRZ	P2,T3		;STARTING ADDRESS
	CAML	P1,.USHSS	;HIGHEST ADDRESS BELOW THE START OF THE HISEG?
	CAMLE	P2,.USHSE	;STARTING ADDRESS ABOVE THE END OF THE HISEG?
	AOS	(P)		;YES, ALL IS GOODNESS
	POPJ	P,		;RETURN
;SUBROUTINE TO ZERO PAGES ALLOCATED TO A JOB (LOW SEGMENT)
; WHEN THE JOB HAS A NON-SHARABLE HIGH SEGMENT
; CALLED ONLY ON A SWAP-IN
;CALLING SEQUENCE:
;	MOVE	J,SEGMENT NUMBER
;	PUSHJ	P,ZERHGH
;	...	RETURNS HERE (PAGES HAVE BEEN ZEROED)
;	...	RETURNS	HERE IF PAGES CAN BE ZEROED IN TRADITIONAL FASHION
;		T1=NUMBER OF WORDS TO ZERO
;MUST BE CALLED IN SECTION 1
ZERHGH::CAILE	J,JOBMAX##	;A HIGH SEGMENT?
	JRST	CPOPJ1##	;YES, KISER CAN ZERO THE PAGES
	PUSH	P,J		;SAVE THE JOB NUMBER
	SKIPLE	J,JBTSGN##(J)	;DOES THIS JOB HAVE A HIGH SEGMENT?
	TLNE	J,SHRSEG	;AND IS IT NON-SHARABLE?
	JRST	JPOPJ1##	;NO, KISER CAN ZERO THE PAGES
	PUSH	P,T2		;SAVE HIGHEST ADDRESS ALLOCATED
	HRRZS	J		;ZERO JUNK FOR SEGSIZ (MAY BE IN SECTION 1)
	PUSHJ	P,SEGSIZ##	;GET THE SIZE OF THE HIGH SEGMENT
	EXCH	T2,(P)		;T2 = HIGHEST ADDRESS ALLOCATED
	SUB	T2,(P)		;T2 = HIGHEST ADDRESS IN THE LOW SEG
	LSH	T1,W2PLSH##	;NUMBER OF PAGES TO ZERO
	MOVEM	T1,(P)		;SAVE THAT
	MOVE	J,-1(P)		;RESTORE THE JOB NUMBER
	PUSHJ	P,SNPAGS##	;FIND THE FIRST PAGE TO ZERO
	POP	P,T3		;RESTORE NUMBER OF PAGES TO ZERO
ZERHG1:	MOVE	T2,T1		;SETUP ARGUMENT TO ZPAGE
	PUSHJ	P,ZPAGE		;ZERO THE PAGE
	SSX	T1,MS.MEM	;PAGTAB SECTION
	HRRZ	T1,PAGTAB(T1)	;NEXT PAGE TO ZERO
	SOJG	T3,ZERHG1	;LOOP OVER ALL PAGES
	JRST	JPOPJ##		;INDICATE PAGES HAVE BEEN ZEROED
IFN FTIPCF,<
	SUBTTL	IPCF INTERFACE
;SUBROUTINE TO REMOVE A PAGE FROM A JOBS ADDRESS SPACE
;ENTER WITH T1= VIRTUAL PAGE NUMBER, J= JOB NUMBER (JOB ADDRESSABLE)
;ENTER ALSO WITH P3=ADDRESS OF TARGET IPCF PACKET, IF IPCF
;OR P3=0 IF NOT (COMCON).  THIS IS SO WE KNOW TO CALL MIGRATE WAITING
;ROUTINES IF P3 =/= 0
;RETURNS CPOPJ IF PAGE NOT IN JOBS ADDRESSING SPACE
;RETURNS CPOPJ1 NORMALLY, T2=PHYSICAL PAGE NUMBER IF PAGE IN CORE,
; OR T2 = BIT 18 + DSK ADDRESS IF PAGE IS ON DSK
;ON NORMAL RETURN, THE IPCF INTERLOCK AND MM WILL BE HELD FOR THE TARGET
;JOB IF P3 =/= 0 ON ENTRY.
IPCRMV::JUMPE	T1,CPOPJ##	;CANT REMOVE PAGE 0
	PUSHJ	P,LGLPG		;LEGAL PAGE NUMBER?
	  POPJ	P,		;NO
	PUSHJ	P,TPSHS
	  POPJ	P,		; OR A PAGE IN SHARABLE HI SEG
	SE1ENT			;FOR PAGE MAP ENTRY
	PUSHJ	P,GTPME		;GET MAP ENTRY
	JUMPE	T2,CPOPJ##	;ERROR IF PAGE NOT ALLOCATED
	TLZ	T2,(PM.NAD)	;KEEP ONLY ADDRESS
	CAMN	T2,[PM.ZER]	;OR IF ABZ
	JUMPN	P3,CPOPJ##	;ERROR IF NOT SAVE
IFN FTPEEKSPY,<
	PUSHJ	P,TSSPT		;ERROR IF A SPY PAGE
	  CAIA
	POPJ	P,
>
IFN FTMP,<
	JUMPE	P3,[PUSHJ P,GGVMM##	;IF DOING THIS FOR COMCON
		    JRST  IPCRM1   ]
>
IFE FTMP,<
	JUMPE	P3,IPCRM1
>
	PUSHJ	P,IPMCHK##	;CHECK MIGRATE STUFF IF IPCF

IFN FTMP,<
	PUSHJ	P,UPMM##	;GET MM RESOURCE
>
IPCRM1:	PUSHJ	P,RMVPGI	;OK, REMOVE FROM MAP
	  JRST	IPCRM5		;DISK ADDR (OR ON OUT QUEUE)
	PUSH	P,T2		;SAVE ENTRY
	TLNE	T2,(PM.OIQ!PM.SSP) ;ON A QUEUE?
	JRST	IPCRM2		;YES
	MOVSI	T1,(UP.WHC)
	IORM	T1,.USBTS	;NO, WORKING SET CHANGED
	JUMPE	P3,IPCR1A	;IF FROM COMCON, MAKE PAGE NOWHERE
	TLO	T2,(PM.OIQ!PM.SSP)
	MOVEM	T2,(P)		;RETURN THE BITS FOR THE ENTRY
	MOVEI	T3,PAGSNQ##	;PUT ON THE SLOW QUEUE
	HRRZS	T1,T2		;CLEAR BOTH LEFT HALVES
	EXCH	T1,(T3)		;APPROPRIATE QUEUE
	SSX	T2,MS.MEM
	HRRM	T1,PAGTAB(T2)
	HLLZS	PT2TAB(T2)	;NO BACK
	SSX	T1,MS.MEM
	TRNE	T1,-1
	HRRM	T2,PT2TAB(T1)
	AOS	PAGSNC##
IPCRM9:	MOVEI	T1,.IPCFI##(P3) ;ADDRESS IN PACKET WHERE PAGE NUMBER GOES
	DPB	T1,NVPNT2	;LOW ORDER BITS
	ANDCMI	T1,<P2.VPN_-<^L<P2.VPN>+P2.SPN>> ;CLEAR LOW ORDER STUFF
	LSH	T1,<^D35-<^L<MT.JOB>+MT.SJB-1>-P2.SPN>
	TLO	T1,(MT.IPC)	;IPCF PAGE
	MOVEM	T1,MEMTAB(T2)	;SET HIGH ORDER OF ADDR+MT.IPC
IPCR2A:
IFN FTKL10&FTMP,<
	SETOM	SAVCTL##	;SWEEP CACHE
>
IPCRM3:	PUSHJ	P,DCVMT		;ADJUST VM COUNTERS
	PUSHJ	P,STVSIZ
	POP	P,T2
	PJRST	FIXAD1		; AND SKIP-RETURN

;HERE IF PAGE ON DISK (MAY BE ON IP OR OUT QUEUE TOO)

IPCRM5:	TLO	T2,IP.DSK##_-^D18 ;LIGHT DISK
	PUSH	P,T2		;SAVE FOR LATER RETURN
IPCRM6:	CAIE	T3,PAGIPQ##	;WAS IT ON THE IP QUEUE?
	JRST	IPCRM3		;NO, OUT QUEUE, DISK ADDR IS SAFE
	SSX	T4,MS.MEM	;POINT TO MEMTAB
	DPB	J,[POINT PT.SJB,PAGTAB(T4),<^L<PT.JOB>+PT.SJB-1>]
	MOVEI	T3,PIOWQ##	;PUT JOB INTO PAGING I/O WAIT
	DPB	T3,PJBSTS##	; UNTIL I/O IS DONE ON "IP" QUEUE
	PUSHJ	P,[IFN FTMP,<
		   PUSHJ P,REMMM## ;REMEMBER STATE OF THE MM
>
		   PJRST WSCHED##] ;WAIT
	TLZ	T2,IP.DSK##_-^D18
	PUSHJ	P,ONPOQ		;IS IT NOW ON THE PAGING QUEUE?
	  CAIA			;NO
	JRST	IPCRM6		;BE SURE IT'S NOW ON THE OUT QUEUE
	PUSHJ	P,GTPME		;GET PAGE ENTRY AGAIN
	JUMPE	T2,IPCRM3	;PAGE ON DISK, ADDRESS IS RIGHT
	SETZM	(T4)		;OOPS, MUST HAVE HAD ERROR AND IP2ERR PUT BACK
	TLZ	T2,(PM.NAD)	;ONLY ADDRESS
	TLO	T2,IP.DSK##_-^D18 ;SET DISK
	MOVEM	T2,(P)		;SAVE
	JRST	IPCRM6		;BE ABSOLUTELY SURE IT'S ON THE OUT QUEUE

;HERE IF IPCRMV CALLED FROM COMCON AND PAGE WAS IN CORE NOT ON ANY QUEUE
IPCR1A:	MOVSI	T1,IPCBIT
	SSX	T2,MS.MEM	;SET SECTION NUMBER
	IORM	T1,PAGTAB(T2)	;IPCF PAGE IN NO MAP
	JRST	IPCR2A		;CONTINUE

;HERE IF PAGE WAS ON ONE OF THE "IN" QUEUES
IPCRM2:	SSX	T2,MS.MEM	;SET INDEX
	JUMPN	P3,IPCRM9	;IF IPCSER, JUST UPDATE MEMTAB ADDR
	TLNE	T2,(PM.SSP)	;SLOW?
	SKIPA	T3,[PAGSNQ]	;YES
	MOVEI	T3,PAGINQ
	PUSHJ	P,RMVPFQ	;REMOVE
	TLZ	T2,(PM.NAD)	;CLEAR BITS
	MOVEM	T2,(P)		;STORE AS JUST PAGE #
	JRST	IPCR1A		;NOW IPCF PAGE NOWHERE (FOR COMCON)
;SUBROUTINE TO PAGE OUT A PAGE FOR IPCF
;ENTER J=JOB NO JOB ADDRESSABLE) T2=PHYS PAGE OR BIT 18+DSK ADR
;EXIT CPOPJ IF NO SWAPPING SPACE AVAILABLE OR IO ERROR
;EXIT CPOPJ1 IF ALL OK, T2=DSK ADDRESS OF PAGE
IPCPAG::TLNE	T2,(1B0+PM.OIQ+PM.SSP) ;DISK ADR?
	PJRST	CPOPJ1##	;YES, ITS ALREADY OUT
	PUSHJ	P,SAVE2##	;NO, SAVE SOME ACS
IFN FTMP,<
	PUSHJ	P,MMOWN##
	  PUSHJ	P,GGVMM##	;GUARD AGAINST RACES
>
	PUSH	P,U
	PUSHJ	P,IPCSSP	;ALLOCATE SWAPPING SPACE AND MAKE A SWPLST ENTRY
	PUSHJ	P,PGWAIT	;START THE IO AND WAIT FOR IT
	  SOS	-1(P)		;ERROR - NON SKIP RETURN
	HRRZ	P1,T2		;SWPLST INDEX
IFN FTIPCF,<
	PUSHJ	P,GVIPCP	;RETURN THE PAGE IF NOT ALREADY RETURNED
>;END FTIPCF
				; BY THE SWAPPER
	MOVE	T2,U		;GET DSK ADR IN T2 (+ BIT 18)
	PJRST	UPOPJ1##	;AND TAKE SKIP-RETURN

;SUBROUTINE TO ALLOCATE SWAPPING SPACE TO PAGE OUT AN IPCF PAGE
; RETURNS CPOPJ ALWAYS, T1 SETUP TO MAKE A SWPLST ENTRY

IPCSSP::PUSHJ	P,SAVE1##	;SAVE A WORKING AC
	SE1ENT			;MUST BE IN SECTION 1 TO ADDRESS MEMTAB
	MOVSI	P1,LOKPHB	;INDICATE SWAPPING OUT THIS PAGE
	IORM	P1,@[IW MS.MEM,PAGTAB(T2)] ;SO IT GETS LEFT ALONE BY LOKCON
	MOVE	P1,T2
	SKIPA	U,[PG.SLO+1]	;GET 1 PAGE ON SLOW SWAPPING MEDIUM
IPCSS1:	MOVEI	U,1
	PUSHJ	P,SWPSPC##
	  JRST	IPCSS1		;CANT GET ANY SPACE - ERROR RETURN
	TLO	T1,(MT.LEF)	;INDICATE LAST PAGE
	SSX	P1,MS.MEM	;SET SECTION NUMBER
	MOVEM	T1,MEMTAB(P1)	;SAVE DSK ADR IN MEMTAB
	MOVE	U,T1
	.CREF	MT.LEF
;	TLO	U,IP.DSK##_-^D18	;DSK ADR (+BIT 0)
	HRRZ	T1,P1		;CORE ADR
	LSH	T1,11		;MAKE SWPLST ENTRY
	TDO	T1,[SL.DIO+SL.IPC+1]	;OUTPUT 1 PAGE
	POPJ	P,		;RETURN
>	;END FTIPCF
IFN FTIPCF,<
;SUBROUTINE TO INSERT A PAGE INTO A JOBS ADDRESS SPACE
;ENTER J=JOB NUMBER (JOB ADDRESSABLE)
; T1=VIRTUAL PAGE NUMBER, T2=PHYSICAL PAGE NUMBER OR BIT 0 + DSK ADDRESS
;EXIT CPOPJ IF PAGE ALREADY EXISTS OR ERROR (NEW SIZE TOO BIG, IO ERROR)
;EXIT CPOPJ1 NORMALLY
;ON ERROR RETURN, T1 CONTAINS IPCFR. ERROR CODE FOR FAILURE
;(PAGING I/O, LIMIT EXCEEDED, ETC.)

IPCINS::PUSHJ	P,SAVE1##	;SAVE SOME ACS
IFN FTMP,<
	PUSHJ	P,MMOWN##
	  PUSHJ	P,GGVMM##	;MUST HAVE IF DON'T ALREADY
>
	MOVE	P1,T2		;REMEMBER ADR
	LSHC	T1,P2SLSH##	;CONVERT TO SECTION #
	SKIPE	.UPMP+SECTAB(T1);SECTION EXIST?
	JRST	IPCIN1		;PROCEED IF SO
	MOVEI	T4,1		;# OF SECTION MAP PAGES
	PUSH	P,P1		;SAVE ARG
	MOVEI	T3,1		;ONE PAGE OF INCREASE
	SKIPL	.USBTS		;ALREADY BIG?
	AOS	T3		;INCLUDE .WSBNZ
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,SZCHK		;MAKE SURE HE CAN GET MAP PHYSICALLY
	  JRST	[ADJSP P,-2	;FIX STACK
		 MOVEI T1,IPCRP%## ;;NO (PHYSICAL) ROOM (FOR MAP)
		 POPJ  P,   ]	;RETURN
	PUSHJ	P,GSMPGS
	PUSHJ	P,CRSMAP	;CREATE MAP
	POP	P,P1
IPCIN1:	SE1ENT			;ENTER SECTION 1
	LSHC	T1,S2PLSH##	;BACK TO PAGE #
	PUSHJ	P,GTPME		;GET MAP ENTRY
	JUMPN	T2,IPCI1B	;DUPLICATE PAGE ERROR
	MOVEI	T3,1		;ONE PAGE OF INCREASE
	PUSH	P,T1
	PUSHJ	P,SZCHK		;TRYING TO GET TO BIG?
	  TLO	P1,200000	;YES
	HLRZ	T3,.PDCVL##(W)	;GET CURRENT VIRTUAL LIMIT
	SKIPN	T3		;IF HE DOESN'T HAVE A LIMIT
	AOSA	T3		;THEN HE'S OK (FLAG FOR LATER)
	SUBI	T3,-UPMPSZ##(T1) ;EXCESS PAGES HE HAS
	POP	P,T1		;RESTORE T1
	JUMPG	T3,IPCI1C	;HE'S OK
IPCI1A:	SKIPA	T1,[IPCRV%##]	;NO ROOM (VIRTUAL LIMIT)
IPCI1B:	MOVEI	T1,IPCUP%##	;DUPLICATE PAGE
	POPJ	P,

IPCI1C:	MOVE	T2,P1		;ADDRESS TO T2
	TLZ	T2,(PM.NAD)	;CLEAR CRUD
	TLZE	P1,(PM.OIQ)	;ON AN "IN" QUEUE?
	JRST    [TLNE  P1,200000 ;TOO BIG?
	         JRST  IPCI2A	;YES, INSERT AS IS
		 TLZN  P1,(PM.SSP) ;SLOW?
		 SKIPA T3,[PAGINQ##] ;NO
		 MOVEI T3,PAGSNQ## ;YES
		 PUSHJ P,RMVPFQ	;REMOVE IT FROM THE QUEUE
		 JRST  IPCI7A]	;AND PUT IT IN THE JOB'S MAP
	TLZN	P1,IP.DSK##_-^D18 ;INSERTING A DSK ADR?
	JRST	IPCIN7		;NO

;HERE IF PAGE ON DSK
	TLNN	P1,200000	;IF TRYING TO GET TOO BIG OR
	JRST	IPCIN3		;SWAP PAGE IN FOR HIM
	JUMPLE	T3,IPCI1A	;ERROR IF CAN'T GO (MORE) VIRTUAL
IPCIN2:	TLZ	P1,(PM.NAD)	;KEEP GNLY ADDRESS
	TLO	P1,(PM.CSH!PM.WRT!PM.PUB!PM.AAB)	;SET ACCESS ALLOWED
	MOVEM	P1,(T4)		;SAVE DSK ADR IN MAP
	JRST	IPCIN9		;FINISH UP

;HERE IF PAGE ON QUEUE AND CAN'T PAGE IN FOR JOB

IPCI2A:	SSX	T2,MS.MEM	;PHYS PAGE INVOLVED (POINT TO MEMTAB)
	DPB	J,[POINT MT.SJB,MEMTAB(T2),<^L<MT.JOB>+MT.SJB-1>]
	DPB	T1,NVPNT2	;SET VIRTUAL PAGE # INVOLVED
	TLZ	P1,(PM.NAD^!PM.SSP) ;PARANOIA TO CLEAR JUNK BITS
	TLO	P1,(PM.OIQ!PM.CSH!PM.PUB!PM.WRT!PM.AAB)	;ON IN QUEUE
	MOVEM	P1,(T4)		;SAVE ENTRY IN MAP
	MOVSI	T4,(MT.IPC)	;CLEAR BIT IN MEMTAB
	ANDCAM	T4,MEMTAB(T2)
	JRST	IPCIN9		;CONTINUE

;HERE TO SWAP THE PAGE IN SO CAN PUT IT IN THE MAP
IPCIN3:	PUSH	P,T4		;SAVE MAP POINTER
IPCI3A:	PUSHJ	P,ONPOQ		;ON "IP" OR "OUT" QUEUE?
	  JRST	IPCIN5		;NO, "REALLY" OUT
	CAIE	T3,PAGIPQ##	;ON THE "IP" QUEUE?
	JRST	IPCIN4		;NO, ON THE "OUT" QUEUE
	SSX	T4,MS.MEM	;MEMTAB SECTION
	DPB	J,[POINT PT.SJB,PAGTAB(T4),<^L<PT.JOB>+PT.SJB-1>] ;SAVE JOB NUMBER SO CAN GET STARTED AGAIN
	MOVEI	T3,PIOWQ##	;PUT JOB INTO PAGING I/O WAIT
	DPB	T3,PJBSTS##	; UNTIL I/O IS DONE ON "IP" QUEUE
IFN FTMP,<
	PUSHJ	P,[PUSHJ P,REMMM## ;REMEMBER STATE OF THE MM
		   PJRST WSCHED##] ;WAIT
>
IFE FTMP,<
	PUSHJ	P,WSCHED##
>
	JRST	IPCI3A		;NOW TRY TO FIND IT ON A QUEUE
IPCIN4:	MOVE	P1,T2		;SAVE DISK ADDR
	HRRZ	T2,T4		;PHYSICAL PAGE NUMBER
	PUSHJ	P,RMVPFQ	;REMOVE PAGE FROM THE "OUT" QUEUE
	EXCH	P1,T2		;PHYSICAL PAGE TO P1, DSK ADDR TO T2
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,DLTPGD	;RECLAIM DISK SPACE
	POP	P,T1		;RESTORE T1
	POP	P,T4		;(FIX STACK - RESTORE MAP POINTER)
	JRST	IPCI7A		;AND PUT IT INTO THE JOB'S MAP

IPCIN5:	EXCH	T1,(P)		;SAVE VPN, GET POINTER
	SKIPG	BIGHOL##	;IS THERE A FREE PAGE IN CORE?
	JRST	IPCIN6		;NO
	LDB	T1,JBYLSA##	;FIRST PAGE OF JOB
	MOVEI	T2,1
	PUSHJ	P,ADPAGS##	;AND INSERT ANOTHER PAGE THERE
	SSX	T1,MS.MEM	;SECTION WHICH CONTAINS MEMTAB
	TLZ	P1,(PM.NAD)
	TLO	P1,(MT.LEF)	;LAST
	MOVEM	P1,MEMTAB(T1)
	MOVE	P1,(P)
	DPB	P1,NVPNT1
	HRRZ	P1,T1		;PHYSICAL PAGE NUMBER IN P1
	MOVE	T1,(P)		;GET VIRTUAL PAGE NUMBER
	PUSHJ	P,INSPAG	;PUT THE NEW PAGE IN THE MAP
	MOVE	T1,P1		;RESTORE PHYSICAL PAGE NUMBER
	LSH	T1,11		;MAKE A SWPLST ENTRY
	TDO	T1,[SL.IPC+1]	; 1 PAGE, IPC-TYPE
	S0PSHJ	PAGEIT		;SWAP IN (S0PSHJ SO RETURN IN S1, WILL FALL
				;INTO S0 IF STARTING I/O
	  JRST	IPCI10		;IO ERROR - RETURN
	POP	P,T1		;OK, RESTORE VIRT PAGE NO
	PUSHJ	P,GTPME		;SET UP POINTER TO MAP SLOT
	JRST	IPCIN8		;AND CONTINUE
;HERE WHEN NOT ENOUGH CORE IN CORE
IPCIN6:	TLZ	P1,(PM.NAD)
	MOVEM	P1,(T1)		;SAVE DSK ADDR IN MAP
	MOVE	T1,(P)		;VIRTUAL PAGE NUMBER
	PUSHJ	P,INSDWE	;PUT DSK ADR IN MAP
	LDB	T1,IMGIN##	;SIZE OF JOB
	ADDI	T1,1		;IT WILL GROW BY 1 PAGE
	PUSHJ	P,XPANDP##	;GET THE PAGE INTO CORE
IFN FTMP,<
	PUSHJ	P,DIFMM##	;GIVE UP MM
>
	PUSHJ	P,WSCHED##	;WAIT FOR THE SWAP TO HAPPEN
IFN FTMP,<
	PUSHJ	P,UIFMM##	;RESTORE MM
>
	POP	P,T1		;RESTORE VIRT PAGE NO.
	JRST	IPCIN9		;AND FINISH UP

;HERE WHEN PAGE IS IN CORE
IPCIN7:	TLZE	P1,200000	;PHYSICAL LIMIT EXCEEDED?
	JRST	IPCI11		;YES, SEE ABOUT PUTTING PAGE ON QUEUE
	SOS	%CNPIC##	;DECREMENT COUNT OF IPCF PAGES IN CORE
IPCI7A:	TLZ	P1,(PM.NAD)	;PARANOIA
	PUSHJ	P,INSPAG	;INSERT THE PAGE IN THE JOB'S MAP
	LDB	T3,JBYLSA##	;FIRST PAGE IN THE LOW SEGMENT
	SSX	T3,MS.MEM	;TO ADDRESS PAGTAB SECTION
	MOVE	T2,PAGTAB(T3)	;ADD THIS PAGE TO THE FRONT
	HRRM	P1,PAGTAB(T3)	; OF THIS JOB'S PAGTAB LIST
	SSX	P1,MS.MEM	;PAGTAB SECTION
	HRRZM	T2,PAGTAB(P1)	;(CLEAR IPCBIT IN LH)
	HRRM	T3,PT2TAB(P1)
	SSX	T2,MS.MEM
	HRRM	P1,PT2TAB(T2)
IPCIN8:	MOVSI	T2,(UP.WHC)	;WORKING SET HAS CHANGED
	IORM	T2,.USBTS	;TURN THAT ON FOR THE PAGE FAULT HANDLER
IPCIN9:	PUSHJ	P,ICUPR		;BUMP UPREL IF THIS PAGE CONTIGUOUS
	HRL	P1,T1		;FIX UP JBTADR, JOBREL, ETC
	HRROI	T1,777000	;IF JOB IS VIRTUAL NOW,
	AND	T1,.USVRT	;MUST COUNT PAGE IN VMCMAX NOW
	JUMPE	T1,IPCI9A
	AOS	VMTOTL##	;INCREMENT AMOUNT OF VM IN USE
	SOS	VMCMAX##
IPCI9A:	PUSHJ	P,SETVRT	;ADJUST COUNTS, ETC.
	PJRST	FIXADR		; AND TAKE SKIP RETURN TO USER

;HERE ON A PAGING IO ERROR
IPCI10:	HRRZ	P1,T2		;INDEX INTO SWPLST
	PUSHJ	P,DLTSLX	;ZAP THE SWPLST ENTRY
	POP	P,T1		;RESTORE THE VIRTUAL PAGE NUMBER
	PUSHJ	P,DLTPAG	;RETURN THE PAGE
	MOVEI	T1,IPCIE%##	;PAGING I/O ERROR
	POPJ	P,

;HERE IF PAGE IS IN CORE, BUT WE CAN'T FIT IT INTO THE JOBS PHYS LIMIT
;PUT THE PAGE ON THE "IN" QUEUE AND PUT THE DISK ADDR IN THE MAP
;T1=VIRT PAGE #, T4 HAS MAP POINTER, T2 & P1 HAVE PHYS PAGE # + SOME
;EXTRANEOUS BITS IN P1

IPCI11:	HRLI	P1,(PM.OIQ!PM.AAB!PM.CSH!PM.PUB!PM.WRT)
	MOVEM	P1,(T4)		;SAVE POINTER IN MAP
	SSX	P1,MS.MEM	;POINT TO MEMTAB
	SETZM	MEMTAB(P1)	;CLEAR JUNK IN MEMTAB
	DPB	J,[POINT MT.SJB,MEMTAB(P1),<^L<MT.JOB>+MT.SJB-1>]
	DPB	T1,[POINT P2.SPN,PT2TAB(P1),<^L<P2.VPN>+P2.SPN-1>]
	EXCH	T2,PAGINQ##	;MAKE FIRST PAGE ON IN QUEUE
	HRRZM	T2,PAGTAB(P1)	;POINT US AT HIM (CLEARING IPCBIT)
	SKIPE	T2		;IF THERE IS A PAGE
	HRRM	P1,@[IW MS.MEM,PT2TAB(P1)] ;THEN SET BACK LINK TOO
	HLLZS	PT2TAB(P1)
	AOS	PAGINC##	;INCREMENT
	JRST	IPCIN9		;FINISH UP
;SUBROUTINE TO DELETE A PAGE FROM CORE OR DISK
;ENTER T2=ADR OF PAGE (BIT 0 ON IF DSK)
;ALWAYS RETURNS CPOPJ
;ENTER AT IPCDEL IF %CNPIC IS TO BE ADJUSTED IF PAGE WAS IN CORE, AT
;IPCDLX IF NOT

IPCDLX::
	TDZA	T1,T1		;FLAG TO NOT CHANGE %CNPIC
IPCDEL::
	SETO	T1,
	SE1ENT
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN MM?
	  PUSHJ	P,GGVMM##	;NO, GET IT
>
	TLZ	T2,(<PM.NAD^!<PM.OIQ!PM.SSP!1B0>>) ;CLEAR ALL BUT THESE
	TLZE	T2,(PM.OIQ+PM.SSP) ;PAGE ON THE "IN" QUEUE?
	JRST	[MOVEI T3,PAGSNQ##
		 PUSHJ P,RMVPFQ	;REMOVE IT FROM THE "IN" QUEUE
		 JRST DLTPGC]	;DELETE PAGE FROM CORE AND RETURN
	PUSH	P,T2		;SAVE ADDRESS
	TLZE	T2,(1B0)	;JUST DISK ADDRESS
	PUSHJ	P,ONPOQ		;PAGE ON "IP" OR "OUT" QUEUE?
	  JRST	IPCDE1		;NO, JUST A GARDEN VARIETY PAGE
	SSX	T4,MS.MEM	;MEMTAB SECTION
	CAIE	T3,PAGIPQ##	;ON THE IN PROGRESS QUEUE?
	JRST	[SETZM MEMTAB(T4) ;MAKE SURE ITS NOT FOUND ON A QUEUE SEARCH
		 PUSHJ P,DLTPGD	;NO, "OUT" QUEUE, GIVE BACK DISK SPACE
		 JRST T2POPJ##]	;RESTORE T2 AND RETURN
	MOVSI	T2,(MT.GPB)	;GIVE BACK DISK SPACE WHEN I/O COMPLETES
	IORM	T2,MEMTAB(T4)
	JRST	T2POPJ##	;AND GIVE PAGE ON DISK RETURN

IPCDE1:	POP	P,T2		;RESTORE PAGE NUMBER OR DISK ADDRESS
	TLZE	T2,(1B0)	;DSK?
	JRST	DLTPGD		;YES
	ADDM	T1,%CNPIC	;ADJUST %CNPIC IF NECESSARY
	JRST	DLTPGC		;NO
;SUBROUTINE TO RETURN IPC PAGES TO THE FREE CORE LIST
;CALLING SEQUENCE:
;	PUSHJ	P,GVIPCP
;ALWAYS RETURNS CPOPJ

GVIPCP::SKIPN	IPCCNT##	;ANY IPCF PAGES WHICH HAVE PAGING OUTPUT DONE?
	POPJ	P,		;NO, RETURN
	PUSHJ	P,SAVE2##	;SAVE SOME WORKING ACS
GVIPC1:	MOVEI	P1,SWPLST##	;START LOOKING AT THE BEGINNING OF SWPLST
	MOVE	P2,SLECNT##	;NUMBER OF ENTRIES IN SWPLST
GVIPC2:	SKIPE	T1,(P1)		;A NON-ZERO SWPLST ENTRY?
	TLNN	T1,(SL.IOD)	;YES, IS I/O DONE FOR THIS SWPLST ENTRY?
GVIPC3:	AOJA	P1,GVIPC2	;NO, LOOK AT THE NEXT SWPLST ENTRY
	TLC	T1,(SL.IPC)	;BE SURE NOT PAGING QUEUE ENTRY
	TLNN	T1,(SL.SIO!SL.IPC) ;AN IPCF PAGE? (WANT SL.IPC CLEAR SO THIS
				;PAGE WON'T BE SEEN AGAIN)
	TLNN	T1,(SL.DIO)	;AND WAS IT BEING PAGED OUT?
	JRST	GVIPC4		;NO, LOOK AT THE NEXT SWPLST ENTRY
	PUSH	P,T1		;SAVE SWPLST INDEX
	SUBI	P1,SWPLST	;DLTSLE WANTS RELATIVE INDEX
	PUSHJ	P,DLTSLX	;REMOVE THE SWPLST ENTRY
	POP	P,T1		;RESTORE SWPLST INDEX
	LDB	T1,[POINT 13,T1,26]
	MOVSI	P1,IPCBIT+LOKPHB
	PUSHJ	P,IPCLKP	;LINK PAST IF REQUIRED
	PUSHJ	P,GVPAGS##	;RETURN THE PAGE TO THE FREE CORE LIST
	SOSG	IPCCNT##	;DECREMENT THE COUNT OF IPCF PAGES PAGED OUT
	POPJ	P,		;RETURN IF NO MORE
	JRST	GVIPC1		;ELSE, LOOK FOR THE NEXT ONE
GVIPC4:	SOJG	P2,GVIPC3	;LOOK AT THE NEXT SWPLST ENTRY
	STOPCD	GVIPC5,DEBUG,IPN,	;++IPC PAGE NOT FOUND
GVIPC5:	SETZM	IPCCNT##	;ZERO IPCCNT TO AVOID A LOOP
	POPJ	P,		;AND RETURN

;SUBROUTINE TO LINK PAST THE PAGTAB PAGE FOR ABOVE.  ONLY A SUBROUTINE
;SO CAN USE SE1ENT

IPCLKP:	SE1ENT			;ENTER SECTION 1
	HRRZ	P2,T1		;PAGE #
	SSX	P2,MS.MEM	;SECTION NUMBER
	ANDCAB	P1,PAGTAB(P2)	;NO LONGER AN IPCF PAGE
	PUSH	P,P1		;SAVE SUCCESSOR
	HRRZ	P1,PT2TAB(P2)	;GET PREDECESSOR
	CAMN	T1,LMPAG##	;LAST MONITOR PAGE?
	MOVEM	P1,LMPAG##	;UPDATE
	HLLZS	PT2TAB(P2)	;CLEAR LINKS THIS PAGE
	SETZM	PAGTAB(P2)
	POP	P,P2		;RESTORE SUCCESSOR
	TRNE	P1,-1
	HRRM	P2,@[IW MS.MEM,PAGTAB(P1)]
	TRNE	P2,-1
	HRRM	P1,@[IW MS.MEM,PT2TAB(P2)]
	POPJ	P,
>	;END FTIPCF!FTEXE
	SUBTTL	SEGCON

;SUBROUTINE TO RETURN CORE ALLOCATED TO A NON-SHARABLE HIGH SEGMENT
;ENTER WITH JOB NUMBER -2(P), PHYSICAL SEGMENT SIZE -1(P)
KCOREV::LDB	T1,IMGIN##	;SIZE OF THE SEGMENT
	JUMPN	T1,KCOREH##	;IF NON-ZERO, ITS SHARABLE AND SEGCON CAN
				; GIVE BACK THE PAGES
	MOVE	T2,J		;SAVE HIGH SEG #
	MOVE	J,-2(P)		;GET THE JOB NUMBER
	PUSHJ	P,SVEUB##	;SETUP THE UBR TO POINT AT THE CURRENT JOB
	LDB	T1,JBYSG2##	;GET SECTION #
IFN FTXMON,<
	PUSHJ	P,SVPCS##
>
	MOVE	J,T2
	MOVEI	T1,0		;ASKING FOR 0K OF CORE
	PUSHJ	P,CORE1##	;RETURN THE CORE
	  STOPCD .+1,DEBUG,CMS,	;++CORE1 MUST SKIP
IFE FTXMON,<
	SETZM	-5(P)		;SO SEGCON WON'T CHANGE VIRTAL WHICH
				; WAS ALREADY MADE RIGHT BY VIRCHK
>
IFN FTXMON,<
	SETZM	-11(P)		;SVPCS USES MORE STACK
>
	POPJ	P,
;GENERALIZED REMAP (GIVEN A COLLECTION OF CONTIGUOUS PAGES, MOVE
; THEM TO THE VIRTUAL ADDRESS SPECIFIED BY THE USER AND MAKE THEM A
; HIGH SEGMENT)
;CALLING SEQUENCE:
;	MOVE	J,CURRENT JOB NUMBER
;	MOVE	T1,CURRENT STARTING VIRTUAL PAGE NUMBER
;	MOVE	T2,NEW STARTING VIRTUAL PAGE NUMBER
;	MOVE	T3,NUMBER OF PAGES
;	MOVSI	T4,FLAGS	;AS FOLLOWS:
;		1B0		;ON=NON-SHARABLE NEW HIGH SEG, OFF=SHARABLE
;		1B1		;APPEND TO EXISTING HIGH SEG IF ON
;RETURNS CPOPJ IF ARGUMENTS ARE WRONG, PAGES IN THE RANGE SPECIFIED
; DON'T ALL EXIST, OR MOVING THE PAGES TO THE VIRTUAL ADDRESSES
; SPECIFIED WOULD CAUSE THE HIGH SEGMENT AND LOW SEGMENT TO OVERLAP
;RETURNS CPOPJ1 IF EVERYTHING IS OK, NEW HIGH SEGMENT NUMBER IN J
NREMAP::TLO	M,400000	;CAUSE ERRORS TO JUST RETURN RATHER THAN GOING STOTAC
	JUMPLE	T3,IALERR	;REMAPPING NO PAGES IS ILLEGAL
	PUSHJ	P,SAVE4##	;SAVE WORKING ACS
	MOVE	J,.USJOB	;CURRENT JOB NUMBER
	DMOVE	P1,T1		;SAVE ARGUMENTS
	DMOVE	P3,T3		; ..
	PUSHJ	P,LGLPG		;IS CURRENT STARTING VIRTUAL PAGE A LEGAL PAGE NUMBER?
	  POPJ	P,		;NO
	MOVE	T1,P2		;IS NEW STARTING VIRTUAL PAGE A LEGAL PAGE NUMBER?
	PUSHJ	P,LGLPG		; ..
	  POPJ	P,		;NO
	ANDI	T1,HLGPNO	;DOES NEW SEGMENT
	ADDI	T1,-1(P3)	;CROSS A SEGMENT BOUNDARY?
	TRNE	T1,-1^!HLGPNO	;?
	JRST	ILPERR		;YES, THIS IS NOT ALLOWED
	MOVE	T1,P1		;RESTORE STARTING VIRTUAL PAGE NUMBER
	SE1ENT			;FOR REFS
NREMA1:	LSHC	T1,P2SLSH##	;SECTION #
	SKIPN	.UPMP+SECTAB(T1);EXIST?
	JRST	PMEERR		;NO, ERROR
	LSHC	T1,S2PLSH##
	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE USER'S MAP
	JUMPE	T2,PMEERR	;(REDO RELOCATION)
IFN FTPEEKSPY,<
	PUSHJ	P,TSSPT		;A SPY PAGE?
>
	PUSHJ	P,TPAHS		;IS THIS A HIGH SEGMENT PAGE?
	  JRST	PSHERR		;YES, THAT'S ILLEGAL
	ADDI	T1,1		;NEXT PAGE
	SOJG	T3,NREMA1	;CHECK ALL PAGES BEING REMAPPED
	TLNN	P4,(1B1)	;DON'T KILL OLD HIGH SEG?
	S0PSHJ	KILHSH##	;REMOVE JOB'S CURRENT HIGH SEG
	CAMN	P1,P2		;NSA=OSA?
	JRST	NREMA4		;YES, NOTHING TO CHECK
	MOVE	T1,P2		;NSA
	ADD	T1,P3		;NSA+L
	CAML	P2,P1		;NSA.LT.OSA?
	JRST	NREMA2		;NO
	MOVE	T2,P2		;NSA
	CAMLE	T1,P1		;NSA+L.LE.OSA?
	MOVE	T1,P1		;NO, CHECK NSA TO OSA
	JRST	NREMA3		;YES, CHECK NSA TO NSA+L
NREMA2:	MOVE	T2,P1		;OSA
	ADD	T2,P3		;OSA+L
	CAMG	T2,P2		;OSA+L.GT.NSA?
	MOVE	T2,P2		;NO, CHECK NSA TO NSA+L
;	JRST	NREMA3		;YES, CHECK OSA+L TO NSA+L
NREMA3:	PUSHJ	P,CKNZP		;MAKE SURE PAGES BEING REMAPPED DON'T OVERLAP
				; OTHER PAGES IN THE PROGRAM'S ADDRESS SPACE
	  JRST	PCEERR		;THEY DO, GIVE PAGE CANNOT EXIST BUT DOES ERROR
NREMA4:	TLNE	P4,(1B1)	;WANT NEW HIGH SEG?
	SKIPN	J,JBTSGN##(J)	;NO, UNLESS THERE ISN'T ONE
	PUSHJ	P,FNDSGN##	;FIND A SEGMENT NUMBER FOR THE JOB'S NEW HI SEG
	TLNE	J,SHRSEG	;CAN'T ADD TO/FIDDLE WITH SHARABLE THIS WAY
	JRST	PSHERR		;..
	HRRZS	J
	SKIPN	JBTADR##(J)	;DON'T CHANGE ORIGIN IF APPENDING
	DPB	P2,JBYHSO##	;STORE THE VIRTUAL PAGE NUMBER OF THE HI SEG ORIGIN
	PUSH	P,J		;SAVE THE NEW HIGH SEGMENT NUMBER
	ROT	P2,P2SLSH##	;DESTINATION SECTION
	SKIPN	JBTADR##(J)	;APPENDING?
	SKIPA	J,.USJOB	;NO, LOAD JOB #
	SKIPA	J,.USJOB	;APPENDING, STILL LOAD JOB #
	DPB	P2,JBYSG2##	;SET SEGMENT
	ROT	P2,S2PLSH##	;MOVE BACK
	TLNE	P4,(1B1)	;ADDING TO EXISTING HS?
	JRST	[LDB	T1,JBYHSS## ;YES, PICK UP OLD SIZE
		 ADDI	T1,(P3)	;NEW SIZE
		 DPB	T1,JBYHSS## ;SET IT
		 JRST	NREMA5 ] ;DON'T AFFECT ORIGIN
	MOVE	T1,P2		;GET NEW STARTING PAGE NUMBER
	LSH	T1,P2SLSH##	;STARTING SECTION NUMBER
	DPB	T1,JBYSG2##	;STORE IT AS HIGH SEG ORIGIN FOR THIS USER
	DPB	P3,JBYHSS##	;STORE THE NEW HIGH SEGMENT'S SIZE
NREMA5:	JUMPL	P4,NREMA7	;JUMP IF NON-SHARABLE
	MOVN	T1,P3		;NUMBER OF PAGES IN THE NEW HIGH SEGMENT
	HRL	T1,P1		;STARTING PAGE NUMBER OF THE OLD HIGH SEGMENT
	MOVSS	T1		;MAKE AN ABOJN POINTER
NREMA6:	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE USER'S MAP
	TLZ	T2,(PM.NAD)	;CLEAR ACCESS BITS
	PUSH	P,T1		;SAVE THE AOBJN POINTER
	PUSH	P,T2		;AND THE PHYSICAL PAGE NUMBER
	PUSHJ	P,LKPSF		;LINK PAST THE PAGE IN PAGTAB
	PUSHJ	P,SCNPTB	;FIND THE PAGE AND ITS PREDESSOR IN PAGTAB
	POP	P,T2		;RESTORE THE PHYSICAL PAGE NUMBER
	SSX	T1,MS.MEM	;SET PAGTAB SECTION
	MOVEM	T2,PAGTAB(T1)	;LINK AROUND THIS PAGE, AND
	SSX	T2,MS.MEM	;DITTO
	HLLZS	PAGTAB(T2)	; INDICATE THAT THIS IS NOW THE LAST PAGE IN THE LIST
	HRRM	T1,PT2TAB(T2)
	POP	P,T1		;RESTORE THE AOBJN POINTER
	AOBJN	T1,NREMA6	;AND LOOP UNTIL ALL HIGH SEGMENT PAGES
				; ARE IN PAGTAB IN THE SAME ORDER THAT THEY APPEAR
				; IN THE JOB'S MAP
	TLZ	P4,(1B0)	;HIGH SEG IS SHARABLE
NREMA7:	CAML	P1,P2		;MOVING THE PAGES UP?
	TDZA	T1,T1		;NO, DOWN OR REMAP IN PLACE
	MOVEI	T1,-1(P3)	;NUMBER OF PAGES - 1
	HRLS	T1		;OFFSET
	HRLS	P1		;FIRST PAGE
	HRR	P1,P2		;DESTINATION PAGE
	ADD	P1,T1		;SOURCE,,DESTINATION
	PUSH	P,P4		;SAVE SHARABILITY ATTRIBUTE
	MOVEI	P4,0		;BECAUSE THERE ARE ONLY 16 ACS
	PUSH	P,P4		; ..
NREMA8:	HRRZ	T1,P1		;GET DESTINATION PAGE
	LSH	T1,P2SLSH##	;SECTION #
	SKIPE	.UPMP+SECTAB(T1);SECTION EXIST?
	JRST	NREMA9		;YES
	PUSH	P,P1		;NO, MUST CREATE IT
	MOVEI	T4,1		;# OF MAPS TO CREATE
	PUSHJ	P,GSMPGS	;GET PAGES
	PUSHJ	P,CRSMAP	;CREATE SECTION MAP & .WSBNZ IF MUST
	POP	P,P1		;RESTORE P1
NREMA9:
NREM10:	MOVE	T1,P1		;SOURCE PAGE,,DESTINATION PAGE
	PUSHJ	P,MV1PG		;REMAP THE PAGE
	SKIPGE	T3,-1(P)	;SHARABLE HIGH SEGMENT?
	JRST	NREM11		;NO
	DPB	T3,T4		;YES, CLEAR THE WORKING SET BIT
	MOVSI	T4,(PM.AAB)
	ANDCAM	T4,(T1)		;CLEAR ACCESS ALLOWED
	PUSH	P,T1		;SAVE BYTE POINTER TO THE MAP
	PUSHJ	P,DCVMT		;ADJUST COUNTS
	POP	P,T1		;RESTORE BYTE POINTER TO THE MAP
NREM11:	MOVE	T3,(T1)		;YES, GET THE CONTENTS OF THE MAP
	TLZ	T3,(PM.WRT)	;WRITE PROTECT THE PAGE
	TLO	T3,(PM.NIA)	;SET NO I/O ALLOWED
	MOVEM	T3,(T1)		;STORE THE WRITE PROTECTED ENTRY IN THE MAP
	JUMPE	T2,NREM12	;WAS THE LOW SEGMENT PAGE IN THE WORKING SET?
	AOS	(P)		;COUNT THE NUMBER OF PHYSICAL PAGES IN THE HIGH SEGMENT
NREM12:	HLRZ	T1,P1		;SOURCE PAGE
	HRRZ	T2,P1		;DESTINATION PAGE
	MOVE	T4,-1(P)	;SHARABILITY/APPEND ATTRIBUTE
	TLNE	T4,200000	;APPEND?
	SKIPA	T3,.USHSS	;YES, DON'T AFFECT .USHSS
	SKIPA	T3,T2
	LSH	T3,W2PLSH##	;SO THE REST WORKS RIGHT
	CAIGE	T1,(P1)		;MOVING PAGES DOWN?
	JRST	NREM13		;NO
	TLNN	T4,200000	;DON'T CHANGE IF APPEND
	SUB	T3,P4		;YES
	AOBJP	P1,NREM14	;BUMP SOURCE,,DESTINATION PAGES
NREM13:	ADD	T2,P4		;MOVING PAGES UP
	SUB	P1,[1,,1]	;DECREMENT SOURCE,,DESTINATION
NREM14:	LSHC	T2,P2WLSH##	;CONVERT TO WORDS
	TRO	T2,PG.BDY##	;NEXT PAGE BOUNDARY - 1
	DMOVEM	T2,.USHSE	;STORE END, BEGINNING OF HS
	PUSHJ	P,ISITNZ	;NZS PAGE?
	  TDZA	T2,T2		;GO TO DCUPN1
	MOVEI	T2,DECNCR-DCUPN1 ;GO TO DECNCR
	PUSHJ	P,DCUPN1(T2)
	CAIGE	P4,-1(P3)	;REMAPPED ALL THE PAGES REQUESTED?
	AOJA	P4,NREMA8	;NO, REMAP THE NEXT PAGE
	HRRZS	.USHSE		;MAKE SURE THESE ARE SECTION RELATIVE
	HRRZS	.USHSS
	HLRZ	T1,P1		;LAST PAGE MOVED
	CAIGE	T1,(P1)		;MOVING PAGES UP?
	ADDI	P1,1(P3)	;YES, HIGHEST PAGE = NEW ORGIGIN + NUMBER OF PAGES
	MOVEI	T1,-1(P1)	;HIGHEST VIRTUAL PAGE IN THE HIGH SEGMENT
	LSH	P1,P2WLSH##	;CONVERT TO WORDS
	SUBI	P1,1		;PAGE BOUNDARY - 1
	HRRM	P1,.JDAT+JOBHRL## ;STORE HIGHEST VIRTUAL ADDRESS IN HI SEG FOR THE USER
	POP	P,P2		;RESTORE NUMBER OF PHYSICAL PAGES IN HI SEG
	POP	P,P4		;AND SHARABALITY
	MOVE	J,(P)		;RESTORE THE HIGH SEGMENT NUMBER
	TLNN	P4,(1B1)	;ADDING TO OLD SEGMENT?
	TDZA	T2,T2		;NO
	HLRZ	T2,JBTSWP##(J)	;YES, ADD TO OLD NUMBER NEW NUMBER
	ADDI	P2,(T2)
	JUMPGE	P4,NREM15	;JUMP IF THE HIGH SEGMENT IS SHARABLE
	HRLM	P2,JBTSWP##(J)	;STORE THE NUMBER OF IN CORE PAGES IN THE HI SEG
	SETZM	JBTIMI##(J)	;AND CLEAR SIZES
	SETZM	JBTIMO##(J)
	JRST	NREM16		;AND SKIP ON
NREM15:	PUSHJ	P,GTPME		;PHYSICAL PAGE WHICH CORRESPONDS TO THE
	MOVE	T3,T2		; THE HIGHEST VIRTUAL PAGE IN THE HIGH SEGMENT
	DPB	P2,IMGIN##	;STORE THE SIZE OF THE HIGH SEGMENT
	LDB	T1,JBYHSO##	;HIGH SEGMENT STARTING VIRTUAL PAGE
	MOVE	J,.USJOB	;CURRENT JOB NUMBER
	LDB	T2,JBYSG2##	;GET SECTION TOO
	LSH	T2,S2PLSH##
	IORI	T1,(T2)
	PUSHJ	P,GTPME		;GET MAP CONTENTS (PHYSICAL PAGE)
	MOVE	P4,T2		;SET ARGUMENT TO SCNPT
	LDB	T1,IMGIN##	;DECREASE LOW SEGMENT SIZE BY THE NUMBER OF
	SUBI	T1,(P2)		; PAGES MAPPED INTO THE HIGH SEGMENT
	DPB	T1,IMGIN##
	TLZ	P4,(PM.NAD)	;SAVE ONLY PAGE #
	HRRZ	P4,@[IW MS.MEM,PT2TAB(P4)]
	TLZ	T3,(PM.NAD)	;PHYSICAL PAGE OF THE TOP OF THE HIGH SEGMENT
	SSX	T3,MS.MEM	;PAGTAB SECTION
	SSX	P4,MS.MEM	;DITTO
	MOVE	T1,PAGTAB(T3)	;GET ITS LINK
	HLLZS	PAGTAB(T3)	;TERMINATE PAGTAB LINKED LIST FOR THE HIGH SEGMENT
	HRRM	T1,PAGTAB(P4)	;LINK PAGES PAST THE HI SEG TO THE LOW SEG
	SSX	T1,MS.MEM
	TRNE	T1,-1		;IF NO PAGE
	HRRM	P4,PT2TAB(T1)
NREM16:	MOVE	J,.USJOB	;BE SURE POINTING @JOB
	LDB	T1,JBYHSS##	;HIGHEST PAGE IN HIGH SEG
	LSH	T1,P2WLSH##	;CONVERT TO HIGHEST WORD
	SUBI	T1,1		;HIGHEST WORD - 1
	HRLI	T1,.VJDT	;VIRTUAL ADDRESS OF THE VESTIGUAL JOB DATA AREA
	LDB	T2,JBYSG2##	;GET HIGH SEG SECTION # BEFORE SWITCHING J
	MOVE	J,(P)		;SEGMENT #
	MOVSM	T1,JBTADR##(J)	;SAVE HIGH PROTECTION,,RELOCATION
	LDB	T1,JBYHSO##	;GET THE HIGH SEGMENT ORIGIN VIRTUAL PAGE
	LSH	T2,S2PLSH##	;SECTION TO PAGE
	IORI	T1,(T2)		;FULL PAGE #
	PUSHJ	P,GTPME		;GET THE HIGH SEGMENT ORIGIN PHYSICAL PAGE
	DPB	T2,JBYHSA##	;STORE THAT FOR REDOING THE HIGH SEGMENT MAP
	HRLI	T2,(<PM.DCD>B2+PM.WRT+PM.CSH+PM.PUB)
	MOVEM	T2,.UPMP+.UMVJD
	MOVE	J,.USJOB	;JOB # AGAIN
	CAME	J,.CPJOB##	;CURRENT JOB?
	JRST	NREM17		;NO, (VIRCHK) DON'T AFFECT .CPXXX
	MOVEM	R,.CPADR##	;STORE NEW LOW SEGMENT PROTECTION,,RELOCATION
	HLRZM	R,.CPREL##	;AND THE HIGHEST RELATIVE ADDRESS IN THE LOW SEGMENT
NREM17:	POP	P,J		;RESTORE SEGMENT #
	MOVS	T1,JBTADR##(J)	;FOR UREMAP
	MOVS	T1,JBTADR(J)	;FOR UREMAP
	HLRZM	R,.USHVA	;FOR ADDRESS CHECKING AT INTERRUPT LEVEL
	PJRST	FIXMJ1		;CLEAR THE A.M. AND SKIP RETURN
	SUBTTL	UUOCON  INTERFACE WITH UUO HANDLER AND IOCSS

;SUBROUTINE TO TEST IF A UUO PAGE-FAULT WILL OCCUR
;ENTER WITH T1=ADR TO BE TESTED
;NON-SKIP RETURN IF A PAGE FAULT WILL OCCUR, CPOPJ1 IF ADR IS OK
;PRESERVES ALL ACS
FLTST::	PUSH	P,T1		;SAVE T1
	EXCTUU	<MAP T1,(T1)>	;MAP THE PAGE
	PUSHJ	P,FLTCHK
	  JRST	TPOPJ##
	JRST	TPOPJ1##

FLTCHK::TLNN	T1,(MP.BAD)	;BAD FAIL OR
	TLNN	T1,(MP.BTS)	; NO INFO?
	POPJ	P,		;YES TO EITHER, WILL FAULT
	JRST	CPOPJ1##	;REF OK. WIN.
;CHKIND  -- CHECK A USER WORD FOR US TO INDIRECT OFF OF.
;CALL:
;	MOVE	T1,[USER BYTE POINTER]
;	PUSHJ	P,CHKIND
;	 FAIL, ON ADDRESS CHECK OF SOME SORT
;	SUCCESS, T1 CONTAINS RESOLVED BYTE POINTER
;TRASHES M
;NOTE - THIS AND CHKBPT WILL HAVE TO BE RE-WRITTEN WHEN AND IF USER-MODE
;EXTENDED ADDRESSING IS IMPLEMENTED, SINCE NEITHER TRY TO SOLVE FOR THAT
;CASE (THINK OF ONE-WORD GLOBAL BYTE POINTERS! YIKES!)

CHKIND::TLNN	T1,(17B17)	;CHECK FOR INDEXING FIRST
	JRST	CHKAT		;NONE, CHECK FOR INDIRECTING
	PUSH	P,T1		;SAVE CURRENT ADDRESS
	LDB	T1,[POINT 4,T1,17] ;EXTRACT AC FROM INDEX FIELD OF WORD
	DPB	T1,[POINT 4,M,12] ; AND PLACE IT INTO AC FIELD OF A UUO
	PUSHJ	P,GETTAC##	;   SO GETTAC CAN RETURN US THE AC CONTENTS
	HRRZS	T1		;USE RIGHTMOST 18 BITS OF AC ONLY
	ADD	T1,(P)		;SIMULATE INDEXING BY ADDING RH TO ADDRESS
	POP	P,(P)

CHKAT:	TLNN	T1,(1B13)	;INDIRECT BIT ON?
	JRST	CPOPJ1##	;NOPE - ADDRESS IS RESOLVED
	HRRI	M,(T1)		;ADDRESS (RH ONLY) FOR GETWRD TO USE
	PUSHJ	P,GETWRD##	;GET THE WORD, DOING ALL CHECKS
	  POPJ	P,		;ADDRESS CHECK - LET CALLER HANDLE THIS
	PUSHJ	P,SCDCHK##	;GIVE OTHER JOBS A CHANCE, AND USER A CHANCE
				; TO ^C OUT OF THIS (IF HE GAVE US A LOOP).
	JRST	CHKIND		;START OVER AGAIN, WITH NEW ADDRESS
;CHKINS  -- CHECK A USER WORD FOR US TO INDIRECT OFF OF.
;CALL:
;	MOVE	T1,[USER INSTRUCTION WORD]
;	PUSHJ	P,CHKINS
;	  <ERROR RET>	ADDRESS CHECK OF SOME SORT
;	<SKIP RETURN>	ON SUCCESS
;ON SUCCESS RETURN, T1 CONTAINS RESOLVED ADDRESS AND T2 CONTAINS SECTION OF
; REFERENCE (USEFUL WHEN T1 POINTS TO AN AC).  LH(T2) INDICATES WHETHER
; REFERENCE WAS GLOBAL OR LOCAL.
;PRESERVES ALL OTHER ACS
;IMPLICITLY USES PCS -- CALL AT CHKINX WITH SECTION-NESS IN T2 TO OVERRIDE

;FOR REAL INDIRECT WORDS (RATHER THAN INSTRUCTION WORDS), THERE ARE ANALOGOUS
;ROUTINES NAMED CHKEFI AND CHKEFX.

CHKINS::
IFN FTXMON,XSFM	T2		;GET DEFAULT SECTION OF REFERENCE
CHKINX::SE1ENT			;SPEED UP GETEWD SLIGHTLY
IFN FTXMON,PUSHJ P,SAVE2##	;FOR SCRATCH ACS
	PUSH	P,M		;SAVE PRESERVED AC
IFN FTXMON,<			;HARD CASES ONLY FOR MULTI-SECTION MACHINES
	ANDI	T2,(SECMSK)	;KEEP ONLY SECTION NUMBER FROM XSFM
CIFIW:	PUSH	P,T1		;SAVE FOR LATER INDIRECTION CHECK
	SETZM	P2		;REMEMBER DOING IFIW
	HRRZ	P1,T1		;GET Y FIELD
	LDB	M,[POINT 4,T1,12] ;AND X FIELD
	HRLI	T1,(T2)		;INCLUDE SECTION IN CASE NO INDEXING
	JUMPE	M,CIFIW6	;GO TEST INDIRECTION IF NOT
	PUSHJ	P,GETWDU##	;YES, FETCH INDEX REGISTER CONTENTS
	MOVE	M,T1		;SCRATCH COPY
	JUMPE	T2,CIFIW2	;IF SECTION 0 INDEX
	JUMPL	M,CIFIW2	;OR LH(X) .LT. 0
	TLNN	M,-1		;OR LH(X) .EQ. 0
CIFIW2:	TLZA	T1,-1		;THEN ONLY 18-BITS OF INDEXING
	HRRE	P1,P1		;ELSE SIGN-EXTEND Y TO 36-BITS
	ADD	T1,P1		;DO THE INDEXING
	JUMPE	T2,CIFIW4	;IF SECTION 0
	JUMPL	M,CIFIW4	;OR LH(X) .LT. 0
	TLNN	M,-1		;OR LH(X) .EQ. 0
	JRST	CIFIW4		;THEN LOCAL INDEXING
	SETOM	P2		;FLAG GLOBAL INDEXING
	CAIA			;DON'T DIDDLE SECTION
CIFIW4:	HRLI	T1,(T2)		;E STAYS IN LOCAL SECTION
	TLZ	T1,770000	;30-BIT ADDRESSING
	HLR	T2,T1		;SAVE SECTION FOR NEXT ITERATION

;CHECK IFIW INDIRECTION

	SKIPE	P2		;LOCAL INDEXING?
	TDNN	T1,[^-1,,^-17]	;NO, GLOBAL REFERENCE TO AC?
CIFIW6:	TRNE	T1,^-17		;IS LOCAL REFERENCE TO A REGISTER?
	CAIA			;NO, MEM. REF.
	ANDI	T1,17		;YES, REDUCE TO OBVIOUS AC (SECTION-NESS IN T2)
	POP	P,M		;GET BACK ORIGINAL WORD
	TLNN	M,20		;IFIW I BIT ON?
	JRST	CEFIW9		;NO, CHECK OUT AC'S AND RETURN
CIFIW8:	PUSHJ	P,SCDCHK##	;YES, ALLOW USER TO ^C AND/OR SYSTEM TO SCHEDULE
	MOVE	M,T1		;GET ADDRESS OF NEW ADDRESS
	PUSHJ	P,GETEWD##	;FETCH IT
	  JRST	MPOPJ##		;PROPAGATE FAILURE
CIFIW9:	JUMPE	T2,CIFIW	;ONCE IN SECTION 0, ALWAYS HAVE IFIW'S
	JUMPGE	T1,CEFIW	;EFIW IF NOT MARKED AS IFIW
	TLNN	T1,(1B1)	;MAKE SURE NOT RESERVED FORMAT
	JRST	CIFIW		;NO, JUST ANOTHER IFIW
	JRST	MPOPJ##		;YES, GIVE FAILURE RETURN

CHKEFI::XSFM	T2		;SETUP DEFAULT SECTION OF REFERENCE
CHKEFX::PUSHJ	P,SAVE2##	;GET SOME SCRATCH ACS
	PUSH	P,M		;SAVE PRESERVED AC
	ANDI	T2,(SECMSK)	;KEEP ONLY SECTION NUMBER FROM XSFM
	JRST	CIFIW9		;DISPATCH ON TYPE OF INDIRECTION

CEFIW:	PUSH	P,T1		;SAVE FOR LATER INDIRECTION CHECK
	SETOM	P2		;EFIW'S GIVE GLOBAL RESULTS
	LDB	M,[POINT 4,T1,5] ;LOAD EFIW X FIELD
	TLZ	T1,770000	;Y FIELD ONLY IN T1
	MOVE	P1,T1		;SCRATCH COPY
	JUMPE	M,CEFIW6	;SKIP INDEXING IF NO INDEX REGISTER
	PUSHJ	P,GETWDU##	;FETCH CONTENTS OF INDEX REGISTER
	ADD	T1,P1		;INDEX THE Y FIELD
	TLZ	T1,770000	;30-BIT ADDRESSING

;CHECK EFIW INDIRECTION

CEFIW6:	POP	P,M		;GET BACK ORIGINAL WORD
	HLR	T2,T1		;KEEP SECTION OF REFERENCE FOR RETURN
	TLNE	T1,(1B1)	;CHECK EFIW I BIT
	JRST	CIFIW8		;ITERATE IF ON
				;CHECK OUT RETURN VALUE IF NOT

;CHECK AC ADDRESSING AND VALIDATE RANGE

CEFIW9:	TLNE	T1,^-<(SECMSK)>	;CHECK THAT FINAL ADDRESS IS LEGAL
	JRST	MPOPJ##		;FAIL IF NOT
	HRL	T2,P2		;GET EA-IS-GLOBAL FLAG IN LH(T2)
	TDNN	T1,[^-1,,^-17]	;AC REFERENCE?
	SKIPN	T2		;FROM NON-ZERO SECTION?
	JRST	MPOPJ1##	;NO, JUST RETURN SUCCESSFULLY
	HRLI	T1,1		;YES, MAKE PROPER GLOBAL AC REFERENCE
	JRST	MPOPJ1##	;GIVE SUCCESS RETURN

> ;END OF IFN FTXMON

IFE FTXMON,<			;EASY CASE FOR NON-EXTENDED MACHINES
CHKIN0:	PUSHJ	P,CHKIND	;DO AN EA-CALC
	  JRST	MPOPJ##		;PROPAGATE FAILURE
	SETZ	T2,		;RETURN SECTION NUMBER
	ANDI	T1,-1		;CLEAR NON-ADDRESS BITS
	JRST	MPOPJ1##	;RETURN SUCCESS

CHKEFI==:CHKINS			;NO DIFFERENCE ON S0-ONLY MACHINE
CHKEFX==:CHKINX			;DITTO

> ;END OF IFE FTXMON
;CHKBPT  --  RANGE CHECK A BYTE POINTER AFTER RESOLVING INDIRECT AND INDEXING
;CALL IS:
;
;	MOVE	T1,[BYTE POINTER TO USER VIRTUAL SPACE]
;	MOVEI	T2,NUMBER OF BYTES
;	PUSHJ	P,CHKBPT
;	 ON ADDRESS CHECK
;	ON SUCCESS, T1 CONTAINS RESOLVED BYTE POINTER
;TRASHES M
;WILL NOT WORK ON A KI OR A KA.

CHKBPT::PUSHJ	P,SAVE2##	;GET SOME PRESERVED REGISTERS
	LDB	P2,[POINT 6,T1,5] ;GET P FIELD OUT OF BYTE POINTER
	CAILE	P2,44		;IF IT IS GREATER THAN WORD SIZE, IT IS OWGBP
	POPJ	P,		;ERROR RETURN.
	MOVE	P2,T2		;SAVE BYTE COUNT
	HRLZI	P1,777740	;FIELD CONTAINING BYTE SIZE AND COUNT
	AND	P1,T1		;GET BYTE SIZE AND COUNT INTO SAVED REGISTER
	XOR	T1,P1		;WIPE SAID BITS IN T1 (FIGURE THIS ONE OUT!)
	PUSHJ	P,CHKIND	;RESOLVE INDIRECTION AND INDEXING IN ADDRESS
	  POPJ	P,		;ADDRESSING ERROR OF SOME SORT
	IOR	P1,T1		;ADD IN RESOLVED ADDRESS TO BYTE SIZE AND COUNT
	ADJBP	P2,P1		;GET A BYTE POINTER TO THE END OF THE STRING
	TLZ	P2,-1		;MAKE IT BE NOTHING BUT AN ADDRESS
	MOVEI	M,1		;1 BYTE
	ADJBP	M,P1		;GET POINTER TO FIRST BYTE (SINCE ILDB POINTER)
CHKBPN:	TLZ	M,-1		;MAKE IT BE AN ADDRESS
	PUSHJ	P,GETWRD##	;TRY TO GET THE WORD (CALL PFH MAYBE)
	  POPJ	P,		;CAN'T, ERROR RETURN
	TRO	M,777		;POINT M AT THE LAST WORD IN THAT PAGE
	AOJ	M,		;MAKE THAT THE FIRST WORD IN THE NEXT PAGE
	CAIG	M,(P2)		;WAS THE END OF STRING IN THAT PAGE?
	JRST	CHKBPN		;NO, TRY THE NEXT PAGE
	MOVE	T1,P1		;GET BYTE POINTER TO RETURN
	JRST	CPOPJ1##	;SUCCESS RETURN
;BRNGE  --  RANGE CHECK A USER I/O BUFFER
;CALL IS:
;
;	MOVX	T1,<BUFFER>
;	PUSHJ	P,BRNGE
;	RETURN
;
;WHERE <BUFFER> IS THE USER VIRTUAL ADDRESS OF THE .BFHDR WORD OF THE
;USER BUFFER (THE SECOND WORD OF THE BUFFER HEADER).
;
;	***   MAY ONLY BE CALLED AT UUO LEVEL   ***
;
;IF AN I/O-ILLEGAL ADDRESS IS GIVEN (IN PROTECTED JOBDAT OR IN USER'S
;HIGH SEGMENT) BRNGE DISPATCHES TO ADRERR TO GIVE AN ADDRESS CHECK; IF A
;PAGE FAULT OCCURS (ACCESS ALLOWED OFF OR PAGED OUT) BRNGE DISPATCHES TO
;THE PAGE FAULT HANDLER (WHICH WILL IN TURN RE-EXECUTE THE UUO . . .);
;IF A NONEXISTANT ADDRESS IS ENCOUNTERED BRNGE DISPATCHES TO ADRERR.
;
;ON RETURN THE ENTIRE BUFFER IS ADDRESSABLE.
;
;USES T1 AND T2.

BRNGE::	EXCTUX	<HLRZ T2,(T1)>	;GET BUFFER SIZE (DATA SIZE + 1)
	TRZ	T2,IOUSE	;REDUCE TO COUNT ALONE
	SUBI	T1,1		;T1:=START OF BUFFER AREA (.BFSTS WORD)
	ADDI	T2,1(T1)	;T2:=END OF BUFFER
				;FALL INTO LRNGE
;LRNGE  --  RANGE CHECK A BLOCK OF USER ADDRESS SPACE (I/O)
;TRNGE  --  RANGE CHECK A BLOCK OF USER ADDRESS SPACE (NON-I/O)
;CALL IS:
;
;	MOVX	T1,<FIRST>
;	MOVX	T2,<LAST>
;	PUSHJ	P,LRNGE/TRNGE
;	RETURN
;
;WHERE <FIRST> IS THE FIRST ADDRESS OF THE BLOCK TO BE ADDRESS CHECKED,
;AND <LAST> IS THE LAST ADDRESS OF THE BLOCK TO BE ADDRESS CHECKED.
;
;	***   MAY ONLY BE CALLED AT UUO LEVEL   ***
;
;IF ANY ADDRESS WITHIN THE RANGE <FIRST> TO <LAST> INCLUSIVE IS NOT
;I/O-LEGAL LRNGE WILL DISPATCH TO ADRERR (TRNGE WILL IGNORE); IF ANY
;ADDRESS WOULD CAUSE A PAGE FAULT (EITHER ACCESS ALLOWED OFF OR PAGED
;OUT) BOTH LRNGE AND TRNGE DISPATCH TO THE PAGE FAULT HANDLER (WHICH
;WILL RE-EXECUTE THE USER UUO); IF AN ADDRESS IS ENCOUNTERED WHICH
;IS NON-EXISTANT BOTH LRNGE AND TRNGE DISPATCH TO ADRERR.
;
;ON RETURN THE ENTIRE RANGE IS ADDRESSABLE.
;
;USES T1 AND T2.

LRNGE::	TLNE	T2,-1		;IF BUFFER WRAPS AROUND CORE
	PJRST	ADRERR##	; IT'S AN ADDRESS ERROR
	TLO	T2,400000	;INDICATE CALL TO LRNGE
TRNGE::	CAILE	T1,(T2)		;IF BUFFER WRAPS AROUND CORE
	JRST	UADERR##	;IT'S AN ADDRESS ERROR
XRNGE:	JUMPGE	T2,TRNGE1	;IF CALL TO LRNGE ENSURE I/O LEGAL ADDR
	PUSHJ	P,IADRCK##	;LEGAL ADDRESS?
	  JRST	ADRERR##	;NO, PAGE DOESN'T EXIST, HI SEG PAGE, OR SPY PAGE
	  JRST	UUOFLT		;PAGE FAULT
TRNGE1:	EXCTUX	<SKIP	(T1)>	;ENSURE ADDRESS IS ACCESSIBLE
	  ERJMP	UUOFLT		;IF NOT, CHECK FOR PAGE FAULT
	TRO	T1,PG.BDY##	;HIGHEST ADR IN THE PAGE
	CAIL	T1,(T2)		;CHECKED ALL REQUIRED PAGES?
	POPJ	P,		;YES, RETURN
	ADDI	T1,PAGSIZ##	;NO, STEP TO NEXT PAGE
	JRST	XRNGE		;AND TEST IT
;SUBROUTINE TO CHECK A RANGE OF ADDRESSES, CALLED FROM ANY LEVEL
;RETURNS CPOPJ IF SOME ADR NOT IN CORE (PAGE FAULT OR NON-EXISTANT)
;RETURNS CPOPJ1 IF EVERYTHING IS OK

ZRNGE::	TRO	T1,PG.BDY##	;TOP ADR IN PAGE
	PUSH	P,T2		;SAVE T2 FROM IADRCK
ZRNGE1:	PUSHJ	P,IADRCK##	;MAKE SURE PAGE LEGAL AND IN CORE
	  PJRST	T2POPJ##	;ILLEGAL ADR ERR
	  PJRST	T2POPJ##	;PAGE FAULT
	CAML	T1,(P)		;LEGAL, DONE?
	PJRST	T2POJ1##	;YES, GOOD RETURN
	ADDI	T1,PAGSIZ##	;NO, STEP TO NEXT PAGE
	JRST	ZRNGE1		;AND TEST IT
;SUBROUTINE TO TEST IF AN ADDRESS WILL GIVE A PAGE FAULT
;ENTER J= JOB NUMBER, R=RELOACATION, RH(M)=ADR TO TEST
;SKIP-RETURNS IF ADR IS OK OR WILL GIVE AN ADRESS ERROR
;DISPATCHES TO PAGE-FAULT HANDLER IF LEGAL, PAGE NOT IN CORE
; AND AT UUO LEVEL (NOT PI OR SCHEDULER)
;NON-SKIP RETURN IF PAGE-FAULT TYPE ADDRESS, NOT AT UUO LEVEL
;PRESERVES ALL ACS

FLTSX:	PUSH	P,T1		;SAVE ACS
	LDB	T1,[POINT 23,M,35]	;GET ADDRESS
FLTSX2:	PUSHJ	P,FLTST
	  JRST	FLTSX3		;NO, CHECK IF AT UUO LEVEL
	PJRST	TPOPJ1##	;AND GIVE OK RETURN

;HERE ON A PAGE-FAULT
FLTSX3:	CONSO	PI,PI.IPA	;PI LEVEL?
	SKIPE	.CPISF##	;NO, IN SCHEDULER?
	JRST	TPOPJ##		;YES, ERROR RETURN
	CAMN	J,.CPJOB##	;NO, IS THIS THE RUNNING JOB?
	PJRST	UUOFLT		;YES, CALL PFH
	PJRST	TPOPJ##		;ERROR

;HERE IF PAGE FAULT FROM GETWRD AND FRIENDS

FLTSY::	PUSH	P,T1		;SAVE ACS
	MOVE	T1,.USPFW	;GET PAGE FAIL WORD
	PJRST	FLTSX2		;AND FAULT

;SUBROUTINE TO INCREMENT JOBPD1
INCPD1::HRRZ	T2,.JDAT+JOBPD1##+1	;JOBPD1
	ADDI	T2,1		;+1 (CAN'T AOS, SINCE MIGHT = -1)
	HRRM	T2,.JDAT+JOBPD1##+1	;STORE BACK
	POPJ	P,		; AND RETURN
;SUBROUTINE TO CHECK ARGUMENTS TO A UUO
;ENTER T1=C(AC)  T3=CHECK-BITS FOR THE UUO
;CALLS PAGE FAULT HANDLER IF ERROR WILL OCCUR, RETURNS IF OK
;PRESERVES T1,T4
UUOCHK::MOVE	T2,JBTSTS##(J)	;GET JBTSTS FOR JOB
	TRNE	T2,JS.ASA	;JS.ASA ON?
	POPJ	P,		;YES, MONITOR KNOWS WHAT ITS DOING (???)
	PUSH	P,T1		;NO, SAVE T1
	TRNE	T3,UU.EA+UU.LER;EFFECTIVE ADR CHECK?
	SKIPA	T2,T1		;YES, GET ADR
	MOVE	T2,.JDAT+JOBPD1##+1	;NO, GET LOC OF UUO
	TRNE	T3,UU.CEA+UU.LER	;CHECK C(ADR)?
	JRST	UUOCH1		;YES
	TRNN	T3,UU.CAC	;NO, CHECK C(AC)?
	LDB	T1,[POINT 6,T3,35]	;NO, GET NO OF ARGS FROM T3
	JRST	UUOCH2		;AND CONTINUE

;HERE TO CHECK ADR
UUOCH1:	PUSH	P,M		;SAVE M
	HRR	M,T1		;LOC TO CHECK
	PUSHJ	P,GETWRD##	;GET C(EA)
	  JRST	UUOCH3		;BAD - CALL PFH
	POP	P,M		;RESTOR M
	TRNE	T3,UU.LER	;LOOKUP/ENTER/RENAME?
	TLNN	T1,-1		;YES, LH=0?
	TRZA	T1,770000	;YES, NUMBER OF ARGS ALREADY IN T1, CLEAR FUNNY BITS
	MOVEI	T1,3		;NO, CHECK 4 WORDS (TO ADR+3)
UUOCH2:	TRNE	T3,UU.MNS	;MINUS N?
	MOVNS	T1		;YES
	TRNN	T3,UU.LFT	;NO OF ARGS IN LH?
	TLZA	T1,-1		;NO, CLEAR LH
	HLRZS	T1		;YES, USE LH
	EXCH	T1,T2		;GET 1ST ADR, SAVE NUMBER
	TLZ	T1,-1
	SKIPN	T1		;GET TOP ADR (A+N-1) IN T2
	AOSA	T2,T1
	ADDI	T2,(T1)
	TRNN	T3,UU.LER
	SUBI	T2,1
	PUSHJ	P,XRNGE		;ALL PAGES IN CORE?
	PJRST	TPOPJ##		;YES, RETURN

;HERE WHEN ADR ITSELF ISN'T IN CORE
UUOCH3:	HRRZ	T1,M		;BAD ADR IN T1
	POP	P,M		;RESTORE M
	PJRST	UUOFLT		;AND CALL PFH
;HERE IF ARGUMENT NOT IN CORE - PAGE FAULT WILL OCCUR IF UUO PROCEEDS
;T1= BAD ADDRESS
UUOFL1:	POP	P,(P)		;MAKE THE LIST RIGHT

UUOFLT::NTGIVE			;RETURN THE NETSER INTERLOCK.
IFN FTMP,<
	PUSHJ	P,TGVMM##	;OWN THE MM?
>
	LDB	T3,[POINT UPGWID+9,T1,35] ;ADDR
	TLO	T3,(PF.BAD)	;INDICATE THIS IS FROM A UUO
	DMOVE	T1,.JDAT+JOBPD1## ;ADDR OF UUO
	SOS	T2		;(NOT RETURN PC)
	MOVE	J,.CPJOB##	;SET UP J
	TLNE	T1,(XC.USR)	;LOSE IF NOT USER MODE (COMCON)
	PUSHJ	P,USRFL1	;CALL PFH (GENERALLY DOESN'T RETURN)
	PJRST	UADERR##

;HERE ON A TIME INTERRUPT
TIMFLT::MOVE	P,[XWD MJOBPD##+2,.JDAT+JOBPDL##+2] ;SET UP P
	MOVE	J,.CPJOB##	;SET UP J
	SETZ	F,		;MAKE SURE F DOESN'T CONTAIN CRUD AT USER EXIT
	PUSHJ	P,FNDPDB##	;GET THE PDB
	  JRST	USRXIT		;IF NO FAULT DATA-IGNORE INTERRUPT
	DMOVE	T1,.USPFP	;GET PC
	DMOVEM	T1,.JDAT+JOBPD1## ;SAVE PC (IN JOBPD1)
	HRRZ	T3,.PDTMI##(W)	;RESET COUNTER--THIS MUST BE DONE AFTER
	JUMPE	T3,TIMFL1
	MOVEM	T3,.PDTMC##(W)	; RESET OF JOBPD1 TO PROTECT PSISER
	MOVEI	T3,0		;INDICATE TIME INTERRUPT
	PUSHJ	P,USRFL1	;CALL PFH
	JRST	USRXIT##	;CANT GET PFH - IGNORE INTERRUPT

;HERE IF USER HASN'T ENABLED FOR TIME INTERRUPTS
;RECOMPUTE THE FAULT-RATE AND DISMISS THE INTERRUPT
TIMFL1:	MOVEI	P1,1		;USE 1 PAGE AS BASIS
	PUSHJ	P,USRATE	;COMPUTE NEW PAGE-INTERVAL
	MOVE	T1,TICSEC##	;RECOMPUTE IN 1 SECOND
	MOVEM	T1,.PDTMC##(W)
	PJRST	USRXIT##	;GO RESTART USER JOB

;T4=PC WORD, T3=PAGE FAIL WORD

USRFLT::TDZA	T4,T4			;NORMAL ENTRY
USRFL1:	MOVEI	T4,USRFLY-USRFLZ
	PUSHJ	P,USRFLZ(T4)	;SUBROUTINE, SO CAN SET UP MAP
	  POPJ	P,		;JUST RETURN
	USERAC			;GIVE HIM BACK HIS ACS
	XJEN	.USMUO		;RETURN TO USER

USRFLZ:
	TLNE	T3,(PF.BAD)	;"BAD" TYPE FAULT?
	POPJ	P,		;YES, TOO BAD
	MOVE	J,.CPJOB##	;NO, SET J
	TLNN	T3,(PF.ACC)	;IF PAGE IS ACCESSIBLE, THIS MUST BE A HISEG.
	SKIPA	R,.CPADR##	;NO, SET UP R
	JRST	USRFL9		;YES, HANDLE SPECIALLY

;USRFLY - SOME COMMENTS: BIT PF.BAD, WHICH IN A NORMAL PAGE FAIL WORD IS USED
;	TO INDICATE A "BAD" FORM OF PAGE FAIL (PAGE FAIL CODE .GT. 20), IS
;	USED HERE TO INDICATE CALL FROM MONITOR UUO. USRFLT WILL NOT CALL US
;	IF THE BIT IS LIT, AND UUOFLT WILL ALWAYS LIGHT IT.
;
;	ALSO, BIT VM.ZER IS THE LOW ORDER BIT OF THE PAGE FAIL ADDRESS. THE
;	LOW ORDER BITS OF THE PF ADDRESS ARE NEVER USED, SO USING THIS BIT
;	IS LEGAL.

USRFLY:
	DMOVEM	T1,.USMUO	;SAVE PC DBLWRD
	SKIPN	.JDAT+.JBPFH##	;DO WE HAVE A PFH?
	JRST	PFH##		;CALL PFH (GENERALLY DOESN'T RETURN)
	JUMPE	T3,USRFL2	;GO IF A TIME INTERRUPT
	LDB	T4,[POINT UPGWID,T3,26]	;NOT TIME, GET VIRT PAGE NO.
IFN FTXMON,<
	TRNN	T4,<MXSECN_S2PLSH##> ;IS THIS AN EXTENDED PAGE?
	TLNE	T2,MXSECN	;OR IS THE PC EXTENDED?
	JRST	USRFLE		;YES, ILL MEM REF
>
	MOVEI	T1,(T3)		;GET PAGE FAULT ADDR AGAIN
	LSH	T1,W2PLSH##	;CONVERT TO PAGE #
	S1PSHJ	GTPME		;GET MAP CONTENTS
	JUMPE	T2,CPOPJ##	;GO IF NO PAGE
	TLZ	T2,(PM.NAD)
	CAMN	T2,[PM.ZER]	;PAGE EXISTS, IS IT ABZ?
	VM.ZER==1		;NAME A BIT. INSIGNIFICANT BIT OF PF ADDRESS
	TROA	T3,VM.ZER	;YES, REMEMBER THAT
	TRZ	T3,VM.ZER	;NO
USRFL2:	PUSHJ	P,FNDPDS##	;FIND PDB FOR JOB
	HRRZ	T1,.JDAT+.JBPFH##	;GET ADR OF PFH
	JUMPE	T1,GETPFH	;LOAD DEFAULT IF NONE THERE
	CAIL	T1,JOBPFI##	;PFH REALLY THERE?
	PUSHJ	P,FLTST
	  POPJ	P,		;NO, CAN'T DO ANYTHING
	ADDI	T1,5		;POINT TO TOP LOC TO STORE IN
	PUSHJ	P,FLTST		;IS TOP OF BLOCK THERE?
	  POPJ	P,		;NO, CAN'T DO GOOD THINGS FOR HIM
USRFL3:	JUMPE	T3,USRFL4	;IF NOT A TIME INTERRUPT,
	LDB	T1,[POINT UPGWID,T3,26]	;GET VIRTUAL PAGE
	HRL	T3,T1		;SAVE IN LH(T3)
	PUSHJ	P,TSWST		;IS PAGE IN WORKING SET?
	  JRST	USRFL5		;NO
	MOVSI	T2,(PM.AAB)
	TDNE	T2,.UPMAP(T1)
	STOPCD	.+1,DEBUG,WAD,	;++WSBTBL AND AABTBL DISCREPENCY
	MOVEI	T1,PC.PNA	;YES, SET REASON = PAGE NOT ACCESSABLE
	MOVSI	T2,(UP.SAA)	;SET ACCESS ALLOWED AUTOMATICALLY BIT
	TDNN	T2,.USBTS	;SHOULD WE SET A.A.?
	JRST	USRFL6		;NO, GIVE FAULT TO PFH
	HLRZ	T1,T3		;PAGE NUMBER, SIGN BIT SAYS SET A.A.
	PUSHJ	P,SCAABT	;TURN ON ACCESS ALLOWED
	PUSHJ	P,ADJANA	;MAKE .UPANA AND .UPVRT RIGHT
	JRST	USRFLX		;CONTINUE PROGRAM EXECUTION
USRFL4:	MOVEI	T1,PC.TIM	;SET REASON = TIME FAULT
	JRST	USRFL6		;AND CONTINUE
;HERE IF PAGE NOT IN WORKING SET
USRFL5:	MOVEI	T1,PC.PNC	;REASON = PAGE NOT IN CORE
	TLNE	T3,(PF.BAD)	;IF FAULT FROM A UUO,
	MOVEI	T1,PC.UUO	; REASON = UUO FAULT
	TRNN	T3,VM.ZER	;ALLOCATED BUT ZERO PAGE?
	JRST	USRFL6		;NO
	ADDI	T1,PC.AZM-PC.UUO	;YES, INCEMENT REASON BY 3
	HLRZ	T2,T3
	MOVSI	T4,(PM.AAB)
	IORM	T4,.UPMAP(T2)
USRFL6:	HLL	T1,T3		;VIRTUAL PAGE IN LH(T1)
	HRRZ	M,.JDAT+.JBPFH## ;GET ADR OF PFH
	PUSH	P,T1		;SAVE PAGE,,REASON
	GETPC	T1,.USMUO	;GET SINGLE WORD PC (MUST BE S0)
	PUSHJ	P,PUTWD1##	;SAVE PC IN WORD 1
	POP	P,T1		;RESTORE PAGE,,REASON
	MOVE	T2,.USBTS
	TLZE	T2,(UP.WHC)	;WORKING SET CHANGED?
	TLO	T1,(PC.WHC)
	TLZE	T2,(UP.WSS)	;WORKING SET SCRAMBLED?
	TLO	T1,(PC.WSS)
	MOVEM	T2,.USBTS
	PUSHJ	P,PUTWD1##	; IN WORD 2
	HRRZ	P1,T1		;SAVE REASON
	.MOVE	T1,.PDTTM##(W)	;GET TIME
	SKIPE	.USFFT		;FIRST FAULT?
	JRST	USRFL7		;NO
	HRRZS	.PDVRT##(W)	;CLEAR FAULT INTERVAL
	MOVEM	T1,.USFFT	;YES, SAVE AS FIRST FAULT TIME
USRFL7:	SUB	T1,.USFFT	;COMPUTE VIRTUAL TIME
	IMULI	T1,^D1000	;CONVERT TO MILLISECS
	IDIV	T1,TICSEC##
	PUSHJ	P,PUTWD1##	;SAVE VIRT TIME IN WD 3
	CAIN	P1,PC.TIM	;TIME INTERRUPT?
	PUSHJ	P,PGRUPD	;YES, CALL PAGE RATE UPDATE ROUTINE
	CAIE	P1,PC.TIM	;TIME INTERRUPT?
	CAIN	P1,PC.PNA	;OR PAGE NOT IN AABTAB?
	SKIPA	P1,[1]		;COUNT IN RH FOR "NON-REAL" FAULTS
;HERE ON A TIME OR ACCESS-ALLOWED FAULT
	MOVSI	P1,1		;COUNT IN LH FOR "REAL" FAULTS
	ADDM	P1,.USVCT	;COUNT FAULT IN UPMP
	ADDM	P1,SYSVCT##	;COUNT SYSTEM FAULTS
	MOVE	T1,J		;GET JOB #
	PUSHJ	P,FPDBT1##
	  TDZA	T1,T1		;HUH?
	MOVE	T1,.PDVRT##(T1)
	PUSHJ	P,PUTWD1##	;STORE IN WD 4
IFN FTPI,<
	PUSHJ	P,PSIIVA##	;GET INTERRUPT VECTOR ADDR
>
IFE FTPI,<
	MOVEI	T1,0
>
	PUSHJ	P,PUTWD1##	; AND STORE FOR USER WD 5
	SUBI	M,5		;POINT BACK TO START OF BLOCK
	PUSHJ	P,GETWDU##	;GET ADR OF PFH
	HLL	T1,.USMUO	;GET FLAGS
	TLZ	T1,(IC.BIS+IC.ATN+IC.LIP) ;CLEAR TRAP BITS, BIS
	TLO	T1,USRMOD	;BE SURE PFH RUNS IN USER MODE
	PUTPC	T1,.USMUO	;SAVE FULL WORD S0 PC OF PFH
	PUSHJ	P,CLRASA##	;CLEAR JS.ASA
	SKIPN	.CPTMF##	;DID THE CLOCK TICK?
	JRST	CPOPJ1##	;NO -- GO TO THE USER
	MOVE	T1,JBTSTS##(J)	;YES -- GET JOB STATUS
	PUSHJ	P,USCHD1##	;RESCHEDULE
	JRST	CPOPJ1##	;GO TO THE USER

IFN FTXMON,<
;FAIL BECAUSE A PROGRAM WITH A PFH IS RUNNING EXTENDED.
USRFLE:	PUSHJ	P,INLMES##	;TYPE A MESSAGE AT HIM
	ASCIZ	\?Extended page fail, cannot be passed to user PFH\
>
	POPJ	P,
;HERE WHEN THE PAGE FAULT IS A WRITE VIOLATION

USRFL9:	PUSH	P,T1		;SAVE T1
	SKIPLE	T1,JBTSGN##(J)	;A REAL HIGH SEGMENT?
	TLNN	T1,UWPOFF	;YES, WRITE ENABLED?
	JRST	TPOPJ##		;NO, ILL MEM REF
	MOVE	T1,T3		;PAGE FAIL WORD
	LSH	T1,W2PLSH##	;PAGE #
	ANDI	T1,HLGPGS	;CLEAR EXTRANEOUS JUNK
IFN FTXMON,<
	XJRST	[MCSEC1+.+1]	;ENTER SECTION 1 FOR PAGE MAP REF
>
	PUSHJ	P,GTPME		;GET POINTER
	TDO	T2,[PM.WRT]	;MAKE THE PAGE WRITABLE
	MOVEM	T2,(T4)
	CLRPGT	(P4)		;MAKE NEW MAPPING VISABLE
	USERAC			;USER ACS
	XJRSTF	.USPFP		;AND RETURN TO THE USER
				;LEAVING POINTER MESSED UP
USRFLX:	CLRPGT	(P4)
	JRST	CPOPJ1##	;TRY, TRY AGAIN

GETPFH:
	PUSH	P,T3		;SAVE T3
	MOVSI	T1,(UP.MPF)
	IORM	T1,.USBTS
	MOVSI	T1,'PFH'	;GO GET SYS:PFH.VMX
	MOVEI	T2,0		;TOP LOC = -1
	PUSHJ	P,GETXXX	;LOAD PFH
	  JRST	[POP P,(P)	;CANT GET IT -ERROR
		 PJRST CNGPFH]
	MOVSI	T1,(UP.MPF)
	ANDCAM	T1,.USBTS
	MOVEM	T2,.JDAT+.JBPFH## ;SAVE TOP,,START
	MOVSI	T3,(UP.MGP)	;INDICATE MONITOR GOT PFH
	IORM	T3,.USBTS
	PUSHJ	P,EXOPFH	;SEE IF PFH SHOULD BE CONCEALED
	HRRZS	.USFFT		;FIRST FAULT TIME = 0
	MOVE	T3,MAXINT##	;PRETEND NO FAULTS FOR A LONG TIME
	MOVE	T1,J
	PUSHJ	P,FPDBT1##
	CAIA
	HRLM	T3,.PDVRT##(T1)	;ALLOW SEVERAL TO GET
				; THE PROGRAM STARTED UP.
	POP	P,T3		;RESTORE T3
	LDB	T1,[POINT 9,T3,26] ;VIRTUAL PAGE
	LSH	T1,P2WLSH##	;CONVERT TO AN ADR
	MOVE	T2,.JDAT+.JBPFH## ;RESTORE T2
	HLRZ	T4,T2		;TOP OF PFH
	CAIL	T1,(T2)		;WAS FAULT FOR AN ADR WHICH WE HAVE CHANGED
	CAILE	T1,(T4)		; BY READING PFH OVER IT?
	JRST	USRFL3		;NO, CONTINUE
	TLNN	T3,(PF.BAD)	;YES, WAS IT A UUO?
	JRST	USRFLX		;NO, GO READ CURRENT CONTENTS
	POPJ	P,		;YES, UUO ERROR
;HERE TO READ SYS:DDT.VMX
GETDDT::GETPC	T1,USRPC##
	TLNN	T1,(XC.USR)
	GETPC	T1,.JDAT+JOBPD1##
	MOVEM	T1,.JDAT+JOBOPC##
	PJSP	T2,MSTART##	;SET UP ACS
;
	JSP	T1,MONSTR##	;START JOB
	MOVE	T1,[SIXBIT /VMDDT/] ;LOAD SYS:VMDDT.EXE
	MOVEI	T2,700000	;WHERE TO PUT IT
	PUSHJ	P,GETXXX	;GO GET IT
	PUSHJ	P,CNGDDT
	JUMPN	T2,GETDD2	;JUMP IF GOT DDT
	PUSHJ	P,TTYFUW##	;MAKE SURE TTY ATTACHED FOR ERROR MSG
	PUSHJ	P,PPQCRL##	;PRINT CRLF ?
	JRST	URUNSB##	;
GETDD2:	MOVEM	T2,.JDAT+JOBDDT## ;SAVE L(DDT) IF WE WON
	MOVEM	T2,USRDDT##	;AND IN PROTECTED AREA
	PUSHJ	P,CHKMED##	;SET MEDDLE SO CAN'T CHANGE SHARABLE HIGH SEGMENT
	JRST	STARTD##	;START AT DDT OR "NO START ADR"
;SUBROUTINE CALLED BY THE SWAPPER TO MAKE PFH CONCEALED
SXOPFH::PUSHJ	P,SVEUB##	;MAKE ADDRESSABLE
	HRRZ	T1,.JDAT+.JBPFH## ;START OF PFH
	JUMPE	T1,CPOPJ##	;RETURN IF PFH ISN'T AROUND
	HLRZ	T2,.JDAT+.JBPFH## ;HIGHEST ADDRESS IN PFH
	CAML	T2,T1		;TOP .GT. START?
	PUSHJ	P,ZRNGE		;IN CORE AND LEGAL?
	  POPJ	P,		;NO, SKIP IT
	MOVE	T3,.JDAT+.JBPFH## ;TOP,,START
	PUSHJ	P,CKHSZ		;CAN'T BE HI SEG PAGES EITHER
	  POPJ	P,		;FORGET IT
	MOVE	T2,T3		;T2 GETS (.JBPFH)
;YES, FALL INTO EXOPFH
;SUBROUTINE TO SEE IF PFH SHOULD BE CONCEALED
EXOPFH::MOVEI	T1,JS.XO	;EXECUTE ONLY BIT
	MOVSI	T3,(UP.MGP)	;MONITOR GOT PFH BIT
	TDNE	T3,.USBTS	;FROM SYS?
	TDNN	T1,JBTSTS##(J)	;IS THIS AN EXECUTE ONLY PROGRAM?
	POPJ	P,		;NO
	SKIPLE	T1,JBTSGN##(J)	;JOB HAVE A HI-SEG?
	TLNN	T1,GTSSEG	;AND WILL IT BE CONCEALED?
	POPJ	P,		;NO, FORGET IT
	HLRZ	T3,T2		;HIGHEST ADDRESS IN PFH
	SUBI	T3,(T2)		;LENGTH OF PFH
	TRZ	T3,PG.BDY##	;AND OUT LOW BITS
	ADDI	T3,PAGSIZ##	;ROUND UP
	LSH	T3,W2PLSH##	;LENGTH OF PFH IN PAGES
	HRRZ	T1,T2		;STARTING ADDRESS OF PFH
	LSH	T1,W2PLSH##	;STARTING PAGE NUMBER
EXOPF1:	PUSHJ	P,GTPME		;GET CONTENTS OF MAP SLOT
	TDZ	T2,[PM.PUB]	;MAKE THE PAGE CONCEALED
	MOVEM	T2,(T4)		;STORE IT BACK IN THE MAP
	SOSLE	T3		;DONE ALL OF PFH'S PAGES?
	AOJA	T1,EXOPF1	;NO, LOOP OVER ALL PAGES
	POPJ	P,		;RETURN
;SUBROUTINE TO TEST AND REMOVE PFH IF FROM SYS
RMVPFH::SETZM	.PDTMC##(W)	;TURN OFF TIMER TRAPS
        HLLZS	.PDTMI##(W)
	SETZM	.USLFT		;LAST FAULT TIME TOO (FOR MONPFH)
	MOVSI	T1,(UP.MGP)
	SKIPE	T3,.JDAT+.JBPFH## ;IS THERE A PFH?
	TDNN	T1,.USBTS	;YES, FROM SYS?
	POPJ	P,		;NO, DONT DO ANYTHING
	PUSHJ	P,CKHSZ
	  POPJ	P,
	ANDCAM	T1,.USBTS	;YES, CLEAR THE BIT
	PUSHJ	P,SAVE1##
	LDB	P1,[POINT 9,T3,8] ;LAST PAGE OF PFH
	LDB	T1,[POINT 9,T3,26] ;FIRST PAGE OF PFH
	JUMPE	T1,CPOPJ##
	CAMGE	P1,T1		;TOP .GE. START?
	POPJ	P,		;NO, FORGET IT
IFN FTMP,<
	PUSHJ	P,GGVMM##
>
	PUSH	P,U		;SAVE U FOR COMCON
	MOVE	R,JBTADR##(J)	;MAY NOT BE SETUP
RMVPF1:	PUSHJ	P,GTPME		;GET MAP CONTENTS
	JUMPE	T2,RMVPF2	;FORGET IT IF NO PAGE THERE
	PUSH	P,T1
	PUSHJ	P,DLTPAG	;GIVE BACK THE PAGE
	PUSHJ	P,DCVMT
	POP	P,T1
RMVPF2:	CAIGE	T1,(P1)		;DONE?
	AOJA	T1,RMVPF1	;NO, RETURN NEXT PAGE
	SETZM	.JDAT+.JBPFH##	;NOW NO PFH
	MOVEM	R,.CPADR##	;YES, ADJUST .CPREL, .CPADR
	HLRZM	R,.CPREL##
	HLRZM	R,.USHVA	;FOR ADDRESS CHECKING AT INTERRUPT LEVEL
	PJRST	UPOPJ##		;AND RETURN

;SUBROUTINE TO SAY "CAN NOT GET DDT"
CNGDDT:	SKIPA	T1,[SIXBIT /DDT/]
;DITTO FOR PFH
CNGPFH:	MOVSI	T1,'PFH'	;WHAT WE COULDN'T GET
	PUSH	P,U		;SAVE POSSIBLE LDB POINTER
	PUSH	P,T1		;SAVE 'XXX'
	PUSHJ	P,TTYSRC##	;FIND THE TTY
	  JRST	CNGXX1		;WHOOPS! FORGET IT
	MOVEI	T1,[ASCIZ "?
?Can not get "]
	PUSHJ	P,CONMES##	;TYPE "?CAN NOT GET"
	MOVE	T2,(P)		;RESTORE "XXX"
	PUSHJ	P,PRNAME##	;PRINT "PFH" OR "DDT" AND RETURN WITH T2=0
CNGXX1:	POP	P,T1		;RESTORE T1
	JRST	UPOPJ##		;AND RETURN
;SUBROUTINE TO GET XXX.VMX
;CALLING SEQUENCE:
;	MOVE	T1,[SIXBIT/XXX/]
;	MOVEI	T2,WHERE TO PUT IT OR 0 IF AT THE TOP OF CORE
;	PUSHJ	P,GETXXX
;RETURNS CPOPJ ON ERROR
;RETURNS CPOPJ1 ON SUCCESS, T2 = HIGHEST ADDRESS READ INTO,,START ADDRESS
;ENTER AT MAKPGS TO CREATE PAGES, T2 = WHERE, T3 = HOW MANY

MAKPGS:	MOVEI	T1,0		;FLAG CREATING PAGES
	TRZ	T2,PG.BDY##	;MAKE SURE IT STARTS AT PAGE BOUNDARY
	LSH	T3,P2WLSH##	;NUMBER OF WORDS TO MAKE
	MOVNS	T3		;-N
	HRLZM	T3,.JDAT+SGALEN## ;FAKE OUT LOOKUP STUFF
GETXXX:	MOVEI	T3,.USUAC	;SAVE THE CURRENT EXEC ACS
	EXCTUX	<BLT T3,.USUAC+17>
	PUSHJ	P,SETASA##	;GET ARGUMENTS FROM SHADOW ACS
	PUSH	P,T2		;SAVE WHERE TO PUT IT
	PUSH	P,T2		;ALLOCATE STACK SPACE
	MOVSI	T2,'EXE'
	DMOVEM	T1,.JDAT+SGANAM## ;INTO LOOKUP BLOCK
	JUMPE	T1,GETXX3	;SKIP THE LOOKUP IF MAKPGS
	PUSHJ	P,GETXXC	;GET EXTENDED CHANNEL NUMBER
	 POPJ	P,		;URP.
	MOVE	T1,USRJDA##	;GET POINTER TO DDB CURRENTLY HERE
	MOVEM	T1,(T2)		;SAVE AS AN EXTENDED CHANNEL
	MOVEM	T2,(P)		;SAVE POINTER TO EXTENDED CHANNEL
	SETZM	USRJDA##	;DONT RELEASE WHEN WE INIT
	MOVEI	T1,D		;INIT SYS: IN DUMP MODE
	MOVE	T2,[JACCT,,JS.XO]
	TDNE	T2,JBTSTS##(J)
	TLO	T1,PHONLY
	MOVSI	T2,'SYS'
	DMOVEM	T1,.JDAT+SGAMOD##
	SETZM	.JDAT+SGAHED##
	OPEN	SGAMOD##
	  JRST	GETX11		;CANT INIT SYS:
	SETZM	.JDAT+SGALEN##
	LOOKUP	SGANAM##	;LOOKUP XXX.VMX
	  SKIPA	T1,[PHONLY,,DR]
	JRST	GETXX1
	MOVEM	T1,.JDAT+SGAMOD##
GETXX1:	SKIPL	.JDAT+SGAMOD##	;PHYSICAL ONLY?
	TDZA	T3,T3		;NO
	MOVEI	T3,UPHNLY	;YES, PHONLY
	MOVE	T1,.JDAT+SGANAM## ;FILE NAME
	MOVEM	T1,.JDAT+SGADEV##+1 ;STORE THAT IN THE MERGE ARGUMENT BLOCK
	DMOVE	T1,[SGADEV##	;POINTER TO ARGUMENT LIST
		    SIXBIT /SYS/] ;DEVICE
	DMOVEM	T1,.JDAT+SGADEV##-1 ;STORE THOSE IN THE MERGE ARGUMENT BLOCK
	SETZB	T1,T2		;ZERO WORDS 2,3,4,5
	DMOVEM	T1,.JDAT+SGADEV##+2 ;..
	DMOVEM	T1,.JDAT+SGADEV##+4 ;..
	PUSHJ	P,VJSIZ		;CURRENT SIZE OF THE PROGRAM
	PUSH	P,T4		;SAVE THAT
	PUSH	P,.JDAT+JOBPD1##;SAVE JOBPD1
	SETZM	.JDAT+JOBPD1##	;SO IT WON'T LOOK LIKE A USER MODE UUO
	MERGE.	10,(T3)		;MERGE XXX.EXE INTO THE ADDRESS SPACE
	  JRST	[POP	P,(P)	;FAILED
		 JRST	GETX11]	;CAN'T GET XXX
	POP	P,.JDAT+JOBPD1##;RESTORE JOBPD1
	PUSHJ	P,VJSIZ		;SIZE OF THE PROGRAM AFTER THE MERGE
	POP	P,T1		;SIZE BEFORE THE MERGE
	SUB	T4,T1		;INCREASE IN SIZE
	LSH	T4,P2WLSH##	;CONVERT TO NUMBER OF WORDS
	SKIPE	T2,-1(P)	;WHERE TO PUT IT SPECIFIED?
	JRST	GETXX2		;YES
	MOVSI	T2,1		;NO. AT TOP OF ADDRESS SPACE
	SUB	T2,T4		;ORGIN
GETXX2:	HRLS	T2		;ORGIN TO THE LEFT HALF
	ADDI	T2,-1(T4)	;HIGHEST ADDRESS
	MOVSM	T2,-1(P)	;STORE HIGHEST ADDRESS,,ORGIN FOR RETURN
	AOS	-2(P)		;GOOD RETURN
	JRST	GETX12		;RESTORE THE WORLD AND EXIT

GETXX3:	MOVE	J,.CPJOB##	;RESTORE J
	HLRE	T3,.JDAT+SGALEN## ;LENGTH OF FILE
	JUMPGE	T3,GETX11	;BETTER BE NEGATIVE
	MOVNS	T3		;+LENGTH
	ADDI	T3,PG.BDY##	;CONVERT TO REQUIRED NO OF PAGES
	LSH	T3,W2PLSH##
	PUSHJ	P,CHKLIN##	;GET BELOW LIMIT
	  JRST	GETX11		;CAN'T DO IT
GETXX7:	HLRE	T1,.JDAT+SGALEN## ;NO OF PAGES TO CREATE
	SKIPE	T2,-1(P)	;WHERE TO CREATE THEM
	JRST	GETXX8
	MOVSI	T2,1		;AT TOP OF CORE - FIND REAL START
	ADD	T2,T1		;START ADR
	TRZ	T2,PG.BDY##	;START PAGE
	HRRZM	T2,-1(P)	;SAVE ON LIST AS START LOC
GETXX8:	SUBM	T2,T1		;TOP ADDRESS IN T1, START ON THE STACK
	SUBI	T1,1
	XOR	T1,-1(P)	;CROSSING A SECTION?
	TLNE	T1,-1		;?
	JRST	GETX11		;YES, NOT ALLOWED
	XOR	T1,-1(P)
	HRLM	T1,-1(P)	;TOP ADR,,START ADR
	MOVE	T3,-1(P)
	MOVSS	T1
	PUSHJ	P,CKHSO
	  JRST	GETX11
	MOVSS	T1
	SUBI	T1,-1(T2)	;NUMBER OF WORDS NEEDED
	ADDI	T1,PG.BDY##	;ROUND UP
	LSHC	T1,W2PLSH##	;NUMBER OF PAGES AND START PAGE
	MOVEM	T1,.JDAT+SGAPPN## ;SAVE NUMBER OF PAGES
	MOVEI	T3,.JDAT+SGAPPN##+1 ;WHERE TO STORE NEEDED PAGE NUMBERS
GETXX9:	HRRZM	T2,(T3)		;SAVE NEEDED PAGE NUMBER
	SOJLE	T1,GETX10	;GO IF HAVE ENOUGH
	ADDI	T3,1		;WHERE TO STORE NEXT PAGE NUMBER
	AOJA	T2,GETXX9	;BUMP THE PAGE NO AND CONTINUE
GETX10:	MOVE	T1,[1,,SGAPPN##]
	MOVEM	T1,.JDAT+17	;CREATE PAGES
	PAGE.	17,
	  JRST	GETX11		;CANT CREATE THE PAGES - TOUGH LUCK
	AOS	-2(P)		;GOOD RETURN
GETX11:	SKIPN	.JDAT+SGANAM##	;MAKPGS?
	JRST	GETX12		;YES, NO CHANNEL TO DESTROY
	CLOSE	CLSNMB		;CLOSE THE FILE
	RELEASE			;GET RID OF THE DDB
GETX12:	MOVE	J,.CPJOB##	;RESOTRE J
	PUSHJ	P,CLRASA##	;CLEAR JS.ASA IN JBTSTS
	MOVSI	T2,.USUAC	;RESTORE THE EXEC ACS ON ENTRY
	EXCTXU	<BLT T2,17>
	POP	P,T2		;GET POINTER TO EXTENDED USER CHANNEL ZERO
	PUSH	P,(T2)		;GET POINTER TO USER'S CHANNEL 0 DDB
	SETZM	(T2)		;CLEAR EXTENDED CHANNEL POINTER TO IT
	POP	P,USRJDA##	;AND RESTORE USER'S CHANNEL ZERO
	JRST	T2POPJ##	;RESTORE T2 AND RETURN
;GET AN EXTENDED CHANNEL NUMBER
;RETURN
;	CPOPJ,	NO FREE CORE OR NO FREE CHANNELS
;	CPOPJ1,	T2/ POINTER TO FREE CHANNEL SLOT

GETXXC:	HRRZ	T1,.USCTA	;AN EXTENDED CHANNEL TABLE ALREADY SETUP?
	JUMPN	T1,GETXC1	;YES, FIND A FREE CHANNEL
	MOVEI	T2,HIGHXC##-20	;NO, ALLOCATE AN EXTENDED CHANNEL TABLE
	PUSHJ	P,GTFWDC	;GET FUNNY WORDS CACHED
	  POPJ	P,		;ERROR - NO PER-PROCESS SPACE AVAILABLE
	HRRM	T1,.USCTA	;STORE THE ADDRESS OF THE XCT
	MOVSI	T2,(T1)		;FORM A BLT POINTER
	HRRI	T2,1(T1)	; ..
	SETZM	(T1)		;ZERO FIRST WORD OF THE TABLE
	BLT	T2,HIGHXC##-21(T1) ;ZAP, THE TABLE IS INITIALIZED
;HERE WITH T1 = ADDRESS OF THE EXTENDED CHANNEL TABLE
GETXC1:	MOVE	T2,T1		;ADDRESS OF THE TABLE
GETXC2:	SKIPN	(T2)		;CHANNEL IN USE?
	JRST	CPOPJ1##	;NO, AVAILABLE
	CAIGE	T2,HIGHXC##-20(T1) ;YES, LOOKED AT THE ENTIRE TABLE?
	AOJA	T2,GETXC2	;NO, LOOP OVER ENTIRE TABLE
	POPJ	P,		;ERROR - NO FREE CHANNELS AVAILABLE
	SUBTTL	PAGE. UUO

UPAGE.::PUSHJ	P,SAVU##	;JOB1 DEPENDS ON THIS
	HLRZ	U,T1		;FUNCTION IN U
	CAIL	U,NPGUUO	;IS IT A LEGAL FUNCTION?
	JRST	UIFERR		;NO, ILLEGAL ARGUMENT LIST ERROR
	MOVE	U,PAGJMP(U)	;GET DISPATCH ENTRY
	HLRZ	T3,U		;PUT CHECK BITS IN T3
	HRR	M,T1		;ADDRESS OF THE ARGUMENT LIST
	TLNE	U,UU.NCL	;NEGATIVE ARGUMENT LEGAL?
	PUSHJ	P,[PUSH P,T1	;YES
		   PUSHJ P,GETWSU##
		   JUMPGE T1,TPOPJ ;GO IF NOT NEGATIVE
		   PUSHJ P,GETWS1## ;NEXT ARGUMENT MUST BE IN CORE
		   POP P,T1
		   POP P,(P)	;POP OFF CALL
		   SOJA M,UPAGE1] ;CHECK IF IT CAN BE DONE IF LOCKED
	HRRZS	T1		;CLEAR FUNCTION FROM LEFT HALF
	PUSHJ	P,UUOCHK	;INSURE THAT ALL ITEMS IN THE ARGUMENT LIST
				; ARE IN CORE
UPAGE1:	TLNN	U,UU.NAL	;IS THIS FUNCTION ALLOWED IF THE JOB IS LOCKED?
	JRST	UPAGE2		;YES, PROCEED
	MOVSI	T1,NSHF!NSWP	;LOCKED BITS
	SKIPLE	T2,JBTSGN##(J)	;DOES THIS JOB HAVE A HIGH SEGMENT?
	TLNE	T2,SHRSEG	;YES, IS IT SHARABLE?
	MOVEI	T2,0		;NO, SET HIGH SEGMENT NUMBER TO ZERO
	TDNN	T1,JBTSTS##(J)	;IS THE LOW SEGMENT LOCKED?
	TDNE	T1,JBTSTS##(T2)	;IS THE HIGH SEGMENT LOCKED?
	JRST	IILERR		;YES, ILLEGAL IF LOCKED ERROR
UPAGE2:
IFN FTMP,<
	PUSHJ	P,UUOLVL##	;CAN'T WAIT FOR ANYTHING IF AT CLOCK LEVEL
	  JRST	UPAGE3		;(WHICH ALREADY HAS MM)
	TLNN	U,UU.CP1	;CAN THIS UUO BE EXECUTED ON CPU1?
	PUSHJ	P,UPMM##	;NO, INSURE JOB OWNS THE MM RESOURCE
>
UPAGE3:				;CLOCK LEVEL ALSO ALREADY HAS MM
	HRRZ	T1,U		;GET SUBR ADDRESS
	CAIN	T1,PAGACC	;PAGE ACCESSIBILITY CHECK?
	JRST	UPAGE4		;YES, DON'T DECODE PAGE NUMBER AS ADDDRESS
	PUSHJ	P,GETWSU##	;GET THE NUMBER OF ARGUMENTS
	TLNE	U,UU.NCL	;IF NEGATIVE COUNT IS LEGAL,
	MOVMS	T1		;POSITIVE ARGUMENT COUNT
	HRLI	T1,1(M)		;LEFT HALF OF T1 POINTS AT THE FIRST ARGUMENT
	MOVSS	T1		;T1 = NUMBER OF ARGUMENTS,,ADDRESS OF FIRST ARGUMENT
UPAGE4:	PUSHJ	P,FNDPDS##	;GET PDB (FOR LIMITS)
	SETZM	.USTMU		;BE SURE ZEROED
	PUSH	P,U		;SAVE DISPATCH BITS
	PUSHJ	P,(U)		;DISPATCH TO PERFORM REQUESTED FUNCTION
	  JRST	UPAGEE		;ERROR EXIT
	PUSHJ	P,SETHSA	;SET JBTHSA
	PUSHJ	P,ZAPSCS	;CHECK EMPTY SECTION MAPS
IFN FTMP,<
	PUSHJ	P,INTLVL##	;DON'T FIDDLE WITH MM IF AT CLOCK LEVEL
	PUSHJ	P,TGVMM##	;OWN THE MM?
>
	POP	P,U		;RESTORE DISPATCH BITS
	GETPC	T2,.JDAT+JOBPD1## ;GET USER PC
	TLNE	U,UU.WCC	;CAN THIS UUO CAUSE THE W.S. TO CHANGE
	PUSHJ	P,INPFH		;YES, PFH DOING THIS UUO?
	  PJRST	CPOPJ1##	;DON'T INDICATE W.S. HAS CHANGED
	MOVSI	T1,(UP.WHC)	;WORKING SET HAS CHANGED BIT
	IORM	T1,.USBTS	;REMEMBER THAT
	SKIPL	.USTMU		;YES, BETTER BE ZERO ON EXIT?
	AOSA	(P)		;WE'RE GOING TO GIVE A SKIP RETURN
	XCT	PMW		;OOPS
	POPJ	P,		;RETURN
UPAGEE:	PUSHJ	P,ZAPSCS	;CLEAR EMPTY SECTIONS
	POP	P,(P)		;FIX STACK
	SKIPL	T3,.USTMU	;ANY PAGES MOVED BY PLTSN?
	JRST	UPAGE9		;NO
	SE1ENT			;MUST BE IN S1 TO TOUCH MAPS&PAGTAB/MEMTAB
UPAGE5:	SSX	T3,MS.MEM	;POINT TO PAGTAB/MEMTAB SECTION
	LDB	T1,NVPNT3	;GET VIRTUAL PAGE THIS PHYS PAGE BELONGS TO
	PUSHJ	P,GTPME		;GET PAGE MAP ENTRY
	TLNE	T2,(PM.OIQ)	;WAS PAGE ON AN IN QUEUE?
	JRST	UPAGE6		;YES, TREAT AS SUCH
	XOR	T2,MEMTAB(T3)	;BE SURE DISK ADDRESSES ARE THE SAME
	TDNE	T2,[MT.DAD]	;...
	XCT	PMW		;++PAGE MAP IS WRONG
	MOVEI	T1,PAGOUQ##	;PUT PAGE ON OUT QUEUE
	JRST	UPAGE7
UPAGE6:	TLNN	T2,(PM.SSP)	;SLOW?
	SKIPA	T1,[PAGINQ##]	;NO, FAST
	MOVEI	T1,PAGSNQ##	;SLOW
	TLZ	T2,(PM.NAD)	;QUICK CHECK
	CAIE	T2,(T3)		;PAGE NUMBERS SHOULD MATCH
	STOPCD	CPOPJ,DEBUG,PMW, ;++PAGE MAP WRONG
UPAGE7:	EXCH	T1,T3		;QUEUE TO T3, PAGE TO T1
	MOVSI	T4,(P2.TRN)	;CLEAR TRANSIENT PAGE BIT
	ANDCAM	T4,PT2TAB(T1)
	HRRZ	T4,PAGTAB(T1)	;GET CURRENT SUCCESSOR
	HRRZS	T1		;ADDPTQ RE-ADDS IN MS.MEM
	PUSHJ	P,ADDPTQ	;ADD TO A QUEUE
UPAGE8:	SKIPE	T3,T4		;IF THERE IS A NEXT PAGE
	JRST	UPAGE5		;LOOP BACK
UPAGE9:
IFN FTMP,<
	PUSHJ	P,INTLVL##	;CLOCK LEVEL ALREADY HAD IT
	  PJRST	TGVMM##		;OWN THE MM RESOURCE?
>
	POPJ	P,		;RETURN
;PAGE. UUO DISPATCH TABLE

PAGJMP:	UU.NCL+UU.NAL+UU.LER+UU.WCC,,PAGEB   ;(0) PAGE IN/OUT
	UU.NCL+UU.NAL+UU.LER+UU.WCC,,CHGPGS  ;(1) CREATE/DESTROY PAGES
	UU.NCL+UU.NAL+UU.LER,,MOVPGS	;(2) MOVE/EXCHANGE PAGES
	UU.NCL+UU.LER,,SETAAB		;(3) SET/CLEAR ACCESS ALLOWED BITS
	UU.CP1+UU.LER,,GETWSB	;(4) GET WORKING SET BIT TABLE
	UU.CP1+UU.LER,,GETAAB	;(5) GET ACCESS ALLOWED BIT TABLE
	UU.CP1,,PAGACC		;(6) CHECK PAGE ACCESSABILITY
	UU.NAL+UU.LER+UU.WCC+UU.CP1,,GREMAP	;(7)GENERALIZED REMAP
				; UU.CP1 SO NREMAP CAN GET MM BY HAND

	UU.NCL+UU.LER,,SETCSB	;(10) SET/CLEAR CACHE BITS
IFN FTPEEKSPY,<
	UU.NCL+UU.LER,,SPYPGS		;(11) SPY ON PAGES
>
IFE FTPEEKSPY,<
	UU.LER,,UIFERR		;(11) NOT IMPLEMENTED
>
	UU.NCL+UU.LER+UU.NAL,,CHGSEC	;(12) CREATE/DESTROY SECTION MAPS
	UU.CP1+UU.LER,,PAGCHK		;(13) ACCESSIBILITY BIT MAP
	UU.CP1+UU.LER,,PAGACL		;(14) PAGE ACCESSIBILITY, LIST FORM

NPGUUO==.-PAGJMP

HSPAG==200000			;PLTSN SETS IF PAGE IS IN A HIGH SEGMENT
ARGMD==100000			;ARGUMENT MODIFIER, SET BY PLTSN IF ANY AGRUMENT
				; HAS 1B1=1
;HERE TO FIND PAGES WHICH HAVE GIVEN ACCESSIBILITY

PAGCHK:	HLRZ	P1,T1		;GET ARG COUNT
	SOJLE	P1,IALERR	;NOT ENOUGH ARGS
	PUSHJ	P,GETWD1##	;BIT MASK OF STATE
	MOVE	P4,T1		;SAVE IN P4
	SOJLE	P1,IALERR	;NOT ENOUGH ARGS
	PUSHJ	P,GETWD1##	;BITS HE CARES ABOUT
	MOVE	U,T1
	SOJLE	P1,IALERR	;ERROR IF NO MORE ARGS
	PUSHJ	P,GETWD1##	;GET STARTING PAGE #
	CAILE	T1,HLGPGS
	  JRST	ILPERR		;NO
	SE1ENT			;ENTER SECTION 1
PAGCH1:	MOVSI	P2,-^D35	;# WORDS PER PAGE
	SETZ	P3,		;MASK WORD
PAGCH2:	TRNN	T1,HLGPNO	;CROSS SECTION BOUNDARY?
	JRST	PAGC17		;YES
PAGCH3:	HRRZ	T2,T1
	LSH	T2,P2SLSH##
	MOVE	T4,T2		;IN CASE CALL RSECT4
	SKIPN	T2,.UPMP+SECTAB(T2) ;DOES SECTION EXIST?
	JRST	PAGC19		;NO
	TLNN	U,(PA.NXS)	;CARE ABOUT SECTION EXISTENCE?
	JRST	PAGCH4		;NO
	TLNE	P4,(PA.NXS)	;SECTION EXISTS, WANT NON-EX SECTIONS?
	JRST	 PAGC20		;WANTS NON-EX SECT
PAGCH4:	TLNN	U,(PA.IND)	;CARE ABOUT INDEPENDENCE?
	JRST	PAGC40		;NO
	TLNN	T2,(<PM.ACD^!PM.DCD>B2) ;IS IT INDEPENDENT?
	TLON	P4,(PA.IND)	;IT IS INDIRECT, IS THAT WHAT HE WANTS?
	TLNN	P4,(PA.IND)	;OR THE OTHER
	JRST	PAGC16		;WRONG
	TDNN	U,[PA.ISN]	;CARE ABOUT SECTION #?
	JRST	PAGC40		;NO
	PUSHJ	P,RSECT4	;GET REAL SECTION #
	  JFCL			;IGNORE SKIP
	LSH	T4,<<^D35-5>-^L<PA.ISN>> ;PUT IT IN THE RIGHT PLACE
	XOR	T4,P4		;CHECK FOR EQUIVALENCE
	AND	T4,U		;WHERE IT IS CARED ABOUT
	TDNE	T4,[PA.ISN]	;..
	JRST	PAGC16		;DOESN'T MATCH
PAGC40:	PUSHJ	P,GTPME		;GET PAGE MAP ENTRY
	TLNN	P4,(PA.NXP)	;WANT NON-EXISTENT PAGES?
	JUMPE	T2,PAGC16	;WANTS EXISTENT PAGES AND THIS ONE DOESN'T
	TLNN	U,(PA.OUT)	;CARE ABOUT OUT PAGES?
	JRST	PAGCH5		;NO
	TLNN	T2,(PM.COR)	;IN-CORE PAGE?
	TLZE	P4,(PA.OUT)	;OUT, DOES HE WANT OUT?
	TLNE	P4,(PA.OUT)	;OR IN?
	JRST	PAGC16		;WANTS WHAT IT ISN'T
PAGCH5:	TLNN	U,(PA.NCS)	;CARE ABOUT CACHE?
	JRST	PAGCH6		;NO
	TLNN	T2,(PM.CSH)	;CACHED?
	TLZE	P4,(PA.NCS)	;WANT CACHED...
	TLNE	P4,(PA.NCS)	;OR UNCACHED?
	JRST	PAGC16
PAGCH6:	TLNN	U,(PA.WRT)	;CARE ABOUT WRITE?
	JRST	PAGCH7		;NO
	TLNN	T2,(PM.WRT)	;WRITABLE?
	TLON	P4,(PA.WRT)	;CARE?
	TLNN	P4,(PA.WRT)	;...
	JRST	PAGC16
PAGCH7:	TLNN	U,(PA.RED)	;CARE ABOUT READ STATUS?
	JRST	PAGCH8		;NO
	TLNN	T2,(<PM.DCD>B2)	;IS PAGE ACCESIBLE?
	TLON	P4,(PA.RED)
	TLNN	P4,(PA.RED)
	JRST	PAGC16
PAGCH8:	TLNN	U,(PA.GSP)	;CARE ABOUT SPY?
	JRST	PAGCH9		;NO
	TLNN	T2,(PM.SPY)	;IS IT?
	TLON	P4,(PA.GSP)
	TLNN	P4,(PA.GSP)
	JRST	PAGC16
PAGCH9:	TLNN	U,(PA.VSP)	;CARE ABOUT SPY PAGES?
	JRST	PAGC30		;NO
	TLNN	T2,(PM.SPY)	;IS THIS ANY KIND OF SPY PAGE?
	JRST	PAGC16		;NO, CAN'T BE VIRTUAL OR NOT THEN
	TLNN	T2,(<PM.ACD^!PM.DCD>B2) ;VIRTUAL IF IT'S INDIRECT
	TLON	P4,(PA.VSP)	;IT'S PHYSICAL, HE WANTED PHYSICAL?
	TLNN	P4,(PA.VSP)	;OR VIRTUAL
	JRST	PAGC16		;HE WANTED WHAT IT ISN'T
	TRNN	U,PA.SPN	;CARE ABOUT THE PAGE # BEING SPIED ON?
	JRST	PAGC30		;NO
	PUSH	P,U		;SAVE U (CARE MASK)
	TLNN	T2,(<PM.ACD^!PM.DCD>B2) ;NOW, WAS IT VIRT OR PHYS?
	JRST	PAGC27		;PHYS
	PUSH	P,T2		;SAVE T2
	PUSHJ	P,PAGA10	;GET PAGE # (RETURNED IN U)
	POP	P,T2		;RESTORE T2
	SKIPA	T3,U		;LOAD VIRT PAGE # INTO T3
PAGC27:	MOVE	T3,T2		;PHYSICAL PAGE # FROM T2
	POP	P,U		;RESTORE CARE MASK
	XOR	T3,P4		;FIND THE DIFFERENCES BETWIXED REALITY AND FANTASY
	AND	T3,U		;SUPPRESSING THOSE THINGS WE DON'T CARE ABOUT
	TRNE	T3,PA.SPN	;ARE THEY THE SAME?
	JRST	PAGC16		;NO
PAGC30:PAGC30:	PUSHJ	P,TPNHS		;IS IT IN A HIGH SEG?
	  SKIPA	T3,[PA.GHI]	;REMEMBER IT IS
	TDZA	T3,T3
	  TLZE	P4,(PA.GHI)	;YES
	TLZE	P4,(PA.GHI)
	TLNN	U,(PA.GHI)	;HIGH SEG?
	TDOA	P4,T3		;REMEMBER THAT IT'S IN THE HIGH SEG
	JRST	PAGC16
PAGC10:	TLNN	U,(PA.AA)	;CARE ABOUT ACCESS ALLOWED?
	JRST	PAGC11
	TLNN	T2,(PM.AAB)
	TLON	P4,(PA.AA)
	TLNN	P4,(PA.AA)
	JRST	PAGC16
PAGC11:	MOVSI	T3,SHRSEG	;IS THIS PAGE
	TLNE	T3,JBTSGN##(J)	;IN A
	TLNN	P4,(PA.GHI)	;SHARABLE HIGH SEG?
	SKIPA	T3,[PA.GSH]	;REMEMBER IT'S NOT SHARABLE
	TDZA	T3,T3
	TLON	P4,(PA.GSH)	;NO
	TLON	P4,(PA.GSH)
	TLNN	U,(PA.GSH)	;WRONG SENSE, DO WE CARE?
	TDCA	P4,T3		;WE DON'T CARE OR IT'S RIGHT, SKIP ON
	JRST	PAGC16
PAGC12:	TLNN	U,(PA.LCK)	;CARE IF IT'S LOCKED?
	JRST	PAGC13		;NO
	TLNE	P4,(PA.GHI)	;IS IT A HIGH SEG PAGE?
	TDNN	T3,JBTSGN##(J)	;YES, IS HIGH SEG SHARABLE?
	SKIPA	T3,J		;NO, OR IT'S LOW SEG PAGE
	HRRZ	T3,JBTSGN##(J)	;ELSE POINT AT HIGH SEG
	MOVE	T3,JBTSTS##(T3)	;STATUS WORD
	TLNE	T3,NSHF!NSWP	;LOCKED?
	TLZE	P4,(PA.LCK)
	TLNE	P4,(PA.LCK)
	JRST	PAGC16
PAGC13:	TLNN	U,(PA.CPO)	;CARE IF WE CAN PAGE IT OUT?
	JRST	PAGC14		;NO
	TLNN	P4,(PA.GSH)	;IS IT SHARABLE?
	SKIPN	T1		;OR IS IT PAGE 0?
	TLZE	P4,(PA.CPO)	;CAN'T BE PAGED, WHICH SENSE DOES HE WANT?
	TLNE	P4,(PA.CPO)
	JRST	PAGC16
PAGC14:	TLNN	U,(PA.ZER)	;CARE IF IT'S ABZ?
	JRST	PAGC15		;NO
	TLZ	T2,(PM.NAD)
	CAMN	T2,[PM.ZER]	;IS IT ABZ?
	TLZE	P4,(PA.ZER)
	TLNE	P4,(PA.ZER)
	JRST	PAGC16
PAGC15:	AOS	P3		;TURN BIT ON
PAGC16:	LSH	P3,1		;NEXT
	AOS	T1		;NEXT PAGE #
	AOBJN	P2,PAGCH2	;CONTINUE
	EXCH	P3,T1		;SAVE T1
	PUSHJ	P,PUTWD1##	;PUT BIT MASK
	MOVE	T1,P3		;RESTORE T1
	SOJG	P1,PAGCH1
	JRST	CPOPJ1##

PAGC17:	CAILE	T1,HLGPGS	;NO MORE SECTIONS?
	JRST	PAGC18		;NO, FINISH UP
	SETZ	T1,
	PUSHJ	P,SCDCHK##	;DELAY ON PER-SECTION BASIS
	JRST	PAGCH3

PAGC18:	TRNN	P2,-1		;ANY BITS TO PUT?
	JRST	CPOPJ1##	;NO, DONE
	MOVE	T1,P3
	AOS	(P)
	JRST	PUTWD1##	;PUT LAST WORD IN

;HERE IF A WHOLE SECTION DOESN'T EXIST
PAGC19:	PUSH	P,P4		;SAVE P4
	TLNN	U,(PA.BTS^!PA.NXS) ;CARE ABOUT ANYTHING OTHER THAN SECTION ACCESS?
	TLNN	U,(PA.NXS)	;DO WE EVEN CARE ABOUT SECTION EXISTENCE?
	JRST	PAGC20
	TLNE	P4,(PA.NXS)	;DO WE WANT NON-EX SECTIONS?
PAGC20:	TDZA	P4,P4		;SET NO BITS
	SETO	P4,		;SET ALL BITS
	ASH	P2,-^D18	;-# OF BITS LEFT IN WORD
	MOVMS	P2		;+# OF BITS LEFT IN WORD
	LSHC	P3,(P2)		;SET/CLEAR THAT MANY BITS
	MOVNS	P2		;-# OF PAGES JUST SET/CLEARED
	ADDI	P2,1000		;# OF PAGES LEFT IN SECTION
	ASH	P4,-^D36	;SET P4 TO -1 OR ZERO
	MOVE	T1,P4		;COPY TO T1
PAGC21:	PUSHJ	P,PUTWD1##	;STORE WORD
	SOJLE	P1,TPOPJ1##	;FIX STACK AND RETURN
	SUBI	P2,^D35		;# OF PAGES LEFT IN SECT AFTER NEXT WORD
	JUMPGE	P2,PAGC21	;CAN PUT IN A FULL WORD
	SETZ	P3,		;START WITH A CLEAN SLATE
	LSHC	P3,^D35(P2)	;SET/CLEAR LEFTOVER BITS
	POP	P,P4
	JRST	PAGC17
;HERE TO DETERMINE PAGE ACCESSABILITY

PAGACC:	PUSHJ	P,GETTAC##	;GET THE CONTENTS OF THE USER'S AC
	HRRZS	T1		;GET PAGE NUMBER IN QUESTION
	CAILE	T1,HLGPGS	;IS IT LEGAL?
	JRST	ILPERR		;NO
	PUSHJ	P,PAGAC1	;GET THE PAGE BITS
	PJRST	STOTC1##	;STORE THE RESULTS AND RETURN TO THE USER

;HERE FOR LIST FORMAT PAGACL

PAGACL:	HLRZ	P1,T1		;COUNT
	SOS	P1		;REMOVE COUNT WORD
	SOJLE	P1,IALERR	;MUST BE AT LEAST ONE MORE ARG
	PUSHJ	P,GETWD1##	;GET STARTING PAGE #
	PUSH	P,T1		;SAVE STARTING PAGE
PGACL0:	MOVEI	P2,HLGPNO+1	;FOR CALLING SCDCHK
PGACL1:	PUSHJ	P,PAGAC1	;GET ACCESSIBILITY
	PUSHJ	P,PUTWD1##	;STORE IT
	AOS	T1,(P)		;POINT TO NEXT PAGE
	SOJL	P2,PGACL2
	SOJG	P1,PGACL1	;CONTINUE
	JRST	TPOPJ1##

PGACL2:	PUSHJ	P,SCDCHK##
	JRST	PGACL0
;SUBROUTINE TO GET THE PAGE ACCESSABILITY BITS
;CALL:
;	MOVE	T1,PAGE #
;	PUSHJ	P,GETPAC
;	HERE WITH BITS IN T1
;
GETPAC::MOVE	J,.CPJOB##	;JOB NUMBER
GTPACC::HRRZS	T1		;PAGE NUMBER THAT THE USER IS INTERESTED IN
	CAILE	T1,HLGPGS	;PAGE NUMBER SPECIFIED .LE. HIGHEST LEGAL PAGE?
	JRST	ILPERR		;NON-EXISTENT
PAGAC1:	SE1ENT
	MOVEI	U,0		;ASSUME THE PAGE DOESN'T EXIST
	LSHC	T1,P2SLSH##	;MAP
	PUSH	P,T2		;SAVE T2
	MOVE	T4,T1		;GET COPY
	CAILE	T4,MXSECN	;LEGAL?
	JRST	PAGAC8		;NO, IS NON-EXISTENT THEN
	PUSHJ	P,RSECT4	;GET SECTION #
	  JFCL			;DON'T CARE ABOUT SKIP
	SKIPN	T2,.UPMP+SECTAB(T1);SECTION EXIST?
	JRST	PAGAC8
	EXCH	T2,(P)		;RESTORE T2, SAVING ENTRY
	LSHC	T1,S2PLSH##	;RESTORE PAGE #
	POP	P,T2
	TLNN	T2,(<PM.DCD^!PM.ACD>B2) ;INDIRECT?
	JRST	PAGAC0		;NO
	DPB	T4,[POINT 5,U,<^L<PA.ISN>+5-1>] ;POSITION IT
	TLO	U,(PA.IND)	;SET INDIRECT
	SKIPN	.UPMP+SECTAB(T4) ;DOES REAL SECTION EXIST?
	JRST	PAGAC9		;NO
PAGAC0:	PUSHJ	P,GTPME		;GET CONTENTS OF THE MAP
	JUMPE	T2,PAGAC7	;NON-EXISTENT
	MOVE	T3,T2		;SAVE THE MAP ENTRY
	TLZ	T2,(PM.NAD)	;ABZ?
	CAMN	T2,[PM.ZER]
	TLO	U,(PA.ZER)	;ZERO PAGE
	PUSHJ	P,TSWST		;IS THE PAGE IN THE WORKING SET?
	  TLO	U,(PA.OUT)	;NO, INDICATE THAT THE PAGE IS PAGED-OUT
	TLNE	T3,(PM.AAB)	;IN AABTAB?
	TLO	U,(PA.AA)	;YES, INDICATE ACCESS IS ALLOWED
	TLNE	U,(PA.OUT)	;IN MEMORY?
	JRST	PAGAC2		;NO - MUST BE CACHED
	TLNN	T3,(PM.CSH)	;YES - CACHE TURNED OFF?
	TLO	U,(PA.NCS)	;YES, TELL USER NOT CACHED
PAGAC2:
IFN FTPEEKSPY,<
	MOVEI	T3,0		;ASSUME A SPY PAGE
	PUSHJ	P,TSSPT		;IS IT?
	  SKIPA	T3,JBTSGN##(J)	;NO, GET HIGH SEG STATUS
	JRST	[TLNN	T2,(<PM.DCD^!PM.ICD>B2)	;VIRTUAL SPY PAGE?
		 TROA	U,(T2)		;PROPAGATE PHYSICAL PAGE NUMBER
		 PUSHJ	P,PAGA10 ;IF VIRTUAL, HANDLE IT
		 JRST	PAGA1A]	;MERGE WITH COMMON CODE
>
IFE FTPEEKSPY,<
	MOVE	T3,JBTSGN##(J)
>
	JUMPE	T3,PAGAC3	;IF NO HI SEG AND NOT SPY PAGE, MUST BE WRITEABLE
	PUSHJ	P,TPNHS		;SEE IF PAGE IS IN HIGH SEG
	  TLOA	U,(PA.GHI)	;IT IS, FLAG AS SUCH
	JRST	PAGAC3		;LOW SEGMENT ERGO WRITEABLE
IFN FTPEEKSPY,<
	TLNN	T3,SPYSEG	;HIGH SEG ACTUALLY SPY SEG?
	JRST	PAGA1B		;NO, DON'T CHANGE
	HRR	U,T2		;YES, PROPAGATE PHYSICAL PAGE NUMBER
PAGA1A:	TLOA	U,(PA.GSP!PA.CPO) ;YES, TELL USER
>
PAGA1B:	TLNE	T3,SHRSEG	;CAN PAGE BE SHARED WITH ANYONE ELSE?
	TLO	U,(PA.GSH!PA.CPO) ;YES, FLAG IT AS SHARABLE
	TLNE	T3,UWPOFF	;UWP OFF (I.E.,WRITE-ENABLED)?
PAGAC3:	TLO	U,(PA.WRT)	;YES, PAGE IS CONTAINED IN THE HIGH SEGMENT AND THE
				; HIGH SEGMENT IS WRITABLE SO THE PAGE IS WRITABLE
	GETPC	T4,.JDAT+JOBPD1## ;PC OF THE PAGE ACCESSABILITY UUO
	TLNN	T4,(IC.LIP)	;UUO DONE FROM A CONCEALED PAGE?
	JRST	PAGAC5		;YES, PAGE CAN BE READ
	PUSHJ	P,GTPME		;CONTENTS OF THE MAP
	TDNE	T2,[PM.PUB]	;A PUBLIC PAGE?
	JRST	PAGAC5		;THEN THE PAGE CAN BE READ
	TLZ	T2,(PM.NAD)	;KEEP ONLY ADDRESS
	TLNN	U,(PA.OUT)
	CAMN	T2,[PM.ZER]	;IF NOT ABZ,
	CAIA
	JRST	PAGAC4		;PAGE CANNOT BE READ
	SKIPLE	T2,JBTSGN##(J)	;JOB HAVE A HI-SEG?
	TLNN	T2,GTSSEG	;WAS IT GETSEGED?
	JRST	PAGAC5		;NO, PAGE CAN BE READ
	TLNE	U,(PA.GHI)	;IS THE TARGET PAGE IN THE HI SEG?
PAGAC4:	TLZA	U,(PA.RED!PA.WRT);  YES, PAGE CANNOT BE READ
PAGAC5:	TLO	U,(PA.RED)	;HERE IF PAGE CAN BE READ
	TRNN	T1,HLGPNO	;PAGE ZERO OF SOME FLAVOR?
	PUSHJ	P,ISITS0	;YES, IS IT THE REAL PAGE ZERO?
	  TLNE	U,(PA.GSH!PA.GSP) ; OR SPY OR SHARABLE HISEG?
	TLOA	U,(PA.CPO!PA.AA);YES - NEVER PAGEABLE, ACCESS ALWAYS ALLOWED
	CAIA			;NO
	TLZ	U,(PA.OUT)	;YES - ALSO NEVER PAGED OUT
	TLNE	U,(PA.GSP)	;SPYING?
	JRST	PAGAC6		;YES - "LOCK" MEANINGLESS
	MOVSI	T2,NSHF!NSWP	;LOCKED BITS
	TLNN	U,(PA.GHI)	;IS IT A HIGH-SEGMENT PAGE
	SKIPA	T4,J		;NO, GET IT'S LOW SEG "NUMBER"
	HRRZ	T4,JBTSGN##(J)	;YES, GET ITS HIGH SEG "NUMBER"
	TDNE	T2,JBTSTS##(T4)	;IS PAGE IN LOCKED SEGMENT
	TLO	U,(PA.LCK!PA.CPO)	;YES, THEN ALSO CAN'T BE PAGED OUT
PAGAC6:	SKIPA	T1,U		;YES, THEN IT CANNOT BE PAGED OUT
PAGAC7:	MOVSI	T1,(PA.NXP)	;PAGE IS NON-EXISTANT
	POPJ	P,		;RETURN

PAGAC8:	POP	P,T2		;FIX STACK
	TDZA	T1,T1		;JUST SET THESE BITS
PAGAC9:	MOVE	T1,U
	TLO	T1,(PA.NXS!PA.NXP)	;NON-EXISTENT SECTION & PAGE
	POPJ	P,

IFN FTPEEKSPY,<
PAGA10:	MOVEI	T3,SPTTAB##(T2)	;ACTUAL POSITION IN SPT
	CAIL	T3,SPTLOW##	;IS IT MAPPED VIA JBTUPM?
	JRST	PAGA91		;NO, LOOK ON
	MOVS	T3,T2		;YES, GET ACTUAL PAGE OFFSET
	ANDI	T3,PG.BDY##	;MASK IT DOWN
	CAIL	T3,.UPCDB	;IS IT FOR THE CDB?
	CAILE	T3,.UPCDB+1	;EITHER PAGE?
	JRST	PAGA9C		;NO, CHECK OTHER CASES
	MOVEI	T3,<.CPCDB##+MCSEC1/PAGSIZ##>-.UPCDB(T3) ;YES, UPDATE TO PAGE NUMBER
	JRST	PAGA9A		;EXIT VIA COMMON CODE
PAGA9C:	CAIL	T3,SECTAB	;IF A SECTION MAP,
	CAILE	T3,SECTAB+HLGSNO ;OF ANY USER SECTION,
	HRRI	T3,<<<MCSEC1+FYSORG-<UMAPSN+UMAPS>>/PAGSIZ##>-.UMORG+SECTAB>(T3)
	HRRI	T3,<UMAPSN+UMAPS>/PAGSIZ##-SECTAB(T3) ;YES, ASSUME IN UMAPSN
PAGA9A:	HRR	U,T3		;COPY VIRTUAL PAGE SPIED UPON
	TLO	U,(PA.VSP)	;NOTE IS VIRTUAL
	SETZ	T3,		;FOR LATER
	POPJ	P,		;RETURN
PAGA91:
IFN FTXMON,<
	CAIL	T3,SPTHGH##	;IS IT IN SECTIONS 0/1?
	JRST	PAGA92		;NO, LOOK ON
>
	MOVS	T3,T2		;YES, GET ACTUAL PAGE OFFSET
	ANDI	T3,PG.BDY##	;MASK IT DOWN
	TRO	T3,<MCSEC1/PAGSIZ##> ;SET SECTION 1
	JRST	PAGA9A		;SET FOR MCSEC1, NOW RETURN IT
IFN FTXMON,<
PAGA92:	CAIL	T3,SPTCOM##	;IS IT IN MS.HGH?
	JRST	PAGA93		;NO, LOOK ON
	MOVS	T3,T2		;YES, GET ACTUAL PAGE OFFSET
	ANDI	T3,PG.BDY##	;MASK IT DOWN
	TRO	T3,<MS.HGH/PAGSIZ##> ;SET FOR FOR CORRECT SECTION
	JRST	PAGA9A		;RETURN IT
PAGA93:	SUBI	T3,SPTCOM##-<(MS.FMD)> ;CONVERT SPT LOC TO SECTION NUMBER
	LSH	T3,S2PLSH##	;THEN TO PAGE BASE
	MOVSS	T2		;GET PAGE OFFSET IN CORRECT PLACE
	ANDI	T2,PG.BDY##	;MASK IT DOWN
	TRO	T3,(T2)		;FORM FULL PAGE NUMBER
	JRST	PAGA9A		;RETURN IT
> ;END IFN FTXMON
> ;END IFN FTPEEKSPY
;HERE TO SET/CLEAR CACHE BITS IN THE LOW SEGMENT OF
; A LOCKED JOB

IFN FTLOCK,<
SETCSB:	SE1ENT
	MOVSI	T2,NSHF!NSWP	;JOB MUST BE LOCKED
	TDNN	T2,JBTSTS##(J)	;IS IT?
	JRST	UIFERR		;NOT IMPLEMENTED FOR JOBS NOT LOCKED
	MOVEI	T2,PA.IHB+PA.PME	;CHECK ARGUMENT LIST (PAGE MUST EXIST)
	PUSHJ	P,PLTSN		;VERIFY LIST
	  POPJ	P,		;BAD ARGUMENT LIST
	TLNE	M,HSPAG		;A HIGH SEGMENT PAGE SEEN?
	JRST	UIFERR		;YES, NOT IMPLEMENTED FOR HIGH SEGMENTS
	ADD	T3,T2		;TOTAL NUMBER OF PAGES IN THE ARGUMENT LIST
	PUSHJ	P,FSTPAG	;POINT M AT FIRST ARGUMENT - 1
SETCS1:	PUSHJ	P,NXTPAG	;NEXT ARGUMENT
	HRRZ	T2,T1		;JUST PAGE #
	LSH	T2,P2SLSH##	;CONVERT TO SECTION #
	SKIPN	.UPMP+SECTAB(T2) ;IF SECTION DOESN'T EXIST
	JRST	SETCS2		;IT MUST BE PG.IDC SO IGNORE
	PUSHJ	P,GTPME		;GET MAP ENTRY
	TDZN	T2,T2		;ARE ANY BITS SET IN T2 (CLEAR ALWAYS)?
	JRST	SETCS2		;IGNORE NON-EX PAGE
	TLNE	T1,(PG.GAF)	;SET OR CLEAR THE CACHE BIT?
	TLOA	T2,(<IORM T1,(T4)>) ;SET CACHE BIT
	MOVSI	T2,(<ANDCAM T1,(T4)>)
	MOVSI	T4,(PM.CSH)
	XCT	T2		;SET OR CLEAR THE BIT
SETCS2:	SOJG	T3,SETCS1	;LOOP OVER THE ENTIRE ARGUMENT LIST
	PUSHJ	P,CSDMP##	;FLUSH THE CACHE
	JRST	FIXMJ1		;CLEAR PAGING MEMORY AND RETURN
>
;HERE TO PAGE IN/OUT PAGES
PAGEB:	MOVEI	T2,PA.PME+PA.PMI+PA.PCI
	PUSHJ	P,PLTSN		;VERIFY THE ARGUMENT LIST (PAGE MUST EXIST
				; AND FOR PAGING OUT MUST BE IN CORE, FOR
				; PAGING IN THE PAGE MUST NOT BE IN CORE)
	  POPJ	P,		;ERROR IN THE ARGUMENT LIST
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSHJ	P,FSTPAG	;POINT M AT FIRST ARGUMENT - 1
	PUSHJ	P,SZCHK		;MAKE SURE THAT AFTER PAGING OUT THE REQUESTED PAGES
				; THAT PAGING IN THE REQUESTED PAGES WON'T EXCEED
				; THE USER'S PHYSICAL LIMIT
	  PJRST	TBGERR		;USER IS ATTEMPTING TO GET TO BIG
	JUMPN	T2,[HLRZ T4,.PDMVL##(W)
		    JUMPE T4,TBGERR
		    JRST .+1]
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES TO PAGE-IN
	PUSH	P,T2		;AND THE NUMBER OF PAGES TO PAGE-OUT
	MOVE	P1,T2		;TOTAL NUMBER OF PAGES TO XFER
	ADD	P1,T3
	PUSHJ	P,USRATE	;COMPUTE PAGING INTERVAL
	PUSHJ	P,SYRATE	;COMPUTE SYSTEM-WIDE PAGING INTERVAL
	MOVE	T1,TICSEC##	;HAS HE GOT A VIRTUAL TIMER RUNNING?
	SKIPN	.PDTMC##(W)
	MOVEM	T1,.PDTMC##(W)	;NO, GET TIME INTERRUPTS ANYWAY
;HERE TO GET SWAPPING SPACE
	MOVE	U,(P)		;NUMBER OF PAGES OF DISK SPACE TO ALLOCATE
				; FOR PAGING OUT PAGES
	JUMPE	U,PAGEB1	;IF NO PAGES TO PAGE-OUT PROCEED WITH PAGING IN
	MOVN	P1,(P)		;NEGATIVE NUMBER OF PAGES TO GO OUT
;	MOVE	U,T1		;STARTING DISK ADDRESS
	PUSHJ	P,PAGOMT	;SETUP MEMTAB FOR PAGING OUT THE PAGES INDICATED
				; BY THE USER
IFN FTMP,<
	SETOM	SAVCTL##	;MAKE SURE CACHE GETS SWEPT
>
	PUSHJ	P,FSTPAG	;RESET ARG LIST
PAGEB1:	POP	P,T2		;RESTORE THE NUMBER OD PAGES TO BE PAGED-OUT
	POP	P,T3		;AND THE NUMBER OF PAGES TO BE PAGED-IN
	SKIPN	.USTMU		;ANY PAGES ON THE INCORE QUEUES?
	JUMPE	T3,FIXMJ1	;CLEAR THE A.M. AND RETURN TO THE USER IF
				; THERE ARE NO PAGES TO BE PAGED IN
	MOVE	P2,T3		;SAVE THE NUMBER OF PAGES REQUIRED
	SETZB	T1,P4		;INDICATE NO PAGES ALLOCATED
	SKIPN	P1,T3		;SKIP IF SOME PAGES "REALLY" NEED TO BE PAGED IN
	JRST	PAGEB2		;ALL PAGES TO BE PAGED IN ARE ALREADY IN CORE
	SKIPE	.USTMU		;ANY PAGES ON QUEUES?
	PUSHJ	P,PAGIMT	;FILL IN THE QUEUE PAGES
	  JFCL			;SHOULD ALWAYS BE HERE
	MOVE	T3,P1		;# OF PAGES TO ALLOCATE
	PUSHJ	P,FSTPAG	;POINT M AT FIRST ARGUMENT - 1
	PUSHJ	P,FRDCRW##	;ENOUGH PAGES IN CORE TO SATISFY THIS REQUEST?
	  JRST	[SE1ENT		;SECTION 1 FOR CALLS TO GETPME
		 SETZ	P3,	;NO NON-EX SECTION MAPS
		 MOVE	T3,P2	;# OF PAGES TO REALLY PAGE IN
		 PJSP	P4,CHGP11] ;CREATE ON DISK
	LDB	T1,JBYLSA##	;FIRST PAGE OF JOB
	MOVE	T2,P2		;SETUP ARGUMENTS TO ADPAGS
	PUSHJ	P,ADPAGS##	;ALLOCATE THE REQUIRED NUMBER OF PAGES
;HERE WITH T1 = FIRST PHYSICAL PAGE ALLOCATED
PAGEB2:	MOVEI	P4,0		;INDICATE INITIAL CALL TO PAGIMT
	PUSH	P,P2		;SAVE # OF PAGES ALLOCATED
	MOVN	P3,P2		;GET -# OF PAGES INTO P3
	PUSHJ	P,PAGIMT	;SETUP MEMTAB FOR PAGING INPUT
	  JRST	PAGEB6		;PAGES BEING INPUT ARE CONTIGUOUS ON THE DISK
;HERE ON A PAGE IN WHEN THE PAGES ARE FRAGMENTED
	SUBM	P4,(P)		;-# OF PAGES REMAINING ON STACK
	MOVMS	(P)		;+# OF PAGES REMAINING ON STACK
	TLO	P3,(MT.LEF)	;INDICATE NOT LAST FRAGMENT
	MOVE	P1,P4		;SAVE THE NUMBER OF PAGES IN THIS FRAGMENT
	MOVEI	P4,0		;INDICATE THE START OF A FRAGMENT TABLE
	PUSHJ	P,GT4MR		;GET A 4 WORD CORE BLOCK FOR THIS FRAGMENT
	  JRST	PAGE10		;NO AVAILABLE
	PUSH	P,P4		;SAVE THE START ADDRESS OF THE CORE BLOCK
PAGEB3:	MOVE	P2,P4		;P2 = AN AOBJN POINTER TO THE CURRENT BLOCK
				; IN THE FRAGMENT TABLE
PAGEB4:	DPB	P3,[POINT SL.SPN,P1,<^L<SL.PPN>+SL.SPN-1>]
	MOVEM	P1,(P2)		;STORE THE SWPLST ENTRY FOR THIS FRAGMENT
	JUMPGE	P3,PAGEB5	;JUMP IF THIS IS THE LAST FRAGMENT
	MOVEI	P4,0		;INITIALIZE THE COUNTEROF THE NUMBER OF PAGES
				; IN THIS FRAGMENT
	MOVN	P3,-1(P)	;-# OF PAGES USABLE
	PUSHJ	P,PAGIMT	;SETUP MEMTAB FOR THIS FRAGMENT
	  TLZA	P3,(MT.LEF)	;INDICATE LAST FRAGMENT
	TLO	P3,(MT.LEF)	;INDICATE NOT LAST FRAG
	SUBM	P4,-1(P)	;# OF PAGES REMAINING
	MOVMS	-1(P)
	MOVE	P1,P4		;SAVE THE NUMBER OF PAGES IN FRAGMENT
	AOBJN	P2,PAGEB4	;STORE THE FRAGMENTED SWPLST ENTRY AND CONTINUE
	MOVE	P4,P2		;T4 = POINTER TOFRAGMENT TABLE
	PUSHJ	P,GT4MR		;ADD ANOTHER BLOCK TO THE FRAGMENT TABLA
	  JRST	PAGEB9		;NONE AVAILABLE
	JRST	PAGEB3		;CONTINUE
PAGEB5:	SETZM	1(P2)		;ZERO LAST ENTRY + 1 IN FRAGMENT TABLE
	POP	P,T1		;RESTORE THE POINTER TO THE START OF THE
				; FRAGMENT TABLE
	HRLI	T1,FRGSEG	;INDICATE A FRAGMENTED SWPLST ENTRY
	ADJSP	P,-1		;CLEAN JUNK OFF THE STACK
	JRST	PAGEB7		;MAKE THE ENTRY IN SWPLST AND DO THE I/O
PAGEB6:	POP	P,(P)		;FIX STACK (# OF PAGES ALLOCATED)
	MOVE	T1,P4		;BUILD A SWPLST ENTRY
	DPB	P3,[POINT SL.SPN,T1,<^L<SL.PPN>+SL.SPN-1>]
PAGEB7:	JUMPE	P2,PAGEB8	;GO IF NO I/O TO DO
	PUSHJ	P,PAGEIT	;PAGE THE PAGES IN
	  JRST	PIOERR		;PAGING I/O ERROR
PAGEB8:	SKIPN	T1,.USNXP	;IF RANGE SPECIFIED GET HIGHEST PAGE
	PUSHJ	P,GETWSU##	;GET LAST (HIGHEST) PAGE BEING CREATED
	PUSHJ	P,JSTVRT	;ZERO .UPVRT IF NOW NON-VIRTUAL
	PJRST	FIXMJ1		;CLEAR THE A.M. AND RETURN TO THE USER
PAGEB9:	POP	P,(P)		;POP OFF JUNK
PAGE10:	HALT	.		;AND RECOVER (NOT IMPLIMENTED)
;SUBROUTINE TO SETUP MEMTAB AND THE UPMP FOR A PAGE IN
;CALLING SEQUENCE:
;	MOVE	T1,FIRST PHYSICAL PAGE ALLOCATED
;	MOVE	M,ADDRESS - 1 OF FIRST PAGE IN THE ARGUMENT LIST
;	MOVEI	P3,-# OF PAGES ALLOCATED (ONLY NEEDED IF P1=/=0)
;	MOVEI	P4,0
;	PUSHJ	P,PAGIMT
;RETURNS CPOPJ1 WHEN A NON-CONTIGUOUS DISK ADDRESS IS FOUND, CPOPJ WHEN
; THE ENTIRE ARGUMENT LIST HAS BEEN SCANNED, RETURNS P4 = # OF PAGES,
; P3 = FIRST PHYSICAL PAGE

PAGIMT:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	SE1ENT			;MUST BE IN SECTION 1 TO ADDRESS PAGTAB/MEMTAB
	HRLZS	P3		;MAKE AOBJN POINTER
	MOVE	P1,T1		;SAVE THE FIRST PHYSICAL PAGE ALLOCATED
	PUSH	P,[0]		;INIT FIRST VIRTUAL,,FIRST PHYSICAL
	PUSH	P,[0]		;INIT PREV DSK ADDR+PREV PHYS PAG
PAGIM1:	PUSHJ	P,INTLVL##	;AT INTERRUPT LEVEL?
	  TRNE	P3,777		;NO, DONE ~1000 PGS
	CAIA			;DON'T WAIT
	PUSHJ	P,SCDCHK##
	PUSHJ	P,NXTPAG	;GET THE NEXT USER ARGUMENT
	JUMPL	T1,PAGIM1	;JUMP IF ARGUMENT INDICATES PAGE TO BE PAGED-OUT
	HRRZS	T1		;CLEAR JUNK
	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE MAP
IFN FTPEEKSPY,<
	TLNE	T2,(PM.SPY)	;SPY PAGE?
	JRST	PAGIM1		;YES, DON'T TRY TO PAGE IT
>
	MOVE	T3,T2		;PRESERVE DISK ADDRESS ACROSS CALL TO TSWST	
	PUSHJ	P,TSWST		;ALREADY IN THE WORKING SET?
	  TDNN	T3,[PM.ADR^!PM.ZER] ;NO, ABZ?
	JRST	PAGIM1		;ALREADY IN OR ABZ PAGE (PG.IDC)
	PUSHJ	P,GTPME		;GET CONTENTS AND POINTER AGAIN
	SKIPN	.USTMU		;PAGES ON INCORE QUEUES?
	JRST	PAGIM4		;NO, SKIP THIS
	TLZ	T2,(PM.NAD)	;ISOLATE ADDRESS
	TLNE	T3,(PM.OIQ)	;IS THIS PAGE ON THE "IN" QUEUE?
	JRST	PAGIM2		;YES, SHOULD BE ON OUR QUEUE THEN
	HRRZ	T4,.USTMU	;GET HEADER FOR PRIVATE QUEUE
	SKIPE	T4		;ANYTHING THERE?
	PUSHJ	P,SRCPQ0	;YES, SEARCH QUEUE FOR PAGE
	  JRST	PAGIM4		;NOT THERE
	PUSH	P,T1		;SAVE T1
	PUSH	P,T4		;AND T4
	PUSHJ	P,DLTPGD	;RETURN THE DISK PAGE
	POP	P,T2		;RESTORE PAGE NUMBER TO T2
	POP	P,T1		;RESTORE T1
PAGIM2:	HRRZ	T3,.USTMU	;FIRST PAGE ON PRIVATE LIST?
	CAIE	T3,(T2)		;?
	JRST	[PUSHJ	P,LKPSF	;NO, JUST LINK PAST
		 JRST	PAGIM3]	;CONTINUE
	SSX	T3,MS.MEM	;POINT TO RIGHT SECTION
	HRR	T3,PAGTAB(T3)	;GET SUCCESSOR (IF ANY)
	HRRM	T3,.USTMU	;RESET LIST HEADER
	TRNE	T3,-1		;IF THERE IS A SUCCESSOR
	HLLZS	PT2TAB(T3)	;CLEAR HIS BACK LINK
	HLLZS	@[IW MS.MEM,PAGTAB(T2)] ;CLEAR LINKS IN REMOVED PAGE
	HLLZS	@[IW MS.MEM,PT2TAB(T2)]
;HERE WITH PHYSICAL PAGE NUMBER IN T2
PAGIM3:	MOVE	P2,T2		;PUT THIS PAGE ON THIS JOB'S PAGTAB CHAIN
	LDB	T3,JBYLSA##	; BUT PUT IT AT THE FRONT
	SSX	P2,MS.MEM	; ...
	HRRM	T3,PT2TAB(P2)	;JBYLSA IS PREVIOUS TO US
	SSX	T3,MS.MEM	; SO THAT A ZERO INDICATES THE LAST PAGE
	EXCH	T2,PAGTAB(T3)	; ALLOCATED FOR THIS PAGE IN
	MOVEM	T2,PAGTAB(P2)	; ...
	SSX	T2,MS.MEM
	TRNE	T2,-1		;IF NOT LAST PAGE
	HRRM	P2,PT2TAB(T2)	;STORE BACK LINK
	MOVSI	T2,(P2.TRN)	;CLEAR TRANSIENT BIT
	ANDCAM	T2,PT2TAB(P2)
	PUSHJ	P,GTPME		;GET CONTENTS AND POINTER AGAIN
	TLO	P1,400000	;PAGE ISN'T IN PAGTAB
	HRRZS	P2		;CLEAR SECTION NUMBER
	AND	T2,[PM.NAD]	;ISOLATE ACCESS BITS
	IOR	P2,T2		;ACCESS BITS+PHYSICAL PAGE NUMBER FOR BELOW
	JRST	PAGIM7		;PUT THE PAGE IN THE WORKING SET
;HERE WHEN THE PAGE ISN'T ON A QUEUE, T2=MAP CONTENTS, P1=PHYSICAL PAGE NUMBER,
; 0(P)=PREVIOUS PHYSICAL PAGE NUMBER+PREVIOUS DISK ADDRESS OR 0 IF FIRST TIME
; THROUGH FOR THIS FRAGMENT
PAGIM4:	JUMPE	P1,PAGIM1	;IF NO CORE ALLOCATED
	ADDI	P4,1		;BUMP COUNT OF NUMBER OF PAGES IN THIS FRAGMENT
	SSX	P1,MS.MEM	;PAGTAB SECTION
	MOVE	P2,T2		;MAP CONTENTS TO P2
	TLZ	T2,(PM.NAD)	;ISOLATE DISK ADDRESS
	MOVEM	T2,MEMTAB(P1)	;STORE DISK ADDRESS
	SKIPE	-1(P)		;FIRST TIME THROUGH FOR THIS FRAGMENT?
	JRST	PAGIM5		;NO
	HRRZM	P1,-1(P)	;YES, REMEMBER FIRST PHYSICAL PAGE IN FRAGMENT
	HRLM	T1,-1(P)	;AND FIRST VIRTUAL PAGE IN FRAGMENT
	JRST	PAGIM6		;SKIP ON SINCE DON'T KNOW NEXT VIRTUAL PAGE NUMBER YET
PAGIM5:	LDB	T2,[POINT 14,(P),35] ;PHYSICAL PAGE NUMBER FROM LAST TIME
	SSX	T2,MS.MEM	;PAGTAB SECTION
	DPB	T1,NVPNT2	;STORE NEXT VPN
	PUSHJ	P,GTPME		;GET MAP CONTENTS
	MOVE	P2,T2		;COPY IT
	LDB	T3,[POINT 21,(P),20] ;PREVIOUS DISK ADDRESS
	AOS	T3		;FOR AJACENCY CHECK
	XOR	T3,T2		;END THIS FRAGMENT? (THIS DISK ADDRESS
	TDNE	T3,[PM.ADR]	; NOT ADJACENT TO LAST)
	SOJA	P4,PAGIM9	;FINISH UP THIS FRAGMENT
PAGIM6:	DPB	P1,[POINT 14,(P),35] ;SAVE PHYSICAL PAGE
	DPB	T2,[POINT 21,(P),20] ; AND DISK ADDRESS FOR NEXT TIME THROUGH
;HERE TO PUT PHYSICAL PAGE INTO THE MAP, P1=PHYSICAL PAGE NUMBER IF POSITIVE,
; P2=PHYSICAL PAGE NUMBER IF P1 IS NEGATIVE, LH(P2)= ACCESS BITS FOR PAGE,
; T4=BYTE POINTER TO THE MAP
PAGIM7:	MOVE	T3,T4		;SAVE BYTE POINTER
	PUSHJ	P,WSBIT		;CHECK TO SEE IF THE PAGE IS IN THE WORKING
				; SET (STOP IF IT IS), AND RETURN AN INDEX
				; AND THE BIT POSITION TO ADD IT TO THE WORKING SET
	AOS	JBTIMI##(J)	;INCREASE THE NUMBER OF PAGES IN CORE
	.CREF	IMGIN
	IORM	T2,(T4)		;ADD THIS PAGE TO THE WORKING SET
	MOVSI	T2,(PM.BTS)
	AND	T2,P2		;GET BITS FROM PREVIOUS ENTRY CONTENTS
	SKIPGE	P1		;PAGE ALREADY IN CORE?
	TROA	T2,(P2)		;YES, PHYSICAL PAGE NUMBER IS IN P2
	HRRI	T2,(P1)		;PHYSICAL PAGE #
	TLNN	P2,(PM.AAB)	;SHOULD ACCESS ALLOWED BE ON FOR THIS PAGE?
	TLZA	T2,(<PM.DCD>B2)
	TLO	T2,(<PM.DCD>B2)
	TLO	T2,(PM.COR)	;CORE ADDRESS
	MOVEM	T2,(T3)		;MAP THIS PAGE INTO THE USERS ADDRESS SPACE
	PUSH	P,T2		;INCHJ CLOBBERS T2
	PUSHJ	P,INCHJ		;INCREMENTED THE NUMBER OF PAGES IN THE
				; HIGH SEGMENT THAT ARE IN CORE
	POP	P,T2		;RESTORE PAGE NUMBER
	TLZN	P1,400000	;PAGE WAS ON A QUEUE?
	JRST	PAGIM8		;NO
	MOVSI	T3,1		;"DECREMENT" COUNT OF PAGES ON QUEUE
	ADDB	T3,.USTMU	;...
	SKIPE	T3		;IF NOW ZERO (SHOULD BE IF DONE)
	AOJA	P3,PAGIM1	;NO, GO GET ANOTHER ARGUMENT
	JUMPE	P1,PAGI10	;DONE IF NO REAL PAGES (SHOULD BE TRUE)
	AOJA	P3,PAGIM1	;YES, SETUP TO PAGE THEM IN
PAGIM8:	SSX	P1,MS.MEM	;PAGTAB SECTION
	SKIPGE	P1,PAGTAB(P1)	;GET THE NEXT PHYSICAL PAGE ALLOCATED
	STOPCD	CPOPJ##,DEBUG,APF,	;++ALLOCATED PAGE FREE
	AOBJN	P3,PAGIM1	;IF NO QUEUED PAGES, ARE THERE MORE PHYSICAL?
	SKIPE	.USTMU		;STILL SOME QUEUED PAGES?
	JRST	PAGIM1		;YES, GO PUT THEM IN THE MAP
	JRST	PAGI10
;HERE WHEN FRAGMENTED
PAGIM9: PUSHJ	P,PREPAG	;BACK UP
	MOVE	T1,P1		;WHERE TO START ON NEXT CALL
	AOSA	-2(P)		;FRAGMENTED RETURN
PAGI10:	LDB	P1,[POINT 14,(P),35] ;GET LAST PHYSICAL PAGE
	POP	P,T2		;POP OFF REMINDER
	POP	P,P3		;FIRST VIRTUAL,,FIRST PHYSICAL
	JUMPE	T2,CPOPJ##	;RETURN IF ALL PAGES ARE ALREADY IN CORE
	SSX	P1,MS.MEM	;MEMTAB SECTION
	HLRZ	P2,P3		;FIRST PAGE OF FRAGMENT
	DPB	P2,NVPNP1	;SET NEXT PAGE OF FRAGMENT
	MOVSI	P2,(MT.LEF)
	IORM	P2,MEMTAB(P1)	;STORE AS LAST PAGE OF FRAGMENT
	POPJ	P,
;SUBROUTINE TO SETUP MEMTAB FOR PAGING OUT
;CALLING SEQUENCE:
;	MOVE	M,ADDRESS - 1 OF ENTRY IN THE ARGUMENT LIST
;	MOVE	U,XWD - NUMBER OF PAGES ALLOCATED CONTIGUOUSLY ON THE DISK,
;		STARTING DISK ADDRESS
;	MOVEI	P1,-# OF PAGES TO GO OUT
;	MOVEI	P3,0
;	PUSHJ	P,PAGOMT
;ALWAYS RETURNS CPOPJ

PAGOMT:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	SE1ENT			;MUST BE IN SECTION 1
PAGOM1:	PUSHJ	P,INTLVL##	;AT INTERRUPT LEVEL?
	TRNE	P1,777		;IF NOT, STOP APPROX EVERY 1000 PGS
	CAIA
	PUSHJ	P,SCDCHK##
	PUSHJ	P,NXTPAG	;GET THE NEXT ARGUMENT FROM THE USER'S ARGUMENT LIST
	JUMPGE	T1,PAGOM1	;JUMP IF THE ARGUMENT REQUESTS PAGING-IN
PAGOM2:	HRRZS	T1		;PAGING-OUT, CLEAR THE HIGH ORDER BITS
	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE MAP
IFN FTPEEKSPY,<
	TLNE	T2,(PM.SPY)	;SPY PAGE?
	JRST	PAGOM1		;YES, DON'T TRY IT
>
	MOVE	T3,T2		;SAVE ENTRY
	PUSHJ	P,TSWST		;IN THE WORKING SET?
	  JRST	PAGOM1		;IDC MUST HAVE BEEN ON IF IT ISN'T IN THE WS
	TDNE	T3,[PM.ADR^!PM.ZER] ;ABZ PAGE?
				;(ZERO ENTRY SHOULD BE CAUGHT BY PLTSN)
	.CREF	IMGIN
	SOSA	JBTIMI##(J)	;DECREMENT # OF PAGES IN CORE
	JRST	PAGOM1		;ABZ OR IN CORE, MUST BE PG.IDC
	TLZ	T3,(PM.NAD)	;CLEAR ACCESS BITS (GET PHYS PAGE NUM)
	JUMPN	P3,PAGOM3	;JUMP IF NOT FIRST TIME THROUGH FOR THIS FRAGMENT
	HRLI	P3,(T1)
	HRR	P3,T3		;REMEMBER FIRST VIRTUAL AND FIRST PHYSICAL PAGE
PAGOM3:	MOVE	P2,T3		;SAVE PHYSICAL PAGE NUMBER
	PUSH	P,T1		;SAVE VIRTUAL PAGE NUMBER
	MOVE	T2,P2		;ARG FOR LKPSP
	PUSHJ	P,LKPSF		;LINK PAST THE PHYSICAL PAGE IN PAGTAB
	MOVE	T1,P2		;CURRENT PHYSICAL PAGE
	MOVEI	T3,PAGINQ##	;ASSUME PAGE IS TO GO ON THE "IN" QUEUE
	TLNE	M,ARGMD		;DID THE USER SPECIFY SLOW SWAPPING SPACE?
	MOVEI	T3,PAGSNQ##	;YES, PUT THE PAGE ON THE SLOW SWAPPING "IN" QUEUE
	EXCH	T1,(T3)		;MAKE IT FIRST PAGE ON "IN" QUEUE
	SSX	P2,MS.MEM	;PAGTAB SECTION
	MOVEM	T1,PAGTAB(P2)	;LINK PREVIOUS FIRST PAGE INTO QUEUE
	HLLZS	PT2TAB(P2)	;WE HAVE NO PREVIOUS
	SSX	T1,MS.MEM
	TRNE	T1,-1
	HRRM	P2,PT2TAB(T1)	;SET BACK LINK IF NOT LAST
	AOS	1(T3)		;INCREMENT NUMBER OF PAGE ON "IN" QUEUE
	POP	P,T1		;RESTORE VIRTUAL PAGE NUMBER
	PUSHJ	P,DECHJ		;DECREMENT NUMBER OF PAGES IN CORE IF A HIGH SEGMENT
	PUSHJ	P,TSWST		;IS THIS PAGE IN THE WORKING SET? (MUST BE)
	  STOPCD PAGOM2,DEBUG,PIW,		;++PAGE ISN'T IN WORKING SET
	ANDCAM	T2,(T4)		;IT WON'T BE AFTER PAGING IT OUT
	PUSHJ	P,GTPME		;GET MAP CONTENTS AGAIN
	TLZ	T2,(<PM.DCD>B2!PM.COR) ;NO ACCESS, MAKE IT LOOK OUT
	TLO	T2,(PM.OIQ)	;INDICATE ON "IN" QUEUE
	TLNE	M,ARGMD		;DID THE USER SPECIFY SLOW SWAPPING?
	TLO	T2,(PM.SSP)	;YES, REMEMBER THAT TOO
	MOVEM	T2,(T4)		;STORE IT BACK IN THE MAP
	DPB	T1,NVPNP2	;STORE VIRTUAL PAGE #
	.CREF	P2.MBZ		;IMPLIED BIT SET
	MOVE	T2,.USJOB	; AND JOB NUMBER (FOR SWAPPER FIXUP)
	LSH	T2,<^D35-<^L<MT.JOB>+MT.SJB-1>>
	MOVEM	T2,MEMTAB(P2)	;SET MEMTAB, CLEARING REST
	AOJL	P1,PAGOM1	;LOOP OVER ALL PAGES TO BE PAGED OUT
	S0JRST	JSTVRT		;SET .UPVRT NON-0, UPDATE VMCMAX AND RETURN
;SUBROUTINE TO COMPUTE THE PAGING-RATE FOR A USER
;ENTER WITH P1=NUMBER OF PAGES IN THE UUO
;EXIT LH(.PDVRT)=T1 CONTAINING THE NEW INTERVAL
USRATE::PUSH	P,W		;SAVE W
	PUSHJ	P,FNDPDB##	;GET PDB
	  JRST	WPOPJ##
	PUSHJ	P,GTDTIM	;GET DELTA TIME MT2
	IDIVI	T2,(P1)		;BIAS BY NUMBER OF PAGES XFERRED
	CAMLE	T2,MAXINT##	;GREATER THAN MAX INTERVAL?
	MOVE	T2,MAXINT##	;YES, USE MAX INTERVAL
	IMUL	T2,VMCNST##	;ALPHA(*(DELTA-T)/N)
	HLRZ	T1,.PDVRT##(W)
	IMUL	T1,VMCDIF##	;(EXP-ALPHA)*INT(I-1)
	ADD	T1,T2		;ADD IN THE CURRENT CONTRIBUTION
	IDIV	T1,VMCEXP##	;SCALE IT
USRAT1:	HRLZM	T1,.PDVRT##(W)	;AND SAVE NEW VALUE
	JRST	WPOPJ##

;SUBROUTINE TO COMPUTE THE SYSTEM-WIDE PAGING RATE

SYRATE::MOVE	T1,UPTIME##
	SUB	T1,LSFTIM##	;COMPUTE SYSTEM-WIDE PAGING INTERVAL
	IDIVI	T1,(P1)
	IMUL	T1,VMCNST##
	MOVE	T2,JBTVIR##
	IMUL	T2,VMCDIF##
	ADD	T1,T2
	IDIV	T1,VMCEXP##
	MOVEM	T1,JBTVIR##	;SAVE SYSTEM-WIDE INTERVAL
	MOVE	T2,UPTIME##	;SAVE LAST FAULT TIME
	MOVEM	T2,LSFTIM##
	POPJ	P,

;SUBROUTINE TO ADJUST PAGING RATE OF USER IF NO PAGES TRANSFERRED DURING INTERVAL
PGRUPD::PUSH	P,W
	PUSHJ	P,GTDTIM	;GET DELTA-TIME IN T2
	CAMLE	T2,MAXINT##	;IF TOO BIT
	MOVE	T2,MAXINT##	;THEN CUT DOWN
	IMUL	T2,VMCNST##	;ADJUST BY PAGE RATE ALGORITHM
	IDIV	T2,VMCDIF##	;..
	PUSHJ	P,FNDPDB##	;GET PDB
	  TDZA	T1,T1		;?
	HLRZ	T1,.PDVRT##(W)
	ADD	T1,T2		;ADJUST BY TIME GONE BY
	CAMLE	T1,MAXINT##	;CHECK FOR OVERFLOW
	MOVE	T1,MAXINT##	;IF SO, USE MAXIMUM
	JRST	USRAT1		;SAVE NEW VALUE AND RETURN

;SUBROUTINE TO COMPUTE DELTA TIME.
; STARTS NEW INTERVAL, RETURNS TIME DURING LAST INTERVAL IN T2
GTDTIM:	MOVE	T1,.PDTTM##(W)	;GET CURRENT RUN TIME
	MULI	T1,RTUPS##	;CONVERT TO 10-MICRO SEC UNITS
	ADD	T2,.PDTT2##(W)
	DIV	T1,TICSEC##	;CONVERT
	MOVE	T2,T1
	SUB	T2,.USLFT	;COMPUTE DELTA-TIME
	MOVEM	T1,.USLFT	;SAVE NOW AS LAST FAULT TIME
	POPJ	P,		;RETURN
;SUBROUTINE TO SCAN PAGTAB
;RETURNS T1= LAST PAGE IN PAGTAB CHAIN
;SCNPT PRESERVES T3

SCNPTB:	SE1ENT			;GET TO SECTION 1 TO ADDRESS PAGTAB
	LDB	T1,JBYLSA##	;GET FIRST PAGE ALLOCATED TO THIS JOB
	TLZA	P4,-1		;INDICATE NO PREDESSOR
SCNPT1:	HRRZ	T1,T2		;PREDESSOR TO NEXT PAGE
	SSX	T1,MS.MEM	;PAGTAB SECTION
	SKIPGE	T2,PAGTAB(T1)	;GET NEXT PAGE ALLOCATED TO THIS JOB
	STOPCD	.+1,DEBUG,IPF,	;++IN-USE PAGE FREE
	HRRZS	T2
	JUMPN	T2,SCNPT1	;JUMP IF NOT LAST PAGE ALLOCATED TO JOB
	HRRZS	T1		;CLEAR SECTION NUMBER
	POPJ	P,		;RETURN


;MAKE SWPLST ENTRY, START IO, RETURN SWPLST INDEX IN T2
PGWAIT:	MOVEI	T2,PIOWQ##	;PAGE I/O QUEUE CODE
	DPB	T2,PJBSTS##	;PUT THE JOB INTO PAGE I/O WAIT
IFN FTMP,<
	PUSH	P,T1		;SETCSJ DESTROYS T1
	PUSHJ	P,SETCSJ##	;SET JBTST3 ETC. IN CASE NEXT IS CALLED
	POP	P,T1		;RESTORE SWPLST ENTRY
>
	PUSHJ	P,MAKSLE	;MAKE THE SWPLST ENTRY
	HRRM	T2,.USSLX
	PUSHJ	P,SQOUT##	;START THE PAGING IO
	HRRZ	T2,.USSLX	;GET SWPLST INDEX
	MOVE	J,.CPJOB##	;CURRENT JOB'S JOB NUMBER
	MOVE	R,JBTADR##(J)	;ADDRESS OF THE JOB
IFN FTMP,<
	PUSHJ	P,REMMM##	;REMEMBER STATE OF THE MM
>
	PUSHJ	P,WSCHED##	;WAIT UNTIL IT IS RUNNABLE AGAIN
	MOVE	T1,SWPLST##(T2)	;GET THE SWPLST ENTRY FOR THIS PAGING OPERATION
	TLNN	T1,(SL.CHN+SL.ERR)
	AOS	(P)		;SKIP RETURN SINCE NO PAGING I/O ERRORS
	POPJ	P,		;RETURN TO WAITER


;SUBROUTINE TO GET A PAGE INTO CORE
;ENTER T1=SWPLST ENTRY
;RETURNS WHEN PAGE IS IN CORE - CPOPJ IF IO ERROR, CPOPJ1 IF OK
PAGEIT::PUSHJ	P,SAVE1##	;SAVE P1
	PUSHJ	P,PGWAIT	;WAIT UNTIL ITS DONE
	  POPJ	P,		;PAGING I/O ERROR
	HRRZ	P1,T2		;INDEX INTO SWPLST
	AOS	(P)		;OK RETURN
	PJRST	DLTSLX		;DELETE THE SWPLST ENTRY AND RETURN
;HERE TO CREATE OR DELETE PAGES

CHGPGS:	MOVEI	T2,PA.PME+PA.PCE;PAGE MUST EXIST ON DESTROY, CANNOT ON CREATE
	PUSHJ	P,PLTSN		;VALIDATE THE ARGUMENT LIST
	  POPJ	P,		;ILLEGAL ARGUMENT
	TLNE	M,HSPAG		;ANY HI SEG PAGES IN ARG LIST?
	JUMPN	T2,IALERR	;YES, CANT DELETE HI-SEG PAGES
	PUSHJ	P,FSTPAG	;POINT M AT THE USER'S ARGUMENT LIST
	PUSHJ	P,SZCHKX	;MAKE SURE THAT THE JOB WON'T BE TO BIG IF
				; PAGES ARE CREATED AFTER DESTROYING THOSE
				; SPECIFIED IN THE ARGUMENT LIST
	  JRST	[TLNN	M,ARGMD	;TRYING TO GET TO BIG
		 JRST	TBGERR
		 JRST	.+1]
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	MOVE	P3,T4		;#SECTION MAPS+.WSBNZ
	SUBI	T1,(T2)		;CURRENT VIRTUAL SIZE MINUS PAGE BEING DESTROYED
	SUB	T1,.USTMU	;MINUS ALLOCATED BUT ZERO PAGES
	ADDI	T1,(T3)		;REAL NEW SIZE
	HLRZ	T4,.PDCVL##(W)	;CURRENT VIRTUAL LIMIT
	CAILE	T1,UPMPSZ##(T4)	;TRY TO GET TO BIG?
	JUMPN	T3,[JUMPN T4,TBGERR ;YES, ERROR RETURN
		    TLNE M,ARGMD
		    JRST NVLERR
		    JRST .+1]
	MOVE	T1,T3		;NUMBER OF PAGES BEING CREATED
	SUBI	T1,(T2)		;MINUS THE NUMBER OF PAGES BEING DESTROYED
	SUB	T1,.USTMU	;MINUS ALLOCATED BUT ZERO PAGES
				; (THEY'RE ALREADY ALLOCATED FOR IN VMCMAX)
	HRROI	T4,777000
	AND	T4,.USVRT	;GET VIRTUAL STATUS, EXCEPT ANA
	TLNE	M,ARGMD		;CREATING ABZ PAGES (IF SO WILL BE VIRTUAL)
	AOS	T4		;YES, BE SURE T4 IS NON-ZERO
	CAMLE	T1,VMCMAX##	;TRYING TO EXCEED MAX VM CORE?
	JUMPN	T4,NSAERR	;CHECK ONLY VALID IF NOT VIRTUAL
	ADDI	T1,(P3)		;PLUS NUMBER OF SECTION MAPS BEING CREATED
	CAMLE	T1,VIRTAL##	;IS THERE ENOUGH VIRTUAL CORE TO SATISFY THE REQUEST?
	JRST	NSAERR		;CAN NEVER EXCEED VIRTAL, HOWEVER
	ANDCMI	T4,777		;(CLEAR ANY AOS WE MAY HAVE DONE)
	JUMPE	T4,CHGPG1	;IF NOT ALREADY VIRTUAL, SETVRT WILL FIX VM(CMAX,TOTL)
	SUBI	T1,(P3)		;MAPS ETC NOT INCLUDED IN VMCMAX
	ADDM	T1,VMTOTL##
	MOVNS	T1
	ADDM	T1,VMCMAX##	;DECREASE TOTAL AMOUNT OF VIRTUAL CORE AVAILABLE
CHGPG1:	SE1ENT			;FOR PAGTAB/MEMTAB/PAGE MAP ENTRIES
	JUMPE	T2,CHGPG4	;JUMP IF NOT DESTROYING PAGES
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES BEING CREATED
	PUSH	P,T2		;AND THE NUMBER BEING DELETED
	PUSHJ	P,INTLVL##	;DON'T WAIT AT CLOCK LEVEL
	PUSHJ	P,IOWATM	;WAIT FOR I/O TO STOP
CHGPG2:	PUSHJ	P,NXTPAG	;GET THE NEXT ARGUMENT
	JUMPGE	T1,CHGPG2	;JUMP IF NOT A DELETE REQUEST
	HRRZS	P1,T1		;CLEAR THE HIGH ORDER BIT, CLEAR LEFT HALF OF P1
	MOVE	T3,T1
	LSHC	T3,P2SLSH##
	PUSHJ	P,GTPME		;GET PAGE MAP ENTRY NOW
	JUMPE	T2,CHGPG2	;DOESN'T REALLY EXIST (PG.IDC)
	EXCH	T1,T3
	PUSHJ	P,DECNZC	;DECREMENT NZS COUNT IF APPLICABLE
	EXCH	T1,T3
	PUSHJ	P,DLTPAG	;DELETE THE PAGE
CHGPG3:	SOSLE	T1,(P)		;DELETED ALL THAT WERE REQUESTED?
	JRST	[PUSHJ	P,INTLVL## ;AT INTERRUPT LEVEL?
		 TRNE	T1,777	;NO, STOP EVERY APPROX 1000 PAGES
		 JRST	CHGPG2	;AT CLOCK LEVEL OR LIMIT NOT EXPIRED
		 PUSHJ	P,SCDCHK## ;WAIT
		 JRST	CHGPG2]
	PUSHJ	P,FSTPAG	;RESTORE THE ARGUMENT LIST POINTER
	POP	P,(P)		;POP OFF JUNK
	POP	P,T3		;RESTORE THE NUMBER OF PAGES BEING CREATED
CHGPG4:	JUMPE	T3,FIXADR	;CLEAR THE A.M. AND RETURN TO THE USER IF NOT
				; CREATING PAGES
	ADDI	T3,(P3)		;INCLUDE SECTION MAPS BEING CREATED
	MOVE	P2,T3		;SAVE THE NUMBER OF PAGES BEING CREATED
	MOVN	T1,T3		;MINUS THE NUMBER OF PAGES BEING CREATED
	ADDM	T1,VIRTAL##	;UPDATE VIRTAL TO REFLECT THE DECREASE
	TLNE	M,ARGMD		;CREATING ABZ PAGES?
	SKIPE	T3,P3		;SHOULD ALLOCATE PAGES ANYWAY IF NEED MAPS
	CAIA
	JRST	CHGPG5		;CREATE ABZ PAGES (NO MAPS TO MAKE)
	PUSHJ	P,FRDCRW##	;ARE THERE ENOUGH PAGES IN CORE TO SATISFY REQUEST?
	  JRST	CHGP10		;NOT ENOUGH, EXPAND
	PUSH	P,P2		;# OF PAGES BEING CREATED
	TLNE	M,ARGMD		;UNLESS IT'S ALL ABZS
	MOVEM	T3,(P)		;THEN ONLY WANT # OF MAPS
	POP	P,T2		;RESTORE # OF PAGES TO GET
	LDB	T1,JBYLSA##	;FIRST PAGE OF JOB
	PUSHJ	P,ADPAGS##	;ALLOCATE THE PAGES
;HERE WITH T1 = FIRST PHYSICAL PAGE ALLOCATED
	SKIPA	P1,T1		;FIRST PHYSICAL PAGE ALLOCATED TO P1
CHGPG5:	SETZ	P1,		;NO PAGES ALLOCATED (ABZS ONLY)
	SUBI	P2,(P3)		;DON'T INCLUDE SECTION PAGES IN MAP COUNTER
CHGPG6:	PUSHJ	P,NXTPAG	;GET THE NEXT ARGUMENT
	JUMPL	T1,CHGPG6	;JUMP IF DELETE PAGE REQUEST
	HRRZS	T1		;CLEAR BIT 1
	LSHC	T1,P2SLSH##	;SECTION #
	PUSHJ	P,CRSMAP	;CREATE SECTION MAP AND/OR POINT TO IT
	MOVE	T3,T1		;SAVE SECTION #
	LSHC	T1,S2PLSH##	;BACK TO PAGE #
	PUSHJ	P,ISITNZ	;ONLY REMEMBER S0 PAGES
	HRL	P4,T1		;SAVE THE HIGHEST VIRTUAL PAGE SEEN SO FAR
	PUSHJ	P,GTPME		;GET POINTER TO THE MAP SLOT (PAGE NO IN T1)
	TLZ	T2,(PM.NAD)
	CAMN	T2,[PM.ZER]	;ABZ PAGE?
	JRST	CHGPG7		;YES
	JUMPN	T2,CHGPG6	;NO, MUST BE REAL PAGE (PG.IDC)
	EXCH	T1,T3		;SAVE PAGE #, GET SECION #
	PUSHJ	P,INCNZC	;INCREMENT AS REQUIRED
	MOVE	T1,T3		;RESTORE PAGE #
CHGPG7:	TLNN	M,ARGMD
	JRST	CHGPG8
	PUSH	P,T1		;SAVE T1
	CAMN	T2,[PM.ZER]
	PUSHJ	P,INSMEM	;YES, FIX VIRTAL
	POP	P,T1		;RESTORE PAGE #
	MOVE	P3,T4		;TPAHS DESTROYS T2
	PUSHJ	P,TPNHS		;A HIGH SEG PAGE?
	  SKIPG	JBTSGN##(J)	;YES, NON-SHARABLE?
	SKIPA	T2,[PM.WRT!PM.AAB!PM.CSH!PM.PUB+PM.ZER]	;WRITABLE IF NOT HIGH SEG
	MOVE	T2,[PM.AAB!PM.CSH!PM.PUB+PM.ZER]
	MOVEM	T2,(P3)		;STORE THAT IN THE MAP
	JRST	CHGPG9		;GET THE NEXT ARGUMENT
;HERE TO ADD A PAGE, T1=VIRTUAL PAGE NUMBER, P1 = PHYSICAL PAGE NUMBER,
; MAKE THE MAP ENTRY AND TURN ON THE BIT IN THE WORKING SET BIT TABLE
CHGPG8:	PUSHJ	P,INSPAG	;INSERT THE PAGE IN THE USER'S MAP
;HERE TO ZERO THE PAGE OBTAINED
	PUSHJ	P,ZERPAG	;ZERO THE PAGE
	PUSHJ	P,INCHJ		;INCREMENT THE NUMBER OF PAGES ALLOCATED
				; IN CORE TO THE HIGH SEGMENT IF THIS IS A HIGH
				; SEGMENT PAGE
CHGPG9:	PUSHJ	P,ICUPR		;UPDATE THE HIGHEST CONTIGUOUS PAGE IN THE LOW SEG
	SOJLE	P2,[HLL	 P4,P1	;HIGHEST PAGE SEEN
		    JRST FIXADR] ;.DONE
	PUSHJ	P,INTLVL##	;AT CLOCK LEVEL?
	TRNE	P2,777		;NO, STOP EVERY APPROX 1000 PAGES
	CAIA
	PUSHJ	P,SCDCHK##	;TO CHECK FOR OTHER THINGS
	TLNN	M,ARGMD
	SKIPA	T1,P1		;LAST PAGE
	JRST	CHGPG6		;ONLY ABZS
	SSX	T1,MS.MEM	;SET TO GET NEXT PAGE
	HRR	P1,PAGTAB(T1)	;P1 = PHYSICAL PAGE NUMBER OF NEXT PAGE ALLOCATED
	JRST	CHGPG6		;LOOP OVER ALL
;HERE WHEN NOT ENOUGH PAGES AVAILABLE IN CORE TO SATISFY A CREATE PAGES
; REQUEST
CHGP10:	TLNE	M,ARGMD		;JUST CREATING ABZ PAGES?
	JRST	CHGPG5		;YES, MUST BE HERE BECAUSE NEEDED MAPS (IGNORE)
	SETZ	P4,		;FLAG WE'RE REALLY CREATING
CHGP11:	SKIPE	T4,P3		;# OF SECTION MAPS NEED TO CREATE
	PUSHJ	P,GSMPG3	;GET SECTION MAP PAGES (ALREADY KNOW ABOUT .WSBNZ)
	MOVNS	P3		;# OF MAP PAGES
	ADD	P2,P3		;DON'T INCLUDE AS INCREASE
	ADD	P3,T3		;SAVE THE NUMBER OF PAGES TO BE CREATED
	PUSHJ	P,INTLVL##	;NO WAITING AT CLOCK LEVEL
	PUSHJ	P,IOWATM	;WAIT FOR I/O TO STOP BEFORE CALLING XPAND
CHGP12:	PUSHJ	P,INTLVL##	;INTERRUPT LEVEL?
	TRNE	P3,777		;NO, STOP APPROX EVERY 1000 PAGES
	  CAIA
	PUSHJ	P,SCDCHK##
	PUSHJ	P,NXTPAG	;GET THE NEXT ARGUMENT
	JUMPL	T1,CHGP12	;JUMP IF NOT CREATE PAGE ARGUMENT
	LSHC	T1,P2SLSH##	;GET SECTION #
	PUSHJ	P,CRSMAP	;CREATE SECTION MAP
	MOVE	T3,T1		;SAVE SECTION #
	LSHC	T1,S2PLSH##
	HRL	P2,T1		;SAVE THE HIGHEST VIRTUAL PAGE SEEN
	PUSHJ	P,GTPME		;GET ENTRY
	TLNE	T2,(PM.COR)	;IS THIS PAGE IN CORE?
	JUMPN	P4,CHGP12	;YES, MUST HAVE BEEN ON A QUEUE
	TLZ	T2,(PM.NAD)	;SEE IF...
	TDNE	T2,[PM.ADR^!PM.ZER] ;PAGE ALREADY EXIST (IDC)?
	JUMPE	P4,CHGP12	;YES, UNLESS HERE FROM PAGE IN/OUT
CHGP13:	EXCH	T1,T3		;IN CASE CALLING INCNZC
	CAME	T2,[PM.ZER]	;AN ABZ...
	PUSHJ	P,INCNZC	;INCREMENT NZS COUNT
	MOVE	T1,T3
	PUSHJ	P,INCHJ		;INCREMENT NUMBER OF HIGH SEGMENT PAGES
				; IN CORE IF THIS IS A HIGH SEGMENT PAGE
				; EVEN THOUGH ITS NOT IN CORE YET SINCE
				; IT WILL BE WHEN THE JOB SWAP IN
	PUSHJ	P,TPNHS		;SHARABLE HS PAGE?
	  SKIPG	JBTSGN##(J)	;?
	TDZA	T2,T2
	MOVEI	T2,INSDWL-INSDWE
	PUSHJ	P,INSDWE(T2)
	PUSHJ	P,GTPME		;CONTENTS OF THE MAP SLOT
	TDNN	T2,[PM.ADR]		;PAGE # OR DISK ADDRESS?
	PUSHJ	P,ICUPR		;UPDATE UPREL IF A CONTIGUOUS PAGE
	SOJG	P3,CHGP12	;LOOP OVER ALL ARGUMENTS
	JRST	FIXDSK		;FIX REVELANT VARIABLES
;SUBROUTINE FOR ABOVE TO CREATE AND/OR MAP TO PROPER SECTION WHEN CREATING PAGESS
;ENTER WITH T1=USER SECTION TO CREATE, P1=PHYSICAL PAGE ALLOCATED FOR IT
;(CHAINED FROM PAGTAB)
;IF P1=0, THEN THE MAP WILL BE CREATED AND THE JOB WILL SWAP OUT
;(ASSUMING NOT LOCKED) AND RETURN WHEN THE MAP IS IN CORE.  IF P1 IS
;NEGATIVE, THEN THE MAP WILL BE CREATED ON DISK, BUT THE THE JOB WILL
;NOT SWAP OUT.  IN THE LATTER CASE IT IS THE CALLER'S RESPONSIBILITY TO SET
;UP.BIG WHEN .WSBNZ EXISTS IN CORE

CRSMAP:	SE1ENT
	PUSH	P,T1		;SAVE T1
	ANDI	T1,MXSECN	;ENFORCE LEGALITY
	PUSH	P,T2		;SAVE T2
	PUSH	P,T4		;SAVE T4
	SKIPE	.UPMP+SECTAB(T1);SECTION EXIST?
	JRST	CRSMP4		;YES, JUST SET UP AND RETURN
	JUMPLE	P1,CRSMP7	;NO CORE
CRSMP1:	PUSH	P,P1
	SSX	P1,MS.MEM
	MOVSI	T2,(UP.BIG)	;BIG USER BIT
	TDNE	T2,.USBTS	;ALREADY BIG?
	JRST	CRSMP2		;YES, DON'T WORRY ABOUT IT
	IORM	T2,.USBTS	;SET BIT
	MOVEI	T2,(P1)		;GET PHYSICAL PAGE
	HRLI	T2,(<PM.DCD>B2+PM.WRT+PM.PUB) ;BITS
	MOVEM	T2,.UPMP+.UMWSB ;CREATE NZS WSBTAB
	PUSHJ	P,CLPTZO
	EXP	.WSBNZ
	PUSHJ	P,ZPAGE
	PUSHJ	P,[PUSH  P,T1	;SAVE T1 AGAIN
		   MOVEI T1,.UPMVP/PAGSIZ##-2 ;.WSBNZ VPN
 		   JRST  TSWST1];GET BIT MASK FOR IT
	IORM	T2,(T4)		;PUT IT ON IN WSBTAB TOO
	MOVSI	T4,1		;AND ADD TO # OF FSPACE PAGES
	ADDM	T4,JBTPDB##(J)	;..
	HRR	P1,PAGTAB(P1)	;NEXT FREE PAGE
	HRRM	P1,(P)		;SAVE UPDATED P1
CRSMP2:	MOVEI	T2,(P1)		;PAGE #
	JUMPLE	T2,[POP  P,P1	;RESTORE UPDATE P1
		    JRST CRSMP7]
	HRLI	T2,(<PM.DCD>B2+PM.CSH+PM.PUB+PM.WRT+PM.COR)
	MOVEM	T2,.UPMP+SECTAB(T1)
	HRR	P1,PAGTAB(P1)	;NEXT PAGE
	PUSHJ	P,ZPAGE
	PUSHJ	P,[PUSH  P,T1	;SAVE T1
		   MOVEI T1,.UPMVP/PAGSIZ##(T1)
		   JRST  TSWST1];GET BIT MASK
				;IGNORE .USSPT)
	IORM	T2,(T4)		;TURN IT ON
CRSMP3:	HRRM	P1,(P)		;NOW SAVE CURRENT RH(P1)
	LDB	P1,NZSSCN##	;# OF MAPS
	AOS	P1		;ONE MORE
	DPB	P1,NZSSCN##
	POP	P,P1
CRSMP4:
CRSMP5:	SOJL	T1,CRSMP6	;IN CASE S0
	IDIVI	T1,^D36/UP.SCS	;GET COUNTER
	LDB	T4,PNTNZS(T2)	;GET IT
	JUMPN	T4,CRSMP6	;DONE
	MOVEI	T4,UP.VRG
	DPB	T4,PNTNZS(T2)
CRSMP6:	POP	P,T4
	JRST	TTPOPJ##	;RETURN

;HERE IF DON'T HAVE ANY MORE CORE FOR MAPS

CRSMP7:	MOVSI	T2,NSWP!NSHF	;LOCKED?
	TDNE	T2,JBTSTS##(J)	;?
	JRST	CRSM11		;YES, WAIT FOR CORE TO APPEAR, I GUESS
	PUSH	P,T1		;SAVE T1
	MOVEI	T1,.UPMVP/PAGSIZ##(T1)
	PUSHJ	P,INSDMC	;INSERT THE PAGE
	LDB	T2,NZSICN##	;NUMBER OF MAPS ALREADY WAITING FORE
	SKIPN	T2		;THERE ARE SOME
	LDB	T2,NZSSCN##	;IF NOT, NUMBER WE ALREADY HAVE
	AOS	T2		;INCREASE
	DPB	T2,NZSICN##	;# NEED FOR SWAPIN
CRSMP8:	SKIPGE	.USBTS		;ALREADY A BIG USER?
	JRST	CRSM10		;YES, DON'T WORRY ABOUT .WSBNZ
CRSMP9:	MOVEI	T1,.UPMVP/PAGSIZ##-1-1 ;VPN OF .WSBNZ
	PUSHJ	P,INSDMU	;PUT THE PAGE IN
	LDB	T2,IFYPGS##	;# OF FUNNY PAGES NEED
	SKIPN	T2
	LDB	T2,NFYPGS##	;FIRST TIME
	AOS	T2
	DPB	T2,IFYPGS##	;NUMBER FOR SWAPIN
CRSM10:	JUMPL	P1,[POP  P,T1	;RESTORE T1
		    JRST CRSMP5];RESTORE ACS AND RETURN
	PUSH	P,S		;SAVE S AND F
	PUSH	P,F
	PUSHJ	P,IOWAT		;..
	POP	P,F		;RESTORE
	POP	P,S
	PUSHJ	P,XPANDH##	;MARK JOB AS EXPANDING
IFN FTMP,<
	PUSHJ	P,DIFMM##	;SAVE STATE OF MM
>
	PUSHJ	P,WSCHED##	;WAIT 'TIL WE COME BACK
IFN FTMP,<
	PUSHJ	P,UIFMM##	;GET THE MM BACK
>
	POP	P,T1		;RESTORE T1
	MOVSI	T4,(UP.BIG)	;SET BIT
	IORM	T4,.USBTS
	JRST	CRSMP4		;RESTORE ACS, SET MAP, SET BITS

CRSM11:	PUSH	P,T3
	MOVEI	T1,.UPMVP/PAGSIZ##-1-1
	PUSHJ	P,TSWST		;.WSBNZ EXIST?
	  SKIPA	T3,[1]		;NEED A PAGE FOR IT
	SETZ	T3,
	AOS	T3
CRSM12:	PUSHJ	P,FRDCRW##	;AVAILABLE NOW?
	  JRST	CRSM13		;NO

	MOVEI	T2,(T3)
	LDB	T1,JBYLSA##	;FIRST PAGE OF JOB
	PUSHJ	P,ADPAGS##
	MOVEI	P1,(T1)
	POP	P,T3
	MOVE	T1,-1(P)
	JRST	CRSMP1

CRSM13:
IFN FTMP,<
	PUSHJ	P,DIFMM##
>
	MOVEI	T1,1
	PUSHJ	P,SLEEPF##
IFN FTMP,<
	PUSHJ	P,UIFMM##
>
	JRST	CRSM12

;HERE IF CREATED MAP BUT NOT .WSBNZ

CRSM14:	HLL	P1,(P)		;RESTORE LEFT HALF OF P1
	POP	P,(P)		;LEAVE T4 ON STACK
	JRST	CRSMP9
;HERE TO GET PAGES FOR A SECTION MAP.  RETURN WITH FIRST
;PAGE ALLOCATED IN P1, CALL WITH # OF PAGES TO GET IN T4.  OVERWRITES
;ONLY P1.  IF PAGES NOT AVAILABLE, RETURNS WITH P1=0


GSMPGS:	JUMPE	T4,CPOPJ##	;JUST IN CASE
	PUSHJ	P,SAVT##	;SAVE EVERYTHING
	SKIPL	.USBTS		;ALREADY A BIG USER?
	AOS	T4		;NO, ADD ONE FOR .WSBNZ
GSMPG1:	MOVEI	T3,(T4)		;# TO CREATE
	PUSHJ	P,FRDCRW##	;AVAILABLE?
	  JRST	[SKIPE T4,BIGHOL## ;GET AS MUCH AS WE CAN
		 JRST	GSMPG2
		 SETZ	P1,	;NONE AVAILABLE
		 POPJ	P,   ]	;SO GIVE UP NOW
GSMPG2:	MOVEI	T2,(T4)
	LDB	T1,JBYLSA##
	PUSHJ	P,ADPAGS##	;ADD IT IN
	MOVEI	P1,(T1)		;FIRST PHYSICAL PAGE ALLOCATED IN P1
	POPJ	P,

;HERE IF ALREADY INCREMENTED FOR .WSBNZ

GSMPG3:	PUSHJ	P,SAVT##
	JRST	GSMPG1

;HERE TO EXCHANGE OR REMAP PAGES, ENTER T1 = N,,ARGUMENT LIST POINTER
; WHERE EACH WORD IN THE ARGUMENT LIST IS OF THE FORM
;	XWD	FLAG+SOURCE PAGE,DESTINATION PAGE
; WHERE FLAG = 1B0 IF THE PAGES ARE TO BE EXCHANGED, AND FLAG = 0B0
; IF THE SOURCE PAGE IS TO BE REMAPPED TO THE DESTINATION PAGE.
; IF FLAG = 1, BOTH SOURCE AND DESTINATION PAGES MUST EXIST.
; IF FLAG = 0, DESTINATION PAGE MUST NOT EXIST

MOVPGS:	SE1ENT
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSH	P,T1		;SAVE LEN,,ADDR OF ARG LIST
	HLRZ	P1,T1		;NUMBER OF ARGUMENTS
	MOVEI	P3,-1(T1)	;ADDRESS OF FIRST WORD OF ARGUMENT LIST
	MOVEI	P4,-1(T1)	;ADDRESS OF LAST WORD
	ADD	P4,P1		;  OF THE ARGUMENT LIST
	LSH	P3,W2PLSH##	;CONVERT TO PAGE NUMBER
	LSH	P4,W2PLSH##
	PUSHJ	P,FSTPAG	;POINT M AT THE USER'S ARGUMENT LIST
	PUSHJ	P,IOWATM	;WAIT UNTIL ALL I/O STOPS
MOVPG1:	TRNN	P1,777		;(THIS FUNCTION NOT EXECUTED @INTERRUPT LEVEL)
	PUSHJ	P,SCDCHK##	;STOP EVERY APPROX 1000 PGS
	PUSHJ	P,NXTSPG	;GET THE NEXT ARGUMENT
	PUSH	P,T1		;SAVE IT AT 0(P)
	HRRZ	T3,T1		;SAVE DESTINATION PAGE
	TLZE	T1,400000	;MOVE OR EXCHANGE PAGE?
	TLO	T3,400000	;EXCHANGE, REMEMBER THAT
	HLRZS	T1		;GET THE SOURCE PAGE
	PUSHJ	P,LGLPG		;IS IT A LEGAL PAGE?
	  JRST	MOVPG9		;NO, ILLEGAL PAGE ERROR
	PUSHJ	P,TPMOV		;IN A SHARABLE HIGH SEGMENT, OR MOVPGS IN ANY HI SEG?
	  JRST	MOVPG9		;YES, GO PROCESS ERROR
	LSHC	T1,P2SLSH##
	SKIPN	.UPMP+SECTAB(T1);SECTION EXIST?
	JRST	MOVPG2		;NO, ERROR
	LSHC	T1,S2PLSH##
	PUSHJ	P,GTPME		;GET POINTER
	JUMPN	T2,MOVPG3	;PAGE MUST EXIST
MOVPG2:	PUSHJ	P,PMEERR	;IT DOESN'T, ERROR
	JRST	MOVPG9
;HERE WHEN IT HAS BEEN VERIFIED THAT THE SOURCE PAGE EXISTS
MOVPG3:	HRRZ	T1,T3		;DESTINATION PAGE
	PUSHJ	P,LGLPG		;IS IT A LEGAL PAGE?
	  JRST	MOVPG9		;NO, ERROR
	PUSHJ	P,TPMOV		;IS IT IN A SHARABLE HIGH SEGMENT?
	  JRST	MOVPG9		;YES, ERROR
	LSHC	T1,P2SLSH##	;GET SECTION
	SKIPN	T4,.UPMP+SECTAB(T1);DOES SECTION EXIST?
	JUMPL	T3,MOVPG5	;EXCHANGE, PAGE MUST EXIST AND CAN'T
	PUSH	P,P1		;IN CASE WE NEED IT
	JUMPN	T4,MOVPG4	;ALREADY HAVE A MAP
	SOSGE	VIRTAL##	;CAN WE GET A MAP PAGE?
	JRST	[AOS	VIRTAL##;RESTORE VIRTAL
		 PUSHJ	P,TBGERR	;SET ERROR
		 POP	P,P1	;RESTORE P1
		 JRST	MOVPG9 ];AND FIX THINGS UP
	MOVEI	T4,1		;ONE MAP PAGE
	PUSHJ	P,GSMPGS	;GET PAGE FOR SECTION MAP
MOVPG4:	PUSHJ	P,CRSMAP	;CREATE SECTION MAP
	LSHC	T1,S2PLSH##
	POP	P,P1		;RESTORE P1
	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE MAP SLOT FOR THE
				; DESTINATION PAGE
	JUMPL	T3,MOVPG6	;VERIFY DEST PAGE DIFFERENTLY IF EXCH
	JUMPE	T2,MOVPG7	;MOVE, PAGE MUST NOT EXIST
MOVPG5:	PUSHJ	P,PCEERR	;IT DOES, ERROR
	JRST	MOVPG9
;HERE ON AN EXCHANGE
MOVPG6:	JUMPN	T2,MOVPG7	;DEST PAGE MUST EXIST
	PUSHJ	P,PMEERR	;IT DOESN'T, ERROR
	JRST	MOVPG9
;HERE WHEN IT HAS BEEN VERIFIED THAT THE DESTINATION PAGE DOES NOT
; EXIST IF THIS IS A REMAP OR DOES EXIST IF THIS IS AN EXCHANGE

MOVPG7:	MOVE	T1,(P)		;RESTORE USER'S ARG FOR MV1PG
	PUSHJ	P,MV1PG		;MOVE OR EXCHANGE THE PAGES
	XOR	T3,T2		;BOTH PAGES IN CORE OR ON DISK?
	MOVSI	T2,UU.WCC	;
	SKIPE	T3
	IORM	T2,-10(P)	;NO, SET WORKING SET HAS CHANGED BIT
	SKIPGE	(P)		;IF WE JUST DID AN EXCHANGE,
	JRST	MOVPG8		;  THEN NOTHING CHANGED
	HLRZ	T1,(P)		;LIKE DELETING FROM PAGE
	PUSHJ	P,DCUPR		;FIX NUMBERS (MEM,REL)
	HRRZ	T1,(P)		;LIKE CREATING TO PAGE
	PUSHJ	P,ICUPR		;ADJUST NUMBERS
MOVPG8:	POP	P,(P)		;DISCARD LAST ARGUMENT
	SOJG	P1,MOVPG1	;LOOP OVER THE ENTIRE ARGUMENT LIST
	POP	P,(P)		;DISCARD LEN,,ADDR OF ARG LIST
	PJRST	FIXAD1		;UPDATE SOFTWARE RELOCATION INFORMATION, CLEAR A.M.


;HERE IF WE FOUND AN ILLEGAL ARGUMENT HALFWAY THROUGH THE ARGUMENT
;LIST.  SCAN THE LIST BACKWARDS, UNDOING EVERYTHING DONE SO FAR.

MOVPG9:	POP	P,(P)		;DISCARD ARG BEING PROCESSED
	EXCH	T1,(P)		;SAVE ERROR CODE, RETRIEVE LEN,,ADDR
	HLRZS	T1		;WE WANT NUMBER OF ARGUMENTS
	SUBM	T1,P1		;PUT NUMBER OF ARGUMENTS TO UN-DO IN P1
	JUMPE	P1,TPOPJ##	;GET OUT IF FIRST ARGUMENT WAS BAD
MOVP10:	TRNN	P1,777		;WAIT APPROX EVERY 1000 PGS
	PUSHJ	P,SCDCHK##
	PUSHJ	P,PREPAG	;BACK UP TO PREVIOUS ARGUMENT
	MOVSS	T1		;MAKE IT AN ARG FOR UNDOING ITSELF
	TRZE	T1,400000	;WAS IT AN EXCHANGE?
	TLO	T1,400000	;YES, REMEMBER THAT
	PUSH	P,T1		;SAVE USER'S MODIFIED ARGUMENT
	PUSHJ	P,MV1PG		;UNDO THIS ARGUMENT
	SKIPGE	(P)		;IF THIS WAS AN EXCHANGE,
	JRST	MOVP11		;  THEN NOTHING CHANGED
	HLRZ	T1,(P)		;IT WAS A MOVE, RETRIEVE SOURCE PAGE
	PUSHJ	P,DCUPR		;FIX REL, MEM
	HRRZ	T1,(P)		;NOW DEST PAGE
	PUSHJ	P,ICUPR		;FIX UP NUMBERS
MOVP11:	POP	P,(P)		;DISCARD USER'S ARG
	SOJG	P1,MOVP10	;LOOP OVER ALL ARGS
	CLRPGT	(0)		;CLEAR AM IN CASE WE GOT INTERRUPTED
	JRST	TPOPJ##		;RESTORE ERROR CODE
GBPTR:	IDIVI	T1,^D36		;WORD NUMBER
	MOVNI	T2,-^D35(T2)	;BIT POSITION
	HRLI	T1,000100	;MAKE A 1 BIT BYTE POINTER
	DPB	T2,[POINT 6,T1,5]
	POPJ	P,		;RETURN

XCBITS:	LDB	T2,T1		;SOURCE BYTE (BIT)
	LDB	T3,T4		;DESTINATION BYTE (BIT)
	DPB	T2,T4		;SOURCE = DESTINATION
	DPB	T3,T1		;DESTINATION = SOURCE
	POPJ	P,		;RETURN

;SUBROUTINE TO MAKE MEMTAB RIGHT ON MOVE OR EXCHANGE OF PAGES ON THE "IN" QUEUE
; CALL WITH T2 = MAP CONTENTS, T3 = VIRTUAL PAGE NUMBER
MVPMT:	TLNN	T2,(PM.OIQ)	;PAGE ON "IN" QUEUE?
	POPJ	P,		;NO, NOTHING TO FIX
	SE1ENT			;SO CAN ADDRESS MEMTAB
	SSX	T2,MS.MEM	;MEMTAB SECTION
	DPB	T3,NVPNT2	;STORE NEW VIRTAL PAGE NUMBER (JOB NUMBER IS OK)
	POPJ	P,		;AND RETURN

;SUBROUTINE TO TEST FOR PAGE-LEGALITY IN EXCHANGE, MOVE PAGES
TPMOV:	CAMLE	P3,P4		;ARG LIST CROSS 777777?
	JRST	TPMOV1		;YES, CHECK PAGE # DIFFERENTLY
	CAML	T1,P3		;NO, IS THE USER TRYING TO MOVE THE ARG LIST?
	CAMLE	T1,P4		;  OR EXCHANGE IT (JUST AS BAD)?
	JRST	TPMOV2		;NO, GO TEST OTHER THINGS
	JRST	IALERR		;YES, CAN'T LET HIM
;HERE WHEN ARG LIST CROSSES 777777
TPMOV1:	CAMGE	T1,P3		;HIS PAGE NUMBER BETWEEN ARG LIST AND 777777?
	CAMG	T1,P4		;  OR BETWEEN 0 AND END OF ARG LIST?
	JRST	IALERR		;YES, CAN'T ALLOW IT
TPMOV2:
	MOVE	T2,T1		;GET PAGE #
	LSH	T2,P2SLSH##	;CONVERT TO SECTION #
	SKIPN	.UPMP+SECTAB(T2) ;SECTION EXIST?
	JRST	CPOPJ1##	;NO, THEN NOT SPY OR SHARABLE PAGE
IFN FTPEEKSPY,<
	PUSHJ	P,TSSPT		;A SPY PAGE?
	  CAIA
	JRST	PSHERR
>
	PUSHJ	P,TPAHS		;IN A HI SEG?
	  SKIPA	T2,JBTSGN##(J)	;YES
	PJRST	CPOPJ1##	;NO, OK
	TLNE	T2,SHRSEG!SPYSEG ;SHARABLE HI SEG OR SPY?
	PJRST	PSHERR		;YES
	JUMPG	T3,IALERR	;NO, CANT MOVPAG FROM ANY HI SEG
	PJRST	CPOPJ1##	;ALL OK
;SUBROUTINE TO MOVE OR EXCHANGE 1 PAGE IN MAP, ENTER T1=FROM-PAGE,,TO-PAGE
; BIT 0=1 IF EXCHANGE THE PAGES, EXIT T1=POINTER TO TO-PAGE MAP SLOT,
; T3= FROM-PAGE WSBTAB BIT, T4=POINTER TO WSBTAB FOR TO-PAGE. ALL NECESSARY
;SECTION MAPS MUST EXIST ALREADY AND DESTINATION SECTION MAPPED THROUGH .USSPT

MV1PG::	MOVE	T3,T1		;SAVE ARGUMENT
	HLRZS	T1		;GET SOURCE PAGE
	LSHC	T1,P2SLSH##	;GET SECTION #
	TRZN	T1,400000_P2SLSH##	;NO CHANGE IF EXCHANGE
	PUSHJ	P,DECNZC	;DECREMENT COUNT
	LSHC	T1,S2PLSH##	;CONVERT BACK TO PAGE #
	PUSHJ	P,GTPME
	HRRZ	T1,T3		;DESTINATION PAGE
	PUSH	P,T2		;SAVE CONTENTS OF SOURCE MAP SLOT
	PUSH	P,T4		;AND BYTE POINTER TO SOURCE MAP SLOT
	LSHC	T1,P2SLSH##	;SECTION
	SKIPL	T3		;NO CHANGE IF EXCHANGE
	PUSHJ	P,INCNZC	;ELSE INCREMENT COUNT
				;(NOTE IT'S ALREADY MAPPED ON ENTRY)
	LSHC	T1,S2PLSH##	;CONVERT BACK
	PUSHJ	P,GTPME		;GET MAP POINTER
	TLZN	T3,400000	;MOVE OR EXCHANGE?
	MOVEI	T2,0		;MOVE, SET TO STORE 0 IN SOURCE SLOT
	EXCH	T4,(P)		;GET POINTER TO SOURCE, SAVE PTR TO DESTINATION
	MOVEM	T2,(T4)		;STORE
				; SOURCE SLOT
	MOVSS	T3		;SOURCE VIRTUAL PAGE NUMBER TO RIGHT HALF
	PUSHJ	P,MVPMT		;FIX MEMTAB IF OIQ
	MOVSS	T3		;RESTORE T3
	MOVE	T4,(P)		;GET DESTIATION POINTER BACK
	MOVE	T2,-1(P)	;RESTORE CONTENTS OF SOURCE SLOT
	POP	P,-1(P)		;MOVE DESTINATION PTR BACK BY ONE
	MOVEM	T2,(T4)		;STORE IN DESTINATION SLOT
	PUSHJ	P,MVPMT		;FIXUP MEMTAB IF NECESSARY
	ANDI	T1,HLGPNO	;KEEP ONLY PAGE #
	PUSHJ	P,GBPTR		;GET A BYTE POINTER TO BIT TABLES
	HRRZ	T4,T3		;FROM PAGE NUMBER
	LSH	T4,P2SLSH##	;JUST FOR SECTION
	PUSHJ	P,RSECT4
	  JFCL
	IMULI	T4,WSBTBL	;OFFSET
	SKIPN	T4		;NZS?
	SKIPA	T4,[WSBTAB]	;NO
	ADDI	T4,.WSBNZ-WSBTBL
	ADD	T4,T1		;MAKE BYTE POINTER
	HLRZ	T1,T3		;SETUP TO GET BYTE POINTER FOR DESTINATION BIT
	ANDI	T1,HLGPNO	;KEEP ONLY PAGE #
	PUSHJ	P,GBPTR		;GET THAT
	HLRZS	T3		;GET ARG AGAIN
	LSH	T3,P2SLSH##	;JUST FOR SECTION
	EXCH	T4,T3
	PUSHJ	P,RSECT4	;GET REAL SECTION # FOR SOURCE
	  JFCL
	EXCH	T4,T3
	IMULI	T3,WSBTBL	;OFFSET
	SKIPN	T3		;NZS?
	SKIPA	T3,[WSBTAB]	;NO
	ADDI	T3,.WSBNZ-WSBTBL
	ADD	T1,T3		;RELOCATE BYTE POINTER
	PUSHJ	P,XCBITS	; THE WORKING SET TABLE
	PJRST	TPOPJ##		;RESTORE BYTE POINTER TO DESTINATION SLOT AND RETURN
;HERE TO SET/CLEAR THE ACCESS ALLOWED BITS IN THE MAP AND AABTAB

SETAAB:	MOVEI	T2,PA.IHB+PA.PME+PA.PMI
	PUSHJ	P,PLTSN		;CHECK THE ARGUMENT LIST (PAGES MUST EXIST
				; AND BE IN CORE)
	  POPJ	P,		;ARGUMENT ERROR
	PUSHJ	P,SAVE1##	;SAVE P1,P2
	SE1ENT
	HLRZ	P1,T1		;NUMBER OF ARGUMENTS
	PUSHJ	P,FSTPAG	;POINT M AT USER'S ARGUMENT LIST
	MOVSI	T1,(UP.SAA)	;SET A.A. AUTOMATICALLY BIT
	TLNN	M,ARGMD		;DID THE USER SPECIFY IT?
	JRST	[ANDCAM T1,.USBTS
		JRST SETAA1]	;NO, CLEAR THE BIT
	IORM	T1,.USBTS	;YES, REMEMBER IT
SETAA1:	PUSHJ	P,NXTPAG	;GET THE NEXT ARGUMENT
	HRRZ	T2,T1		;ONLY PAGE #
	LSH	T2,P2SLSH##	;CONVERT TO SECTION #
	SKIPE	.UPMP+SECTAB(T2) ;SECTION EXIST?
	PUSHJ	P,SCAABT	;SET OR CLEAR THE BIT
SETAA2:	SOJG	P1,SETAA1	;LOOP OVER ALL THE ARGUMENTS
	PUSHJ	P,ADJANA
FIXMJ1::CLRPGT	(0)		;CLEAR PAGE MEMORY
	JRST	CPOPJ1##	;SKIP RETURN
;SUBROUTINE TO SET OR CLEAR ACCESS ALLOWED BITS IN AABTAB AND THE MAP
; CALL WITH T1 = THE VIRTUAL PAGE NUMBER, SIGN BIT ON IF A.A. TO BE CLEARED
; EXITS CPOPJ ALWAYS

SCAABT:	SE1ENT			;MUST BE IN S1
	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE MAP SLOT FOR THIS PAGE
	JUMPE	T2,CPOPJ##	;DON'T DO ANYTHING IF PAGE DOESN'T EXIST
	TLNN	T1,400000	;SET OR CLEAR ACCESS ALLOWED?
	JRST	SCAAB1
	TLZE	T2,(<PM.DCD>B2)

	AOS	.USANA		;YES, BUMP NO. OF NOT-ACCESSABLE PAGES
	TLZ	T2,(PM.AAB)
	JRST	SCAAB2
SCAAB1:
	TLON	T2,(<PM.DCD>B2)

	SOS	.USANA		;YES, DECR NO OF NOT-ACCESSABLE PAGES
	TLO	T2,(PM.AAB)
SCAAB2:	MOVEM	T2,(T4)		;STORE ENTRY BACK IN THE MAP WITH THE
				; ACCESS ALLOWED BIT SET OR CLEARED
	POPJ	P,		;RETURN

;SUBROUTINE TO MAKE UPVRT AGREE WITH UPANA

ADJANA::MOVE	T3,.USANA
	IORM	T3,.USVRT	;ENSURE UPVRT NON-0 IF NON-ACCESS PAGES EXIST
	JUMPN	T3,CPOPJ##	;IF NO NON-ACCESS PAGES,
	MOVEI	T3,777		; CLEAR THAT PORTION OF UPVRT
	ANDCAM	T3,.USVRT
	POPJ	P,		;RETURN
;HERE TO RETURN THE WORKING SET BIT TABLE TO THE USER
GETWSB:	MOVEI	T2,WSBTAB	;SOURCE ADDRESS
IFN FTXMON,<
	XSFM	T3		;DESTINATION
	HRLI	T3,(T1)		;LOW ORDER PART
	MOVSS	T3		;SET HALVES CORRECTLY
> ;IFN FTXMON
IFE FTXMON,<MOVEI T3,(T1)>	;DESTINATION ADDRESS
	HLRZS	T1		;NUMBER OF WORDS TO RETURN
	PUSH	P,T1		;SAVE # OF WORDS REQUESTED
	CAILE	T1,WSBTBL	;ASKING FOR MORE THAN THERE ARE?
	MOVEI	T1,WSBTBL	;YES, RETURN NUMBER THERE ACTUALLY ARE
IFN FTXMON,<XBLTXU T1>		;MOVE TABLE TO THE USER
IFE FTXMON,<
	MOVSS	T2		;SOURCE IN LH
	HRRI	T2,(T3)		;DEST. IN RH
	ADD	T3,T1		;ONE BEYOND END
	EXCTXU	<BLT T2,-1(T3)>	;MOVE TABLE TO THE USER
> ;END IFE FTXMON
	ERJMP	UADERR##	;MUSTA BEEN TO A HISEG
	HRLOI	T4,1777		;SET TO CLEAR BIT REPRESENTING THE UPMP
	JUMPGE	U,TPOPJ1##	;WAS THE ENTIRE TABLE REQUESTED?
	EXCTXU	<ANDCAM T4,-1(T3)>	;YES, CLEAR JUNK FROM THE LAST WORD
	POP	P,T1		;RESTORE # OF WORDS REQUESTED
	SUBI	T1,WSBTBL	;# WORDS LEFT
	JUMPLE	T1,CPOPJ1##	;NO, DONE
	SKIPL	.USBTS		;IS USER EXTENDED?
	JRST	GETWSZ		;NO, JUST ZERO REST OF BLOCK
IFN FTXMON,<
	PUSH	P,T1		;SAVE # OF WORDS LEFT
	MOVEI	T2,.WSBNZ	;GET ADDR OF EXTENDED TABLE
	CAILE	T1,PAGSIZ##	;WANT MORE THAN A PAGE WORTH?
	MOVEI	T1,PAGSIZ##	;CAN'T GET ANY MORE
	EXCTXU	<EXTEND T1,[XBLT]>
	ERJMP	UADERR##	;NOT THERE
	POP	P,T1
	SUBI	T1,PAGSIZ##
	JUMPLE	T1,CPOPJ1##	;IF NO MORE, DONE
> ;END IFN FTXMON
GETWSZ:	EXCTXU	<SETZM (T3)>	;CLEAR NEXT WORD
	SOJLE	T1,CPOPJ1##
IFN FTXMON,<
	MOVE	T2,T3		;STARTING WORD
	AOS	T3		;DESTINATION WORD
	EXCTUU	<EXTEND T1,[XBLT]> ;CLEAR REST OF USER'S BLOCK
> ;END IFN FTXMON
IFE FTXMON,<
	MOVSI	T2,(T3)		;SOURCE ADDR
	HRRI	T2,1(T3)	;DEST. ADDR
	ADD	T3,T1		;FINAL+1
	EXCTUU	<BLT T2,-1(T3)>	;CLEAR REST OF USER'S BLOCK
> ;END IFE FTXMON
	ERJMP	UADERR##	;WENT BEYOND USER'S CORE
	JRST	CPOPJ1##	;DONE
;HERE TO RETURN AABTAB.  T1 CONTAINS THE # OF WORDS TO RETURN

GETAAB:	PUSHJ	P,SAVE1##	;SAVE P1
	SE1ENT
	HRRZI	M,-1(T1)	;WHERE TO START RETURNING
	HLRZ	U,T1		;# OF WORDS TO RETURN
	JUMPE	U,CPOPJ1##	;NOTHING TO RETURN
	SETZ	P1,		;LET'S START AT THE VERY BEGINNING
	MOVSI	T3,(PM.AAB)
GETAA1:	SKIPN	.UPMP+SECTAB(P1)
	JRST	GETAA6
	MOVEI	T1,(P1)		;ARG FOR STUTMP
	MOVE	T4,[UMAPSN+UMAPS]
GETAA2:	SETZ	T1,		;DEFAULT BIT MASK
	MOVSI	T2,-^D36	;PER WORD
GETAA3:	LSH	T1,1		;SHIFT OVER
	TDNE	T3,(T4)		;AABTAB BIT ON?
	AOS	T1		;YES
	AOS	T4
	TRNE	T4,HLGPNO	;CROSS SECTION BOUNDARY?
	AOBJN	T2,GETAA3	;LOOP OVER ALL
GETAA4:	PUSHJ	P,PUTWS1##	;PUT THE WORD IN CORE
	TRNN	T4,HLGPNO	;CROSS SECTION OR WORD BOUNDARY?
	AOJA	P1,GETA4A	;SECTION (CAN NEVER BE BOTH)
	SOJG	U,GETAA2
	JRST	CPOPJ1##
GETA4A:	CAIG	P1,MXSECN	;AS LONG AS NOT TOO BIG
GETAA5:	SOJG	U,GETAA1	;CONTINUE
	JRST	CPOPJ1##

GETAA6:	MOVEI	T2,WSBTBL
	SETZ	T1,
GETAA7:	PUSHJ	P,PUTWS1##
	SOJLE	T2,GETAA1
	SOJG	U,GETAA7
	JRST	CPOPJ1##
;HERE TO MAKE A CONTIGUOUS COLLECTION OF PAGES A HIGH SEGMENT

GREMAP:	PUSHJ	P,SAVE1##	;SAVE A WORKING AC
	HLRE	P1,T1		;GET THE NUMBER OF ARGUMENTS
	JUMPLE	P1,IALERR	;.LE. 0 IS ILLEGAL
	SOJL	P1,IALERR	;THERE MUST BE AT LEAST TWO ARGUMENTS
				; (NUMBER OF PAGES AND STARTING PAGE)
	HRRI	M,(T1)		;ADDRESS OF THE ARGUMENTS
	PUSHJ	P,INTLVL##	;CAN'T WAIT IF INTERRUPT (CLOCK) LEVEL (VIRCHK)
	PUSHJ	P,IOWATM	;WAIT FOR I/O TO STOP
	PUSHJ	P,GETWSU##	;GET THE FIRST ARGUMENT (NUMBER OF PAGES TO BE REMAPPED)
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN MM?
	  PUSHJ	P,UPMM##	;MUST HAVE THE MM TO DO A REMAP
>
	JUMPE	P1,GREMA4	;DELETE HS PAGES FUNCTION
	PUSH	P,T1		;SAVE IT
	PUSHJ	P,GETWS1##	;GET THE STARTING PAGE NUMBER
	PUSHJ	P,LGLPG		;IS IT A LEGAL PAGE?
	  JRST	T2POPJ##	;NO, TELL THE USER ILLEGAL PAGE NUMBER
	MOVE	T2,T1		;STARTING PAGE NUMBER TO T2
	SOJLE	P1,GREMA1	;JUMP IF THIRD ARGUMENT WASN'T SPECIFIED
	PUSH	P,T1		;SAVE SECOND ARGUMENT (GETWSU CLOBBERS T2)
	PUSHJ	P,GETWS1##	;GET THE DESTINATION PAGE NUMBER
	PUSHJ	P,LGLPG		;IS THAT A LEGAL PAGE NUMBER?
	  JRST	[POP P,(P)	;NO
		JRST T2POPJ##]	;ILLEGAL PAGE RETURN TO THE USER
	MOVE	T2,T1		;DESTINATION PAGE TO T2
	POP	P,T1		;RESTORE SOURCE PAGE
GREMA1:	POP	P,T3		;RESTORE THE NUMBER OF PAGES TO BE REMAPPED
	MOVSI	T4,(1B0)	;DON'T ALLOW A USER TO CREATE A SHARABLE
	JUMPGE	T3,GREMA2	;APPEND STYLE REMAP?
	MOVMS	T3		;MAYBE, MAKE T3 + IN ANY CASE
	MOVEI	P1,GREMA3	;IF APPENDING, WE WILL EXIT HERE
	SKIPE	.USHSE		;DOES JOB ALREADY HAVE A HIGH SEG?
	TLOA	T4,(1B1)	;YES, INDICATE APPEND
GREMA2:	MOVEI	P1,SHARE1##	;IN WIN CASE, GO TO SHARE1 FOR NORMAL REMAP
	PUSHJ	P,NREMAP	;DO THE REMAP
	  PJRST	STOTAC##	;ERROR, STORE THE ERROR CODE FOR THE USER
	PJSP	T3,(P1)		;WIN, MAKE REMAPPED PAGES INTO A HIGH SEGMENT
GREMA3:	MOVE	J,.USJOB	;POINT TO JOB FOR MAPHGH
	AOS	(P)		;SKIP RETURN
	PJRST	MAPHGH##	;JUST APPENDING
GREMA4:	SKIPLE	J,JBTSGN##(J)	;GET SEGMENT
	TLNE	J,SHRSEG	;CAN'T DO SHARABLE
	JRST	PSHERR		;..
	MOVE	T2,JBTADR##(J)	;GET HIGH SEG JBTADR
	MOVE	J,.USJOB
	MOVE	P1,.USHSE	;END OF CURRENT HIGH SEG
	LSH	P1,W2PLSH##	;CONVERT TO HIGHEST PAGE IN SEG
	SUBI	P1,-1(T1)	;FIRST PAGE TO DELETE
	LSH	P1,P2WLSH##	;MAKE SURE
	SUB	P1,.USHSS	;HE'S NOT TRYING TO DELETE THE LOW SEG TOO?
	JUMPL	P1,IALERR	;HE IS, LOSE
	SKIPN	P1		;DELETING ENTIRE HS?
	TDZA	T2,T2		;YES, SET IT'S CLEAR
	HRLI	T2,-PAGSIZ##+PG.BDY(P1) ;YES, SET NEW RELOCATION
	ADD	P1,.USHSS
	LDB	T4,JBYSG2##	;SECTION HIGH SEG IS IN
	HRLI	P1,(T4)		;SET IT
	LSH	P1,W2PLSH##	;BACK TO FIRST PAGE TO DELETE
	MOVNS	T1		;MAKE COUNT
	HRLI	P1,(T1)		;FOR AOBJN POINTER
	LDB	T1,JBYSG2##	;SET SECTION
	SE1ENT			;ENTER SECTION 1 HERE
	PUSH	P,T2		;SAVE NEW R FOR HIGH SEG
	LSH	T1,S2PLSH##
	IORI	P1,(T1)		;SET IN AOBJN PTR TOO
GREMA5:	MOVEI	T1,(P1)		;PAGE TO DELETE
	TRNE	T1,-1^!HLGPNO	;IF IN A NON-ZERO SECTION
	AOS	.USNCR		;UNDO THE CALL TO DECNCR BY DLTPAG
	PUSHJ	P,DLTPAG	;DELETE IT
	MOVEI	T1,(P1)		;T1 ISN'T PRESERVED IN DLTPAG
	LSH	T1,P2SLSH##	;CONVERT TO SECTION
	SKIPE	T1		;DECREMENT IF NZS
	PUSHJ	P,DECNZC	;YES
	PUSHJ	P,DCVMT
GREMA6:	AOBJN	P1,GREMA5
	MOVSI	T1,(UP.WHC)	;WORKING SET HAS CHANGED
	IORM	T1,.USBTS
	CLRPGT	(0)
	AOS	-1(P)		;GOOD RETURN
	HRRZ	J,JBTSGN##(J)
	EXCH	R,(P)		;GET R FOR HIGH SEG
	MOVSI	T1,(UP.CTX)	;PUSH?
	TDNN	T1,.USBTS	;?
	MOVEM	R,JBTADR##(J)
	PUSHJ	P,SETVRT	;ADJUST #S
	LDB	T1,PCORSR##
	MOVE	J,.USJOB
	SKIPE	R		;IF ZERO, STORE ZERO
	AOS	T1		;# OF PAGES, NOT HIGHEST ADDRESSABLE
	DPB	T1,JBYHSS##	;..
	HLRZ	T1,R		;SET JOBHRL TOO
	SKIPE	T1
	ADD	T1,.USHSS	;..
	HRRM	T1,.JDAT+JOBHRL##
	JRST	RPOPJ##		;RESTORE R AND RETURN
;HERE TO CREATE/DESTROY SPY PAGES

IFN FTPEEKSPY,<
SPYPGS:	SE1ENT
	PUSHJ	P,SAVE4##	;SAVE ALL
	PUSH	P,T1		;SAVE ADDRESS OF THE ARGUMENT LIST
	MOVSI	T1,PVSPYA	;REQUIRES SPY PRIVILEGES
	PUSHJ	P,PRVBIT##	;DOES THE JOB HAVE THEM?
	  SKIPA	T1,(P)		;YES, PROCEED
	JRST	[POP P,(P)	;NO, POP OFF JUNK AND
		 JRST NPVERR]	; GIVE NEED PRIVILEGES ERROR RETURN
	PUSHJ	P,FSTPAG	;POINT M AT USERS ARGUMENT LIST
	HLRE	P3,T1		;NUMBER OF ARGUMENTS
	JUMPLE	P3,[POP P,(P)	;ZERO OR NEGATIVE ARGUMENT COUNT IS ILLEGAL
		    JRST IALERR];GIVE ILLEGAL ARGUMENT LIST RETURN
	SKIPGE	-5(P)		;PHYSICAL ONLY? P1 ON STACK
	TDZA	P2,P2		;PHYS ONLY
	MOVEI	P2,1
	SETZB	P4,.USTMU	;SECTION MAPS
SPYPG1:	PUSHJ	P,NXTSPG	;GET THE NEXT ARGUMENT
	PUSHJ	P,LGLPR		;LEGAL USER VIRTUAL PAGE NUMBER?
	  JRST	TPOPJ##		;NO
	MOVE	P1,T1		;SAVE CURRENT T1
	LSH	T1,P2SLSH##	;GET SECTION #
	ANDI	T1,MXSECN	;CLEAR JUNK
	SKIPN	T2,.UPMP+SECTAB(T1);SECTION EXIST?
	JRST	[JUMPGE P1,SPYP12 ;CREATE, OK FOR NX SECTION
		 TLNE   P1,(PG.IDC) ;DON'T CARE LIT?
		 JRST   SPYP2A	;IDC IS LIT, BUT DON'T CREATE MAP
		 POP  P,(P)
		 JRST   PMEERR   ];BUT NOT FOR DELETE
SPYPG2:	MOVE	T1,P1		;RESTORE T1
	PUSHJ	P,GTPME		;GET CONTENTS OF THE MAP CORRESPONDING TO THAT PAGE
	JUMPL	T1,SPYP2A	;DELETE SPY PAGE?
	JUMPE	T2,SPYPG3	;CREATE AND PAGE DOESN'T EXIST, NO SWEAT
	TLNE	P1,(PG.IDC)	;DON'T CARE?
	PUSHJ	P,TPNHS		;YES, BUT IF IT'S IN THE HIGH SEG, CAN'T DELETE
	  CAIA			;CARES OR IT'S IN THE HS
	JRST	SPYPG3
	POP	P,(P)		;NO, MAP SLOT MUST BE ZERO
	JRST	PCEERR		;PAGE CANNOT EXIST ERROR
SPYP2A:	HLRZ	T4,P4
	CAIL	T4,(T1)
	JRST	[POP	P,T1	;FIX STACK
		 JRST	IALERR]	;ILLEGAL ORDER IF NOT INCREASING
	HRL	P4,T1		;REMEMBER HIGHEST DELETE PAGE SEEN
	TLNE	P1,(PG.IDC)	;DO WE CARE?
	JUMPE	T2,SPYPG4	;NO
	HRRZ	T1,P1
	PUSHJ	P,TSSPT
	  CAIA
	JRST	SPYPG4
	POP	P,(P)
	JRST	PMEERR
SPYPG3:	MOVE	T1,P1
	HRRZ	T4,P4		;LAST PAGE CREATED
	CAIL	T4,(T1)		;INCREASING ORDER?
	JRST	[POP	P,T1	;FIX STACK
		 JRST	IALERR]	;ILLEGAL ORDER IF NOT INCREASING
	HRR	P4,T1		;REMEMBER HIGHEST PAGE
	HLRZ	T2,T1		;MONITOR PAGE NUMBER
	LSH	T2,P2WLSH##	;MAKE WORD AFTER CLEARING BITS
	XCT	[CAML   T2,MEMSIZ##
		 PUSHJ	P,MONVPC](P2)	;MAP THE VIRTUAL ADDRESS
	  TLNE	P1,(PG.IDC)	;OR DOESN'T CARE?
	JRST	SPYPG4		;ALL IS MORE OR LESS WELL
	POP	P,(P)		;NO
	JRST	ILPERR		;ILLEGAL PAGE NUMBER ERRROR
SPYPG4:	SOJG	P3,SPYPG1	;LOOP OVER THE ENTIRE ARGUMENT LIST
	POP	P,T1		;RESTORE ARGUMENT LIST POINTER
	HLRZ	P3,T1		;COUNT OF ARGUMENTS
	SKIPE	T4,.USTMU	;# OF SECTION MAPS
	PUSHJ	P,GSMPGS	;TRY TO GET MAPS NOW
	PUSHJ	P,FSTPAG	;POINT M AT USER'S ARGUMENT LIST
SPYPG5:	PUSHJ	P,NXTSPG	;GET THE NEXT ARGUMENT
	HRRZ	T4,T1		;USER VIRTUAL PAGE NUMBER
	PUSHJ	P,GMPTR		;GET MAP POINTER
	HLRZ	T2,T1		;MONITOR PAGE NUMBER
	HRRZS	T1		;CLEAR JUNK
	ROT	T1,P2SLSH##	;CONVERT TO SECTION
	TRNE	T2,400000	;IS THIS A DELETE?
	JRST	[HRL	T2,T1	;YES, DOES SECTION EXIST (IDC)?
		 ANDI	T1,MXSECN
		 SKIPN	.UPMP+SECTAB(T1)
		 JRST	SPYPG9	;NO, DON'T CREATE A MAP TO DESTROY
		 HLRZ	T1,T2	;RESTORE T1
		 HRRZS	T2	;AND T2
		 JRST	.+1   ]	;CONTINUE
	PUSHJ	P,CRSMAP
	ROT	T1,S2PLSH##
	TRNE	T2,400000	;DELETING A SPY PAGE?
	JRST	SPYPG7		;YES
	MOVE	T3,(T4)		;GET CONTENTS OF MAP
	SKIPE	T3		;IF PAGE DOESN'T EXIST, PROCEED
	PUSHJ	P,[PUSHJ P,SAVT## ;ELSE DELETE WHAT'S
		   PJRST DLTPAG ] ;THERE ALREADY
	MOVE	T3,T2		;MONITOR PAGE NUMBER TO T3
	SKIPGE	-4(P)		;PHYSICAL ONLY? P1 ON THE STACK
	JRST	SPYPG6		;YES
	ANDI	T2,<MXSECN*<HLGPNO+1>+HLGPNO>
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,MONVPM	;MAP THE VIRTUAL PAGE
	  JFCL			;IGNORE
	MOVE	T3,T1		;PAGE MAP ENTRY
	POP	P,T1
	JRST	SPYPG8		;DEPOSIT INTO MAP
SPYPG6:	TLOA	T3,(<PM.DCD>B2+PM.PUB+PM.SPY+PM.NIA)
SPYPG7:	SETZ	T3,		;SET TO REMOVE THE SPY PAGE
SPYPG8:	MOVEM	T3,(T4)		;STORE MAPPING IN THE USER'S MAP
	LSH	T1,P2SLSH##	;SECTION #
	JUMPE	T1,SPYPG9	;A SECTION 0 PAGE
	JUMPE	T3,[PUSHJ P,DECNZC ;DELETE, DECREMENT COUNT
		    JRST  SPYPG9  ]
	PUSHJ	P,INCNZC
SPYPG9:	SOJG	P3,SPYPG5	;NEXT ARGUMENT
	MOVSI	T1,(UP.CSP)	;MAP MAY CONTAIN SPY PAGES BIT
	IORM	T1,.USBTS	;TURN IT ON TO SAVE TIME LATER
	JRST	FIXMJ1		;NEW MAPPING IN AFFECT, GOOD RETURN

SPYP12:	HRRZ	T2,P1		;PAGE BEING CREATED
	XOR	T2,P4		;GET DIFFERENCES
	TRNE	T2,MXSECN_S2PLSH## ;SEE IF WE SAW THIS NON-EXISTENT SECT BEFORE
	AOS	.USTMU		;NO, REMEMBER TO CREATE MAP
	JRST	SPYPG3
;SUBROUTINE TO DELETE A SPY PAGE, CALL WITH T1 = USER VIRTUAL PAGE
; NUMBER OF THE PAGE, RETURNS CPOPJ IF SPY PAGE DELETED, CPOPJ1 IF NOT
; A SPY PAGE
DLTSP:	PUSHJ	P,TSSPT		;A SPY PAGE?
	  JRST	CPOPJ1##	;NO, SKIP RETURN
	SETZM	(T4)		;ZERO MAP SLOT
	POPJ	P,		;AND RETURN

;SUBROUTINE TO CLEAR SPY PAGES FROM A USER'S MAP, CALLED BY GETMIN
CLRSPG::SE1ENT		;FOR MAP REFERENCES
	MOVSI	T1,(UP.CSP)	;JOB MAY HAVE SPY PAGES IN ITS MAP BIT
	SKIPE	JBTADR##(J)	;DOES IT HAVE CORE IN CORE?
	TDNN	T1,.USBTS	;YES, AND DID IT DO A FUNCTION 11 OF THE PAGE. UUO?
	JRST	CLRSP6		;NO, BE SURE BIT CLEAR AND RETURN NOW
	SETZ	T1,		;START AT SECTION 0
CLRSP1:	MOVEI	T4,HLGPNO+1	;MAX # OF PAGES IN SECTION
	MOVSI	T2,(PM.SPY)	;BIT TO CHECK
	SKIPE	T3,T1		;COPY SECTION #
	LSH	T3,S2PLSH##	;CONVERT TO PAGE #
	ADD	T3,[UMAPSN+UMAPS]
CLRSP2:	TDNE	T2,(T3)		;SPY PAGE?
	SETZM	(T3)		;CLEAR MAPPING
	AOS	T3		;ADVANCE
CLRS2A:	SOJG	T4,CLRSP2
CLRSP3:	SKIPL	.USBTS		;EXTENDED PROGRAM?
	JRST	CLRSP5		;NO, DONE
	AOS	T1		;NEXT SECTION
CLRSP4:	CAILE	T1,MXSECN	;DONE MAYBE?
	POPJ	P,		;YES
	SKIPE	T2,.UPMP+SECTAB(T1) ;SECTION EXIST?
	TLNE	T2,(<PM.DCD^!PM.ACD>B2) ;IS IT INDIRECT?
	AOJA	T1,CLRSP4	;KEEP LOOKING IF NO SECTION MAP
	JRST	CLRSP1

CLRSP5:	MOVSI	T1,(UP.CSP)	;NO LONGER HAS SPY PAGES
CLRSP6:	ANDCAM	T1,.USBTS
	POPJ	P,

;HERE TO MAP MONITOR PAGE IN T2 INTO A USER POINTER IN T1
;CPOPJ ON FAILURE, CPOPJ1 ON SUCCESS

MONVPC:	LSH	T2,W2PLSH##	;CHANGE ADDRESS TO PAGE
MONVPM:	MOVE	T1,T2		;COPY PAGE
	ANDI	T2,PG.BDY##	;KEEP PAGE WITHIN SECTION
	LSH	T1,P2SLSH##	;ISOLATE SECTION NUMBER HERE
	CAILE	T1,MXSECN	;IS IT REASONABLE?
IFE FTXMON,<
	JRST	MONVP4		;NO, CHECK FOR DECNET SECTION
>
IFN FTXMON,<
	JRST	MONVPE		;NO, GIVE ERROR RETURN
	CAILE	T1,(MCSEC1)	;IS IT WHERE MOST CODE LIVES?
	JRST	MONVP4		;NO, LOOK HARDER
>
	CAIL	T2,.CPCDB##/PAGSIZ##	;IS IT THE CDB?
	CAILE	T2,<.CPCDB##/PAGSIZ##>+1 ;EITHER PAGE?
	JRST	MONVP9		;NO, CHECK FOR FUNNY SPACE
	MOVE	T1,[<PM.ICD>B2!PM.PUB!PM.SPY!<XWD <.CPCDB##/PAGSIZ##>,<SPTLOW##-SPTTAB##>>]
	ADD	T1,.CPCPN##	;MAKE POINTER TO CURRENT .CPCDB
	MOVEM	T1,.USCDB	;STASH IT AWAY
	ADD	T1,[XWD 1,0]	;MAP SECOND PAGE
	MOVEM	T1,.USCDB+1	;STORE THAT, TOO
	MOVSI	T1,.UPCDB-<.CPCDB##/PAGSIZ##>(T2) ;GET CORRESPONDING UPT OFFSET
	JRST	MONVP0		;EXIT VIA PER-JOB MAPPING
MONVP9:	CAIL	T2,.FPPP/PAGSIZ##	;IS IT IN FUNNY SPACE?
	CAILE	T2,.LPPP/PAGSIZ##	; ...?
	JRST	MONVP1		;NO, HANDLE IN SPTLOW
	MOVSI	T1,.UMORG-<FYSORG/PAGSIZ##>(T2) ;GET SLOT OFFSET IN RIGHT PLACE
MONVP0:	HRRI	T1,M.CPU##(J)	;POINT TO JBTUPM(J) IN SPT
	JRST	MONVP3		;GO THROUGH COMMON EXIT
MONVP1:	MOVS	T1,T2		;GET PAGE OFFSET IN CORRECT PLACE
	HRRI	T1,SPTLOW##-SPTTAB## ;POINT TO CORRECT STARTING PLACE IN SPT
MONVP2:	ADD	T1,.CPCPN##	;OFFSET FOR CPU NUMBER
MONVP3:	TLO	T1,(<PM.ICD>B2+PM.PUB+PM.SPY) ;MAKE COMPLETE MAPPING POINTER
	JRST	CPOPJ1##	;RETURN SUCCESS
IFE FTXMON,<
MONVP4:	CAIE	T1,1		;IS IT THE DECNET DATA SECTION?
	JRST	MONVPE		;NO, IT'S ILLEGAL
>
IFN FTXMON,<
MONVP4:	CAIE	T1,(MS.HGH)	;IS IT THE OTHER PER-CPU SECTION?
	JRST	MONVP5		;NO, LOOK ONWARD
>
	MOVS	T1,T2		;YES, GET PAGE OFFSET IN CORRECT HALFWORD
	HRRI	T1,SPTHGH##-SPTTAB## ;POINT TO CORRECT STARTING PLACE IN SPT
	JRST	MONVP2		;EXIT VIA PER-CPU MAPPING
IFN FTXMON,<
MONVP5:	CAIE	T1,(UMAPSN)	;IS IT THE OTHER SPECIAL SECTION?
	JRST	MONVP6		;NO, HANDLE COMMON DATA SECTION
	CAIL	T2,<UMAPS/PAGSIZ##>	;IS IT IN RANGE?
	CAILE	T2,<UMAPS/PAGSIZ##>+HLGSNO ;BOTH WAYS?
	JRST	MONVPE		;NO, GIVE ERROR RETURN
	MOVSI	T1,SECTAB-<UMAPS/PAGSIZ##>(T2) ;YES, POSITION MAPPING OFFSET
	JRST	MONVP0		;EXIT VIA UPT MAPPING
MONVP6:	MOVEI	T1,SPTCOM##-SPTTAB##-<(MS.FMD)>(T1) ;POINT TO SPT SLOT
	HRLI	T1,(T2)		;YES, INCLUDE MAPPING OFFSET FOR PAGE
	JRST	MONVP3		;EXIT VIA COMMON CODE
>	;END IFN FTXMON

MONVPE:	SETZ	T1,		;CLEAR MAPPING
	POPJ	P,
>	;END IFN FTPEEKSPY
;HERE TO CREATE/DESTROY SECTION MAPS

CHGSEC:	SE1ENT
	PUSHJ	P,FSTPAG		;GET FIRST ARGUMENT
	HLRES	T1
	MOVM	P4,T1			;# OF ARGS TO P4
	MOVE	P3,P4			;SAVE ALSO IN P3
	MOVSI	T2,-<MXSECN+1>		;MAX # OF SECTIONS
	SETZ	P2,			;MAKE MASK OF SECTIONS NOW INDIRECT
	MOVSI	T4,(<PM.ACD^!PM.DCD>B2)	;SEE IF SECTION IS INDIRECT
CHGSC0:	LSH	P2,1			;NEXT SECTION
	TDNE	T4,.UPMP+SECTAB(T2)	;IS THIS SECTION INDIRECT?
	AOS	P2			;THIS SECTION IS INDIRECT
	AOBJN	T2,CHGSC0
	LSH	P2,^D35-<MXSECN>
	SETZB	P1,T4			;# OF PAGES CREATED,,DESTROYED, PAGES TO ADD
	XSFM	T2			;SECTION # OF PC SECTION
	ANDI	T2,MXSECN		;KEEPING ONLY SECTION #
	MOVEM	T2,.USTMU		;SAVE IT
	SETO	T2,			;HIGHEST SECTION SEEN THUS FAR
CHGSC1:	PUSHJ	P,NXTSPG		;GET NEXT ARG
	CAIL	T2,(T1)			;MONOTONICALLY INCREASING?
	JRST	IALERR			;NO
	MOVEI	T2,(T1)			;UPDATE
	JUMPL	T1,CHGSC3		;DESTROY MAP
	TLNN	T1,(PG.SLO)		;CREATE MAP EX NIL?
	AOJA	T4,CHGSC2		;YES, ONLY VERIFY RIGHT HALF
	TLNN	T1,<-1^!<<(PG.GAF!PG.SLO!PG.IDC)>!MXSECN>>;ANY ILLEGAL BITS?
CHGSC2:	TRNE	T1,<-1^!MXSECN>		;LEGAL SECTION #?
	JRST	ILSERR			;NO
	TLO	T1,400000		;MAKE IFIW
	AOS	P1			;ONE MORE CREATE TO PROCESS
	PUSH	P,T1			;SAVE ARG
	MOVSI	T3,(1B0)		;TURN ON THAT THIS SECTION IS INDIRECT
	MOVNI	T1,(T1)
	LSH	T3,(T1)			;FIND RIGHT BIT
	POP	P,T1			;RESTORE ARG
	SKIPN	.UPMP+SECTAB(T1)	;NO, DOES SECTION EXIST?
	JRST	[TLNE	T1,(PG.SLO)	;INDIRECT SECTION?
		 JRST	CHGS2A		;CHECK TARGET SECTION
		 JRST	CHGSC4]		;SECTION WON'T BE INDIRECT LATER
	TLNN	T1,(PG.IDC)		;IDC LIT?
	JRST	SCEERR			;NO, SECTION CAN'T EXIST
	TLNN	T1,(PG.SLO)		;WERE WE TO CREATE THIS FROM NOTHING?
	TDZA	P2,T3			;SECTION WON'T BE INDIRECT LATER
CHGS2A:	TDOA	P2,T3			;TURN IT ON FOR THIS SECTION
	SOJA	T4,CHGSC4		;ONE LESS PAGE TO GET MAP FOR
	HRRZM	T1,.USTMU+1		;SAVE THE TARGET SECTION
	HLRZS	T1			;GET THE SECTION MAPPING TO
CHGS2B:	ANDI	T1,MXSECN		;SAVE ONLY SECTION #
	MOVNS	T1			;-SECTION #
	MOVSI	T3,(1B0)		;MAKE BIT MASK AGAIN
	LSH	T3,(T1)			;...
	MOVNS	T1			;SECTION # AGAIN
	CAILE	T1,(T2)			;HAVE WE ALREADY SCANNED THIS FAR?
	TRNE	P2,1			;OR DONE A FUTURE SCAN ALREADY?
	PUSHJ	P,CHGS20		;SCAN AHEAD IN THE LIST
	TDNN	P2,T3			;WILL SECTION BE INDIRECT AFTER PROCESSING?
	JRST	CHGSC4			;NO
	PUSHJ	P,CHGS30		;GET TARGET SECTION
	CAMN	T1,.USTMU+1		;LOOP?
	JRST	IALERR			;YES, HE LOSES
	JRST	CHGS2B
CHGSC3:	TRNE	T1,-1			;CAN'T DELETE SECTION 0
	TRNE	T1,<-1^!MXSECN>		;AND MUST BE A LEGAL SECTION
	JRST	ILSERR			;LOSE
	SKIPN	.UPMP+SECTAB(T1)	;SECTION EXIST (NOTE SIGN BIT ON
					;SO OK EVEN IF IN S1)
	JRST	[TLNE	T1,(PG.IDC)	;IDC LIT?
		 JRST	CHGSC4		;YES, JUST PROCEED
		 JRST	SMEERR	]	;CAN'T DESTROY NON-EX SECTION
	CAMN	T1,.USTMU		;TRYING TO DESTROY SECTION WITH ARGS?
	JRST	IALERR			;CAN'T
	ADD	P1,[1,,0]		;# OF SECTIONS BEING DESTROYED
	MOVSI	T3,(1B0)		;THIS SECTION IF INDIRECT, NO
	MOVNI	T1,(T1)			;LONGER EXISTS
	LSH	T3,(T1)			;...
	ANDCAM	T3,P2			;...
CHGSC4:	SOJG	P4,CHGSC1		;VALIDATE ALL ARGS
	PUSH	P,T4			;SAVE NUMBER OF MAPS TO ALLOCATE
	PUSHJ	P,FSTPAG		;GET FIRST PAGE
	MOVE	P4,P3			;RESTORE COUNT
	PUSHJ	P,FNDPDB##		;POINT TO THE PDB
	TLZN	P1,-1			;ANY MAPS TO DESTROY?
	JRST	CHGSC8			;NO
CHGSC5:	PUSHJ	P,NXTSPG		;GET NEXT ARGUMENT
	JUMPGE	T1,CHGSC7		;A CREATE, IGNORE FOR NOW
	SKIPN	T2,.UPMP+SECTAB(T1)	;GET SECTION ENTRY
	JRST	CHGSC7			;CONTINUE
	HRRZM	T1,.USSPT
	TLNE	T2,(<PM.ACD^!PM.DCD>B2)	;IMMEDIATE POINTER?
	JRST	CHGSC6			;NO, JUST ZAP SECTION POINTER
	PUSH	P,T1			;SAVE MAPPING
	LDB	T2,JBYSG2##		;GET HIGH SEG SECTION #
	CAIN	T2,(T1)			;THIS SECTION?
	S0PSHJ	KILHGS##		;YES, KILL HIGH SEG THEN
	HRRZS	T1,(P)			;SECTION ARG AGAIN
	PUSHJ	P,KILSEC		;KILL ALL PAGES IN SECTION
	LDB	T1,NZSSCN##
	SOS	T1			;DECREMENT MAP COUNT
	DPB	T1,NZSSCN##
	POP	P,T1			;RETURN
	MOVE	T2,.UPMP+SECTAB(T1)	;GET POINTER
	ANDI	T2,37777		;PAGE # ONLY
	PUSHJ	P,LKPSF			;LINK PAST THE PAGE IN PAGTAB
	SSX	T2,MS.MEM		;PAGTAB SECTION
	HLLZS	PAGTAB(T2)		;INDICATE LAST PAGE ALLOCATED
	HRRZS	T2
	PUSHJ	P,DLTPGC		;DELETE PAGE
	MOVE	T1,.USSPT		;GET SECTION # ONE MORE TIME
	MOVEI	T1,.UPMVP/PAGSIZ##(T1)	;TURN OFF WSB FOR IT
	PUSHJ	P,TSWST			;GET IT
	  CAIA
	ANDCAM	T2,(T4)			;CLEAR BIT
	MOVE	T1,.USSPT		;ONE MO' TIME
CHGSC6:	LDB	T4,JBYSG2##		;GET HIGH SEG SECTION
	CAMN	T4,.USSPT		;THIS SECTION (ONLY IF INDIRECT)?
	PUSHJ	P,RSECT4		;YES, GET REAL SECTION
	  JFCL				;IGNORE SKIP
	DPB	T4,JBYSG2##		;PUT IT IN INDEPENDENT SECTION
	SETZM	.UPMP+SECTAB(T1)	;CLEAR
CHGSC7:	SOJG	P4,CHGSC5		;OVER ALL ARGS
CHGSC8:	JUMPE	P1,TPOPJ1##		;CLEAR JUNK, NOTHING MORE TO DO
	MOVE	T4,(P)			;# OF PAGES WE NEED
	SKIPE	P1,T4			;REALLY WANT ANY?
	PUSHJ	P,GSMPGS		;GET THEM
	PUSHJ	P,FSTPAG		;POINT TO FIRST PAGE AGAIN
	MOVE	P4,P3			;RESTORE COUNT
CHGSC9:	PUSHJ	P,NXTSPG		;GET NEXT PAGE
	JUMPL	T1,CHGS10		;DESTROY
	HRRZ	T2,T1			;JUST SECTION #
	HRRZM	T1,.USSPT		;SAVE
	TLNE	T1,(PG.SLO)		;CREATE SECTION EX NIL?
	JRST	CHGS11			;NO, MAP TOGETHER
	SKIPN	P1			;HAVE CORE?
	SETO	P1,			;NO, DON'T WAIT FOR IT
	PUSHJ	P,CRSMAP		;MAKE SECTION
	SKIPN	T1,.USSPT		;IN CASE SECTION 0
	JRST	CHGS10
	SOS	T1
	IDIVI	T1,^D36/UP.SCS	;GET COUNTER
	LDB	T4,PNTNZS(T2)	;GET IT
	CAIN	T1,UP.VRG		;JUST CREATED?
	JRST	CHGS10			;YES
	MOVE	P2,T2
	MOVE	T1,.USSPT		;GET SECTION NUMBER
	LDB	T2,JBYSG2##		;GET HIGH SEG SECTION #
	CAIN	T2,(T1)			;THIS SECTION?
	S0PSHJ	KILHGS##		;YES, KILL HIGH SEG THEN
	MOVE	T1,.USSPT		;GET SECTION #
	PUSHJ	P,KILSEC		;EMPTY SECTION IF IDC AND IT EXISTED
	MOVEI	T4,UP.VRG
	DPB	T4,PNTNZS(P2)		;SO IT WON'T GET DELETED
CHGS10:	SOJG	P4,CHGSC9		;DO NEXT
	SETZ	T1,			;RESTORE SECTION 0 MAPPING
	POP	P,T4			;RESTORE AMT OF CORE WE WANTED
	JUMPE	T4,CPOPJ1##		;DONE IF NOTHING REALLY CREATED
	AOS	(P)
	SKIPL	P1			;GET ALL MAPS IN CORE?
	POPJ	P,			;YES, RETURN
	PUSHJ	P,XPANDH##		;MARK JOB EXPANDING
IFN FTMP,<
	PUSHJ	TGVMM##
>
	PUSHJ	P,WSCHED##		;WAIT
	MOVSI	T1,(UP.BIG)
	IORM	T1,.USBTS		;BE SURE SET
	POPJ	P,

;HERE IF USER WANTS TO MAP TWO SECTIONS TOGETHER

CHGS11:	HRRZ	T2,T1			;TARGET SECTION
	SKIPE	T2,.UPMP+SECTAB(T2)	;DOES IT EXIST ALREADY?
	TLNE	T2,(<PM.DCD^!PM.ACD>B2)	;IF SO, IS IT INDIRECT ANYWAY?
	JRST	CHGS12			;NON-EX OR INDIRECT, ALL IS WELL
	PUSH	P,T1			;SAVE T1
	PUSHJ	P,KILSEC		;KILL ALL PAGES IN SECTION
	HRRZ	T1,(P)			;SECTION BEING KILLED
	MOVE	T2,.UPMP+SECTAB(T1)
	PUSHJ	P,ZAPNZM
	POP	P,T1
CHGS12:	HLRZ	T2,T1			;SOURCE SECTION
	ANDI	T2,MXSECN		;KEEP ONLY SECTION #
	ANDI	T1,MXSECN		;..
	MOVEI	T2,SECTAB(T2)		;SOURCE SECTION
	IORI	T2,(<PM.ICD>B2!PM.CSH!PM.WRT!PM.PUB)
	HRLI	T2,CPUN##(J)		;INDEX INTO THE SPT
	MOVSM	T2,.UPMP+SECTAB(T1)	;SET IT
	JRST	CHGS10
;HERE TO SCAN AHEAD IN THE ARG LIST TO SET ALL BITS FOR SECTIONS
;WHICH WILL BE INDIRECT
CHGS20:	PUSHJ	P,SAVT##		;SAVE THE T'S
	PUSH	P,.USNXP		;SAVE CURRENT POSITION
	MOVEI	T4,-1(P4)		;# OF ARGS LEFT
	SOJLE	T4,CHGS24
CHGS21:	PUSHJ	P,NXTSPG		;GET NEXT PAGE
	MOVNI	T2,(T1)			;WHATEVER THE TARGET PAGE IS
	MOVSI	T3,(1B0)		;MASK FOR THAT PAGE
	LSH	T3,(T2)			;MAKE IT
	TLNN	T1,(PG.GAF)		;IS THIS A DELETE?
	TLNN	T1,(PG.SLO)		;NO, IS THIS A MAP TOGETHER?
	TDZA	P2,T3			;DELETE OR CREATE EMPTY
	TDO	P2,T3			;MAP TOGETHER
	SOJG	T4,CHGS21
CHGS24:	POP	P,.USNXP		;RESTORE .USNXP
	POPJ	P,			;ALL BITS SET
;HERE TO GET NEXT LEVEL DOWN IN SECTION FOR SECTION IN T1
CHGS30:	PUSH	P,.USNXP		;SAVE CURRENT .USNXP
	PUSH	P,T1			;SAVE THE ARG
	PUSH	P,T2
	PUSH	P,T3
	PUSH	P,T4
	CAMG	T1,.USTMU+1		;NEED TO GO BACK IN LIST?
	SKIPA	T4,P3			;RESTORE # OF ARGS
	SKIPA	T4,P4			;NO
	PUSHJ	P,FSTPAG		;BACK TO THE BEGINNING
CHGS31:	PUSHJ	P,NXTSPG		;GET NEXT ARG
	HRRZ	T2,T1			;TARGET SECTION
	CAMLE	T2,-3(P)		;PASSED DESIRED SECTION?
	JRST	CHGS35			;YES, USE CURRENT MAPPING
	CAME	T2,-3(P)		;IS THIS THE DESIRED SECTION?
	SOJG	T4,CHGS31		;NO, LOOK AHEAD
	TLNN	T1,(PG.GAF)		;IS DELETE SET (SHOULD NOT BE)
	TLNN	T1,(PG.SLO)		;IS SLO SET (SHOULD BE)
	STOPCD	.,JOB,MIC		;++MONITOR IS CONFUSED
	HLRZS	T1			;THE SECTION
	ANDI	T1,MXSECN
	JRST	CHGS37
CHGS35:	MOVE	T1,-3(P)		;USE CURRENT MAPPING
	SKIPE	T1,.UPMP+SECTAB(T1)		;GET THAT SECTION POINTER
	TLNN	T1,(<PM.ACD^!PM.DCD>B2)	;BETTER BE INDIRECT
	XCT	MIC
	LDB	T1,[POINT 5,T1,17]	;SECTION IT'S CURRENTLY MAPPED TO
CHGS37:	MOVEM	T1,-3(P)
	POP	P,T4
	POP	P,T3
	POP	P,T2
	POP	P,T1
	POP	P,.USNXP
	POPJ	P,
;SUBROUTINE TO SCAN A LIST OF PAGES, VERIFY THAT EACH ENTRY IN THE
; LIST REPRESENTS A LEGAL VIRTUAL PAGE NUMBER, AND COUNT THE NUMBER
; OF ENTRIES WITH THE HIGH ORDER BIT ON AND THE NUMBER OF ENTRIES WITH
; THE HIGH ORDER BIT OFF.
;CALLING SEQUENCE:
;
;	MOVE	T1,[XWD N,ADDRESS OF LIST]
;	MOVE	T2,REQUIRED ATTRIBUTES
;	PUSHJ	P,PLTSN
;ERROR RETURNS, ILLEGAL PAGE NUMBER, PAGE EXISTS BUT MUST NOT, PAGE
; DOESN'T EXIST BUT MUST, PAGE MUST BE IN CORE BUT ISN'T, PAGE MUST
; NOT BE IN CORE BUT IS, AN ATTEMPT HAS BEEN MADE TO DO ANYTHING TO A
; PAGE IN A SHARABLE HIGH SEGMENT.
;RETURNS CPOPJ ON AN ERROR, T1 = ERROR CODE,
; RETURNS CPOPJ1 ON SUCCESS, T1 PRESERVED, T2 = NUMBER OF ENTRIES
; WITH THE SIGN BIT ON, T3 = THE NUMBER OF ENTRIES WITH THE SIGN BIT OFF
; .UPTMP=C(T3) - NUMBER OF ALLOCATED BUT ZERO PAGES
; T4=# OF NON-EXISTENT SECTIONS (AND PA.PME WASN'T ON) + 1 IF UP.BIG WASN'T ON
;AND T4 IS NON-ZERO OTHERWISE (SO WILL ALLOCATE PAGE FOR .WSBNZ)

;RETURNS WITH BIT 0 ON IN M IF BIT 1(PG.SLO, PG.DSK) IS ON IN ANY ARGUMENT WORD

PLTSN:	PUSHJ	P,INTLVL##	;NO WAITING AT INTERRUPT LEVEL
	PUSHJ	P,IOWAT		;WAIT FOR I/O TO STOP (SO I/O CAN'T CHANGE ARG LIST)
	PUSHJ	P,SAVE3##	;SAVE P1-P3
	PUSHJ	P,SAVR##	;AND R
	SE1ENT
	PUSH	P,T1		;SAVE POINTER TO THE ARGUMENT LIST
	HRRZ	P1,T1		;SAVE COPY FOR COMPUTING LIST LIMITS
	PUSHJ	P,FSTPAG	;POINTER TO USER'S ARGUMENT LIST
	HLRE	P2,T1		;NUMBER OF ARGUMENTS
	JUMPLE	P2,[PUSHJ P,IALERR
		JRST T2POPJ##]	;MUST BE A POSITIVE NUMBER OF ARGUMENTS
	ADJSP	P,2		;FOR STORING LIMITS
	PUSH	P,P2		;SAVE THE NUMBER OF ARGUMENTS
	MOVE	P3,.USNXP	;NEGATIVE ARG LIST FORM?
	AOSE	P3		;?
	MOVEI	P2,1		;YES, THEN ARG LIST SIZE IS 1
	SOS	P1		;INCLUDE COUNT
	ADDI	P2,(P1)		;LAST PAGE OF ARG LIST
	TRZ	P1,<PAGSIZ##-1>	;SO WON'T SHIFT INTO P2
	LSHC	P1,W2PLSH##	;FIRST AND LAST PAGES CONTAINING ARG LIST
	DMOVEM	P1,-2(P)	;SAVE THEM
	MOVE	P2,T2		;CHECK BITS
PLTSN0:	SETZB	P1,.USTMU	;INITIALIZE ARGUMENT TYPE COUNTER AND .UPTMP TO ZERO
	SETZB	R,P3		;NOTE CAN **NEVER** THINK OF DESTROYING P0
PLTSN1:	PUSHJ	P,NXTPAG	;GET THE NEXT ARGUMENT
	TLZE	T1,(PG.SLO)	;CREATE VIRTUAL OR PAGE ON SLOW DEVICE?
	TLO	M,ARGMD		;YES, REMEMBER THAT
	MOVE	T3,T1		;SAVE ARG
	HRRZS	T1
	TRNN	T1,HLGPNO	;IS IT PAGE 0 OF SOME FLAVOUR?
	PUSHJ	P,ISITS0	;??
	  CAIA			;IS NOT PAGE 0
	JRST	PLTSN2		;IS PAGE 0, CHECK IT SOME OTHER WAY
	PUSHJ	P,LGLPG		;A LEGAL PAGE?
	  JRST	PLTSN3		;NO
PLTSN4:	JUMPE	T1,PLTS30	;CHECK PAGE 0 OTHERWISE
	CAML	T1,-2(P)	;DOES IT CONTAIN THE ARG LIST?
	CAMLE	T1,-1(P)	;?
PLTS30:	SKIPA	T1,T3
	JRST	PLTSN3		;LOSE
	TRNN	P2,PA.IHB	;IGNORE THE HIGH ORDER BIT OF THE ARGUMENT?
	JUMPGE	T1,PLTSN5	;NO, JUMP IF THE HIGH ORDER BIT IS OFF
	TLZ	T1,400000	;CLEAR THE HIGH ORDER BIT
	CAIL	P3,(T1)		;THIS PAGE HIGHER THAN LAST ONE SEEN?
	JRST	[PUSHJ P,IALERR	;NO, ILLEGAL ARGUMENT LIST ERROR
		JRST PLTS16]	;ARGUMENT LIST MUST BE IN INCREASING VIRTUAL ORDER
	MOVEI	P3,(T1)		;SAVE AS HIGHEST PAGE SEEN SO FAR
	MOVEI	T3,1		;ASSUME NORMAL CASE (SEE NOTE @PLTSN8)
	TRNN	P2,PA.PMI	;MUST THE PAGE BE IN CORE?
	JRST	PLTSN8		;NO
	PUSHJ	P,TSWST		;SEE IF THE PAGE IS IN THE WORKING SET
	  TLOA	T3,(1B0)	;FLAG TO NOT ADD ANY COUNT
	JRST	PLTSN8		;IN THE WORKING SET
	TLNE	T1,(PG.IDC)	;DOES HE WANT US TO IGNORE THIS?
	JRST	PLTSN8		;YES, DO SO
	PUSHJ	P,PMIERR	;HE CARES, HE ALSO LOSES
	PJRST	PLTS16
PLTSN5:	JUMPE	P3,PLTS5A	;FIRST TIME
	CAIL	P3,(T1)		;THIS PAGE HIGHER THAN THE LAST PAGE SEEN?
	JRST	[PUSHJ P,IALERR	;NO, ILLEGAL ARGUMENT LIST ERROR
		JRST PLTS16]	;LOSE
PLTS5A:	MOVEI	P3,(T1)		;SAVE AS HIGHEST PAGE SEEN
	MOVSI	T3,1		;ADD 1 TO THE COUNT OF ARGUMENTS WITH THE
				; HIGH ORDER BIT OFF (SEE NOTE @PLTSN8)
	PUSHJ	P,PLTS20	;SECTION EXIST?
	  JRST	PLTS17		;NO, SEE ABOUT NON-EX SECTION CREATION
	PUSHJ	P,GTPME		;GET CONTENTS OF MAP SLOT
	TLZ	T2,(PM.NAD)
	CAMN	T2,[PM.ZER]	;ABZ PAGE?
	AOSA	.USTMU		;YES, BUMP COUNTER
	TRNN	P2,PA.PCE	;CAN THE PAGE EXIST?
	JRST	PLTSN6		;YES, PROCEED
	JUMPE	T2,PLTS13	;DOES PAGE EXIST (GO IF NO)?
	TLO	T3,(1B0)	;IN CASE WE DON'T CARE
	TLNE	T1,(PG.IDC)	;REALLY NOT WANT IT TO EXIST?
	JRST	PLTS13
	PUSHJ	P,PCEERR	;YES, PAGE CANNOT EXIST BUT DOES ERROR
	JRST	PLTS16		;LOSE
PLTSN6:	TRNN	P2,PA.PCI	;CAN THE PAGE BE IN CORE?
	JRST	PLTSN8		;YES, PROCEED
	PUSH	P,P1		;NEED TO SAVE T2 HERE
	MOVE	P1,T2
	PUSHJ	P,TSWST		;IS THE PAGE IN THE WORKING SET?
	CAMN	P1,[PM.ZER]	;NO, ABZ?
	  TLOA	T3,(1B0)	;NO COUNT TO ADD
	JRST	PLTSN7		;NO, ALL IS WELL
	CAME	P1,[PM.ZER]	;ALWAYS CARE ON PAGE I/O IF ABZ
	TLNN	T1,(PG.IDC)	;DO WE?
	JRST	[POP	P,P1	;RESTORE P1
		 JRST	PLTS15]	;CONTINUE
PLTSN7:	POP	P,P1
;AT THIS POINT T3 AS "1" IN THE RIGHT HALF IF THE ARG HAD THE SIGN ON,
;AND "1" IN THE LEFT HALF IF THE SIGN BIT WAS OFF.  HOWEVER, IF THE 
;SIGN BIT OF T3 IS ON, THIS NUMBER WILL *NOT* BE ADDED TO TO THE
;ACCUMULATED COUNTS.  THE CODE *CANNOT* JUST ZERO T3 TO INDICATE
;NOTHING TO ADD AS THE EXISTANCE OF THE COUNT IN THE APPROPRIATE
;HALFWORD IS USED TO DECIDE WHETHER THE ORIGINAL ARG HAD THE SIGN
;BIT ON OR NOT.  NOTE THAT RIGHT-HALF TESTERS CAN TEST FOR -1, BUT
;LEFT HALF TESTERS MUST TEST FOR NO MORE BITS THAN 377777.

PLTSN8:	TRNN	P2,PA.PME	;MUST THE PAGE EXIST?
	JRST	PLTS13		;NO, PROCEED
	PUSHJ	P,PLTS20
	  TDZA	T2,T2		;NO, PAGE DOESN'T THEN
	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE MAP SLOT
	JUMPN	T2,PLTSN9	;IT DOES
	TLO	T3,(1B0)	;IN CASE WE DON'T CARE
	TLNE	T1,(PG.IDC)	;DO WE?
	TRNE	P2,PA.PMI!PA.PCI ;CAN'T FOLLOW IGNORE BIT FOR PAGE IN/OUT
	CAIA
	JRST	PLTS13		;NO
	PUSHJ	P,PMEERR	;JUMP IF PAGE DOESN'T EXIST SINCE IT MUST
	JRST	PLTS16		;LOSE
PLTSN9:	TRNN	T3,-1		;SIGN BIT OFF IN ARGUMENT?
	TRNN	P2,PA.PCI	;REALLY ASKING IF THIS IS A PAGE IN
	JRST	PLTS13		;NO, DON'T CHECK INCORE QUEUES
	TLNE	T2,(PM.OIQ)	;ON IN LIST?
	JRST	[TLNN	T2,(PM.SSP) ;SLOW?
		 SKIPA	T3,[PAGINQ##] ;NO, FAST
		 MOVEI	T3,PAGSNC## ;SLOW QUEUE
		 TLZ	T2,(PM.NAD) ;CLEAR JUNK
		 JRST	PLTS11]	;REMOVE PAGE
	TLZ	T2,(PM.NAD)	;ISOLATE ADDRESS
PLTS10:	PUSHJ	P,ONPOQ		;NO, IS THE PAGE ON THE IP OR OUT LIST?
	  JRST	PLTS12		;NO
	CAIN	T3,PAGIPQ##	;THIS PAGE IN THE IN PROGRESS QUEUE?
	JRST	PLTS18		;YES
	HRRZ	T2,T4		;YES, GET THE PAGE
PLTS11:	PUSHJ	P,RMVPFQ	;REMOVE PAGE FROM QUEUE
	HRRZ	T3,.USTMU	;CURRENT PAGE ON PRIVATE QUEUE
	HRRM	T3,@[IW MS.MEM,PAGTAB(T2)] ;POINT AHEAD
	SKIPE	T3		;AND IF SOMETHING IS THERE
	HRRM	T2,@[IW MS.MEM,PT2TAB(T3)] ;POINT HIM BACK
	HRRM	T2,.USTMU	;PUT PAGE IN OUR PRIVATE QUEUE
	MOVSI	T3,(P2.TRN)	;MARK PAGE IN TRANSIT
	IORM	T3,@[IW MS.MEM,PT2TAB(T2)]
	MOVSI	T3,-1		;AND "INCREMENT" COUNT
	ADDM	T3,.USTMU
	TDZA	T3,T3		;DON'T NEED TO ALLOCATE ANY CORE
PLTS12:	MOVSI	T3,1		;NO, COUNT THE PAGE
PLTS13:	PUSHJ	P,PLTS20	;SECTION EXIST?
	  JRST	PLTS14		;NO, DON'T WORRY ABOUT HIGH SEGS THEN
PLTS19:	PUSHJ	P,TPNHS		;IS THE PAGE IN A HIGH SEGMENT?
	  TLO	M,HSPAG		;YES, REMEMBER HIGH SEGMENT PAGE SEEN
	MOVE	T2,JBTSGN##(J)	;GET HIGH SEGMENT BITS
	TLNE	M,HSPAG		;WAS THIS A HIGH SEGMENT PAGE?
	TLNN	T2,SHRSEG!SPYSEG;YES, IS THE HIGH SEGMENT SHARABLE OR A SPY SEG?
	JRST	PLTS14		;NO
	PUSHJ	P,PSHERR	;YES, PAGE IN A SHARABLE HIGH SEGMENT ERROR
	JRST	PLTS16		;LOSE
PLTS14:	SKIPL	T3		;IF SIGN BIT SET, DON'T ACCUMULATE
	ADD	P1,T3		;ACCUMULATE NUMBER OF ARGUMENTS
	SOSLE	(P)		;LOOKED AT ALL ARGUMENTS IN THE LIST?
	JRST	PLTSN1		;NO, LOOP OVER ALL ARGUMENTS
	ADJSP	P,-3		;CLEAR STACK JUNK
	HRRZ	T2,P1		;T2 = NUMBER OF ARGUMENTS WITH THE SIGN BIT ON
	HLRZ	T3,P1		;T3 = NUMBER OF ARGUMENTS WITH THE SIGN BIT OFF
	MOVEI	T4,(R)		;# OF NON-EX SECTIONS
	SKIPGE	.USBTS		;ALREADY A BIG USER?
	JRST	TPOPJ1##	;YES, DON'T NEED TO MAKE .WSBNZ
	JUMPE	T4,TPOPJ1##	;NOT BIG ALREADY, BUT NOT BECOMING SO EITHER
	AOJA	T4,TPOPJ1##	;RESTORE T1 AND RETURN

PLTS15:	PUSHJ	P,PCIERR
PLTS16:	ADJSP	P,-4		;FIX STACK
	POPJ	P,
				; ERROR CODE IN T1

PLTS17:	TRNN	P2,PA.PCE	;CAN'T EXIST?
	  JRST	PLTSN6		;NO, CHECK OTHER THINGS
	HLRZ	T4,R		;PREVIOUS HIGHEST SECTION COUNTED
	HRL	R,T2		;REMEMBER SECTION
	CAME	T4,T2		;SAME AS CURRENT?
	AOJA	R,PLTS14
	JRST	PLTS14

;HERE IF PAGE ON THE IP QUEUE

PLTS18:	SSX	T4,MS.MEM	;YES, MUST WAIT UNTIL I/O IS DONE, PAGTAB SECTION
	DPB J,[POINT PT.SJB,PAGTAB(T4),^L<PT.JOB>+PT.SJB-1] ;STORE JOB NUMBER IN IP QUEUE
	MOVEI	T3,PIOWQ##	; SO JOB CAN BE WOKEN UP WHEN I/O IS DONE
	DPB	T3,PJBSTS##	;PUT JOB IN PAGING I/O WAIT
	PUSHJ	P,[IFN FTMP,<
		   PUSHJ P,REMMM## ;REMEMBER STATE OF THE MM
>
		   PJRST WSCHED##] ;COME BACK WHEN "IP" QUEUE HAS BEEN WRITTEN
	PUSHJ	P,GTPME		;(IN CASE PAGE WRITE ERROR ENCOUNTERED)
	JRST	PLTS10		;SEE IF IT'S ON THE OUT QUEUE NOW
PLTS20:	HRRZ	T2,T1		;PAGE #
	LSH	T2,P2SLSH##	;CONVERT TO SECTION #
	SKIPE	.UPMP+SECTAB(T2) ;DOES IT EXIST?
	AOS	(P)		;YES
	POPJ	P,

PLTSN2:	TLNE	T3,(PG.IDC)	;IS THIS AN I DON'T CARE?
	JUMPGE	T3,PLTSN4	;W/O PG.GAF LIT?
PLTSN3:	PUSHJ	P,IALERR
	JRST	PLTS16
;SUBROUTINE TO SEE IF A PAGE IS ON THE "IN PROGRESS" OR "OUT: QUEUE
;CALL:
;	MOVE	T2,MAP CONTEXTS (DSK ADDRESS)
;	PUSHJ	P,ONPOQ		;SEE IF ON EITHER QUEUE
;	  NOT FOUND
;	FOUND, T3=QUEUE, T4=PHYSICAL PAGE NUMBER
;PRESERVES T1

ONPOQ::	SE1ENT			;ENTER SECTION 1
	MOVEI	T3,PAGOUQ##	;"OUT" QUEUE HEADER
	PUSHJ	P,SRCPQ		;SCAN THE QUEUE
ONIPQ::
	  SKIPA	T3,[PAGIPQ##]	;NOT THERE, TRY "IP" QUEUE
	JRST	CPOPJ1##	;FOUND RETURN
;	PJRST	SRCPQ		;SCAN THAT QUEUE

;SUBROUTINE TO SEARCH A PAGE QUEUE TO SEE IF IT CONTAINS A PAGE WITH A GIVEN
; DSK ADDRESS
;CALL:	MOVE	T2,DSK ADDRESS
;	MOVEI	T3,ADDRESS OF QUEUE HEADER
;	PUSHJ	P,SRCPQ		;SEARCH THE PAGE QUEUE
;	  NOT FOUND
;	FOUND, T4=PHYSICAL PAGE NUMBER
;PRESERVES T1

SRCPQ:	SKIPN	T4,(T3)		;ANYTHING AT ALL ON THE QUEUE?
	POPJ	P,		;NO, SO PAGE IN QUESTION ISN'T
SRCPQ0:	PUSHJ	P,SAVE1##	;SAVE A WORK REG
SRCPQ1:	SSX	T4,MS.MEM	;PAGTAB SECTION
	LDB	P1,[POINT MT.SAD,MEMTAB(T4),<^L<MT.DAD>+MT.SAD-1>]
	CAMN	P1,T2		;SAME AS DSK ADDRESS FROM A MAP?
	JRST	SRCPQ2		;YES, FOUND IT
	HRRZ	T4,PAGTAB(T4)	;NEXT PAGE ON QUEUE, LAST PAGE?
	JUMPN	T4,SRCPQ1	;NO, LOOP OVER ALL PAGES ON THE LIST
	POPJ	P,		;PAGE NOT IN THE LIST
SRCPQ2:	HRRZS	T4		;ISOLATE PHYSICAL PAGE NUMBER
	JRST	CPOPJ1##	;AND GIVE FOUND RETURN

;SUBROUTINE TO POINT M AT THE FIRST ARGUMENT IN THE USER'S ARGUMENT
; LIST AND SETUP .UPNXP IF A NEGATIVE COUNT WAS SPECIFIED, I.E.,
; A RANGE OF PAGES RATHER THAN A LIST OF PAGES

FSTPAG:	PUSHJ	P,SAVT##	;MAKE THIS LOOK LIKE A HRRI M,-1(T1)
	PUSHJ	P,GETSAC##	;GET CONTENTS OF USER'S AC
	SETOM	.USNXP		;ASSUME A TRADITIONAL ARGUMENT LIST
	HRRI	M,(T1)		;SETUP M TO GET ARGUMENT COUNT
	PUSHJ	P,GETWSU##	;GET ARGUMENT COUNT
	JUMPGE	T1,CPOPJ##	;POSITIVE MEANS A LIST IS SPECIFIED
	PUSHJ	P,GETWS1##	;GET THE RANGE
	JRST	PREPA1		;STORE IT FOR CALLS TO NXTPAG AND RETURN

;SUBROUTINE TO GET THE NEXT WORD FROM THE USER'S ARGUMENT LIST
; FSTPAG MUST HAVE BEEN CALLED BEFORE CALLING NXTPAG

NXTPAG:	MOVE	T1,.USNXP	;A RANGE OF PAGES SPECIFIED?
	CAMN	T1,[-1]
	PJRST	GETWS1##	;NO, GET NEXT ARGUMENT FROM LIST
	TLNN	T1,37777             ;LEFT HALF, RIGHT HALF ARGUMENT?
	AOSA	T1		;NO, JUST INCREMENT LEFT HALF
	AOBJN	T1,.+1		;YES, INCREMENT BOTH HALVES
	JRST	PREPA2		;STORE FOR NEXT CALL AND RETURN

NXTSPG:	MOVE	T1,.USNXP	;A RANGE OF PAGES SPECIFIED?
	CAMN	T1,[-1]
	PJRST	GETWS1##	;NO, GET NEXT ARGUMENT FROM LIST
	AOBJN	T1,.+1		;YES, INCREMENT BOTH HALVES
	JRST	PREPA2		;STORE FOR NEXT CALL AND RETURN

;SUBROUTINE TO GET PREVIOUS WORD FROM THE USER'S ARGUMENT LIST
; FSTPAG MUST HAVE BEEN CALLED BEFORE CALLING PREPAG

PREPAG:	MOVE	T1,.USNXP	;A RANGE OF PAGES SPECIFIED?
	CAMN	T1,[-1]
	SOJA	M,GETWSU##	;NO, BACK UP TO PREVIOUS ARGUMENT IN LIST AN GET IT
PREPA1:	TLNN	T1,37777	;PAGE PAIR?
	SOSA	T1		;NO, BACK UP THE PAGE NUMBER
	SUB	T1,[1,,1]	;BACK UP 1 PAGE
PREPA2:	MOVEM	T1,.USNXP	;SAVE FOR NEXT CALL
	POPJ	P,		;AND RETURN
;ERROR RETURNS

PIOERR:	PUSHJ	P,SAVE1##
	HRRZ	P1,T2		;SWPLST INDEX
	MOVE	S,SWPLST##(P1)	;GET THE SWPLST ENTRY CONTAINING THE ERROR
	TLNN	S,(SL.DIO)	;INPUT ERROR?
	JRST	PIOER1		;YES, NOTHING CAN BE DONE ABOUT IT
	PUSHJ	P,MAPBAK	;RESTORE THE MAP
	SOS	.JDAT+JOBPD1##+1 ;FORCE THE UUO TO BE REDONE
	POPJ	P,		;RETURN
PIOER1:	PUSHJ	P,DLTSLX	;DELETE THE SWPLST ENTRY
	JRST	PIOER2		;RETURN ERROR CODE TO THE USER

;ERROR RETURNS
	ERCODE	UIFERR,PAGUF%	;(0)UNIMPLEMENTED FUNCTION
	ERCODE	IALERR,PAGIA%	;(1)ILLEGAL ARGUMENT LIST
	ERCODE	ILPERR,PAGIP%	;(2)ILLEGAL PAGE
	ERCODE	PCEERR,PAGCE%	;(3)PAGE CANNOT EXIST BUT DOES
	ERCODE	PMEERR,PAGME%	;(4)PAGE MUST EXIST BUT DOESN'T
	ERCODE	PMIERR,PAGMI%	;(5)PAGE MUST BE IN CORE BUT ISN'T
	ERCODE	PCIERR,PAGCI%	;(6)PAGE CANNOT BE IN CORE BUT IS
	ERCODE	PSHERR,PAGSH%	;(7)PAGE IN A SHARABLE HIGH SEGMENT
	ERCODE	PIOER2,PAGIO%	;(10)PAGING I/O ERROR
	ERCODE	NSAERR,PAGNS%	;(11)NO SWAPPING SPACE AVAILABLE
	ERCODE	TBGERR,PAGLE%	;(12)CORE (VIRTAL OR USER LIMIT) EXCEEDED
	ERCODE	IILERR,PAGIL%	;(13)ILLEGAL IF LOCKED
	ERCODE	NVLERR,PAGNV%	;(14)ATTEMPT TO CREATE ABZ PAGE WITH CVPL=0
	ERCODE	NPVERR,PAGNP%	;(15)NOT PRIVILEGED
	ERCODE	SCEERR,PAGSC%	;(16)SECTION CAN'T EXIST BUT DOES
	ERCODE	SMEERR,PAGSM%	;(17)SECTION MUST EXIST BUT DOESN'T
	ERCODE	ILSERR,PAGIS%	;(20)ILLEGAL SECTION
	SUBTTL	SUBROUTINES

FIXDSK::PUSH	P,J		;SAVE J
	MOVE	J,.USJOB	;J = THE CURRENT JOB'S JOB NUMBER
	LDB	T1,IMGIN##	;T1 = THE NUMBER OF PAGES THIS JOB HAS IN CORE
	ADDI	T1,(P2)		;THE NEW SIZE
	PUSHJ	P,XPANDP##	;CAUSE THE ADDITIONAL PAGES TO BE ALLOCATED ON
				; THE NEXT SWAP-IN
	HLRZS	P2		;HIGHEST VIRTUAL PAGE SEEN
;***FOR NOW****
	TRZ	P2,777		;DON'T INCLUDE NZS FOR NOW
;***CROCK***
	MOVE	T1,(P)		;RESTORE SEGMENT OR JOB NUMBER
	CAIG	T1,JOBMAX##	;IS THIS A HIGH SEGMENT?
	JRST	FIXDS1
	LDB	T1,[POINT 9,R,8];CURRENT SIZE OF THE JOB
	CAIG	P2,(T1)		;HAS THE JOB INCREASED ITS VIRTUAL SIZE?
	MOVEI	P2,(T1)		;NO, ORIGIONAL SIZE
	DPB	P2,JBYHSS##	;YES, STORE NEW HIGH SEGMENT SIZE
	DPB	P2,[POINT 9,R,8];STORE NEW HIGHEST VIRTUAL ADDRESS IN SEGMENT
	MOVE	T1,(P)		;SEG # AGAIN
	MOVEM	R,JBTADR##(T1)	;STORE THAT
FIXDS1:	POP	P,J		;RESTORE SEG # TO J
	PUSHJ	P,SETVRT	;SET .UPVRT NON-0, UPDATE VMTOTL,VMCMAX
	MOVE	T1,.USJOB	;JOB NUMBER
	MOVE	R,JBTADR##(J)	;SETUP R FOR THE LOW SEGMENT FOR WSCHED
				;OR FOR THE HIGH SEG FOR SEGCON/VIRCHK
	AOS	(P)		;GOOD RETURN
	SKIPN	.CPISF##	;ON CLOCK LEVEL (CORE COMMAND)?
	CAILE	J,JOBMAX##	;IF A HIGH SEG,
	POPJ	P,		;SEGCON WILL CALL WSCHED
IFN FTMP,<
	PUSHJ	P,REMMM##	;REMEMBER STATE OF THE MM RESOURCE
>
	PJRST	WSCHED##	;AND WAIT UNTIL JOB GOES OUT AND COMES BACK IN
FIXADR:	TLNE	P1,-1^!HLGPNO	;NZS PAGE SEEN?
	JRST	FIXMJ1		;YES, NOTHING TO DO
	HLRZ	T1,P1		;HIGHEST PAGE SEEN
	CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	PUSHJ	P,TPAHS		;PAGE IN THE HIGH SEGMENT?
	  JRST	FIXMJ1		;YES, NOTHING TO DO
	PUSHJ	P,JSTVRT	;SET .UPVRT NON-0, UPDATE VMCMAX
	LDB	T1,PCORSZ##	;LOW SEGMENT SIZE - 1
	HLRZS	P1		;PUT HIGHEST VIRTUAL PAGE SEEN IN THE RIGHT HALF
	CAIG	P1,(T1)		;WAS A PAGE CREATED ABOVE THE HIGHEST WHICH EXISTED?
	MOVE	P1,T1		;YES, NEW HIGHEST
	DPB	P1,PCORSZ##	;STORE NEW LOW SEGMENT SIZE
	MOVE	R,JBTADR##(J)	;GET SEGMENT SIZE,,SEGMENT ADDRESS
	CAME	J,.CPJOB##
	PJRST	FIXMJ1
FIXAD1:	HLRZM	R,.USHVA	;FOR ADDRESS CHECKING AT INTERRUPT LEVEL
	CAME	J,.CPJOB##	;ONLY FIX FOR CURRENT JOB (VIRCHK)
	PJRST	FIXMJ1		;JUST CLEAR AM
	MOVEM	R,.CPADR##	;STORE FOR UUOCON
	HLRZM	R,.CPREL##	;AND FOR ADDRESS CHECKING
	PJRST	FIXMJ1		;CLEAR THE A.M. AND RETURN TO THE USER
;ROUTINE TO INCREMENT .UPREL ON CREATE PAGES UUO
;ONLY ICUPR PRESERVES T1
ICUPRW:	LSH	T1,W2PLSH##	;GET PAGE NUMBER INVOLVED
ICUPR:	PUSHJ	P,ISITS0	;IS IT IN SECTION 0?
	  JRST	INCNCR		;NO, JUST INCREMENT .USNCR
	CAIG	J,JOBMAX##
	PUSHJ	P,TPAHS
	  POPJ	P,		;DON'T WORRY ABOUT IT
	PUSH	P,T1		;PRESERVE ARG
	ANDI	T1,HLGPNO	;CLEAR SECTION # (PAGE RESOLVES TO S0 IF WE'RE HERE)
	SKIPN	T2,.USREL	;JOB VIRTUAL?
	HLRZ	T2,R		;NO, PHYSICAL SIZE EQUALS VIRTUAL SIZE
	LSH	T2,W2PLSH##	;CONVERT TO HIGHEST PAGE NUMBER
	CAIGE	T1,1(T2)	;PAGE IN THE MIDDLE OF THE ADR SPACE?
	JRST	TPOPJ##		;YES, NOTHING TO DO
	SKIPN	.USREL		;NON-CONTIGUOUS CORE IMAGE?
	HLRZM	R,.USREL	;NO, STORE R SINCE IT MAY BE NOW
	HLRZ	T3,R		;HIGHEST VIRTUAL ADDRESS IN THIS JOB'S ADDRESS SPACE
	LSH	T3,W2PLSH##	;CONVERT TO HIGHEST PAGE
	CAIE	T1,1(T2)	;NEXT PAGE NON-CONTIGUOUS?
	JRST	ICUPR4		;YES, UPDATE UPMEM, SETUP R AND RETURN
	MOVE	T2,.USHSS	;IS THERE A HI SEG?
	SKIPN	.USHSE
	MOVSI	T2,1		;NO, MAKE SURE TEST WILL FAIL
	LSH	T2,W2PLSH##	;COMPUTE START PAGE OF HI SEG
	PUSH	P,T2		;SAVE START PAGE ON THE LIST
	ADDI	T1,1		;NEXT PAGE
ICUPR1:	CAILE	T1,(T3)		;IS THIS PAGE ABOVE THE HIGHEST?
	JRST	ICUPR3		;YES, ALL PAGES ARE CONTIGUOUS
	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE MAP
	JUMPE	T2,ICUPR2	;IF NEXT PAGE EXISTS,
	CAML	T1,(P)		; IF ABOVE HI SEG
	JRST	ICUPR2		; WE'RE DONE. IF NOT ABOVE HI SEG,
	SOS	.USMEM		; IT WILL NOW BE INCLUDED IN .UPREL
				; SO REMOVE IT FROM .UPMEM
	AOJA	T1,ICUPR1
ICUPR2:	LSH	T1,P2WLSH##	;CONVERT FROM PAGE NUMBER TO ADDRESS
	SOSA	T1		;ADDRESS - 1
ICUPR3:	MOVEI	T1,0		;ALL PAGES ARE CONTIGUOUS
	MOVEM	T1,.USREL	;STORE NEW UPREL
	POP	P,(P)		;REMOVE START HI-SEG PAGE FROM LIST
	SKIPA	T1,(P)		;GET PAGE IN QUESTION
ICUPR4:	AOS	.USMEM		;A NON-CONTIGUOUS PAGE, COUNT UP THE NUMBER OF SAME
	ANDI	T1,HLGPNO	;JUST TO BE SURE
	CAIL	T1,(T3)		;CURRENT PAGE HIGHER THAN PREVIOUS HIGHEST?
	DPB	T1,[POINT 9,R,8];YES, MAKE R REFLECT THE HIGHER PAGE
	MOVEM	R,JBTADR##(J)	;NEW PROTECTION,,RELOCATION
	SKIPN	T1,.USREL
	HLRZ	T1,R
	MOVEM	T1,JOBREL##+.JDAT
	PJRST	TPOPJ##		;RESTORE VIRTUAL PAGE NUMBER AND RETURN
;ROUTINE TO DECREMENT .UPREL (PRESERVES T1)
DCUPR:	PUSHJ	P,ISITS0	;IN SECTION 0?
	  JRST	DECNCR		;JUST DECREMENT .USNCR
	CAIG	J,JOBMAX##	;A HIGH SEGMENT?
	PUSHJ	P,TPAHS		;MAKE SURE
	  POPJ	P,		;YES, NOTHING TO DO
DCUPN1:	SKIPN	T2,.USREL	;ALREADY A VIRTUAL USER?
	HLRZ	T2,R		;LH(R) = HIGHEST VIRTUAL ADDRESS
	ADDI	T2,1
	MOVE	T3,T1		;T3 = VIRTUAL PAGE NUMBER
	LSH	T3,P2WLSH##	;CONVERT TO HIGHEST VIRTUAL ADDRESS
	CAIG	T2,(T3)		;LOWER THAN PREVIOUS HIGHEST (IGNORING SECTION,
				;WE'RE REALLY IN S0)?
	SOJA	T2,DCUPR1	;UPDATE UPREL AND R
	MOVEI	T4,PG.BDY##(T3)	;TOP NEW ADR
	ADDI	T4,1
	SUBM	T2,T4		;NUMBER OF PAGES ABOVE .UPREL
	ASH	T4,W2PLSH##
	ADDM	T4,.USMEM	;INCREASE NO OF NON-CONTIG VIRTUAL PAGES
	ADD	T2,[-1,,MPGSIZ##]
	PUSH	P,T1		;SAVE IN CASE WE NEED TO
	CAMN	T3,T2		;ADJACENT TO HIGHEST PAGE?
	SKIPE	T2,.USREL	;YES, NO CHANGE
	SOSA	T2,T3		;NEW UPREL = NEW ALLOCATION - 1
	SOJA	T3,DCUPR3	;LEAVE UPREL = 0, DECREASE R
	MOVEM	T2,.USREL	;STORE NEW VALUE OF UPREL
	SKIPN	T2		;IF NOW CONTIGUOUS
	HLRZ	T2,R		; USE JOB SIZE
	MOVEM	T2,.JDAT+JOBREL## ;UPDATE USERS JOBREL
	JRST	TPOPJ##		;AND RETURN
DCUPR1:	SOS	.USMEM		;DECREMENT COUNT OF NON-CONTIGUOUS PAGES
	LDB	T3,[POINT 9,R,8] ;CURRENT HIGHEST PAGE IN THE LOW SEGMENT
	ANDI	T1,HLGPNO	;CLEAR SECTION # (WE KNOW THIS REALLY RESOLVES
				;TO S0)
	CAIE	T1,(T3)		;DECREASING SIZE?
	POPJ	P,		;NO GO AWAY
	PUSH	P,T1
	LSH	T2,W2PLSH##	;CONVERT HIGEST CONTIGUOUS ADDRESS TO PAGE NUMBER
	SUBI	T3,1(T2)	;NUMBER OF PAGES ABOVE NEW HIGHEST PAGE
	MOVE	T4,T1
	PUSHJ	P,GMPTR
DCUPR2:	MOVE	T2,(T4)		;EACH MAP ENTRY IS A FULL WORD
	TLNN	T2,(PM.SPY!PM.NIA) ;SPY OR HIGH SEG PAGE?
	JUMPN	T2,DCUPR4	; IF NON-ZERO, DON'T CHANGE UPREL
	SUB	R,[PAGSIZ##,,0]	;THIS SLOT EMPTY - DECREMENT R
	SOS	T4		;PREVIOUS MAP SLOT
	SOJG	T3,DCUPR2	;LOOP OVER ALL PAGES POSSIBLY NOT IN THE MAP
	SKIPE	.USREL
	HRL	R,.USREL	;NEW HIGHEST ADDRESS
	SETZM	.USREL		;ALL PAGES IN THE LOW SEGMENT ARE CONTIGUOUS
	JRST	DCUPR4		;STORE R AND RETURN
DCUPR3:	HRL	R,T3		;NEW HIGHEST ADDRESS
	HLRZM	R,.JDAT+JOBREL##;STORE NEW HIGHEST ADDRESS IN LOW SEG FOR THE USER
DCUPR4:	MOVEM	R,JBTADR##(J)	;STORE NEW PROTECTION,,RELOCATION
	POP	P,T1		;RESTORE T1
	POPJ	P,		;AND RETURN

INCNCR:	AOSA	.USNCR
DECNCR:	SOS	.USNCR
	POPJ	P,
;ROUTINE TO DECIDE WHETHER PAGE GIVEN IN T1 IS REALLY A SECTION 0 PAGE
;OR NOT.  SKIP RETURN IF REALLY MAPPED TO SECTION 0, NON-SKIP OTHERWISE

ISITS0:	TRNN	T1,-1^!HLGPNO	;IF IT SAYS IT'S S0
	JRST	CPOPJ1##	;THEN IT PROBABLY IS
	PUSH	P,T1		;SAVE THE ARG
	HRRZS	T1		;CLEAR LH JUNK
	LSH	T1,P2SLSH##	;GET SECTION #
ISITS1:	MOVE	T1,.UPMP+SECTAB(T1) ;GET SECTION MAP POINTER
	TLNN	T1,(<PM.ACD^!PM.DCD>B2) ;IS IT INDIRECT?
	JRST	TPOPJ##		;NO, CAN'T INDIRECT TO S0 THEN
	LDB	T1,[POINT 5,T1,17] ;GET SECTION NUMBER IT MAPS TO IF INDIRECT
	JUMPN	T1,ISITS1	;CHECK IT
	JRST	TPOPJ1##	;IT IS S0 IF THIS IS

;ROUTINE TO DO THE OPPOSITE OF ISITS0

ISITNZ:	TRNN	T1,-1^!HLGPNO	;DOES IT CLAIM TO BE NZS?
	POPJ	P,		;NO, THEN IT ISN'T
	PUSH	P,T1		;SAVE ARG
	HRRZS	T1		;CLEAR LEFT HALF JUNK
	LSH	T1,P2SLSH##	;GET SECTION # ONLY
ISITN1:	MOVE	T1,.UPMP+SECTAB(T1)
	TLNN	T1,(<PM.ACD^!PM.DCD>B2) ;INDIRECT?
	JRST	TPOPJ1##	;NO
	LDB	T1,[POINT 5,T1,17]
	JUMPN	T1,ISITN1	;CHECK NEW MAPPING
	JRST	TPOPJ##		;IT IS IN S0
;ROUTINE TO ADD A DISK PAGE TO THE WORKING SET
;ENTER T1=VIRTUAL PAGE NUMBER OF THE PAGE
;INSDWE MAKES THE PAGE WRITE ENABLED, INSDWL MAKES THE PAGE WRITE LOCKED
;INSDSK DECIDES ON INSDWL OR INSDWE DEPENDING ON THE CONTENTS OF J (HIGH
;SEG CALLS INSDWL)

INSDSK:	CAIG	J,JOBMAX
	  JRST	INSDWE

INSDWL:	PUSHJ	P,GTPME		;GET POINTER
	TLO	T2,(PM.CSH!PM.PUB)	;JUST SET AABTAB BIT
	JRST	INSDSX

INSDWE:	PUSHJ	P,GTPME		;GET MAP POINTER
	TLO	T2,(PM.WRT!PM.CSH!PM.PUB)	;SET AABTAB BIT
INSDSX:	TDNN	T2,[PM.ADR^!PM.ZER] ;IS IT AN ABZ PAGE?
	TLNN	T2,(PM.ZER)	;MAYBE
	JRST	INSDSY		;NOT ABZ
	TDZ	T2,[PM.ADR]	;MAKE ZERO SO SETIMT WON'T
	TLO	T2,(PM.AAB)	;CREATE PAGE WITH AAB ON
	MOVEM	T2,(T4)		;DO DEPOSIT NOW
	PUSHJ	P,INSMEM
	JRST	INSDSZ		;FINISH UP
INSDSY:	TDNN	T2,[PM.ADR]	;NOT ABZ, EXPANDING OR CREATING?
	TLO	T2,(PM.AAB)	;CREATING, SET AAB
	MOVEM	T2,(T4)
INSDSZ:	PUSHJ	P,WSBIT		;GET BIT AND INDEX INTO WORKING SET TABLE
	IORM	T2,(T4)		;ADD THE PAGE TO THE WORKING SET
	POPJ	P,

;ROUTINE TO INSERT A MONITOR PAGE INTO THE JOBS MAP

INSDMC:	PUSHJ	P,GTPME		;GET MAP POINTER
	TLO	T2,(PM.CSH!PM.WRT!PM.PUB)	;SET CACHE BIT
	JRST	INSDSX
INSDMU:	PUSHJ	P,GTPME
	TLO	T2,(PM.WRT!PM.PUB)
	JRST	INSDSX
;ROUTINE TO INSERT A PAGE IN THE MAP, WSBTAB AND AABTAB
;ENTER T1=VIRTUAL PAGE NUMBER, P1=PHYSICAL PAGE NUMBER
;EXIT T1=VIRTUAL PAGE NUMBER
;NOTE THAT INSPAG SHOULD ONLY BE CALLED FOR USER MODE PAGES
;AND INSMPC SHOULD NOT BE CALLED FOR NON-ZERO SECTION USER PAGES (SECTION
;NUMBER CONFUSION VS PAGE 1000-1030=FUNNY SPACE PAGES)

INSPAG:	MOVE	T3,.USJOB	;CURRENT JOB'S JOB NUMBER
	.CREF	IMGIN
	AOS	JBTIMI##(T3)	;INCREMENT NUMBER OF PAGES ALLOCATED IN PHYSICAL CORE
INSMPC:
	MOVE	T3,P1
	HRLI	T3,(<PM.DCD>B2+PM.PUB+PM.WRT+PM.CSH+PM.AAB+PM.COR)

	PUSHJ	P,WSBIT		;GET BIT AND INDEX INTO WSBTAB
INSMPU:	IORM	T2,(T4)		;INDICATE THIS PAGE IS NOW IN THE WORKING SET
	CAILE	J,JOBMAX##	;HIGH SEGMENT?
	TDZ	T3,[PM.WRT]	;YES, WRITE LOCK THE PAGE
	PUSHJ	P,GTPME
	MOVEM	T3,(T4)		;STORE THE PHYSICAL PAGE NUMBER IN THE MAP
	TLZ	T2,(PM.NAD)
	CAME	T2,[PM.ZER]
	POPJ	P,
;HERE TO ADJUST VIRTAL, UPMEM FOR ALLOCATED BUT 0 PAGES
INSMEM:	AOS	VIRTAL##	;VIRTAL WAS ALREADY UPDATED
	CAIG	J,JOBMAX##
	PUSHJ	P,TPAHS
	  POPJ	P,
	PUSHJ	P,ISITS0	;IS IT A SECTION ZERO PAGE?
	  PJRST	DECNCR		;NO, DECREMENT .USNCR
	PUSH	P,T1		;SAVE THE ARG
	ANDI	T1,HLGPNO	;MAKE IT S0
	SKIPN	T2,.USREL
	HLRZ	T2,R		;IF THIS PAGE IS NON-CONTIGUOUS,
	LSH	T2,W2PLSH##
	CAILE	T1,1(T2)	; ICUPR WILL AOS UPMEM
	SOS	.USMEM		; SO DECREMENT IT IN ANTICIPATION
	JRST	TPOPJ##
;ROUTINE TO ZERO A PAGE
;ENTER WITH T1=VIRTUAL PAGE NUMBER
;EXIT T1=VIRTUAL PAGE NUMBER
ZERPAG::PUSHJ	P,GTPME		;GET MAP POINTER
ZPAGE:	HRLI	T2,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.CSH)
IFN FTMP&FTKL10,<
	PUSHJ	P,MLSCSH##	;IS FREEOR CACHED
	  TLZ	T2,(PM.CSH)	;MUST BE UNCACHED
>
	MOVEM	T2,.UPMP+.UMTMP
	CLRPGT	(0,.TEMP)	;CLEAR THE A.M. SO NEW MAPPING WILL BE USED
	MOVE	T2,[.TEMP,,.TEMP+1]
	SETZM	.TEMP		;CLEAR THE FIRST WORD OF THE PAGE
	BLT	T2,.TEMP+PG.BDY## ;ZERO THE PAGE
	MOVEI	T2,PAGSIZ##	;NUMBER OF WORDS ZEROED
	ADDM	T2,CLRWRD##	;UPDATE AMOUNT OF TIME SPENT ZEROING CORE
	POPJ	P,		;AND RETURN


;SUBROUTINE TO ADJUST VMTOTL AND VMCMAX WHEN A PAGE
; IS BEING REMOVED
;PRESERVES ALL ACS BUT T1

DCVMT::	SKIPL	T1,.USVRT	;IF HI SEG IS VIRTUAL,
	TRNE	T1,777000	;OR LOW SEG IS VIRTUAL
	SOSA	VMTOTL##	;ADJUST NUMBERS
	POPJ	P,		;JUST ACCESS ALLOWED - RETURN
	AOS	VMCMAX##	;INCR. VMCMAX
	POPJ	P,

;SUBROUTINE TO RETURN THE CURRENT VIRTUAL SIZE
; OF A JOB IN T4
;PRESERVES T3

VJSIZ:	PUSH	P,T3		;SAVE T3
	PUSH	P,J		;AND J
	MOVE	J,.USJOB	;CURRENT JOB'S JOB NUMBER
	PUSHJ	P,VMSIZE	;GET THE JOB'S VIRTUAL SIZE
	MOVE	T4,T1		;LOW SEGMENT VIRTUAL SIZE
	ADD	T4,T2		;ADD HIGH SEGMENT VIRTUAL SIZE
	POP	P,J		;RESTORE J
	JRST	T3POPJ##	;RESTORE T3 AND RETURN JOB'S VIRTUAL SIZE IN T4
;SUBROUTINE TO SEE IF PAGE UUO WILL CAUSE THE JOB TO BECOME TOO BIG
;ENTER  WITH T3 AS AMOUNT OF INCREASE
;EXIT CPOPJ IF TOO BIG, CPOPJ1 IF OK
;EITHER EXIT T1 = CURRENT VIRTUAL SIZE OF THE JOB
;PRESERVES T2-T4
SZCHK:	JUMPE	T3,CPOPJ1##	;RETURN IF NOT INCREASING NUMBER OF PAGES IN CORE
	PUSH	P,T4
	PUSHJ	P,GSIZD		;SEE IF IT WILL FIT
	SOS	-1(P)		;NO, ERROR
	  JFCL			;YES, HE CAN GROW TO MPPL
	MOVE	T1,T4		;CURRENT VIRTUAL SIZE
	POP	P,T4
	PJRST	CPOPJ1##	;SKIP RETURN

;SAME AS SZCHK, BUT ENTER WITH T3=INCREASE AND T4=# OF NON-EX SECT MAPS
;AND UP.BIG SET IN .USBTS IF USER ALREADY HAS SOME INDEPENDENT NZS
;SECTION (NORMAL CASE).

SZCHKX:	JUMPE	T4,SZCHK	;SAME AS SZCHK UNLESS EXTENDED
	PUSH	P,T3		;SAVE T3
	ADDI	T3,(T4)		;AMOUNT OF INCREASE INCLUDING MAPS
	.CREF	UP.BIG
	SKIPL	.USBTS		;IS HE ALREADY EXTENDED?
	AOS	T3		;INCLUDE .WSBNZ
	PUSHJ	P,SZCHK
	  JRST	T3POPJ##	;RETURN
	AOS	-1(P)
	JRST	T3POPJ##	;GOOD RETURN

;SUBROUTINE TO WAIT FOR I/O TO STOP
;PRESERVES T1-T4
IOWAT:	PUSHJ	P,SAVT##	;SAVE T1-T4
IFN FTMP,<
	PUSHJ	P,REMMM##	;REMEMBER STATE OF THE MM
>
	CAIE	T2,PA.PME+PA.PCE ;CREATING A PAGE?
	JRST	IOWAIT##	;NO, WAIT FOR I/O TO STOP
	JRST	INWAT1		;YES,,WAIT FOR INPUT TO STOP

;SUBROUTINE TO WAIT FOR INPUT TO STOP
;PRESERVES T1-T4
INWAT::	PUSHJ	P,SAVT##	;BE NICE AND SAVE T1-T4
INWAT1:	MOVEI	T1,WAITI	;WAIT FOR INPUT TO STOP
	JRST	IOALL##

;SUBROUTINE TO WAIT FOR INPUT TO STOP ON A DEVICE
WAITI:	TLNN	S,IO		;INPUT
	JRST	WAIT1##		;YES, WAIT UNTIL IT COMPLETES
	POPJ	P,		;NO, DON'T WAIT

;SUBROUTINE TO REMEMBER THE STATE OF THE MM RESOURCE AND CALL IOWAIT
IOWATM:
IFN FTMP,<
	PUSHJ	P,REMMM##	;REMEMBER THE STATE OF THE MM
>
	PJRST	IOWAIT##	;WAIT FOR I/O, MM WILL RESTORED ON EXIT
;SUBROUTINE TO CHECK IF ADDING A HIGH SEGMENT TO A JOBS ADDRESSING
; SPACE WOULD CAUSE IT TO BE TO BIG
;EXITS CPOPJ IF IT WON'T FIT AT ALL,
;EXITS CPOPJ1 IF PAGING OUT THE LOW SEGMENT WILL MAKE IT FIT,
;EXITS CPOPJ2 IF IT WILL FIT PHYSICALLY
;RESPECTS T2
GSZSG::	LDB	T1,IMGIN##	;SIZE OF THE HIGH SEGMENT
	ADDI	T1,UPMPSZ##+1	;PLUS SIZE OF THE UPMP + PAGE 0
	LSH	T1,P2WLSH##	;CONVERT TO WORDS
	PUSH	P,T2		;SAVE T2
	HRRZ	T2,.PDCVL##(W)	;CURRENT PHYSICAL LIMIT/GUIDELINE
	JUMPE	T2,GSZSG1	;JUMP IF THERE ISN'T ONE
	TRZN	T2,400000	;LIMIT?
	HRRZ	T2,.PDMVL##(W)	;NO, GUIDELINE - USE MAX PHYSICAL LIMIT
	JUMPE	T2,GSZSG1	;JUMP IF NONE
	LSH	T2,P2WLSH##	;CONVERT TO WORDS
	CAMG	T1,T2		;EXCEEDING LIMIT?
GSZSG1:	CAMLE	T1,CORMAX##	;OR BIGGER THAN CORMAX?
	PJRST	T2POPJ##	;YES, THEN IT WILL NEVER FIT
	PUSHJ	P,VJSIZ		;GET CURRENT VIRTUAL SIZE
	PUSHJ	P,SEGSIZ##	;AND SIZE OF NEW HISEG
	ADD	T4,T2		;COMPUTE NEW VIRTUAL SIZE
	HLRZ	T2,.PDCVL##(W)	;GET CURRENT VM LIMIT
	CAMGE	T2,T4		;WILL IT FIT?
	JUMPN	T2,T2POPJ##	;NO, ERROR TO EXCEED VM LIMIT
	SETZB	T2,T3		;IT WILL FIT PHYSICALLY, SEE IF MUST GO VIRTUAL
	PUSHJ	P,GSIZD		;CHECK LIMITS
	  JRST	[HRRZ T2,.PDMVL##(W) ;IGNORE WON'T FIT SINCE ALREADY CHECKED THAT
		 JUMPE T2,T2POPJ## ;WON'T FIT IF NOT MPPL
		 JRST .+1]	;OK
	  SKIPA	T4,T1		;T4 = VIRTUAL SIZE
	JRST	GSZSG4		;IT WILL FIT PHYSICALLY
	HLRZ	T2,.PDCVL##(W)	;GET CURRENT VM LIMIT
	JUMPE	T2,T2POPJ##	;DOESN'T FIT IF NO VIRTUAL AND TOO BIG FOR PHYSICAL
	MOVSI	T1,(UP.GET)	;GETTING GET?
	TDNE	T1,.USBTS	;IF SO, THATS OK
	JRST	GSZSG4		;SAY IT WILL FIT PHYSICALLY
	PUSH	P,J		;SAVE THE HIGH SEGMENT NUMBER
	MOVE	J,.CPJOB##	;JOB NUMBER
	LDB	T1,IMGIN##	;JOB'S CURRENT PHYSICAL SIZE
	LSH	T1,P2WLSH##	;CONVERT TO WORDS
	ADD	T4,T1		;COMPUTE NEW JOB SIZE
	MOVE	T2,JBTSTS##(J)	;JOB STATUS FOR THIS JOB
	TLNE	T2,JACCT	;IS IT A PRIVILEGED PROGRAM?
	JRST	GSZSG3		;YES, DON'T GO VIRTUAL
	TRNN	T2,JS.RUU	;GETSEG?
	PJRST	GSZSG2		;YES, DON'T CHECK FOR RUNNING A PRIV. PROG.
	MOVE	T1,.JDAT+SGANAM## ;NAME OF THE PROGRAM BEING RUN
	TLNE	F,SYSDEV	;BEING RUN FROM SYS?
	PUSHJ	P,PRVPG##	;YES, IS IT A PRIVILEDGED PROGRAM?
GSZSG2:	SOS	-2(P)		;NO, ONLY FITS IF VIRTUAL
GSZSG3:	POP	P,J		;RESTORE HIGH SEGMENT NUMBER
GSZSG4:	POP	P,T2		;AND PRESERVED AC
	JRST	CPOPJ2##	;GIVE SINGLE OR DOUBLE SKIP RETURN
;SUBROUTINE TO TEST VARIOUS CORE LIMITS, ENTER GSIZI WITH T3=# PAGES OF INCREASE
;ENTER GSIZD WITH T3-T2=# PAGES OF INCREASE, EXIT CPOPJ IF WILL NEVER FIT PHYSICALLY
;EXIT CPOPJ1 IF .GT. CPPL, .LE. MPPL, EXIT CPOPJ2 IF .LE. CPPL
;RETURNS T1=NEW HIGHEST ADR, T4=NEW JOB SIZE, RESPECTS T2-T3
GSIZT::	PUSH	P,T1		;SAVE T1
	PUSH	P,T3		;AND T3
	MOVE	T3,T4		;SET ARGUMENT FOR GSIZI
	PUSHJ	P,GSIZI		;SEE IF IT WILL FIT
	  SOS	-2(P)		;NOT AT ALL
	  CAIA			;ONLY VIRTUALLY
	AOS	-2(P)		;PHYSICALLY
	POP	P,T3		;RESTORE PRESERVED AC
	PJRST	TPOPJ1##	;RESTORE T1 AND RETURN
GSIZI::	PUSH	P,T2		;SAVE T2
	TDZA	T2,T2		;NO PAGES OF DECREASE
GSIZD::	PUSH	P,T2		;PRESERVE T2
	PUSH	P,T2		;PUT ARGUMENT ON THE STACK
	PUSHJ	P,VJSIZ		;GET THE JOBS CURRENT VIRTUAL SIZE
	PUSHJ	P,SEGSIZ##	;PHYSICAL SIZE OF THE SEGMENT
	CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	SUBI	T2,UPMPSZ##	;NO, SUBTRACT OUT THE UPMP SIZE
	SUB	T2,(P)		;SUBTRACT OUT THE NUMBER OF PAGES OF DECREASE
	POP	P,(P)		;POP OFF JUNK
	ADD	T2,T3		;NEW PHYSICAL SIZE OF THE SEGMENT
	LSH	T2,P2WLSH##	;CONVERT TO WORDS
	SOS	T1,T2		;HIGHEST ADDRESS REQUESTED IN T1
	PUSH	P,P1		;SAVE P1
	MOVSI	P1,PHONLY	;ASK IF IT WILL FIT PHYSICALLY
	PUSHJ	P,SUMSEG##	;WILL BOTH SEGMENTS PLUS THE INCREASE FIT?
	  SKIPA	P1,.PDCVL##(W)	;NO, GET THE CURRENT PHYSICAL LIMIT/GUIDELINE
	AOJA	T2,[HRRZ P1,.PDCVL##(W)
		    JUMPE P1,GSIZ2
		    LSH T2,W2PLSH##
		    CAIGE T2,(P1)
		    JRST GSIZ2	;NOT EXCEEDING GUIDELINE
		    LSH T2,P2WLSH##
		    SOJA T2,.+1];EXCEEDING GUIDELINE, SEE IF IT WILL FIT ANYWAY
	ADDI	T2,UPMSZW##	;ACCOUNT FOR THE UPMP
	TLO	P1,PHONLY	;GET PHYSICAL LIMIT
	EXCH	J,.USJOB
	LDB	T1,NZSSCN##	;# OF MAPS
	.CREF	UP.BIG
	SKIPL	.USBTS
	AOS	T1
	LSH	T1,P2WLSH##	;WORDS
	ADDI	T2,(T1)
	PUSHJ	P,CORBND##	; ..
	EXCH	J,.USJOB
	CAMG	T2,T1		;GETTING TO BIG PHYSICALLY?
	TRNE	P1,400000	;NO, GUIDELINE OR LIMIT?
	JRST	GSIZ1		;LIMIT, CAN'T HELP HIM
	MOVE	P1,.PDMVL##(W)	;GET THE MAXIMUM PHYSICAL LIMIT
	LSH	T2,W2PLSH##	;CONVERT TO WORDS
	TRNE	P1,-1		;WAS MPPL SET?
	CAILE	T2,-1(P1)	;YES, TRYING TO EXCEED THAT?
GSIZ1:	SOS	-2(P)		;YES, WON'T FIT
	JRST	GSIZ3		;RESTORE ACS AND NON-SKIP RETURN
GSIZ2:	AOS	-2(P)		;HERE IF CAN FIT PHYSICALLY
GSIZ3:	POP	P,P1		;RESTORE P1
	PJRST	T2POJ1##	;RESTORE T2 AND RETURN
;SUBROUTINE TO GET THE MAP ENTRY FOR THE VIRTUAL PAGE SPECIFIED BY
; THE CONTENTS OF T1
;CALLING SEQUENCE:
;
;	MOVE	T1,VIRTUAL PAGE NUMBER
;	PUSHJ	P,GTMPE
;RETURN CPOPJ,  T2 = CONTENTS OF THE MAP, T4= MAP SLOT POINTR
;T1,T3 PRESERVED

GTPME::	HRRZ	T4,T1		;ARGUMENT TO GMPTR
	PUSHJ	P,GMPTR		;GET A BYTE POINTER TO THE MAP SLOT
	MOVE	T2,(T4)		;CONTENTS OF THE SLOT
	POPJ	P,		;RETURN

;SUBROUTINE TO GET THE MAP ENTRY FOR A PAGE
;ENTER T4=VIRTUAL PAGE NUMBER
;EXIT T4=CONTENTS OF MAP SLOT
;T1-T3 PRESERVED
GTPM4::	PUSHJ	P,GMPTR		;GET POINTER TO MAP SLOT
	MOVE	T4,(T4)		;GET MAP CONTENTS
	POPJ	P,		;AND RETURN

;SUBROUTINE TO SEE IF THE VIRTUAL PAGE NUMBER SPECIFIED BY THE CONTENTS OF
; T1 IS A LEGAL VIRTUAL PAGE NUMBER
;PRESERVES T1

LGLPG::	TLNE	T1,377777	;EXTRA BITS ON IN LH
	JRST	ILPERR		;YES, ILLEGAL PAGE NUMBER
LGLPR:	HRRZ	T2,T1		;PAGE NUMBER (HIGH ORDER BIT MAY BE ON IN T1)
	JUMPE	T2,ILPERR	;REAL PAGE 0 IS ILLEGAL
	CAILE	T2,HLGPGS	;LESS THAN HIGHEST LEGAL PAGE NUMBER?
	JRST	ILPERR		;ILLEGAL PAGE
	TRNN	T2,HLGPNO	;COULD IT BE PAGE 0 IN ANOTHER FORM?
	PUSHJ	P,ISITS0	;MAYBE, IS REALLY IN S0?
	  AOS	(P)		;NOT IN S0 OR NOT P0
	POPJ	P,		;P0
;SUBROUTINE TO TEST TO SEE IF THE VIRTUAL PAGE SPECIFIED BY THE CONTENTS
; OF T1 IS IN THE WORKING SET, I.E., IN CORE, RETURNS CPOPJ IF NOT, CPOPJ1
; IF SO, T2 = MASK TO SET OR CLEAR THE BIT, T4 IS THE INDEX INTO THE
; WORKING SET BIT TABLE
;PRESERVES T1,T3

TSWST::	PUSH	P,T1
TSWST1:	HRRZS	T1		;CLEAR JUNK
	MOVEI	T4,MXSECN_S2PLSH## ;GET SECTION # SPECIFIED
	ANDI	T4,(T1)
	LSH	T4,P2SLSH##	;MAKE IT A SECTION INDEX
	CAILE	T1,HLGPGS	;FUNNY SPACE?
	TDZA	T4,T4		;YES, S0
	TRZA	T1,-1^!HLGPNO	;CLEAR SECTION #
	MOVEI	T1,HLGPNO+1-<.MCFV/PAGSIZ##>(T1)
	PUSHJ	P,RSECT4	;GET REAL SECTION # IN T4
	SKIPA	T4,[WSBTAB-.WSBNZ+WSBTBL]
	IMULI	T4,WSBTBL
	ADDI	T4,.WSBNZ-WSBTBL
	IDIVI	T1,^D36		;WORD NUMBER IN T1, BIT POSITION IN T2
	MOVE	T2,BITTBL##(T2)	;GET POSITIONED BIT FROM BIT NUMBER
	.CREF	UP.BIG
	CAIG	T4,.UPMP	;IS IT IN THE S0 WSBTAB (WHICH ALWAYS EXISTS)
	SKIPGE	.USBTS		;NO, DOES NZS WSBTAB EXIST (UP.BIG)
	TLOA	T4,400000+T1	;IFIW (WSBTAB EXISTS)
	TLOA	T4,400000+T1	;IFIW (.WSBNZ DOESN'T)
	TDNN	T2,@T4		;IS THE BIT ON IN WSBTAB (PAGE IN CORE)?
	SOS	-1(P)		;NO, NON-SKIP RETURN
	MOVEI	T4,@T4		;RETURN WORD NUMBER IN T4
	PJRST	TPOPJ1##	;RESTORE VIRTUAL PAGE NUMBER AND RETURN

;ROUTINE TO GET THE "REAL" (I.E. INDEPENDENT) SECTION # IN T4.
;RETURNS CPOPJ1 WITH "REAL" SECTION NUMBER IN T4, OR CPOPJ WITH T4 CLEARED
;IF REAL SECTION IN SECTION 0.  STARTS WITH C(T4) AND IS ASSUMED TO BE
;ZERO IF IT IS 0 OR NEGATIVE.  USES T2.

RSECT4::SKIPG	T4		;NO, SEE IF IT IS
	TDZA	T4,T4		;WANTS SECTION 0
	SKIPN	T2,.UPMP+SECTAB(T4) ;GET SECTION POINTER
	POPJ	P,		;RETURN SAYING S0 OR NON-EX SCN
	TLNN	T2,(<PM.ACD^!PM.DCD>B2) ;IS THIS AN INDEPENDENT SECTION?
	JRST	CPOPJ1##	;YES
	LDB	T4,[POINT 5,T2,17] ;NOTE THAT 540 AND 37 DON'T
				;OVERLAP ANY NON-ZERO BITS
	JUMPN	T4,RSECT4	;AND CHECK IT OUT
	POPJ	P,		;UNLESS IT'S S0
;SUBROUTINE TO GET BIT, INDEX FOR WSBTAB
;ENTER AND EXIT WITH ACS LIKE TSWST
;RETURNS NON-SKIP IF PAGE ISNT IN WORKING SET, HALTS IF IT IS
;PRESERVES T1,T3
WSBIT:	PUSHJ	P,TSWST		;IS THE PAGE IN THE WORKING SET?
	  POPJ	P,		;NO, RETURN
	STOPCD	CPOPJ##,DEBUG,PIN,	;++PAGE IN WORKING SET

;SUBROUTINE TO TEST IF BIT ON IN AABTAB
;ENTER WITH T4=MAP POINTER (CORRECT .UPMAP ASSUMED!)
;ENTER AT TSAATC WITH MAP CONTENTS ALREADY IN T4
;EXIT CPOPJ1 IF BIT IS ON, CPOPJ OTHERWISE
;PRESERVES ALL ACS
TSAAT:	PUSH	P,T4		;SAVE BIT
	MOVE	T4,(T4)		;GET MAP CONTENTS
	TLNE	T4,(PM.AAB)	;ACCESS ALLOWED?
	AOS	-1(P)		;YES, SKIP RETURN
	PJRST	T4POPJ##	;RESTORE T1 AND RETURN

;SUBROUTINE TO SEE IF PAGE SPECIFIED BY T1 IS A SPY PAGE.  ENTER WITH PAGE #
;IN T1 (PRESERVED).  EXIT WITH MAP CONTENTS IN T2 AND BYTE POINTER IN T4.
;ASSUMES CORRECT MAP IN .UPMAP.  EXIT CPOPJ1 IF THIS IS A SPY PAGE, CPOPJ
;OTHERWISE

IFN FTPEEKSPY,<
TSSPT::	SE1ENT
	PUSHJ	P,GTPME		;GET CONTENTS
	TLNE	T2,(PM.SPY)	;SPY PAGE?
	AOS	(P)
	POPJ	P,
>

;SUBROUTINE TO TEST TO SEE IF USER IS IN HIS PAGE FAULT HANDLER
;CALL WITH:
;	T2 = PC
;	PUSHJ	P,INPFH
;	  RETURN HERE IF IN PFH
;	RETURN HERE IF NOT
;
; RESPECTS ALL AC'S EXCEPT T3
;
INPFH::	HRRZ	T3,.JDAT+.JBPFH## ;GET START OF PFH
	SKIPE	.JDAT+.JBPFH##	;ANY PAGE FAULT HANDLER AT ALL
	CAILE	T3,(T2)		;ABOVE START?
	JRST	CPOPJ1##	;NO--NOT IN PFH
	HLRZ	T3,.JDAT+.JBPFH## ;GET END OF PFH
	CAIGE	T3,(T2)		;ABOVE END?
	JRST	CPOPJ1##	;YES--NOT IN PFH
	POPJ	P,0		;IN PFH
;SUBROUTINE TO DESTROY PAGES.  ENTER WITH VIRTUAL PAGE NUMBER OF PAGE
; TO BE DELETED IN T1, PAGE MUST EXIST
; GET PHYSICAL PAGE NUMBER, ZERO MAP ENTRY, FIND PHYSICAL PAGE NUMBER
; IN PAGTAB, LINK PAGTAB AROUND IT, UPDATE CORTAL, BIGHOL

DLTPAG:	PUSHJ	P,DLTSP		;DELETE SPY PAGE?
	  POPJ	P,		;YES
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN THE MM?
	  PUSHJ	P,MMDIE##	;NO, STOP
>
	PUSHJ	P,RMVPAG	;REMOVE THE PAGE FROM THE MAP
	  JRST	DLTPGE		;GIVE BACK THE SWAPPING SPACE

;HERE WITH T2=PAGE TO BE GIVEN BACK
DLTPGC::SE1ENT			;MUST BE IN SECTION 1 TO ADDRESS PAGTAB
	HRRZ	T1,T2
	SSX	T2,MS.MEM
	SETZM	PAGTAB(T2)	;ONLY ONE PAGE TO RETURN (CLEAR BITS AS WELL)
	HLLZS	PT2TAB(T2)	;SO GVPAGS DOESN'T GET CONFUSED
	AOS	VIRTAL##	;AND THE AMOUNT OF SWAPPING SPACE AVAILABLE
	PJRST	GVPAGS##	;RETURN THE PAGE

;HERE IF MAPPED PAGE IS ON DISK
DLTPGE:	JUMPE	T2,CPOPJ##	;GO IF PAGE WAS ON THE OUT QUEUE
	MOVSI	T1,(UP.CTX)	;IF THIS IS FOR A JOB DOING A PUSH,
	TDNE	T1,.USBTS	; (TEST)
	POPJ	P,		;YES, DON'T GIVE AWAY HIS VIRTUAL PAGES (OR BAC)
	;NO, FALL INTO DLTPGD

;HERE IF PAGE IS ON DISK
DLTPGD::AOS	VIRTAL##	;INCREMENT THE AMOUNT OF SWAPPING SPACE AVAILABLE
	TLZ	T2,(PM.NAD)
	CAMN	T2,[PM.ZER]
	POPJ	P,		;YES, ALL DONE
DLTDSP:	MOVE	T1,T2		;ARGUMENT TO FXSAT
	MOVEI	U,1		;NUMBER OF PAGES TO RETURN
	PJRST	FXSAT1##	;GIVE BACK THE SWAPPING SPACE
;SUBROUTINE TO REMOVE PAGE FROM JOBS ADDRESSING SPACE
;ENTER T1= VIRTUAL PAGE TO BE REMOVED
;EXIT CPOPJ, T2=DSK ADDRESS IF PAGE ON DSK
; OR EXIT CPOPJ1, T2= PHYSICAL PAGE NUMBER IF PAGE IN CORE
;IF CALLED AT RMVPGI AND PAGE WAS ON A QUEUE, T2 WILL IN CLUDE OIQ!SSP
;(IF IN QUEUES) OR T3 WILL CONTAIN QUEUE HEADER AND T4 PHYS PAGE (OUT OR IP)

RMVPGI:	PUSHJ	P,SAVE1##	;SAVE P1
	JSP	P1,RMVPG0	;SET NON-ZERO AS A FLAG
RMVPAG:	PUSHJ	P,SAVE1##	;SAVE P1
	SETZ	P1,		;SET FLAG
RMVPG0:	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE MAP SLOT
	SETZM	(T4)		;ZERO THE MAP SLOT SINCE PAGE NO LONGER EXISTS
	PUSH	P,T2		;SAVE THE PREVIOUS MAP CONTENTS
	PUSHJ	P,DCUPR		;DECREMENT UPREL
	MOVE	T3,(P)		;GET PREVIOUS MAP-SLOT CONTENTS
	TLNN	T3,(PM.AAB)	;ACCESS ALLOWED ON?
	TDNN	T3,[PM.ADR^!PM.ZER]
	JRST	RMVPG1
	TLNN	T3,(PM.AAB)
	SOS	.USANA		;YES, DECR COUNT
RMVPG1:	LDB	T2,[POINT PM.SAD,T3,<^L<PM.ADR>+PM.SAD-1>]
	TLNE	T3,(PM.OIQ)	;PAGE ON THE "IN" QUEUE?
	JRST	RMVPG5		;YES
	MOVEM	T2,(P)		;NO, JUST RETURN DSK ADDR/PAGE #
	TLNN	T3,(PM.COR)	;IF PAGE IS IN CORE, IT ISN'T ON A QUEUE
	PUSHJ	P,ONPOQ		;PAGE ON "IP" OR "OUT" QUEUE?
	  JRST	RMVPG2		;NO, JUST A GARDEN VARIETY PAGE
	JUMPN	P1,T2POPJ##	;DON'T CHANGE QUEUE IF CALLED FROM IPCRMV
	SSX	T4,MS.MEM	;MEMTAB SECTION
	CAIE	T3,PAGIPQ##	;ON THE IN PROGRESS QUEUE?
	JRST	[MOVSI	T3,(UP.CTX)	;JOB DOING A PUSH?
		 TDNN	T3,.UPBTS	;IF NOT,
		 SETZM MEMTAB(T4) ;DON'T BOTHER TO PUT PHYSICAL PAGE ON
		 JRST T2POPJ##]	; FREE CORE LIST, BUT DON'T FIND IN "OUT" QUEUE
	MOVSI	T2,(MT.GPB)	;GIVE BACK DISK SPACE WHEN I/O COMPLETES
	MOVSI	T3,(UP.CTX)	;JOB DOING A PUSH?
	TDNN	T3,.UPBTS	;IF SO,
	IORM	T2,MEMTAB(T4)
	SETZM	(P)		;INDICATE NO PAGE TO GIVE BACK
	JRST	T2POPJ##	;AND GIVE PAGE ON DISK RETURN
RMVPG2:	SETZ	T3,		;SO IPCSER KNOWS IT'S NOT ON A QUEUE
	PUSHJ	P,TSWST		;WAS THE PAGE IN THE WORKING SET?
	  TLOA	T3,400000	;NO, REMEMBER THAT
	.CREF	IMGIN
	SOS	JBTIMI##(J)	;YES, DECREMENT THE COUNT OF THE NUMBER OF
				; PAGES IN CORE
	ANDCAM	T2,(T4)		;CLEAR THE BIT IN THE WORKING SET TABLE
	POP	P,T2
	TLZE	T3,400000	;PAGE ON DISK?
	POPJ	P,		;YES, NON-SKIP RETURN
	SE1ENT			;GET TO SECTION 1
	SKIPE	T1		;DON'T LINK PAST PAGE ZERO
	PUSHJ	P,LKPSF		;LINK PAST THE PAGE IN PAGTAB
	PUSH	P,T2		;SAVE THE PHYSICAL PAGE NUMBER
	SSX	T2,MS.MEM	;PAGTAB SECTION
	HLLZS	PAGTAB(T2)	;INDICATE LAST PAGE ALLOCATED
RMVPG3:	PUSHJ	P,DECHJ		;DECREMENT THE NUMBER OF HIGH SEGMENT PAGES
				; IN CORE IF THIS IS A HIGH SEGMENT PAGE
RMVPG4:	MOVEI	T2,777		;IF REMOVED ALL NON-ACCESSABLE PAGES,
	SKIPE	.USANA
	PJRST	T2POJ1##	;DONE
	ANDCAM	T2,.USVRT	; CLEAR THAT PORTION OF .UPVRT
	PJRST	T2POJ1##	;RESTORE T2 AND GIVE PAGE-IN-CORE RETURN

RMVPG5:	JUMPN	P1,RMVPG4	;RETURN WITH BITS NOW IF FROM IPCRMV
	MOVEM	T2,(P)		;NOT AFTER THIS IT'S NOT
	TLNE	T3,(PM.SSP)
	SKIPA	T3,[PAGSNQ##]
	MOVEI	T3,PAGINQ##
	PUSHJ	P,RMVPFQ	;REMOVE IT FROM THE "IN" QUEUE
	JRST	RMVPG4		;FIX COUNTS AND RETURN
;SUBROUTINE TO REMOVE A PAGE FROM A QUEUE
;CALL:
;	MOVE	T2,PHYSICAL PAGE NUMBER
;	MOVEI	T3,ADDRESS OF QUEUE HEADER
;	PUSHJ	P,RMVPFQ	;REMOVE THE PAGE FROM THE QUEUE
;	ALWAYS RETURN HERE
;STOPCDS IF PAGE ISN'T ON THE QUEUE

RMVPFQ:	SE1ENT			;ENTER SECTION 1
	SOSL	1(T3)		;DECREMENT COUNT OF PAGES ON QUEUE
	SKIPN	T4,(T3)		;ANY PAGES ON THE QUEUE
	STOPCD	CPOPJ##,DEBUG,PQW, ;++PAGE QUEUE WRONG
	CAME	T2,T4		;FIRST ELEMENT IN THE QUEUE?
	JRST	LKPSF		;NO, JUST LINK AROUND THE PAGE
	SSX	T4,MS.MEM	;PAGTAB SECTION
	MOVE	T4,PAGTAB(T4)	;SUCCESSOR TO PAGE BEING REMOVED
	MOVEM	T4,(T3)		;STORE AS NEW FIRST ELEMENT IN QUEUE
	SSX	T4,MS.MEM	;SECTION AGAIN
	HLLZS	PT2TAB(T4)
	HLLZS	@[IW MS.MEM,PAGTAB(T2)] ;CLEAR LINK IN THIS PAGE
	HLLZS	@[IW MS.MEM,PT2TAB(T2)] ;AND BACK LINK
	POPJ	P,		;AND RETURN

;SUBROUTINE TO ADD A PAGE TO A QUEUE
;CALL:
;	MOVE	T1,PHYSICAL PAGE NUMBER
;	MOVEI	T3,ADDRESS OF QUEUE HEADER
;	PUSHJ	P,ADDPTQ	;ADD THE PAGE TO THE QUEUE
;	ALWAYS RETURN HERE

ADDPTQ:	EXCH	T1,(T3)		;NEW FIRST PAGE ON THE QUEUE, GET OLD FIRST
	AOS	1(T3)		;ONE MORE PAGE ON THE QUEUE
	MOVE	T3,(T3)		;PREVIOUS FIRST PAGE
	SSX	T3,MS.MEM	;PAGTAB SECTION
	MOVEM	T1,PAGTAB(T3)	;LINK IT INTO CHAIN
	HLLZS	PT2TAB(T3)	;WE HAVE NO PREVIOUS
	SSX	T1,MS.MEM	;PAGTAB SECTION
	TRNE	T1,-1		;IF NOT LAST,
	HRRM	T3,PT2TAB(T1)	;SET BACK LINK
	POPJ	P,		;RETURN
;SUBROUTINE TO LINK PAGTAB AROUND THE PAGE SPECIFIED BY THE CONTENTS OF T2
;CALLING SEQUENCE:
;	MOVE	T2,PAGE TO BE LINKED PAST
;	PUSHJ	P,LKPSP
;RETURNS CPOPJ, T3 = PREDECESSOR TO PAGE LINKED AROUND
;PRESERVES T1

REPEAT 0,<

LKPSP::	LDB	T4,JBYLSA##	;FIRST PAGE OF THE LOW SEGMENT
	SE1ENT			;SETION 1 TO ADDRESS PAGTAB
LNKPS1:	MOVE	T3,T4		;SAVE PREVIOUS PAGE IN T3
	SSX	T3,MS.MEM	;PAGTAB SECTION
	SKIPG	T4,PAGTAB(T3)	;NEXT PAGE OF THE SEGMENT
	STOPCD	.+1,DEBUG,FIP,	;++FREE-PAGE IN USE
	CAIE	T2,(T4)		;IS THIS THE PAGE TO BE LINKED AROUND?
	JRST	LNKPS1		;NO, TRY THE NEXT PAGE
	SSX	T4,MS.MEM	;PAGTAB SECTION
	SKIPGE	T4,PAGTAB(T4)	;GET THE NEXT PAGE
	STOPCD	CPOPJ##,DEBUG,PIF,	;++PAGE IS FREE
	MOVEM	T4,PAGTAB(T3)	;LINK AROUND THE PAGE
	HRRZS	T3		;CLEAR SECTION NUMBER
	HLLZS	@[IW MS.MEM,PAGTAB(T2)] ;CLEAR LINK IN THIS PAGE
	HLLZS	@[IW MS.MEM,PT2TAB(T2)]
	TRNN	T4,-1		;ANY NEXT PAGE?
	POPJ	P,		;NO
	SSX	T4,MS.MEM	;SECTION AGAIN
	HRRZM	T3,PT2TAB(T4)	;BACK LINK
	POPJ	P,		;AND RETURN
>				;END REPEAT 0
LKPSF::	SE1ENT			;SECTION 1
	HRRZ	T4,T2		;PAGE TO BE LINKED PAST
	SSX	T4,MS.MEM	;SECTION # FOR MEMTAB
	HRRZ	T3,PT2TAB(T4)
	SSX	T3,MS.MEM	;FOR IT TOO
	SKIPGE	T4,PAGTAB(T4)	;NEXT
	STOPCD	CPOPJ##,DEBUG,PIF,	;++PAGE IS FREE
	MOVEM	T4,PAGTAB(T3)	;LINK FORWARD
	HRRZS	T3
	HLLZS	@[IW MS.MEM,PAGTAB(T2)] ;CLEAR LINK IN THIS PAGE
	HLLZS	@[IW MS.MEM,PT2TAB(T2)]
	TRNN	T4,-1		;ANY NEXT PAGE?
	POPJ	P,		;NO, NOTHING MORE TO DO
	SSX	T4,MS.MEM
	HRRM	T3,PT2TAB(T4)
	POPJ	P,
;SUBROUTINE TO MOVE PAGES FROM THE "OUT" QUEUE CHAIN TO THE FREE CORE CHAIN
;CALLING SEQUENCE:
;	MOVE	T3,AMOUNT NEEDED
;	PUSHJ	P,FRPCR
;	  RETURNS HERE IF NOT ENOUGH CAN BE MADE AVAILABLE
;	RETURNS HERE - HAVE BEEN MADE AVAILABLE, BIGHOL WILL SATISFY REQUEST
;PRESERVES ALL ACS

FLSOPQ::SE1ENT			;ENTER SECTION 1
	SOS	(P)		;UNDO SKIP RETURN
	JRST	FRPCR1		;PUT ALL PAGES ON THE "OUT" QUEUE ON FREE CORE LIST

FRPCR::	PUSHJ	P,SAVT##	;THE SWAPPER IS PARTICULAR ABOUT ACS
	SUB	T3,BIGHOL##	;NUMBER OF PAGES THAT WEREN'T AVAILABLE
	CAMLE	T3,PAGOUC##	;THAT MANY AVAILABLE ON THE "OUT" QUEUE?
	JRST	[MOVE T3,-3(P)	;MAY STILL BE ABLE TO MAKE CORE AVAILABLE
		 SUB T3,CORTAL##; BY DELETING DORMANT SEGMENTS
		 CAMLE T3,PAGOUQ## ;CAN BE DONE?
		 POPJ P,	;NO, HAVE TO SWAP TO MAKE CORE AVAILABLE
		 SOS (P)	;YES, CORE IS AVAILABLE IF DORMANT SEGMENTS
		 SE1ENT		; ARE DELETED AND THE QUEUE IS FLUSHED - NON-SKIP
		 JRST FRPCR1]	; RETURN TO SEGCON SO IT WILL DELETE DORMANT SEGMENTS
	SE1ENT			;MUST BE IN SECTION 1 TO FOLLOW PAGTAB
	MOVE	T2,PAGOUC##	;NUMBER OF PAGES ON "OUT" QUEUE
	MOVNS	T3		;MINUS NUMBER OF PAGES NEEDED FROM THE QUEUE
	ADD	T2,T3		;NUMBER OF PAGES TO SKIP AT THE BEGINING OF THE QUEUE
	ADDB	T3,PAGOUC##	;DECREASE NUMBER OF PAGES ON QUEUE BY THAT AMOUNT
	JUMPN	T3,FRPCR2	;GO IF QUEUE ISN'T EMPTY
FRPCR1:	SETZB	T1,PAGOUC##	;ZERO COUNT (CONVENIENT FOR FLSOPQ)
	EXCH	T1,PAGOUQ##	;FIRST PAGE ON QUEUE, QUEUE IS NOW EMPTY
	JUMPE	T1,CPOPJ1##	;EXIT IF EMPTY (FLSOPQ)
	JRST	FRPCR3		;RETURN ALL OF THE PAGES TO THE FREE CORE LIST
FRPCR2:	SOS	T2		;FIND THE PREDECESSOR
	MOVE	T3,PAGOUQ##	;FIRST PAGE ON THE "OUT" QUEUE
	PUSHJ	P,SNPAG1##	;SKIP THAT NUMBER OF PAGES
	SSX	T1,MS.MEM	;PAGTAB SECTION
	HLLZS	PAGTAB(T1)	;NEW END OF QUEUE
	MOVE	T1,T3		;PAGE TO START GIVING BACK AT
FRPCR3:	PUSHJ	P,GVPAGS##	;RETURN THE PAGES TO THE FREE CORE LIST
	JRST	CPOPJ1##	;AND GIVE SUCCESS RETURN
;SUBROUTINE TO TEST IF THE PAGE SPECIFIED BY THE CONTENTS OF T1
; IS CONTAINED IN A SHARABLE HIGH SEGMENT OR A SPY SEGMENT
;CALLING SEQUENCE:
;	MOVE	T1,PAGE NUMBER TO BE TESTED
;	MOVE	J,JOB NUMBER
;	PUSHJ	P,TPSHS
;RETURNS CPOPJ IF THE PAGE IS CONTAINED IN A SHARABLE HIGH SEGMENT
; OR A SPY SEGMENT, CPOPJ1 IF NOT
;PRESERVES T1,T3

TPWHS:	SKIPLE	T2,JBTSGN##(J)	;DOES THIS JOB HAVE A REAL HIGH SEGMENT?
	TLNN	T2,UWPOFF	;IS WRITE PROTECT OFF FOR THE HIGH SEGMENT?
	JRST	CPOPJ1##	;NO, PAGE ISN'T IN A WRITABLE HIGH SEGMENT
IFN FTPEEKSPY,<
	PUSHJ	P,TSSPT		;A SPY PAGE?
	  JRST	TPAHS		;NO
	JRST	CPOPJ1##
>
IFE FTPEEKSPY,<
	JRST	TPAHS		;TEST TO SEE IF THE PAGE IS IN THE HIGH SEGMENT
>
TPSHS::	MOVE	T2,JBTSGN##(J)	;HIGH SEGMENT NUMBER PLUS HIGH SEGMENT BITS
	TLNN	T2,SHRSEG!SPYSEG;SHARABLE SEGMENT OR SPY SEGMENT?
	JRST	CPOPJ1##	;NO, PAGE IS NOT IN A SPY OR SHR SEG
TPAHS::	PUSH	P,T1		;SAVE THE VIRTUAL PAGE NUMBER
	PUSHJ	P,HSVAD##	;GET STARTING AND ENDING VIRTUAL ADDRESSES
				; OF THE HIGH SEGMENT
	HRRZS	J		;CLEAR JUNK
	LSHC	T1,W2PLSH##	;CONVERT TO STARTING AND ENDING PAGE NUMBERS
	HRRZ	T4,(P)		;VIRTUAL PAGE IN QUESTION
	CAIL	T4,(T2)		;BELOW THE START OF THE HIGH SEGMENT?
	CAILE	T4,(T1)		;OR ABOVE THE TOP OF THE HIGH SEGMENT
	AOS	-1(P)		;PAGE ISN'T IN THE HIGH SEGMENT
	PJRST	TPOPJ##		;RESTORE THE VIRTUAL PAGE NUMBER AND RETURN

;SUBROUTINE TO CHECK SECTION # AGAINST JBYSG2 AS WELL AS THE
;CHECKS TPAHS/TPSHS DOES.  SAME RETURNS AS TPAHS

TPNSHS::
	PUSHJ	P,SAVT##
	MOVEI	T3,TPSHS
	JRST	TPNHS1
TPNHS::	PUSHJ	P,SAVT##
	MOVEI	T3,TPAHS
TPNHS1:	LDB	T4,[POINT 5,T1,26]
	PUSHJ	P,RSECT4	;RESOLVE SECTION # TO INDEPENDENT SECTION
	  JFCL			;IGNORE POSSIBLE SKIP RETURN
	LDB	T2,JBYSG2##	;GET HI SEG SECTION #
	CAIE	T2,(T4)		;THIS SECTION #
	  JRST	CPOPJ1##	;NO, NOT IN HIGH SEG
	ANDI	T1,HLGPNO	;CLEAR SECTION #
	PJRST	(T3)		;AND CHECK

;SUBROUTINE TO INCREMENT OR DECREMENT JBTSWP FOR A HI SEG
;PRESERVES T1
INCHJ::	SKIPA	T3,[1,,0]	;PREPARE TO INCREMENT NUMBER OF HIGH SEGMENT
				; PAGES IN CORE
DECHJ:	MOVSI	T3,-1		;DECREMENT NUMBER OF HIGH SEGMENT PAGES IN CORE
	PUSHJ	P,TPNHS		;IS THIS PAGE IN THE HIGH SEGMENT?
INCHJA:   SKIPG	JBTSGN##(J)	;YES, IS THERE A HIGH SEGMENT?
	POPJ	P,		;NO, NOTHING TO DO
	MOVSI	T4,(UP.CTX)	;GET CONTEXT SERVICE BIT
	TDNE	T4,.USBTS	;DELETING A HISEG FOR CTXSER?
	POPJ	P,		;YES, DON'T TOUCH THE PAGE COUNT
	HRRZ	T4,JBTSGN##(J)	;NO, GET HIGH SEGMENT NUMBER
	ADDM	T3,JBTSWP##(T4)	;INCREMENT OR DECREMENT PAGE COUNT
	JUMPL	T3,CPOPJ##	;RETURN IF REMOVING A PAGE FROM CORE
	PUSH	P,T1
	PUSH	P,T4
	PUSHJ	P,SCWEXO##
	POP	P,T4
	POP	P,T1
	LDB	T4,[POINT 9,JBTUPM##(T4),8] ;FIRST VIRTUAL PAGE IN THE HI-SEG
MAPHI::	LDB	T3,JBYSG2##	;SECTION OF HIGH SEG
	LSH	T3,S2PLSH##	;CONVERT TO SECTION
	IORI	T4,(T3)
	PUSHJ	P,GTPM4		;YES, GET FIRST PHYSICAL PAGE IN HI SEG
	HRLI	T4,(<PM.DCD>B2+PM.WRT+PM.PUB)
	MOVEM	T4,.UPMP+.UMVJD
	POPJ	P,		;AND RETURN

;SUBROUTINE TO SET UP JBTHSA FOR NON-SHARABLE HI SEG CASES
;IN CASE IT CHANGED (PARTICULARY FOR LOKCON, BUT SO THE INFORMATION
;WILL BE CORRECT ANYWAY). PRESERVES ALL ACS, IF A NON-SHARABLE HI SEG UPDATES
;JBTHSA ACCORDING TO CURRENTLY MAPPED UPMP
SETHSA:	PUSHJ	P,SAVT##	;SAVE TEMP AC'S
	SE1ENT
	PUSH	P,J		;AND J
	MOVE	J,.USJOB	;GET JOB NUMBER
 	MOVEI	T1,JS.RUU	;IN RUN UUO?
	MOVSI	T2,(JS.IGS)	;OR GETSEG UUO?
	TDNN	T1,JBTSTS##(J)	;IF SO, .UPHSS IS NOT
	TDNE	T2,JBTST2##(J)	;RELIABLE
	JRST	JPOPJ##		;SO DON'T TRUST IT
	SKIPLE	J,JBTSGN##(J)	;DOES JOB HAVE A REAL
	TLNE	J,SHRSEG	;NON-SHARABLE HI SEG
	JRST	JPOPJ##		;NO
	HRRZS	J		;IN CASE S1
	MOVE	T1,.USHSS	;GET START OF HI SEG
	LSH	T1,W2PLSH##	;CVT TO PAGE #
	PUSHJ	P,TSWST		;IS IT IN THE WORKING SET?
	TDZA	T2,T2		;NO, STORE ZERO IN JBTHSA
	PUSHJ	P,GTPME		;GET CONTENTS OF THAT SLOT IF IN WS
	DPB	T2,JBYHSA##	;STORE IN JBTHSA
	JRST	JPOPJ##		;AND RETURN
;SUBROUTINE TO WAIT FOR MIGRAT TO PASS US
;CALLED BY IPCFS
;USES T1

MIGWAT:
IPMWAT::PUSH	P,J			;SAVE J
IPMWT1:	HRRZ	T1,MIGRAT##		;MIGRATE IN PROGRESS?
	JUMPE	T1,JPOPJ##		;NO
	CAMLE	T1,.USJOB		;IF SO, HAS IT PASSED US?
	JRST	JPOPJ##			;NOT IN PROGRESS OR HAS PASSED US
	MOVEI	T1,1			;SLEEP A BIT
	MOVE	J,.CPJOB
	PUSHJ	P,SLEEPF##		;..
	JRST	IPMWT1			;AND CHECK AGAIN
	SUBTTL	KILL NON-ZERO SECTION PAGES

;HERE TO KILL ALL NON-ZERO SECTIONS AND PAGES, AND MARK THE USER SMALL AGAIN.

KILNZS::SKIPN	JBTADR##(J)		;JOB REALLY HAVE ANY CORE?
	JRST	CPOPJ1##		;NO, DON'T DO ANYTHING THEN
	PUSHJ	P,SAVE4##		;SAVE ACS
	PUSHJ	P,SAVT##		;SAVE THESE TOO
	SE1ENT				;FOR PAGTAB/MEMTAB
	MOVSI	P1,-<MXSECN+1>		;AOBJN POINTER TO SECTIONS
	AOBJP	P1,CPOPJ1##		;DONE
	PUSH	P,J			;SAVE J
	MOVE	J,.USJOB		;GET CURRENTLY MAPPED JOB
KILNZ1:	PUSHJ	P,KILNZ6		;SEE IF NEED TO WAIT
	  JRST	JPOPJ##
KILNZ2:	SKIPE	P2,.UPMP+SECTAB(P1)	;SECTION EXIST?
	TLNE	P2,(<PM.ACD^!PM.DCD>B2)	;INDIRECT OR IMMEDIATE?
	JRST	KILNZ3			;NOTHING TO DO
	MOVEI	T1,(P1)
	PUSHJ	P,KILSEC		;KILL THE SECTION
	MOVEI	T2,(P2)			;GET SECTION MAP ENTRY
	MOVEI	T1,(P1)			;SECTION # AGAIN
	PUSHJ	P,ZAPNZM		;KILL THE MAP
	TDZA	T1,T1
KILNZ3:	HRREI	T1,KILNZ2-KILNZ1
	SETZM	.UPMP+SECTAB(P1)
	AOBJN	P1,KILNZ1(T1)		;CONTINUE
	SKIPL	.USBTS			;REALLY A BIG USER?
	JRST	KILNZ5			;CLEAR PAGING MEM AND RETURN
KILNZ4:	MOVE	T2,.UPMP+.UMWSB		;WSBTAB FOR NZS
	ANDI	T2,37777		;KILL IT TOO
	PUSHJ	P,LKPSF			;LINK PAST THE PAGE IN PAGTAB
	SSX	T2,MS.MEM		;PAGTAB SECTION
	HLLZS	PAGTAB(T2)		;INDICATE LAST PAGE ALLOCATED
	HRRZS	T2
	PUSHJ	P,DLTPGC
	SETZM	.UPMP+.UMWSB
	MOVEI	T1,.UPMVP/PAGSIZ##-1-1	;VPN OF .WSBNZ
	PUSHJ	P,TSWST			;GET BIT TO CLEAR IN...
	CAIA
	ANDCAM	T2,(T4)			;WSBTAB
	MOVSI	P1,(UP.BIG)
	ANDCAM	P1,.USBTS		;NO LONGER A BIG USER
	MOVSI	T1,-1			;DECREMENT # FUNNY PAGES
	ADDM	T1,JBTPDB##(J)
KILNZ5:	SETZ	T1,
	DPB	T1,NZSXCN##		;CLEAR # OF NZS SECTIONS
	CLRPGT	(0)			;FLUSH PAGING MEMORY
	JRST	JPOPJ1##		;RESTORE J AND RETURN
KILNZ6:	SKIPE	SCDRTF##		;FORCED RESCHED PENDING?
	JRST	KILNZ7
	PUSH	P,T1			;SAVE T1
	SKIPE	T1,.CPTMF##		;CLOCK TICK AT ALL?
	CAIG	T1,3			;MORE THAN 3 TIMES?
	PJRST	TPOPJ1##		;OK TO PROCEED
	POP	P,T1
KILNZ7:	PUSHJ	P,UUOLVL##		;UUO LEVEL?
	  POPJ	P,			;NO
	AOS	(P)			;SKIP RETURN WHEN WE DO
IFN FTMP,<
	PUSHJ	P,REMMM##		;REMEBER STATE OF MM
>
	PJRST	WSCHED##		;WAIT

;SUBROUTINE TO KILL ALL PAGES IN A (NON-ZERO) SECTION
;NOTE THAT J MUST BE SET UP

KILSEC:	PUSHJ	P,SAVE3##		;GET AN AC
	MOVE	P3,.USVRT		;GET VIRTUAL STATUS OF JOB
	ANDCMI	P3,777			;FORGET ANA
	MOVE	P2,T1			;SECTION #
	PUSHJ	P,GETNZC		;GET COUNT OF PAGES IN SECTION
	SKIPN	P1,T1			;SAVE IT
	POPJ	P,			;NOTHING TO DO
	PUSH	P,P2			;SAVE SECTION #
	LSH	P2,S2PLSH##		;SECTION # (SO DCUPR DOES RIGHT THING)
	HRLI	P2,-<HLGPNO+1>		;STARTING AT PAGE 0
KILSE1:	HRRZ	T1,P2			;FOR DLTPAG & GTPME
	PUSHJ	P,GTPME			;GET PAGE MAP ENTRU
	JUMPE	T2,KILSE2		;NOTHING TO DO THIS ENTRY
	JUMPE	P3,KILS1A		;IF NOT VIRTUAL, SKIP THIS
	SOS	VMTOTL##		;LESS VM IN USE
	AOS	VMCMAX##
KILS1A:	PUSHJ	P,DLTPAG		;DELETE THE PAGE
	SOJLE	P1,KILSE3		;DONE
KILSE2:	AOBJN	P2,KILSE1		;CONTINUE
KILSE3:	PUSHJ	P,SETVRT		;FIX .USVRT
	POP	P,T1			;RESTORE SECTION #
	SETZ	T2,
	PJRST	PUTNZC			;NO PAGES LEFT
;ROUTINE TO KILL ALL EMPTY NZS MAPS, MAKE USER SMALL IF HE NOW IS.

ZAPSCS:	SKIPL	.USBTS			;NEED TO DO THIS AT ALL?
	POPJ	P,			;NO
	SE1ENT				;ENTER SECTION 1
	PUSHJ	P,SAVE2##		;SAVE P1 & P2
	MOVSI	P1,-MXSECN		;NOTE THAT SECTION 0 NOT INCLUDED
IFN FTMP,<
	PUSHJ	P,MMOWN##		;OWN THE MM?
	  PUSHJ	P,GGVMM##		;MM IF REQUIRED
>
	MOVE	P2,[POINT UP.SCS,.USSCT,] ;ARRAY OF COUNTS
ZAPSCL:	ILDB	T2,P2			;COUNT OF PAGES
	JUMPN	T2,ZAPSCE		;KILL SECTION IF NEED TO
	SKIPE	T2,.UPMP+SECTAB+1(P1)	;GET THE MAP ENTRY
	TLNE	T2,(<PM.ACD^!PM.DCD>B2)	;DON'T INCLUDE INDIRECTS
	JRST	ZAPSCE
	MOVEI	T1,1(P1)		;SECTION # KILLING
	PUSHJ	P,ZAPNZM		;KILL THE MAP
	SETZM	.UPMP+SECTAB+1(P1)	;CLEAR THE ENTRY
ZAPSCE:	AOBJN	P1,ZAPSCL		;..
	LDB	P1,NZSXCN##		;ANY MAPS HAVE OR DESIRED?
	JUMPN	P1,CPOPJ##		;DONE
	PUSH	P,J			;KILNZ4 WANTS J ON THE STACK
	SOS	-1(P)			;KILNZ4 TRIES TO SKIP
	JRST	KILNZ4

;HERE TO KILL A SECTION MAP.  POINTER TO MAP IN T2
;T1=SECTION # BEING KILLED
;***DOES NOT ZERO MAP SLOT***

ZAPNZM:	PUSH	P,T1			;SAVE T1
	ANDI	T2,37777		;KEEP ONLY PHYS. PAGE #
	PUSHJ	P,LKPSF			;LINK PAST THE PAGE IN PAGTAB
	SSX	T2,MS.MEM		;PAGTAB SECTION
	HLLZS	PAGTAB(T2)		;INDICATE LAST PAGE ALLOCATED
	HRRZS	T2
	PUSHJ	P,DLTPGC		;RETURN THE PAGE
	POP	P,T1			;RESTORE SECTION #
	MOVEI	T1,.UPMVP/PAGSIZ##(T1)	;TURN OFF WSB FOR IT
	PUSHJ	P,TSWST			;GET IT
	POPJ	P,
	ANDCAM	T2,(T4)			;CLEAR BIT
	LDB	T2,NZSSCN##		;DECREMENT # OF MAPS
	SOS	T2
	DPB	T2,NZSSCN##
	LDB	T2,NZSICN##		;JUST IN CASE
	JUMPE	T2,CPOPJ##
	SOS	T2
	DPB	T2,NZSICN##
	POPJ	P,
;ROUTINES TO INCREMENT/DECREMENT EXISTENT PAGES IN NON-ZERO SECTIONS.
;CALL WITH T1=SECTION # TO CHANGE.  PRESERVES WORLD.
;NOTE - TO BE CALLED AT UUO LEVEL ONLY -

INCNZC:	JUMPE	T1,CPOPJ##		;DON'T DIDDLE SECTION 0
	PUSHJ	P,SAVT##		;SAVE ACS
	MOVEI	T3,1			;FLAG INCREMENT
	JRST	CHGNZC			;FIX IT

DECNZC:	JUMPE	T1,CPOPJ##		;DON'T CHANGE SECTION 0
	PUSHJ	P,SAVT##		;SAVE ACS
	MOVNI	T3,1
CHGNZC:	HRRZS	T1			;CLEAR JUNK
CHGNZ0:	MOVE	T2,.UPMP+SECTAB(T1)	;GET SECTION #
	TLNN	T2,(<PM.ACD^!PM.DCD>B2)	;INDEPENDENT SECTION?
	JRST	CHGNZ1			;YES, PROCEED
	LDB	T1,[POINT 5,T2,17]	;NOTE 540(SECTAB) AND 37 DON'T
					;OVERLAP ANY NON-ZERO BITS
	JUMPN	T1,CHGNZ0		;SEE IF IT'S INDEPENDENT
CHGNZ1:	SOSGE	T1			;NOTHING FOR SECTION 0
	POPJ	P,			;REALLY WAS SECTION 0
	IDIVI	T1,^D36/UP.SCS		;SIZE OF BYTE
	LDB	T4,PNTNZS(T2)		;GET COUNT
	TRZ	T4,UP.VRG		;NO LONGER A "VIRGIN" SECTION
	ADD	T4,T3			;ADJUST COUNT
	DPB	T4,PNTNZS(T2)		;REPLACE
	POPJ	P,

GETNZC:	PUSH	P,T2
	SOS	T1
	IDIVI	T1,^D36/UP.SCS		;SIZE OF BYTE
	LDB	T1,PNTNZS(T2)
	JRST	T2POPJ##		;RETURN

PUTNZC:	PUSH	P,T2
	SOS	T1
	IDIVI	T1,^D36/UP.SCS
	EXCH	T3,(P)
	DPB	T3,PNTNZS(T2)
	JRST	T3POPJ##
	SUBTTL	ROUTINE TO DO CLRPGT FOR BOTH SECTION 0 AND 1

;CALL:
;	PUSHJ	P,CLPTZO
;	EXP	(ADDRESS TO CLEAR)
;USES NOTHING

CLPTZO:	SE1ENT
	PUSH	P,T1
	HRRZ	T1,@-1(P)
	CLRPT	(T1)		;CLEAR SECTION LOCAL (SECTION 1)
	CLRPT	@T1		;CLEAR GLOBAL (SECTION 0)
	JRST	TPOPJ1##
PNTCNT:	POINT	18,T1,17
	POINT	14,T1,13
	POINT	14,T1,13
MAXCNT:	400000+T1,,-1
	400000+T1,,37
	400000+T1,,3

PNTNZS:	POINT	UP.SCS,.USSCT(T1),<UP.SCS-1>
	POINT	UP.SCS,.USSCT(T1),<2*UP.SCS-1>

	$LIT
	$HIGH
VMEND:	END