;<135-TENEX>PAGEM.MAC;254    17-DEC-75 15:16:30    EDIT BY ROSENBERG
; PUT A "COPY" OF ONRQ IN-LINE IN MAKPGA TO AVOID NESTED PIOFFS/PIONS
;<135-TENEX>PAGEM.MAC;253    20-NOV-75 14:54:58    EDIT BY ROSENBERG
; MAKE MRPAC JSYS CORRECT FOR RESIDENT MONITOR MAPPING EITHER ON OR OFF
;<134-TENEX>PAGEM.MAC;252     4-NOV-75 11:15:57    EDIT BY ALLEN
; BE SURE SCHED SEES PSI SET AT RELMP4
;<134-TENEX>PAGEM.MAC;251    15-SEP-75 17:27:50    EDIT BY PLUMMER
; REMOVE .PLOCK
;<134-TENEX>PAGEM.MAC;250     2-SEP-75 09:45:48    EDIT BY PLUMMER
;<134-TENEX>PAGEM.MAC;248    28-AUG-75 16:05:29    EDIT BY PLUMMER
; FORBID SETPT FROM FORMING INDIRECT MAP LOOPS
;<134-TENEX>PAGEM.MAC;246    18-AUG-75 11:17:10    EDIT BY PLUMMER
; FIX ASOFAI AGAIN
;<134-TENEX>PAGEM.MAC;244     5-AUG-75 11:44:57    EDIT BY CLEMENTS
; CHANGE "P2" TO "PATCH2" TO AVOID CONFLICT WITH NEW AC NAME
;<134-TENEX>PAGEM.MAC;243     8-JUL-75 09:31:15    EDIT BY PLUMMER
; FORCE DDUMP TO RUN IN ASOFAI
;<134-TENEX>NPAGEM.MAC;2    22-MAY-75 15:53:30    EDIT BY ALLEN
; PGRINI NO LONGER COMPUTES DRMIN0,1,2 BUT TAKES VALUES FROM
; PARAMS.
;<134-TENEX>NPAGEM.MAC;1    15-MAY-75 12:33:12    EDIT BY ALLEN
; FIX SETPT RACE CONDITION. RELMPG NOW SKIPS IF SUCCESSFUL AND ALWAYS
; RETURNS NOSKED
;<134-TENEX>PAGEM.MAC;240    21-APR-75 16:44:52    EDIT BY TOMLINSON
; extern DISE
;<134-TENEX>PAGEM.MAC;239    21-APR-75 16:39:35    EDIT BY TOMLINSON
; Correct spelling of FSHBAL in asofn edit below
;<134-TENEX>PAGEM.MAC;238    16-APR-75 17:57:56    EDIT BY PLUMMER
;<134-TENEX>PAGEM.MAC;237    16-APR-75 12:56:59    EDIT BY PLUMMER
; MAKE ASOFN TRY SECOND TIME AFTER GC BEFORE FAILING
;<134-TENEX>PAGEM.MAC;236     3-MAR-75 17:29:35    EDIT BY CLEMENTS
; MOVE RECURSIVE TRAP CHECK IN GC LOGIC (PDL OV IN RS04 DRIVER)
;<134-TENEX>PAGEM.MAC;235    28-FEB-75 15:43:27    EDIT BY CLEMENTS
; REVERSE ORDER OF PAGER OPS AT PGRRST, IN CASE LITERALS ABOVE 77777
;<134-TENEX>PAGEM.MAC;234    11-FEB-75 17:19:39    EDIT BY ALLEN
; FIX (HOPEFULLY) FOR SUMNRX INCORRECT BUG
;<134-TENEX>PAGEM.MAC;233    11-FEB-75 17:02:50    EDIT BY ALLEN
; BRING GCCOR UP TO DATE IN TESTING FOR WAITLIST FORK
;<133-TENEX>PAGEM.MAC;232    17-DEC-74 17:20:09    EDIT BY ALLEN
; BUG FIX IN SETPPG

SEARCH PROLOG

TITLE PAGEM

;TENEX PAGE MANAGEMENT MODULE - D. MURPHY

	INTERN MAKPGU,MAKPGA,PLCKT
	INTERN ASOFN,RELOFN,SETMPG,READB,MRPACS,MSPACS,MRMAP,NOFN
	INTERN MLKPG,MULKPG,FPTA,MRPT,SETPT,DISKP,DRUMP,RWX,SWPCOR
	INTERN DDMP,DELOFN,MONCOR,COPYB,SPT,SPTH,CORWB,SPC1,SWPZPG
	INTERN MULKCR,MULKMP,CST0,CST1,CST2,CST3,MLKMA
	INTERN .MRPAC,PRELDF,SWRSAF,POSPGF,.RWSET
	INTERN SWPINT
	INTERN SWPDON,DWRBIT,SWPERR
	INTERN DSKRT,GCALC,PGRRST,PRELD,PGRTRP,SWPIN0,ASSPT,DESPT
	INTERN SWPRT,SETPPG,GCCOR,XGC,SWPRST,POSTPG,ICAPT,PGRINI
	INTERN MKSHRP,SETDVP

;LINKAGE TO PISRV AND SCHED

EXTERN BHC,BITS,BLOCK1,BUGCHK,BUGHLT,DEVMPE,PSISV2,RSKEDN,PNDING
EXTERN DISGE,DISLT,DRMRD,DRMWR,DSKRD,DSKWR,ETIME,FKCNO,FKJOB,FKNR,CGFLG
EXTERN BSBITS,RLBITS,BKGFLG,EDISMS,DISL
EXTERN FKPGS,FKPT,FKWSP,FORKX,FRECB,FSHBAL,ILIST,FKPT6M,MAXQ
EXTERN INDFLG,INSKED,ISKED,ITRAP,JOBNAM,LSTERR,MAXNRX,MENTR,MINNR
EXTERN MRETN,MSTKOV,NBPROC,NGCLCT,PPCLCT,NPMAX,NRPLQ,NRPMIN,JOBRTT
EXTERN PATCH2,PPG,PSIRQ,PSIRQ0,PSKED,R,RJAV,RJQNT,RPLQ,RSKP,TOPTRP
EXTERN SCHEDP,SCHEDR,SJSIZ,GCCR,SNPMAX,SPFLTS,PTRAP,STIME,SUMNRX
EXTERN TODCLK,TOTRC,WTLST,WTSPT,WTSPTT,POTEN
EXTERN RUNLST,RUNLSB,FKFLGS,WTFK,NOSK,FORCEM,BLST,WTCLCT,RNLS,ZIFA,NOFLT

; LINKAGE TO DSK AND DRM

	EXTERN GDSTX,DRMASN,DSKASN,DASDRM,DEDSK,DRMFRE
	EXTERN CVDSK,UDSKIO
	EXTERN DRMIO,DSKIO

; LINKAGE TO DISC AND FILE SYSTEM

	EXTERN JFNOFN,OFNJFN,JFNDCR,OPNX16,OPNX9,OPNX10

;PARAMETERS

DISKP:	1		;DISK ON SYSTEM
DRUMP:	IFDEF DRMCHN,<1>	;1 = DRUM AVAIL,
	IFNDEF DRMCHN,<0>	;0 = USE DISK, -1 = USE NOTHING
PRELDF:	0		;NO PRELOADING IF 0
SWRSAF:	0		;REASSIGN SWAP ADDRESSES IF .G. 0
POSPGF:	0		;POST PURGE IF .G. 0


LS NHIPG,1		;HIGEST PAGE USED BY SWAPPER
LS SPTC,1		;COUNT OF SPT (EXCLUDING OFN) ENTRIES IN SPT
LS NOF,1		;COUNT OF ENTRIES IN OFN PART OF SPT
LS FRESPT,1		;FREE SPT LIST
LS MAXSPL,1		;MAX NUMBER OF PROBES TO SPTH
LS MMSPTN,1		;OFN OF MONITOR MAP
GS LOKPGS,1		;COUNT OF LOCKED PAGES, VIA MLKPG
GS LOKSUM,1		;NET NUMBER OF LOCKS, MLKPG-MULKPG
GS MAXLOK,1		;MAX NUMBER OF PAGES TO BE LOCKED
GS NXTDMP,1		;FLAG TO CAUSE DDMP ACTION
GS DDTIME,1		;TIME NEXT DDMP DUE
LS IOIP,1		;SWAP WRITES IN PROGRESS
GS DRMIN0,1		;DO NOT PERMIT NEW JOB IF DRUM SPACE LT THIS
GS DRMIN1,1		;DDMP DELETES DRUM ADDRESSES IF DRUM SPACE
			;FALLS BELOW THIS
GS DRMIN2,1		;SWPOUT WILL NOT ASSIGN NEW DRUM ADDRESSES
			;FOR PAGES WITH DISK ADDRESSES
			;IF DRUM SPACE FALLS BELOW THIS
GS PRELRQ,1		;PRELOADING SWAPIN IF NON-0
GS JDSPTP,1		;SPT INDEX FOR NORMAL JSYS DISPATCH VECTOR

; FOLLOWING CELLS USED IN REMOVING PAGES FROM SWAPPABLE STORE
GS PGELCT,1	; COUNT OF LOCKED PAGES FOUND TRYING TO REMOVE PAGES

SPC0:	EXP <SSPT-NOFN>*5/6
SPC1:	EXP SSPT-NOFN-40

;INITIALIZATION, SPT, CST, ETC.

PGRINI:	SETZM SPTC
	SETZM NOF
	SETZM MAXSPL
	MOVEI 1,SPT+NOFN
	MOVEI 2,SSPT-NOFN
	CALL ILIST		;MAKE LIST OF FREE SPT ENTRIES
	MOVEM 1,FRESPT
	SETZM SPTH
	MOVE 1,[XWD SPTH,SPTH+1]
	BLT 1,SPTH+NOFN-1	;ZERO OUT SPTH
	CALL ASSPT		;ASSIGN SPT SLOT FOR MMAP
	MOVE 2,[XWD 1B31,MMAP/1000]
	MOVEM 2,SPT(1)
	MOVEM 1,MMSPTN
	MOVSI 2,0(1)
	SETZ 1,			;START WITH CORE PAGE 0
	MOVSI 3,400000
	MOVSI 4,RWXB
PGRI1:	MOVEM 1,MMAP(2)		;MAKE MAPPED MON EQUIVALENT TO UNMAPPED
	HLLM 4,MMAP(2)		;PRIVATE POINTER, ALL ACCESS
	MOVEM 3,CST0(1)		;LEGAL AGE WORD
	MOVEM 1,CST1(1)		;BACKUP ADDRESS IS SELF
	MOVEM 2,CST2(1)		;OFN.PN
	ADDI 1,1
	CAMGE 1,SWPCOR		;FILL TO END OF RES MON
	AOJA 2,PGRI1
	MOVSI 4,010000
PGRI2:	MOVEM 4,CST0(1)		; MAKE REST OF CORE UNAVAILABLE
	SETZM CST1(1)
	SETZM CST2(1)
	SETZM CST3(1)
	CAIGE 1,MAXCOR-1
	 AOJA 1,PGRI2
	MOVSI 4,WRITEB
	ANDCAM 4,MMAP+1		;PROTECT JSYS TABLE
	MOVEI 3,PATCH2+777
	LSH 3,-^D9		;FIRST PAGE OF RES MON
IFE JTRPSW-1,<			;IF MAPPING RES MON FOR JSYS TRAPS
	JRST PGRI6		;DON'T WRITE PROTECT RES MON
	      >			;TEMPORARY TO ALLOW BUGCHK AND BUGHLT
PGRI5:	CAIGE 3,100		;DON'T PROTECT PAGES ALWAYS MAPPED
	ANDCAM 4,MMAP(3)	;WRITE PROTECT RES MON
	ADDI 3,2
	CAMGE 3,MONCOR		;MON WILL BE WRITE PROTECTED IF
	SOJA 3,PGRI5		;MAPRESMON FLOP MANUALLY TURNED ON
IFE JTRPSW-1,<
PGRI6:	       >		;TO AVOID WRITE PROTECT
	ADDI 2,MMAP+2
	HRLI 2,-1(2)
	SETZM -1(2)
	BLT 2,MMAP+PJMPG-1	;ZERO REMAINDER OF MON MAP
	SETZM TOTRC
	SETZM NRPLQ
	MOVE 2,[XWD RPLQ,RPLQ]
	MOVEM 2,RPLQ		;REPLACEMENT QUEUE EMPTY
	SETZM PNDING
	SETZM SUMNRX
	MOVE 1,[DRMII2]		;INITIAL VALUE FOR DRMIN2
	MOVEM 1,DRMIN2		;NO NEW DRUM ASSIGNMENTS BELOW THIS
	MOVE 1,[DRMII1]		;INITIAL VALUE FOR DRMIN1
	MOVEM 1,DRMIN1		;DEASSIGN PAGES TRICKLED TO DISK
				;IF DRMFRE FALLS BELOW THIS

	MOVE 1,[DRMII0]		;INITIAL VALUE FOR DRMIN0
	MOVEM 1,DRMIN0		;NO NEW JOBS
				;IF DRMFRE FALLS BELOW THIS

	SETZM PGR71
	MOVSI 1,400000
	MOVEM 1,PGR72
	CALL PGRRST
	MOVE 1,SWPCOR
	MOVEI 2,MAXCOR-1
	CALL MAKPGA		; MAKE ALL PAGES AVAILABLE
	MOVE 1,NRPMX		;INITIALIZE NRPMIN
	MOVEM 1,NRPMIN
	CALL ASSPT		;GET SPT SLOT FOR JSYS DISP VECTOR
	MOVEI 2,NJDVPG
	DPB 2,[POINT 22,SPT(1),35]	;SET SPT WORD TO PT TO PAGE
	MOVEM 1,JDSPTP		;SAVE SPT INDEX FOR PAGE
	RET

PGRRST:	PGRCLD			; .. (CONO 0) AND DATAO PROT + REL
	PGRON			;TURN ON AND LOAD PAGER. (CONO 6)
	RET

NRPMX:	5		;RPLQ MIN, SHOULD BE .G. MINNR

;BOUNDARIES SET BY POSTLD

MONCOR:	0			;NUMBER PAGES OF RES MON
SWPCOR:	0			;FIRST PAGE OF REAL CORE FOR SWAPPING

;RESTART SWAPPER - REINITIATE IO OPERATIONS IN PROGRESS AT TIME OF CRASH

SWPRST:	SETZM IOIP
	MOVE 6,SWPCOR		;SCAN CST AND CHECK STATE OF PAGES
SWPRS1:	LDB 1,[POINT 6,CST0(6),5] ;GET STATE CODE
	CAIN 1,06		;READ IN PROGRESS?
	JRST SWPRSR		;YES, GO RESTART IT
	CAIN 1,04		;WRITE?
	JRST SWPRSW		;YES
SWPRS2:	CAMGE 6,NHIPG		;LOOKED AT ALL PAGES?
	AOJA 6,SWPRS1		;NO
	RET

SWPRSW:	MOVSI 1,DWRBIT		;WRITE OPERATION
	AOSA IOIP		;COUNT WRITES IN PROGRESS
