Google
 

Trailing-Edge - PDP-10 Archives - BB-BT99S-BB_1990 - 10,7/mon/vmser.mac
There are 11 other files named vmser.mac in the archive. Click here to see a list.
TITLE	VMSER - VIRTUAL MEMORY SERVICE ROUTINE  V4774
SUBTTL	J. FLEMMING, T. WACHS/KBY	07-NOV-89

	SEARCH	F,S,DEVPRM
	SALL
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
;1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1973,1990>


XP VVMSER,4774    ;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
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
NVPNT3:	POINT P2.SPN,PT2TAB(T3),<^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,UDBKDB(U)	;SET UP J POINTING TO  KONTROLLER
				;(PRESERVE UUO/INT LEVEL FLAG)
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,UDBKDB(T3)	;YES, GET 2ND KON
				;(PRESERVE UUO/INT LEVEL FLAG)
	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,UDBKDB(U)	;GET (NEW) KON
				;(PRESERVE UUO/INT LEVEL FLAG)
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
	MOVE	T2,KDBCHN(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,<
	MOVE	T2,UDBKDB(U)	;FILE TRANSFERS WAITING ON THIS CHAN?
	MOVE	T2,KDBCHN(T2)
	SKIPE	CHNQUE(T2)
	SKIPN	T2,UNI2ND(U)	;AND DUAL PORTED?
	JRST	SWPS16		;NO, OK LET IT HAPPEN
	HRR	J,UDBKDB(T2)	;YES, IS OTHER KON BUSY?
				;(PRESERVE UUO/INT LEVEL FLAG)
	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,UDBKDB(U)	;GET KON BACK
				;(PRESERVE UUO/INT LEVEL FLAG)
SWPS16:>
IFN FTMP,<
	MOVE	T2,UDBCAM(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,KDBCHN(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,UDBKDB(U)	;KONTROLLER
				;(PRESERVE UUO/INT LEVEL FLAG)
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,UDBKDB(T3)	;YES, GET 2ND KON
				;(PRESERVE UUO/INT LEVEL FLAG)
	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,UDBKDB(U)	;GET (NEW) KON
				;(PRESERVE UUO/INT LEVEL FLAG)
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,KDBCHN(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
	MOVE	J,UDBKDB(U)	;SET KONTROLLER
IFN FTDUAL,<
	CAIE	P2,@KDBCHN(J)	;IGNORE BUSY IF INT ON THIS CHAN
	SKIPGE	@KDBCHN(J)	;CHAN BUSY?
	JRST	SWPPI3		;IDLE, USE PRIME PORT
	SKIPN	T3,UNI2ND(U)	;BUSY, DUAL-PORTED DRIVE?
	JRST	SWPPI3		;NO, WAIT FOR PRIME PORT
	MOVE	J,UDBKDB(T3)	;YES, GET 2ND KON
	CAIE	P2,@KDBCHN(J)	;IGNORE BUSY IF INT ON THIS CHAN
	SKIPGE	@KDBCHN(J)	;CHAN BUSY?
	HRRZ	U,UNI2ND(U)	;IDLE, USE 2ND PORT
	MOVE	J,UDBKDB(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,@KDBCHN(J)
	SKIPGE	@KDBCHN(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
>
	MOVE	J,UDBKDB(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,KDBCHN(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,@KDBCHN(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,KDBCHN(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
;RETURNS CDB OFFSET IN T4 *ONLY* ON NON-SKIP RETURN
SWPCP:	MOVE	T4,UDBCAM(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,UDBCAM(T3)	;2ND PORT ON THIS CPU?
	TDNN	T3,.CPBIT##
	JRST	SWPCP1		;NO
	HRRZ	U,UNI2ND(U)	;SWITCH TO OTHER PORT
	MOVE	J,UDBKDB(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
	MOVEI	T4,(T1)		;COPY CPU NUMBER
	IMULI	T4,.CPLEN##	;TRANSLATE TO CDB OFFSET
	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##	;SET UP MAPPING
	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 22-BIT CHAN
IFN FTKL10,<
	MOVE	T2,CHNTYP(P3)	;GET CHANNEL TYPE BITS
	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)
	TLNE	P4,(SL.IPC)	;IPCF?
	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		;IF IPCF OR PAGING QUEUE
	HRRZ	T2,JBTUPM##(J)	;SWAPPING THE UPMP?
	CAIG	J,JOBMAX##	;IF HIGH SEG OR
	CAIE	T2,(P4)		;NOT SWAPPING UPT
	JRST	THIS4		;PROCEED
	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 PHYSICAL 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 IPCF/PAGING QUEUE
	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
	CAIG	J,JOBMAX##	;LOW OR HIGH SEG?
	SKIPA	P4,[GMPTR]	;LOW SEG
	MOVEI	P4,GMHPTR	;HIGH SEG
	PUSHJ	P,(P4)		;GET POINTER FOR MAP
	MOVE	P4,(T4)		;GET MAP ENTRY
	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,-PAGSIZ	;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,<(INSVL.(.CCFDT,CC.OPC)_-4)> ;+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##	;GET ADDRESS
	JUMPLE	P2,THIS13	;DONE IF P2=0
	AOBJN	P1,THIS4	;MORE TO DO, GET NEXT CHUNK
	PUSHJ	P,GETMOR##	;NEED ANOTHER 4-WORD BLOCK
	  JRST	THIS20		;NONE AVAILABLE
	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,(CC.HLT)	;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		;INPUT OR PAGING QUEUE
	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>]
	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:	SE1ENT			;NEED TO BE IN S1 FOR HIGH SEGS
	CAILE	J,JOBMAX##	;JOB?
	SKIPA	P3,JBTVAD##(J)	;ADDRESS OF MAP
	SKIPA	P3,.USLPS	;JOB, GET POINTER FROM UPT
	HRRZ	P3,.M2VPN-.M2MAP(P3) ;GET ENTRY
	TLNN	P1,-1		;FRAGMENTED SWPLST ENTRY?
	JRST	GETVPR		;NOT FRAGMENTED
	PUSHJ	P,FRGIDX	;GET FRAGMENT INDEX
	ADDI	P3,(T1)		;POINTER INTO TABLE
	MOVE	P3,(P3)		;AND ENTRY
GETVPR:	CAILE	J,JOBMAX##	;IF A HIGH SEG
	ADD	P3,JBTVAD##(J)	;CONVERT TO MAP POINTER
	POPJ	P,

SETVPN:	SE1ENT			;NEED TO BE IN S1 FOR HIGH SEGS
	CAILE	J,JOBMAX##	;JOB?
	SKIPA	T2,JBTVAD##(J)	;JBYVAD IF HIGH SEG
	SKIPA	T2,[.USLPS]	;NO, STORE FOR CURRENT JOB
	XMOVEI	T2,.M2VPN-.M2MAP(T2) ;POINT TO VPN TABLE AREA FOR HIGH SEG
	TLNN	P1,-1		;FRAGMENTED?
	JRST	SETVP5		;NO
	PUSHJ	P,FRGIDX	;COMPUTE A FRAGMENT INDEX
	HRRZ	T2,(T2)		;RELOCATE
	ADD	T2,T1		;PLACE TO STORE
SETVP5:	JUMPE	P3,SETVP6	;(ZERO IS A SPECIAL CASE)
	CAILE	J,JOBMAX##	;ELSE, IF HIGH SEG,
	SUB	P3,JBTVAD##(J)	;CONVERT BACK TO RELATIVE POINTER
SETVP6:	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 JOB OR HIGH SEG J
;USES T1,T2
RTNVPN::CAILE	J,JOBMAX##	;JOB OR HIGH SEG?
	JRST	RTNVPH		;HIGH SEG
	PUSHJ	P,SVEUB##	;JOB, MAP IT
	SKIPN	T2,.USLPS	;IS THERE A POINTER?
	POPJ	P,		;NO, JUST RETURN
				;(NO GOOD TO ZERO .USLPS SINCE NON-ZERO ON DSK)
RTNVPC:	MOVE	T1,-1(T2)	;GET COUNT
	SOS	T2		;ADDRESS
	PJRST	GIVWDS##

RTNVPH:	SE1ENT			;NEED TO BE IN S1
	LDB	T1,JBYVAD##	;POINT TO MAP AREA
	HRRZ	T2,.M2VPN-.M2MAP(T1) ;GET POINTER TO VPN TABLE
	JUMPE	T2,CPOPJ##	;IF NOTHING TO DO
	HLLZM	.M2VPN-.M2MAP(T1) ;HIGH SEG MAP STAYS IN CORE
	JRST	RTNVPC		;JOIN COMMON CODE
;SUBROUTINE TO SET UP J FROM SWPLST ENTRY
;ENTER P1 POINTING TO SWPLST
;EXITS WITH J NEGATIVE IF PAGING QUEUE; CPOPJ IF LOW SEG,
;CPOPJ1 IF HIGH SEG OR QUEUE

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		;INDICATE PAGING QUEUE
	CAILE	J,JOBMAX##	;IF HIGH SEG OR PAGING QUEUE
	AOS	(P)		;GIVE SKIP RETURN
	POPJ	P,		;RETURN


;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
	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
	SKIPLE	JBTST2##(J)	;DEMAND PAGING?
	SUB	T1,.USWLP	;YES, DON'T WRITE OUT WRITE LOCKED PAGES
	LDB	T2,NFYPGS##	;ADD 1 PAGE FOR UPMP
	ADD	T1,T2
	LDB	J,NZSSCN##	;GET NUMBER OF NZS MAPS
	ADDI	J,(T1)
	PUSH	P,J		;SAVE NUMBER OF PAGES TO WRITE
	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
	POP	P,T2		;NUMBER OF PAGES TO WRITE
	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
	JUMPL	W,MAKSLE	;GO IF WORKING SET SWAPPING
	LDB	T2,IMGIN##	;YES, ADJUST SIZES FOR NEXT INPUT
	LDB	T3,IMGOUT##	; ..
	SUB	T2,T3		;AMOUNT OF EXPANSION IF ANY
	ADDI	T2,1		;ACCOUNT FOR PAGE 0
	DPB	T2,IMGIN##	;NEW INPUT SIZE
	MOVEI	T2,1		;NEW OUTPUT SIZE
	DPB	T2,IMGOUT##	;STORE THAT
	PUSHJ	P,NCBPOP	;COUNT NUMBER OF CAN'T BE PAGED OUT PAGES
	  JFCL			;ALWAYS SKIPS
	.CREF	IMGIN,IMGOUT
	ADDM	T4,JBTIMI##(J)	;UPDATE COUNTS FOR NUMBER OF PAGES THAT
	ADDM	T4,JBTIMO##(J)	; CAN'T BE PAGED OUT
	PJRST	MAKSLE		;MAKE A SWPLST ENTRY 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	BUSLSH		;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,4		;WORDS NEEDED
	PUSHJ	P,GETWDS##	;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

;HERE FOR HI SEG
BUSLSH:	PUSHJ	P,SAVE3##	;SAVE ACS
	SE1ENT			;NEED TO BE IN SECTION 1
	LDB	U,IMGIN##	;NO OF PAGES TO SWAP IN
	LDB	P1,JBYHSA##	;FIRST PAGE ALLOCATED TO HIGH SEG
	MOVE	T1,P1		;COPY TO T1
	LSH	T1,SL.SCT	;SHIFT INTO PLACE
	TLO	T1,(SL.SIO)	;SET IT'S SWAPPING
	PUSH	P,T1		;SAVE T1
	SSX	P1,MS.MEM	;POINT TO MEMTAB
	SETZ	P2,		;CLEAR P2
	.CREF	FRGSEG
	LDB	T4,JBYVAD##	;RELATVE ADDRESS OF MAP
	SKIPGE	T1,JBTSWP##(J)	;FRAGMENTED ON OUTPUT?
	JRST	BUSLHF		;YES
	TLO	T4,(GIDX(P2))	;SET A GLOBAL INDEX
	LDB	T1,IMGOUT##	;NUMBER OF PAGES I/O WILL BE DONE FOR
	IORM	T1,(P)		;SET COUNT INTO SWPLST ENTRY
	.CREF	SL.CNT
BUSLH1:	TRNN	P1,-1		;IS THERE A PAGE TO INSERT?
	STOPCD .,STOP,WNP	;++WRONG NUMBER OF PAGES
	SKIPN	T1,@T4		;GET MAP ENTRY
	JRST	BUSLH3		;NO ENTRY, EXPANDING
	TLO	T1,(<PM.DCD>B2!PM.COR)	;TURN ON ACCESSIBILITY
	MOVSI	T3,(PM.NAD)	;KEEP BITS IN T3
	AND	T3,T1		;...
	ANDCAM	T3,T1		;AND ADDRESS IN T1
	IORI	T3,(P1)		;PAGE MAP ENTRY
	MOVEM	T3,@T4		;STORE THIS ENTRY
	MOVEM	T1,MEMTAB(P1)	;SET DISK ADDRESS (CLEARING REST)
	SOJLE	U,BUSLH2	;DONE IF NO MORE PAGES
	AOS	P2		;NEXT VIRTUAL PAGE
	DPB	P2,NVPNP1	;STORE POINTER TO NEXT PAGE
	MOVE	P3,P1		;SAVE THIS PAGE
	HRR	P1,PAGTAB(P1)	;NEXT PAGE
	JRST	BUSLH1		;LOOP BACK

BUSLH3:	PUSHJ	P,BUSLHZ		;ZERO THE REST OF THE PAGES
	MOVE	P1,P3		;WHERE TO SET MT.LEF
BUSLH2:	MOVSI	T1,(MT.LEF)	;SET MEMTAB FLAG
	IORM	T1,MEMTAB(P1)	;..
	POP	P,T1		;RESTORE T1
	AOS	(P)		;SKIP RETURN
	PJRST	MAKSLE		;MAKE SWPLST ENTRY AND RETURN

BUSLHF:	POP	P,(T1)		;PUT INITIAL ENTRY INTO FRAGMENT TABLE
	TLO	T1,(SL.FRG!SL.SIO) ;INDICATE THIS IS A FRAGMENTED ENTRY
				;(NOTICE THAT THIS IS ALSO THE SIGN BIT!)
	PUSH	P,T1		;SAVE THAT SWPLST ENTRY
	PUSH	P,T1		;SAVE A WORKING COPY
	MOVE	T4,JBTVAD##(J)	;RELATVE ADDRESS OF MAP
	TLO	T4,(GIDX(P2))	;SET A GLOBAL INDEX
BUSLF3:	TRNN	P1,-1		;IS THERE A PAGE?
	XCT	WNP		;NO, ERROR
	SKIPN	T2,@T4		;GET MAP ENTRY
	JRST	BUSLF5		;NO MAP ENTRY, ZERO REST OF PAGES
	TLO	T2,(<PM.DCD>B2!PM.COR) ;TURN ON GOOD BITS
	MOVSI	T1,(PM.NAD)	;BITS TO T1,
	AND	T1,T2		;..
	ANDCAM	T1,T2		;AND DISK ADDR TO T2
	HRRI	T1,(P1)		;PUT IN THE PAGE
	MOVEM	T1,@T4		;UPDATE THE PAGE MAP ENTRY
	MOVEM	T2,MEMTAB(P1)	;STORE DISK ADDRESS IN MEMTAB
	AOS	P2		;INCREMENT VIRTUAL PAGE NUMBER
	DPB	P2,NVPNP1	;NEXT PAGE
	.CREF	SL.CNT
	AOS	T1,@(P)		;UPDATE COUNT IN SWPLST ENTRY
	TLC	T1,SL.CNT	;IT'S EASIER TO TEST ZEROES...
	SOJLE	U,BUSLF6	;DONE IF NO MORE PAGES
	MOVE	T3,@T4		;GET NEXT ENTRY
	TLZ	T3,(PM.NAD)	;ONLY ADDRESS
	AOS	T2		;INCREMENT OLD DISK ADDR
	TLNE	T1,SL.CNT	;ABOUT TO OVERFLOW COUNT (1000P HIGH SEG)?
	CAME	T2,T3		;NO, ARE DISK ADDRS SAME?
	JRST	BUSLF6		;ABOUT TO OVERFLOW OR DISK ADDRS DIF
	MOVE	P3,P1		;SAVE PREVIOUS PAGE
	HRR	P1,PAGTAB(P1)	;GET NEXT PHYSICAL PAGE
	JRST	BUSLF3		;LOOP AROUND

BUSLF6:	MOVSI	T3,(MT.LEF)	;LAST PART OF THIS FRAGMENT
	IORM	T3,MEMTAB(P1)	;SET IT
	JUMPLE	U,BUSLF9	;JUMP IF DONE
	HRR	P1,PAGTAB(P1)	;POINT TO NEXT PHYS PAGE
	MOVEI	T1,(P1)		;PUT IN T1
	LSH	T1,SL.SCT	;POSITION IT
	TLO	T1,(SL.SIO)	;SWPLST BIT
	AOS	(P)		;POINT TO NEXT SLOT IN FRAGMENT TABLE
	MOVEM	T1,@(P)		;STORE BASE FOR NEW ENTRY
	JRST	BUSLF3		;AND PROCESS MORE PAGES

BUSLF5:	PUSHJ	P,BUSLHZ	;ZERO REST OF PAGES AND INSERT IN MAP
	MOVE	P1,P3		;AND FINISH THE SWPLST ENTRY UP
	JRST	BUSLF6

BUSLF9:	POP	P,T1		;WORKING COPY
	SETZM	1(T1)		;END THE SWPLST FRAGMENT TABLE
	POP	P,T1		;COPY TO MAKE SWPLST ENTRY WITH
	AOS	(P)		;GIVE GOOD RETURN
	PJRST	MAKSLE		;MAKE IT

;SUBROUTINE TO FINISH OFF PAGES WE EXPANDED INTO

BUSLHZ:	PUSH	P,.UPMP+.UMTMP	;SAVE CURRENT TEMP MAPPING
BSLHZ1:	TRNN	P1,-1		;THERE SHOULD BE A PAGE
	XCT	WNP		;ELSE SOMEONE IS CONFUSED
	MOVE	T2,@JBTVAD##(J)	;GET FIRST ENTRY IN MAP (FOR BITS)
	AND	T2,[PM.NAD]	;KEEP ONLY THAT
	IORI	T2,(P1)		;PAGE TO INSERT
	MOVEM	T2,@T4		;STORE THE PAGE
	PUSHJ	P,ZPAGE		;ZERO THE PAGE
	HRR	P1,PAGTAB(P1)	;POINT TO NEXT PAGE
	SOSLE	U		;DONE IF COUNT WENT TO ZERO
	AOJA	P2,BSLHZ1	;CONTINUE IF MORE PAGES
	POP	P,.UPMP+.UMTMP	;RESTORE UUO LEVEL .TMP SLOT
	CLRPT	.TEMP		;..
	POPJ	P,
;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,.USTMP
	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:	MOVEI	T2,JBTSGN##-.HBLNK(J)	;POINTER TO SEGMENT DATA BLOCKS
BISL9A:	SKIPG	T2,.HBLNK(T2)	;POINT TO NEXT
	JRST	BISL10		;DONE
	HRRZS	T2		;CLEAR BITS
	JUMPE	T2,BISL10	;?
	SKIPLE	T3,.HBSGN(T2)	;GET SEGMENT WORD
	TLNE	T3,SHRSEG	;SKIP IF SHARABLE
	JRST	BISL9A		;NO, GO MAKE THE SWPLST ENTRY
	HRRZS	T3		;CLEAR JUNK
	LDB	T4,[POINT 9,JBTADR##(T3),8]	;YES
	SKIPE	JBTADR##(T3)	;HIGHEST ADR IN HIGH SEG
	ADDI	T4,1
	DPB	T4,[PHSSLH+.HBHSZ(T2)]
	JRST	BISL9A		;CHECK ALL SEGS

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 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:	SE1ENT			;NEED TO BE IN SECTION 1
	PUSHJ	P,SAVE4##	;SAVE PS
	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
	LDB	T4,JBYVAD##	;VIRTUAL ADDRESS
	SETZB	P3,.M2VPN-.M2MAP(T4) ;START AT RELATIVE VIRT PAGE 0
	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:	HRRZ	P2,T1		;FRAGMENT TABLE ADDRESS
	HRRZ	T1,T3		;ADDRESS OF VPN TABLE
	LDB	T2,JBYVAD##	;POINTER
	MOVEM	T1,.M2VPN-.M2MAP(T2) ;STORE FOR LATER
	MOVEI	P3,STOHDA	;ROUTINE TO STORE DISK ADDRESS IN MEMTAB
	SETZ	T3,		;START AT VPN 0
	LDB	T2,JBYHSA##	;FIRST PHYS ADDRESS
	PJRST	BFSLST		;SETUP SWPLST FRAGMENT TABLE,
				;MAKE SWPLST ENTRY, AND RETURN

;SUBROUTINE TO STORE DISK ADDRESS IN MEMTAB, CALL WITH T1=DISK ADDRESS,
; T2=MEMTAB INDEX, ALWAYS RETURNS CPOPJ
STOHDA:	AOS	P3		;INCREMENT OFFSET POINTER
	DPB	P3,NVPNT2	;STORE IN PT2TAB
	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	T1,		;NO VPN TABLE
	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,<PAGSIZ_<^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
;T1 IS ADDRESS OV VPN TABLE TO STORE IN (ZERO IF NONE)
;T3 HAS STARTING VPN (OR JUNK)

BFSLST:	PUSHJ	P,SAVE3##	;SAVE ACS
	PUSH	P,T1		;ADDR OF VPN TABLE (OR ZERO)
	PUSH	P,T3		;VPN TO START AT (OR JUNK)
	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
	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
	EXCH	P3,-2(P)	;GET VIRTUAL POINTER
	SKIPN	-3(P)		;ANY VPN TABLE ADDRESS?
	JRST	BFSLS7		;NO
	MOVEM	P3,@-3(P)	;YES, STORE VPN
	AOS	-3(P)		;INCREMENT
BFSLS7:	PUSHJ	P,SETXMT	;SET UP FOR THIS FRAG
	EXCH	P3,-2(P)	;STORE UPDATED POINTER RESTORE P3
	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
	ADJSP	P,-2		;FIX STACK
	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) ;SWPLST ENTRY TO SWAP 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
IFN FTMP,<
DLTSXI::
	TDZA	T1,T1
DLTSLX::
	SETZ	T1,
	PUSH	P,F		;PROBABLY NOT NECESSARY
	MOVEI	F,SWPDDB##	;FOR PIOFF
	PIOFF			;GUARD AGAINST INTERPROCESSOR RACE
	PUSHJ	P,DLTSLZ	;DELETE SWPLST ENTRY AND DECREMENT SLECNT
	PION
	JRST	FPOPJ##		;RESTORE F AND RETURN
>
IFE FTMP,<
DLTSXI::
>
DLTSLO::TDZA	T1,T1
IFE FTMP,<
DLTSLX::
>
DLTSLE::SETO	T1,		;FLAG ENTRY AT DLTSLE
DLTSLZ:	PUSH	P,T1		;SAVE FLAG
	SKIPN	T1,SWPLST##(P1)	;GET ENTRY
	STOPCD	DLTSL3,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
	SKIPN	(P)		;ENTRY AT DLTSLO/DLTSXI?
	JRST	DLTSL3		;YES
	POP	P,(P)		;FIX STACK
	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,4		;WORDS USED
	PUSHJ	P,GIVWDS##
	JUMPE	P1,CPOPJ##	;DONE IF LINK=0
	JRST	RTNBL1		;NOT DONE, RETURN NEXT BLOCK


DLTSL2:	SETZM	SWPCNT##	;ZERO SWPCNT SO WONT KEEP GETTING HERE
DLTSL3:	POP	P,(P)		;FIX STACK
	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,4		;WORDS NEEDED
	PUSHJ	P,GETWDS##
	  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>	;USER ADDRESS?
	JRST	[ADD T4,[MS.MAP+UMAPS]	;YES
		 POPJ P,]
	ADDI	T4,.UPMP-<.MCFV/PAGSIZ>+.UMORG ;OFFSET TO MAP SLOTS IN UPT
	CAILE	T4,.UPMP+.UMUPT		;SECTION MAP?
	MOVEI	T4,SECTAB-.UMORG-<<.UPMVP/PAGSIZ>-<.MCFV/PAGSIZ>>(T4)
	POPJ	P,

;SUBROUTINE TO GET THE BYTE POINTER FROM A HIGH SEG "VIRTUAL POINTER"
;NOTE THAT THIS IS SIMPLY THE OFFSET FROM THE BEGINNING OF THE MAP PAGE

GMHPTR:	LDB	P4,JBYVAD##		;VIRTUAL ADDRESS WHERE MAP IS
	ADD	T4,P4			;POINT THERE
	POPJ	P,			;RETURN
;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
	ANDCAB	P4,.USBTS	;.USBTS INDICATING MAP INFO
	SETZ	W,		;ASSUME DEMAND PAGING
	TRNN	P4,UP.NVS	;WRITE LOCKED PAGES HAVE A DISK COPY?
	JRST	SETOM2		;NO, MUST DO WORKING SET SWAPPING
	MOVE	P4,.USJOB	;GET JOB NUMBER
	SKIPE	.USVRT		;JOB VIRTUAL?
	SKIPGE	JBTST2##(P4)	;YES, IN A RUN QUEUE?
SETOM2:	TLO	W,400000	;NOT VIRTUAL OR IN A RUN QUEUE, WS SWAPPING
	SKIPE	R,.USSPT	;EXTENDED SECTION
	JRST	SETO18		;YES
	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
	MOVE	T4,F		;FOR THE FIRST TIME AT SETOM6
	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
	PUSHJ	P,CKWSS		;SEE IF DOING WORKING SET SWAPPING
	  JRST	SETOM8		;NO, DEMAND PAGING, CKWSS FIXED THINGS UP
	MOVEM	U,MEMTAB(F)	;SAVE DISK ADDRESS IN MEMTAB
	MOVEI	T4,(M)
	CAIE	T4,<.UPMVP-1>/PAGSIZ
	JRST	SETOM7
	MOVSI	T4,(UP.MAP)	;MAP INFO
	IORM	T4,.USBTS
	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:	TLNN	T4,(PM.WRT)	;PAGE WRITE LOCKED?
	JUMPGE	W,SETO13	;YES, DON'T STORE IN MEMTAB UNLESS WS SWAPPING
	HRR	F,W		;LAST WRITE ENABLED PAGE
	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?
	CAIE	T4,.UPMVP/PAGSIZ ;DID WE JUST DO THE UPT?
	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	SETO21		;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
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 DO FIXUPS FOR WRITE LOCKED PAGES AND TAKE CARE OF DEMAND
; PAGING IF APPROPRIATE. CALL WITH T4=CONTENTS OF THE MAP, RETURNS CPOPJ
; IF ALL THE WORK HAS BEEN DONE, CPOPJ1 IF THE NORMAL THING SHOULD BE DONE.
;PRESERVES T ACS.

CKWSS:	SKIPE	.USWLP		;IGNORE PM.WRT IF NO WE PAGES (NON-SHARABLE) HI SEG
	TLNE	T4,(PM.WRT)	;PAGE WRITE LOCKED?
	HRR	W,F		;NO, SAVE PHYSICAL PAGE NUMBER OF LAST WE PAGE
	TRNE	M,-1^!HLGPNO	;MONITOR PAGE?
	JRST	CPOPJ1##	;YES, THIS ISN'T APPLICABLE
	PUSHJ	P,SAVT##	;ALL OF THIS CODE IS VERY TOUCHY ABOUT ACS
	JUMPL	W,CKWSS2	;IF WSS, JUST TAKE CARE OF WRITE LOCKED PAGES
;HERE WHEN WE ARE GOING TO DEMAND PAGE IN THE JOB THE NEXT TIME IT COMES IN
	HRRZ	T1,M		;VIRTUAL PAGE WITHIN SECTION
	TRZ	R,HLGPNO	;MASK OUT POSSIBLE PAGE WITHIN SECTION
	TRO	T1,(R)		;SECTION NUMBER, VIRTUAL PAGE WITHIN IMAGE
	JUMPE	T1,CPOPJ1##	;DON'T DO ANY OF THIS FOR PAGE 0
	MOVE	T3,T4		;COPY BITS (TSWST CLOBBERS T4)
	PUSHJ	P,CCBPOP	;SEE IF THIS PAGE CAN BE PAGED OUT
	  JRST	CKWSS1		;NO, PSI VECTOR, .JBBPT, .JBINT, ETC.
	PUSHJ	P,TSWST		;GET BIT AND POINTER TO WSBTAB
	  STOPCD	CPOPJ##,DEBUG,MBW, ;MUST BE IN WORKING SET
	ANDCAM	T2,(T4)		;ITS NOT ANYMORE
	PUSH	P,T3		;NEED T3 FOR NEXT PART
	PUSH	P,J		;J MUST CONTAIN THE JOB NUMBER
	MOVE	J,.USJOB	; ..
	PUSHJ	P,DECHJ		;DECREMENT HIGH SEGMENT INCORE PAGE COUNT IF
				; THIS IS A NON-SHARABLE HIGH SEGMENT PAGE
	POP	P,J		;RESTORE ACS
	POP	P,T3		; ..
CKWSS1:	TLNE	T3,(PM.WRT)	;ALL DONE (EASY PART) IF PAGE NOT WRITE LOCKED
	JRST	CPOPJ1##	;RETURN AND CAUSE PAGE TO BE WRITTEN OUT
;HERE WHEN DOING DEMAND PAGING AND PAGE IS WRITE LOCKED (WE HAVE BOTH AN
; IN-CORE COPY OF IT AND A COPY ON THE DISK)
	MOVE	T4,T1		;SAVE VIRTUAL PAGE NUMBER FOR GMPTR
	HLRZ	T2,P3		;VIRTUAL PAGE BEING REMEMBERED AS FIRST
	CAIN	T2,(T4)		;IS IT THIS PAGE?
	SETZ	P3,		;YES, THEN NOT REALLY STARTING AT THIS PAGE
	MOVEI	T2,0		;ZERO MEMTAB
	HRRZ	T1,T3		;PHYSICAL PAGE NUMBER
	SSX	T1,MS.MEM	;MEMTAB SECTION
	EXCH	T2,MEMTAB(T1)	;GET DISK ADDRESS, ZERO MEMTAB
	TDZ	T2,[PM.NAD]	;ISOLATE DISK ADDRESS
	AND	T3,[PM.BTS-PM.COR] ;JUST ACCESS BITS OF INTEREST
	IOR	T2,T3		;FORM FULL DISK ADDRESS
	PUSHJ	P,GMPTR		;GET POINTER TO THE MAP
	EXCH	T2,(T4)		;T2=PHYSICAL PAGE, MAP=DISK ADDRESS
	TDZ	T2,[PM.NAD]	;PHYSICAL PAGE NUMBER
	PUSHJ	P,LKPSF		;LINK PAST PAGE IN PAGTAB
	MOVE	T1,T2		;PHYSICAL PAGE NUMBER - ARGUMENT FOR ADDPTQ
	MOVEI	T3,PAGOUQ	;WHERE TO PUT IT
	PJRST	ADDPTQ		;PUT PAGE ON "OU" QUEUE. THIS COULD BE POSPONED
				; UNTIL THE SWAP COMPLETED BUT SINCE WE ARE
				; SWAPPING NOW, MAKE THE CORE AVAILABLE AS SOON
				; AS POSSIBLE
;HERE WHEN VIRTUAL BUT DOING WORKING SET SWAPPING
CKWSS2:	HRR	W,F		;PHYSICAL PAGE NUMBER OF LAST PAGE
	AOS	(P)		;HAVE TO SWAP OUT THE PAGE IN ANY EVENT
	SKIPE	.USWLP		;IGNORE PM.WRT IF NO WL PAGES
	TLNE	T4,(PM.WRT)	;PAGE WRITE LOCKED?
	POPJ	P,		;NO, RETURN AND JUST SWAP IT OUT
	HRRZ	T2,T4		;YES, THEN IT STILL HAS DISK SPACE FROM
	PJRST	RTNDPG		; FROM PREVIOUS SWAP-IN, RETURN IT
;THE FOLLOWING ROUTINE ARE CROCKS BECAUSE WE DON'T ALLOW PAGES CONTAINING
; PSI INTERRUPT VECTORS, THE PAGE(S) POINTED TO BY .JBINT, AND THE PAGE
; POINTED TO BY .JBBPT TO BE REMOVED FROM THE WORKING SET. THEY WILL BE
; REMOVED IF THE VARIOUS ROUTINES INVOLVED GET TAUGHT HOW TO BE RUN AT UUO
; LEVEL AND HOW TO PAGE IN A PAGE. THIS WOULD ALSO SAVE CONSIDERABLE WORK
; ON THE PART OF PFH.

;SUBROUTINE TO CALL CHECKER OR COUNTER OF CBPO PAGES. FOR CHECKER, CALL WITH
; T1=VIRTUAL PAGE TO CHECK, EXITS CPOPJ IF CBPO, CPOPJ1 OTHERWISE. COUNTER
; RETURNS WITH T4=COUNT OF CBPO PAGES.

NCBPOP:	PUSHJ	P,SAVE3##	;SAVE SOME WORKING ACS
	SETZ	T4,		;INITIAL COUNT
	MOVEI	P2,CNCBPO	;ROUTINE TO CALL
	JRST	CCBPO1		;JOIN COMMON CODE
CCBPOP:	PUSHJ	P,SAVE3##	;SAVE ACS
	MOVEI	P2,CKCBPO	;ROUTINE TO CALL
CCBPO1:	MOVE	P1,T1		;PAGE TO CHECK, ALSO PRESERVE P1 ON A SKIP RETURN
	PUSH	P,J		;SAVE J
	MOVE	J,.USJOB	;JOB NUMBER, SOME OF THESE ROUTINES NEED IT
	MOVEI	P3,GETJLM##	;.JBINT LIMITS
	PUSHJ	P,(P2)		;CALL COUNTER OR CHECKER
	  JRST	JPOPJ##		;NON-SKIP RETURN
	MOVEI	P3,GETBLM##	;.JBBPT PAGE
	PUSHJ	P,(P2)		;CALL COUNTER OR CHECKER
	  JRST	JPOPJ##		;NON-SKIP RETURN
	MOVEI	P3,GETPLM##	;PSI VECTOR LIMITS
	PUSHJ	P,(P2)		;CALL COUNTER OR CHECKER
	  JRST	JPOPJ##		;NON-SKIP RETURN
	MOVE	T1,P1		;RESTORE T1
	JRST	JPOPJ1##	;SKIP RETURN

;CALL THE FOLLOWING WITH P3=ADDRESS OF ROUTINE TO CALL

;ROUTINE TO COUNT NUMBER OF CBPO PAGES, INITIAL CALL SET T4=0, RETURNS T4=COUNT
CNCBPO:	PUSHJ	P,(P3)		;GET LIMITS
	SKIPN	T1		;START IN PAGE 0?
	JUMPE	T2,CPOPJ1##	;GO IF BOTH START AND END ARE IN PAGE 0
	SUB	T2,T1		;NUMBER OF PAGES - 1 IN THE RANGE
	ADD	T4,T2		;ADD TO TOTAL SO FAR
	AOJA	T4,CPOPJ1##	;SKIP BUT COUNT AT LEAST ONE PAGE

;ROUTINE TO SEE IF PAGE CONTAINED IN P1 CAN'T BE PAGED OUT
CKCBPO:	PUSHJ	P,(P3)		;GET LIMITS
	CAML	P1,T1		;BELOW FIRST PAGE?
	CAMLE	P1,T2		;OR ABOVE HIGHEST?
	JRST	CPOPJ1##	;YES, OK TO REMOVE IT FROM THE WS
	POPJ	P,		;CBPO
;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
	MOVE	R,J		;SAVE PM.ADR FOR JXPN CHECK
	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
	TDNE	R,[PM.ADR]	;SWAPPING OUT (EXPANDING) TO ALLOCATE THIS PAGE?
				; IF SO, DOESN'T HAVE A DISK COPY SO DON'T WL
	SKIPN	.USVRT		;USER VIRTUAL?
	JRST	SETI3A		;NO
	TRNE	M,-1		;PAGE ZERO?
	TRNE	M,<-1^!HLGPGS>	;ON A MONITOR PAGE?
	JRST	SETI3A		;YES, DON'T WRITE LOCK THOSE PAGES
	SKIPE	R,MIGRAT##	;MIGRATING JOB?
	JRST	[ANDI	R,JOBMSK## ;ONLY JOB #, DISCARD FLAGS IN LH
		 CAMN	R,.USJOB ;THIS JOB?
		 JRST	SETI3A	;YES, DON'T WRITE-LOCK
		 JRST	.+1]	;GO AHEAD AND WRITE-LOCK PAGES
	TLZ	J,(PM.WRT)	;CLEAR WRITE ENABLE
	AOS	.USWLP		;AND BUMP THE NUMBER OF WRITE LOCKED PAGES
SETI3A:	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	SETI17		;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
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	MAPBAH		;DO HIGH SEG
	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
;HERE TO PUT HIGH SEG MAP BACK IN PLACE
;NOTE THAT A HIGH SEG IS ALWAYS ORDERED SUCH THAT PAGES ARE IN
;INCREASING ORDER

MAPBAH:	SE1ENT			;GET INTO SECTION 1
	LDB	T1,JBYHSA	;FIRST PAGE OF HIGH SEG
	SSX	T1,MS.MEM	;ADDRESS PAGTAB
	LDB	T2,JBYVAD##	;AND THE ADDRESS OF THE MAP
	SETZ	T3,		;CLEAR THE COUNTER
	TLO	T2,(GIDX(T3))	;SET AN INDEX
MAPBH1:	MOVSI	T4,(PM.NAD)	;GET THE ENTRY
	AND	T4,@T2		;FOR THIS PAGE (BITS ONLY)
	TLO	T4,(<PM.DCD>B2!PM.COR)
	HRRI	T4,(T1)		;AND THE PAGE
	MOVEM	T4,@T2		;UPDATE
	HRR	T1,PAGTAB(T1)	;NEXT PAGE IN HIGH SEG
	TRNE	T1,-1		;IF THERE IS ANY
	AOJA	T3,MAPBH1	;ON TO NEXT PAGE
	S0JRST	DLTSLX		;DONE
;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,<<^L<P2.VPN>+P2.SPN-1>-^D35>
	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,<<^L<P2.VPN>+P2.SPN-1>-^D35>
	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,JBYSSA##	;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			;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

	CLPLEN==10		;LENGTH (ROUNDED UP TO A 4-WORD BOUNDRY)

	$CSENT	(GETCLP::)	;GLOBAL ENTRY
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	DMOVE	P1,T1		;SAVE CALLER'S ARGUMENTS
	DMOVE	P3,T3		;...
	MOVEI	T2,CLPLEN	;GET MEMORY FOR REQUEST BLOCK
	S0PSHJ	GETWDS##	;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,CLPLEN	;NUMBER OF WORDS
	MOVE	T2,P1		;ADDRESS OF THEM
	S0JRST	GIVWDS##	;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
IFN FTXMON,<
	SKIPE	.UONCE##	;IF USER-MODE,
	PJRST	USRNZN##	;GO GET A PAGE IN SAT SPACE
>
	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
	HRRZ	T2,T1		;PAGE NUMBER
	MOVE	T1,R		;SECTION NUMBER
	MOVEM	T2,SPTCOM##-<(MS.FMD)>(T1)	;STORE IN SPT SLOT
	PUSH	P,T2		;SAVE THE PAGE NUMBER OF THE NEW SECTION MAP
	ADDI	T1,SECTAB	;WHERE TO STORE
	PUSHJ	P,STMAPS	;STORE PAGE NUMBER IN THE SECTION MAP
	HRRZ	T2,R		;SECTION NUMBER
	ADD	T2,.CPEPT##	;ADD IN EPT ADDRESS
	MOVE	T2,SECTAB(T2)	;GET SECTION MAP ENTRY
	MOVEI	T1,[HRRZ  T3,R	;GET SECTION NUMBER
		    ADD   T3,P1	;ADD IN CDB ADDRESS
		    MOVEM T2,.CPMMA##-.CPCDB##(T3) ;FIX UP .CPMMA
		    POPJ P,]
	PUSHJ	P,CPUAPP##	;DO IT FOR ALL CPUS
	POP	P,T2		;RESTORE PAGE NUMBER OF THE NEW 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	;MAKE SECTION MAP ADDRESSABLE
;	CLRPT	.TEMP		;MAKE NEW MAPPING VISIBLE
	CLRPGT			;WANT TO FLUSH ENTIRE PAGING MEMORY TO BE
				; SURE WE HAVE AN UP-TO-DATE SECTION MAP
	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:	PUSH	P,P1		;SAVE NUMBER OF MAP SLOTS TO RESERVE
	PUSH	P,P2		; AND STARTING MAP SLOT
	MOVSI	T2,1		;GET INVALID MAP SLOT MARKER
CREMN5:	MOVEM	T2,.TEMP(P2)	;MANUALLY UPDATE OUR MAP
	SOJLE	P1,CREMN6	;DECREMENT COUNT OF SLOTS TO RESERVE, JUMP WHEN
				; WE'VE RESERVED THE LAST ONE
	AOJA	P2,CREMN5	;LOOP FOR REMAINING SLOTS

CREMN6:	MOVEI	T1,.TEMP(P2)	;WHERE TO STORE IN THE SECTION MAP
	PUSHJ	P,STMAPE	;RESERVE THE LAST MAP SLOT WHILE WE HAVE THE MM
				;(YES, WE'VE ALREADY STORED THE MAPPING, BUT WE
				; WANT TO FORCE OTHER CPUS TO UPDATE THEIR
				; PAGING MEMORIES, SO WE HAVE TO CALL STMAPE)
	POP	P,P2		;RESTORE STARTING MAP SLOT
	POP	P,P1		; AND NUMBER OF MAP SLOTS

	MOVE	T3,P1		;NUMBER OF PAGES TO ALLOCATE
	PUSHJ	P,GETPHP	;GET THE PAGES
	POP	P,.UPMP+.UMTMP	;MAKE THE SECTION MAP ADDRESSABLE
	CLRPT	.TEMP		;MAKE NEW MAPPING VISIBLE
	MOVE	P3,P2		;STARTING MAP SLOT (NEEDED FOR VIRTUAL ADDRESS)
	HRRZ	P4,T1		;FIRST PHYSICAL PAGE ALLOCATED
CREMN7:	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
	MOVSI	T1,TNCSHB	;"TEMPORARILY UNCACHED" BIT
	IORB	T1,PAGTAB(P4)	;SET THE BIT AND GET THE LINK TO NEXT PAGE
	HRRZ	P4,T1		;NEXT PAGTAB ENTRY
	SOSLE	P1		;LAST PAGE?
	AOJA	P2,CREMN7	;NO, MAKE ENTRIES FOR EVERY PAGE *WE* ALLOCATED
	CLRPGT			;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).  IF LH (T2) NON-ZERO, MAP ENTRY IS STORED VERBATIM (SEE CREMN5).

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
	TLNE	P3,-1		;LH NON-ZERO?
	JRST	STMAP1		;YES, MUST BE CREMN5 RESERVING SLOTS
	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 THAN 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	[M.CPU##-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

IFN FTXMON,<
	$CSENT	(GFWNZN::)
	HRLI	T1,400000	;SET NZS FLAG
	JRST	GFWNZZ		;JOIN COMMON CODE
GFWNZ2::SKIPA	T1,[400000,,(MS.SAT)]	;SECTION 2 CORE
GFWNZS::MOVE	T1,[400000,,(MS.MEM)]	;GENERAL NZS SPACE
	SE1ENT			;MUST BE IN SECTION 1 TO ALLOCATE NZS SPACE
GFWNZZ:
>
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	[M.CPU##-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
	CAIN	T4,PAGSIZ	;REQUESTED EXACTLY ONE PAGE?
	JRST	CPOPJ1##	;YES, RETURN NOW
	SKIPN	DINITF##	;INITIALIZATION?
	CAILE	T4,PAGSIZ	;REQUESTING MORE THAN 1 PAGE
	JRST	GTFW10		;YES, MERGE THIS PAGE AND TRY AGAIN
				;(KEEP ALLOC CONTIGUOUS DURING INIT)
	SUB	T2,T4		;AMOUNT LEFT OVER AFTER SATISFYING REQUEST
	PUSH	P,T1		;SAVE ADDRESS OF NEWLY ACQUIRED CHUNK
	ADD	T1,T4		;ADDRESS OF RESIDUE
	EXCH	T1,T2		;WANT ARGS IN OTHER ORDER
	.CREF	NZS
	SKIPGE	R		;IS THIS FUNNY SPACE?
	TLO	R,(PIH)		;NO, LIGHT HEADER FLAG
	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,(DRP)	;LIGHT BIT SAYING NOT TO RETURN FULL PAGES
	EXCH	T1,T2		;WANT LENGTH AND ADDRESS IN THE OTHER ORDER
	.CREF	NZS
	SKIPGE	R		;IS THIS FUNNY SPACE?
	TLO	R,(PIH)		;NO, LIGHT HEADER FLAG
	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
;	T3/FLAGS,,?		;BITS (SEE BELOW)
;	PUSHJ	P,GVFWDS

;FLAG BITS IN T3:

	RSP==1B1		;RESTRICTED SPACE
	DRP==1B2		;DON'T RECLAIM FULL PAGES

;INTERNAL FLAG BITS (IN R)

	NZS==1B0		;NZS-STYLE LIST (EVEN IF CORE IS IN S0)
	PIH==1B1		;PREDECESSOR IS HEADER (I.E. FIRST TIME THROUGH)

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,(NZS!PIH)	;FLAG NOT FUNNY SPACE
>
IFE FTXMON,<
	MOVSI	R,(NZS!PIH)	;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,[IFIW!RSP+.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,[IFIW+.USFCU] ;GET UNCACHED LIST HEADER
>
	MOVEI	T3,.USFCC	;GET CACHED LIST HEADER
GVFWD3:	SPUSH	T3		;PUSH LEFT HALF
	TLZ	T3,(DRP)	;CLEAR POSSIBLE FLAG.
	TLNE	R,(NZS)		;FUNNY SPACE?
	TLNE	R,(PIH)		;PIH ON ONLY FIRST TIME
	CAIA
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,(NZS)		;FUNNY SPACE?
	JUMPE	T4,GVFWD5	;SECTION ZERO IS ZERO TERMINATED
	CAIN	T4,(T2)		;ALREADY IN FREE LIST
	STOPCD	CPOPJ##,STOP,PFL ;++PIECE ON FREE LIST
	CAIL	T4,(T2)		;KEEP CHUNKS IN ADDRESS ORDER
	JRST	GVFWD5		;IT GOES HERE
	HRR	T3,T4		;REMEMBER LINK
	TLZ	R,(PIH)		;PREDECESSOR NO LONGER HEADER
	JRST	GVFWD3		;AND LOOK AT THE NEXT

GVFWD5:	PUSH	P,T3		;SAVE PREVIOUS (AND FLAGS)
	TLZ	T3,(DRP)	;BE SURE FLAG IS CLEAR
	MOVEI	T4,(T3)		;ADDRESS OF PREVIOUS
	JUMPL	R,GVFWD6	;ALWAYS COMBINE NZS
	.CREF	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:
IFN FTKL10,<
	TLNN	R,(PIH)		;PREDECESSOR IS HEADER (FIRST TIME)?
GVFWD7:	CAIN	T4,.USFCU	;UNCACHED HEADER
>
IFE FTKL10,<
	TLNE	R,(PIH)		;PREDECESSOR IS HEADER (FIRST TIME)?
>
	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##,STOP,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	.,STOP,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,(DRP)	;SUPRESS RECLAMATION OF FULL PAGES
	POPJ	P,		;YES, ALL DONE NOW
	TLCE	R,(NZS)		;FUNNY SPACE?
	JUMPE	R,CPOPJ		;NO, CAN'T RECLAIM ONCE-ONLY CORE
	TLC	R,(NZS)		;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,PG.BDY	;MAX WORDS THAT CAN BE RETURNED
	ADDI	T2,PG.BDY	;AND ROUND ADDRESS TO CHUNK BOUNDRY
	TRZ	T2,PG.BDY	;...
	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
		 TLNN	R,(PIH)		;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,(RSP)	;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			;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
	CLRPT	.TEMP		;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
	HRRM	T2,.PDTMI##(W)
	MOVEI	T2,1		;FIRST TIME, COUNT DOWN FAST
	MOVEM	T2,.PDTMC##(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 ANY POSSIBLE 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 #
	  JRST	T2POPJ##	;SECTION DOESN'T EXIST
	POP	P,T2		;RESTORE T2
FLTTC1:	MOVE	T4,T2		;GET WORD ADDRESS AGAIN
	LSH	T4,W2PLSH	;PAGE #
	SE1ENT
	SKIPN	T4,@[IW MS.MAP,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
	HRRZ	T3,JBTSGN##(J)	;ANY HIGH SEGS?
	JUMPE	T3,CPOPJ##	;DONE IF NONE
	PUSH	P,T2		;SAVE  SUM(HIGH SEG SIZE)
VMSIZ1:	HRRZ	T2,.HBSGN(T3)	;GET SEGMENT # OR SIZE IF SPY SEG
	SKIPLE	.HBSGN(T3)	;SPY SEG?
	HLRZ	T2,JBTADR##(T2)	;NO, GET SIZE FROM JBTADR
	AOS	T2		;CONVERT TO
	LSH	T2,W2PLSH	;PAGES
	ADDM	T2,(P)		;ADD IN
	HRRZ	T3,.HBLNK(T3)	;NEXT SEGMENT
	JUMPN	T3,VMSIZ1	;LOOP
	JRST	T2POPJ##	;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
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,TPNHX		;YES, IS THIS PAGE IN THE HIGH SEGMENT?
	  SKIPA	J,.HBSGN(T2)	;YES, GET HIGH SEGMENT NUMBER
	AOJA	P1,[POP	P,T1	;RESTORE T1
		    JRST PHYPV1]
	POP	P,T1
	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

..UPMN==<.UPMAP-FYSORG>/PAGSIZ+^D512	;BIT NUMBER OF .UPMAP IN WSBTAB
..UPTN==<.UPMP-FYSORG>/PAGSIZ+^D512	;BIT NUMBER OF .UPMP IN WSBTAB
..UPMI==..UPMN/^D36		;INDEX IN WSBTAB OF BIT FOR .UPMAP
..UPTI==..UPTN/^D36		;INDEX IN WSBTAB OF BIT FOR .UPMP
..UPMB==1B0_<<..UPMI*^D36>-..UPMN> ;THE BIT IN THE WORD
..UPTB==1B0_<<..UPTI*^D36>-..UPTN> ;THE BIT IN THE WORD

ADJWS::	PUSHJ	P,SAVE2##	;SAVE P1 & P2
	MOVSI	P1,(IORM T1,(T4)) ;SET ARG  FOR ADJWS1
IFE ..UPMI-..UPTI,<		;IF BOTH BITS IN SAME WSBTAB WORD
	MOVE	T3,[..UPMB!..UPTB] ;GET THE BITS
	IORM	T3,WSBTAB+..UPMI ;MAKE SURE BITS FOR UPM AND UPT ON IN WSBTAB
>; END IFE
IFN ..UPMI-..UPTI,<		;IF BITS IN DIFFERENT WSBTAB WORDS
	MOVE	T3,[..UPMB]	;GET UPM BIT
	IORM	T3,WSBTAB+..UPMI ;SET IT
	MOVE	T3,[..UPTB]	;GET UPT BIT
	IORM	T3,WSBTAB+..UPTI ;SET IT
>; END IFN
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,J		;SAVE J
	MOVE	J,.USJOB	;JOB NUMBER
	SKIPN	T2,.USREL	;NON-CONTIGUOUS?
	HLRZ	T2,JBTADR##(J)	;NO, GET JBTADR
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,FNSPCS##	;FIND SEGMENT
	  JRST	VRTSZ1		;ONLY SHARABLE OR SPY
	HRRZS	J		;CLEAR JUNK
	HLRZ	T1,JBTADR##(J)	;YES, GET ITS SIZE
	ADD	T2,T1		;LOW+HIGH SIZES
VRTSZ1:	POP	P,T1		;RESTORE T1
	LSH	T2,W2PLSH
	ADD	T2,.USNCR	;AND NZS PAGES
	ADD	T2,.USMEM	;+NO OF NON-CONTIG PAGES
	AOJA	T2,JPOPJ##	;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 #
	ANDI	T3,MXSECN	;KEEP ONLY SECTION #
	PUSHJ	P,GETREL	;GET LOGICAL .USREL
	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
	MOVE	T1,J		;PUT SEGMENT # IN T1
	PUSH	P,T1		;SAVE IT
	MOVE	J,.USJOB	;GET CURRENT JOB #
	PUSHJ	P,FNDHSB##	;GET HIGH SEG DATA BLOCK
	  XCT	NSS##		;NOT FOUND
	PUSHJ	P,HSVAD##	;COMPUTE THE EXTENT OF THE HIGH SEGMENT
	POP	P,J		;RESTORE HIGH SEGMENT #
	DMOVEM	T1,.USTMP+3	;SAVE VALUES FROM HSVAD
	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
	PUSH	P,T3		;SAVE SECTION #
	JRST	VIRCH5		;NO, LOW SEG VIRTUAL CORE
;HERE IF CAN GET PHYSICAL CORE
VIRCH3:	PUSH	P,T3		;SAVE SECTION #
	CAIG	J,JOBMAX##	;HIGH SEG?
	JRST	VIRCH4		;NO
	SKIPN	T2,.USTMP+3	;(T1 STORED FROM PREV CALL TO HSVAD)
	MOVE	T2,.USTMP+4	;IF ZERO (T2 STORED FROM PREV CALL TO HSVAD)
	ADD	T1,.USTMP+4	;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
	POP	P,T3		;SECTION #
	LSH	T3,S2PLSH	;CONVERT TO PAGE #
	IORI	T2,(T3)		;REAL PAGE TO CREAT AND REMAP
	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
	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	VIRC19
;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
	MOVE	T1,J		;SEG # TO T1
	PUSH	P,J		;SAVE J
	MOVE	J,.USJOB	;POINT J AT JOB
	PUSHJ	P,FNDHSB##	;FIND SEGMENT
	  JRST	JPOPJ##		;?
	LDB	T1,[PSG2LH+.HBSG2(T1)] ;SECTION HIGH SEG IS IN
	TRO	T1,(PG.GAF)	;SPECIFY WE KNOW SECTION
	HRLM	T1,.JDAT+JOBUAL+3 ;SET SECTION
	POP	P,J		;RESTORE J
	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:	MOVEM	T2,.USTMP	;SAVE ".USREL"
	ADJSP	P,2		;ALLOCATE SPACE FOR HSBS
	SSXE	T1,(T3)		;SET PCS SECTION
	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
	PUSH	P,T3		;SAVE T3
	MOVSS	T3		;SECTION #
	PUSH	P,J		;SAVE J
	PUSHJ	P,GTRSGN##	;IN THIS SECTION
	  JRST	VIRC11		;ONLY SPY SEGS
	JUMPE	J,VIRC11	;NO SEG RELEVANT
	TLZ	J,-1^!SPYSEG	;CLEAR ALL BUT SPYSEG (IFIW)
	SKIPL	J		;SPY SEG?
	SKIPA	T2,JBYHSO##	;NO, GET ORIGIN FROM JBTUPM
	MOVE	T2,[PSPOLH+.HBSPO(T1)]
	LDB	T2,T2		;GET ORIGIN
	MOVEM	T1,-2(P)	;SAVE FIRST HIGH SEG BLOCK ADDR
	MOVEI	T3,-1		;GET HIGHEST SEGMENT IN ADDRESS SPACE
	HRL	T3,-1(P)	;SECTION #
	MOVE	J,.USJOB	;JOB #
	PUSH	P,T2		;SAVE ORIGIN OF FIRST SEG
	PUSHJ	P,GTRSGN##	;GET HIGHEST SEGMENT IN SECTION
	  JFCL			;DON'T CARE
	POP	P,T2		;RESTORE T2
	JUMPL	J,[LDB  T4,[PSPOLH+.HBSPO(T1)] ;GET ORIGIN
		   JRST VIRCH6]	;PROCEED
	HRRZS	J		;GET PARAMETERS FROM HIGH SEG DATA BASE
	LDB	T4,JBYHSO##	;ORIGIN
	HLRZ	J,JBTADR##(J)
VIRCH6:	LSH	J,W2PLSH	;CONVERT TO HIGHEST PAGE
	ADDI	T4,1(J)		;FIRST PAGE NOT IN HS
	MOVEM	T1,-3(P)	;SAVE HIGHEST HSB ADDR
	POP	P,J		;RESTORE J
	POP	P,T1		;AND SECTION
	MOVE	T3,T1		;SECTION
	PUSHJ	P,GETADR	;GET JBTADR FOR SECTION
	CAMN	T3,.USTMP	;IS ".USREL" EQUAL TO "JBTADR" FOR SECTION?
	JRST	VIRCH7		;YES, JUST DELETE TO HIGH SEG
	AOS	T3		;CONVERT TO PAGE
	LSH	T3,W2PLSH
	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
	LSH	T1,S2PLSH	;CONVERT TO PAGE
	IORI	T4,(T1)		;SET SECTION IN PAGE #
	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 HI SEG TO WORRY ABOUT
VIRC11:	POP	P,J		;RESTORE J
	POP	P,T1
	MOVE	T3,T1		;SECTION
	PUSHJ	P,GETADR	;GET JBTADR FOR SECTION
	AOS	T2,T3		;GET THOSE OFF-BY-ONES
	LSH	T2,W2PLSH	;CONVERT TO PAGES
VIRCH7:	SETZM	(P)		;DON'T HAVE TO DO ANOTHER SET OF UUOS
	LSH	T1,S2PLSH	;CONVERT TO PAGE
VIRC12:	SETZM	.JDAT+JOBUAL##+6 ;NO SECOND PAGE UUO
VIRC13:	IORI	T2,(T1)		;SET SECTION #
	HRRZ	T3,.JDAT+JOBUAL##+1 ;BASE PAGE
	SUBI	T2,(T3)		;# OF PAGES TO DELETE
VIRC35:	MOVNM	T2,.JDAT+JOBUAL##
	PUSH	P,T1		;SAVE SECTION PAGE ADDRESS
	PUSHJ	P,VIRC14	;DO THE FIRST SET OF UUOS
	  JRST	[ADJSP	P,-3	;FIX STACK
		 POPJ	P,]	;RETURN
	POP	P,T3		;RESTORE SECTION (PAGE)
VIRC31:	POP	P,T1		;FIRST HSB
	SKIPE	T1		;ANY TO DO AT ALL?
	CAMN	T1,(P)		;OR ONLY ONE HIGH SEG?
	JRST	TPOPJ1##	;ONE OR LESS HIGH SEGS
	PUSHJ	P,HSVAD##	;GET ADDRESS LIMITATIONS OF HIGH SEG
	AOS	T4,T1		;FIRST ADDRESS NOT IN THIS HIGH SEG
	LSH	T4,W2PLSH	;CONVERT TO PAGE
	TLO	T4,(PG.GAF!PG.IDC) ;TURN ON DELETE AND IDC
	IORI	T4,(T3)		;PUT IN SECTION
	LSH	T3,P2SLSH	;CONVERT TO SECTION
	MOVEM	T4,.JDAT+JOBUAL##+1 ;SET FIRST PAGE TO DELETE
	PUSHJ	P,GTNSGN##	;GET NEXT HIGH SEG ABOVE THIS
	PUSH	P,T1		;SAVE THE HSB ADDR
	PUSHJ	P,HSVAD##	;GET ADDRESS LIMITATIONS OF THIS SEG
	LSH	T2,W2PLSH	;FIRST PAGE OF THIS HIGH SEG
	HRRZ	T4,.JDAT+JOBUAL##+1 ;GET STARTING PAGE TO DELETE AT
	LSH	T3,S2PLSH	;CONVERT TO SECTION
	IORI	T2,(T3)		;PUT IN SECTION
	SUBI	T2,(T4)		;# OF PAGES TO DELETE
	JUMPE	T2,VIRC31	;NOTHING TO DO
	MOVNM	T2,.JDAT+JOBUAL## ;SET # OF PAGES TO DO
VIRC32:	POP	P,T4		;GET HSB
	CAMN	T4,(P)		;IS THIS THE HIGHEST SEGMENT?
	JRST	[SETZM	.JDAT+JOBUAL##+6 ;NO SECOND UUO
		 ADJSP	P,-1	;FIX STACK
		 PJRST	VIRC14]	;EXIT
	AOS	T4,T1		;FIRST PAGE NOT IN THIS HIGH SEG
	TLO	T4,(PG.GAF!PG.IDC)
	IORI	T4,(T3)		;PUT IN SECTION
	MOVEM	T4,.JDAT+JOBUAL##+2
	LSH	T3,P2SLSH	;CONVERT TO SECTION AGAIN
	PUSHJ	P,GTNSGN##	;NEXT HIGH SEG ADDRESS-WISE IN THIS SECTION
	PUSH	P,T1		;SAVE HSB ADDR
	PUSHJ	P,HSVAD##	;GET LIMITS OF HIGH SEG
	LSH	T2,W2PLSH	;FIRST PAGE OF THIS HIGH SEG
	HRRZ	T4,.JDAT+JOBUAL##+2 ;LAST PAGE OF PREVIOUS
	LSH	T3,S2PLSH	;BACK TO PAGE
	IORI	T2,(T3)		;PUT IN SECTION
	SUBI	T2,(T4)		;# OF PAGES TO DELETE
	JUMPE	T2,VIRC32	;SKIP TO NEXT HIGH SEG
	MOVE	T1,T3		;SECTION (PAGE)
	JRST	VIRC35
;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:	PUSH	P,J		;SAVE J
	MOVE	J,.USJOB
VIRC20:	PUSHJ	P,VIRC14
	  CAIA
	AOS	-1(P)
	POP	P,J		;RESTORE J
	MOVE	R,JBTADR##(J)
	POPJ	P,

;SUBROUTINE TO COMPUTE .USREL (JBTADR) FOR SEGMENT IN J BASED
;ON SECTION NUMBER IN T3 (IF LOW SEG).  R IS ASSUMED SET UP FOR
;JOB OR SEGMENT (SECTION 0)

GETREL:	EXCH	T3,T4		;SAVE T4, PUT SECTION # IN T4
	PUSHJ	P,RSECT4	;GET SECTION #
	  JFCL			;CATCH NON-EX SECTION LATER
	EXCH	T3,T4		;RESTORE T4 AND PUT SECTION IN T3
	CAIG	J,JOBMAX##	;IS THIS A HIGH SEG?
	SKIPN	T2,.USREL	;NO, IS S0 LOW SEG CONTIGUOUS?
	HLRZ	T2,R		;HIGH SEG OR CONTINGUOUS S0 SPACE
	JUMPE	T3,CPOPJ##	;IF SECTION 0, DONE
	CAIG	J,JOBMAX##	;AGAIN, WAS IT LOW SEG?
	SKIPN	T2,.UPMP+SECTAB(T3) ;DOES SECTION EXIST?
	POPJ	P,		;NO, AVOID IME AND RETURN HIGHEST ADDR AS 0
	HRRZ	T2,T3		;GET SECTION #
	LSH	T2,S2PLSH	;CONVERT TO PAGE #
	SE1ENT			;MUST ENTER SECTION 1 TO REFERENCE MAPS
GETRL1:	SKIPE	@[IW MS.MAP,UMAPS(T2)] ;DOES THIS ENTRY EXIST?
	AOSA	T2		;YES, STEP TO NEXT
	JRST	GETRL3		;ENTRY DOESN'T EXIST, STEP BACK
	TRNE	T2,HLGPNO	;WANDER OFF THE END OF THE SECTION?
	JRST	GETRL1		;NO, CHECK NEXT ENTRY
GETRL3:	LSH	T2,P2WLSH	;CONVERT TO FIRST NON-EX WORD
	HRRZS	T2		;CLEAR SECTION
	SOJA	T2,CPOPJ##	;CONVERT TO HIGHEST ADDR AND RETURN


;SUBROUTINE TO RETURN JBTADR (LH) IN T3.  INPUT IS SECTION # IN T3
;ASSUMES R, J SET UP FOR SECTION 0

GETADR:	PUSH	P,T2		;SAVE T2
	EXCH	T3,T4		;SAVE T4 & PUT SECTION # THERE
	PUSHJ	P,RSECT4	;RESOLVE SECTION
	  JFCL			;DON'T CARE NOW
	EXCH	T4,T3		;RESTORE T4, PUT SECTION IN T3
	POP	P,T2		;OK TO RETORE T2 NOW
	SKIPN	.UPMP+SECTAB(T3) ;SECTION EXIST?
	POPJ	P,		;NO, HIGHEST ADDR IS 0
	JUMPN	T3,GETAD1	;SECTION 0?
	HLRZ	T3,R		;YES, GET IT FROM R
	POPJ	P,
GETAD1:	SE1ENT			;NEED TO BE IN S1 TO ACCESS MAPS
	PUSH	P,T1		;SAVE T1
	MOVE	T1,T3		;SECTION #
	LSH	T1,S2PLSH	;CONVERT TO PAGE #
	TRO	T1,HLGPNO	;HIGHEST POSSIBLE PAGE IN SECTION
GETAD2:	SKIPE	@[IW MS.MAP,UMAPS(T1)] ;PAGE EXIST?
	PUSHJ	P,TPNHS		;HIGH SEG PAGE?
	TRNN	T1,HLGPNO	; HS OR NX - FALLING OFF BOTTOM OF SECTION
	SKIPA	T3,T1		;PUT HIGHEST EXISTENT PAGE IN T1
	SOJA	T1,GETAD2	;CHECK PREVIOUS PAGE
	LSH	T3,P2WLSH	;CONVERT TO WORD ADDR
	HRRZS	T3		;GET ONLY SECTION RELATIVE PORTION
	SKIPE	@[IW MS.MAP,UMAPS(T1)] ;IF PAGE DIDN'T EXIST
	PUSHJ	P,TPNHS		;OR WAS PART OF HIGH SEG
	  JRST	TPOPJ##		;THEN DON'T PUT IN PG.BDY
	TRO	T3,PG.BDY	;HIGHEST ADDRESS IN SECTION
	JRST	TPOPJ##		;RESTORE T1 AND RETURN
;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,.HBSGN(T2)	;YES, IS THERE A HIGH 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]
	MOVEI	T2,UP.NVS	;NOT VIRTUAL WHEN SWAPPED BIT
	SKIPN	.USWLP		;IF .UPWLP WENT TO ZERO,
	ANDCAM	T2,.USBTS	;CLEAR THE BIT
	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,PG.BDY	;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,PG.BDY	;ABOUT TO GO OVER SECTION BOUNDARY?
	TRCN	T4,PG.BDY	;(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
	PUSH	P,T1		;ARG
	MOVEI	T1,(J)		;JOB #
	MOVE	J,.USJOB	;LOAD JOB #
	PUSHJ	P,FNDHSB##	;GET SEG DATA BLOCK
	  JRST	[POP	P,T1	;RESTORE T1
		 JRST	JPOPJ1##] ;NO OVERLAP
	MOVE	P1,T1		;SEG DATA BLOCK ADDR TO P1
	POP	P,T1		;RESTORE T1
	LDB	P2,[PSG2LH+.HBSG2(P1)] ;GET SECTION
	CAIE	P2,(T1)		;SECTION DESIRED?
	JRST	JPOPJ1##	;NO, NO OVERLAP THEN
	LDB	P1,JBYHSO##	;LOWEST PAGE IN SEGMENT
	LSH	P1,P2WLSH	;WORD ADDR
	HLRZ	P2,JBTADR##(J)	;HIGHEST ADDR IN SEGMENT
	POP	P,J		;RESTORE J
	HLRZ	P3,T3		;HIGHEST ADDRESS IN THE RANGE
	CAIL	P3,(P1)
	CAIGE	P2,(T3)
	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

ZERHGH::SE1ENT
	CAILE	J,JOBMAX##	;A HIGH SEGMENT?
	JRST	CPOPJ1##	;YES, KISER CAN ZERO THE PAGES
	PUSH	P,J		;SAVE THE JOB NUMBER
	PUSH	P,T2		;SAVE HIGHEST ADDRESS ALLOCATED
	MOVEI	T2,JBTSGN##-.HBLNK(J) ;POINT TO FIRST SEG
ZERHG0:	HRRZ	T2,.HBLNK(T2)	;NEXT HIGH SEGMENT
	JUMPE	T2,[POP  P,T2	;RESTORE T2
		    JRST JPOPJ1##] ;NO NON-SHARABLE SEGMENTS, LET CORE1 ZERO
	SKIPLE	J,.HBSGN(T2)	;IS SEGMENT A SPY SEG?
	TLNE	J,SHRSEG	;NO, IS IT NON-SHARABLE?
	JRST	ZERHG0		;IT'S SPY OR SHARABLE
	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
	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
	HRRZS	T1,T2		;CLEAR BOTH LEFT HALVES
	PUSHJ	P,LKPSF		;REMOVE PAGE FROM JOB
	MOVEI	T3,PAGSNQ##	;QUEUE TO ADD TO
	PUSHJ	P,ADDPTQ	;PUT ON THE QUEUE
IPCRM9:	SSX	T2,MS.MEM	;POINT TO MEMTAB SECTION
	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
	.CREF	MT.DAD		;(THIS CLEARS THE DISK ADDRESS)
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
	PUSHJ	P,GVIPCP	;RETURN THE PAGE IF NOT ALREADY RETURNED
				; 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
;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
	PUSHJ	P,FNDPDS##	;SET UP PDB FOR SIZE CHECKS
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,JBYSSA##	;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)
	TLO	P1,(PM.AAB)	;MAKE SURE ACCESS ALLOWED
	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,
	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
	MOVEI	T1,(T2)		;GET HIGH SEG #
	PUSHJ	P,FNDHSB##	;GET SEG DATA BLOCK
	  XCT	NSS##		;NO SUCH HIGH SEGMENT
	LDB	T1,[PSG2LH+.HBSG2(T1)] ;GET SECTION HIGH SEG IS IN
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,FLMCOM	;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,TPNHS		;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?
	PUSHJ	P,[MOVE   T1,.JDAT+SGAEND## ;GET FLAGS
		   TLNE   T1,GTSGO## ;IF SEGOP
		   POPJ   P,	; DON'T DELETE ANY SEGMENTS
		   HRRZ   T1,P2	;NEW STARTING ADDRESS
		   LSH    T1,P2SLSH ;CONVERT TO SECTION #
		   PUSHJ  P,SVPCS## ;SET AS PCS SECTION
		   SETZ   T1,	;KILL ALL SEGS THAT SECTION
		   S0JRST KILHSH##]
	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:	TLNN	P4,(1B1)	;WANT NEW HIGH SEG?
	JRST	NREM4A		;YES
	PUSHJ	P,FNSPCS##	;GET SEGMENT
	  JRST	PSHERR		;SHARABLE NOT ALLOWED
	JUMPN	T1,NREM4D	;HAVE ONE (GET NEW ONE IF NONE)
NREM4A:	PUSHJ	P,FNDSGN##	;FIND A SEGMENT NUMBER FOR THE JOB'S NEW HI SEG
	  JRST	NFSERR		;NO FREE SEGMENT #S

;AT THIS POINT, J HAS THE SEGMENT NUMBER WE ARE DIDDLING WITH AND
;T1 POINTS TO THE JOB'S SEGMENT DATA BLOCK (MAY NOT BE INITIALIZED IF
;A NEW SEGMENT)

NREM4D:	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,[PSG2LH+.HBSG2(T1)] ;STORE SEGMENT SECTION
	ROT	P2,S2PLSH	;MOVE BACK
	TLNE	P4,(1B1)	;ADDING TO EXISTING HS?
	JRST	[LDB	T2,[PHSSLH+.HBHSZ(T1)] ;YES, PICK UP OLD SIZE
		 ADDI	T2,(P3)	;NEW SIZE
		 DPB	T2,[PHSSLH+.HBHSZ(T1)] ;SET IT
		 JRST	NREMA5 ] ;DON'T AFFECT ORIGIN
	MOVE	T2,P2		;GET NEW STARTING PAGE NUMBER
	LSH	T2,P2SLSH	;STARTING SECTION NUMBER
	DPB	T2,[PSG2LH+.HBSG2(T1)]	;STORE IT AS HIGH SEG ORIGIN FOR THIS USER
	DPB	P3,[PHSSLH+.HBHSZ(T1)]	;STORE THE NEW HIGH SEGMENT'S SIZE
;HERE, IF THE SEGMENT IS SHARABLE, REMOVE THE PAGES FROM THE JOB'S
;WORKING SET AND PAGTAB CHAIN AND PUT THEM IN THE SECONDARY MAP
;PAGE OBTAINED BELOW

NREMA5:	PUSH	P,T1		;SAVE SEGMENT DATA BLOCK ADDRESS
	JUMPL	P4,NREMA7	;JUMP IF NON-SHARABLE
	MOVEI	T1,(P3)		;NUMBER OF SLOTS REQUIRED IN MAP
	EXCH	J,-1(P)		;GET SEGMENT #
	PUSHJ	P,GTHMAP##	;GET HIGH SEG MAP
	  JRST	[POP	P,T1	;FIX STACK
		 POP	P,J	;RESTORE J
		 JRST	NCRERR]	;ERROR
	PUSH	P,P2		;SAVE P2
	MOVE	P2,T1		;MAP ADDR
	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
	PUSH	P,[0]		;WHERE FIRST PHYSICAL PAGE OF HIGH SEG IS

;HERE TO REMOVE PAGES AND MOVE THEM INTO SECONDARY MAP

NREMA6:	PUSHJ	P,GTPME		;GET THE CONTENTS OF THE USER'S MAP
	MOVEM	T2,(P2)		;SAVE PTR IN 2NDARY MAP
	MOVSI	T3,(<PM.NAD^!<PM.AAB!PM.COR>>) ;ACCESS BITS
	AND	T3,T2		;ONLY BITS IN T3
	TLZ	T2,(PM.NAD)	;AND ONLY ADDR IN T2
	TLO	T3,<(<PM.ICD>B2)>(P2) ;CONVERT TO INDIRECT POINTER
	HRRI	T3,JBTUPM##-SPTTAB##(J) ;SPT SLOT WHERE 2NDARY MAP IS
	MOVEM	T3,(T4)		;SAVE NEW POINTER IN USER'S MAP
	AOS	P2		;INCREMENT OFFSET
	PUSHJ	P,LKPSF		;LINK PAST THE PAGE IN PAGTAB
	EXCH	T1,(P)		;GET OLD PREDECESSOR
	JUMPE	T1,NREM6A	;NONE
	HRRM	T2,@[IW MS.MEM,PAGTAB(T1)] ;LINK FORWARD
	HRRM	T1,@[IW MS.MEM,PT2TAB(T2)] ;THEN POINT BACK TOO
NREM6A:	MOVE	T1,(P)		;GET T1 BACK
	HRRZM	T2,(P)		;NEW LAST PAGE IN SEGMENT
	AOBJN	T1,NREMA6	;AND LOOP UNTIL ALL HIGH SEGMENT PAGES
				; ARE IN PAGTAB IN THE SAME ORDER THAT THEY APPEAR
	POP	P,(P)		;FIX STACK
	EXCH	J,-2(P)		;SAVE SEG # AND GET JOB # BACK
	POP	P,P2		;AND P2
				; IN THE JOB'S MAP
	TLZ	P4,(1B0)	;HIGH SEG IS SHARABLE
;HERE TO MOVE THE PAGES TO THEIR NEW VIRTUAL ADDRESSES IN USER SPACE

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	NREM10		;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
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
	SKIPE	.USVRT		;VIRTUAL?
	SKIPL	P4		;YES, DON'T CHANGE PM.WRT (SWAP OUT WILL FIX IT)
	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
	CAIL	T1,(P1)		;MOVING PAGES DOWN?
	AOBJP	P1,NREM14	;BUMP SOURCE,,DESTINATION PAGES
				;(MUST ALWAYS JUMP)
NREM13:	SUB	P1,[1,,1]	;DECREMENT SOURCE,,DESTINATION
NREM14:	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
	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,-1(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
	SETZB	P2,JBTIMO##(J)	;CLEAR OUTPUT SIZE AND DON'T DECREAS LOW SEG
NREM15:	DPB	P2,IMGIN##	;SET IMGIN SIZE FOR HIGH SEG (0 FOR NON-SHR)
	JUMPE	P2,NREM16	;IF ZERO (ONLY NON-SHARE CASE) SKIP SOME
	MOVE	J,.USJOB	;CURRENT JOB NUMBER
	LDB	T1,IMGIN##	;DECREASE LOW SEGMENT SIZE BY THE NUMBER OF
	SUBI	T1,(P2)		; PAGES MAPPED INTO THE HIGH SEGMENT
	DPB	T1,IMGIN##
NREM16:	MOVE	T1,(P)		;SEGMENT DATA BLOCK ADDRESS
	LDB	T1,[PHSSLH+.HBHSZ(T1)] ;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
	MOVE	J,-1(P)		;SEGMENT #
	MOVSM	T1,JBTADR##(J)	;SAVE HIGH PROTECTION,,RELOCATION
	JUMPGE	P4,NREM32	;GET FIRST PAGE OF SEG FROM HS MAP IF SHARABLE
	MOVE	T1,(P)		;SEG DATA BLOCK ADDR AGAIN
	LDB	T2,[PSG2LH+.HBSG2(T1)] ;SECTION HIGH SEG IS IN
	LDB	T1,JBYHSO##	;GET THE HIGH SEGMENT ORIGIN VIRTUAL PAGE
	LSH	T2,S2PLSH	;SECTION TO PAGE
	TROA	T1,(T2)		;NO, MAKE FULL PAGE #
NREM32:	SKIPA	T2,@JBTVAD##(J)	;GET ENTRY FROM HIGH SEG MAP
	PUSHJ	P,GTPME		;GET THE HIGH SEGMENT ORIGIN PHYSICAL PAGE
	DPB	T2,JBYHSA##	;STORE FOR POSTERITY
	HRLI	T2,(<PM.DCD>B2+PM.WRT+PM.CSH+PM.PUB)
	MOVEM	T2,.UPMP+.UMVJD
	CLRPT	.VJDT		;MAKE THE NEW MAPPING VISIBLE
	MOVE	T1,.JDAT+SGANAM## ;FILE SEGMENT CAME FROM
	SKIPN	.VJDT+.JBHNM##	;ALREADY A NAME IN .JBHRL?
	JRST	NREM33		;YES, LEAVE IT ALONE
	JUMPE	T1,NREM34	;JUMP IF JUST REMAP (SEGMENT NOT FROM A FILE)
	MOVE	T2,.JDAT+SGAEND## ;FLAGS
	TLNE	T2,GTSGO##	;SEGOP? (USER CAN PROVIDE A NAME)
	TLNE	T2,GTHGH##	;SEGOP, REMAP FUNCTION?
	JRST	NREM34		;NO, USER DID NOT SUPPLY A NAME
NREM33:	MOVEM	T1,.VJDT+.JBHNM## ;YES, STORE THE NAME IN .JBHNM
NREM34:	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:	SKIPE	.USVRT		;VIRTUAL?
	SKIPL	P4		; AND A NON-SHARABLE HIGH SEGMENT?
	JRST	NREM18		;NO
	PUSHJ	P,XPANDH##	;YES, MUST SWAP OUT THE JOB TO GET .USWLP RIGHT
IFN FTMP,<
	PUSHJ	P,DIFMM##	;GIVE UP AND REMEMBER MM
>
	PUSHJ	P,WSCHED##	;WAIT UNTIL THE JOB GOES OUT AND COMES BACK IN
IFN FTMP,<
	PUSHJ	P,UIFMM##	;RESTORE MM
>
NREM18:	POP	P,T1		;RESTORE SEGMENT DATA BLOCK ADDR
	POP	P,J		;RESTORE SEGMENT #
	HLRZM	R,.USHVA	;FOR ADDRESS CHECKING AT INTERRUPT LEVEL
	PJRST	FIXMJ1		;CLEAR THE A.M. AND SKIP RETURN
;SUBROUTINE TO CHANGE A HIGH SEG'S CORE ADDRESSES TO DISK ADDRESSES
;IN THE HIGH SEG MAP.  CALLED WITH J=HIGH SEG NUMBER

HCTOD::	SE1ENT				;ENTER S1
	PUSHJ	P,SAVE4##		;SAVE SOME ACS
	PUSH	P,J			;AND J
	HRRZS	J			;CLEAR JUNK
	LDB	P1,JBYVAD##		;VIRTUAL ADDRESS OF MAP
	LDB	P2,IMGIN##		;# OF SLOTS IN USE IN MAP
HCTOD1:	HLLZ	P3,(P1)		;BITS IN P3
	HRRZ	P4,(P1)		;PAGE # IN P4
	LDB	P4,[POINT MT.SAD,@[IW MS.MEM,MEMTAB(P4)],^L<MT.DAD>+MT.SAD-1]
	IOR	P3,P4		;PUT DISK ADDR IN
	TLZ	P3,(<PM.ACD>B2!PM.COR) ;CLEAR ACCESSIBILITY
	MOVEM	P3,(P1)		;STORE UPDATED MAP
	SOJLE	P2,JPOPJ##	;EXIT IF NO MORE ENTRIES
	AOJA	P1,HCTOD1	;YES
	SUBTTL	UUOCON  INTERFACE WITH UUO HANDLER AND IOCSS

	$CSUB

;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.

	$HIGH
;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,PG.BDY	;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
	S0JRST	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?
	  S0JRST	ADRERR##	;NO, PAGE DOESN'T EXIST, HI SEG PAGE, OR SPY PAGE
	  JRST	UUOFLT		;PAGE FAULT
TRNGE1:	EXCTUX	<SKIP	(T1)>	;ENSURE ADDRESS IS ACCESSIBLE AND WRITABLE
	  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

	$CSUB

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?
	JRST	@[MCSEC0+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

	$HIGH

;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	[PUSHJ P,WLPFLT	;YES, HANDLE SPECIALLY
		   POPJ P,	;REALLY A WRITE VIOLATION
		 USERAC		;GIVE HIM HIS ACS BACK
		 XJRSTF .USPFP]	;RETURN TO THE USER - PAGE IS WRITE ENABLED

;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
	MOVE	T1,.USMUP	;GET SINGLE WORD PC (MUST BE S0)
	HLL	T1,.USMUO	;AND FLAGS
	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?
	AOSA	SYSIWS##	;COUNT "IN WORKING SET" FAULT
	AOSA	SYSNIW##	;COUNT "NOT IN WORKING SET" FAULT
	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##	;TALLY UP OLD COUNTER TOO
	MOVE	T1,J		;GET JOB #
	PUSHJ	P,FPDBT1##
	  TDZA	T1,T1		;HUH?
	MOVE	T1,.PDVRT##(T1)
	PUSHJ	P,PUTWD1##	;STORE IN WD 4
	PUSHJ	P,PSIIVA##	;GET INTERRUPT VECTOR ADDR

	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
	HLLZM	T1,.USMUO	;SAVE FLAGS
	HRRZM	T1,.USMUP	;AND 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,
;SUBROUTINE TO WRITE ENABLE A PAGE IF ITS WRITE LOCKED
;CALL WITH T1=VIRTUAL ADDRESS TO BE WRITE ENABLED, ALWAYS RETURNS CPOPJ

CHKWLP::SKIPN	.USWLP		;NOT WRITE LOCKED IF NOT VIRTUAL
	POPJ	P,		;SAVE SOME TIME
	PUSH	P,T1		;SAVE ADDRESS
	EXCTUU	<MAP T1,(T1)>	;MAP THE VIRTUAL ADDRESS
	PUSHJ	P,FLTCHK	;BAD PAGE?
	  STOPCD	TPOPJ##,DEBUG,BDP, ;++BAD PAGE
	TLNE	T1,(PM.WRT)	;PAGE WRITABLE ALREADY?
	JRST	TPOPJ##		;YES, NOTHING TO DO
	EXCH	T3,(P)		;ARGUMENT FOR WLPFLT
	PUSHJ	P,WLPFLT	;WRITE ENABLE THE PAGE
	  STOPCD	TPOPJ##,DEBUG,CWP, ;CAN'T WRITE-ENABLE PAGE
	JRST	T3POPJ##	;RESTORE T3 AND RETURN

;HERE WHEN THE PAGE FAULT IS A WRITE VIOLATION

WLPFLT::SE1ENT			;MUST BE IN SECTION 1 TO MAKE PAGE REFERENCES
	PUSH	P,J		;SAVE J
	MOVE	J,.USJOB	;NEED J TO BE SETUP FOR TPNHX
	MOVE	T1,T3		;PAGE FAIL WORD
	LSH	T1,W2PLSH	;PAGE #
	ANDI	T1,HLGPGS	;CLEAR EXTRANEOUS JUNK
	MOVSI	T4,UWPOFF	;BIT TO TEST IF PAGE IN HIGH SEG
	PUSHJ	P,TPNHX		;IS PAGE IN A HIGH SEG?
	  TDNE	T4,.HBSGN(T2)	;YES, IS SEGMENT WRITABLE?
	CAIA			;NOT IN A HIGH SEGMENT OR WRITABLE
	JRST	JPOPJ##		;IN A WRITE LOCKED HIGH SEGMENT
IFN FTPEEKSPY,<
	PUSHJ	P,TSSPT		;A SPY PAGE?
	  CAIA			;NO, OK TO WRITE ENABLE IT
	JRST	JPOPJ##		;YES, CAN'T WRITE ENABLE PAGE
>
	SKIPE	.USWLC		;DID USER WRITE-LOCK SOME PAGES?
	JRST	JPOPJ##		;YES, MONITOR CAN'T HAVE THEM THEN
	MOVE	T1,T3		;GET PAGE FAIL PAGE AGAIN
	LSH	T1,W2PLSH
	ANDI	T1,HLGPGS	;CLEARING JUNK
	PUSHJ	P,GTPME		;GET POINTER
	TLNE	T2,(<PM.ACD>B2)	;MAKE SURE ITS ACCESSIBLE
	TLOE	T2,(PM.WRT)	;MAKE PAGE WRITABLE
	STOPCD	JPOPJ##,DEBUG,PAW, ;PAGE ALREADY WRITE-ENABLED
	MOVEM	T2,(T4)
	SKIPN	.USWLP		;DON'T OWN ANY DSK SPACE IF NO WL PAGES
	JRST	WLPFL1		;SKIP ON
	AOS	SYSWLF##	;COUNT NUMBER OF MODIFIED PAGE FAULTS
	PUSHJ	P,RTNDPG	;RETURN SWAPPING SPACE
WLPFL1:	POP	P,J		;RESTORE J
USRFLX:	CLRPGT
	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::HLLZ	T1,USRPC##
	IOR	T1,USRPC##+1
	TLNE	T1,(XC.USR)
	JRST	GETDD1
	HLLZ	T1,.JDAT+JOBPD1##
	IOR	T1,.JDAT+JOBPD1##+1
GETDD1:	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
				;AS IF IT REALLY MATTERS
	PUSHJ	P,GETXXX	;GO GET IT
	  SKIPA			;ERROR
	JRST	GETDD2		;GOT IT
	PUSHJ	P,CNGDDT	;PRINT ERROR MESSAGE
	PUSHJ	P,TTYFUW##	;MAKE SURE TTY ATTACHED FOR ERROR MSG
	PUSHJ	P,PPQCRL##	;PRINT CRLF ?
	JRST	URUNSB##	;
GETDD2:	PUSHJ	P,CHKMED##	;SET MEDDLE SO CAN'T CHANGE SHARABLE HIGH SEGMENT
	MOVE	T2,.JDAT+JOBDDT## ;DDT START ADDRESS
	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
	MOVE	T1,JBTSGN##(J)	;GET SEGMENT WORD
	TLNN	T1,CONSEG	;JOB HAVE CONCEALED HIGH SEG?
	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
	  JRST	TTPOPJ##	;RESTORE AC'S IF THE WORLD FALLS APART
	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
	HLL	T1,JBTSTS##(J)	;STATUS WORD
	HLR	T1,JBTSGN##(J)	;SEGMENT WORD
	TDNE	T1,[NSHF!NSWP,,LOKSEG]
	JRST	IILERR		;YES, ILLEGAL IF LOCKED ERROR
UPAGE2:
IFN FTMP,<
	PUSHJ	P,INTLVL##	;CAN'T WAIT FOR ANYTHING IF AT CLOCK LEVEL
	  TLNE	U,UU.CP1	;CAN THIS UUO BE EXECUTED ON CPU1?
	JRST	UPAGE3		;ALREADY HAVE (CLOCK LVL) OR DON'T NEED MM
>
	SKIPL	MIGRAT		;IF WAITING TO MIGRATE IPCF PAGES,
	JRST	UPAG2B		;CONTINUE IF NO MIGRATION IN PROGRESS
	MOVSI	T1,-1
	ADDM	T1,JBTCCC##(J)	;YES, J SHOULD BE OK AT UUO LEVEL
UPAG2A:	MOVEI	T1,1		;WAIT FOR FILFND TO FINISH
	PUSHJ	P,SLEEPF##
	SKIPGE	MIGRAT##	;DONE WITH IPCF YET?
	JRST	UPAG2A		;NO
	PUSHJ	P,DECCCC##	;ALLOW JOB TO ^C AGAIN
UPAG2B:
IFN FTMP,<
	PUSHJ	P,UPMM##	;NOW GET THE JOB 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
	TLNN	U,UU.WCC	;CAN THIS UUO CAUSE THE W.S. TO CHANGE
	JRST	UPAGER		;NO, RETURN
	MOVE	T2,.JDAT+JOBPD1##+1 ;GET USER PC WITHOUT ANY FLAGS
	TLNE	T2,(SECMSK)	;PC IN SECTION ZERO?
	JRST	UPAGWS		;NO, THEN THIS IS NOT FROM PFH
	PUSHJ	P,INPFH		;YES, PFH DOING THIS UUO?
	  JRST	UPAGER		;RETURN
UPAGWS:	MOVSI	T1,(UP.WHC)	;WORKING SET HAS CHANGED BIT
	IORM	T1,.USBTS	;REMEMBER THAT
UPAGER:	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
	UU.NCL+UU.LER,,LOKPGS		;(15) LOCK SPECIFIED PAGES
	UU.NCL+UU.LER,,PAGWLK		;(16) WRITE-ENABLE/LOCK PAGES

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	R,T1
	SOJLE	P1,IALERR	;ERROR IF NO MORE ARGS
	PUSHJ	P,GETWD1##	;GET STARTING PAGE #
	SE1ENT			;ENTER SECTION 1
PAGCH1:	CAILE	T1,HLGPGS
	JRST	ILPERR		;NO
	MOVSI	P2,(1B0)	;FIRST BIT TO SET
	TDZA	P3,P3		;CLEAR MASK WORD VALUE
PAGCH2:	LSH	P2,-1		;ADVANCE BIT TO SET IN WORD
	TRNN	T1,HLGPNO	;CROSS SECTION BOUNDARY?
	PUSHJ	P,SCDCHK##	;KAF GUARD
PAGCH3:	CAILE	T1,HLGPGS	;RAN OUT OF LEGAL PAGES?
	JRST	PAGCH5		;YES, OUT OF BIT MAP NOW
	PUSH	P,T1
	PUSHJ	P,GTPACC	;GET PAGE ACCESSIBILITY BITS
	XOR	T1,P4		;DIFFERENCES BETWEEN REALITY AND FANTASY
	TDNN	T1,R		;BUT DO ANY OF THEM MATTER?
	TDO	P3,P2		;NO, THIS PAGE MATCHES
	POP 	P,T1		;RESTORE PAGE NUMBER
PAGCH4:	TRNN	P2,1		;ANY MORE ROOM IN WORD?
	AOJA	T1,PAGCH2	;YES
PAGCH5:	EXCH	P3,T1		;WORD TO DEPOSIT
	PUSHJ	P,PUTWD1##	;GIVE TO USER
	MOVE	T1,P3		;GET PAGE # BACK
	SOJLE	P1,CPOPJ1##	;USER WANT MORE (RETURN IF NO)?
	AOJA	T1,PAGCH1	;ON TO NEXT
;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			;IGNORE NON-EX RETURN
	SKIPN	T2,.UPMP+SECTAB(T1) ;GET MAP
	JRST	PAGAC8		;NON-EXISTENT
	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?
	  TLOA	U,(PA.OUT)	;NO, INDICATE THAT THE PAGE IS PAGED-OUT
	JRST	PAGA0A		;IF WSBTAB ON, NO SWEAT
	TLNE	T3,(PM.LOK)	;IF PAGE IS LOCKED,
	TLC	U,(PA.OUT!PA.LCK) ;THEN IT ISN'T IN THE WORKING SET
PAGA0A:	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:	MOVE	T2,T3		;RESTORE MAP ENTRY
IFN FTPEEKSPY,<
	TLNN	T2,(PM.SPY)	;IS THIS A SPY PAGE?
	JRST	PAGA2A		;NO, SEE ABOUT HIGH SEG
	TLNN	T2,(<PM.DCD^!PM.ICD>B2)	;VIRTUAL SPY PAGE?
	TROA	U,(T2)		;PROPAGATE PHYSICAL PAGE NUMBER
	PUSHJ	P,PAGA10	;IF VIRTUAL, HANDLE IT
	MOVE	T4,T2		;MOVE MAP ENTRY HERE
	SETZB	T2,T3		;NO HIGH SEG TO WORRY ABOUT
	JRST	PAGA1A		;MERGE WITH COMMON CODE
PAGA2A:>
	MOVE	T4,T2		;PRESERVE PAGE MAP ENTRY
	PUSH	P,T1		;SAVE T1 (NEED TO KEEP SECTION #)
	PUSHJ	P,TPNHX		;SEE IF PAGE IS IN SOME HIGH SEG
	  TLOA	U,(PA.GHI)	;IT IS, FLAG AS SUCH
	TDZA	T2,T2		;NO HIGH SEG DATA BLOCK
	SKIPA	T3,.HBSGN(T2)	;GET HIGH SEG DATA WORD
IFN FTPEEKSPY,<
	TDZA	T3,T3		;NO HIGH SEG EITHER
	TLNN	T3,SPYSEG	;HIGH SEG ACTUALLY SPY SEG?
	JRST	PAGA1B		;NO, DON'T CHANGE
	DPB	T4,[POINT <36-^L<PA.SPN>>,U,35] ;YES, GIVE PHYSICAL PAGE #
	POP	P,T1		;YES, RESTORE T1 NOW
PAGA1A:	TLOA	U,(PA.GSP!PA.CPO) ;YES, TELL USER
>
IFE FTPEEKSPY,<
	SETZ	T3,
>
PAGA1B:	POP	P,T1		;RESTORE T1
	JUMPE	T2,PAGA1C	;A LOW SEG PAGE
	TLNE	T3,SHRSEG	;CAN PAGE BE SHARED WITH ANYONE ELSE?
	TLOA	U,(PA.GSH!PA.CPO) ;YES, FLAG IT AS SHARABLE
	PUSHJ	P,[TLNN T3,UWPOFF ;IS NON-SHARABLE SEG WRITE-LOCKED?
		   TLZA T4,(PM.WRT) ;YES, MAKE SURE WE KNOW THAT
		   TLO  T4,(PM.WRT) ;MAKE SURE WE KNOW IT'S ENABLED
		   JRST CPOPJ1##] ;(MONITOR CAN'T DIDDLE WRITE ON SHARABLE HIGH SEGS)
	  TLZ	U,(PA.LCK)	;SHARABLE CAN'T BE LOCKED (FOOLED BY INDIRECT FIELD)
	SKIPLE	T3		;IF A REAL HISEG (SHARABLE OR NOT)
	DPB	T3,[POINT <36-^L<PA.SGN>>,U,35] ;THEN STORE THE SEGMENT NUMBER
PAGA1C:	SKIPE	.USWLP		;IS MONITOR WRITE-LOCKING PAGES?
	TLNE	U,(PA.GHI)	;YES, IS THIS A HIGH SEG PAGE (OK TO CHECK WRITE)
	TLNE	T4,(PM.WRT)	;HS OR NOT MONWL:  WRITABLE PAGE?
	TLOA	U,(PA.WRT)	;A WRITABLE LOW OR HIGH SEG PAGE
	TLZ	U,(PA.WRT)	;A WRITE-LOCKED PAGE
	PUSH	P,T2		;SAVE HIGH SEG DATA BLOCK ADDR
	MOVE	T2,.JDAT+JOBPD1## ;PC FLAGS OF THE PAGE ACCESSABILITY UUO
	TLNN	T2,(IC.LIP)	;UUO DONE FROM A CONCEALED PAGE?
	JRST	PAGAC5		;YES, PAGE CAN BE READ
	TLNE	T4,(PM.PUB)	;A PUBLIC PAGE?
	JRST	PAGAC5		;THEN THE PAGE CAN BE READ
	TLZ	T4,(PM.NAD)	;KEEP ONLY ADDRESS
	TLNN	U,(PA.OUT)
	CAME	T4,[PM.ZER]	;IF NOT ABZ,
	JRST	PAGAC4		;PAGE CANNOT BE READ
	TLNN	T3,SPYSEG	;IF NOT SPY,
	TLNN	T3,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
	POP	P,T4		;HIGH SEG BLOCK ADDR (OR ZERO)
	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,.HBSGN(T4)	;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
	JRST	PAGAC6		;RETURN THE BITS
PAGAC7:	TLO	U,(PA.NXP)	;PAGE IS NON-EXISTENT
PAGAC6:	MOVE	T1,U		;COPY BITS FOR RETURN
	POPJ	P,		;AND RETURN THE PAGE BITS

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+<CDBPGS##-1> ;ANY 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-<MS.MAP+UMAPS>>/PAGSIZ>-.UMORG+SECTAB>(T3)
	HRRI	T3,<MS.MAP+UMAPS>/PAGSIZ-SECTAB(T3) ;YES, ASSUME IN MS.MAP
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
	PUSH	P,T2		;MUST SAVE MAP ENTRY
	MOVSS	T2		;GET PAGE OFFSET IN CORRECT PLACE
	ANDI	T2,PG.BDY	;MASK IT DOWN
	TRO	T3,(T2)		;FORM FULL PAGE NUMBER
	POP	P,T2		;RESTORE MAP ENTRY
	JRST	PAGA9A		;RETURN THE PAGE NUMBER
> ;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	T1,PVLOCK	;BIT DENOTING PRIVILEDGES TO LOCK
	PUSHJ	P,PRVBIT##	;IS THIS USER A SUFFICIENT WHEEL?
	  SKIPA			;YES, PROCEED
	JRST	NPVERR		;NO PRIVS
	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
>
;UUO TO SET OR CLEAR WRITE-ENABLE FOR PAGES.  THIS ONLY WORKS
;FOR LOW SEG PAGES

PAGWLK:	MOVEI	T2,PA.PME!PA.PWE!PA.PWL	;PAGES TO BE WRITE-LOCKED MUST EXIST
	SE1ENT			;ENTER SECTION 1
	PUSHJ	P,PLTSN		;CHECK THE ARG LIST
	  POPJ	P,		;BAD ARG LIST
	DMOVE	P2,T2		;SAVE PAGE COUNTS
	SKIPE	.USWLP		;HAVE ANY MONITOR-LOCKED PAGES?
	PUSHJ	P,CLRWLP	;YES, MAKE ALL POSSIBLE PAGES WRITABLE
PAGWL4:	PUSHJ	P,FSTPAG	;POINT TO BEGINNING OF ARG LIST
PAGWL5:	PUSHJ	P,NXTPAG	;GET NEXT PAGE
	MOVE	T3,T1		;SAVE ARG
	PUSHJ	P,GTPME		;GET ENTRY
	JUMPL	T3,PAGWL	;LOCK THE PAGE
PAGWE:	TLON	T2,(PM.WRT)	;IF WRITE
	SOS	.USWLC		;WAS WRITE-LOCKED, TAKE OUT OF COUNT
	MOVEM	T2,(T4)		;WRITE-ENABLE THE PAGE
	SOJG	P3,PAGWL5	;CONTINUE IF MORE TO ENABLE
	JUMPG	P2,PAGWL5	;OR WRITE-LOCK
	JRST	CPOPJ1##	;GIVE GOOD RETURN

PAGWL:	TLZE	T2,(PM.WRT)	;WAS PAGE ALREADY WRITE-LOCKED?
	AOS	.USWLC		;NO, INCREMENT THE WRITE-LOCK COUNT
	MOVEM	T2,(T4)
	SOJG	P2,PAGWL5	;CONTINUE IF MORE TO WRITE-LOCK
	JUMPG	P3,PAGWL5	;OR WRITE-ENABLE
	JRST	CPOPJ1##
;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,JBYSSA##	;FIRST PAGE OF JOB
	MOVE	T2,P2		;SETUP ARGUMENTS TO ADPAGS
	PUSHJ	P,ADPAGS##	;ALLOCATE THE REQUIRED NUMBER OF PAGES
	MOVSI	P4,NSHF	;BE SURE WE DON'T SWAP
	IORM	P4,JBTSTS##(J)	;(NSWP CAN'T BE ON HERE)
;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,PGBGCR	;GET CORE
	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,PGBGCR	;GET CORE
	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:	MOVSI	T2,NSHF		;MAKE US SWAPPABLE AGAIN
	ANDCAM	T2,JBTSTS##(J)
	JUMPE	P2,PAGEB8	;GO IF NO I/O TO DO
	PUSHJ	P,PAGEIT	;PAGE THE PAGES IN
	  JRST	PIOERR		;PAGING I/O ERROR
PAGEB8:	MOVE	T1,.USNXP	;LAST VALUE OF .USNXP
	CAME	T1,[-1]		;REGULAR FORMAT?
	SOSA	T1		;NO, NEGATIVE FORMAT
	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

PGBGCR:	PUSHJ	P,GT4MR
	  CAIA			;NOT IMMEDIATELY AVAILABLE
	POPJ	P,		;RETURN WITH CORE
	PUSHJ	P,SAVT##	;SAVE EVERYTHING
	MOVSI	T1,-1		;MAKE HIM NON-CONTRL-CABLE
	ADDM	T1,JBTCCC##(J)	;..
PGBGC1:	SETZ	T1,
	PUSHJ	P,SLEEPF##	;WAIT A BIT TO SEE IF CORE APPEARS
	PUSHJ	P,GT4MR		;IS CORE NOW AVAILABLE?
	  JRST	PGBGC1		;NO, WAIT SOME MORE
	PJRST	DECCCC##	;CLEAR ^C WAIT
;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,SCDCKM	;WAIT IF AT UUO LEVEL
	  JFCL			;CLOCK LEVEL IS RUNNING OUT OF TIME ****
	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
	SKIPN	.USWLP		;IF WRITE-LOCKED PAGES, TAKE CARE OF IT LATER
	PUSHJ	P,[PUSHJ P,SAVT## ;SAVE VOLATILE ACS
		   PUSHJ P,TPAHS ;IF PAGE IS IN A HIGH SEGMENT, IT WILL GET
		     POPJ P,	; WRITE LOCKED SO DON'T GIVE BACK DISK SPACE
		   MOVE T2,-2(P);DISK ADDRESS TO BE RETURNED
		   PJRST DLTPGD];RETURN DISK SPACE
	MOVE	T2,T4		;PAGE NUMBER TO T2
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!PM.WRT) ;CORE ADDRESS+PM.WRT
	SKIPN	.USWLP		;CORE IMAGE ALREADY CONTAIN WRITE LOCKED PAGES?
	JRST	PAGI7A		;NO, PAGE DOESN'T HAVE A DSK ADDRESS
	HRRZ	T4,T2		;PHYSICAL PAGE NUMBER
	SSX	T4,MS.MEM	;INDEX INTO MEMTAB
	MOVE	T4,MEMTAB(T4)	;GET DISK ADDRESS
	TDNN	T4,[MT.DAD]	;IF PAGE IS ON "IN" QUEUE, THERE'S NO DSK ADDR
	JRST	PAGI7A		;DON'T WRITE LOCK PAGE IF NO DSK ADDRESS
	TLZ	T2,(PM.WRT)	;WRITE LOCK THE PAGE
	AOS	.USWLP		;AND COUNT UP THE NUMBER OF WRITE LOCKED PAGES
PAGI7A:	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,SCDCKM	;MAYBE WAIT IF AT UUO LEVEL
	  JFCL			;CLOCK LEVEL IS RUNNING OUT OF TIME ***
	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
	SKIPE	.USWLP		;PAGES HAVE DISK ADDRESSES?
	TLNE	T3,(PM.WRT)	;WRITE ENABLED?
	TLZA	M,40000		;NO, REMEMBER THAT
	TLO	M,40000		;YES
	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
	TLNE	M,40000		;IF PAGE IS WRITE LOCKED,
	MOVEI	T3,PAGOUQ##	; GO DIRECTLY TO "OU" QUEUE, DON'T PASS GO,
				; DON'T COLECT 200 DOLLARS
	PUSHJ	P,ADDPTQ	;PUT THE PAGE ON THE SPECIFIED QUEUE
	POP	P,T1		;RESTORE VIRTUAL PAGE NUMBER
	SSX	P2,MS.MEM	;FOR ADDRESSING MEMTAB BELOW
	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
	SKIPE	.USWLP		;PAGES HAVE DISK COPIES?
	TLNE	T2,(PM.WRT)	;PAGE WRITE LOCKED (STILL HAS A DISK COPY)?
	JRST	PAGOM4		;NO
	MOVEI	T3,0		;ZERO MEMTAB ENTRY
	EXCH	T3,MEMTAB(P2)	; AND GET DISK ADDRESS
	TDZ	T3,[PM.NAD]	;ISOLATE DISK ADDRESS
	AND	T2,[PM.BTS]	;EXTRACT ACCESS BITS
	IOR	T2,T3		;ADD IN DISK ADDRESS
	MOVEM	T2,(T4)		;STORE IN THE MAP
	SOS	.USWLP		;ONE LESS WRITE LOCKED PAGE
	JRST	PAGOM5		;NEXT PAGE
PAGOM4:	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
	.CREF	MT.DAD		;(IN PARTICULAR, THE DISK ADDRESS)
PAGOM5:	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,SYSUPT##
	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,SYSUPT##	;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

REPEAT 0,<
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,PG.BDY	;(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,SCDCKM ;SEE IF NEED TO WAIT
		   JFCL		;NEED SOME WAY OUT HERE ****
		 JRST	CHGPG2]	;LOOP FOR MORE PAGES
	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,JBYSSA##	;FIRST PAGE OF JOB
	PUSHJ	P,ADPAGS##	;ALLOCATE THE PAGES
	MOVSI	P1,NSHF	;FORCE NON-SWAPPABILITY
	IORM	P1,JBTSTS##(J)	;(NSWP CAN'T BE ON HERE)
;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	T2,[PM.WRT!PM.AAB!PM.CSH!PM.PUB+PM.ZER]	;ASSUME WRITABLE
	PUSHJ	P,TPNHS		;A HIGH SEG PAGE?
	  TLZ	T2,(PM.WRT)	;NOT WRITABLE
	MOVEM	T2,(T4)		;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,[MOVSI  T1,NSHF
		    ANDCAM T1,JBTSTS##(J)
		    HLL    P4,P1 ;HIGHEST PAGE SEEN
		    JRST   FIXADR] ;.DONE
	PUSHJ	P,SCDCKM	;SEE IF TIME TO WAIT
	  JFCL			;NEED A WAY OUT HERE ***
	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)
	MOVSI	T1,NSHF	;DON'T SWAP 'TIL READY
	IORM	T1,JBTSTS##(J)
	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,SCDCKM	;WAIT IF NECESSARY (AT UUO LEVEL)
	  JFCL			;NEED A WAY OUT FOR CLOCK LEVEL ***
	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 SWAPS IN
	MOVE	T3,T1		;PUT PAGE # BACK IN T3
	PUSHJ	P,TPNHX		;SHARABLE HS PAGE?
	  SKIPG	.HBSGN(T2)	;?
	TDZA	T2,T2
	MOVEI	T2,INSDWL-INSDWE
	MOVE	T1,T3		;RESTORE T1 TO PAGE #
	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
	MOVSI	T1,NSHF
	ANDCAM	T1,JBTSTS##(J)
	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	CRSMP5		;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
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	CRSMP5		;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,JBYSSA##	;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,JBYSSA##
	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:	PUSHJ	P,SCDCKM	;WAIT IF NECESSARY
	  JFCL			;CAN'T GET HERE--WE'RE AT UUO LEVEL
	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			;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,.HBSGN(T2)	;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			;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,[MS.MAP+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:	SETZM	.JDAT+SGANAM##	;NO NAME
	SETZM	.JDAT+SGAEND##	;ALSO NO FLAGS
SREMAP::PUSHJ	P,SAVE4##	;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
	PUSH	P,.JDAT+SGANAM##;SAVE NAME
	PUSH	P,.JDAT+SGAEND##;AND FLAGS IN CASE IOWAIT OR UPMM BLOCK
	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
>
	POP	P,.JDAT+SGAEND##;RESTORE FLAGS
	POP	P,.JDAT+SGANAM##;AND NAME
	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
	SKIPA	T2,T1		;DESTINATION PAGE TO T2
GREMA1:	PUSH	P,T1		;SAVE SOURCE PAGE
	MOVSI	T4,(1B0)	;DON'T ALLOW A USER TO CREATE A SHARABLE
	SKIPL	-1(P)		;APPEND STYLE REMAP (CHECKING SAVED T3)?
	JRST	GREMA2		;NO
	MOVMS	-1(P)		;MAYBE, MAKE IT POSITIVE
	PUSHJ	P,FNSPCS##	;JOB HAVE A NON-SHARABLE HIGH SEG IN THIS SECTION?
	  JRST	GREMA2		;NO
	JUMPE	T1,GREMA2	;NO SEGMENT AT ALL
	MOVEI	P1,GREMA3	;IF APPENDING, WE WILL EXIT HERE
	HRRZ	J,.HBSGN(T1)	;GET SEGMENT #
	LDB	T1,JBYHSO##	;GET ORIGIN PAGE OF HIGH SEG
	HLRZ	J,JBTADR##(J)	;GET SIZE-1
	JUMPE	J,GREM40	;HAVE A HIGH SEG, BUT IT DOESN'T EXIST YET
	LSH	J,W2PLSH	;CONVERT TO PAGES-1
	ADDI	T1,1(J)		;FIRST PAGE AFTER HIGH SEG
	CAIN	T1,(T2)		;IS IT THE DESTINATION PAGE
	JRST	GREM40		;YES, ALL IS WELL
	ADJSP	P,-2		;FIX STACK
	PJRST	IALERR		;ILLEGAL ARG LIST

GREM40:	TLOA	T4,(1B1)	;YES, INDICATE APPEND
GREMA2:	MOVEI	P1,SHARE1##	;IN WIN CASE, GO TO SHARE1 FOR NORMAL REMAP
	POP	P,T1		;RESTORE SOURCE PAGE
	POP	P,T3		;RESTORE # OF PAGES
	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
	PUSHJ	P,SETVRT	;SET UP .USVRT
	AOS	(P)		;SKIP RETURN
	PJRST	MAPHGH##	;JUST APPENDING
GREMA4:	HRRZ	P4,T1		;SAVE T1
	HLRZS	T1		;SECTION #
	TRZE	T1,(PG.GAF)	;SPECIFIED SECTION #?
	PUSHJ	P,SVPCS##	;YES, SET THAT SECTION
	PUSHJ	P,FNSPCS##	;FIND NON-SHARABLE SECTION IN PCS
	  JRST	PSHERR		;SHARABLE NOT ALLOWED
	JUMPE	T1,PSHERR	;OR NON-EXISTENT SEGMENT
	EXCH	T1,P4		;PUT BLOCK ADDR IN P4 RESTORING ARG
	MOVE	T2,JBTADR##(J)	;GET HIGH SEG JBTADR
	LDB	P3,JBYHSO##	;GET HIGH SEG ORIGIN
	LSH	P3,P2WLSH	;CONVERT TO WORD
	MOVE	J,.USJOB
	HLRZ	P1,T2		;END OF CURRENT HIGH SEG
	LSH	P1,W2PLSH	;CONVERT TO HIGHEST PAGE IN SEG
	SUBI	P1,-1(T1)	;FIRST PAGE TO DELETE
	JUMPL	P1,IALERR	;HE IS, LOSE
	LSH	P1,P2WLSH	;MAKE SURE
	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,P3
	LDB	T4,[PSG2LH+.HBSG2(P4)] ;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,[PSG2LH+.HBSG2(P4)]	;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
	AOS	-1(P)		;GOOD RETURN
	HRRZ	J,.HBSGN(P4)	;GET SEG NUMBER
	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##
	SKIPE	R		;IF ZERO, STORE ZERO
	AOS	T1		;# OF PAGES, NOT HIGHEST ADDRESSABLE
	DPB	T1,[PHSSLH+.HBHSZ(P4)]
	HLRZS	R		;SET JOBHRL
	LDB	T2,JBYHSO##	;GET HIGH SEG ORIGIN
	LSH	T2,P2WLSH	;CONVERT TO WORD
	SKIPE	T1,R
	ADDI	T1,(T2)		;ADD IN BEGINNING
	HRRM	T1,.JDAT+JOBHRL##
	MOVE	J,.USJOB
	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,(P)	;FIX STACK
		 JRST	IALERR]
	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,(P)	;FIX STACK
		 JRST	IALERR]
	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,HLGPGS
	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,[MS.MAP+UMAPS]
CLRSP2:	TDNN	T2,(T3)		;SPY PAGE?
	JRST	CLRS2B		;NO
	SETZM	(T3)		;CLEAR MAPPING
	JUMPE	T1,CLRS2B	;GO IF S0
	PUSHJ	P,DECNZC	;KEEP THE COUNTS RIGHT
CLRS2B:	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?
	JRST	CLRSP5		;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
	SETZM	.USCDB		;MAKE SURE CLOCK1 KNOWS WE'RE CLEAN
	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?
	JRST	MONVPE		;NO, GIVE ERROR RETURN
IFN FTXMON,<
	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
	PUSH	P,T2		;SAVE AN AC
	MOVSI	T2,-CDBPGS##	;SET UP AOBJN
	MOVEM	T1,.USCDB(T2)	;STORE MAPPING
	ADD	T1,[XWD 1,0]	;MAP NEXT PAGE
	AOBJN	T2,.-2		;LOOP FOR ALL CDB PAGES
	POP	P,T2		;RESTORE T2
	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
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
MONVP5:	CAIE	T1,(MS.MAP)	;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
	CAMN	T2,.USTMU		;TRYING TO CHANGE ARG LIST SECTION?
	JRST	IALERR			;YES, LOSE
	JUMPE	T2,ILSERR		;ALSO MUSTN'T TOUCH S0
	TRNE	T2,^-MXSECN		;MAKE SURE SECTION IS IN RANGE
	JRST	ILSERR			;ILLEGAL SECTION HERE, TOO
	JUMPL	T1,CHGSC3		;DESTROY MAP
	TLNN	T1,(PG.SLO)		;CREATE MAP EX NIL?
	AOJA	T4,CHGSC2		;YES, ONLY VERIFY RIGHT HALF
	TLNE	T1,<-1^!<<(PG.GAF!PG.SLO!PG.IDC)>!MXSECN>>;ANY ILLEGAL BITS?
	JRST	ILSERR			;NO
CHGSC2:	TLO	T1,400000		;MAKE IFIW
	AOS	P1			;ONE MORE CREATE TO PROCESS
	MOVE	T3,BITTBL##(T1)		;GET BIT FOR THIS SECTION
	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
	TLNE	T1,(PG.SLO)		;WERE WE TO CREATE THIS FROM NOTHING?
	JRST	CHGS2A			;NO, GO DEAL WITH INDIRECTION
 	TDZ	P2,T3			;YES, SECTION WON'T BE INDIRECT LATER
	MOVE	T3,.UPMP+SECTAB(T1)	;GET MAP ENTRY
	TLNN	T3,(<PM.DCD^!PM.ACD>B2)	;IS IT CURRENTLY INDIRECT?
	SOJA	T4,CHGSC4		;NO, WE CAN JUST RE-USE THE MAP
	JRST	CHGSC4			;YES, STILL NEED TO CREATE A MAP
CHGS2A:	TDO	P2,T3			;TURN IT ON FOR THIS SECTION
	HRRZM	T1,.USTMU+1		;SAVE THE TARGET SECTION
	HLRZS	T1			;GET THE SECTION MAPPING TO
CHGS2B:	ANDI	T1,MXSECN		;SAVE ONLY SECTION #
	MOVE	T3,BITTBL##(T1)		;BIT FOR THIS SECTION
	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:	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
	ADD	P1,[1,,0]		;# OF SECTIONS BEING DESTROYED
	TDZ	P2,BITTBL##(T1)		;DEFINITELY WILL NOT BE INDIRECT
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,FNDPDS##		;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,P1			;SAVE MAPPING
	MOVEI	P1,(T1)			;SECTION
	S0PSHJ	KILHSS##		;KILL ALL HIGH SEGS THAT SECTION
	POP	P,P1
	MOVE	T1,.USSPT		;SECTION ARG AGAIN
	PUSHJ	P,KILSEC		;KILL ALL PAGES IN SECTION
	  JFCL				;CAN'T GET HERE--WE'RE AT UUO LEVEL
	LDB	T1,NZSSCN##
	SOS	T1			;DECREMENT MAP COUNT
	DPB	T1,NZSSCN##
	MOVE	T1,.USSPT
	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
	JRST	CHGS6A
CHGSC6:	MOVEI	T4,(T1)			;SECTION WE'RE WORKING WITH
	PUSHJ	P,RSECT4		;YES, GET REAL SECTION
	  JFCL				;IGNORE SKIP
	SETZ	T1,			;NO SEGMENT DATA BLOCK
CHGS6B:	PUSHJ	P,GNXHSB##		;FIND NEXT SEGMENT
	  JRST	CHGS6A			;NO MORE
	LDB	T2,[PSG2LH+.HBSG2(T1)]	;GET CURRENT SECTION FOR SEGMENT
	CAMN	T2,.USSPT		;IS IT THE ONE WE'RE DELETING?
	DPB	T4,[PSG2LH+.HBSG2(T1)]	;YES, SET NEW SECTION FOR SEGMENT
	JRST	CHGS6B			;LOOP OVER SEGMENTS
CHGS6A:	MOVE	T1,.USSPT
	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
	MOVE	T4,.UPMP+SECTAB(T2)	;GET CURRENT MAP INFO
	TLNE	T4,(<PM.DCD^!PM.ACD>B2)	;FORMERLY INDIRECT?
	SETZM	.UPMP+SECTAB(T2)	;YES, DON'T CONFUSE CRSMAP
	SKIPN	P1			;HAVE CORE?
	SETO	P1,			;NO, DON'T WAIT FOR IT
	PUSHJ	P,CRSMAP		;MAKE SECTION
	MOVE	T1,.USSPT		;IN CASE SECTION 0
	SOJL	T1,CHGS10
	IDIVI	T1,^D36/UP.SCS		;GET COUNTER
	LDB	T4,PNTNZS(T2)		;GET IT
	CAIN	T4,UP.VRG		;JUST CREATED?
	JRST	CHGS10			;YES
	PUSH	P,P1
	MOVE	P1,.USSPT		;GET SECTION #
	S0PSHJ	KILHSS##		;KILL ALL HIGH SEGMENTS IN THIS SECTION
	POP	P,P1
	MOVE	T1,.USSPT		;GET SECTION #
	PUSHJ	P,KILSEC		;EMPTY SECTION IF IDC AND IT EXISTED
	  JFCL				;CAN'T GET HERE--WE'RE AT UUO LEVEL
	MOVE	T1,.USSPT
	SOS	T1
	IDIVI	T1,^D36/UP.SCS		;GET COUNTER
	MOVEI	T4,UP.VRG
	DPB	T4,PNTNZS(T2)		;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
	  JFCL				;CAN'T GET HERE--WE'RE AT UUO LEVEL
	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,M.CPU##(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,
;HERE TO LOCK INDIVIDUAL PAGES IN CORE.  ARG LIST FORMAT:
;
;	LIST:	# OF ARGS
;		BITS+VPN,,[PHYS PAGE #]
;		...
;BITS:  GAF ON IMPLIES UNLOCK, OFF IMPLIES LOCK SPECIFIED PAGE
;	ARGMOD ON IMPLIES LOCK IN EVM, OFF IMPLIES NO EVM
;IF PHYS PAGE # SPECIFIED AS ZERO, PAGE IS LOCKED IN PLACE
;IF EVM IS REQUESTED FOR SOME PAGE, ON GOOD RETURN EVM STARTING ADDRESS
;IS STORED IN THE AC.

LOKPGS:	SE1ENT				;MUST RUN IN SECTION 1
	MOVE	T3,JBTSTS##(J)		;IS JOB LOCKED?
	TLNE	T3,NSHF!NSWP
	JRST	PALERR			;YES, DON'T LET HIM DO THIS
	PUSHJ	P,SAVE4##		;SAVE P1-P4
	HLRZS	T1			;JUST # OF ARGS
	PUSH	P,T1			;SAVE # OF ARGS
	MOVE	T3,T1			;SLIGHTLY MORE PERMANENT PLACE
	SETO	P1,			;CA FLAG/COUNT OF PAGES BEING LOCKED
	SETZ	P2,			;# OF PAGES TO DELETE
	SETZB	P3,P4			;# OF PHYS PAGES (P3), AMT OF EVM (P4)
	PUSHJ	P,FSTPAG		;START AT THE BEGINNING
LOKPG2:	PUSHJ	P,NXTLPG		;GET FIRST PAGE
	PUSH	P,T1			;SAVE
	HLRZS	T1			;GET VIRTUAL PAGE #
	ANDI	T1,HLGPGS		;SAVE ONLY PAGE #
	LSHC	T1,P2SLSH		;GET SECTION #
	CAIG	T1,MXSECN		;LEGAL?
	SKIPN	.UPMP+SECTAB(T1)	;AND DOES SECTION EXIST?
	JRST	[ADJSP	P,-2		;FIX STACK
		 SKIPL	P1		;IF REQUIRED
		 PUSHJ	P,CAFREE##	;RETURN THE CA RESOURCE
		 JRST	ILPERR]		;BAD PAGE #
	LSHC	T1,S2PLSH		;REVERT TO PAGE
	TRNN	T1,HLGPNO		;IS THIS PAGE 0?
	PUSHJ	P,ISITS0		;OF SOME FLAVOUR?
	CAIA				;NO
	JRST	[ADJSP	P,-2		;FIX STACK
		 SKIPL	P1		;IF REQUIRED
		 PUSHJ	P,CAFREE##	;RETURN THE CA RESOURCE
		 JRST	ILPERR]		;BAD PAGE
	PUSHJ	P,GTPME			;GET ENTRY
	POP	P,T1			;RESTORE FULL ARG
	SKIPL	T1			;UNLOCK?
	TDZA	T4,T4
	MOVEI	T4,1
	XCT	[TLNE T2,(PM.LOK)
		 TLNN T2,(PM.LOK)](T4)
	JRST	[TLNE   T1,(PG.IDC)	;CARE?
		 JRST   LOKPG4		;NO
		 POP	P,(P)		;FIX STACK
		 SKIPL	P1		;WRONG MODE (NO CA YET)
		 PUSHJ  P,CAFREE##	;FREE THE CA
		 JRST   PALERR(T4)]	;NO
	JUMPE	T2,[POP		P,(P)	;FIX STACK
		    SKIPL 	P1	;IF REQUIRED
		    PUSHJ	P,CAFREE## ;RETURN THE CA RESOURCE
		    JRST	PMEERR]	;PAGE MUST EXIST
	JUMPL	T1,[AOJA P2,LOKPG4]	;COUNT IF DELETE
	TLNE	T2,(PM.COR)		;IN CORE?
	JRST	LOKPG3			;YES, NO PROBLEM
;WE REALLY OUGHT TO PAGE IN THE PAGE FOR THE GUY, BUT FOR
;NOW THAT IS NOT IMPLEMENTED.  TO IMPLEMENT, REPLACE CODE HERE
	POP	P,(P)			;FIX STACK
	SKIPL	P1			;IF REQUIRED,
	PUSHJ	P,CAFREE##		;RETURN THE RESOURCE
	JRST	UIFERR
LOKPG3:	PUSHJ	P,LKPGCA		;GET CA IF REQUIRED, INCREMENT P1
	TLNE	T1,(PG.SLO)		;NEED EVM FOR THIS PAGE?
	AOS	P4			;YES
	SKIPGE	-5(P)			;PHYS ONLY (SAVED P1 ON STACK)?
	AOJA	P3,LOKPG4		;THEN COUNT THIS PAGE
	TRNE	T1,-1			;OR IF A SPECIFIC PAGE REQ'D
	TLOA	P3,(1B0)		;SET THE SIGN BIT
	JRST	LOKPG4			;NO
	HLLM	P3,.USLPG		;FLAG FOR LOKCON
	HRRZS	T1			;PAGE #
	LSH	T1,P2WLSH		;CONVERT TO WORD
	CAML	T1,MEMSIZ##		;CAN PHYS PAGE EXIST?
	JRST	[POP	P,(P)		;FIX STACK
		 SKIPL	P1		;IF REQUIRED,
		 PUSHJ	P,CAFREE##	;RETURN THE RESOURCE
		 JRST	ILPERR]		;NO
	LSH	T1,W2PLSH		;CONVERT BACK TO PAGE #
	SSX	T1,MS.MEM		;POINT TO PAGTAB SECTION
	MOVE	T1,PAGTAB(T1)		;GET ENTRY
	TLNE	T1,LKBITS		;PART OF LOCKED JOB, MONITOR, ETC.?
;***CHECK OTHER THINGS***
	JRST	[POP	P,(P)		;FIX STACK
		 SKIPL	P1		;IF REQUIRED,
		 PUSHJ	P,CAFREE##	;RETURN THE RESOURCE
		 JRST	PNAERR]		;PAGE IN LOCKED JOB, ETC.
LOKPG4:	SOJG	T3,LOKPG2		;SCAN LIST
	JUMPLE	P2,LOKPG8		;NO PAGES TO UNLOCK
	PUSHJ	P,FSTPAG		;START AGAIN
	MOVSI	T3,(PM.LOK)
LOKPG5:	PUSHJ	P,NXTLPG		;GET NEXT PAGE
	JUMPGE	T1,LOKPG5		;A LOCK
	HLRZS	T1			;ONLY VPN
	ANDI	T1,HLGPGS
	PUSHJ	P,GTPME			;GET POINTER TO PAGE
	TLNN	T2,(PM.LOK)		;IS IT LOCKED?
	JRST	LOKPG5			;MUST HAVE BEEN A DON'T CARE PAGE
	ANDCAM	T3,(T4)			;CLEAR LOCK IN HERE
	TLZ	T2,(PM.NAD)		;KEEP ONLY PAGE #
	AOS	JBTIMI##(J)		;INCREMENT IMGIN
	.CREF	IMGIN
	PUSHJ	P,RMVLPG
	PUSHJ	P,WSBIT
	IORM	T2,(T4)			;PUT BACK IN THE WORKING SET
	LDB	T1,JBYLSA##		;GET FIRST PAGE OF JOB
	SSX	T1,MS.MEM		;SET SECTION
	SSX	T2,MS.MEM
	HRRZ	T3,PAGTAB(T1)
	HRRM	T2,PAGTAB(T1)		;SET FORWARD LINKS
	HRRM	T3,PAGTAB(T2)
	SKIPE	T3			;IF NOT ZERO
	HRRM	T2,@[IW MS.MEM,PT2TAB(T3)]
	HRRM	T1,PT2TAB(T2)
	SOJG	P2,LOKPG5
LOKPG8:	SETZ	T1,			;NOT LOCKING EITHER SEG
	PUSHJ	P,CHKLPG##		;SEE IF THINGS WILL FIT
	  JRST	[POP	P,(P)		;RESTORE STACK
		 SKIPL	P1		;IF REQUIRED,
		 PUSHJ	P,CAFREE##	;RETURN THE RESOURCE
		 JRST	IRLERR]		;INSUFFICIENT ROOM TO LOCK
	MOVEI	T1,(P3)			;# OF PAGES LOKPHY NEEDS TO KNOW
	PUSH	P,P1			;SAVE FLAG
	MOVN	P1,-1(P)		;GET -COUNT
	SKIPE	P3			;IF ONLY IN-PLACE PAGES, JUST DO HERE
	PUSHJ	P,LOKPHY##		;LOCK
	POP	P,P1			;RESTORE CA FLAG
	SKIPGE	-5(P)			;COULD ANY IN-PLACE PGS BE THERE?
	JRST	LKPEVM			;NO (SAVED P1), SEE IF NEED EVM
	PUSHJ	P,FSTPAG		;START
LOKPG9:	PUSHJ	P,NXTLPG		;GET NEXT PAGE
	JUMPL	T1,LOKP10		;DELETE, ALREADY DONE
	TRNE	T1,-1			;SPECIFIC PAGE REQUESTED?
	JRST	LOKP10			;YES, THIS IS NOT AN IN PLACE
	HLRZS	T1			;GET PAGE #
	ANDI	T1,HLGPGS
	PUSHJ	P,GTPME			;GET PAGE MAP ENTRY
	PUSH	P,T2			;SAVE PAGE #
	MOVSI	T2,(PM.LOK)		;LOCK PAGE
	IORM	T2,(T4)			;SET IT
	POP	P,T2			;RESTORE PHYS PAGE #
	TLZ	T2,(PM.NAD)		;CLEAR BITS
	PUSHJ	P,LKPSF			;PULL OUT OF JOB'S PAGTAB CHAIN
	HRRZ	T4,.USLPG		;CURRENT 1ST PAGE IN LOCKED Q
	HRRM	T2,.USLPG		;WE ARE NOW FIRST
	SSX	T2,MS.MEM
	DPB	T1,[POINT P2.SPN,PT2TAB(T2),<^L<P2.VPN>+P2.SPN-1>]
	HRRM	T4,PAGTAB(T2)		;SAVE
	TRNE	T4,-1			;IF THERE IS A SUCCESSOR
	HRRM	T2,@[IW MS.MEM,PT2TAB(T4)]  ;POINT HIM AT US
	PUSHJ	P,TSWST			;GET BIT
	  CAIA				;ALREADY CLEAR
	ANDCAM	T2,(T4)			;CLEAR
	SOS	JBTIMI##(J)		;DECREMENT IMGIN
	.CREF	IMGIN
LOKP10:	SOSLE	(P)			;ANY MORE ARGS?
	JRST	LOKPG9			;YES
LKPEVM:	SKIPL	P1			;IF REQUIRED,
	PUSHJ	P,CAFREE##		;RETURN CA RESOURCE NOW
	JUMPE	P4,TPOPJ1##		;DONE IF NO EVM
	MOVSI	T1,(PM.CSH)		;TURN CACHE OFF
	SETZ	T2,
	DMOVEM	T1,.USTMP		;YES, MUST BE .USTMP (NOT .USTMU)
	MOVN	T1,P4			;-AMOUNT OF EVM REQUIRED
	PUSHJ	P,LOKEVX##		;LOCK PAGES IN EVM
	  CAIA				;OOPS
	JRST	TPOPJ1##		;DONE
	PUSHJ	P,EVMERR		;NO EVM ERROR
	POP	P,(P)			;FIX STACK
	CAIA				;FALL INTO CLEAR LOCKED PAGES CODE

CLRLPG::SE1ENT
	SKIPN	T2,.USLPG		;ANY PAGES TO UNLOCK?
	POPJ	P,			;NO
	PUSH	P,T1			;SAVE T1
	LDB	T3,JBYLSA##		;FIRST PAGE OF LOW SEG
	SSX	T3,MS.MEM		;PAGTAB ADDRESS
	PUSH	P,PAGTAB(T3)		;SAVE CURRENT LINK TO NEXT
	SSX	T2,MS.MEM		;SET INDEX FOR THIS
	HRRM	T3,PT2TAB(T2)		;SET BACK LINK
CLRLP1:	HRRM	T2,PAGTAB(T3)		;STORE LINK TO NEXT
	HRRI	T3,(T2)			;POINT FORWARD
	MOVSI	T2,LKBITS		;CLEAR LOCKED BITS IN PAGTAB
	AND	T2,PAGTAB(T3)		;GET THE BITS THAT ARE SET
	ANDCAM	T2,PAGTAB(T3)
	TLNN	T2,LOKEVB		;THIS PAGE IN EVM?
	JRST	CLRLP2			;NO
	SOS	.C0EVU##		;CLEAR THIS PAGE USED
	PUSH	P,T3
	MOVE	T3,MEMTAB(T3)		;EVM ADDRESS
	.CREF	MT.EVM
	MOVE	T2,EVMPTR##
	S0PSHJ	ZERBTS##		;CLEAR EVM BITS
	PUSHJ	P,CONEVA##
	POP	P,T3
CLRLP2:	LDB	T1,NVPNT3		;GET VIRT PAGE THIS PAGE IS FOR
	PUSHJ	P,GTPME			;GET PAGE ENTRY
	MOVSI	T2,(PM.LOK)		;CLEAR BIT
	ANDCAM	T2,(T4)			;CLEAR THIS
	AOS	JBTIMI##(J)		;PUT BACK IN WORKING SET
	PUSHJ	P,WSBIT			;GET BIT
	IORM	T2,(T4)			;TURN IT ON
	HRRZ	T2,PAGTAB(T3)		;LINK TO NEXT
	JUMPN	T2,CLRLP1		;LOOP BACK
	POP	P,T2			;RESTORE REST OF JOB'S CHAIN
	HRRM	T2,PAGTAB(T3)		;LINK FROM LOCKED CHAIN TO IT
	SSX	T2,MS.MEM		;RIGHT SECTION
	TRNE	T2,-1			;ASSUMING THERE ARE MORE PAGES,
	HRRM	T3,PT2TAB(T2)		;SET BACK LINK
CLRLP4:	SETZM	.USLPG			;NO MORE LOCKED PAGES
	JRST	TPOPJ##			;RESTORE T1 AND RETURN


LKPGCA:	AOJN	P1,CPOPJ##		;ONLY GET CA IF FIRST TIME
IFN FTMP,<
	PUSHJ	P,REMMM##		;REMEMBER STATE OF MM
>
	PUSHJ	P,CAWAIT##		;GET THE CA RESOURCE
	AOJA	P1,CPOPJ##		;RETURN

;HERE TO REMOVE A LOCKED PAGE FROM A JOB'S CHAIN (NOT RE-INSERTING IT
;ANYWHERE).  T2 HAS PHYSICAL PAGE TO REMOVE

RMVLPG:	PUSHJ	P,SAVT##		;SAVE TS
	MOVEI	T3,.USLPG
	PUSHJ	P,REMPFQ
	MOVSI	T1,LKBITS		;GET THE LOCK BITS
	SSX	T2,MS.MEM		;POINT TO THE SECTION
	AND	T1,PAGTAB(T2)		;GET WHAT THE BITS ARE
	ANDCAM	T1,PAGTAB(T2)		;THEN CLEAR THEM
	TLNN	T1,LOKEVB		;WAS PAGE IN EVM?
	POPJ	P,			;NO, NOTHING MORE TO DO
	MOVE	T3,MEMTAB(T2)		;ELSE MUST RETURN THE EVM
	.CREF	MT.EVM
	SOS	.C0EVU##		;LESS IN USE
	MOVE	T2,EVMPTR##
	S0PSHJ	ZERBTS##		;CLEAR BITS
	PJRST	CONEVA##		;RETURN
;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,PG.BDY	;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	T4,(T1)		;GET PAGE NUMBER
	LSH	T4,P2SLSH	;CONVERT TO SECTION
	TRNE	P2,PA.PWE	;MUST PAGE BE WRITE ENABLED?
	PUSHJ	P,RSECT4	;MUST BE WRITE ENABLED, DOES IT EXIST?
	  JRST	PLTS4A		;DOESN'T EXIST (AND IS THUS WE, SORT OF) OR WE
	PUSHJ	P,GTPME		;GET THE PAGE MAP ENTRY
	TLNN	T2,(PM.WRT)	;IS IT WRITE-ENABLED?
	TLNE	T1,(PG.IDC)	;DOES HE CARE?
	JRST	PLTS4A		;NO
	PUSHJ	P,PWLERR	;CAN'T BE WRITE-LOCKED
	PJRST	PLTS16

PLTS4A:	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:	MOVE	T2,(T4)		;GET FULL ENTRY AGAIN
	TRNE	P2,PA.PWL	;MUST PAGE BE WRITE-LOCKED?
	TLNN	T2,(PM.WRT)	;YES, AND IS IT?
	JRST	PLTS6A		;WE DON'T CARE, OR IT IS
	TLNE	T1,(PG.IDC)	;DOES HE REALLY CARE?
	JRST	PLTS6A		;NO
	PUSHJ	P,PWEERR
	JRST	PLTS16

PLTS6A:	TRNN	P2,PA.PCI	;CAN THE PAGE BE IN CORE?
	JRST	PLTSN8		;YES, PROCEED
	PUSH	P,P1		;NEED TO SAVE T2 HERE
	MOVSI	P1,(PM.NAD)	;REALLY ONLY WANT ENTRY PART
	ANDCA	P1,T2		;SO ONLY PICK UP THAT PART
	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!PA.PWE!PA.PWL ;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,PAGSNQ## ;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,TPNHX		;IS THE PAGE IN A HIGH SEGMENT?
	  TLOA	M,HSPAG		;YES, REMEMBER HIGH SEGMENT PAGE SEEN
	JRST	PLTS14		;NOT A HIGH SEG PAGE
	MOVE	T2,.HBSGN(T2)	;GET HIGH SEGMENT BITS
	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
EXNXP:	EXCH	T1,.USNXP	;GET CURRENT VALUE AND SET NEW ONE
	POPJ	P,

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

NXTLPG::MOVS	T1,.USNXP	;RANGE SPECIFIED?
	CAMN	T1,[-1]		;?
	PJRST	GETWS1##	;NO, GET NEXT ARG
	AOS	T1		;ALWAYS INCREMENT LEFT HALF
	MOVSS	T1		;PUT HALVES BACK
	TRNE	T1,-1		;IF THIS SPECIFIED 0 FOR DEST,
	AOS	T1		;LEAVE AS 0 ELSE INCREMENT
	JRST	EXNXP		;RETURN CURRENT VALUE AND STORE NEXT

;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
	TLNN	T1,37777	;PAGE PAIR?
	SOSA	T1		;NO, BACK UP THE PAGE NUMBER
	SUB	T1,[1,,1]	;BACK UP 1 PAGE
PREPA1:	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
	ERCODE	PALERR,PAGAL%	;(21)PAGE ALREADY LOCKED
	ERCODE	PAUERR,PAGAU%	;(22)PAGE ALREADY UNLOCKED (MUST BE CONTIGUOUS
				;WITH PALERR)
	ERCODE	PNAERR,PAGNA%	;(23)PAGE NOT AVAILABLE (E.G. PHYS PAGE REQ'D
				;TO BE LOCKED IS IN A LOCKED JOB, ETC.)
	ERCODE	IRLERR,PAGNR%	;(24) NO ROOM TO LOCK
	ERCODE	EVMERR,PAGNE%	;(25) INSUFFICIENT EVM AVAILABLE
	ERCODE	NFSERR,PAGNN%	;(26)NO FREE SEGMENT #S
	ERCODE	NCRERR,PAGNC%	;(27)NO FREE CORE AVAILABLE
	ERCODE	PWLERR,PAGWL%	;(30)PAGE ALREADY WRITE-LOCKED
	ERCODE	PWEERR,PAGWE%	;(31)PAGE ALREADY WRITE-ENABLED
	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,PG.BDY	;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
	MOVE	T1,(P)		;SEG NUMBER IN QUESTION
	PUSHJ	P,FNDHSB##	;GET HIGH SEG BLOCK FOR THIS SEG #
	  XCT	NSS##		;NO SUCH SEGMENT
	DPB	P2,[PHSSLH+.HBHSZ(T1)]
	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
	PUSHJ	P,GICUPH	;GET HIGH 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

;SUBROUTINE FOR ABOVE

GICUPH:	PUSH	P,T1		;SAVE T1
	PUSH	P,T3		;T3
	PUSH	P,T4		;AND T4
	PUSH	P,J		;J
	MOVSI	T3,-1		;FIND LOWEST ADDRESSED SEG IN PCS
	PUSHJ	P,GTRSGN##	;GET LOWEST SEGMENT
	  JFCL			;NONE
	JUMPL	J,[LDB  T2,[PSPOLH+.HBSPO(T1)] ;SPY SEG ORIGIN
		   JRST GICUP1]
	HRRZS	J
	LDB	T2,JBYHSO##	;ORIGIN OF THAT SEGMENT
GICUP1:	POP	P,J		;RESTORE J
	POP	P,T4		;T4
	POP	P,T3		;T3
	JRST	TPOPJ##		;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,[-PAGSIZ]
	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
;HIGH SEGMENT CALLS INSDWL

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
	CLRPT	.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
	  JFCL			;WORRY ABOUT THIS LATER
	SKIPN	T4		;IF NOT S0, MULTIPLY
	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,
;CPOPJ IF SECTION NON-EXISTENT
;STARTS WITH C(T4) AND IS ASSUMED TO BE
;ZERO IF IT IS 0 OR NEGATIVE.  USES T2.

RSECT4::JUMPG	T4,RSCT4A	;GO IF SECTION NON-ZERO
	SETZ	T4,		;HE REALLY WANTS S0
	JRST	CPOPJ1##	;GOOD RETURN
RSCT4A:	CAIG	T4,MXSECN	;DON'T FALL OFF THE END
RSCT4B:	SKIPN	T2,.UPMP+SECTAB(T4) ;GET SECTION POINTER
	POPJ	P,		;RETURN SAYING 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,RSCT4B	;AND CHECK IT OUT
	JRST	CPOPJ1##	;RETURN IF 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##,STOP,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)
DLTPGF:	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
	SJSP	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:	TLNE	T3,(PM.LOK)	;IS THIS PAGE LOCKED?
	JRST	RMVPG7		;YES, HANDLE DIFFERENTLY
	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 #
	PUSH	P,T3		;SAVE MAP ENTRY
	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	[POP P,T3	;RESTORE PAGE MAP ENTRY
		 JRST RMVPG2]	;NO, JUST A GARDEN VARITY PAGE
	POP	P,(P)		;POP OFF JUNK
	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,.USBTS	;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,.USBTS	;IF SO,
	IORM	T2,MEMTAB(T4)
	SETZM	(P)		;INDICATE NO PAGE TO GIVE BACK
	JRST	T2POPJ##	;AND GIVE PAGE ON DISK RETURN

;HERE WITH T3=CONTENTS OF THE MAP (SIGN BIT GUARENTEED OFF)
RMVPG2:	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
	SKIPL	T3		;PAGE IN THE WORKING SET?
	TLNE	T3,(PM.WRT)	;YES, IS IT ALSO WRITE LOCKED?
	CAIA			;NO
	PUSHJ	P,[SKIPN .USWLP	;NO DISK SPACE TO GIVE BACK IF NO WL PAGES
		   POPJ P,	;JUST GO AWAY
		   PUSHJ P,SAVT## ;YES, IT HAS BOTH A DISK AND IN-CORE COPY
		   MOVSI T1,(UP.CTX)
		   TDNE T1,.USBTS
		   POPJ P,	;IF PUSH, DON'T DO ANYTHING
		   PJRST RTNDPG];SO RETURN DISK SPACE
	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

RMVPG7:	POP	P,T2		;RESTORE PAGE #
	TLZ	T2,(PM.NAD)	;KEEP ONLY PAGE
	AOS	(P)		;GIVE IN-CORE RETURN
	PJRST	RMVLPG		;REMOVE PAGE AND RETURN

;SUBROUTINE TO RETURN DISK SPACE WHEN A PAGE IS WRITE ENABLED
;ENTER WITH T2=PHYSICAL PAGE NUMBER, ALWAYS RETURNS CPOPJ

RTNDPG:	SKIPN	.USWLC		;ELSE DECREMENT PROPER COUNT
	SOSA	.USWLP		;MUST BE A MONITOR PAGE
	SOS	.USWLC
RTNFS0::TLZ	T2,(PM.NAD)	;CLEAR ACCESS BITS
	SSX	T2,MS.MEM	;INDEX INTO MEMTAB
	LDB	T1,[POINT MT.SAD,MEMTAB(T2),<^L<MT.DAD>+MT.SAD-1>] ;DISK ADDRESS
	SETZM	MEMTAB(T2)	;DON'T FIND IT ON "OU" QUEUE
	PUSH	P,U		;DON'T CLOBBER U, LOTS! OF PEOPLE DEPEND ON IT
	SKIPE	T2,T1		;ARGUMENT FOR DLTPGD
	PUSHJ	P,DLTPGF	;RETURN SWAPPING SPACE
	JRST	UPOPJ##		;RESTORE U AND RETURN
;SUBROUTINE TO RETURN SWAPPING SPACE ALLOCATED TO PAGE 0, FUNNY SPACE,
; AND SECTION MAPS FOR A JOB WHOSE CORE IMAGE CONTAINS WRITE LOCKED PAGES

RTNNWL::PUSHJ	P,SVEUB##	;JOB'S NOT ADDRESSABLE HERE
	SKIPN	.USWLP		;JOB HAVE ANY WRITE LOCKED PAGES?
	POPJ	P,		;NO, NOTHING TO RETURN
	SE1ENT			;MUST BE IN SECTION 1 TO REFERENCE PAGTAB/MEMTAB
	MOVEI	T1,0		;PAGE 0 IS ALWAYS WRITE ENABLED
	PUSHJ	P,GTPME		; SO GET PHYSICAL PAGE NUMBER
	PUSHJ	P,RTNFS0	; AND RETURN ITS SWAPPING SPACE
;THE FOLLOWING CODE ASSUMES FUNNY SPACE STARTS AT HLGPNO+1, GIVE BACK
; FUNNY SPACE PAGES AND SECTION MAPS
;SETUP TO START SCANNING WSBTAB WHERE FUNNY SPACE BEGINS
	SKIPA	M,.+1
	SETZ	HLGPNO
	MOVEI	T1,^D36-<<HLGPNO+1>-^D36*<<HLGPNO+1>/^D36>>
	MOVEI	T2,WSBTAB+<HLGPNO+1>/^D36
	MOVE	T3,(T2)
	LSH	T3,<<HLGPNO+1>-^D36*<<HLGPNO+1>/^D36>>
	PUSHJ	P,SAVE1##	;NEED AN EXTRA AC
RTNNW1:	PUSHJ	P,NXTWS3	;GET NEXT PAGE OF FUNNY SPACE
	HRRZ	P1,M		;VIRTUAL PAGE NUMBER
	CAIE	P1,.UPMVP/PAGSIZ ;UPT?
	CAIN	P1,.UPMVP/PAGSIZ-1 ; OR MAP?
	JRST	RTNNW1		; YES, ALREADY GIVEN BACK ON UPT AND MAP SWAP IN
	CAILE	P1,.UPMVP/PAGSIZ+MXSECN ;DONE?
	POPJ	P,		;YES, RETURN
	PUSHJ	P,[PUSHJ P,SAVT## ;PRESERVE T ACS FOR NEXT CALL TO NXTWS3
		   MOVE T2,(T4)	;PHYSICAL PAGE NUMBER
		   PJRST RTNFS0];RETURN SWAPPING SPACE
	JRST	RTNNW1		;NEXT PAGE
;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
;REMPFQ WILL REMOVE A PAGE FROM A GENERALIZED QUEUE WHOSE ADDRESS
;IS IN T3 (USED BY LOKPGS CODE)

RMVPFQ:	SE1ENT			;ENTER SECTION 1
	SOSL	1(T3)		;DECREMENT COUNT OF PAGES ON QUEUE
REMPFQ:	SKIPN	T4,(T3)		;ANY PAGES ON THE QUEUE
	STOPCD	CPOPJ##,DEBUG,PQW, ;++PAGE QUEUE WRONG
	CAIE	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
	HRRM	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
;ON CPOPJ RETURN, T2 POINTS TO HIGH SEG DATA BLOCK IN WHICH PAGE WAS FOUND

TPWHS:
IFN FTPEEKSPY,<
	PUSHJ	P,TSSPT		;A SPY PAGE?
	  CAIA			;NO
	JRST	CPOPJ1##
>
	MOVSI	T4,UWPOFF	;IF IT IS AN A HIGH SEG
	PUSHJ	P,TPAHS		;IS IT IN HIGH SEG?
	  TDNN	T4,.HBSGN(T2)	;IN HIGH SEG, IS HIGH SEG WRITABLE?
	AOS	(P)		;NOT IN HIGH SEG OR NOT IN WRITABLE HIGH SEG
	POPJ	P,

TPAHS::	TDZA	T2,T2		;CLEAR T2
TPSHS::	MOVSI	T2,SHRSEG!SPYSEG ;BITS TO TEST
	PUSHJ	P,SAVE3##	;SAVE P1
	SETO	P1,		;FLAG LOOK AT ALL SEGMENTS
TPXHS:	SKIPN	P3,T2		;BITS IN LEFT HALF OF P3
	SETCA	P3,		;IF ZERO, PRETEND -1
	MOVEI	P2,(T1)		;AND PAGE # IN RIGHT HALF
	PUSH	P,T1		;SAVE THE VIRTUAL PAGE NUMBER
	TDZA	T1,T1		;GET FIRST HIGH SEG BLOCK
TPXHS1:	POP	P,T1		;RESTORE LAST BLOCK FOUND
	PUSHJ	P,GNXHSB##	;GET NEXT HIGH SEG BLOCK
	  JRST	TPOPJ1##	;NOT IN ANY HIGH SEG
	PUSH	P,T1		;SAVE HIGH SEG BLOCK ADDR
	TDNN	P3,.HBSGN(T1)	;ARE THOSE BITS SET IN THE HIGH SEG WORD?
	JRST	TPXHS1		;NO
	PUSHJ	P,HSVAD##	;GET STARTING AND ENDING VIRTUAL ADDRESSES
				; OF THE HIGH SEGMENT
	LSHC	T1,W2PLSH	;CONVERT TO STARTING AND ENDING PAGE NUMBERS
	CAIL	P2,(T2)		;BELOW THE START OF THE HIGH SEGMENT?
	CAILE	P2,(T1)		;OR ABOVE THE TOP OF THE HIGH SEGMENT
	JRST	TPXHS1		;OK FOR THIS HIGH SEG
	JUMPL	P1,TTPOPJ##	;POINT T2 AT HIGH SEG BLOCK, RESTORE T1, RETURN
	MOVE	T1,(P)		;GET HIGH SEG BLOCK ADDR AGAIN
	LDB	T1,[PSG2LH+.HBSG2(T1)] ;SECTION #
	CAIE	T1,(P1)		;RIGHT SECTION?
	JRST	TPXHS1		;NO, LOOP ON
	JRST	TTPOPJ##	;POINT T2 AT HSB, RESTORE T1, RETURN
;SUBROUTINE TO CHECK SECTION # AGAINST JBYSG2 AS WELL AS THE
;CHECKS TPAHS/TPSHS DOES.  SAME RETURNS AS TPAHS
;TPNHS SAVES ALL T ACS, ALL OTHER ENTRY POINTS DESTROY T1 AND T2
;BUT PRESERVE T3 AND T4

TPNHS::	PUSHJ	P,SAVT##
TPNHX:	TDZA	T2,T2
TPNSHS:	MOVSI	T2,SHRSEG!SPYSEG ;BITS TO TEST
	PUSHJ	P,SAVE3##	;SECTION #
	MOVE	P1,T4		;SAVE T4 FOR ALL CALLERS
	MOVEI	T4,(T1)		;GET PAGE #
	LSH	T4,P2SLSH	;ONLY SECTION #
	PUSHJ	P,RSECT4	;RESOLVE SECTION # TO INDEPENDENT SECTION
	  JRST	CPOPJ1##	;NON-EXISTENT SECTION ISN'T IN HIGH SEG
	EXCH	T4,P1		;PUT SECTION INTO P1 AND RESTORE T4
	ANDI	T1,HLGPNO	;KEEP ONLY PAGE #
	PJRST	TPXHS		;CONTINUE

;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
	PUSH	P,T1		;SAVE T1
	PUSHJ	P,TPNHX		;IS THIS PAGE IN THE HIGH SEGMENT?
	  SKIPG	.HBSGN(T2)	;IS THERE A REALY HIGH SEG?
	JRST	TPOPJ##		;SPY SEG OR NOT IN HIGH SEG
	MOVSI	T4,(UP.CTX)	;GET CONTEXT SERVICE BIT
	TDNE	T4,.USBTS	;DELETING A HISEG FOR CTXSER?
	JRST	TPOPJ##		;YES, DON'T TOUCH THE PAGE COUNT
	HRRZ	T4,.HBSGN(T2)	;NO, GET HIGH SEGMENT NUMBER
	ADDM	T3,JBTSWP##(T4)	;INCREMENT OR DECREMENT PAGE COUNT
	JUMPL	T3,TPOPJ##	;RETURN IF REMOVING A PAGE FROM CORE
	EXCH	J,T4		;PUT SEGMENT NUMBER IN USEFUL PLACE
	LDB	J,JBYHSO##	;GET ORIGIN PAGE
	PUSH	P,J		;SAVE THAT
	PUSH	P,P2		;SAVE P2
	MOVE	P2,T2		;HIGH SEG DATA BLOCK ADDR TO P2
	MOVE	J,T4		;RESTORE J
	PUSHJ	P,SCWEXO##
	POP	P,P2		;RESTORE P2
	POP	P,T4
	POP	P,T1
	POPJ	P,

;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			;MUST BE IN SECTION 1 (GTPME)
	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
	MOVEI	T1,JBTSGN##-.HBLNK(J) ;HEADER FOR SEGMENT DATA BLOCK ADDR
SETHS1:	HRRZ	T1,.HBLNK(T1)	;GET NEXT BLOCK
	JUMPE	T1,JPOPJ##	;DONE IF NO MORE
	SKIPLE	J,.HBSGN(T1)	;SPY SEG?
	TLNE	J,SHRSEG	;OR SHARABLE?
	JRST	SETHS1		;NOT CONCERNED WITH THOSE
	HRRZS	J		;MAKE USABLE INDEX
	LDB	T4,[PSG2LH+.HBSG2(T1)] ;GET SECTION #
	LSH	T4,S2PLSH	;CONVERT TO PAGE #
	LDB	T2,JBYHSO##	;GET VIRT PAGE # OF ORIGIN OF SEGMENT
	ADD	T4,T2		;MAKE FULL PAGE #
	PUSHJ	P,GTPM4		;GET PAGE MAP ENTRY
	TLNN	T4,(PM.COR)	;IN CORE?
	SETZ	T4,		;NO, STORE 0
	DPB	T4,JBYHSA##	;STORE FIRST PAGE
	JRST	SETHS1		;CONTINUE
;SUBROUTINE TO WAIT FOR MIGRAT TO PASS US
;CALLED BY IPCFS
;USES T1


IPMWAT::PUSH	P,J			;SAVE J
IPMWT1:	SKIPL	T1,MIGRAT##		;MIGRATE IN PROGRESS?
	HRRZS	T1			;(CLEAR FLAGS)
	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,SCDCKM		;SEE IF NEED TO WAIT
	  JRST	JPOPJ##
KILNZ2:	SKIPN	P2,.UPMP+SECTAB(P1)	;SECTION EXIST?
	JRST	KILNZ3
	TLNN	P2,(<PM.ACD^!PM.DCD>B2)	;INDIRECT OR IMMEDIATE?
	JRST	KILN2A			;IMMEDIATE
	MOVEI	T4,(P1)			;SECTION IN QUESTION
	PUSHJ	P,RSECT4		;REAL SECTION #
	  JFCL
	MOVEI	T1,(T4)			;INTO T1
	PUSHJ	P,STPCS##		;PUT PCS IN INDEPENDENT SECTION
	JRST	KILNZ3
KILN2A:	MOVEI	T1,(P1)			;SECTION IN QUESTION
	PUSHJ	P,KILSEC		;KILL THE SECTION
	  JRST	JPOPJ##			;RAN OUT OF TIME--TRY AGAIN NEXT TICK
	MOVE	T2,.UPMP+SECTAB(P1)	;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				;FLUSH PAGING MEMORY
	JRST	JPOPJ1##		;RESTORE J AND RETURN
SCDCKM:	SKIPE	SCDRTF##		;FORCED RESCHED PENDING?
	JRST	SCDCK1
	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
SCDCK1:	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
	JRST	CPOPJ1##		;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
	PUSHJ	P,SCDCKM		;AVOID A POSSIBLE KAF
	  JRST	KILSE4			;TIME TO QUIT--CLEAN UP
KILSE2:	AOBJN	P2,KILSE1		;CONTINUE
KILSE3:	PUSHJ	P,SETVRT		;FIX .USVRT
	AOS	-1(P)			;SET TO RETURN GOODNESS
	POP	P,T1			;RESTORE SECTION #
	SETZ	T2,
	PJRST	PUTNZC			;NO PAGES LEFT
KILSE4:	PUSHJ	P,SETVRT		;FIX UP .USVRT
	MOVE	T1,(P)			;GET SECTION NUMBER
	PUSHJ	P,GETNZC		;HOW MANY WERE THERE BEFORE?
	SUB	T1,P1			;THERE ARE FEWER NOW
	MOVE	T2,T1			;GET IN RIGHT REGISTER
	POP	P,T1			;RESTORE SECTION NUMBER
	PJRST	PUTNZC			;FIX COUNT AND GIVE 'ABORT' RETURN
;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##
;SUBROUTINE TO WRITE-ENABLE ALL MONITOR (AND USER) WRITE-LOCKED PAGES
;USES T1-T2

CLRWLP:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVE	P1,.USWLP	;# OF MONITOR-LOCKED PAGES
	ADD	P1,.USWLC	;+# OF USER LOCKED PAGES
	JUMPE	P1,CPOPJ##	;ALREADY ALL DONE?
	SETZ	T1,		;CLEAR PAGE WE'RE ON
CLRWL1:	SKIPN	P2,@[IW MS.MAP,UMAPS(T1)] ;GET PAGE ENTRY
	AOJA	T1,CLRWL3	;CONTINUE IF NO PAGE
	PUSH	P,T1		;SAVE PAGE #
	PUSHJ	P,TPNSHS	;IN A HIGH SEG?
	  JRST	CLRWL7		;YES, PONDER THE PROBLEM
	POP	P,T1		;RESTORE T1
	TLZE	P2,@[IW MS.MAP,UMAPS(T1)] ;WRITE-ENABLE; WAS IT ALREADY?
	SOJLE	P1,CLRWL9	;YES, COUNT AS CHANGED - DONE IF NO MORE
	AOS	T1		;POINT TO NEXT PAGE
CLRWL3:	TRNE	T1,HLGPNO	;CROSS SECTION BOUNDARY?
	JRST	CLRWL1		;NO, LOOP ON
	LSH	T1,P2SLSH	;YES, GET SECTION #
CLRWL4:	CAILE	T1,MXSECN	;ABOVE TOP IN # OF SECTIONS?
	JRST	CLRWL9		;YES, DONE
	SKIPE	T2,.UPMP+SECTAB(T1) ;DOES NEW SECTION EXIST?
	TLNE	T1,(<PM.ACD^!PM.DCD>B2) ;YES, IS IT INDIRECT?
	AOJA	T1,CLRWL4	;EXISTS AND ISN'T INDIRECT, CONTINUE
	LSH	T1,S2PLSH	;CONVERT BACK TO PAGE #
	PUSHJ	P,SCDCHK##	;BLOCK IF WE SHOULD
	JRST	CLRWL1		;THEN LOOP AROUND

;HERE IF PAGE IN HIGH SEG
;***SHOULD SKIP TO END OF HIGH SEG***

CLRWL7:	POP	P,T1		;RESTORE T1
	AOJA	T1,CLRWL3	;FOR NOW, JUST CONTINUE

CLRWL9:	SETZM	.USWLP		;CLEAR
	SETZM	.USWLC		;ALL COUNTS
	POPJ	P,		;RETURN
	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##
;NOTE THAT THE DX ENTRIES IN THIS TABLE SHOULD NEVER BE USED BY THIS
PNTCNT:	POINT	14,T1,13	;RH10
	POINT	14,T1,13	;DX10 (HAH!)
	POINT	14,T1,13	;RH20
MAXCNT:	400000+T1,,37		;RH10
	400000+T1,,37		;DX10 (HAH!)
	400000+T1,,3		;RH20

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

	$LIT
	$HIGH
VMEND:	END