SWPRSR:	SETZ 1,			;READ OPERATION
	HRRI 1,0(6)
	MOVE 2,CST1(6)		;BACKUP ADDRESS
	TLNE 2,10		;DISK?
	JRST SWPRS3		;YES
	TLNN 2,16		;DRUM?
	BUG(HLT,<ILLEGAL ADDRESS IN CST1 ENTRY, CAN'T RESTART>)
	CALL DRMIO
	JRST SWPRS2

SWPRS3:	CALL DSKIO
	JRST SWPRS2

;PERIODIC ROUTINE TO TRICKLE PAGES TO DISK

DDMP:	MOVE 1,TODCLK
	CAMGE 1,DDTIME		;TIME YET?
	RET			;NO
	SKIPE DISKP		;DISK ON SYSTEM, AND
	SKIPE NXTDMP		;DUMP REQUESTED?
	RET			;NO
	ADDI 1,^D60000		;NEXT ONE DUE IN 30 SEC.
	MOVEM 1,DDTIME
	SETZ 0,			;CLEAR FLAGS
	MOVE 1,DRMFRE
	CAMGE 1,DRMIN1		;ENOUGH DRUM SPACE?
	TLO 0,(1B0)		;NO, TAKE SPECIAL ACTION
	AOS NXTDMP		;TO DETECT REQUESTS DURING ROUTINE
	MOVE 11,FORKX		;CONSTRUCT HANDLE FOR DDPG2
	HRLZ 11,FKPGS(11)
	HRRI 11,DDPG2		;WILL BE USED LATER
	MOVSI 10,-NOFN		;PREPARE TO SCAN ALL OFN'S
	AOBJN 10,.+1		;0 NOT USED
DDMP9:	NOSKED
	MOVE 1,SPTH(10)		;GET HASH WORD FOR THIS OFN
	JUMPLE 1,DDMP1S		;NOT IN USE
	MOVE 1,SPT(10)		;IN USE, GET CURRENT ADR
	TLNE 1,10		;XB ON DISK?
	JRST DDMP1E		;FORGET IT
	MOVSI 2,SPTLKB
	IORM 2,SPTH(10)		;LOCK OFN AGAINST RELEASE
	MOVEI 1,0(10)		;MAP THE XB
	MOVE 2,[XWD RWX,DDPG1A]
	CALL SETMPG
	SETZ 6,
	PUSH P,6
	CALL DDMPXA		;GET XB DISK ADDRESS
	MOVEM 6,0(P)		; SAVE WRITE FLAG FOR XB
	CAIGE 7,DST+NDST	;IN DST?
	CAIGE 7,DST
	JRST .+3		;NO
	MOVSI 3,BWRBIT		;YES, CLEAR BACKUP WRITE BIT
	ANDCAM 3,0(7)
	OKSKED
	MOVE 2,[XWD DDPG2A,DDPG2A+1]
	SETZM DDPG2A		;ZERO A PAGE TO GET THE BACKUP XB
	BLT 2,DDPG2A+777
	MOVSI 7,-1000		;SCAN ALL WORDS OF XB
DDMP8:	MOVE 1,DDPG1A(7)	;WORD FROM XB
	JUMPE 1,DDMP61		;QUICK CHECK FOR NULL
	NOSKED
DDMP81:	MOVE 1,DDPG1A(7)	;WORD FROM XB
	JUMPE 1,DDMP6		;NOT IN USE
	TLNN 1,SHRBIT		;SHARE POINTER?
	JRST DDMP4		;NO, PRIVATE
	LSH 1,-^D9		;GET SPT NUMBER
	ANDI 1,SPTM
	MOVE 1,SPT(1)
	TLZ 1,-1B31		;FLUSH SHARE COUNT
	JRST DDMP4

DDMP6:	OKSKED
	JRST DDMP61

DDMP1E:	TLNE 1,-1B31		;SHARE COUNT 0?
	JRST DDMP1S		;NO
	SETOM SPTH(10)		;YES, RELEASE OFN
	SOS NOF
DDMP1S:	OKSKED
	JRST DDMP1

DDMPXA:	MOVE 1,SPT(10)		;SET ABOUT FINDING DISK ADDRESS
	TLNE 1,17
	JRST DDMPX1		;IN DST
	MOVE 7,CST2(1)
	CAIE 7,0(10)		;ALL CONSISTENT?
	JRST DDBAD1		;NO
	MOVE 7,CST0(1)		;GET CORE WRITE BIT
	TLNE 7,(CORMB)		;WRITTEN IN CORE?
	SETO 6,			;YES
	MOVEI 7,CST1(1)		;IF IN CST, REMEMBER WHERE
DDMPX2:	MOVE 1,0(7)
	TLNE 1,10		;DISK?
	RET			;YES, DONE
DDMPX1:	MOVE 2,1
	CALL GDSTX
	MOVE 7,DST(2)		;GET DRUM WRITE BIT
	TLNE 7,BWRBIT		;WRITTEN ON DRUM?
	SETO 6,			;YES
	MOVEI 7,DST(2)		;REMEMBER WHERE DISK ADDRESS IS
	JRST DDMPX2

DDMP4:	TLNE 1,617700		;ANY STRANGE BITS?
	JRST DDBAD		;YES, SKIP IT
	TLNE 1,10		;DISK?
	JRST DDMP3		;YES, ALL SET
	TLNN 1,16		;DRUM
	TLNN 1,17		;OR CORE?
	JRST DDMP5		;YES, PROCESS IT
	JRST DDMP6		;UNASSIGNED, IGNORE IT

DDMP3:	OKSKED
	TLNN 1,10		;JUST MAKE SURE WE HAVE DISK ADR
	JRST DDBAD
	MOVEM 1,DDPG2A(7)	;STORE DISK ADDRESS IS XB COPY
	LDB 1,[POINT 12,DDPG1A(7),13]	;GET ACCESS BITS FROM ORIG PTR
	DPB 1,[POINT 14,DDPG2A(7),13]	;STORE THEM IN XB COPY
DDMP61:	AOBJN 7,DDMP8		;SCAN OVER WORDS IN XB
DDMPXB:	NOSKED
	POP P,1			;GET XB WRITE FLAG
	JUMPE 1,DDMPX3		;DON'T WRITE XB IF NOT CHANGED
	MOVE 1,11		;GET ID OF COPY PAGE
	CALL MLKPG		;LOCK THE PAGE
	PUSH P,1		;SAVE CORE PAGE NUMBER
	CALL DDMPXA		;GET XB DISK ADDRESS
	MOVE 2,[1B14+1000]	;DISK IO CONTROL WORD, WRITE+1000 WORDS
	TLZE 1,NEWFB		;CLEAR NEW FILE BIT
	MOVEM 1,0(7)
	OKSKED
	PUSH P,2
	CALL CVDSK		;CONVERT TO HARDWARE FORMAT
	POP P,2
	POP P,3			;CORE PAGE NUMBER
	LSH 3,^D9
	CALL UDSKIO		;OPERATE DISK
	AOS DSKWR		;COUNT OPERATIONS
	MOVE 6,1		;SAVE ERROR BITS
	MOVE 1,11
	CALL MULKPG		;UNLOCK PAGE
	JUMPN 6,.+1		;NON-ZERO MEANS ERRORS
	NOSKED
DDMPX3:	MOVSI 2,SPTLKB
	ANDCAM 2,SPTH(10)	;UNLOCK OFN
	MOVE 1,DDPG1A		;MAKE SURE XB IN CORE BEFORE UNMAPPING
	SETZ 1,
	MOVEI 2,DDPG1A
	CALL SETMPG		;UNMAP XB
	OKSKED
DDMP1:	AOBJN 10,DDMP9		;COUNT OFN'S
	MOVNS NXTDMP		;RESET IF NO INTERVENING REQUESTS
	SETOM CGFLG		;REQUEST GARBAGE COLLECTION
	RET

DDMP5:	TLNN 1,17		;IN CORE?
	JRST DDMP52		;YES
	MOVE 2,1		;ON DRUM, GET DST WORD
	CALL GDSTX
	MOVE 1,DST(2)
	TLNN 1,BWRBIT		;CHANGED FROM BACKUP?
	JUMPGE 0,DDMP3		;NO, IGNORE IF NOT LOW ON DRUM SPACE
	MOVE 1,DDPG1A(7)	;GET PAGE SWAPPED IN
	TLNE 1,SHRBIT
	JRST DDMP51		;SHARE POINTER, GET SPTN
	MOVSI 1,0(10)		;CONSTRUCT OFN.PN
	HRRI 1,0(7)
DDMP53:	PUSH P,7
	CALL SWPINW		;SWAP IN PAGE AND WAIT
	POP P,7
	JRST DDMP81		;NOW PAGE IS IN CORE

DDMP51:	LSH 1,-^D9		;GET SPTN
	ANDI 1,SPTM
	JRST DDMP53

DDMP52:	TRNE 1,-MAXCOR		;LIKELY PAGE?
	JRST DDBAD		;NO
	MOVSI 6,400000		;FLAG TO NOTE IF WRITING NEEDED
	AND 6,0			;INIT TO DRUM SPACE FLAG
	MOVE 2,CST0(1)
	TLNE 2,(CORMB)		;PAGE WRITTEN WHILE IN CORE?
	SETO 6,			;YES
	MOVE 2,CST1(1)		;GET BACKUP ADR
	TLNE 2,10		;DISK?
	JRST DDMP54		;YES
	CALL GDSTX
	MOVE 2,DST(2)		;GET NEXT BACKUP ADR
	TLNE 2,BWRBIT		;CHANGED ON DRUM?
	SETO 6,			;YES
DDMP54:	JUMPE 6,DDMP55		;DISK ADR NOW IN 2, WRITING NEEDED?
	PUSH P,7
	CALL AGESET		;YES
	POP P,7
	MOVSI 3,DSKSWB
	IORB 3,CST3(1)		;REQUEST DISK SWAP AT NEXT SWAP TIME
	CALL SWPOT0		;SWAP IT OUT NOW
	SETOM 0(P)		;FORCE WRITING OF XB TOO
DDMP55:	MOVE 1,2
	JRST DDMP3

;LOSSAGE PRINTOUT

DDBAD1:	POP P,1
DDBAD:	POP P,1			;FLUSH JUNK
	SETZM NSKED
	HRROI 1,[ASCIZ /
*****BAD INDEX BLOCK, OFN /]
	PSOUT
	MOVEI 1,101
	MOVEI 2,0(10)
	MOVEI 3,^D8
	NOUT
	JFCL
	MOVEI 1,EOL
	PBOUT
	MOVSI 2,SPTLKB
	ANDCAM 2,SPTH(10)	;UNLOCK OFN
	JRST DDMP1

;ASSIGN OFN
; AC1/ 14-35 INDEX BLOCK FILE ADDRESS (DISK, DRUM OR CORE)
;       5-13 CLASS FIELD (IF DISK)
;          1 WRITE BIT
;          2 THAWED BIT
;	   3 NEW FILE BIT
;RETURN SKIP WITH OFN IN AC1 IF PROPER OPENING
;RETURN NO-SKIP IF ILLEGAL SHARED OPENING (ILLEGAL CONFIGURATION
;      OF THAWED AND WRITE BITS)

ASOFN:	TLNN 1,10		;DISK?
	RET			;NO, RETURN BAD
	MOVEI 7,1		;SAY NO GC HAS BEEN DONE YET
ASOF0:	NOSKED
	PUSH P,1

	TLZ 1,-1B31		;FLUSH CLASS AND BITS
	MOVE 6,1
	MOVE 4,MAXSPL		;MAX NUMBER OF PROBES INTO SPTH
	SETO 5,
	SETZ 1,			;START SEARCH WITH 0

ASOF1:	ADDI 1,1		;LOOK LINEARLY
	MOVEI 3,0(1)

REPEAT 0,<			;THIS IS HASH LOOKUP NOT CURRENTLY USED
	IMUL 1,[5654123]	;HASH INDEX BLOCK ADDRESS
	HLRZS 3,1		;USE LEFT HALF
	ANDI 3,NOFN-1		;MAX NUMBER OPEN FILES
	JUMPE 3,ASOF1		;DON'T USE SLOT 0
>
	MOVE 2,SPTH(3)		;GET ENTRY
	JUMPLE 2,ASOF2		;0 IS FREE, -1 IS DELETED
	TLZ 2,-1B31		;FLUSH BITS
	CAMN 2,6		;COMPARE ADDRESSES
	JRST ASOF3		;FOUND
ASOF7:	SOJG 4,ASOF1		;COUNT TRYS AND PROBE AGAIN
	JUMPGE 5,ASOF6		;NOT FOUND. DELETED ENTRY ENCOUNTERED?
	CAIL 1,NOFN-1		;NO, OFN TABLE FULL?
	 JRST ASOFAI		;MAYBE TRY AGAIN AFTER CORE GC
	AOS MAXSPL		;NO, INCREASE MAX LOOK COUNT
	JRST ASOF1		;KEEP LOOKING FOR USABLE SLOT

ASOF2:	JUMPE 2,ASOF4		;FREE => NOT FOUND
	JUMPGE 5,ASOF7		;FIRST DELETED ENCOUNTERED?
	MOVE 5,3		;YES, SAVE IT
	JRST ASOF7

;ASOFN (CONT.)

ASOF4:	JUMPL 5,.+2		;DELETED ENCOUNTERED?
ASOF6:	MOVE 3,5		;YES, USE IT
	POP P,1			;RECOVER CLASS AND BITS
	TLZE 1,1B21		;NEWLY ASSIGNED XB?
	TLO 6,NEWFB		;YES, INDICATE IN DISK ADDRESS
	MOVEM 1,SPTH(3)
	MOVEM 6,SPT(3)		;PUT ADDRESS IN SPT
	AOS NOF			;COUNT OPEN FILES
	MOVSI 1,1B31
	ADDM 1,SPT(3)		;BUMP SHARE COUNT
	PUSH P,3		;SAVE OFN
	CALL SETXB1		;MAP XB
	POP P,3
	OKSKED			;PREVENT PAGE-FAULT WHILE NOSKED .. DCA
	MOVE 1,CXBPGA		;GET XB IN CORE
	NOSKED			;GO NOSKED AGAIN .. DCA
	MOVE 1,SPT(3)		;CORE ADDRESS
	MOVSI 2,SWPERR
	TDNE 2,CST3(1)		;DISK ERROR IN XB?
	JRST ASCHK3		;YES, DON'T OPEN
	MOVSI 1,-1000		;SETUP TO SCAN XB
ASCHK1:	MOVE 2,CXBPGA(1)	;GET WORD FROM XB
	JUMPE 2,ASCHK2		;NOT IN USE
	TLC 2,ACCESB+10		;MUST HAVE ACCESS AND DISK BITS ON,
	TLNE 2,777770-RWX	;RWX AND OTHER ADDRESS BITS DONT CARE,
	JRST ASCHK3		;OTHERS ALL OFF, OTHERWISE DONT OPEN
ASCHK2:	AOBJN 1,ASCHK1
	CALL RELCXB		;OK, RELEASE XB
	JRST ASOF9

ASCHK3:	CALL RELCXB		;FILE NO GOOD, RELEASE XB
	MOVE 1,SPT(3)		;CLEAR OFN AND CORE PAGE
	SETOM SPTH(3)
	SOS NOF
	CALL DECOR
	SETZM CST2(1)
	JSP 4,ONRQ
	MOVEI 1,OPNX16		;ERROR NUMBER FOR BAD XB
SKORET:	OKSKED
	RET			;RETURN BAD


;SHARED OPEN, CHECK WRITE AND THAWED BITS FOR LEGAL COMBINATION

ASOF3:	MOVSI 2,SPTLKB
	TDNE 2,SPTH(3)		;LOCKED BY DDMP?
	JRST ASOFW1		;YES
	POP P,2			;RECOVER CLASS AND BITS
	MOVSI 1,-1B31
	TDNN 1,SPT(3)		;SHARE COUNT 0?
	JRST ASOF8		;YES (FILE EFFECTIVELY NOT OPEN)
	MOVE 1,SPTH(3)		;GET EXISTING BITS
	XOR 1,2			;XOR PRODUCES 0 IF BITS THE SAME
	TLNE 1,THAWB		;THAWED BITS EQUAL?
	JRST ASOFB		;NO, ILLEGAL OPEN
	MOVE 1,SPTH(3)
	IOR 1,2
	TLNN 1,FILWB		;BOTH WRITE BITS 0?
	JRST ASOF5		;YES, LEGAL OPENING, NO CHANGE TO WB
	TLNN 1,THAWB		;THAWED BITS 1?
	JRST ASOFB		;NO, ILLEGAL TO HAVE SHARED WRITING
	AND 2,[XWD FILWB,0]	;LEGAL OPENING, THAWED BITS BOTH 1
	IORM 2,SPTH(3)		;IOR WRITE BITS
ASOF5:	MOVSI 1,1B31		;INCREMENT SHARE COUNT
	ADDM 1,SPT(3)
ASOF9:	OKSKED
	MOVEI 1,0(3)		;RETURN OFN (SPT INDEX)
	JRST RSKP

ASOF8:	MOVE 1,SPT(3)
	TLNE 1,17		;NOW IN CORE?
	JRST ASOF81		;NO
	MOVSI 4,DWRBIT		;YES, WAIT FOR ANY WRITE TO COMPLETE
	TDNE 4,CST3(1)
	JRST ASOFW2
ASOF81:	XOR 2,SPTH(3)		;SET THAW AND WRITE BITS TO GIVEN
	AND 2,[XWD FILWB+THAWB,0]
	XORM 2,SPTH(3)
	JRST ASOF5		;RETURN OK

ASOFB:	MOVEI 1,OPNX9		;ERROR NUMBER FOR FILE BUSY
	JRST SKORET

ASOFW2:	SKIPA 1,2
ASOFW1:	POP P,1
	OKSKED			;HAVE TO WAIT FOR SOMETHING
	CAIA			;WAIT A LITTLE WHILE, THEN TRY
	JRST ASOFN		;AGAIN FROM THE TOP
	JSYS BLOCK1		;THIS RETURNS .-1


ASOFAI:	SOJL 7,ASOFA1		;BEEN HERE BEFORE?
	OKSKED
	MOVEI 1,FSHBAL		;POS. NUMBER
	MOVEM 1,FSHBAL		;REQUEST TO GC CORE BUT KEEP ONLINE
	CALL DISE##		;WAIT FOR IT TO HAPPEN
	SETZM NXTDMP
	SETZM DDTIME		;CAUSE DDUMP TO RUN
	AOS JB0FLG##
	MOVEI 1,NXTDMP
	CALL DISL##		;WAIT FOR IT TO BE DONE
	POP P,1			;RECOVER ARG
	JRST ASOF0		;TRY ONCE MORE

ASOFA1:	POP P,1			;FLUSH ARG
	MOVEI 1,OPNX10		;"NO ROOM"
	JRST SKORET		;OKSKED AND RETURN

;RELEASE OPEN FILE NUMBER, OFN IN AC1

RELOFN:	CALL CKSPLK		; CHEK IF SPT LOCKED BY DDMP. RET NOSKED
	MOVEI 3,0(1)
	CALL SETXB1		;MAP INDEX BLOCK
	LDB 2,[POINT 14,SPT(1),13] ;GET SHARE COUNT
	SETO 4,			;RETURN -1 IF NOT COMPLETELY CLOSED
	CAIE 2,1		;IS THIS FINAL CLOSE?
	JRST RELOF1		;NO
	MOVSI 3,-1000		;SCAN XB
	SETZ 4,			;INIT COUNT OF IN-USE PAGES
RELOF3:	MOVE 2,CXBPGA(3)	;GET XB WORD
	JUMPE 2,RELOF2		;EMPTY
	TLNN 2,10		;ADDRESS OK IF ON DISK OR IN CORE
	TLNN 2,16
	TLNE 2,SHRBIT+INDBIT	;POINTER TYPE OK IF PRIVATE
	JRST RELBAD
	TLNN 2,10
	TLNN 2,17		;UNREFERENCED PAGE?
	AOJA 4,RELOF2		;NO, COUNT IN-USE PAGE
	SETZM CXBPGA(3)
RELOF2:	AOBJN 3,RELOF3
RELOF1:	MOVSI 2,-1B31		;REDUCE SHARE COUNT OF XB ONCE MORE
	ADDM 2,SPT(1)		;FOR CLOSING
	MOVE 1,SPT(1)
	TLNN 1,-1B31		;STILL IN USE?
	CALL SWPOT0		;NO, SWAP OUT
	MOVE 1,4
	CALL RELCXB		;RELEASE TEMP MAPPING
	OKSKED
	RET

RELBAD:	BUG(CHK,<BAD POINTER TYPE IN INDEX BLOCK>)
	MOVE 2,SPT(1)
	MOVSI 3,SWPERR
	IORM 3,CST3(2)		;INDICATE ERROR IN PAGE SO IT WON'T
	JRST RELOF1		;BE WRITTEN ON DISK

CKSPLK:	NOSKED
	MOVSI 2,SPTLKB
	TDNN 2,SPTH(1)
	 RET
	OKSKED
	HRLZS 1
	HRRI 1,SPLTST
	JSYS EDISMS
	HLRZS 1
	JRST CKSPLK

SPLTST:	MOVSI 2,SPTLKB
	TDNN 2,SPTH(1)
	 JRST 1(4)
	JRST 0(4)

;ASSIGN PSB FOR NEW PROCESS

ASPSB:	NOSKED
	CALL ASSPT
	JRST SKORET

ASSPT:	SKIPG 1,FRESPT		;ANY FREE CELLS?
	BUG(HLT,<SPT COMPLETELY FULL>)
	MOVE 1,0(1)
	EXCH 1,FRESPT
	SUBI 1,SPT
	AOS SPTC		;ASSIGN SPT SLOT
	MOVSI 2,1B31+1
	MOVEM 2,SPT(1)		;SHARE COUNT OF 1, NO ADDRESS
	SETZM SPTH(1)
	RET

;DEASSIGN SPT AND RELEASE STORAGE

DESPTN:	NOSKED
	CALL DESPT
	JRST SKORET

DESPT:	MOVSI 2,-1B31
	ADDB 2,SPT(1)		;REDUCE SHARE COUNT
	TLNE 2,-1B31		;NOW ZERO?
	BUG(HLT,<TRIED TO RELEASE SPT SLOT BUT SHARE COUNT NOT 0>)
	MOVE 3,2
	PUSH P,1
	CALL REMFP1		;RELEASE CORE AND/OR DRUM
	POP P,1
	ADDI 1,SPT
	EXCH 1,FRESPT		;PUT ON FREE LIST
	EXCH 1,@FRESPT
	SOS SPTC
	RET

;DELETE XB ASSOCIATED WITH OFN
;LAST STAGE OF DELETE FILE

DELOFN:	CALL WTSPT		;WAIT FOR SPT TO BE UNSHARED
	NOSKED
	JSP 4,WTSPTT		;SHARE COUNT NOW 1?
	JRST DELO1		;NO, GO WAIT SOME MORE
	MOVSI 2,-1B31		;SHARE COUNT SHOULD NOW BE 1
	ADDB 2,SPT(1)		;FOR LAST OPENING
	TLNE 2,-1B31		;NOW 0?
	BUG(HLT,<TRIED TO DELETE INDEX BLOCK BUT SHARE COUNT NOT 0>)
	MOVE 3,2
	SETOM SPTH(1)
	PUSH P,1
	CALL REMFP1		;DELETE ALL STORAGE
	POP P,1
	SOS NOF
	OKSKED
	RET

DELO1:	OKSKED
	JRST DELOFN

;READ MAP GIVEN VIRTUAL ADDRESS

MRMAP:	CALL FPTA		;GET PAGE TABLE ADDRESS

;GENERAL MAP READ
;ENTER HAVING PTN.PN IN 1
; RETURN +1 IF PTN.PN
; RETURN +2 IF OFN.PN

MRPT:	CALL SETCPT
	MOVE 2,CPTPGA(1)	;GET MAP WORD
	JUMPE 2,RDMQ5		;EMPTY
	PUSH P,1		;SAVE ORIG IDENT
	PUSH P,2
	TLNN 2,SHRBIT+INDBIT	;PRIVATE?
	JRST MRMP		;YES
	TLNN 2,SHRBIT		;SHARED OR INDIRECT
	JRST MRMI		;INDIRECT
	LSH 2,-^D9		;GET SPT NUMBER
	ANDI 2,SPTM
	CAIL 2,NOFN		;INDEX BLOCK?
	MOVE 2,SPTH(2)		;NO, GET OFN.PN
MRM1:	MOVE 1,2
	HLRZ 2,1
	CAIL 2,NOFN		;OWNED BY OFN?
	JRST MRMQ		;NO
	AOS -2(P)		;YES, SKIP RETURN
MRMQ1:	POP P,2			;ORIGINAL POINTER
	POP P,3			;FLUSH ORIG IDENT
	AND 2,[XWD RWX+TRAPUB+COPYB,0]
	TLO 2,1B23		;EXISTS BIT
	JRST RELCPT

MRMI:	LSHC 2,-^D9		;RE-FORMAT INTO OFN.PN OR PTN.PN
	ANDI 2,SPTM
	LSH 3,-^D9
	LSHC 2,^D18
	JRST MRM1

MRMP3:	SUB P,BHC+3		;CLEAR STACK
RDMQ5:	SETZB 1,2		;RETURN 0
	JRST RELCPT

MRMQ:	CAME 1,-1(P)		;OWNED BY ORIG IDENT?
	JRST MRMQ1		;NO
MRMP:	PUSH P,1
	HLRZ 2,1
	CAMN 2,MMSPTN		;SWP MON MAP?
	JRST MRMP1		;YES, DON'T PUT IN PMF
	CALL RELCPT
	SKIPGE 1,JOBPMF		;ASSIGN NEW PAGE FROM PMF
	JRST MRMP3		;DON'T HAVE ONE, RETURN 0
	FFFFP
	CALL JFNOFN
	BUG(HLT,<FAILED TO CONVERT JFN FROM FFFFP TO OFN>)
	MOVSI 3,RWX		;PUT PAGE IN PMF WITH ALL ACCESS
	MOVE 2,1
	EXCH 1,0(P)
	CALL SETPT		;PUT PAGE IN PMF
MRMP1:	POP P,2			;OFN.PN OF NEW PAGE
	JRST MRM1

;READ PAGE ACCESSIBILITY
; CALL:	IN 1	; PTN.PN
;	CALL MRPACS
; RETURNS:
;	IN 1	; PAGE ACCESS PER RPACS SPEC
;	IN 3	; LAST PAGE TABLE ENTRY (MEANINGLESS UNLESS USRLKB)
; CLOBBERS AC 2

MRPACS:	PUSH P,[0]
	PUSH P,[XWD RWXB+TRAPUB+COPYB+USRLKB,0]
MRP4:	HLRZ 3,1		;SOURCE PTN
	CAIG 3,0
	BUG(HLT,<ILLEGAL LH OF 1 ARG TO MRPACS>)
	CALL SETXB1		;MAP PT
	MOVE 3,CXBPGA(1)	;GET MAP WORD
	SKIPN -1(P)		;FIRST MAP WORD?
	HLRZM 3,-1(P)		;YES, SAVE FIRST PT ACCESS
	TLC 3,TRAPUB+COPYB+USRLKB	;FOR THESE BITS, WE'RE AND'ING 0'S
	ANDM 3,0(P)		;COMPUTE AND OF ALL MAP WORDS
	TLNN 3,INDBIT		;INDIRECT?
	JRST MRP2		;NO, SHARED OR PRIVATE
	CALL RELCXB
	ROTC 2,-^D9		;REFORMAT INTO PTN.PN
	ANDI 3,SPTM
	LSH 3,^D9
	ROTC 2,^D9
	MOVE 1,3
	JRST MRP4

MRP2:	POP P,1			;AND OF ALL MAP WORDS
	POP P,2			;FIRST POINTER ACCESS
	TLC 1,TRAPUB+COPYB+USRLKB	;BITS FOR WHICH AND'ING 0'S
	JUMPE 2,RELCXB		;RETURN 0 IF FIRST POINTER WAS 0
	TRNN 2,SHRBIT+INDBIT	;FIRST PTR PRIVATE?
	TLO 1,(1B10)		;YES, SO INDICATE
	TLZE 1,ACCESB		;ANY ACCESS?
	TLO 1,(1B5)		;YES, SET BIT IN RESULT
	TRNE 2,INDBIT		;FIRST POINTER INDIRECT?
	TLO 1,(1B6)		;YES, NOTE
	ANDI 2,RWX+TRAPUB+COPYB+USRLKB	;BITS OF ORIG PTR TO GIVE TO USER
	HRRI 1,1B23(2)		;ORIG PTR ACCESS WITH EXISTS BIT TO RH
	TLNN 3,SHRBIT		; SHARE POINTER?
	JRST RELCXB		;RELEASE PT AND RETURN
	LSH 3,-9		; YES, EXTRACT
	ANDI 3,SPTM		; SPT INDEX
	MOVE 3,SPT(3)
	TLNN 3,16		; DISC OR DRUM?
	TLNN 3,1		; NO -- NON-EXISTENT
	 JRST RELCXB		; EXISTS, DONE
	TLZ 1,(1B5)		; NON-EXISTENT, CLEAR "EXISTS" BIT
	JRST RELCXB

;MRPAC - JSYS FOR MONITOR DDT

.MRPAC:	JSYS MENTR
	MOVE 2,0(P)		;RETURN PC
	TLNE 2,UMODF		;FROM MONITOR?
	JRST ITRAP		;NO, ILLEGAL FROM USER
	TLNE 1,400000		;USER?
	JRST [	CALL FPTA	;YES, GET PTN.PN
		JRST MRPC3]
	MOVEI 2,0(1)		;MONITOR, GET ADDRESS
	CAIL 2,100000		;RESIDENT MON?
	JRST MRPC5		;NO.
REPEAT 1,<	;REMOVE THIS CODE TO ASSUME RESIDENT MON IS NEVER MAPPED
	NOSKED			;YES. SEE IF THE RESIDENT MON IS MAPPED
	SETCM 3,PGR72		;PICK UP NOT-(THE CURRENT AGE REGISTER)
	TLO 3,100000		;MAKE SURE THAT IT WON'T CAUSE A TRAP
	EXCH 3,CST0/1000+CST0	;NOW THE AGE OF CST0 IS NOT CURRENT
	MONCLR (<CST0/1000+CST0>/1000) ;CLEAR AR'S USED FOR MAPPING CST0
	EXCH 3,CST0/1000+CST0	;GET THE (UPDATED?) CST0 ENTRY FOR CST0
	XOR 3,PGR72		;COMPARE WITH THE PAGER AGE REGISTER
	OKSKED
	TLNN 3,777000		;HAS THE CST0 ENTRY BEEN UPDATED?
	JRST MRPC6		;YES. THE RESIDENT MON IS BEING MAPPED
>		;END OF CODE TO DETERMINE WHETHER RESIDENT MON IS MAPPED
	MOVSI 1,RWX+1B28	;NO. MEANS PRIVATE AND ALL ACCESS
	JRST MRPC2

MRPC5:	CAIGE 2,PPRMA		;NON-RES MON?
	JRST MRPC6		;NO. MAPPED RESIDENT MONITOR
	CAIL 2,CXBPGA		;CHECK SPECIAL PAGES
	CAILE 2,CPYPGA		;SETPT, ETC. PAGES?
	CAIGE 2,PPRMA+NRSPG*1000 ;SWAPPER PAGES?
	JRST MRPC1		;YES, RETURN NO-ACCESS
	CALL FPTA
MRPC3:	CALL MRPACS
MRPC2:	UMOVEM 1,2		;RETURN RESULT IN 2 LIKE RPACS
	JRST MRETN

MRPC1:	MOVSI 1,(1B10)		;NO-ACCESS
	JRST MRPC2

MRPC6:	LSH 2,-^D9		;HERE FOR MAPPED RESIDENT MONITOR
	SKIPE 1,MMAP(2)		;REQUESTED PAGE EXISTS?
	TLO 1,1B28		;YES
	JRST MRPC2		;RETURN CONTENTS OF MMAP

;SET PAGE ACCESSIBILITY

MSPACS:	PUSH P,2		; SAVE DESIRED PAGE ACCESS
	CALL SETCPT		;MAP PT
	POP P,2
	SKIPN 3,CPTPGA(1)	;PAGE EXISTS?
	 JRST RELCPT		; NO. IGNORE CALL
	CAMGE 1,[NOFN,,0]	; FILE PAGE
	 TLZ 2,TRAPUB+COPYB+USRLKB
				; YES, DISALLOW THESE
	TLNE 3,INDBIT!SHRBIT	; NOT PRIVATE POINTER?
	 TLZ 2,USRLKB		; YES, FORBID USER LOCK
	XOR 3,2			; GET BITS THAT ARE BEING CHANGED
	AND 3,[XWD RWX+TRAPUB+COPYB+USRLKB,0]
	XORM 3,CPTPGA(1)	; CHANGE THE ONES WE WANT
	TLNN 3,USRLKB		; CHANGE USRLKB?
	 JRST RELCPT		; NO, DONE
	TLNN 2,USRLKB		; NOW LOCKED?
	 JRST MULKPG		; NO, UNLOCK THE PAGE
	JRST MLKPG		; YES, LOCK THE PAGE


;SET PAGE IN MONITOR OR USER MAP (INTERNAL MONITOR CALL)
; AC1/ OFN,,PN   (OFN IS SPT POINTER, PN IS 0-777)
; AC2/ 18-35 VIRTUAL ADDRESS OF PAGE (NOT PAGE NUMBER)
;       0    1 => USER MAP, 0 => MONITOR MAP
;       2-4, 8, 9  READ, WRITE, XCT ALLOW BITS (SAME AS PAGER MAP WORD)

SETMPG:	ADD P,BHC+7		;SAVE AC'S
	JUMPGE P,MSTKOV
	MOVEM 1,-6(P)		;THIS IS FASTER THAN BLT OR PUSH
	MOVEM 2,-5(P)
	MOVEM 3,-4(P)
	MOVEM 4,-3(P)
	MOVEM 5,-2(P)
	MOVEM 6,-1(P)
	MOVEM 7,0(P)
	HLLZ 3,2		;GET ACCESS AND DISPOSAL
	PUSH P,3
	EXCH 1,2
	CALL FPTA		;CONVERT ADDRESS TO PTN.PN
	JRST SETP8

;SET PAGE TABLE (FOR PROCESS OR FILE)
; AC1/ SOURCE IDENTIFIER
; AC2/ DESTINATION IDENTIFIER
; AC3/ 2-4, 8, 9 ACCESS PERMISSION, 15-17 DISPOSAL

;IDENT IS OFN.PN (PAGE IN FILE), 0.OFN (INDEX BLOCK),
; PTN.PN (PAGE IN PROCESS), OR 0.PTN (PROCESS PT)

SETPT:	ADD P,BHC+7		;SAVE AC'S
	JUMPGE P,MSTKOV
	MOVEM 1,-6(P)
	MOVEM 2,-5(P)
	MOVEM 3,-4(P)
	MOVEM 4,-3(P)
	MOVEM 5,-2(P)
	MOVEM 6,-1(P)
	MOVEM 7,0(P)
	PUSH P,3		;SAVE ACCESS BITS
	EXCH 1,2
SETP8:	CALL RELMPG		;RELEASE EXISTING PAGE
	 JRST SETPT1		; RELMPG FAILED
	JUMPE 2,SETPT1		;NO NEW PAGE TO SET
SETP5A:	CAMN 1,2		;DON'T ALLOW MAP TO SELF
	JRST SETPF1
	HLRZ 3,2		;GET OFN
	JUMPE 3,SETMXB		;OFN=0 MEANS SPTN IN RH
	TDNE 2,[XWD -SPTM-1,777000] ;LEGAL PTN AND PN?
	BUG(HLT,<ILLEGAL SOURCE IDENTIFIER GIVEN TO SETPT>)
	CALL SETXB1		;MAP INDEX BLOCK
SETP72:	MOVE 3,CXBPGA(2)	;GET WORD FROM XB
	HLRZ 4,1		;GET DESTINATION PTN
	CAIGE 4,NOFN		;FILE?
	JRST SETP7		;YES
	HLRZ 4,2		;GET SOURCE PTN
	CAIL 4,NOFN		;PROCESS?
	JRST SETP5		;YES, GO SETUP INDIRECT POINTER
	TLNE 3,SHRBIT+INDBIT	;PRIVATE?
	JRST SETMP3		;NO
	TLNN 3,ACCESB		;PAGE EXISTS?
	JRST SETP3		;NO, GO CREATE IT
SETP4:	MOVE 4,SPTC		;YES
	CAMGE 4,SPC0		;ROOM IN SPT? (SPT < C FULL)
	JRST SETMP6		;YES
	SETCM 4,3		;GET ACCESS OF SOURCE
	TLNE 4,RWX		;ALL POSSIBLE?
	SKIPG FRESPT		;NO, SHOULDN'T USE IND PTR
	JRST SETP5		;USE IND PTR
	JRST SETMP6		;USE SHR PTR

;HERE, WE ARE SUPPOSED TO RETURN AN INDIRECT POINTER.

;1/	DESTINATION ID (PTN,,PN)
;2/	SOURCE ID (PTN,,PN)
;3/	CONTENTS ON SOURCE PAGE TABLE

SETP5:	SKIPGE INDFLG		;ALLOWING USE OF INDIRECT POINTERS?
	JRST SETPF2		;NO, GO TRY ALTERNATIVES
REPEAT 0,<	;OLD CODE
	TLNE 3,INDBIT		;SOURCE CONTAINS IND PTR?
	JFCL [	CALL RELCXB	;YES, TRACE DOWN ;;; REMOVED DUE TO ACCESS CK FAILING
		ROTC 2,-^D9	;CONSTRUCT IDENT OF PAGE POINTED
		ANDI 3,SPTM	;TO BY IND PTR
		LSH 2,-^D9
		ROTC 2,-^D18
		JRST SETP5A]	;AND USE THAT AS SOURCE
	>
REPEAT 1,<	;NEW CODE

;CHECK TO FORBID INDIRECT POINTER LOOP.  EVERY VIRTUAL ADDRESS MUST
;EVENTUALLY POINT TO A PHYSICAL STORAGE ADDRESS.  INDIRECT LOOP IS
;CHECKED BY TRACING THE CHAIN TO SEE IF IT EVER POINTS AT THE
;MAP ENTRY WHERE THE NEW POINTER WILL BE PLACED.

	MOVE 5,2		;SAVE FOR SETP58
	TLNN 3,INDBIT		;SOURCE PT CONTAINS AN @ PTR?
	 JRST SETP58		;NO. PRIVATE, SHARED, OR EMPTY

SETP51:	LDB 2,[POINT 13,3,26]	;GET @ PTN
	ANDI 3,777		;GET @ PN
	MOVSS 2
	IORI 2,0(3)		;FORM @ PTN,,PN  ID
	CAMN 2,1		;SAME AS DESTINATION
	 JRST SETPF1		;YES.  THIS PMAP WOULD FORM LOOP IF
				;ALLOWED TO FINISH.
	HLRZ 3,2		;GET PTN FOR SETXB1
	JUMPE 3,SETP58		;SPT -- OK.
	CALL SETXB1		;MAP IT
	OKSKED
	SKIP CXBPGA
	NOSKED
	MOVE 3,CXBPGA(2)	;GET CONTENTS OF @ PT WORD
	HLRZ 4,3		;GET OFN/PTN
	CAML 4,[NOFN,,0]	;IF @ TO FILE PAGE, GET OUT (OK)
	TLNN 3,INDBIT		;IF NOT ANOTHER @, OK TOO.
	CAIA
	 JRST SETP51		;LOOP THROUGH ANOTHER @ LINK

SETP58:	MOVE 2,5
	>
	LSHC 2,-^D9		;CONSTRUCT INDIRECT POINTER
	LSH 2,-^D9
	LSHC 2,^D9
	TLO 2,ACCESB+INDBIT
SETMP4:	LDB 3,[POINT 13,2,26]	;GET OFN OF INDEX BLOCK
SETMP5:	MOVSI 4,1B31
	CAIE 3,0		;IF NO OWNING PT
	ADDM 4,SPT(3)		;INCREMENT SHARE COUNT OF INDEX BLOCK
	POP P,3			;RECOVER ACCESS BITS
	XOR 2,3			;PUT ACCESS BITS IN PTR
	TLZ 2,RWX+TRAPUB+COPYB	;USER ALLOWED TO SPECIFY THESE
	XOR 2,3
	MOVEM 2,CPTPGA(1)	;PUT MAP WORD IN MAP
SETPT2:	CALL RELCPT		;RELEASE PT MAPPING
	CALL SWPCXB		;GET RID OF INDEX BLOCK
	MOVE 1,-6(P)
	MOVE 2,-5(P)
	MOVE 3,-4(P)
	MOVE 4,-3(P)
	MOVE 5,-2(P)
	MOVE 6,-1(P)
	MOVE 7,0(P)
	SUB P,BHC+7
	CALL RELCXB
	OKSKED
	RET

SETPT1:	POP P,3			;FLUSH ACCESS BITS
	JRST SETPT2

SETP3:	MOVSI 3,RWXB+1
SETP3A:	MOVEM 3,CXBPGA(2)	;PUT IN XB
	JRST SETP4

;SETMPG (CONT.)

SETPF2:	TLNE 3,SHRBIT+INDBIT	;SHARED NOW?
	JRST SETMP3		;YES, USE SAME POINTER
	JUMPE 3,[MOVSI 3,RWXB+1	;IF SOURCE CURRENTLY EMPTY,
		JRST SETP3A]	;USE UNASSIGNED ADDRESS INDICATION
	SKIPLE FRESPT		;ANY SPT SPACE AT ALL?
	JRST SETMP6		;YES, GO ASSIGN A SLOT
	MOVEI 1,		;GIVE ERROR INDICATION
	JRST SETPTE

SETMP3:	MOVE 2,3		;ALREADY SHARED, USE SAME POINTER
	TLNE 2,INDBIT		;INDIRECT?
	JRST SETMP4		;YES
SETMP7:	LDB 3,[POINT 13,2,26]
	MOVSI 4,1B31		;SHARED,
	ADDM 4,SPT(3)		;INCREMENT SHARE COUNT IN SPT
	HLRZ 3,SPTH(3)		;GET OFN FOR THIS PAGE
	JRST SETMP5		;GO INCREMENT SHARE COUNT OF XB

SETMP6:	SKIPG 4,FRESPT		;ASSIGN NEW SPT SLOT
	BUG(HLT,<SPT COMPLETELY FULL>)
	MOVE 4,0(4)		;GET CDR
	EXCH 4,FRESPT		;LIST OF FREE SLOTS
	SUBI 4,SPT		;MAKE RELATIVE
	AOS SPTC		;COUNT OF USED SPT ENTRIES
	TLNE 3,17		;IN CORE?
	JRST SETP2
	CAME 2,CST2(3)		;CHECK OLD OWNERSHIP
	BUG(HLT,<PAGE TABLE CORE POINTER AND CST2 FAIL TO CORRESPOND>)
	MOVEM 4,CST2(3)		;RECORD NEW LOCATION OF CORE ADDRESS
	HLRZ 6,2		;YES, UPDATE LOCK COUNT FOR
	MOVE 6,SPT(6)		;OWNING PT
	MOVSI 5,-PLKV		;REDUCE IT, BECAUSE IT WILL HAVE
	ADDM 5,CST1(6)		;ONE LESS CORE ADDRESS IN IT
SETP2:	TLZ 3,-1B31		;FLUSH BITS IN ORIGINAL POINTER
	MOVEM 3,SPT(4)		;PUT IT IN SPT
	MOVEM 2,SPTH(4)		;PUT OFN.PN IN SPTH
	HLRZ 3,2		;SAVE OFN
	LSH 4,^D9		;CONSTRUCT SHARE POINTER
	TLO 4,SHRBIT
	XOR 4,CXBPGA(2)		;WITH PROTECTION BITS FROM PT
	TLZ 4,RWXB
	XORB 4,CXBPGA(2)	;PUT CONSTRUCTED SHARE POINTER IN PT
	MOVE 2,4		;AS WELL AS PROCESS MAP
	MOVSI 4,1B31		;BUMP SHARE COUNT FOR POINTER PUT
	ADDM 4,SPT(3)		;IN XB
	JRST SETMP7		;GO INCREMENT SHARE COUNTS, ETC.

SETMXB:	CAIL 2,SSPT		;LEGAL NUMBER?
	BUG(HLT,<ILLEGAL SPT INDEX GIVEN TO SETMXB>)
	HLRZ 3,1		;GET DESTINATION PTN
	CAIGE 3,NOFN		;FILE?
	BUG(HLT,<ILLEGAL DESTINATION IDENTIFIER TO SETMPG OR SETPT>)
	MOVEI 3,0(2)		;REQUEST WAS FOR INDEX BLOCK
	LSH 2,^D9		;MAKE IT INTO SHARE POINTER
	TLO 2,SHRBIT+RWXB
	JRST SETMP5

;DESTINATION IS FILE

SETP7:	HLRZ 4,2		;GET SOURCE PTN
	CAIGE 4,NOFN		;IS FILE?
	JRST SETPF1		;YES, ERROR
	TLNE 3,SHRBIT+INDBIT	;NOT PRIVATE?
	JRST SETPF		;YES
	JUMPE 3,SETP7K		;PAGE NEVER REFERENCED
	TLNE 3,10		;NOW ON DISK?
	JRST SETP71		;YES
	TLNE 3,16		;NOW ON DRUM?
	JRST SETP7D		;YES, GO ADJUST DRUM BACKUP ADR
	PUSH P,1		;IN CORE,
	MOVEI 1,0(3)
	CALL AGESET		;FIX PAGE
	POP P,1
	MOVSI 4,PLKV		;IN CORE,
	ADDB 4,CST1(3)		;GET BACKUP ADR AND LOCK PAGE
	TLNE 4,10		;DISK?
	JRST SETP7C		;YES
	TLNE 4,16		;DRUM?
	JRST SETP7E		;YES
	MOVEI 4,CST1(3)		;NOT ASSIGNED, PUT BACKUP ADR IN CST1
	CALL SETP7A		;ASSIGN BACKUP ADR AND STORE IT
SETP7C:	PUSH P,3
	MOVEM 1,CST2(3)		;IN CORE, ADJUST CST
	MOVSI 4,-PLKV
	ADDM 4,CST1(3)		;UNLOCK PAGE
	HLRZ 4,2		;SOURCE PTN
	MOVE 4,SPT(4)
	MOVSI 3,-PLKV
	ADDM 3,CST1(4)		;REDUCE LOCK COUNT OF PT
	HLRZ 4,1
	MOVE 4,SPT(4)
	MOVSI 3,PLKV
	ADDM 3,CST1(4)		;INCREASE LOCK COUNT OF XB
	POP P,3
SETP71:	SETZM CXBPGA(2)		;PUT SOURCE PTR IN DEST MAP
	HLRZ 4,0(P)		;GET USER SPECIFIED ACCESS
	ANDI 4,RWX
	TLZ 3,-1B31
	TLO 3,ACCESB(4)		;PUT ACCESS AND ACCESS BIT IN PTR
	MOVEM 3,CPTPGA(1)
	EXCH 1,2		;EXCHANGE SOURCE AND DESTINATION PT'S
	MOVE 3,PSB+CPTPG
	EXCH 3,PSB+CXBPG
	MOVEM 3,PSB+CPTPG
	MONCLR CPTPG		;CLEAR AR'S FOR LOCAL MAPPING
	MONCLR CXBPG		; (SECOND DOES NOTHING ON KA10)
	JRST SETP72		;NOW AS IF PAGE WAS IN FILE

SETP7K:	MOVSI 3,RWXB+1		;NEW PAGE, SETUP POINTER
	JRST SETP71

SETP7D:	MOVE 4,3
SETP7E:	PUSH P,2
	PUSH P,3
	MOVE 2,4		;DRUM ADDRESS
	CALL GDSTX		;GET DST INDEX
	MOVEI 4,DST(2)		;WHERE TO STORE ADDRESS
	POP P,3
	POP P,2
	MOVE 5,0(4)		;PRESENT BACKUP
	TLNN 5,10		;DISK?
SETP73:	CALL SETP7A		;NO, ASSIGN DISK ADDRESS AND STORE IT
	TLNN 3,17
	JRST SETP7C
	JRST SETP71

SETP7A:	HLRZ 5,1		;GET OFN OF DESTINATION FILE
	PUSH P,1		;SAVE STUFF
	PUSH P,2
	PUSH P,3
	PUSH P,4
	MOVE 1,SPTH(5)		;GET XB ADRESS AND CLASS
	CALL DSKASN		;ASSIGN DISK ADDRESS FOR PAGE
	JRST SETP7X		;DISK FULL
SETP7Y:	MOVE 5,1
	POP P,4
	POP P,3
	POP P,2
	POP P,1
	DPB 5,[POINT 22,0(4),35]	;STORE ADDRESS WHERE GIVEN
	RET

SETP7X:	SUB P,BHC+4+1		;FLUSH 4 TEMPS AND 1 RETURN
	MOVEI 1,OPNX10		;'NO ROOM'
	MOVEM 1,LSTERR
	MOVEI 1,^D20		;SIZE EXCEEDED PSI
	CALL PSIRQ0
	JRST SETPT1

;POINTER NOW IN SPT OWNED BY FORK. MOVE IT TO FILE

SETPF:	LDB 4,[POINT 13,3,26]	;GET SPTN
	CAMN 2,SPTH(4)		;IS OWNED BY SOURCE?
	TLNE 3,INDBIT		;AND NOT INDIRECT?
	JRST SETPF1		;SORRY, CAN'T GIVE AWAY UNOWNED PAGES
	MOVEM 1,SPTH(4)		;SET NEW OWNERSHIP
	MOVSI 5,-1B31
	AND 5,SPT(4)		;GET CURRENT SHARE COUNT
	HLRZ 4,1
	ADDM 5,SPT(4)		;TRANSFER SHARE COUNT TO NEW OWNING PT
	MOVN 5,5
	HLRZ 4,2
	ADDM 5,SPT(4)		;AWAY FROM OLD PT
	JRST SETMP3		;NOW SETUP SHARE POINTER IN DEST

SETPF1:	MOVEI 1,		;ILLEGAL PAGE TO FILE ATTEMPTED
SETPTE:	MOVEM 1,LSTERR
	MOVEI 1,^D11		;IO ERROR CHANNEL
	CALL PSIRQ0
	RESKD1
	JRST SETPT1		;CLEAN UP AND EXIT

;PUT INDEX BLOCK IN FIXED PAGE (CXBPG) OF PP MAP FOR TEMP USE

SETXB1:	CALL RELCXB		;RELEASE CURRENT ONE
	NOINT			;NO INTERRUPTS WHILE XB MAPPED
	LSH 3,^D9
	TLO 3,RWXB-XCTB+SHRBIT	;MAKE INTO SHARE POINTER, NO XCT
	MOVEM 3,PSB+CXBPG	;PUT INTO CURRENT X BLOCK PAGE
	RET

;RELEASE INDEX BLOCK NOW IN FIXED PAGE

RELCXB:	SKIPN PSB+CXBPG
	RET			;NONE THERE NOW
	SETZM PSB+CXBPG		;CLEAR MAP
	MONCLR CXBPG		;CLEAR MONITOR AR'S
	OKINT
	RET

SWPCXB:	PUSH P,1
	LDB 1,[POINT 13,PSB+CXBPG,26]
	CAIL 1,1		;IS OFN?
	CAIL 1,NOFN
	JRST .+3		;NO, IGNORE IT
	MOVE 1,SPT(1)		;YES, INITIATE SWPOUT
	CALL SWPOT0
POP1:	POP P,1
	RET

;MAP CURRENT PAGE TABLE FOR TEMP USE

SETCPT:	CALL RELCPT		;RELEASE CURRENT ONE
	NOINT
	HLRZ 2,1		;MAKE SHARE POINTER
	LSH 2,^D9
	TLO 2,RWXB-XCTB+SHRBIT
	MOVEM 2,PSB+CPTPG
	RET

;RELEASE CURRENT PT MAPPING

RELCPT:	SKIPN PSB+CPTPG		;ANYTHING THERE?
	RET			;NO
	SETZM PSB+CPTPG		;CLEAR MAP
	MONCLR CPTPG		;CLEAR AR'S
	OKINT
	RET

;RELEASE PAGE FROM MAP
; AC1/ OFN.PN OF PAGE

; RETURNS +1 IF UNSUCCESSFUL
; RETURNS +2 IF SUCCESSFUL
; IN EITHER CASE, RETURNS NOSKED


RELMPG:	NOSKED
	PUSH P,3
	PUSH P,2
	CALL SETCPT
RELMP7:	PUSH P,1
RELMP5:	MOVE 2,CPTPGA(1)	;GET MAP WORD
	JUMPE 2,RELMPR		;EMPTY
	PGRCLD			;CLEAR AR'S
	TLNN 2,SHRBIT+INDBIT	;PRIVATE POINTER?
	JRST RELP3
RELMP1:	HLRZ 3,1		;GET PTN
	TLNE 2,INDBIT		;INDIRECT POINTER
	JRST RELMP3		;THAT'S OK
	CAIGE 3,NOFN		;OWNED BY FILE?
	JRST RELMP4		;CAN'T DELETE FILE PAGE STILL SHARED
	LDB 3,[POINT 13,2,26]	;GET SPTN
	CAMN 1,SPTH(3)		;OWNER TRYING TO DELETE?
	JRST RELMP4		;MUST WAIT TILL UNSHARED
RELMP3:	SETZM CPTPGA(1)		;CLEAR MAP WORD
	MOVE 3,2		;SAVE POINTER
	LSH 2,-^D9
	ANDI 2,SPTM		;GET SPT INDEX
	MOVSI 1,-1B31
	CAIGE 2,NOFN		; OFN OR INDIRECT THRU OFN?
	 JRST RELMP6
	TLNE 3,INDBIT		;INDIRECT POINTER
	 JRST RELP1		; YES, JUST DECREMENT SHARE CNT
	HLRZ 3,SPTH(2)		;IS SHARE POINTER, GET OFN
	JUMPE 3,RELP1		;IF UNOWNED SPTN
	ADD 1,SPT(2)		;SEE IF SHARE COUNT OF PG IS GOING TO 0 .. DCA
	TLNE 1,-1B31		;COUNT NOW 0?
	 JRST [MOVSI 1,-1B31	;NO, REDUCE SHR CTS OF OFN AND PG
	      ADDM 1,SPT(3)
	      ADDB 1,SPT(2)
	      JRST RELMPR]

;MAP THE OWNING XB, GO OKSKED, TOUCH THE PAGE, GO NOSKED AND
;THEN RETEST THE SHARE COUNT TO SEE IF IT IS STILL GOING TO 0 .. DCA
	PUSH P,3		;SAVE 3. SETXB1 CLOBBERS IT .. DCA
	CALL SETXB1		;MAP THE OWNING XB
	POP P,3			;RESTORE 3

;NOTE THAT SETXB1 DOES NOT INCREMENT THE SHARE COUNT IN THE
;SPT ENTRY FOR THE XB. THIS CODE DEPENDS ON THE FACT THAT THE
;CURRENT PROCESS HAS THE FILE OPEN AND THUS THE SHARE COUNT CANNOT
;REACH 0 WHILE OKSKED. SETXB1 DOES A NOINT AND THUS THE CURRENT PROCESS
;CANNOT ITSELF CLOSE THE FILE IN RESPONSE TO A PSI.

	OKSKED			;PREPARE TO TOUCH THE PAGE
	SKIP CXBPGA
	NOSKED

	MOVSI 1,-1B31		;NOW REDUCE SHR COUNTS FOR REAL .. DCA
	ADDM 1,SPT(3)
	ADDB 1,SPT(2)
	TLNE 1,-1B31		;IS SHR COUNT NOW 0?
	JRST [CALL RELCXB	;NO
	      JRST RELMPR]

	TLNE 1,17		;CORE?
	JRST RELMP2		;NO
	CALL AGESET		;IN CORE, SET AGE
	MOVSI 4,PLKV
	ADDM 4,CST1(1)		;AND LOCK WHILE ADJUSTING
RELMP2:	MOVSI 4,-1B31
	ADDM 4,SPT(3)		;REDUCE SHARE COUNT OF XB
	MOVE 4,SPTH(2)		;GET OWNING PTN.PN
	XOR 1,CXBPGA(4)		;PUT ADDRESS BACK IN XB WITH ORIGINAL
	TLZ 1,-1B31-SHRBIT-INDBIT
	XORB 1,CXBPGA(4)	;ACCESS BITS
	TLNN 1,16		;UNREFERENCED DISK ADR?
	TLNN 1,17
	CAIA			;NO
	SETZM CXBPGA(4)		;YES, DELETE IT
	CALL RELCXB		;RELEASE XB
	MOVE 3,2
	ADDI 2,SPT
	EXCH 2,FRESPT		;RETURN SPT SLOT TO FREE LIST
	MOVEM 2,@FRESPT
	SOS SPTC
	TLNE 1,17		;PAGE IN CORE?
	JRST RELP4		;NO
	CAME 3,CST2(1)		;CONFIRM OLD OWNERSHIP
	BUG(HLT,<PAGE TABLE CORE POINTER AND CST2 FAIL TO CORRESPOND>)
	MOVEM 4,CST2(1)		;YES, CHANGE RECORD OF OWNING PT
	HLRZ 4,4		;PTN OF OWNING PT
	MOVE 4,SPT(4)		;CORE ADDRESS OF IT
	MOVSI 2,PLKV
	ADDM 2,CST1(4)		;INCREMENT LOCK COUNT
	MOVSI 4,-PLKV
	ADDM 4,CST1(1)		;UNLOCK PAGE
	JRST RELP2

RELMP6:	MOVE 1,2
	OKSKED			; RESCHEDULING IS NOW PERMISSIBLE
	CALL RELOFN
	 JFCL
	NOSKED
	JRST RELMPX

RELP4:	TLNN 1,10		;DISK ADR?
	TLNN 1,16		;NOT ASSIGNED?
	JRST RELMPR		;YES
	MOVE 1,4
	CALL SWPINP		;GET IT OFF DRUM
RELP2:	CALL AGESET		;MAKE PAGE IN USE
	HLRZ 2,CST2(1)		;SEE WHO OWNS PAGE
	CAIG 2,NFDIB+3		;SYSTEM FILE? (DIR OR BITTAB)
	JRST [	CALL DECOR	;YES, DEASSIGN BUT DON'T SWAPOUT IMMED
		JRST RELMPR]
	CALL SWPOT0		;SWAP IT OUT
RELMPR:
RELMPX:	POP P,1
	SKIPE CPTPGA(1)		;MAP WORD STILL EMPTY?
	 JRST RELMP7		;NO, TRY AGAIN
	POP P,2
	POP P,3
	JRST RSKP

RELP3:	TLNE 2,17		;IN CORE?
	JRST RELP32		;NO, CAN RELEASE ALL.
	TLNE 2,USRLKB		; LOCKED BY USER?
	 CALL MULK1		; YES, UNLOCK THE PAGE
	MOVE 1,0(P)
	MOVSI 3,DWRBIT		;YES, WRITE IN PROGRESS?
	TDNN 3,CST3(2)
	JRST RELP32		;NO, NO PROBLEM
	MOVEI 1,DWRTST		;YES, MUST WAIT FOR COMPLETION
	HRLI 1,0(2)
	JSYS SCHEDR
	NOSKED
	MOVE 1,0(P)		;RECOVER OFN.PN
	JRST RELMP5		;GO TRY AGAIN

RELP32:	CALL REMFPG		;RELEASE ALL STORAGE
	JRST RELMPR

DWRTST:	MOVSI 2,DWRBIT		;SCHED TEST FOR WRITE COMPLETED
	TDNE 2,CST3(1)
	JRST 0(4)
	JRST 1(4)

; SCHEDULER TEST FOR PAGE UNLOCKED

PLCKT:	MOVSI 2,-PLKV
	TDNE 2,CST1(1)
	JRST 0(4)
	JRST 1(4)

RELP1:	ADDM 1,SPT(2)
	JRST RELMPR

RELMP4:	SUB P,BHC+3		;FLUSH TEMPS
	MOVEI 1,		;ILLEG UNMAPPING
	MOVEM 1,LSTERR
	MOVEI 1,^D11
	CALL PSIRQ0		;GENERATE ITRAP
	RESKD1			;MAKE SURE SCHED SEES PSI
	SETZB 1,2
	RET

;REMOVE PAGE FROM SYSTEM (DELETE PERMANENT AND TEMPORARY ADDRESSES)

REMFPG:	MOVE 3,CPTPGA(1)	;GET MAP WORD
	SETZM CPTPGA(1)		;CLEAR MAP WORD
REMFP1:	TLNE 3,10		;DISK?
	JRST REMFF		;YES
	TLNE 3,16		;DRUM?
	JRST REMFD		;YES
	TLNE 3,17		;CORE?
	RET			;DONE
	MOVEI 1,0(3)
	CAMG 1,NHIPG		;LEGAL PAGE?
	CAMGE 1,SWPCOR
	BUG(HLT,<ILLEGAL CORE PAGE NUMBER TO REMFPG>)
	CALL AGESET
	CALL DECOR
	HLRZ 2,CST2(1)		;GET PTN OF OWNING PT
	JUMPE 2,REMFP2		;NONE, SPT
	MOVE 3,SPT(2)		;GET ADR OF OWNING PT
	MOVSI 4,-PLKV
	ADDM 4,CST1(3)		;DECREMENT LOCK COUNT
REMFP2:	MOVE 2,TODCLK		;SETUP OVERDUE TIME
	ADDI 2,^D2000		;AS 2 SEC FROM NOW
REMFP4:	MOVSI 3,(77B5)
	MOVSI 4,-PLKV
	PIOFF
	SETZM CST2(1)		;FLUSH SOURCE
	TDNE 3,CST0(1)		;PAGE NOW ON RPLQ?
	TDNE 4,CST1(1)		;LOCKED?
	JRST REMF21		;YES, IS OR WILL BE PUT ON RPLQ
	MOVSI 3,DWRBIT
	TDNE 3,CST3(1)		;BEING WRITTEN?
	JRST REMFP3		;YES, MUST WAIT
	PION
REMFP5:	JSP 4,ONRQ		;PUT PAGE ON RPLQ
REMF22:	MOVSI 3,-PLKV
	AND 3,CST1(1)		;FLUSH BACKUP ADDRESS, LEAVE LK CNT
	EXCH 3,CST1(1)		;GET BACKUP ADDRESS
	JRST REMFP1

REMFP3:	PION
	CAML 2,TODCLK		;WAITED LONG ENOUGH?
	JRST REMFP4		;NO, KEEP WAITING
	BUG(CHK,<SWAP WRITE FAILED TO COMPLETE IN 2 SEC>)
	ANDCAM 3,CST3(1)	;FORCE COMPLETION
	JRST REMFP5

REMF21:	PION
	JRST REMF22

REMFD:	MOVE 1,3
	PUSH P,1
	CALL DASDRM		;DEASSIGN DRUM ADDRESS
	POP P,2
	CALL GDSTX
	MOVE 3,DST(2)		;GET BACKUP ADDRESS
	SETOM DST(2)		;MAKE DST SLOT EMPTY
	JRST REMFP1

REMFF:	MOVE 1,3
	CALL DEDSK		;DEASSIGN DISK ADDRESS
	RET

;CONSTRUCT PTN.PN FOR
;ADDRESS GIVEN IN 18-35 OF AC1
;BIT 0 OF AC1 SAYS USER (IF 1) OR MONITOR (IF 0) ADDRESS
;RETURN WITH PTN.PN IN AC1

FPTA:	PUSH P,1
	MOVEI 1,0(1)		;CLEAR LH
	LSH 1,-^D9		;GET PAGE NUMBER
	EXCH 1,0(P)		;GET ARG, SAVE PN
	JUMPL 1,FPTAU		;USER MODE IF BIT 0 IS 1
	MOVE 1,0(P)
	CAIL 1,PPMPG		;WHICH PART OF MONITOR?
	JRST FPTA1		;PRIVATE PER PROCESS
	CAIL 1,PJMPG
	JRST FPTA2		;PRIVATE PER JOB
	CAIL 1,PPRMPG
	JRST FPTA3		;PRIVATE PER PROCESSOR AND SWAPPABLE
	BUG(HLT,<FPTA - ARG POINTS TO RESIDENT MONITOR>)

FPTA1:	CAIGE 1,DDPG1		;DISALLOW SPECIAL PAGES
	BUG(HLT,<FPTA - ILLEGAL PAGE IN PROCESS AREA>)
FPTA5:	MOVE 1,FORKX		;GET SPTN OF PSB
	JRST FPTA4

FPTAU:	MOVE 1,FORKX		;GET SPTN OF UPT OR IF NONE, PSB
	HLL 1,FKPGS(1)
	TLNN 1,-1
FPTA4:	HRLZ 1,FKPGS(1)
FPTAR:	HLLM 1,0(P)		;COMBINE WITH PAGE NUMBER
	JRST POP1		;POP TO 1 AND RETURN

FPTA2:	CAIG 1,JSBPG
	JRST FPTA5		;JSB OR JDV, NOT INDIRECT PTR
	LDB 1,[POINT 13,PSB+JSBPG,26]	;SPTN OF JSB
	HRLM 1,0(P)
	HRREI 1,-PJMPG+JOBMAP-JSB ;FIRST JOB PAGE MAPPED BY JOBMAP+0
	ADDM 1,0(P)
	JRST POP1

FPTA3:	HRL 1,MMSPTN		;PERMANENT SPTN OF MON MAP
	JRST FPTAR

;MAKE PRIVATE PAGE IN EXECUTING FORK'S ADDRESS SPACE SHARABLE PAGE.
;1/ ADDRESS OF THE PAGE
;RET WITH 1/ SPT INDEX FOR THE PAGE

MKSHRP:	PUSH	P,2
	PUSH	P,3
	PUSH	P,1
	CALL	ASSPT			;ASSIGN SPT SLOT
	MOVSI	2,1B31			;INCREMENT SHARE COUNT
	ADDM	2,SPT(1)
	EXCH	1,0(P)			;1=ADDRESS,0(P)=SPT SLOT
	CALL	FPTA			;GET PTN,,PN FOR PAGE
	PUSH	P,1
	CALL	MLKPG			;LOCK THE PAGE IN CORE
	POP	P,1			;RESTORE 1 SMASHED BY MLKPG
	CALL	SETCPT			;MAP THE PAGE TABLE
	MOVE	2,0(P)			;2=SPT SLOT
	MOVE	3,CPTPGA(1)		;3=PAGE TABLE ENTRY FOR PAGE
	TLNE	3,SHRBIT+INDBIT		;IS PAGE PRIVATE?
	BUG(HLT,<MKSHRP: PAGE NOT PRIVATE>)
	TLNE	3,17			;IS IT REALLY IN CORE?
	BUG(HLT,<MKSHRP: PAGE NOT IT CORE>)

       NOSKED
	DPB	3,[POINT 22,SPT(2),35]
	MOVEM	2,CST2(3)		;RESET CORE PAGES HOME ADDRESS
	TLO	3,SHRBIT		;MAKE 3 A SHARE PTR TO PAGE
	DPB	2,[POINT 13,3,26]
	MOVEM	3,CPTPGA(1)		;AND PUT IT INTO PAGE TABLE
       OKSKED

	CALL	RELCPT			;UNMAP THE PAGE TABLE
	CALL	MULKPG			;UNLOCK THE PAGE

	HLRZS	1			;NOW UNLOCK PREVIOUS OWNING
	MOVE	1,SPT(1)		;PAGE TABLE (LOCKED AS A SIDE
	MOVSI	2,-PLKV			;EFFECT OF MLKPG AND NOT
	ADDM	2,CST1(1)		;UNLOCKED BY MULKPG SINCE
					;OWNERSHIP CHANGED).
	POP	P,1			;1=SPT INDEX
	POP	P,3
	POP	P,2
	RET


;SET A FORK'S JSYS DISPATCH VECTOR PAGE
;IF SHARE COUNT OF OLD PAGE GOES TO 1 ITS SPT SLOT IS RELEASED
;SAME ARGUMENTS AS SETPT:
;1/ SOURCE IDENTIFIER
;2/ DESTIN IDENTIFIER
;3/ ACCESS

SETDVP:	PUSH	P,1
	PUSH	P,4
	MOVE	1,2
	CALL	SETCPT			;MAP PAGE TABLE FOR PAGE
	MOVE	4,CPTPGA(1)
	TLNE	4,SHRBIT		;MAKE SURE IT IS A SHARE PAGE
	TLNE	4,INDBIT
	BUG(HLT,<PT ENTRY FOR JSYS DISPATCH NOT SHARE PTR>)
	LDB	4,[POINT 13,4,26]	;4=SPT INDEX
	CALL	RELCPT
	MOVE	2,1
	MOVE	1,-1(P)
	CALL	SETPT			;SET FORK'S MAP
	MOVEI	1,(4)
	LDB	4,[POINT 14,SPT(1),13]	;4=SHARE COUNT OF OLD PAGE
	CAIN	4,1			;HAS IT REACHED 1?
	CALL	DESPT			;YES, RELEASE THE SPT ENTRY
	POP	P,4
	POP	P,1
	RET

;GET CORE PAGE GIVEN ADDRESS OR IDENTIFIER
;CLOBBERS 2

GETCPA::CALL FPTA		;CONVERT ADDRESS TO IDENTIFIER
GETCPP:	HLRZ 2,1		;PT OF IDENT
	MOVE 2,SPT(2)		;ADDRESS OF IT
	TLNE 2,17		;IN CORE?
	BUG(HLT,<GETCPP - PAGE NOT IN CORE>)
	CALL MOVRCA		;MOVE 1,PT(1)
	TLNN 1,SHRBIT+INDBIT	;PRIVATE POINTER?
	RET			;YES
	TLNN 1,INDBIT		;NO. INDIRECT?
	JRST [	LDB 2,[POINT 13,1,26]	;SHARED. GET SPT IDX
		MOVE 1,SPT(2)
		RET]
	LSHC 1,-^D9		;REFORMAT INTO PTN.PN
	ANDI 1,SPTM		; ..
	LSH 1,^D9
	LSHC 1,^D9
	JRST GETCPP

;GIVEN A CORE PAGE IN 2, AND N IN 1, FETCH NTH WORD FROM PAGE
;KI VERSION IS IN KISRV
;CAN BE CALLED AT ANY PI LEVEL

IFN KAFLG,<
MOVRCA:	HRLI 2,RWXB		;CONSTRUCT POINTER
	PIOFF
	MOVEM 2,MMAP+PIPG
	CONO PGR,1		;CLEAR MON AR'S
	MOVE 1,PIPGA(1)
	PION
	RET

;GIVEN A CORE PAGE IN 3, AND N IN 2, STORE 4 IN NTH WORD
; OF THE PAGE. KI VERSION NOT YET WRITTEN, WILL BE IN KISRV
; CAN BE CALLED AT ANY PI LEVEL
; USED TO CORRECT THE "CORRECTABLE DATA CHECKS" OF THE 3330.

INTERN XRMRCA
XRMRCA:	HRLI C,RWXB		;CONSTRUCT POINTER
	PUSH P,A		;SAVE WORK AC
	MOVSI A,(1B0)		;LEGAL AGE FOR DISK PAGE BEING READ
	PIOFF
	MOVEM C,MMAP+PIPG
	EXCH A,CST0(C)		;SET LEGAL AGE
	CONO PGR,1		;CLEAR MONITOR AR'S
	XORM 4,PIPGA(B)		;STORE WORD IN PAGE
	MOVEM A,CST0(C)		;PUT RIGHT AGE BACK
	PION
	POP P,A
	RET
>
IFN KIFLG,<
EXTERN MOVRCA,MVMRCA
>

;GET OWNING PAGE TABLE
;GIVEN PTN.PN, LOCATE PT CURRENTLY HAVING ADDRESS OF PAGE

GETONT:	CALL SETCPT		;MAP GIVEN PAGE TABLE
	MOVE 2,CPTPGA(1)	;REF BEFORE NOSKED
	NOSKED
	MOVE 2,CPTPGA(1)	;GET MAP WORD
	TLNN 2,SHRBIT+INDBIT	;PRIVATE POINTER?
	JRST RELCPT		;YES, RELEASE CPT AND RETURN
	TLNN 2,INDBIT		;INDIRECT POINTER?
	JRST GETON1		;NO, SHARE POINTER.
	OKSKED
	LSHC 2,-^D9		;REFORMAT INTO PTN.PN
	ANDI 2,SPTM
	LSH 2,^D9
	LSHC 2,^D9
	CALL RELCPT		;RELEASE CPT
	MOVE 1,2
	JRST GETONT		;TRY AGAIN

GETON1:	LDB 1,[POINT 13,2,26]	;FOR SHARE POINTER, RETURN SPTN
	MOVE 2,SPT(1)		;AND CURRENT ADDRESS
	JRST RELCPT		;RELEASE CPT AND RETURN

;SETUP PAGER FOR PROCESS

SETPPG:	HRRZ 1,FKPGS(7)		;GET PSB
	MOVE 1,SPT(1)
	TLNE 1,17		;MUST BE IN CORE
	BUG(HLT,<SETPPG - PSB NOT IN CORE>)
	HRRZM 1,PGR71		;LEAVE CORE PAGE NUMBER FOR PAGER
	HLRZ 1,FKPGS(7)		;GET PT
	MOVE 1,SPT(1)
	TLNE 1,17		;MUST BE IN CORE
	BUG(HLT,<SETPPG - PT NOT IN CORE>)
SETPG1:	HRLM 1,PGR71		;LEAVE FOR PAGER
	HRRZ 1,FKCNO(7)
	MOVE 2,BITS-^D9(1)	;PROCESS USE BIT
	HLRZ 1,FKNR(7)		;GET PROCESS AGE
	ROTC 1,-^D9
	MOVEM 2,PGR72
	PGRCLD			;LOAD PAGER FROM 71,72
	MOVE 1,ACBAS		;SET AC BASE REGISTER
	SETACB 1
	RET

;PRELOAD PAGES FOR FORK, FORKX IN 7

PRELD:	SKIPE PGR71		;PAGER INITIALIZED?
	SKIPN PRELDF		;PRELOADING IN OPERATION?
	JRST PREL2		;NO
	SETOM PRELRQ		;SET FLAG NOTING PRELOADING SWAPS
	PUSH P,10
	HRRZ 11,FKNR(7)		;CURRENT WS SIZE
	SUBI 11,4		;LESS PSB, UPT, AND 2 RESERVE
	HRRZ 1,FKPGS(7)		;PSB
	LSH 1,^D9		;MAP IT WITH SHARE PTR
	TLO 1,RWXB+SHRBIT
	MOVEM 1,MMAP+FITPG
	HLRZ 1,FKPGS(7)		;PAGE TABLE
	LSH 1,^D9
	TLO 1,RWXB+SHRBIT
	MOVEM 1,MMAP+PRLPG	;MAP IT
	MONCLR PRLPG
	MOVSI 10,-NWSPGS	;SETUP TO SCAN WS BIT WORDS
PREL1:	SKIPE 5,XWSPGS(10)	;ANY PAGES THIS WORD?
PREL6:	JFFO 5,PREL3		;YES
	AOBJN 10,PREL1
PREL7:	POP P,10
PREL2:	SETZM PRELRQ
	RET

PREL3:	ANDCM 5,BITS(6)		;REMOVE BIT FOR PAGE JUST FOUND
	PUSH P,5		;SAVE PARTIAL BIT WORD
	MOVEI 5,0(10)		;COMPUTE PAGE NUMBER IN UPT
	IMULI 5,^D36
	ADDI 6,0(5)
	SKIPE 2,PRLPGA(6)	;GET POINTER FROM UPT
	TLNE 2,INDBIT		;INDIRECT?
	JRST PREL4		;YES, NOT INTERESTED
	HLLZ 1,FKPGS(7)		;CONSTRUCT IDENTIFIER FOR PRIVATE CASE
	HRRI 1,0(6)		;PTN.PN
	TLNE 2,SHRBIT		;SHARE PTR?
	JRST [	LSH 2,-^D9	;YES, GET SPT INDEX
		ANDI 2,SPTM
		MOVEI 1,0(2)	;THAT WILL BE IDENTIFIER
		MOVE 2,SPT(1)	;AND SPT CONTAINS ADDRESS
		JRST .+1]
	TLNE 2,17		;PAGE NOW IN CORE?
	JRST [	SKIPLE NRPLQ	;MAKE SURE THERE'S ROOM
		TLNN 2,16	;AND PAGE IS ASSIGNED
		JRST PREL4
		CALL SWPIN	;NO, SWAP IT IN
		JRST PREL4]
	LDB 1,[POINT 6,CST0(2),5] ;PAGE IS IN CORE, SEE WHAT STATE
	JUMPE 1,PREL5		;ON REPLACABLE
	CAIE 1,4		;BEING WRITTEN?
	JRST PREL4		;NO, ANYTHING ELSE IS OK
	MOVSI 1,(2B5)
	EXCH 1,CST0(2)		;SET NEW STATE, GET OLD
	TLNN 1,(77B5)		;NOW ON REPLACABLE?
	JRST PREL5		;YES
	SOS IOIP		;NO, HAVE NOW DISABLED COMPLETION ACTION
PREL4:	POP P,5			;RECOVER PARTIAL BIT WORD
	SOJG 11,PREL6		;KEEP GOING UNLESS WS EXHAUSTED
	JRST PREL7		;QUIT

PREL5:	SOS NRPLQ		;TAKE PAGE OFF REPLACABLE
	PIOFF
	MOVE 1,CST3(2)
	HLLM 1,0(1)
	MOVS 1,1
	HLRM 1,0(1)
	PION
	SETZM CST3(2)
	MOVSI 1,(2B5)		;SET PAGE TO READ COMPLETE STATE
	HRRI 1,0(7)		;INCLUDE FORK NO
	MOVEM 1,CST0(2)		;IN CASE PROCESS DOES NOT REF IT
	JRST PREL4

;CHECK WS BITS AS PROCESS LEAVES BALSET

POSTPG:	PUSH P,1
	JSP 4,STIME		;TIME THIS
	HRRZ 1,FKPGS(7)
	LSH 1,^D9		;MAP PSB
	TLO 1,RWXB+SHRBIT
	MOVEM 1,MMAP+FITPG
	HLRZ 1,FKPGS(7)		;PAGE TABLE
	LSH 1,^D9		;MAP IT VIA SHR PTR
	TLO 1,RWXB+SHRBIT
	MOVEM 1,MMAP+PRLPG
	MONCLR
	MOVSI 6,-NWSPGS		;SCAN WS BIT WORDS
	SETZ 3,			;COUNTING BITS
REMB2:	SKIPE 4,XWSPGS(6)	;ANY BITS HERE?
REMB7:	JFFO 4,REMB5		;YES, FIND ONE
	AOBJN 6,REMB2
	ADDI 3,3		;PAGES IN WS PLUS 3 FOR MON OVHD
	CAIGE 3,6		;SET NR TO: MAX(6,SIZ,WSBITS+3)
	MOVEI 3,6
	HRRZ 2,FKWSP(7)		;SIZE
	CAIGE 3,0(2)
	MOVEI 3,0(2)
	HRRZ 2,FKNR(7)		;CURRENT NR
	CAILE 3,0(2)		;ABOVE .G. CURRENT?
	MOVEI 3,0(2)		;YES, KEEP CURRENT
	HRRM 3,FKNR(7)		;SET NEW NR
	JSP 4,ETIME		;GET TIME SPENT HERE
	ADDM 1,PPG		;ACCUMULATE IT
	AOS PPG+1		;COUNT OCCURRENCES
	POP P,1
	RET

;SWAP OUT PURGED PAGE

GCSWP:	MOVE 2,CST1(1)
	TLNE 2,-PLKV
	RET
	MOVSI 2,DWRBIT
	TDNE 2,CST3(1)		;DON'T SWAP PAGE IF NOW BEING WRITTEN
	RET
	MOVE 2,CST0(1)
	TLNN 2,(7B2)		;NOW ASSIGNED?
	 RET			;NO, DO NOTHING
	TDNE 2,BSBITS		;BEING SHARED BY SOMEONE IN BALSET?
	 RET			;YES, DON'T COLLECT
	HLRZ 2,CST3(1)		;GET PROCESS ASSIGNMENT
	ANDI 2,7777
	CAIE 2,0(7)		;ASSIGNED TO THIS PROCESS?
	 RET			;NO, DON'T TOUCH IT
	PUSH P,1
	CALL SOSWS2		;YES, DEASSIGN IT
	POP P,1
	SOS POTEN
	AOS PPCLCT	;COUNT PAGES COLLECTED BY POSTPG
	JRST SWPOUT		;SWAP OUT PAGE

;LOOK AT PAGE IN WS

REMB5:	ANDCM 4,BITS(5)		;REMOVE BIT FROM TEMP WORD
	MOVEI 1,0(6)		;COMPUTE PAGE NUMBER IN PT
	IMULI 1,^D36
	ADDI 1,0(5)
	SKIPE 1,PRLPGA(1)	;PAGE NOW EMPTY?
	TLNE 1,INDBIT		;OR INDIRECT?
	JRST REMB6		;YES, FORGET IT
	TLNE 1,SHRBIT		;SHR PTR?
	JRST [	LSH 1,-^D9
		ANDI 1,SPTM	;YES, GET ADDRESS FROM SPT
		MOVE 1,SPT(1)
		JRST .+1]
	TLNE 1,17		;PAGE NOW IN CORE?
	JRST REMB6		;NO, FORGET IT
	MOVE 2,CST0(1)
	TLNN 2,(7B2)		;PAGE IN USE?
	JRST [	TLC 2,(02B5)	;NO, BUT IS READ COMPLETED?
		TLNE 2,(77B5)
		JRST REMB6	;NO, FLUSH IT
		JRST .+1]	;YES, KEEP IT
	PUSH P,3
	PUSH P,4
	SKIPG SWRSAF		;PAGE IS TO BE KEPT. REASSIGNING ADRS?
	JRST POSTP1		;NO
	MOVE 2,CST1(1)		;YES, GET OLD ADDRESS
	TLNN 2,10		;DRUM?
	TLNN 2,16
	JRST POSTP1		;NO
	CALL GDSTX		;GET DST INDEX FOR OLD DRUM ADR
	PUSH P,DST(2)		;SAVE BACKUP ADR
	SETOM DST(2)		;CLEAR OLD DST SLOT
	PUSH P,1		;SAVE CORE ADDRESS
	MOVE 1,CST1(1)
	CALL DASDRM		;DEASSIGN OLD DRUM ADR
	SETO 1,
	CALL DRMASN		;ASSIGN NEW DRUM ADR IN SEQUENCE
	BUG(HLT,<DRUM COMPLETELY FULL>)
	TLO 1,1			;NOTE NEW ADDRESS
	MOVE 2,1
	POP P,1
	DPB 2,[POINT 22,CST1(1),35] ;STORE NEW DRUM ADR
	CALL GDSTX
	POP P,DST(2)		;PUT BACKUP ADR IN NEW DST SLOT
POSTP1:	SKIPLE POSPGF		;POST PURGING REQUESTED?
	CALL GCSWP		;YES, SWAP OUT THE PAGE
	POP P,4
	POP P,3
	AOJA 3,REMB7		;COUNT PAGE AND CONTINUE

REMB6:	SKIPN -1(P)		;FORK WAS DISMISSED OR FORCED OUT?
	AOJA 3,REMB7		;FORCED OUT, DON'T FLUSH UNREF PGS
	MOVE 2,BITS(5)
	ANDCAM 2,XWSPGS(6)	;DISMISSED, FLUSH UNREF PAGES
	JRST REMB7

;DEASSIGN CORE

DECOR:	PUSH P,3		;MUST BE TRANSPARENT TO AC'S
	PUSH P,2
	TLNE 1,17		;GIVEN MAP WORD, NOW IN CORE?
	JRST DECRR		;NO, NOTHING TO DO
	MOVE 3,CST0(1)
	TLNN 3,(70B5)		;PAGE IN USE?
	JRST DECRR		;NO
	HLRZ 2,CST3(1)		;GET PROCESS ASSIGNMENT
	ANDI 2,7777
	CAIL 2,NFKS		;ASSIGNED?
	JRST DECRR		;NO, NOTHING ELSE TO DO
	PUSH P,1
	CALL SOSWSP		;REDUCE N FOR THIS PROCESS
	POP P,1
	MOVSI 2,7777
	IORM 2,CST3(1)		;MAKE PAGE UNASSIGNED
DECRR:	POP P,2
	POP P,3
	RET

;GARBAGE COLLECT CORE, REMOVE PAGES OF PROCESSES NOT IN BAL SET

GCCOR0:	SKIPL BKGFLG		;DONT CALL IF BACKGROUND
	JSP 4,STIME		; ENTER HERE TO DEPG ALL RPLQ
	MOVE 1,NRPLQ		;  INSPECT N PAGES
	JUMPE 1,GCPC2		;N MAY BE 0 ...
	HRRZ 7,RPLQ		;ON REPLACABLE QUEUE
GCPC1:	MOVEI 3,0(7)
	SUBI 3,CST3		;GET PAGE NUMBER
	CALL DEPG		;UNDO POINTER AND FLUSH BACK PTR,
	SETZM CST2(3)		;THUS UNLOCKING OWNING PT
	HRRZ 7,0(7)
	SOJG 1,GCPC1
	JRST GCPC2

GCCOR:	SKIPL BKGFLG		;DONT CALL IF BACKGROUND
	JSP 4,STIME		;TIME GCCOR ACTIVITY
GCPC2:	SETZM POTEN		;RESET POTENTIAL PAGE COUNTER

	MOVE 11,BSBITS		;MASK OF BALSET PROCS
	MOVE 12,RLBITS		;MASK OF RUNLIST PROCS


GCCOR2:	MOVE 6,SWPCOR		;START AFTER RES MON
GCC2:	LDB 1,[POINT 6,CST0(6),5] ;CODE FIELD
	CAIN 1,2		;READ COMPLETED?
	 JRST [HRRZ 2,CST0(6)	;YES, GET INDEX OF OWNING FORK
		CAIL 2,NFKS	;VALID FORK INDEX?
		 JRST GCC4	;NO

		MOVSI 1,WTCLCT	;GET FKFLGS AND INDICATE GCCOR'D
		ANDCAB 1,FKFLGS(2)
		TLNE 1,BLST	;IN BALSET?
		TLNE 1,FORCEM	;BEING FORCED OUT?
		SKIPA 2,CST1(6)
		JRST GCC1	;DONT COLLECT
		TLNE 2,-PLKV	;LOCKED?
		JRST GCC1	;YES, CANT COLLECT
		AOS PNDING
		AOS SUMNRX
		JRST GCCS1]	;COLLECT IT

	CAIGE 1,10		;PAGE IN USE
	JRST GCC1		;NO
	HLRZ 2,CST3(6)		;GET PROCESS ASSIGNMENT
	ANDI 2,7777
	CAIL 2,NFKS		;PAGE NOW ASSIGNED?
	JRST GCCS		;NO, COLLECT IT

	MOVSI 3,WTCLCT		;INDICATE FORK GCCOR'D
	ANDCAB 3,FKFLGS(2)

	SKIPGE FKPT(2)		;HAS FORK BEEN DELETED?
	JRST GCCS		;YES, COLLECT
	TLNE 3,WTLS##		; OWNER ON WAIT LIST?
	 JRST GCCS		; YES. COLLECT IT

	MOVE 1,12		;PROCESS BITS NOT TO BE CLEARED
	ANDB 1,CST0(6)		;CLEAR ALL OTHERS
	TDNE 1,11		;ANY USERS IN BALSET?
	JRST GCC1		;DONT COLLECT
GCCS:	MOVE 2,CST1(6)		;BACKUP ADDRESS
	TLNE 2,-PLKV		;PAGE LOCKED?
	JRST GCCQ		;YES, LEAVE IT
	MOVSI 2,DWRBIT
	TDNE 2,CST3(6)		;PAGE BEING WRITTEN?
	JRST GCCQ		;YES, LEAVE IT
	MOVE 1,CST0(6)
	TLNN 1,(7B2)		;PAGE ASSIGNED?
	JRST GCCS1		;NO
	HLRZ 2,CST3(6)		;GET PROCESS ASSIGNMENT
	ANDI 2,7777
	CAIL 2,NFKS		;ASSIGNED?
	JRST GCCS1		;NO
	CALL SOSWSP
GCCS1:	MOVEI 1,0(6)		;SWAPOUT
	CALL SWPOUT
	SKIPL BKGFLG		;DONT COUNT IF BKGND
	AOS NGCLCT		;COUNT PAGES COLLECTED
GCC1:	CAMGE 6,NHIPG		;STOP AFTER HIGHEST KNOWN PAGE
	AOJA 6,GCC2
	SETZM CGFLG		;INDICATE GCCOR REQUEST SATISFIED
GCC3:	SKIPGE BKGFLG		;TAKE STATS ONLY IN NON-BACKGROUND
	 RET
	JSP 4,ETIME		;END TIMING OF GCCOR
	ADDM 1,GCCR		;CLOCK FOR GCCOR TIME
	AOS GCCR+1		;COUNT OCCURRENCES
	RET

GCC4:	BUG (CHK,<BAD FORK INDEX FOR PAGE WITH AGE=READ COMPLETE>)
	AOS PNDING
	AOS SUMNRX
	JRST GCCS		;COLLECT AND PRAY

GCCQ:	HLRZ 2,CST3(6)		;GET FORK ASSIGNMENT
	ANDI 2,7777
	CAIGE 2,NFKS		;NONE?
	SKIPL FKPT(2)		;OR CURRENTLY EXISTENT FORK?
	JRST GCC1		;YES
	CALL SOSWSP
	MOVSI 1,7777		;PAGE ASSIGNED TO DELETED FORK
	IORM 1,CST3(6)		;REMOVE ASSIGNMENT
	JRST GCC1

;DECREMENT WSP AND RELEASE CORE NUMBER IF WSP 0

SOSWSP:	MOVE 1,FKFLGS(2)	;IS FORK IN BAL SET?
	TLNE 1,BLST
	TLNE 1,FORCEM
	CAIA
	SOS FKNR(2)		;YES, REDUCE FKNR TOO

SOSWS2:	AOS PNDING		;PAGE AWAITS COLLECTION

	SOS 1,FKWSP(2)
	TRNE 1,777777		;WSP NOW 0?
	RET			;NO

	MOVE 1,FKFLGS(2)	;GET FLAG WORD
	TLNE 1,RNLS		;PROCESS STILL ACTIVE?
	RET			;YES, DON'T RELEASE NUMBER
	HRRZ 1,FKCNO(2)
	JUMPE 1,R		;NO NUMBER (?)
	HLLZS FKCNO(2)
	MOVE 1,BITS(1)
	IORM 1,FRECB
	RET

;PAGER TRAP

PGRTRP:	XWD TRAPPC,.+1
	SKIPN INSKED
	CONSZ PI,177B27		;FROM PI ROUTINE?
	BUG(HLT,<PAGER TRAP FROM SCHEDULER OR WHILE PI IN PROGRESS>)
	AOSLE NSKED
	AOSGE INTDF
	BUG(HLT,<PAGER TRAP WITH BAD NSKED OR INTDF>)
	AOSE TRAPC		;FIRST TRAP?
	JRST PGRT4		;NO, GO CHECK RECURSIVE OR ITERATIVE
	MOVEM P,TRAPAP		;SAVE AC-P
	MOVE P,TRAPSP		;SETUP TRAP STACK
	AOS UTRPCT		;COUNT TRAPS (BUT NOT RECURSIVE ONES)
	PUSH P,7		;SAVE AC'S 1-7
PGRT2:	ADD P,BHC+6
	JUMPGE P,MSTKOV		;STACK OVERFLOW?
	MOVEM 1,-5(P)		;FASTER THAN BLT OR PUSH
	MOVEM 2,-4(P)
	MOVEM 3,-3(P)
	MOVEM 4,-2(P)
	MOVEM 5,-1(P)
	MOVEM 6,0(P)
	MOVE 1,TRAPPC		;RETURN
	PUSH P,1		;SAVE IT
	TLNE 1,UMODF		;FROM USER?
	MOVEM 1,UPDL		;YES, LEAVE IT WHERE IT CAN BE FOUND
PGRT3:	SKIPE TRAPC		;IF RECURSIVE TRAP,
	PUSH P,TRAPSW		;OLD STATUS WORD
	PUSH P,TRAPWD		;WRITE DATA
	MOVE 1,TRAPS0		;GET TRAP STATUS WORD FROM WHERE
				;PAGER LEAVES IT
	TLNE 1,(1B10+1B12)	;PI CYC OR NXM?
	BUG(HLT,<PAGER TRAP ON PI CYCLE OR NXM>)
	MOVEM 1,TRAPSW		;TO SAFE PLACE
	SKIPE TRAPC
	JRST PGRTE		;NESTED TRAP, DON'T COUNT TIME TWICE
	MOVE 3,FKRT		;GET CURRENT PROCESS TIME SO WE
	ADD 3,JOBRTT		;CAN TIME THIS CODE
	PUSH P,3
IFN KIFLG,<
	PUSH P,KIMAC1		;SAVE MUUO TEMPS HERE
	PUSH P,KIMAC2>
PGRTE:	SETZM TRAPPC		;ALLOW SCHEDULING 
PGRTD:	HLLZ 1,TRAPSW		;GET TRAP STATUS
	TLNE 1,(1B9)		;PARITY ERROR?
	JRST PGRME		;YES
	SETZ 2,
	ROTC 1,2		;GET TOP 2 BITS
	MOVE 3,TABA(2)		;APPROPRIATE DISPATCH TABLE
	JFFO 1,.+2		;FIND TRAP-CAUSING BIT
	BUG(HLT,<PAGER TRAP WITH BAD OR MISSING TRAP STATUS WORD>)
	MOVE 7,FORKX		;GET FORK AND PROCESS NUMBER
	JRST 0(3)

PGRT4:	PUSH P,7		;TRAPSK ALREADY EXISTS
	HRRZ 7,TRAPPC		;CHECK TRAP PC FOR EITHER OF THE
	CAIE 7,PGMV1+1		;WRITE INSTRUCTIONS DONE TO
	CAIN 7,PGMV2+1		;FINISH UP A WRITE TRAP
	SOSA TRAPC		;TRAP IS ITERATIVE NOT RECURSIVE
	JRST PGRT2		;TRUE RECURSIVE TRAP
	SOS NSKED		;UNDO EFFECTS OF ENTERING TRAP CODE
	SOS INTDF
	POP P,7			;ADJUST VARIABLES AND REPROCESS TRAP
	JRST PGRT3

PGRME:	MOVE 2,[SIXBIT /PAGER/]
	MOVEM 2,DEVMPE		;REQUEST CORE SCAN
	ISB APRCHN
	BUG(CHK,<PARITY ERROR DETECTED BY PAGER>)
	JRST PGUNTP		;TRY AGAIN

;DISPATCH PROCEDURE FOR TRAP STATUS BITS

TABA:	EXP TRP0,TRP1,TRP2,TRP3

TRP1:	CAIL 2,7
	BUG(HLT,<PAGER TRAP WITH BAD TRAP STATUS WORD>)
	XCT TAB1(2)

TAB1:	BUG(HLT,<PAGER TRAP WITH BAD TRAP STATUS WORD>)
	JRST NIC		;SHARED NOT IN CORE
	JRST NIC		;PAGE TABLE NOT IN CORE
	JRST NIC		;2ND INDIRECT PRIV NOT IN CORE
	JRST NIC		;INDIRECT SHARED NOT IN CORE
	JRST NIC		;IND PT NIC
	JRST ILIND		;EXCESSIVE IND.

TRP2:
TRP3:	CAIL 2,7		;INDIRECT OR ORIGINAL PT EQUIVALENT
	BUG(HLT,<PAGER TRAP WITH BAD TRAP STATUS WORD>)
	XCT TAB2(2)

TAB2:	JRST NIC		;PRIVATE NOT IN CORE
	JRST WCPY		;WRITE COPY TRAP
	JRST UTRP		;USER TRAP
	JRST NPG		;ACCESS (OR BIT 10-11 = 3)
	JRST ILRD		;ILLEGAL READ OR XCT
	JRST ILWR		;ILLEGAL WRITE
	BUG(HLT,<PAGER TRAP ON ALR VIOLATION OR ILLEGAL FORMAT>)

;TRAP CODE 0, CST WORD BITS 0-2 = 0

TRP0:	CALL GETTPD		;DECODE EFFECTIVE ADDRESS
	TLNE 2,17		;PAGE MUST BE IN CORE
	BUG(HLT,<CST LESS THAN 100 PAGER TRAP BUT PAGE NOT IN CORE>)
	HLRZ 1,CST0(2)		;GET AGE CODE
	LSH 1,-^D12
	CAIL 1,10
	JRST NIC		;CHANGED STATE RECENTLY
TRP0A:	CAIN 1,6		;READ IN PROGRESS?
	JRST TRP0R		;YES, WAIT FOR IT TO FINISH
	CAIN 1,2		;READ COMPLETED?
	JRST NICN		;YES, GO GET IT
	JRST NIC		;NO, GO AHEAD

TRAPSP:	IOWD NTSK,TRAPSK	;POINTER TO LOCAL STACK

;ASSIGN PAGE AND SET AGE

AGESET:	MOVE 7,FORKX
AGESN:	PUSH P,2
	MOVEI 2,0(1)
AGES1:	HLRZ 1,CST0(2)
	LSH 1,-^D12
	CAIL 1,10		;NOW ASSIGNED?
	JRST [	HLRZ 1,CST3(2)	;YES, FIND OUT WHERE
		ANDI 1,7777
		CAML 2,SWPCOR	;NOT SWAPPABLE PAGE? OR
		CAIN 1,0(7)	;THIS PROCESS?
		JRST AGES2	;YES, OK
		SOS PNDING	;DO THIS BECAUSE PAGE WAS EITHER
				;AWAITING COLLECTION OR SOSWSP
				;WILL AOS THIS COUNTER
		SOS SUMNRX
		CAIL 1,NFKS	;ANY PROCESS?
		JRST ATP1	;NO
		PUSH P,2
		MOVEI 2,0(1)
		CALL SOSWSP	;REDUCE WSP
		POP P,2
		JRST ATP1]	;GO ASSIGN TO THIS PROCESS
AGESX:	XCT TRP0T(1)
AGES2:	MOVEI 1,0(2)
	POP P,2
	RET

TRP0T:	JRST ATP0		;AVAILABLE AND ON REPLACABLE QUEUE
	BUG(HLT,<BAD AGE FIELD IN CST0>)
	JRST ATP1R		;READ COMPLETED
	BUG(HLT,<BAD AGE FIELD IN CST0>)
	JRST ATP4		;WRITE IN PROGRESS
	BUG(HLT,<BAD AGE FIELD IN CST0>)
	JRST ATP2		;READ IN PROGRESS
	BUG(HLT,<BAD AGE FIELD IN CST0>)

TRP0R:	MOVSI 1,0(2)
	HRRI 1,SWPRT
	CALL PGIWT		;WAIT FOR PAGE AND ACCOUNT
	JRST NICN

ATP1R:	MOVSI 1,SWPERR		;CHECK FOR ERROR ON READ
	TDNN 1,CST3(2)
	JRST ATP1		;NO ERROR
	PUSH P,2
	MOVEI 1,^D11		;FILE DATA ERROR PSI CHANNEL
	MOVEI 2,0(7)		;GET FORK NUMBER
	CALL PSIRQ		;INTERRUPT THE FORK
	RESKD1
	POP P,2
	JRST ATP1

ATP2:	MOVSI 1,0(2)
	HRRI 1,SWPRT		;READ NOW IN PROGRESS OR COMPLETED
	JSYS SCHEDP		;RESCHEDULE UNTIL AVAILABLE
	JRST AGES1		;CHECK AGE AGAIN

ATP4:	PIOFF
	LDB 1,[POINT 6,CST0(2),5] ;GET GUARANTEED UP TO DATE STATE
	CAIE 1,4		;WRITE IN PROGRESS?
	JRST [	PION		;NO, GO LOOK AT STATE AGAIN
		JRST AGES1]
	SETZM CST0(2)		;INHIBIT COMPLETION ACTION
	SOS PNDING
	SOS SUMNRX
	PION
	SOS IOIP
	JRST ATP1

ATP0:	SOS NRPLQ		;ONE LESS PAGE ON REPLACABLE
	PIOFF
	MOVE 1,CST3(2)		;UNQUEUE PAGE FROM REPLACABLE
	HLLM 1,0(1)
	MOVS 1,1
	HLRM 1,0(1)
	PION
	SETZM CST3(2)
ATP1:	AOS 1,FKWSP(7)		;INCREASE OWNERSHIP COUNT
	PUSH P,2
	MOVEI 1,0(1)
	PUSH P,1
	MOVE 2,FKFLGS(7)
	TLNE 2,BLST		;IN BALANCE SET?
	TLNE 2,FORCEM		;HALF REMOVED PROCESS?
	JRST [AOS SUMNRX	;YES, TREAT LIKE NON-BALSET
		AOS POTEN
		JRST ATP1A]
	HRRZ 1,FKNR(7)		;GET CURRENT RESERVE
	CAML 1,0(P)		;LESS THAN CURRENT SIZE?
	JRST ATP1A		;NO, OK
	SUB 1,0(P)		;YES, CALCULATE DIFFERENCE
	MOVN 1,1
	ADDM 1,FKNR(7)		;INCREASE RESERVE
	ADDM 1,SUMNRX
ATP1A:	SUB P,BHC+1		;FLUSH GARBAGE
	HLRZ 1,FKNR(7)		;GET UPDATED AGE
	POP P,2			;RESTORE PAGE NUMBER
	DPB 1,[POINT 9,CST0(2),8]	;NEW AGE OF PAGE
	DPB 7,[POINT 12,CST3(2),17]	;ASSIGN PAGE TO PROCESS
	MOVSI 1,(777B8!CORMB)	;PRESERVE AGE AND CORMB
	ANDM 1,CST0(2)		;AND CLEAR ALL PROCESS USE BITS
	JRST AGES2

;ILLEGAL REFERENCE TRAPS

ILRD:	MOVEI 1,^D16		;MR TRAP CHANNEL
	MOVE 2,TRAPSW
	TLNE 2,2		;EXECUTE REFERENCE?
	MOVEI 1,^D18		;YES, MX
ILRF:	CALL PSIRQ0		;REQUEST INTERRUPT, THIS FORK
	RESKD1
	MOVE 1,TRAPSW
	MOVEM 1,UTRSW		;IN CASE USER WANTS TRAP STATUS
	MOVE 2,-1(P)		;WRITE DATA (ASSUMING TOP-LEVEL TRAP)
	MOVEM 2,UTRWD
	MOVE 2,-2(P)		;PC
	TLNN 2,UMODF		;USER?
	SKIPGE INTDF		;OR INTERRUPTABLE?
	JRST .+3		;YES
	TLNE 1,12		;MUST DEFER INTERRUPT, READ REF?
	AOS -2(P)		;YES, DONOT RESTART INSTRUCTION
	TLO 1,12		;SET BITS TO PREVENT WRITE-COMPLETION
	MOVEM 1,TRAPSW		;ACTION ON UNTRAP
	JRST PGUNTP

ILWR:	MOVE 1,TRAPSW
	TLNE 1,1		;MON REF BELOW 400000?
	TRNE 1,400000
	SKIPA 1,[^D17]		;NO, INITIATE MW INTERRUPT
	BUG(HLT,<ATTEMPTED MODIFY REFERENCE TO PROTECTED MONITOR>)
	JRST ILRF

ILIND:	MOVE 1,TRAPSW		;SEE IF READ OR WRITE
	TLNE 1,12
	JRST ILRD		;GIVE READ TRAP INTERRUPT
	JRST ILWR		;OR WRITE TRAP INTERRUPT

UTRP:	MOVEI 3,TRAPUB
	CALL GETTD1		;FIND PAGE WITH TRAPUB SET
	HLRZ 6,1
	CAIGE 6,NOFN		;COULDN'T BE IN FILE XB
	BUG(HLT,<TRAP-TO-USER IN FILE INDEX BLOCK>)
	CALL SETSPG		;MAP PT HOLDING PTR
	MOVSI 2,TRAPUB
	ANDCAM 2,CSWPGA(1)	;CLEAR THE BIT
	CALL RELSPG
	MOVEI 1,^D21
	CALL PSIRQ0		;INTERRUPT ON CHN 21
	RESKD1
	MOVE 1,TRAPSW
	MOVEM 1,UTRSW		;SAVE TRAP STATUS WORD ONLY
	JRST PGUNTP		;FINISH UP WRITE IF ANY AND UNTRAP

;PAGE NOT IN EXISTANCE TRAPS

NPG:	MOVE 1,TRAPSW
	TLNE 1,1		;MONITOR?
	JRST [	MOVEI 1,0(1)	;YES, LEGAL PAGE?
		CAIL 1,JSB
		CAIL 1,JSB+1000
		CAIA
		JRST MILRF1
		CAIL 1,PPMA
		CAIL 1,DDPG1A
		JRST NPG1	;YES
		JRST MILRF1]	;MONITOR MALFUNCTION
NPG1:	CALL GETTPD		;NEW PAGE NEEDED
	HLRZ 6,1		;GET PT NUMBER
	CAIGE 6,NOFN		;MUST BE PT, NOT OFN
	JRST NPG2
	CALL SETSPG		;MAP IT
	SKIPE 2,CSWPGA(1)	;BE SURE PT SLOT NOW EMPTY
	JRST NPGBAD		;IT'S NOT, PROBABLY SPURIOUS TRAP
	MOVSI 2,RWXB+1
	MOVEM 2,CSWPGA(1)	;SETUP NULL POINTER
	CALL RELSPG		;RELEASE MAP
	MOVE 1,PSICHM
	MOVE 2,TRAPSW
	TLNN 2,1		;USER MAP, AND
	TRNN 1,1B22		;CHANNEL 22 ON?
	JRST NICFQ		;NO
	MOVEI 1,^D22		;YES, REQUEST INTERRUPT
	CALL PSIRQ0
	RESKD1
	MOVE 1,TRAPSW
	MOVEM 1,UTRSW
NICFQ:	MOVE 1,DRMFRE##		;SEE IF DRUM IS FULL
	CAILE 1,100		;TO DEFEND SYSTEM FROM DEATH
	JRST NICFQX		;OK
	MOVEI 1,^D20		;FULL. GIVE MACH SIZE EXCEEDED PSI
	CALL PSIRQ0		; TO CURRENT PROCESS
	RESKD1			;MAKE HIM SEE IT, THEN GO ON.
NICFQX:	JRST NIC

MILRF1:	BUG(HLT,<ILLEGAL ADDRESS REFERENCE IN MONITOR>)

NPGBAD:	TLNN 2,ACCESB		;ACCESS BIT ON?
	BUG(HLT,<BAD POINTER IN PAGE TABLE>)
	BUG(CHK,<PROBABLE SPURIOUS PAGER TRAP>)
	CALL RELSPG		;CLEAN UP
	JRST PGUNTP		;GO UNTRAP AND TRY AGAIN

;THIS COULD CONCEIVABLY HAPPEN ON AN IND PTR TO A FILE FROM WHICH
;THE PAGE WAS REMOVED

NPG2:	JRST ILIND		;CAN ONLY GIVE TRAP TO USER

;COPY-ON-WRITE TRAP

WCPY:	MOVE 1,TRAPSW
	TLNE 1,(1B4+1B6)	;OTHER TRAPS ALSO?
	JRST [	TLZ 1,(1B3)	;YES, CLEAR WRITE COPY
		MOVEM 1,TRAPSW	;FROM TRAP CAUSE
		JRST PGRTD]	;AND GO HANDLE THE OTHER CAUSE
WCPY6:	CALL GETTPD
	TLNE 2,17		;ACTUAL PAGE IN CORE?
	JRST NIC		;NO, GET IT IN FIRST
	JUMPE 2,ILWR		;ERROR IF PAGE DOES NOT EXIST AT ALL
	LDB 3,[POINT 6,CST0(2),5] ;AGE FIELD
	CAIN 3,6		;IN PROCESS OF BEING READ?
	JRST WCPY5		;YES. WAIT FOR IT.
	MOVEI 3,COPYB
	CALL GETTD1		;WILL STOP ON FIRST POINTER WITH COPYB
	HLRZ 6,1		;PTN
	CAIG 6,NOFN
	BUG(HLT,<COPY-WRITE POINTER IN INDEX BLOCK>)
	CALL SETSPG		;MAP THE PT
	MOVSI 2,RWX
	AND 2,CSWPGA(1)		;GET ACCESS OF SOURCE PAGE
	IOR 2,[XWD WRITEB+ACCESB+1,1] ;MAKE PRIV PTR WITH UNASS ADR
	EXCH 2,CSWPGA(1)	;EXCH IT WITH THE WC POINTER
	TLNN 2,SHRBIT+INDBIT	;IT SHOULD BE SHARED OR INDIRECT
	JRST WCPY4		;BUT IT'S NOT
	TLO 2,READB		;MAKE SURE WE CAN READ FROM THE PAGE
	MOVEM 2,PSB+CPYPG	;PUT THE ORIG POINTER IN MON MAP
	CALL RELSPG
	PUSH P,1		;SAVE ORIG PTN.PN
WCPY2:	MOVEI 1,CPYPG		;CONSTRUCT IDENT FOR COPY SOURCE PAGE
	HRL 1,FKPGS(7)
	CALL GETPGD		;TRACK IT DOWN
	TLNE 2,17		;IN CORE?
	BUG(HLT,<WCPY - PAGE SHOULD BE IN CORE HERE>)
	MOVEI 1,0(2)
	CALL AGESET		;FIX THE PAGE
	MOVSI 3,PLKV
	ADDM 3,CST1(1)		;AND LOCK IT DURING NEXT SWAPIN
	EXCH 1,0(P)		;SAVE CORE PN, GET ORIG PTN.PN
	CALL SWPINP		;THIS WILL COPY FROM CPYPG TO A NEW PAGE
	POP P,1
	MOVSI 3,-PLKV
	ADDM 3,CST1(1)		;UNLOCK THE SOURCE PAGE
	MOVEI 1,CPYPG
	HRL 1,FKPGS(7)
	CALL MRPT		;GET IDENT OF SHARE PAGE BEING RELEASED
	SETZ 1,			;INDIRECT TO FORK
	PUSH P,1
	OKSKED
	MOVEI 1,CPYPG
	HRL 1,FKPGS(7)
	CALL RELMPG		;RELEASE THE ORIG PAGE FROM MON MAP
	BUG (HLT,<WCPY -- RELMPG FAILED>)
	OKSKED
	CALL RELCPT		;CLEANUP FROM RELMPG
	POP P,1
	JUMPE 1,WCPY3		;IGNORE INDIRECT TO FORK PTR
	MOVE 5,0
	MOVE 6,11		;SAVE AC'S USED BY OFNJFN
	CALL JFNDCR		;DECREMENT MAP COUNT FOR JFN
	MOVE 0,5
	MOVE 11,6		;RESTORE AC'S
WCPY3:	NOSKED
	JRST NIC		;UPDATE STATS AND CONTINUE

WCPY4:	TLZ 2,COPYB		;MAKE IT LOOK LIKE WE COPIED IT
	TLO 2,WRITEB
	MOVEM 2,CSWPGA(1)
	CALL RELSPG
	JRST NIC2

WCPY5:	MOVSI 1,(2)		;WAIT FOR THIS PAGE
	HRRI 1,SWPRT		;READ COMPLETE TEST
	JSYS SCHEDR		;WAIT AND GO OKSKED
	NOSKED
	JRST WCPY6		;TRY AGAIN

;NOT IN CORE TRAP

NIC:	MOVE 1,FKFLGS(7)	;SEE IF THERE IS A REQUEST TO CLEAR IFAV
	TLZE 1,ZIFA		;REQUEST TO ZERO INTERFAULT AV?
	 SETZM IFAV

NICN2:	TLZ 1,NOFLT		;INDICATE SCHED CAN ADJUST FKNR IF NO PAGE FAULTS OCCUR
	MOVEM 1,FKFLGS(7)

	MOVE 1,IFAV		;UPDATE INTERFAULT AV
	FMPR 1,IFAVC0		;AV' = (C*AV + TIME)/(C+1)
	SETZ 2,
	EXCH 2,IFTIM		;ACCUMULATED TIME SINCE LAST FAULT
	ADD 2,JOBRTT		;GET IFTIM UP TO DATE
	FSC 2,233		;FLOAT IT
	FADR 1,2
	FDVR 1,IFAVC1
	MOVEM 1,IFAV
	MOVE 2,JOBNO
	HRRZ 2,JOBNAM(2)	;GET SUBSYSTEM INDEX
	AOS SPFLTS(2)		;ACCOUNT PAGE FAULTS FOR SUBSYSTEM
NICN:	SKIPE TRAPC		;IS THIS A RECURSIVE TRAP?
	JRST NIC2		;YES, AVOID PDL OV IN ANY GC LOGIC
	LDB 1,[POINT 9,FKNR(7),8] ;GET LAST XGC AGE
	LDB 2,[POINT 9,FKNR(7),17] ;CURRENT AGE
	SUBI 2,0(1)		;NOW-THEN
	CAIGE 2,0		;WRAPAROUND?
	ADDI 2,1000-100		;YES
	CAML 2,GCRATE		;TIME FOR ANOTHER XGC?
	JRST NICMG		;YES
NICMG1:	CALL NICCKS		;CHECK FOR ALLOWABLE SIZE
NIC2:	MOVE 3,TRAPSW
	TLNN 3,1		;USER MAP REF?
	JRST [	LSH 3,-^D9	;YES, UPDATE WS BITS
		ANDI 3,777
		IDIVI 3,^D36
		MOVE 4,BITS(4)
		IORM 4,WSPGS(3)
		JRST .+1]
	CALL GETTPD		;DECODE TRAP ADDRESS
	TLNE 2,17		;PAGE IN CORE?
	JRST NIC6		;NO
	MOVEI 1,0(2)		;YES
	CALL AGESET		;SET AGE
	JRST PGUNTP		;RESUME PROCESS

NIC6:	TLNN 2,16		;UNASSIGNED ADR?
	JRST NIC6A		;YES
NIC8:	CALL SWPINW		;SWAP IN THE PAGE
	JRST NIC2

;ADJUST CAPT IF NECESSARY, THEN DO CORE MGT

NICMG:	MOVE 1,IFAV		;CURRENT INTERFAULT AVERAGE
	MOVE 2,CAPT		;CURRENT WINDOW SIZE
	MOVE 3,2
	ASH 3,-4		;ADJUST UP OR DOWN BY 1/16
	CAMGE 1,IFALO		;IFAV NOW TOO LOW?
	ADD 2,3			;YES, MAKE CAPT LARGER
	CAML 1,IFAHI		;IFAV NOW TOO HIGH?
	SUB 2,3			;YES, MAKE CAPT SMALLER
	CAMLE 2,CAPTMX		;SEE IF CAPT WITHIN LIMITS
	MOVE 2,CAPTMX
	CAMGE 2,CAPTMN
	MOVE 2,CAPTMN
	MOVEM 2,CAPT
	MOVEI 1,0(2)		;USE CURRENT CAPT
	CALL XGC
	JRST NICMG1		;RETURN


;AVERAGE SWAP LATENCY * 2 - CONTROLS DESIRED INTERFAULT AVERAGE

SWPLAT:	40.0			;2 * 20MS FOR BRYANT DRUM
IFAMEA:	40.0			;IDEAL IFAV

;WE WOULD LIKE TO KEEP PROCESSES OPERATING WITH
;	IFALO .LT. IFAV .LT. IFAHI
IFAHI:	60.0		;1.5*IFAMEA
IFALO:	20.0		;.5*IFAMEA

AGTICK==^D20			;MILLISECONDS PER TICK OF AGE REGISTER
ICAPT:	^D1000/AGTICK		;WINDOW SIZE IN TICKS
CAPTMX:	^D1500/AGTICK		;MAX CAPT
CAPTMN:	^D500/AGTICK		;MIN CAPT
GCRATE:	^D1000/AGTICK		;RECIPROCAL OF GC FREQUENCY

;DECAY CONSTANT FOR INTERFAULT AVERAGE

IFAVC0:	EXP 10.0		;LARGER C IMPLIES SLOWER IFAV CHANGE
IFAVC1:	EXP 11.0		;IFAVC0+1

NIC6A:	TLNE 1,-1		;IN SPT?
	JRST [	HLRZ 6,1	;NO, GET XB
		CAIL 6,NOFN	;OFN?
		JRST NIC8	;NO
		CALL SETSPG
		MOVSI 2,PLKV
		ADDM 2,CST1(6)	;LOCK PT WHILE ASSIGNING
		CALL RELSPG
		HLRZ 2,1
		JRST NIC6C]
	HLRZ 2,SPTH(1)		;GET OWNING PT
	JUMPE 2,NIC8		;IGNORE IF NONE OR NOT OFN
	CAIL 2,NOFN
	JRST NIC8
NIC6C:	PUSH P,1
	MOVE 1,SPTH(2)		;CLASS, TRACK, ETC.
	CALL DSKASN		;ASSIGN DISK ADDRESS FOR FILE PAGE
	JRST NIC6D		;RAN OUT
	TLO 1,NEWFB		;INDICATE PAGE NEVER PREVIOUSLY WRITTEN
	MOVE 2,1
	POP P,1
	TLNN 1,-1		;IN SPT?
	JRST [	DPB 2,[POINT 22,SPT(1),35] ;YES, STORE NEW ADDRESS
		JRST NIC8]	;NOW GO SWAP IN PAGE
	HLRZ 6,1
	CALL SETSPG		;MAP XB
	DPB 2,[POINT 22,CSWPGA(1),35] ;STORE NEW ADDRESS IN XB
	MOVSI 2,-PLKV
	ADDM 2,CST1(6)		;UNDO LOCK ABOVE
	CALL RELSPG
	JRST NIC8		;NOW PROCEED WITH SWAP

NIC6D:	POP P,1
	TLNN 1,-1		;IN SPT?
	JRST NIC6E		;YES
	HLRZ 6,1		;NO, MUST UNDO LOCK
	CALL SETSPG
	MOVSI 2,-PLKV
	ADDM 2,CST1(6)
	CALL RELSPG
NIC6E:	MOVEI 1,OPNX10		;'NO ROOM'
	MOVEM 1,LSTERR
	MOVEI 1,^D20		;MACH SIZE EXCEEDED INT CHANNEL
	JRST ILRF		;GENERATE ILLEG REF INT

;CHECK OVERALL SIZE FOR PHYSICAL CORE LIMITS

NICCKS:	MOVE 1,IFAV		;GET INTERFAULT AV.
	CAMGE 1,IFALO		;IS HE RUNNING WELL?
	 JRST NICCK2		;NO, DON'T REDUCE HIS FKNR
	HRRZ 1,FKNR(7)		;HE IS RUNNING WELL, SET FKNR TO FKWSP+1
	HRRZ 2,FKWSP(7)
	SUBI 2,-1(1)		;-(FKNR-(FKWSP+1))
	ADDM 2,SUMNRX
	ADDM 2,FKNR(7)
NICCK2:	MOVE 1,CAPT		;INIT WINDOW SIZE FOR POSSIBLE XGC
	ASH 1,-3		;IS 1/8 REG CAPT
NIC3B:	PUSH P,1
NIC3A:	HRRZ 1,FKNR(7)
	HRRZ 3,FKWSP(7)
	CAIG 1,0(3)		;RESERVE GREATER THAN CURRENT ASSMT?
	JRST NIC3C		;NO, GO MAKE IT SO
NIC3G:	MOVE 2,NBPROC		;IS THIS THE ONLY PROC IN BALSET?
	CAIN 2,1
	 JRST [MOVE 3,NRPLQ	;YES, BETTER SEE HOW RPLQ IS DOING
		ADD 3,IOIP
		CAML 3,NRPMIN
		JRST .+1
		JRST NIC3]	;NOT SO WELL, MAKE HIM PAGE AGINST HISSELF
	CAML 1,NPMAX		;DEFINITELY TOO BIG?
	JRST NIC3		;YES
	CAMGE 1,SNPMAX		;DEFINITELY NOT TOO BIG?
	JRST NIC3E		;YES
				;MAYBE TOO BIG -- YES IF OTHER
	CAILE 2,1		;PROCESSES IN BALSET
	JRST NIC3
	JRST NIC3E
NIC3:	CALL GCPG		;TRY COLLECTING JUST 1 PAGE
	JRST .+2		;FAILED, MAYBE NO USER MAP PAGES
	JRST NIC3A
	MOVE 1,0(P)		;GET WINDOW SIZE
	CALL XGC		;DO GC
	POP P,1
	JUMPE 1,R		;JUST CANT GET ANYMORE, AVOID LOOPING
	ASH 1,-1		;IF ANOTHER GC NECESSARY, USE
	JRST NIC3B		;SMALLER WINDOW

NIC3E:	POP P,1			;FLUSH TEMP
	RET

NIC3C:	MOVE 2,RJAV
	CAMGE 2,[2.0]		;LESS THAN 2 FORKS AV?
	JRST NIC3F		;YES, ALLOW NR GROWTH
	MOVE 1,IFAV
	CAMG 1,IFAMEA		;PROCESS FAULT AV .G. DESIRED?
	JRST NIC3F		;NO, ALLOW
	CALL GCPG		;YES, REMOVE 1 PAGE
	JRST NIC3F		;COULDN'T, HAVE TO ALLOW NR INCREASE
	JRST NIC3A

NIC3F:	HRRZ 1,FKNR(7)
	HRRZ 3,FKWSP(7)
	SUBI 3,-1(1)		;SET RESERVE TO BE CURRENT SIZE +1
	ADDM 3,SUMNRX
	ADDM 3,FKNR(7)
	JRST NIC3G

;REMOVE 1 PAGE FROM PROCESS.  SELECT FIRST PAGE OLDER THAN CAPT,
;OR OLDEST PAGE

GCPG:	MOVSI 6,-NWSPGS		;SET TO SCAN WS BIT TABLE
	PUSH P,[0]		;WILL REMEMBER OLDEST PAGE FOUND
	LDB 3,[POINT 9,FKNR(7),17] ;PROCESS AGE NOW
	PUSH P,3
	SUB 3,CAPT		;CUTOFF AGE
	PUSH P,3
	MOVE 3,-1(P)		;USE CURRENT AGE AS INIT MIN AGE
GCPG2:	SKIPE 4,WSPGS(6)
GCPG3:	JFFO 4,GCPG1		;FIND PAGE IN USE
	AOBJN 6,GCPG2
	SUB P,BHC+2		;DIDN'T FIND PAGE OLDER THAN CAPT
	POP P,1			;USE OLDEST PAGE SEEN
	JUMPE 1,R		;DIDN'T FIND COLLECTABLE PAGE
	JRST GCPG4		;COLLECT IT

GCPG1:	ANDCM 4,BITS(5)
	MOVEI 1,0(6)
	IMULI 1,^D36		;COMPUTE MAP PAGE NUMBER
	ADDI 1,0(5)
	SKIPE 1,UPTA(1)		;GET MAP WORD
	TLNE 1,INDBIT
	JRST GCPG3		;IGNORE EMPTY OR INDIRECT
	TLNE 1,SHRBIT		;SHARE PTR?
	JRST [	LSH 1,-^D9	;YES, TRACE
		ANDI 1,SPTM
		MOVE 1,SPT(1)
		JRST .+1]
	TLNE 1,17		;IN CORE?
	JRST GCPG3		;NO
	HLRZ 2,CST0(1)
	TRNN 2,(7B2)		;ASSIGNED?
	JRST GCPG3		;NO
	HLRZ 5,CST3(1)		;YES, TO THIS PROCESS?
	ANDI 5,7777
	CAIE 5,0(7)
	JRST GCPG3		;NO
	LSH 2,-^D9		;YES, GET AGE
	CAMLE 2,-1(P)		;CHECK WRAPAROUND
	SUBI 2,1000-100
	CAMLE 2,0(P)		;OUTSIDE CAPT WINDOW?
	JRST [	MOVE 5,2	;NO, SAVE AGE
		CAMGE 2,3	;OLDEST PAGE SEEN?
		CALL SWPCHK	;SWAPPABLE?
		JRST GCPG3	;NO
		MOVE 3,5	;YES, REMEMBER OLDEST AGE
		MOVEM 1,-2(P)	;AND PAGE
		JRST GCPG3]
	CALL SWPCHK		;CAN SWAPOUT PAGE?
	JRST GCPG3		;NO
	SUB P,BHC+3		;YES, FLUSH TEMPS
GCPG4:	SOS FKWSP(7)		;DEASSIGN PAGE
	SOS FKNR(7)
	AOS PNDING		;COUNT PAGE AWAITING COLLECTION
	CALL SWPOUT		;SWAP IT
	AOS 0(P)		;RETURN GOOD
	RET

;CHECK IF PAGE IS SWAPPABLE NOW

SWPCHK:	MOVE 2,CST1(1)
	TLNE 2,-PLKV
	RET			;PAGE IS LOCKED OR HAS NO SWAP ADR
	MOVSI 2,DWRBIT
	TDNN 2,CST3(1)		;BEING WRITTEN?
	AOS 0(P)		;NO, OK
	RET

;COLLECT OLD PAGES FOR THIS PROCESS, CALLED WITH CUTOFF DIFFERENCE IN 1
;THE PAGES ASSIGNED TO THIS PROCESS ARE ASSUMED TO HAVE AGES RANGING
;FROM M1 TO M2.  M2 IS THE CURRENT AGE, LH OF FKNR. WE WISH TO
;FLUSH ALL PAGES OLDER THAN M, WHERE M1<M<M2.  IF EACH PAGE     >>
;HAS BEN REFERENCED ONLY ONCE, THE AGES WOULD BE EVENLY DISTRIBUTED
;BETWEEN M1 AND M2.  HOWEVER, PAGES ACTIVELY BEING USED SHOULD
;HAVE AGES CLOSER TO M2.  THEREFORE, WE PICK A CUTOFF AGE BY
;SUBTRACTING A SMALL NUMBER FROM M2.  TO PREVENT EXCESSIVE COLLECTION
;WHERE ALL PAGES HAVE BEEN REFERENCED RECENTLY, WE SET A LIMIT
;ON THE TOTAL NUMBER OF PAGES WHICH CAN BE FLUSHED, AND STOP
;IF WE HIT THIS LIMIT. ALSO, SINCE AGES CAN WRAP AROUND THE 9-BIT
;FIELD, AGES GREATER THAN M2 ARE ASSUMED TO BE LEFT FROM THE PREVIOUS
;WRAP AROUND AND ARE ADJUSTED ACCORDINGLY.

XGC:	HRRZ 4,FKCNO(7)
	PUSH P,BITS(4)		;PROCESS USE BIT FOR THIS PROCESS
	MOVE 6,SWPCOR		;FIRST SWAPPING PAGE
	HRRZ 4,FKWSP(7)		;NUMBER PAGES NOW IN CORE
;	ASH 4,-1		;COMPUTE 1/2 CURRENT SIZE
	PUSH P,4		;MAX NUMBER OF PAGES TO COLLECT
	LDB 3,[POINT 9,FKNR(7),17] ;CURRENT AGE CLOCK
	DPB 3,[POINT 9,FKNR(7),8] ;REMEMBER 'TIME' OF LAST XGC
	PUSH P,3
	SUBI 3,0(1)		;CUTOFF AGE, 'OLD'=NOW-DIFFERENCE
	PUSH P,3
XGC2:	HLRZ 1,CST0(6)
	TRNN 1,700000		;PAGE IN USE?
	JRST XGC1		;NO
	HLRZ 2,CST3(6)
	ANDI 2,7777
	CAIE 2,0(7)		;ASSIGNED TO THIS PROCESS?
	JRST XGC1		;NO
	LSH 1,-^D9		;YES, GET AGE FIELD
	MOVE 2,-3(P)		;PROCESS USE BIT
	ANDCA 2,CST0(6)		;LOOK AT OTHER PROCESS USE BITS
	TDNE 2,[377777777]	;IF ANY ON, MEANS REFERENCES BY OTHER
	MOVE 1,-1(P)		;PROCESSE, AGE INVALID SO USE CURRENT
	CAMLE 1,-1(P)		;IF .G. NOW, MUST NOT HAVE WRAPPED
	SUBI 1,1000-100		;SO WRAP IT
	CAMLE 1,0(P)		;.G. OLD?
	JRST XGC1		;YES, SAVE IT
	MOVE 2,CST1(6)
	TLNE 2,-PLKV		;DON'T SWAP PAGE IF LOCKED
	JRST XGC1
	MOVSI 2,DWRBIT
	TDNE 2,CST3(6)		;DON'T SWAP PAGE IF NOW BEING WRITTEN
	JRST XGC1
	SOS FKWSP(7)		;DEASSIGN PAGE FROM THIS PROCESS
	SOS FKNR(7)
	AOS PNDING
	MOVEI 1,0(6)
	CALL SWPOUT		;SWAP IT OUT
	SOSG -2(P)		;COLLECTED ENOUGH PAGES?
	JRST XGC3		;YES
	OKSKED			;DON'T HOG MACHINE FOR TOO LONG
	NOSKED
XGC1:	CAMGE 6,NHIPG		;STOP AFTER HIGHEST KNOWN PAGE
	AOJA 6,XGC2		;NO, LOOK AT NEXT PAGE
XGC3:	SUB P,BHC+4		;FLUSH STACK
	PGRCLD			;CLEAR AR'S
	SETZ 3,
	MOVSI 6,-NWSPGS		;SETUP TO UPDATE WS BITS
XGC5:	SKIPE 4,WSPGS(6)
XGC6:	JFFO 4,XGC4		;FOUND BIT FOR PAGE
	AOBJN 6,XGC5
	RET

XGC4:	ANDCM 4,BITS(5)		;DON'T FIND THAT BIT NEXT TIME
	MOVEI 1,0(6)		;COMPUTE PAGE NUMBER
	IMULI 1,^D36
	ADDI 1,0(5)
	SKIPE 1,UPTA(1)		;PAGE DELETED?
	TLNE 1,INDBIT		;OR INDIRECT?
	JRST XGC7		;YES, FORGET IT
	TLNE 1,SHRBIT		;SHR PTR?
	JRST [	LSH 1,-^D9	;YES, GET ACTUAL ADDRESS
		ANDI 1,SPTM
		MOVE 1,SPT(1)
		JRST .+1]
	TLNE 1,17		;PAGE NOW IN CORE?
	JRST XGC7		;NO, FLUSH IT
	MOVE 2,CST0(1)
	TLNE 2,(7B2)		;STILL IN USE?
	AOJA 3,XGC6		;YES, COUNT IT AND LEAVE IT
	TLC 2,(02B5)		;READ COMPLETED?
	TLNE 2,(77B5)
	JRST XGC7		;NO
	CALL AGESET
	AOJA 3,XGC6		;COUNT PAGE AND KEEP IT

XGC7:	MOVE 1,BITS(5)
	ANDCAM 1,WSPGS(6)	;CLEAR BIT FOR PAGE NO LONGER IN WS
	JRST XGC6

;RELEASE WORKING SET JSYS

.RWSET:	JSYS MENTR
	NOSKED
	MOVE 7,FORKX
	SETZ 1,			;USE 0 WINDOW SIZE
	CALL XGC		;COLLECT ALL PAGES
	HRRZ 1,FKWSP(7)		;SET NEW NR TO MAX(6,SIZE)
	CAIGE 1,6		;SIZE .GE. 6?
	MOVEI 1,6		;NO, USE 6 AS NEW NR
	HRRZ 2,FKNR(7)
	SUBI 1,0(2)
	ADDM 1,FKNR(7)
	ADDM 1,SUMNRX
	OKSKED
	JRST MRETN

;RESUME PROCESS AFTER PAGER TRAP

PGUNTP:	SKIPE TRAPC		;OUTER LEVEL TRAP?
	JRST PGU4		;NO
IFN KIFLG,<
	POP P,KIMAC2
	POP P,KIMAC1>		;RESTORE KI-10 MUUO TEMPS
	POP P,1			;PROCESS TIME AT TIME OF ENTRY
	MOVE 2,FKRT
	ADD 2,JOBRTT		;2=CURRENT PROCESS TIME
	SUB 2,1			;TIME OF TRAP CODE
	ADDM 2,PTTIM		;PAGE TRAP TIME FOR THIS FORK
	ADDM 2,PTRAP		;PAGE TRAP TIME FOR SYSTEM
	AOS TOPTRP		;COUNT TOP LEVEL TRAPS
PGU4:	AOS PTRAP+1		;COUNT TRAPS
IFN KAFLG,<
	CONO PGR,0>		;LOAD WITH NEW AGE
	POP P,2			;RECOVER WRITE DATA
	MOVE 3,TRAPSW		;GET TRAP BITS
	SKIPE TRAPC		;IF RECURSIVE TRAP,
	POP P,TRAPSW		;RESTORE OLD STATUS WORD
	TLNE 3,12		;READ OR XCT?
	JRST PGU1		;YES, RESTART INSTRUCTION
	TLNE 3,1		;USER OR MONITOR?
	JRST PGU2		;MONITOR
PGMV1:	UMOVEM 2,0(3)		;USER
PGU1:	POP P,1			;GET RETURN
	TLNN 1,UMODF		;TO USER?
	JRST PGU3		;NO, MONITOR
	MOVEM 1,FPC		;USER, CAN PUT RETURN IN FPC
	MOVE 7,-6(P)
	MOVE 1,-5(P)
	MOVE 2,-4(P)
	MOVE 3,-3(P)
	MOVE 4,-2(P)
	MOVE 5,-1(P)
	MOVE 6,0(P)
	MOVE P,TRAPAP		;USER MODE, SO MUST BE TOP LEVEL TRAP
	SETOM TRAPC
	SETOM INTDF		;FOR USER, MUST BE -1
	OKSKED
	XCT MJRSTF		;RETURN, WILL GET DEFERRED INTERRUPT TOO

PGMV2:
PGU2:	MOVEM 2,0(3)		;STORE MONITOR WRITE DATA
	JRST PGU1

PGU3:	MOVEM 1,PGURET		;SET UP RETURN
	MOVE 7,-6(P)
	MOVE 1,-5(P)
	MOVE 2,-4(P)
	MOVE 3,-3(P)
	MOVE 4,-2(P)
	MOVE 5,-1(P)
	MOVE 6,0(P)
	SUB P,BHC+7
	SOSGE TRAPC		;TOP LEVEL TRAP?
	MOVE P,TRAPAP		;RESTORE AC-P
	OKSKED			;TURN SCHEDULER BACK ON (WILL ALSO PICK
				;UP PENDING PSI'S)
	OKINT			;TURN PSIS BACK ON AND PICK UP ANY THAT
				;WERE DEFERRED

	JRSTF @PGURET		;RETURN

;GET PAGE DATA
;TRACES PTN.PN IN 1 TO NOT IN CORE OR CORE PAGE NUMBER OR WRITE COPY
;RETURN AS GETTPD

GETPGD:	HLRZ 2,1		;PTN TO 2
	MOVEI 1,0(1)		;PN TO 1
	SETZ 3,			;NO SPECIAL BITS TO STOP ON
	JRST GETPD1		;FOLLOW LIKE IND POINTER

;GET TRAP DATA
;RETURNS OFN.PN OR 0.SPTN IN 1
; MAP WORD IN 2

GETTPD:	SETZ 3,			;NO SPECIAL BITS TO STOP ON
GETTD1:	HRRZ 1,TRAPSW		;TRAP EFFECTIVE ADDRESS
	LSH 1,-^D9		;PAGE NUMBER
	HLRZ 2,TRAPSW		;TRAP BITS
	TRNE 2,1		;USER OR MONITOR?
	JRST NIC4		;MONITOR
	HLL 1,FKPGS(7)		;USER, GET PAGE TABLE SPTN
	MOVE 2,UPTA(1)
NICI2:	TLNE 2,0(3)		;REQUESTED BIT ON?
	RET			;YES, STOP HERE
	TLNE 2,INDBIT		;INDIRECT POINTER?
	JRST NICI		;YES
	TLNN 2,SHRBIT		;SHARE POINTER?
	RET			;NO, PRIVATE
	LSH 2,-^D9		;YES, SHIFT TO B35
	ANDI 2,SPTM		;FLUSH BITS
NICI1:	MOVEI 1,0(2)
	MOVE 2,SPT(1)
	RET

NICI:	SETZ 1,			;INDIRECT POINTER.
	ROTC 1,-^D9		;GET OFN TO 2, PN TO 1
	ROT 1,^D9
	ANDI 2,SPTM
GETPD1:	MOVE 6,SPT(2)		;GET PAGE TABLE ADDRESS
	TLNE 6,17		;IN CORE?
	JRST NICI1		;NO, THAT'S THE TROUBLE.
	HRLI 1,0(2)		;YES, PUT OFN IN 1
	MOVEI 6,0(2)
	CALL SETSPG		;MAP PT
	MOVE 2,CSWPGA(1)	;GET MAP WORD
	CALL RELSPG		;CLEAR TEMPORARY MAP WORD
	JRST NICI2		;GO ANALYZE THIS POINTER

NIC4:	CAIL 1,PJMPG		;MONITOR MAP, WHICH ONE?
	JRST NIC4A		;IN PSB
	CAIL 1,PPRMPG+NRSPG
	JRST NIC4B		;IN RES MON
IFE JTRPSW-1,<
	CAIN 1,NJDVPG		;IF MAPPING RES MON IS PAGE JSYS DSP?
	JRST NIC4B >		;YES.
	BUG(HLT,<PAGE FAULT ON RESIDENT MONITOR ADDRESS>)

NIC4A:	HRL 1,FKPGS(7)		;PSB
	MOVE 2,PSB(1)
	JRST NICI2

NIC4B:	HRL 1,MMSPTN		;PERMANENT SWP MON OFN
	MOVE 2,MMAP(1)
	JRST NICI2

;SWAP IN PAGE TABLE OR PSB
;CALLED FROM SCHED

SWPIN0:	TLNE 1,-1		;SPTN?
	JRST SWP01		;NO
	MOVE 3,SPT(1)		;YES, GET CURRENT ADDRESS
	TLNE 3,17		;OUT OF CORE?
	JRST SWP01		;YES
	LDB 2,[POINT 6,CST0(3),5] ;AGE CODE
	CAIE 2,2		;BEING READ OR COMPLETED?
	CAIN 2,6
	JRST SWP03		;YES
	MOVEI 1,0(3)
	CALL AGESN		;GRAB PAGE OFF RPLQ
SWP03:	MOVSI 1,0(3)		;ALREADY IN CORE
	JRST SWP02

SWP01:	CALL SWPIN
	HLRZ 3,1
SWP02:	MOVSI 2,PLKV
	ADDM 2,CST1(3)		;LOCK PAGE
	RET

;SWAPIN AND WAIT AND STAY NOSKED

SWPINP:	NOSKED
	CALL SWPINW
	OKSKED
	RET

;WAIT FOR PAGE AND ACCOUNT

PGIWT:	JSYS SCHEDR
	MOVNI 2,5		;CHARGE 5 MS PER PAGE FAULT
	ADDM 2,RJQNT		;CHARGE AGAINST QUANTUM
	NOSKED
	RET

;SWAP IN AND WAIT FOR COMPLETION

SWPINW:	MOVE 7,FORKX
	AOS USWPCT		;COUNT SWAPS
	TLNE 1,-1		;PT?
	JRST SWPIW2		;YES
	CALL SWPIN		;SWAPIN AND WAIT FOR COMPLETION
SWPIW1:	CALL PGIWT
	HLRZ 1,1		;RESTORE PAGE NO TO R.H.
	RET

SWPIW2:	PUSH P,1		;SAVE ORIG REQUEST
	HLRZ 1,1		;GET PT
	MOVE 3,SPT(1)
	TLNE 3,17		;CORE?
	JRST SWPIW3		;NO
	MOVEI 1,0(3)
	CALL AGESET		;FIX PAGE
	MOVSI 3,PLKV
	ADDM 3,CST1(1)		;SO IT DOESN'T SNEAK AWAY
SWPIW4:	EXCH 1,0(P)		;SAVE CORE PAGE NUMBER, GET ORIG OFN.PN
	CALL SWPIN		;SWAP THE ORIG PAGE
	EXCH 1,0(P)		;GET PT CORE PAGE NUMBER
	MOVSI 3,-PLKV
	ADDM 3,CST1(1)		;UNLOCK IT
	POP P,1
	JRST SWPIW1

SWPIW3:	NOSKED
	CALL SWPIN		;SWAP IN THE PT
	OKSKED
	HLRZ 2,1
	MOVSI 3,PLKV
	ADDM 3,CST1(2)		;LOCK IT
	HRRI 1,SWPRT
	JSYS SCHEDP		;WAIT TO FINISH
	HLRZ 1,1
	CALL AGESET
	JRST SWPIW4		;NOW GO GET THE PAGE

;SWAP IN PAGE
;AC1/ OFN.PN OR 0.SPTN
;RETURNS AC1/ CORE PAGE NO IN LH

SWPIN:	MOVE 3,NRPLQ		;NUMBER OF REPLACABLE PAGES
	JUMPE 3,SWPQT		;GO WAIT IF NONE
SWPIL1:	SOS NRPLQ
	HRRZ 3,RPLQ		;YES, REMOVE FROM QUEUE
	SUBI 3,CST3
	PIOFF
	MOVE 4,CST3(3)
	HLLM 4,0(4)
	MOVS 4,4
	HLRM 4,0(4)
	PION
	SETZM CST3(3)
	CALL DEPG		;RESET PREVIOUS OWNERSHIP
	TLNE 1,-1		;NEW PAGE FROM PT OR SPT?
	JRST SWPI3		;PT
	MOVE 4,SPT(1)		;SPT, GET ADDRESS
	TLNN 4,17
	BUG(HLT,<SWPIN - SPT PAGE ALREADY IN CORE>)
	DPB 3,[POINT 22,SPT(1),35]	;STORE NEW (CORE) ADDRESS
SWPI4:	TLZ 4,-1B31		;FLUSH BITS
	MOVEM 4,CST1(3)		;STORE BACKUP ADDRESS
	MOVEM 1,CST2(3)		;STORE LOCATION OF OWNING PT
	TLNE 4,16		;BACKUP ADDRESS ASSIGNED?
	JRST SWPI5		;YES, GO READ IN PAGE
	MOVSI 1,400000		;SET LEGAL AGE SO PAGER DOESN'T TRAP
	MOVEM 1,CST0(3)
	TLO 3,RWXB		;NO, ZERO OUT PAGE
	MOVEM 3,MMAP+CSWPG
	SETZM CSWPGA
	MOVEI 1,CSWPGA+1
	HRLI 1,-1(1)
	TRNE 4,1		;SPECIAL UNASSIGNED POINTER?
	MOVE 1,[XWD CPYPGA,CSWPGA] ;YES, COPY FROM CPYPG
	BLT 1,CSWPGA+777
	CALL RELSPG
	MOVSI 1,(2B5+CORMB)	;SET STATUS OF PAGE TO READ COMPLETED
	HRRI 1,0(7)		;INCLUDE FORK NUMBER
	MOVEM 1,CST0(3)
	MOVSI 1,0(3)		;RETURN PAGE NUMBER
	HRRI 1,SWPRT		;RETURN APPROPRIATE SCHED TEST
	RET

SWPI3:	HLRZ 6,1		;GET OWNING PT OFN
	CALL SETSPG		;MAP PT
	MOVSI 4,PLKV
	ADDM 4,CST1(6)		;INCREMENT LOCK COUNT
	MOVE 4,CSWPGA(1)
	TLNN 4,17
	BUG(HLT,<SWPIN - PT PAGE ALREADY IN CORE>)
	DPB 3,[POINT 22,CSWPGA(1),35]	;STORE NEW (CORE) ADDRESS
	CALL RELSPG
	JRST SWPI4

SWPQT:	PUSH P,1		;SAVE REQUESTED PAGE IDENT
	MOVEI 1,SWPWTT		;RESCHEDULE UNTIL NRPLQ NON-0
	JSYS SCHEDP
	POP P,1
	JRST SWPIN

SWPWTT:	SKIPLE NRPLQ
	JRST 1(4)
	SETOM CGFLG		;REQUEST GARBAGE COLLECT
	JRST 0(4)

SWPI5:	MOVEI 1,0(3)
	MOVE 2,CST2(1)		;FIGURE OUT IF PAGE IS MAYBE A PT
	TLNE 2,-1		;IN SPT?
	JRST SWPI6		;NO, COULDN'T BE PAGE TABLE
	CAIL 2,NOFN		;PAGE IS PAGE TABLE IF IT IS FILE XB,
	SKIPN SPTH(2)		;OR IF IT IS SHARED BUT DOES NOT
	JRST .+2		;BELONG TO ANY PT OR XB
	JRST SWPI6
	MOVEI 2,0(1)		;BEFORE INITIATING SWAP OF PT,
	TLO 2,RWXB		;FILL THE ENTIRE CORE PAGE WITH
	MOVEM 2,MMAP+CSWPG	;PTRS WHICH WILL CAUSE THE PAGER TO
	MOVSI 2,400000		;TRAP IN A SAFE WAY SHOULD IT HAPPEN
	MOVEM 2,CST0(1)		;TO INTERPRET AN INDIRECT PTR WHICH
	MOVE 2,[XWD CSWPGA,CSWPGA+1] ;GOES THROUGH THIS PT BEFORE
	MOVSI 3,RWXB+1		;THE READ IS COMPLETED. THIS IS DONE
	MOVEM 3,-1(2)		;BECAUSE THE PAGER DOES NOT CHECK
	BLT 2,CSWPGA+777	;CST0 WHEN READING A PTR FROM AN IND
	CALL RELSPG		;PT AND SO DOESN'T NOTICE IF THE PAGE
SWPI6:	MOVSI 2,(6B5)		;IS BEING SWAPPED IN.
	HRRI 2,0(7)		;INCLUDE FORK NO.
	MOVEM 2,CST0(1)		;PUT READ-IN-PROGRESS CODE IN CST0
	TLNE 4,10		;DISK?
	JRST SWPIK		;YES
	TLNE 4,14		;DRUM?
	BUG(HLT,<SWPIN - ILLEGAL SWAP ADDRESS>)
	CALL DRMIO		;YES, INITIATE READ
	AOS DRMRD		;COUNT DRUM READS FOR STATISTICS
	MOVSI 1,0(1)
	HRRI 1,SWPRT		;RETURN APPROPRIATE SCHED TEST
	RET

SWPIK:	TLNE 4,NEWFB		;NEWLY ASSIGNED PAGE?
	JRST [	CALL SWPZPG	;YES, ZERO IT
		MOVSI 2,NEWFB
		ANDCAM 2,CST1(1)
		MOVSI 2,(2B5+CORMB)
		HLLM 2,CST0(1)	;SET TO READ COMPLETED AND MODIFIED
		JRST .+2]
	CALL DSKIO		;INITIATE DISK READ
	AOS DSKRD		;COUNT DISK READS FOR STATISTICS
	MOVSI 1,0(1)		;RETURN APPROPRIATE SCHED TEST
	HRRI 1,DSKRT
	RET

DEPG:	MOVE 4,CST2(3)		;GET LOCATION OF PT OWNING OLD CONTENTS
	JUMPE 4,R		;0 => WAS NONE
	MOVE 5,CST1(3)		;GET BACKUP ADDRESS
	TLNE 4,-1		;PT OR SPT
	JRST SWPI1		;PT
	DPB 5,[POINT 22,SPT(4),35]	;SPT, RESTORE BACKUP ADDRESS
	MOVSI 6,-1B31
	CAIGE 4,NOFN		;FILE XB?
	TDNE 6,SPT(4)		;WITH SHARE COUNT NOW 0?
	RET			;NO
	SETOM SPTH(4)		;DELETE OFN
	SOS NOF
	RET

SWPI1:	HLRZ 6,4
	CALL SETSPG		;MAP PT
	MOVE 2,CST0(6)		; GET PUB
	TLO 2,(CORMB)		; BE SURE CORMB IS SET
	DPB 5,[POINT 22,CSWPGA(4),35]	;STORE BACKUP ADDRESS
	MOVEM 2,CST0(6)		; RESTORE PUB
	MOVSI 2,-PLKV
	ADDB 2,CST1(6)		;DECREMENT LOCK COUNT
	CALL RELSPG		;RELEASE TEMPORARY MAP WORD
	RET

SETSPG:	PUSH P,1
	MOVE 1,SPT(6)		;GET ADDRESS
	TDNE 1,[XWD 17,-MAXCOR]
	BUG(HLT,<SWPIN - PAGE TABLE NOT IN CORE>)
	HLL 1,CST0(1)		;CHECK AGE
	TLNN 1,(7B2)		;NOW ASSIGNED?
	CALL AGESN		;NO, SET AGE
	LSH 6,^D9		;MAKE SHARE POINTER FROM OFN IN 6
	TLO 6,RWXB-XCTB+SHRBIT
	MOVEM 6,MMAP+CSWPG	;PUT IN PAGE RESERVED FOR SWAPPER
	MOVEI 6,0(1)		;RETURN CORE ADR
	POP P,1
	RET

RELSPG:	SETZM MMAP+CSWPG	;CLEAR MAP WORD
	MONCLR CSWPG		;CLEAR MON AR'S
	RET

;ZERO CORE PAGE GIVEN IN 1

SWPZPG:	MOVEI 2,0(1)
	TLO 2,RWXB		;CONSTRUCT PRIVATE POINTER TO PAGE
	MOVEM 2,MMAP+CSWPG	;PUT IN MON MAP
	MOVSI 3,400000		;GET LEGAL AGE
	EXCH 3,CST0(1)		;SAVE OLD AGE
	MOVE 2,[XWD CSWPGA,CSWPGA+1]
	SETZM -1(2)
	BLT 2,CSWPGA+777	;ZERO THE PAGE
	TLO 3,(CORMB)		;NOTE PAGE WRITTEN INTO
	MOVEM 3,CST0(1)		;RESTORE AGE
	JRST RELSPG		;CLEAR PAGE FROM MMAP AND RETURN

;SCHEDULER TEST FOR PSB AND PT READ COMPLETED

SWPINT:	MOVE 3,4		;SAVE RETURN
	HRRZ 1,FKPGS(7)		;PSB
	MOVE 1,SPT(1)		;ASSIGNED PAGE
	JSP 4,PTRT		;DONE?
	JRST 0(3)		;NO, RETURN NOT RUNNABLE
	CALL SETMAP		;SET AGE AND MAP PSB IF NECESSARY
	SKIPN INDFLG		;LOCKING PSB'S?
	JRST SWPIT1		;NO
	HRRZ 1,FKJOB(7)		;YES, GET SPT
	MOVE 1,SPT(1)		;CORE ADDRESS
	JSP 4,PTRT		;CHECK IT
	JRST 0(3)		;NOT READY
	CALL AGESN
SWPIT1:	HLRZ 1,FKPGS(7)		;PT
	MOVE 1,SPT(1)
	JSP 4,PTRT		;PT READY?
	JRST 0(3)		;NO
	CALL AGESN
	JRST 1(3)

;SCHEDULER TEST FOR READ COMPLETED

DSKRT:	JFCL			;SAME AS SWPRT
SWPRT:	MOVE 2,CST0(1)		;PAGE STATE CODE
SWPRT2:	TLC 2,(06B5)		;COMPARE WITH READ-IN-PROG CODE
	TLNN 2,(77B5)
	JRST 0(4)		;READ STILL IN PROG
	JRST 1(4)

;TEST FOR PAGE TABLE ARRIVAL
PTRT:	MOVE 2,CST0(1)
	TLNE 2,700000		;AGE GE 100?
	 JRST 2(4)		;YES
	JRST SWPRT2		;NO, SEE IF READ COMPLETED

;SET AGE AND SET PSB MAP ENTRY IF NEW FORK
SETMAP:	CALL AGESN		;SET AGE
	MOVSI 4,NEWFKF##	;NEW FORK?
	TDNN 4,FKINT##(7)
	 RET			;NO
	HRRZ 4,FKPGS(7)
	LSH 4,^D9
	TLO 4,RWXB+SHRBIT	;MAKE SHARE POINTER TO PSB
	MOVEM 4,MMAP+FITPG	;PUT IN PPR MAP
	MONCLR FITPG
	MOVEM 4,FITPGA+PSBPG	;IN PSB
	RET

;SWAP COMPLETION ROUTINE, CALLED FROM DRUM AND DISK INTERRUPT CODE

SWPDON:	MOVSI 2,DWRBIT		;WRITE BIT
	TDNE 2,CST3(1)		;WAS WRITE?
	JRST SWPD1		;YES
;IF RESCHEDULING DESIRED ON PAGE ARRIVAL, INCLUDE THE FOLLOWING:
;	AOS PSKED
;	ISB SCDCHN

	MOVSI 2,4B23
SWPD2:	ANDCAM 2,CST0(1)	;CLEAR I/O IN PROGRESS
	JRST 0(4)

SWPD1:	ANDCAM 2,CST3(1)	;CLEAR WRITE BIT
	LDB 2,[POINT 6,CST0(1),5]	;GET TRAP CODE
	CAIE 2,4		;STILL SAYS WRITE?
	JRST [	SKIPE CST2(1)	;NO, PAGE USED AGAIN.  STILL EXISTS?
		JRST 0(4)	;YES
		JRST ONRQ]	;IT WAS DELETED, PUT ON RPLQ
	SOS IOIP		;WRITE NO LONGER IN PROGRESS
	MOVE 2,CST1(1)		;IF WRITE WAS TO DISK, AND PAGE
	HLR 2,CST2(1)		;IS STILL IN SPT
	TLNE 2,10
	TRNE 2,-1
	JRST ONRQ
	MOVEI 2,7777		;FAKE A REFERENCE IN ORDER TO
	HRLZM 2,CST3(1)		;KEEP THE PAGE ON THE DRUM
	DPB 2,[POINT 9,CST0(1),8]
	JRST 0(4)

ONRQ:	MOVEI 2,CST3(1)		;YES, PUT ON REPLACABLE QUEUE
	PIOFF
	HLRZ 3,RPLQ		;NOTE: THERE IS A "COPY" OF THIS
	HRL 3,0(3)		;CODE IN-LINE IN MAKPGA. IF ANY
	HRRM 2,0(3)		;CHANGE IS MADE HERE, BE SURE TO
	MOVSM 3,0(2)		;CHECK TO SEE IF THE SAME CHANGE IS
	HRLM 2,RPLQ		;APPROPRIATE IN MAKPGA ALSO.
	PION
	AOS NRPLQ
	SOS SUMNRX
	SOS PNDING
	MOVSI 2,77B23
	JRST SWPD2


;SWAP OUT PAGE REQUESTED BY PROCESS

SWPOT0:	TLNE 1,17		;IN CORE?
	RET			;NO
	PUSH P,2
	PUSH P,7
	MOVE 7,FORKX
	MOVE 2,CST0(1)
	TLNN 2,(7B2)		;IN USE?
	JRST SWPOT1		;NO
	HLRZ 2,CST3(1)		;ASSIGNMENT
	ANDI 2,7777
	CAIE 2,0(7)		;ASSIGNED HERE?
	JRST SWPOT1		;NO
	SOS FKWSP(2)
	SOS FKNR(2)
	AOS PNDING
	MOVSI 2,7777
	IORM 2,CST3(1)		;DEASSIGN IT
	MOVE 2,CST1(1)
	TLNE 2,-PLKV		;LOCKED?
	 JRST SWPOT1		;YES, DONT TRY TO SWAP
	MOVSI 2,DWRBIT
	TDNE 2,CST3(1)		;BEING WRITTEN?
	JRST SWPOT1		;YES
	PUSH P,3
	PUSH P,4
	PUSH P,5
	CALL SWPOUT
	POP P,5
	POP P,4
	POP P,3
SWPOT1:	POP P,7
	POP P,2
	RET

;INITIATE SWAP OF PAGE
;CALLED IN SCHEDULER FROM GCCOR

SWPOUT:	SKIPN 2,CST2(1)		;GET BACKUP
	JRST BKUPN		;PAGE HAS NO BACKUP, FLUSH IT
	TLNE 2,-1		;SPT?
	JRST SWPU1		;NO
	MOVE 3,SPT(2)
	TLNN 3,-1B31		;SHARE COUNT 0?
	JRST BKUPD		;YES, SWAP TO DISK
	CAIL 2,NOFN		;OFN?
	JRST BKUPS		;NO, SHARED PAGE. GO CHECK REQUEST BIT
	MOVE 2,CST1(1)		;YES, CHECK BACKUP ADDRESS
	TLNN 2,10		;DISK?
	JRST BKUP0		;NO, DRUM ADR ALREADY ASSIGNED
	SKIPL DRUMP		;YES, MUST ENSURE SWAP TO DRUM
	SKIPG DRMFRE
	JRST SWPO3		;OR LEAVE IN CORE IF CAN'T
	JRST SWOFN		;GO ASN DRM ADR, EVEN IF DRM SPC LOW

BKUP0:	MOVE 2,CST1(1)		;CORE PAGE NUMBER IN 1, GET BACKUP ADR
	TLNE 2,16
	TLNE 2,10		;DISK OR NOTHING?
	JRST SWPO4		;YES
	TLZE 2,1		;NEWLY ASSIGNED DRUM ADDRESS? (POSTPG)
	JRST [	MOVEM 2,CST1(1)	;YES, REMOVE NEW BIT
		JRST SWPP1]	;AND WRITE OUT PAGE
	MOVE 3,CST0(1)		;NO, DRUM.
	TLNE 3,(CORMB)		;PAGE WRITTEN INTO?
	JRST SWPO1		;YES
SWPOQ:	TLNE 3,77B23		;PAGE NOW ON REPLACABLE QUEUE?
	JSP 4,ONRQ		;NO, PUT IT THERE
SWPO3:	RET

SWPU1:	HLRZ 2,2		;GET PTN
	CAIGE 2,NOFN		;FILE?
	JRST BKUPD		;YES, SWAP TO DISK
BKUPS:	MOVE 2,CST3(1)
	TLNE 2,DSKSWB		;SWAP TO DISK REQUESTED?
	JRST BKUPDR		;YES
	JRST BKUP0		;PROCESS, SWAP TO DRUM

SWPO1:	CALL GDSTX
SWPO5:	MOVSI 3,BWRBIT		;SET BACKUP WRITTEN BIT
	IORM 3,DST(2)
SWPO2:	MOVSI 3,(CORMB)
	ANDCAM 3,CST0(1)	;CLEAR WRITTEN BIT
	MOVEI 3,4
	DPB 3,[POINT 6,CST0(1),5]	;SET TRAP CODE TO WRITE IN PROG.
	AOS IOIP		;NOTE WRITE IN PROGRESS
	HRLI 1,DWRBIT		;WRITE REQUEST BIT
	CALL DRMIO		;INITIATE DRUM WRITE
	AOS DRMWR		;COUNT DRUM WRITES FOR STATISTICS
	JRST SWPO3

SWPO4:	MOVSI 3,SWPERR
	TDNE 3,CST3(1)		;ERROR READING FROM DISK?
	JRST BKUPN		;YES, DON'T WRITE IT
	MOVE 3,DRMFRE
	SKIPLE DISKP		;IF NO DISK, DON'T MAKE ADD'L SWAP ADRS
	CAMGE 3,DRMIN2		;DRUM NEARLY FULL?
	TLNN 2,10		;YES, SEND TO DISK IF HAVE DISK ADDRESS
	SKIPGE DRUMP		;SWAPPING POSSIBLE?
	JRST [	TLNE 2,10	;NO, DID WE HAVE A DISK ADDRESS?
		JRST BKUPD	;YES, SEND TO DISK (WHATEVER IT IS)
		JRST SWPO3]	;NO PLACE TO PUT PAGE, LEAVE IT IN CORE
SWOFN:	PUSH P,1
	SETO 1,			;FREE CHOICE ASSMT
	CALL DRMASN		;ASSIGN DRUM ADDRESS
	BUG(HLT,<DRUM COMPLETELY FULL>)
	MOVE 2,1
	POP P,1
	MOVE 4,CST1(1)		;GET PREVIOUS BACKUP ADDRESS
	MOVEM 2,CST1(1)		;SET DRUM AS NEW BACKUP ADDRESS
	CALL GDSTX
	MOVEM 4,DST(2)		;PREVIOUS BACKUP ADDRESS TO DST
SWPP1:	MOVE 3,CST0(1)
	TLNE 3,(CORMB)		;PAGE WRITTEN WHILE IN CORE?
	JRST SWPO5		;YES, SET BACKUP WRITTEN BIT ALSO
	JRST SWPO2		;NO

;SWAP PAGE TO DISK

BKUPD:	MOVSI 2,DSKSWB
	ANDCAM 2,CST3(1)	;FLUSH REQUEST BIT IF ANY
BKUPDR:	MOVE 2,CST1(1)		;GET BACKUP ADDRESS
	TLNN 2,16		;NONE?
	JRST BKUP7		;YES
	TLNE 2,10		;DISK?
	JRST BKUP3		;YES
	CALL GDSTX		;DRUM
	MOVE 3,DST(2)		;GET NEXT LEVEL BACKUP ADDRESS
	MOVSI 4,(CORMB)
	TLZE 3,BWRBIT		;WRITTEN SINCE BACKUP?
	IORM 4,CST0(1)		;YES, SET CORE WRITTEN BIT
	SETOM DST(2)		;RELEASE DST SLOT
	EXCH 3,CST1(1)
	PUSH P,1
	MOVE 1,3
	CALL DASDRM		;DEASSIGN DRUM ADDRESS
	POP P,1
	JRST BKUPDR

BKUP7:	BUG(HLT,<BKUPD - BAD CST1 ENTRY OR INCONSISTENT CST>)

BKUP3:	MOVSI 3,(CORMB)		;CLEAR CHANGED IN CORE BIT
	MOVSI 2,SWPERR
	TDNN 2,CST3(1)		;DON'T WRITE IF ERROR FROM READ
	TDNN 3,CST0(1)		;CHANGED?
	JRST BKUPN		;NO, DON'T HAVE TO WRITE
	ANDCAM 3,CST0(1)
	HRLI 1,DWRBIT		;REQUEST WRITE
	AOS DSKWR		;COUNT IT FOR STATISTICS
	AOS IOIP		;NOTE WRITE IN PROGRESS
	MOVSI 3,NEWFB
	ANDCAM 3,CST1(1)	;MAKE SURE NO NEWFB STILL AROUND
	MOVEI 3,4		;INDICATE WRITE IN PROGRESS
	DPB 3,[POINT 6,CST0(1),5]
	CALL DSKIO
	JRST SWPO3

BKUPN:	MOVE 3,CST0(1)
	JRST SWPOQ		;GO PUT PAGE IN QUEUE

; PUT PAGES IN AVAILABLE POOL OF SWAPPING PAGES
; CALL:	1/	FIRST PAGE TO PUT IN
;	2/	LAST PAGE TO PUT IN
;	CALL MAKPGA
; RETURNS +1 ALWAYS
; ARGUMENTS ARE FORCED INTO PROPER RANGE

MAKPGA:	CALL CHKPGA		; CHECK PAGE ARGUMENTS
	PUSH P,2		; SAVE AC'S
	PUSH P,3
	PUSH P,4
	CONI PI,2		; GET CURRENT STATE OF PI
	PUSH P,2		; AND SAVE IT
	PIOFF			; PREVENT CHAOS
MKPGAL:	LDB 2,[POINT 6,CST0(1),5]
				; GET STATE OF THE PAGE
	CAIE 2,01		; IS IT UN AVAILABLE?
	 JRST MAKPGX		; NO, NOTHING TO DO
	SETOM CST0(1)		; SET AGE > 77
	SETZM CST1(1)		; CLEAR CST WORDS
	SETZM CST2(1)
	SETZM CST3(1)
	MOVE 2,1
	HRLI 2,RWXB
	MOVEM 2,MMAP+CSWPG	; SET POINTER TO THE PAGE
	PGRCLD			; RELOAD PAGER
	SKIP CSWPGA		; REFERENCE THE PAGE
	MOVSI 2,010000
	MOVEM 2,CST0(1)		; SET AGE BACK TO UNAVAIL IN CASE NXM
	CONSZ APR,APNXM		; EXISTS?
	 JRST MAKPGX		; NO
	CAMGE 1,SWPCOR
	 MOVEM 1,SWPCOR		; KEEP MIN AVAILABLE AS SWPCOR
	CAML 1,NHIPG		;NEWLY AVAILABLE?
	 MOVEM 1,NHIPG		;YES. UPDATE LENGTH OF SCANS
	SETZM CST0(1)
	MOVEI 2,CST3(1)		;WE WILL NOW PUT ON REPLACEABLE QUEUE
	HLRZ 3,RPLQ		;NOTE: THIS CODE IS A "COPY" OF THE
	HRL 3,0(3)		;CODE IN THE ROUTINE "ONRQ". IF ANY
	HRRM 2,0(3)		;CHANGE IS MADE HERE, BE SURE TO
	MOVSM 3,0(2)		;CHECK TO SEE IF THE CHANGE IS
	HRLM 2,RPLQ		;APPROPRIATE IN THE "ONRQ" ROUTINE ALSO.
	AOS NRPLQ
	AOS TOTRC		;UPDATE COUNT OF AVAILABLE CORE PAGES
	AOS MAXNRX
MAKPGX:	CONO APR,APNXM+APRCHN		; CLEAR NXM FLAG
	CAMGE 1,-3(P)		; REACHED END YET?
	 AOJA 1,MKPGAL		; NO DO NEXT ONE
	SETZM MMAP+CSWPG	; CLEAR MAP ENTRY
	PGRCLD
	CALL FIXRC		; RECOMPUTE VARIABLES DEPENDENT ON TOTRC
	POP P,2			; GET FORMER STATE OF PI
	TRNE 2,200		; WAS IT ON?
	 PION			; YES, TURN IT BACK ON
	POP P,4			;RESTORE REGISTERS
	POP P,3
	POP P,2
	RET

CHKPGA:	CAMGE 2,1		; CHECK THAT SECOND ARG IS .GE. FIRST
	 EXCH 1,2		; IF NOT, REVERSE
	CAIL 2,MAXCOR		; LIMIT TO TABLE SIZES
	 MOVEI 2,MAXCOR-1
	CAMGE 1,MONCOR		; AND NEVER INTO RES MON
	 MOVE 1,MONCOR
	CAMGE 2,1		; BE SURE ARGS STILL OK
	 JRST CHKPGA
	RET

;REMOVE A SET OF PAGES FROM THE SWAPPABLE STORE
;ACCEPTS IN 	1: PAGE NUMBER OF FIRST PAGE TO BE REMOVED
;		2: PAGE NUMBER OF LAST PAGE TO BE REMOVED
;	CALL MAKPGU
; RETURNS
;	+1	; SOME PAGES LOCKED, RH(1) #LOCKED, LH(1) ONE OF THEM
;	+2	; SUCCESS

MAKPGU:	CALL CHKPGA		; CHECK ARGUMENTS
	SUBI 2,-1(1)		; NUMBER OF PAGES
	MOVNS 2
	HRL 1,2
	SETZM PGELCT		; NO LOCKED PAGES FOUND YET
	MOVEM 1,FSHBAL		; CAUSE SCHEDULER TO FLUSH BALSET ETC.
	MOVEI 1,FSHBAL
	CALL DISGE		; WAIT FOR PAGES TO BE FLUSHED
	SKIPN 1,PGELCT		; ANY LOCKED PAGES FOUND
	AOS 0(P)		; NO, SUCCESS RETURN
	RET

; FLUSH ALL PAGES FROM CORE (USED FOR TAKING PAGES OUT OF CIRCULATION)

GCALC:	PUSH P,NRPLQ		; SAVE CURRENT VALUE OF NRPLQ
	CALL GCCOR0		; DEPG AS MUCH AS POSSIBLE THEN GC
	POP P,1
	SKIPN IOIP
	CAME 1,NRPLQ
	 JRST GCALC		; LOOP UNTIL NO CHANGE IN NRPLQ AND NO IOIP
	CALL GCCOR0		; ONCE MORE FOR LUCK
	MOVE 3,FSHBAL		; GET AOBJN POINTER TO PAGES TO FLUSH
	JUMPG 3,GCALX		;DON'T RELEASE CORE
GCFSH:	LDB 1,[POINT 6,CST0(3),5]
	JUMPN 1,[		; NOT ON REPLACEABLE QUEUE
		CAIN 1,01	; ALREADY UNAVAILABLE?
		 JRST GCEFSH	; YES, OK
		SKIPN PGELCT	; NO, MUST BE LOCKED. FIRST LOCKED PAGE?
		 HRLM 3,PGELCT	; YES, SAVE PAGE NUMBER
		AOS PGELCT
		JRST GCEFSH]
	MOVE 4,CST3(3)		; TAKE OFF RPLQ
	HLLM 4,0(4)
	MOVSS 4
	HLRM 4,0(4)
	SOS NRPLQ		; ACCOUNT FOR THIS STOLEN PAGE
	SOS TOTRC		; ADJUST REAL CORE COUNT
	SOS MAXNRX		; AND MAXNRX
	SETZM CST1(3)		; CLEAR CST
	SETZM CST2(3)
	SETZM CST3(3)
	MOVSI 4,(1B5)
	MOVEM 4,CST0(3)
	HRRZ 1,3
	CAMN 1,NHIPG		;FLUSHING TOP PAGE?
	 JRST [	SOS 1,NHIPG	;YES, STEP TOP DOWN ONE
		LDB 1,[POINT 6,CST0(1),5]
		CAIE 1,01	;AVAILABLE?
		JRST GCEFSH	;NO, QUIT
		JRST .]		;YES. TRY AGAIN
	CAMN 1,SWPCOR		; EQUAL TO SWPCOR?
	 JRST [	AOS 1,SWPCOR	; YES, BUMP SWPCOR
		LDB 1,[POINT 6,CST0(1),5]
		CAIN 1,01	; NEXT ONE UNAVAILABLE?
		 JRST .		; YES, BUMP AGAIN
		JRST .+1]	; ELSE CONTINUE
GCEFSH:	AOBJN 3,GCFSH
	CALL FIXRC		; FIX VARIABLES DEPENDENT ON TOTRC

;RESET ALL FKNR TO AVOID LOCKUP DUE TO POSSIBILITY OF FKNR .GT. MAXNRX
	MOVSI 3,-NFKS
GCEFLP:	HRRZ 4,FKWSP(3)		; GET CURRENT NO. OF PAGES (SHOULD BE 0)
	SKIPN 4			; UNLESS HE'S GOT SOME LOCKED
	MOVEI 4,6		; TWAS ZERO, MAKE IT 6
	HRRM 4,FKNR(3)
	AOBJN 3,GCEFLP		; GO 'ROUND AGAIN

	SETOM OLDSUM##		; MAKE SURE WE SCAN FOR LOADABLE PROCS

GCALX:	SETZM FSHBAL		;SAY FLUSH IS COMPLETED

	RET

; FIX RC VARIABLES

FIXRC:	PUSH P,1
;SETUP VARIOUS CONSTANTS FOR CORE MGT

	MOVE 1,TOTRC
	SUB 1,NRPMX
	MOVEM 1,MAXNRX		;MAX VALUE OF SUMNRX
	SUBI 1,10
	MOVEM 1,NPMAX
	CAIL 1,140		;REASONABLY LARGE SYSTEM?
	SUBI 1,40		;YES, SET SNPMAX 16K SMALLER
	MOVEM 1,SNPMAX		;SMALL NPMAX
	SUB 1,NPMAX		;DIFFERENCE OF NPMAX AND SNPMAX
	MOVMM 1,SJSIZ		;FOR 'SMALL' JOB SIZE
	MOVE 1,TOTRC
	SUBI 1,20		;20 IS ARB. LEAVE A LITTLE ROOM FOR SYS.
	MOVEM 1,MAXLOK		;IS MAX NUMBER PAGES TO LOCK
	POP P,1
	RET

;LOCK, UNLOCK PAGE ON REQUEST (FOR DTA IO, ETC.)

MLKMA:	TLNN 1,(1B0)		;LOCK PAGE GIVEN ADDRESS. USER?
	SKIPA 0(1)		;NO, MON. REF PAGE TO ENSURE EXISTS
	XCTUU [SKIP 0(1)]
	CALL FPTA		;TRANSLATE ADDRESS TO OFN.PN
MLKPG:	PUSH P,2
	PUSH P,1
MLKPG0:	CALL GETONT		;GET PTN.PN OR OWNING PT
	TLNN 2,17		;PAGE NOW IN CORE?
	JRST MLKPG1		;YES.
	TLNN 2,16		;NO, EXISTS?
	JRST MLKPG2		;NO
	CALL SWPINP		;INITIATE SWAP AND WAIT FOR COMPL.
	OKSKED
	MOVE 1,0(P)
	JRST MLKPG0		;TRY AGAIN

MLKPG2:	OKSKED			;MUST REF PAGE TO CREATE IT
	TLNE 2,-1		;IN SPT?
	BUG(HLT,<MLKPG: NONX PAGE NOT IN SPT>)
	CALL SETCPT
	SKIP CPTPGA
	CALL RELCPT
	MOVE 1,0(P)
	JRST MLKPG0

MLKPG1:	POP P,1			; FLUSH SAVED AC1
	MOVE 1,CST1(2)
	TLNN 1,-PLKV		;PAGE LOCKED NOW?
	AOS LOKPGS		;NO, COUNT IT
IFN KIFLG,<
	AOS KIMLKF>
	MOVSI 1,PLKV
	ADDM 1,CST1(2)		;INCREMENT LOCK COUNT
	AOS LOKSUM
	MOVEI 1,0(2)
	CALL AGESET		;SET AGE
	MONCLR 0
	POP P,2
	JRST SKORET		;OKSKED AND RETURN

MULKPG:	PUSH P,1
	PUSH P,2
	CALL GETONT		;GET OWNING PT
	TLNE 2,17		;PAGE NOW IN CORE?
	BUG(HLT,<MULKPG - TRIED TO UNLOCK PAGE NOT LOCKED>)
	CALL MULK1
	POP P,2
	POP P,1
	JRST SKORET

MULK1:	MOVSI 1,-PLKV
	TDNN 1,CST1(2)		;LOCK COUNT NON-ZERO?
	BUG(HLT,<TRIED TO UNLOCK PAGE NOT LOCKED>)
	ADDB 1,CST1(2)		;DECREMENT LOCK COUNT
	TLNE 1,-PLKV		;NOW UNLOCKED?
	JRST MULK2		;NO
	SOS LOKPGS
IFN KIFLG,<
	AOS KIMLKF>		;FLAG THAT LOCKING HAS CHANGED
	SKIPE CST2(2)		;STILL EXISTS?
	JRST MULK2		;YES
	PUSH P,4		;NO, HAS BEEN DELETED
	MOVEI 1,0(2)
	JSP 4,ONRQ		;PUT ON REPLACABLE QUEUE
	POP P,4
MULK2:	SOS LOKSUM
	RET

;UNLOCK PAGE GIVEN MONITOR ADDRESS
;ASSUMED NOSKED OR INSKED

MULKMP:	MOVEI 1,0(1)
	LSH 1,-^D9
	CAIL 1,PPRMPG+NRSPG
	CAIL 1,PPMPG
	BUG(HLT,<MULKMP - ILLEGAL MONITOR ADDRESS>)
	MOVE 1,MMAP(1)		;GET CORE ADDRESS
	TLZ 1,-1B31		;FLUSH POINTER BITS
	JRST MULKCR

;UNLOCK PAGE GIVEN CORE PAGE NUMBER IN 1

MULKCR:	CAML 1,SWPCOR		;LEGAL?
	CAIL 1,MAXCOR
	BUG(HLT,<MULKCR - ILLEGAL CORE PAGE NUMBER>)
	PUSH P,2
	MOVEI 2,0(1)
	CALL MULK1
	POP P,2
	RET


	END			;END OF PAGEM.MAC
