;DSK:<FOONEX>PAGEM.PEF;19  8-Jul-80 20:47:15, Edit by FRENCH
;FIX CLEARING OF XBBAT AT ASCHK1
;DSK:<FOONEX>PAGEM.PEF;16  8-Jul-80 14:33:32, Edit by FRENCH
;MINOR BUG FIXES IN SWPFIX (TYPOS)
;DSK:<FOONEX>PAGEM.PEF;9  2-Jul-80 12:23:30, Edit by FRENCH
;ASOFN RETURNS OPNX24 ON SCANNING READ OF XB IF ITS A BAD SPOT (SWAP ERROR)
;DSK:<FOONEX>PAGEM.PEF;7  1-Jul-80 14:23:15, Edit by FRENCH
;FIX TEST OF FROM DISK OR DRUM IN SWPFIX
;DSK:<FOONEX>PAGEM.PEF;6 25-Jun-80 16:54:08, Edit by FRENCH
;FOR SWAP READ ERROR: IF CORE BACKUP DIFF FROM DRUM BACKUP (BWRBIT),
;MAKE DRUM BACKUP THE CORE BACKUP ANYWAY BUT ISSUE INT INSTEAD OF REDOING IO.
;DSK:<PEFMON>PAGEM.MAC;29 24-Jun-80 18:20:24, Edit by FRENCH
;MUCH SMARTNESS FOR DRUM SWAP IN ERRORS - POSSIBLE WINNING RETRIES
;ALLOW FREE CHOICE FOR DRMASN AT SWOFN (BUG: WAS USING CPN)
;DSK:<PEFMON>PAGEM.MAC;19 24-Jun-80 12:57:53, Edit by FRENCH
;ADDED DRUM ADR SWITCHING ON SWAP ERRORS FOR BAT LOGIC
;ADD FLAG PASSING TO REMFPG FOR NON-RELEASE OF BAD FILE PAGES
;REMFPG WILL NOT DEASSIGN DISK ADRS IF HANDED OFNBAT FLAG IN AC2
;XFER BAT BIT FROM XB TO SPTH FOR OFN BEFORE ASCHK1
;XFER BAT BIT FROM SPTH TO COPY OF XB TO BE DUMPED AT DDMPXB
;DSK:<PEFMON>PAGEM.MAC;3 20-Jun-80 16:51:08, Edit by FRENCH
;ADDED SWPFIX TO HANDLE SWAPPING ERRORS
;DSK:<134-TENEX>PAGEM.MAC;267 18-May-80 21:32:51, Edit by PETERS
; Removed TOPS20 AC definitions which are now in PROLOG
;<134-TENEX>PAGEM.MAC;266    27-Jan-80 17:45:09    EDIT BY PETERS
; Fix KAFLG to be KAFLG!F3FLG
;<134-TENEX>PAGEM.MAC;265    19-Nov-79 16:16:31    EDIT BY PETERS
;Add support for sysmem getab to make memory configuration available
;<134-TENEX>PAGEM.MAC;264    16-Sep-79 18:46:04    EDIT BY PETERS
;added isi, ki, and tymshare changes
;[SRI-KA]<134-TENEX>PAGEM.OLD;29, 11-Jun-79 09:30:43, EDIT BY LYNCH
; TOOK OUT OKSKED/NOSKED BUG IN ASOFN.
;<134-TENEX>PAGEM.MAC;28    31-Dec-77 22:30:06    EDIT BY LYNCH
; DID CLEANUP AND PUT IN CALL TO AGESET IN RELOFN
;<134-TENEX>PAGEM.DCL;27    19-Dec-77 04:10:00	  TVEDIT BY HEATHMAN
;1 Edit #1 - Fix DDMP4+7 to keep 160041,,0 pointers out of file system
;<134-TENEX>PAGEM.DCL;26    16-Dec-77 19:57:10    EDIT BY LYNCH
; REFINE NGCC TO KICK OUT NON BALSET PAGES ON TAIL OF CURVE
;<134-TENEX>PAGEM.DCL;25     9-Dec-77 23:01:15    EDIT BY SYSTEM
; ADD ANOTHER CHECK AT NIC8 FOR RPLQ DEPLETION
;<134-TENEX>PAGEM.MAC;24    18-Nov-77 21:22:37    EDIT BY LYNCH
; FIXED UGLY BUG IN NIC CODE -- FORGOT TO GO NOSKED!
;<134-TENEX>PAGEM.DCL;23    16-Nov-77 19:19:49    EDIT BY LYNCH
; FIXED BUG IN NGCC START POINT AT SWPCOR IN GCEFSH CODE.
;<134-TENEX>PAGEM.DCL;22    14-Nov-77 08:47:11    EDIT BY LYNCH
; FIXED THE "EVERYBODY OUT OF THE POOL" LOGIC.
; A COMMENT IN THE MAKPGU ROUTINE ABOUT ONCE MORE FOR LUCK
; IS VERY, VERY DECEPTIVE!!!
;<134-TENEX>PAGEM.DCL;20    13-Nov-77 12:03:16    EDIT BY LYNCH
; FIXED BUG IN AGE CODE INTERPRETATION BETWEEN KA AND KL
; FOR THE NGCC CODE!
;<134-TENEX>PAGEM.MAC;19    10-Oct-77 16:20:42    EDIT BY LYNCH
; PUT IN NEW GARBAGE COLLECTOR CODE (NGCC)
;<134-TENEX>PAGEM.MAC;10    21-Dec-76 15:48:36    EDIT BY LYNCH
; PUT BACK IN THE 5 MS QUANTUM DECREMENT AT PGIWT.
; THE EFFECT OF THIS IS TO PULL OFF PAGE GOBBLERS FROM
; THE INTERACTIVE QUEUE QUICKLY.
;<134-TENEX>PAGEM.MAC;9     1-JUL-76 21:20:28    EDIT BY UNTULIS
;ADDED JSYS TO FIND DRUM PAGES PER FORK (.GPGC - GET PAGE COUNT)
;<134-TENEX>PAGEM.MAC;8    21-APR-76 13:38:16    EDIT BY LYNCH
; TOOK OUT FKIFAV SAVING.  OBSOLETE
;<134-TENEX>PAGEM.MAC;7     5-APR-76 14:40:09    EDIT BY UNTULIS
;ADD ISI SECURITY HOLE PLUG
;<134-TENEX>PAGEM.MAC;2    17-FEB-76 15:52:48    EDIT BY UNTULIS
;ADDED RECLAIM DRUM CODE
;<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
;<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,.RWSET
	INTERN SWPINT
	INTERN SWPDON,DWRBIT,SWPERR
	INTERN DSKRT,GCALC,PGRRST,PGRTRP,SWPIN0,ASSPT,DESPT
	INTERN SWPRT,SETPPG,SWPRST,PGRINI
	INTERN MKSHRP,SETDVP

;LINKAGE TO PISRV AND SCHED

EXTERN BHC,BITS,BLOCK1,BUGCHK,BUGHLT,DEVMPE,PSISV2
EXTERN DISGE,DISLT,DRMRD,DRMWR,DSKRD,DSKWR,ETIME,FKJOB
EXTERN BKGFLG,EDISMS,DISL
EXTERN FKPGS,FKPT,FKWSP,FORKX,FSHBAL,ILIST
EXTERN INSKED,ISKED,ITRAP,JOBNAM,LSTERR,MENTR
EXTERN MRETN,MSTKOV,NPMAX,NRPLQ,NRPMIN,JOBRTT
EXTERN PATCH2,PSIRQ,PSIRQ0,PSKED,R,RJQNT,RPLQ,RSKP,TOPTRP
EXTERN SCHEDP,SCHEDR,SJSIZ,GCCR,SPFLTS,PTRAP,STIME
EXTERN TODCLK,TOTRC,WTLST,WTSPT,WTSPTT
EXTERN FKFLGS,BLST

EXTERN SNSOFN

extern bugmsg,bugtyo,jobpgf

IFN KIFLG,<	;[ISI] Possible linkage to KISRV
EXTERN	KILUPT
EXTERN	KIMAC1,KIMAC2,KIMLKF,KIPGWD,KIRFLG,KXUPT
>

; 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,OPNX24

;PARAMETERS

DISKP:	1		;DISK ON SYSTEM
DRUMP:	IFDEF DRMCHN,<1>	;1 = DRUM AVAIL,
	IFNDEF DRMCHN,<0>	;0 = USE DISK, -1 = USE NOTHING
;		FOLLOWING USED TO CONTROL NGCC CORE GARBAGE COLLECTOR
LS FKPAGE,NFKS		; CUTOFF AGE FOR NGCC
LS GCBALB		; BALSET BIAS FOR THROWING OUT PAGES
LS GCPN			; ROVING POINTER TO LAST PAGE LOOKED AT
LS GCMOD		; SCALE FOR CHKRPQ TEST
LS AGEGLB		; GLOBAL AGE COUNTER 
LS GCSTRT		; FIRE UP NGCC WHEN NRPLQ FALLS BELOW THIS
LS GCDIFF		; COLLECT AT LEAST THIS MANY PAGES FOR RPLQ



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 NXTDMP,1		;FLAG TO CAUSE DDMP ACTION
GS DDTIME,1		;TIME NEXT DDMP DUE
ls ddmpct,1		;flag to aid asofai in recognizing ddmp finish
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 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
;	MOVEI 1,<3*NDST>/^D16	;GET 3/16 OF DRUM SPACE
	MOVEI	1,3200		;ASSIGN PRIVATE PAGES TO DISK BELOW THIS *** SRI-AIC ***
	MOVEM 1,DRMIN2		;NO NEW DRUM ASSIGNMENTS BELOW THIS
	MOVEI	1,3200		;DRUM BARRIER	*** SRI-AIC ***
	MOVEM 1,DRMIN1		;DEASSIGN PAGES TRICKLED TO DISK
				;IF DRMFRE FALLS BELOW THIS
	MOVEI 1,100
	MOVEM 1,AGEGLB
	DPB 1,[POINT 9,PGR72,8]	; INIT AGE FIELD
	MOVEI 1,^D25		; PICK START POINT FOR NGCC
	MOVEM 1,GCSTRT
	MOVEI 1,^D10		; AND NUMBER OF PAGES TO COLLECT EACH TIME
	MOVEM 1,GCDIFF
	MOVEI 1,^D600	; MAX PAGES A FORK COULD EVER HAVE
	IDIV 1,GCSTRT
	MOVEM 1,GCMOD	; SCALE FOR CHKRPQ TEST
	MOVE 1,SWPCOR	; INIT ROBING POINTER FOR NGCC
	MOVEM 1,GCPN

	SETZM PGR71
	CALL PGRRST
	MOVE 1,SWPCOR
ifn kiflg,<
	addi 1,nupt		;reserve for ki upts
>
	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
	movei 1,[sixbit '$pgrini:  /']	;tell oper how much core we have
	jsr bugmsg		;type it
	move 1,totrc		;"user" core
	add 1,swpcor		;plus monitor gives total pages
ifn kiflg,<
	addi 1,nupt		;account for upts if ki
>
	hrli 1,maxcor		;put configuration maximum in left halt
	movsm 1,sysmem##	;leave for getab as online,,maximum
	hrrzs 1			;now clear left half before divide
	idivi 1,2		;convert from pages to k
	idivi 1,^d1000		;get thousands digit
	addi 1,"0"		;make an ascii character
	caie 1,"0"		;skip if thousands not needed
	jsr bugtyo		;type it
	idivi 2,^d100		;get hundreds
	movei 1,"0"(2)		;fetch hundreds and make ascii char
	jsr bugtyo		;type it
	idivi 3,^d10		;get tens and ones digits
	movei 1,"0"(3)		;get tens and make ascii char
	jsr bugtyo		;type it
	movei 1,"0"(4)		;get ones and make ascii char
	jsr bugtyo		;type it
	movei 1,[sixbit 'k physical core online$/']
	jsr bugmsg		;type rest of message
	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 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
	setom 0(p)		;unassigned, force xb write
	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:	MOVSI 1,OFNBAT		;THE SPTH BAT BIT
	MOVSI 2,XBBAT		;THE XB BAT BIT
	TDNE 1,SPTH(10)		;THIS XB BAD?
	 IORM 2,DDPG2A+XBBWRD	;YES-TURN ON BIT IN BAT WORD IN COPY XB
	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
	AOS DDMPCT		;[ISI]
	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)
;note: opnx24 error can only be returned for non-new xb's since
;swpin does not do a disk read for brand new pages.
;therfore, caller need not handle opnx24 if b3 set for new xb in call args

ASOFN:	TLNN 1,10		;DISK?
	RET			;NO, RETURN BAD
	PUSH P,7		;[ISI] Protect AC7
	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
	MOVE 1,CXBPGA		;GET XB IN CORE
	MOVE 1,SPT(3)		;CORE ADDRESS
	MOVSI 2,SWPERR
	TDNE 2,CST3(1)		;DISK ERROR IN XB? (impssbl if brand new xb)
	 JRST ASCHK4		;YES, DON'T OPEN, return bad spot error
	MOVSI 1,XBBAT		;THE XB BAT BIT
	MOVSI 2,OFNBAT		;THE SPTH BAT BIT
	TDNE 1,CXBPGA+XBBWRD	;ON IN XB?
	 IORM 2,SPTH(3)		;YES-REMEMBER IT FOR OFN
	TDNE 1,CXBPGA+XBBWRD	;ON IN XB? DON'T CHANGE IT UNNECESSARILY
	ANDCAM 1,CXBPGA+XBBWRD	;CLEAR IT FROM XB
	MOVSI 1,-1000		;SETUP TO SCAN XB
ASCHK1:	MOVE 2,CXBPGA(1)	;GET WORD FROM XB (XBBAT ALREADY CLEARED OUT)
	JUMPE 2,ASCHK2		;NOT IN USE
	ANDCM 2,[RWX,,-1]	;[ISI] Ignore RWX bits and low addr bits
	TLC 2,ACCESB+01		;[ISI] Flip access & non-exist bits (to zero)
	TLNE 2,10		;[ISI] If disk addr,
	TLZ 2,17		;[ISI]  zero all addr bits
	JUMPN 2,ASCHK3		;[ISI] Any one bits are bad, don't open
ASCHK2:	AOBJN 1,ASCHK1
	CALL RELCXB		;OK, RELEASE XB, IT IS CLEAN FOR MAP USE
	JRST ASOF9

;IF THERE WAS A SWAP ERROR (SWPERR IN CST3) FOR THE XB, DON'T SET
;XBBAT IN XBBWRD SINCE DON'T WANT TO WRITE BACK OVER THE XB.
;INSTEAD RETURN OPNX24 TO CALLER SO CALLER CAN MARK FDB AS BAD FILE.
;FILES WITH ONLY BAD INDEX BLOCKS THEREFORE HAVE JUST FDBBAT ON IN FDB
;BUT NO XBBAT ON IN XBBWRD OF INDEX BLOCK. (AS OPPOSED TO FILES WITH BAD
;FILE PAGES THAT HAVE BOTH FDB AND XB BITS ON).

ASCHK4:	PUSH P,[OPNX24]		;BAD SPOT INDEX BLOCK ERROR
	CAIA
ASCHK3:	PUSH P,[OPNX16]		;BAD LOOKING INDEX BLOCK ERROR
	CALL RELCXB		;FILE NO GOOD, RELEASE XB
	MOVE 1,SPT(3)		;CLEAR OFN AND CORE PAGE
	SETOM SPTH(3)
	SOS NOF
	CALL DECOR		;TRASH ANY CHANGES (LIKE CLEARING OF XBBAT)
	SETZM CST2(1)
	JSP 4,ONRQ
	POP P,1			;ERROR # INTO 1
ASOFNX:	POP P,7			;[ISI]
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
	POP P,7			;[ISI]
	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 ASOFNX		;[ISI]

ASOFW2:	SKIPA 1,2
ASOFW1:	POP P,1
	POP P,7			;[ISI]
	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?
	MOVE 1,FORKX		;[ISI]
	CAMN 1,DDMPFK##		;[ISI]
	 JRST ASOFA1		;[ISI]
	OKSKED
	MOVEI 1,FSHBAL		;POS. NUMBER
	MOVEM 1,FSHBAL		;REQUEST TO GC CORE BUT KEEP ONLINE
	CALL DISE##		;WAIT FOR IT TO HAPPEN
	SETZM DDMPCT
	SETZM NXTDMP
	SETZM DDTIME		;CAUSE DDUMP TO RUN
	AOS JB0FLG##
	MOVEI 1,DDMPCT		;[ISI]
	CALL DISG##		;[ISI] 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 ASOFNX		;[ISI] 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
	TLNE 2,SHRBIT+INDBIT	;[ISI] Pointer type ok if private
	 JRST RELBAD		;[ISI]
	TLNN 2,10		;[ISI] Address ok if on disk or in core
	TLNN 2,16		;[ISI]
	 JRST RELOF6		;[ISI]
	PUSH P,1		;[ISI] From KI TENEX 1.31
	PUSH P,3		;[ISI] Page probably on drum, try to get it
	PUSH P,4		;[ISI]  onto the disk..
	PUSH P,7		;[ISI]
	HRLZ 1,1		;[ISI] Get AC1 set up for call to SWPINP
	HRRI 1,0(3)		;[ISI]
	CALL SWPINP		;[ISI] Bring page into core from drum
	CALL AGESET		;[ISI] Set age
	CALL SWPOT0		;[ISI] Swap out to disk
	POP P,7			;[ISI]
	POP P,4			;[ISI]
	POP P,3			;[ISI]
	POP P,1			;[ISI]
	MOVE 2,CXBPGA(3)	;[ISI] Make sure page not on drum
	JUMPE 2,RELOF2		;[ISI]
	TLNN 2,10		;[ISI]
	TLNN 2,16		;[ISI]
	TLNE 2,SHRBIT+INDBIT	;[ISI]
	 JRST RELBAD		;[ISI]  really bad
RELOF6:	TLNN 2,10		;[ISI] (The end)
	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?
	jrst [	tlnn 1,17	;no, in core?
		 jrst .+1	;no, can't swap out
		call ageset	;yes, go set ownership so swpout works
		call swpot0	;now swap out xb
		jrst .+1]
	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
	SETZ 2,			;NO QUESTION ABOUT BAD SPOTS
	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
	MOVSI 2,OFNBAT		;PASS JUST OFNBAT
	AND 2,SPTH(1)		;FROM SPTH FLAGS
	SETOM SPTH(1)		;DELETE FROM SPTH
	PUSH P,1
	CALL REMFP1		;REMOVE PAGE
	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
ifn kiflg,<
	call kipsad##		;go do fixup for kiupt
>
	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:
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

SETP51:	TLNN 3,INDBIT		;[ISI] SOURCE PT CONTAINS AN @ PTR?
	 JRST SETP58		;NO. PRIVATE, SHARED, OR EMPTY
	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
	CAIGE 3,NOFN		;[ISI] If @ to file page, get out (OK)
	 JRST SETP58
	CALL SETXB1		;MAP IT
	OKSKED
	SKIP CXBPGA
	NOSKED
	MOVE 3,CXBPGA(2)	;GET CONTENTS OF @ PT WORD
	JRST SETP51		; and check it out

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
ifn kiflg,<
	call kipsad##		;go do fixup for kiupt
>
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
	SKIP CPTPGA		;[ISI] Make sure page in core! (RS patch)
	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)
ifn kiflg,<
	call kipsad##		;go do fixup for kiupt
>
	EXCH 1,2		;EXCHANGE SOURCE AND DESTINATION PT'S
	MOVE 3,PSB+CPTPG
	EXCH 3,PSB+CXBPG
	MOVEM 3,PSB+CPTPG
IFN KAFLG!F3FLG,<		;[ISI]
	MONCLR			;[ISI] Clear ARs for exec mapping
>
IFN KIFLG,<			;[ISI]
	PUSH P,2		;[ISI]
	CALL SETCP2		;[ISI]
	CALL SETXB2		;[ISI]
	POP P,2			;[ISI]
>
	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
IFN KIFLG,<			;[ISI]
SETXB2:	MOVE 3,PSB+CXBPG	;[ISI]
	SETKIM (CXBPG,3)	;[ISI]
	DATAO PAG,KIPGWD	;[ISI]
	MOVE 3,PSB+CXBPG	;[ISI]
>
	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
IFN KIFLG,<			;[ISI]
SETCP2:	MOVE 2,PSB+CPTPG	;[ISI]
	SETKIM (CPTPG,2)	;[ISI]
	DATAO PAG,KIPGWD	;[ISI]
	MOVE 2,PSB+CPTPG	;[ISI]
>
	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
	MOVES CPTPGA		;[ISI] Dummy ref & dirty page
RELMP7:	PUSH P,1
RELMP5:	MOVE 2,CPTPGA(1)	;GET MAP WORD
	JUMPE 2,RELMPR		;EMPTY
IFN KIFLG,<			;[ISI] From KI TENEX 1.31 (PAGEM, p29)
	HLRZ 4,1		;[ISI] See if this page is in the monitor..
	HRRZ 3,FORKX		;[ISI] Is the owning page table
	HRRZ 3,FKPGS(3)		;[ISI]  the PSB?
	CAIE 4,0(3)		;[ISI]
	 JRST [	LDB 3,[POINT 13,PSB+JSBPG,26]  ;[ISI] No,
		CAIE 4,0(3)		;[ISI] Is it the JSB?
		CAMN 4,MMSPTN		;[ISI] Or MMAP?
		 JRST .+1		;[ISI]  Yes
		JRST RELKI2 ]		;[ISI]
	MOVEI 3,0(1)		;[ISI] Is the page in the job private area?
	CAIGE 3,NRPLBG/1000	;[ISI]
	 JRST RELKI2		;[ISI]  no
	ROT 3,-1		;[ISI] Blitz this page's entry in the p.t.
	SKIPL 3			;[ISI]
	 HRRZS KIEPT(3)		;[ISI]
	SKIPGE 3		;[ISI]
	 HLLZS KIEPT(3)		;[ISI]
	DATAO PAG,KIPGWD	;[ISI] KI pager should take a fresh look
	JRST RELKI1		;[ISI] (very fast PGRCLD)
RELKI2:				;[ISI]
	AOS KIRFLG		;[ISI] Reset all KI UPTs
>
	PGRCLD			;CLEAR AR'S
RELKI1:				;[ISI]
	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
ifn kiflg,<
	call kipsad##		;go do fixup for kiupt
>
	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
	MOVES CXBPGA		;[ISI] Dummy ref & dirty page
	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:	HLRZ 2,(P)		;GET OFN (FROM OFN.PN)
	MOVE 2,SPTH(2)		;GET FLAGS
	TLZ 2,^-OFNBAT		;PASS JUST OFNBAT FOR NOW
	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)
;ACCEPTS 1/ FILE PAGE # IF CALLING REMFPG
;	 2/ FLAGS: DON'T DEASSIGN ADR BECAUSE PART OF BAD FILE (OFNBAT)
;	 3/ PAGE ADR IF CALLING REMFP1

REMFPG:	MOVE 3,CPTPGA(1)	;GET MAP WORD
	SETZM CPTPGA(1)		;CLEAR MAP WORD
ifn kiflg,<
	call kipsad##		;go do fixup for kiupt
>
REMFP1:	PUSH P,2		;SAVE OFNBAT FLAG
REMFP0:	TLNE 3,10		;DISK?
	JRST REMFF		;YES
	TLNE 3,16		;DRUM?
	JRST REMFD		;YES
	TLNE 3,17		;CORE?
	 JRST REMFPR		;NO-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 REMFP0

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 (CAN'T BE BAD SPOT)
	POP P,2
	CALL GDSTX
	MOVE 3,DST(2)		;GET BACKUP ADDRESS
	SETOM DST(2)		;MAKE DST SLOT EMPTY
	JRST REMFP0

REMFF:	MOVE 1,3
	MOVE 2,(P)		;GET CALLERS FLAGS
	TLNN 2,OFNBAT		;DON'T DEASSIGN IF PART OF BAD FILE
	 CALL DEDSK		;DEASSIGN DISK ADDRESS
REMFPR:	POP P,2			;COMMON EXIT
	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
ifn kiflg,<
	call kipsad##		;go do fixup for kiupt
>
       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!F3FLG,<
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,XRMRCA
>

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

GETONT:	CALL SETCPT		;[ISI] 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
	CALL RELCPT		;RELEASE CPT
	HRRZ 1,2		;[ISI] Reformat into PTN.PN
	ANDI 1,777		;[ISI]
	LSH 2,-^D9		;[ISI]
	ANDI 2,SPTM		;[ISI]
	HRLI 1,(2)		;[ISI]
	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:
ifn kiflg,<
	call kilupt		;set up ki upt pointer
>
	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
	SETZ 2,			; NO PROCESS USE BITS ANYMORE
	MOVE 1,AGEGLB		; GET GLOBAL AGE
	ROTC 1,-^D9
	MOVEM 2,PGR72
	PGRCLD			;LOAD PAGER FROM 71,72
	MOVE 1,ACBAS		;SET AC BASE REGISTER
	SETACB 1
	RET

;DEASSIGN CORE

DASWSP:
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
	SOS FKWSP(2)		; REDUCE PAGE COUNT FOR THIS PROCESS
	MOVSI 2,7777
	IORM 2,CST3(1)		;MAKE PAGE UNASSIGNED
DECRR:	POP P,2
	POP P,3
	RET

;PAGER TRAP

PGRTRP:	XWD TRAPPC,.+1
 IFDEF FOOVID,<
	 CONO APR,3000+APCHNS  ;Re-enable 60HZ clock, which Foovision may mung.
	>
	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
	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

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

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
		CAIL 1,NFKS	;ANY PROCESS?
		JRST ATP1	;NO
		SOS FKWSP(1)	; REDUCE CORE OCCUPANCY FOR PREVIOUS OWNER
		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>)

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
	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 FKWSP(7)		;INCREASE OWNERSHIP COUNT
	MOVE 1,AGEGLB		; GET GLOBAL AGE
	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,<-2*KIFLG-1>(P)	;[ISI] WRITE DATA (ASSUMING TOP-LEVEL TRAP)
	MOVEM 2,UTRWD
	MOVE 2,<-2*KIFLG-2>(P)	;[ISI] PC
	TLNN 2,UMODF		;USER?
	SKIPGE INTDF		;OR INTERRUPTABLE?
	JRST .+3		;YES
	TLNE 1,12		;MUST DEFER INTERRUPT, READ REF?
	AOS <-2*KIFLG-2>(P)	;[ISI] Yes, do not 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,READB		;DO NOT ALLOW IF NO READ ACCESS
	TDNN 2,CSWPGA(1)	;...
	  JRST [ CALL RELSPG
		 JRST ILRD ]
	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
	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
;JUST UPDATE STATISTICS AND CHECK FOR CORE LIMITS

NIC:	MOVE 2,JOBNO
	AOS JOBPGF##(2)		;PAGE FAULTS/JOB
	HRRZ 2,JOBNAM(2)	;GET SUBSYSTEM INDEX
	AOS SPFLTS(2)		;ACCOUNT PAGE FAULTS FOR SUBSYSTEM
				; CHECK RPLQ HERE AND STOP HOGS
NICN:
NIC2:	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 CHKRPQ		; ENSURE NO DISMIS AT SWPQT
	 JRST NIC2		; HAD TO RESKED SO BACK TO TOP
	CALL SWPINW		;SWAP IN THE PAGE
	JRST NIC2

CHKRPQ:
	MOVE 2,NSKED
	CAILE 2,1		; IF NOSKED (TRAP CAUSES ONE, TOO)
	 JRST RSKP		; THEN LET PROCESS HAVE A PAGE
	MOVE 2,NRPMIN
	CAMLE 2,NRPLQ		; ABOVE BARE MIN?
	JRST CHKRP1		; NO
	HRRZ 2,FKWSP(7)		; GET CURRENT # PAGES ASSIGNED TO THIS FORK
	IDIV 2,GCMOD		; SCALE TO ALLOWABLE SIZE
	CAMG 2,NRPLQ		; ENOUGH ROOM LEFT?
	 JRST RSKP		; YES
CHKRP1: MOVEI 1,TRPNEW		; ADDRESS OF TEST
	JSYS SCHEDR		; DISMS AND WAIT FOR RPLQ TO GE REPLENISHED
	NOSKED			; NOW GET BACK TO NORMAL STATE
	RET
TRPNEW:
	MOVE 2,NRPLQ
	CAMGE 2,NRPMIN		; IS IT ABOVE ABSOLUTE MIN?
	 JRST 0(4)		; NOT YET, SO STAY OUT
	HRRZ 2,FKWSP(7)		; GET CURREN NUMBER OF PAGES OWNED BY FORK
	IDIV 2,GCMOD		; SCALE
	CAMG 2,NRPLQ		; ROOM LEFT?
	JRST 1(4)		; YES
	JRST 0(4)		; NO

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 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

;RELEASE WORKING SET JSYS
;EFFECTIVELY A NO OP UNDER NGCC

.RWSET:	JSYS MENTR
	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!F3FLG,<
	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
IFN KAFLG!F3FLG,<		;[ISI]
	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
>
IFN KIFLG,<			;[ISI]
       PIOFF			;[ISI]
	EXCH 1,PGURET		;[ISI] Set up to return thru scheduler
	MOVEM 1,PPC		;[ISI]
	HRRZ 1,MJRSTF		;[ISI] Deferred interrupt waiting?
	CAIN 1,FPC		;[ISI]
	 SETOM PGUNTF##		;[ISI] No, leave via PI on SCDCHN
	MOVE 1,PGURET		;[ISI]
	AOS INSKED		;[ISI] Claim to be in scheduler
	SOS NSKED		;[ISI] Like OKSKED
	SOS INTDF		;[ISI] Like OKINT
       PION			;[ISI]
	SKIPN PGUNTF		;[ISI]
	 JRST RSKD1##		;[ISI] Exit thru scheduler
	ISB SCDCHN		;[ISI] Call scheduler via PI
	 JRST .-1		;[ISI]
>

;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,(400B8+CORMB)	;[ISI] SET LEGAL AGE SO PAGER DOESN'T TRAP
	MOVEM 1,CST0(3)
	TLO 3,RWXB		;NO, ZERO OUT PAGE
	MOVEM 3,MMAP+CSWPG
IFN KIFLG,<			;[ISI]
	MOVEI 1,KIAXB+KIWB(3)	;[ISI]
	MONSET (CSWPG,1) >	;[ISI]
	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)
	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,(400B8+CORMB)	;[ISI] TRAP IN A SAFE WAY SHOULD IT HAPPEN
	MOVEM 2,CST0(1)		;TO INTERPRET AN INDIRECT PTR WHICH
IFN KIFLG,<			;[ISI]
	MOVEI 2,KIAXB+KIWB(1)	;[ISI]
	MONSET (CSWPG,2,3) >	;[ISI]
	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
IFN KIFLG,<			;[ISI]
	MOVEI 6,KIAXB(1)	;[ISI]
	HLL 1,CST0(1)		;[ISI]
	TLNE 1,(CORMB)		;[ISI]
	 IORI 6,KIWB		;[ISI]
	MONSET (CSWPG,6) >	;[ISI]
	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,(400B8+CORMB)	;[ISI] GET LEGAL AGE
	EXCH 3,CST0(1)		;SAVE OLD AGE
IFN KIFLG,<			;[ISI]
	MOVEI 2,KIAXB+KIWB(1)	;[ISI]
	MONSET (CSWPG,2) >	;[ISI]
	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
	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,SWPERR
	TDNE 2,CST3(1)		;ERROR?
	 JRST SWPFIX		;YES-HANDLE IT
SWPDO0:	MOVSI 2,DWRBIT		;WRITE BIT
	TDNE 2,CST3(1)		;WAS WRITE?
	JRST SWPD1		;YES
	skipg 2,forkx		;find out who is now running
	jrst swpd3		;do nothing if sched or ddmpfk
	hrrz 3,cst0(1)		;find out who is waiting for this page
	cail 3,nfks		;legal fork number?
	jrst swpd3		;no, do nothing
	hlrz 2,fkq##(2)		;yes, get sched queue of running fork
	hlrz 3,fkq(3)		;and that of fork waiting for this page
	camg 2,3		;is running fk on higher q than waiting fk?
	jrst swpd3		;no, do nothing
	aos psked		;yes, ask for rescheduling
	isb scdchn		;and poke channel seven to make it happen
swpd3:
	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)


;HERE TO PROCESS SWAPPING ERROR, BAT ENTRY QUEUED FOR JOB 0 ALREADY
;VIA DISK DRIVER

;------------------------------------------------------------------------------
;SWAPPING ERROR HANDLING:
;
;	WRITE: NOT EXPECTED OR HANDLED.
;
;	READ:
;
;		FROM DISK: DECODE USAGE AND POSSIBLY COMPLAIN.
;			   POSSIBLY SET OFNBAT FOR OFN.
;			   SWPERR SEEN LATER IF ALLOWED TO FLY AND
;			   INTERRUPT WILL BE HANDED OFF TO PROCESS.
;
;		FROM DRUM:
;
;			NO BACKUP: ASSIGN TRASH DRUM ADR TO CST.
;				   LEAVE OLD BAD DRUM ADR ASSIGNED.
;				   DECODE USAGE AND POSSIBLY COMPLAIN.
;				   POSSIBLY SET OFNBAT FOR OFN.
;				   SWPERR SEEN LATER IF ALLOWED TO FLY AND
;				   INTERRUPT WILL BE HANDED OFF TO PROCESS.
;
;			BACKUP:
;
;				DST BWRBIT ON:	LEAVE OLD BAD DRUM ADR ASSGNED.
;						MAKE DRUM BACKUP CORE BACKUP.
;						DECODE USAGE & POSSBLY CMPLAIN.
;						POSSIBLY SET OFNBAT FOR OFN.
;						SWPERR SEEN LATER IF ALLOWED TO
;						FLY & INTERRUPT WILL BE HANDED
;						OFF TO PROCESS.
;
;				DST BWRBIT OFF: LEAVE OLD BAD DRUM ADR ASSGNED.
;						MAKE DRUM BACKUP CORE BACKUP.
;						RESTART READ FROM NEW BACKUP.
;------------------------------------------------------------------------------

;ACCEPTS 1/ PAGE NUMBER

SWPFIX:	PUSH P,1		;CLOBBER NO ACS
	PUSH P,2
	PUSH P,3
	PUSH P,4
	MOVE 2,CST3(1)		;WE ARE EXPECTING ONLY READ ERRORS FOR NOW
	TLNE 2,DWRBIT		;WAS IT?
	 BUG (HLT,<SWPFIX: UNEXPECTED DISK WRITE ERROR>)
	MOVE 2,CST1(1)		;GET BACKUP ADR WE READ FROM
	TLNN 2,(DSKABT)		;DID WE READ FROM DRUM?
	 JRST SWPFDR		;YES-DRUM ADR HANDLING
SWPFI0:	MOVE 1,-3(P)		;GET CPN AGAIN INCASE JRSTED BACK FROM SWPFDR
	HLRZ 2,CST2(1)		;GET OWNING SPTN
	JUMPN 2,SWPFI1		;JUMP IF IN PT
	HRRZ 2,CST2(1)		;GET SPTN OF PAGE
	CAIGE 2,NOFN		;INDEX BLOCK?
	JRST [	CALL SWBOFN	;YES -  FLAG IN SPT
		CALL SWPSNS	;IS IT SENSITIVE INDEX BLOCK?
		 JRST SWPX10	;NO - NOTE MILD COMPLAINT
		JRST SWPX11]	;YES-COMPLAIN
	HLRZ 2,SPTH(2)		;GET OFN OF IDENT
	JUMPN 2,SWPFI1		;JUMP IF OFN PRESENT
	HRRZ 2,CST2(1)		;GET SPTN AGAIN IN 2
	CALL FNDFPG		;GET TYPE OF FORK PAGE, 1/ PAGE #, 2/ SPTN
	JRST @[ SWPX12		;0 - UNKNOWN
		SWPX13		;1 - PSB
		SWPX14		;2 - UPT
		SWPX15](2)	;3 - JSB

;HERE WHEN HAVE PAGE TABLE IDENT IN 2

SWPFI1:	CAIGE 2,NOFN		;IN ORDINARY FILE?
	 JRST [	CALL SWBOFN	;YES - MARK IN SPT
		CALL SWPSNS	;IS IT SENSITIVE FILE PAGE?
		 JRST SWPX20	;NO-LET IT RIDE
		JRST SWPX21]	;YES-COMPLAIN
	CAMN 2,MMSPTN		;SWAPPABLE MONITOR?
	 JRST SWPX30		;YES
	CALL FNDFPG		;GET TYPE OF FORK PAGE, 1/ PAGE #, 2/ SPTN
	JRST @[	SWPX22		;0 - UNKNOWN
		SWPX23		;1 - PSB PAGE
		SWPX24		;2 - UPT PAGE
		SWPX25](2)	;3 - JSB PAGE



;HERE TO RESTORE THINGS AND RETURN TO SWPDON

SWPFIR:	POP P,4			;RESTORE ACS
	POP P,3
	POP P,2
	POP P,1
	JRST SWPDO0		;BACK TO SWPDON


;HERE TO RESTORE THINGS AND RETURN TO CALLER OF SWPDON
;HENCE ABORTING REST OF SWPDON (LIKE CLEARING READ IN PROGRESS FOR REDOS)

SWPFIA:	POP P,4			;RESTORE ACS
	POP P,3
	POP P,2
	POP P,1
	JRST (4)		;ABORT REST OF SWPDON

;HERE TO DETERMINE IF OFN IS IN SENSITIVE RANGE
;ACCEPTS OFN IN 2
;SKIPS IF SENSITIVE, NO SKIP IF NOT

SWPSNS:	PUSH P,1		;CLOBBER NO ACS
	HLRZ 1,SNSOFN		;GET START OF RANGE
	CAMGE 2,1		;OFN BELOW LOWEST?
	 JRST SWPSN1		;YES-NOT IN SENSITIVE RANGE
	HRRZ 1,SNSOFN		;NO-GET END OF RANGE
	CAMG 2,1		;OFN ABOVE HIGHEST?
	 AOS -1(P)		;NO-ITS SENSITIVE, SKIP
SWPSN1:	POP P,1
	RET


;HERE TO INDICATE AN ERROR IN AN OFN

SWBOFN:	PUSH P,1		;CLOBBER NO ACS
	MOVSI 1,OFNBAT		;GET BAT BIT
	IORM 1,SPTH(2)		;IN SPTH FOR OFN
	POP P,1
	RET


;DISPOSITION OF SWAP ERROR CASES

;PAGE TABLE ERRORS

SWPX10:	BUG(CHK,<SWPDON: SWAP ERROR IN INDEX BLOCK>)
	JRST SWPFIR

SWPX11:	BUG(HLT,<SWPDON: SWAP ERROR IN SENSITIVE INDEX BLOCK>)

SWPX12:	BUG(HLT,<SWPDON: SWAP ERROR IN UNKNOWN PT>)

SWPX13:	BUG(HLT,<SWPDON: SWAP ERROR IN PSB>)

SWPX14:	BUG(HLT,<SWPDON: SWAP ERROR IN UPT>)

SWPX15:	BUG(HLT,<SWPDON: SWAP ERROR IN JSB>)


;NON PAGE TABLE ERRORS

SWPX20:	JRST SWPFIR		;QUIET ON NORMAL FILE PAGE SWAP ERRORS

SWPX21:	BUG(CHK,<SWPDON: SWAP ERROR IN SENSITIVE FILE PAGE>)
	JRST SWPFIR

SWPX22:	BUG(HLT,<SWPDON: SWAP ERROR IN UNKNOWN PT PAGE>)

SWPX23:	BUG(HLT,<SWPDON: SWAP ERROR IN PSB PAGE>)

SWPX24:	JRST SWPFIR		;QUIET ON UPT PAGE SWAP ERRORS

SWPX25:	BUG(CHK,<SWPDON: SWAP ERROR IN JSB PAGE>)
	JRST SWPFIR

;MISC ERRORS

SWPX30:	BUG(HLT,<SWPDON: SWAP ERROR IN SWAPPABLE MONITOR>)


;HERE FOR BAD SPOT READS FROM DRUM
;CORE PAGE # IN 1
;IF THERE IS A DISK BACKUP AND BWRBIT IS OFF
;MAKE IT THE CORE BACKUP AND TRY IO AGAIN
;LEAVING THE DRUM ADR ASSIGNED BUT NOT LINKED TO A CST
;IF THE BWRBIT IS ON, MAKE DISK THE BACKUP BUT RETURN TO SWPDON
;TO ALLOW USER TO SEE INTERRUPT.  IF USER DOES NOT WRITE ON THE BAD PAGE,
;THE OLD COPY WILL STILL BE THERE.  BETTER THAN COMPLETE TRASH.

SWPFDR:	PUSH P,1		;SAVE CPN [-4(P)] OR {-2(P)}
	MOVE 2,CST1(1)		;GET BACKUP DRUM ADR
	TLZ 2,DSKMSK		;WITHOUT THE LOCK COUNT
	PUSH P,2		;SAVE BAD SPOT DRUM ADR [-3(P)] OR {-1(P)}
	CALL GDSTX		;GET BAD DRUM ADR DST INDEX
	PUSH P,2		;AND SAVE IT [-2(P)] OR {0(P)}
	MOVE 1,DST(2)		;GET THE BACKUP FOR DRUM (HOPEFULLY DISK)
	CAME 1,[-1]		;FREE
	TLNN 1,(DSKABT)		;OR NOT A DISK ADR? (UNASSIGNED)
	CAIA			;YES
	 JRST SWPFD1		;NO-POINT CST AT IT AND TRY AGAIN
	SETO 1,			;GET A TRASHED NEW FREE CHOICE
	CALL DRMASN		;GET A NEW DRUM ADR
	 BUG (HLT,<SWPFDR: CAN'T ASSIGN DRUM ADR FOR SWAP ERROR FIXUP>)	
	PUSH P,1		;SAVE NEW DRUM ADR [-1(P)]
	MOVE 2,1		;WHERE GDSTX LIKES IT
	CALL GDSTX		;GET DST FOR NEW DRUM ADR
	PUSH P,2		;SAVE IT [0(P)]
	MOVE 2,-2(P)		;GET OLD DST INDEX
	MOVE 1,DST(2)		;GET THE CONTENTS
	TLZ 1,BWRBIT		;SAY PAGE NOT CHANGED, HOPE NOT TO WRITE BACK
	MOVE 2,0(P)		;GET NEW DST INDEX
	MOVEM 1,DST(2)		;INSTALL DST FOR NEW DRUM ADR (COPY OF OLD)	
	MOVE 1,-4(P)		;GET CPN
	HLLZ 2,CST1(1)		;GET LOCK COUNT
	TLZ 2,^-DSKMSK		;CLEANLY
	IOR 2,-1(P)		;ADD NEW DRUM ADR TO OLD LOCK COUNT
	MOVEM 2,CST1(1)		;INSTALL NEW DRUM ADR AS BACKUP FOR CPN
	MOVE 2,-2(P)		;GET OLD DRUM ADR DST INDEX
	SETOM DST(2)		;CLEAR IT, OLD DRUM ADR STILL ASSIGNED
	SUB P,BHC+5		;RESYNC STACK
	JRST SWPFI0		;BACK TO REST OF SWAP ERROR HANDLING
				;COMPLAIN AS APPROPRIATE



;HERE FOR DRUM SWAP ERROR AND BACKUP FOR DRUM (DISK) EXISTS.
;STACK HAS CPN,DRUM ADR,DST INDEX AS {-2(P)},{-1(P)},{0(P)}

SWPFD1:	MOVE 1,0(P)		;GET DST INDEX
	MOVE 1,DST(1)		;GET CONTENTS OF DST (PRESERVE STATUS BITS)
	HRLI 2,DSKMSK		;BUILD MASK OF BITS NOT TO KEEP
	TLZ 2,NEWFB(DSKABT)	;KEEP NEW FILE BIT AND DISK DEVICE BIT
	ANDCM 1,2		;CLEAN UP 1 RETAINING NEWFB AND DSKABT
	MOVE 3,-2(P)		;GET CPN
	HLLZ 2,CST1(3)		;GET LOCK COUNT
	TLZ 2,^-DSKMSK		;CLEANLY
	IOR 1,2			;IOR LOCK COUNT AND DISK ADR
	MOVEM 1,CST1(3)		;MAKE CORE BACKUP DISK NOW
	MOVE 1,0(P)		;GET DST INDEX OF BAD DRUM ADR
	MOVE 2,DST(1)		;GET OLD DST CONTENTS
	SETOM DST(1)		;CLEAR IT, BUT DRUM ADR STILL ASSIGNED
	TLNE 2,BWRBIT		;DRUM DIFFERENT FROM DISK?
	 JRST SWPFD2		;YES-SEMI LOSAGE
	MOVE 1,-2(P)		;NO-REQUEUE FOR SWAPPING IN FROM DISK
	MOVSI 2,DWRBIT		;THE WRITE BIT
	TDNE 2,CST3(1)		;WAS IT A WRITE WE ARE GONNA REDO?
	 TLO 1,DWRBIT		;YES-TURN ON DWRBIT IN DSKIO ARG
	CALL DSKIO		;REDO THE IO, DISK THIS TIME
	SUB P,BHC+3		;RESYNC STACK
	JRST SWPFIA		;AND ABORT SWPDON, PROCESS WAITING FOR
				;REDO TO COMPLETE NOW

;HERE AFTER MAKING DISK THE BACKUP FOR CORE AND FOUND BWRBIT ON
;IN BAD SPOT DST.  RESYNC AND CONTINUE - PASSING THE INTERRUPT ON TO USER.

SWPFD2:	SUB P,BHC+3		;RESYNC STACK
	JRST SWPFI0		;COMPLAIN AS APPROPRIATE


;FIND TYPE OF FORK PAGE
; 1/ PAGE #
; 2/ SPTN OF CONCERN

;	CALL FNDFPG

; RETURNS +1 ALWAYS,
; 2/ 	0 - UNKNOWN PAGE
;	1 - PSB
;	2 - UPT
;	3 - JSB

FNDFPG:	PUSH P,1		;CLOBBER NO ACS
	PUSH P,2
	PUSH P,3
	HRRZ 3,CST0(1)		;GET FORKX OF PAGE IN 3
	CAIL 3,0		;LOOK LEGAL?
	CAIL 3,NFKS
	 JRST FNDFP2		;NO-UNKNOWN
	MOVSI 2,-NFNFT		;SETUP TO SCAN TABLE
FNDFP1:	XCT FNFTAB(2)		;GET SPTN FOR A FORK PAGE IN 1
	CAMN 1,-1(P)		;SAME AS GIVEN ONE?
	 JRST FNDFP3		;YES, RETURN INDEX IN 2
	AOBJN 2,FNDFP1		;SCAN TABLE
FNDFP2:	SETZ 2,			;NOT FOUND, 0 IS UNKNOWN
FNDFP3:	HRRZM 2,-1(P)		;CLEAR COUNTER PART OF AOBJN
	POP P,3			;RESTORE ACS
	POP P,2			;HAS ANSWER TYPE
	POP P,1
	RET

FNFTAB:	SETZ 1,			;IMPOSSIBLE SPTN TO FAKE UNKNOWN
	HRRZ 1,FKPGS(3)		;GET SPTN OF PSB FOR FORK IN 3
	HLRZ 1,FKPGS(3)		;GET SPTN OF UPT FOR FORK IN 3
	HRRZ 1,FKJOB(3)		;GET SPTN OF JSB FOR FORK IN 3
NFNFT==.-FNFTAB



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
	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)
	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:
IFN KIFLG,<			;[ISI]
	AOS KIRFLG >		;[ISI] Force resetting of all KI UPTs
	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
	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
	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
IFN KAFLG!F3FLG,<		;[ISI]
	MONCLR (CSWPG)		;[ISI] Clear the AR used for CSWPG
>
IFN KIFLG,<			;[ISI] Set up KI's page table directly
	MOVEI 3,KIAXB+KIWB(1)	;[ISI]  and have the pager take a fresh
	MONSET (CSWPG,3,2)	;[ISI]  look at CSWPG
	DATAO PAG,KIPGWD	;[ISI]
>
	SKIP CSWPGA		; REFERENCE THE PAGE
	MOVSI 2,010000
	MOVEM 2,CST0(1)		; SET AGE BACK TO UNAVAIL IN CASE NXM
IFE F3FLG,<
	CONSZ APR,APNXM		; EXISTS?
>
IFN F3FLG,<
	SETZM CSWPGA		;TRY TO ZERO OUT LOCATION
	SKIPE CSWPGA		;F3 RETURNS -1 ON NXM READS...
>
	 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
MAKPGX:	CONO APR,APNXM+APCHNS	;[ISI] CLEAR NXM FLAG
	CAMGE 1,-3(P)		; REACHED END YET?
	 AOJA 1,MKPGAL		; NO DO NEXT ONE
	SETZM MMAP+CSWPG	; CLEAR MAP ENTRY
	PGRCLD
	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 DEPGIT		; GO BREAK ALL POINTERS TO RPLQ!
	MOVSI 1,-NFKS
	SETZM FKPAGE(1)		; MAKE CUTOFF AGE BE NOW FO AL FORKS
	AOBJN 1,.-1
	PUSH P,GCDIFF		; SAVE OLD VALUE
	MOVEI 1,MAXCOR
	MOVEM 1,GCDIFF		; MAKE MAX SIZE
	CALL NGCC		; NOW COLLECT AS MUCH AS POSSIBLE
	POP P,GCDIFF
	POP P,1			; GET OLD NRPLQ
	SKIPN IOIP
	CAME 1,NRPLQ
	 JRST GCALC		; LOOP UNTIL NO CHANGE IN NRPLQ AND NO IOIP
	CALL DEPGIT		; NOW GO BREAK THE LAST BUNCH OF POINTERS
	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
	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
		MOVEM 1,GCPN	; AND UPDATE GARBAGE COLLECTOR START POINT!
		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
GCALX:	SETZM FSHBAL		;SAY FLUSH IS COMPLETED
	RET

DEPGIT:
	MOVE 1,NRPLQ		; GET SIZE OF LIST
	JUMPE 1,R		; COULD BE EMPTY
	HRRZ 7,RPLQ
DEPGT1:	MOVEI 3,(7)
	SUBI 3,CST3
	CALL DEPG		; BREAK POINTERS TO THIS PAGE
	SETZM CST2(3)
	HRRZ 7,(7)		; CONTINUE DOWN RPLQ LIST
	SOJG 1,DEPGT1
	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

;15 FORK KILL LOGIC CALLS THIS TO CLEAN UP

FKDGCC::MOVE FX,-1(P)
	SETOM FKPAGE(FX)
	PUSH P,P1
	MOVN P1,NHIPG
	ADD P1,SWPCOR
	MOVSI P1,-1(P1)
	ADD P1,SWPCOR

FKDGC1:LDB T1,[POINT 12,CST3(P1),17]	; GET OWNING FORK
	CAIE T1,0(FX)
	 JRST FKDGC2
	LDB T1,[POINT 9,CST0(P1),8]	; GET AGE FIELD
	CAIGE T1,100			;10 Page in use?
	 JRST FKDGC2			;10 No, don't collect
	MOVEI T1,0(P1)
	CALL DASWSP
	MOVE T2,CST1(P1)
	TLNE T2,-PLKV
	 JRST FKDGC2
	MOVE T2,CST3(P1)
	TLNN T2,DWRBIT
	 CALL SWPOUT
FKDGC2:	AOBJN P1,FKDGC1
	POP P,P1
	RET
;NEW GARBAGE COLLECT CORE ROUTINE
;P1 IS THE NUMBER OF PAGES TO COLLECT.
;P2 IS THE PAGE NUMBER OF THE PAGE BEING LOOKED AT.
;NGCC ENTRY POINT

NGCC::				;CALCULATE THE NUMBER OF PAGES TO COLLECT.
	JSP 4,STIME		; COLLECT TIMING DATA
	MOVN P1,GCSTRT		;CALCULATE NUMBER OF PAGES TO COLLECT 
	SUB P1,GCDIFF		;   GCSTRT + GCDIFF - NRPLQ - IOIP
	ADD P1,NRPLQ		; AND PUT IN P1 AS A NEGATIVE NUMBER.
	ADD P1,IOIP
	MOVSI P1,0(P1)
	HRRZ P2,GCPN		; GET ROVING CORE PAGE POINTER FROM LAST PASS
	MOVEI P3,3		;17 INIT LOOP DETECTION COUNTER


NGCC10:LDB T1,[POINT 9,CST0(P2),8]	; GET AGE FIELD FOR THIS PAGE
	CAIGE T1,100		;8 IS THIS PAGE AGE LEGAL?
	 JRST NGCC50		;NO, TRY TO COLLECT IT NOW.
	LDB FX,[POINT 12,CST3(P2),17]	; GET OWNING FORK
	CAIL FX,NFKS		;IS THIS FORK A LEGAL FORK?
	 JRST NGCC40		;NO, TRY TO COLLECT IT NOW.
	SUB T1,AGEGLB		; GET CURRENT PAGE AGE
	MOVNS 1			;18 MAKE CORRECT!!!
	CAIGE T1,0		; CHECK FOR OVERFLOW
	 ADDI T1,700
	CAML T1,FKPAGE(FX)	; IS THE AGE OF THIS PAGE OLDER THAN FKPAGE?
	 JRST NGCC30		;YES...TRY TO COLLECT THIS PAGE...
NGCC12:				; ADJUST AGE FOR PAGE NOT COLLECTED
	MOVE T1,FKFLGS(FX)
	TLNN 1,BLST		; IS THIS FORK IN BALSET?
	 JRST [	HRRZ T2,FKWSP(FX)	; GET CURRENT SIZE
		CAIG T2,3		; IF VERY SMALL, THEN KICK OUT FAST
		SETZM FKPAGE(FX)
		MOVN T1,GCBALB	;21 Bias in favor of balset jobs
		ADDM T1,FKPAGE(FX) ;11  pages out of memory
		JRST .+1 ]	;11
	SOSGE FKPAGE(FX)	;17 ADJUST AGE FOR PAGE NOT COLLECTED
	 SETZM FKPAGE(FX)	;17 PREVENT FROM GOINT NEGATIVE!
NGCC14:	CAMGE P2,NHIPG		;IS THIS THE LAST PAGE OF CORE?
	 AOJA P2,NGCC10		;NO...
	MOVE P2,SWPCOR		;RESET PAGE NUMBER TO LOWEST VALUE.
	SOSGE P3		;17 LOOK FOR "INFINITE" LOOP
	 JRST NGCCXT		;17 EXIT NOW AND PRAY SOME FORK GIVES PAGES BACK
	JRST NGCC10



;				; TRY TO COLLECT THIS PAGE WITH CSTAGE > FKPAGE AND FOR A LEGAL FORK.
NGCC30:	MOVE T1,CST1(P2)	;GET BACKUP ADDRESS WORD
	TLNE T1,-PLKV		;IS PAGE LOCKED?
	 JRST NGCC12		;YES
	MOVE T1,CST3(P2)	;GET DRUM WRITE BIT.
	TLNE T1,DWRBIT	;IS PAGE BEING WRITTEN?
	 JRST NGCC12		;YES
	HRRZ T2,FKWSP(FX)	; ADJUST FKPAGE FOR PAGE TO BE COLLECTED
	CAIN T2,1		; IS THIS THE VERY LAST PAGE?
	 JRST NGCC35		; YES, SO RESET FKPAGE TO HIGH FOR NEXT ENTRY
	CAIG T2,3		; IF VERY SMALL, HELP IT OUT FASTER
	 JRST 	[ SETZM FKPAGE(FX)
		  JRST NGCC36]
	LSH T2,2		;15 SCALE TO GET 20% COLLECTION RATE
	MOVE T3,TOTRC		;GET TOTAL SWAPPABLE CORE SIZE
	IDIVI T3,(T2)	 
	ADD T3,FKPAGE(FX)	;FKPAGE := FKPAGE + TOTRC/4*WSP SECONDS.
	CAIL T3,^D360		;360 SECOND MAXIMUM
NGCC35:	 MOVEI T3,^D360
	MOVEM T3,FKPAGE(FX)
NGCC36:	MOVEI T1,(P2)		; COLLECT THE PAGE
	CALL DASWSP		;DEASSIGN PAGE FROM OWNING FORK.
	CALL SWPOUT		;SWAPOUT THIS PAGE.
	AOBJN P1,NGCC14		;LOOP UNTIL ENOUGH COLLECTED

NGCCXT:	MOVEM P2,GCPN		;SAVE PAGE NUMBER TO START ON NEXT TIME
	JSP 4,ETIME		; FINISH TIMING DATA
	ADDM 1,GCCR
	AOS GCCR+1		; COUNT OCCURRENCES
	RET


;				;AGE OF THIS PAGE IS VALID, BUT THE FORK IS NOT LEGAL.
NGCC40:	MOVE T1,CST1(P2)	;GET BACKUP ADDRESS WORD
	TLNE T1,-PLKV		;IS PAGE LOCKED?
	 JRST NGCC14		;YES
	MOVE T1,CST3(P2)	;GET DRUM WRITE BIT.
	TLNE T1,DWRBIT	;IS PAGE BEING WRITTEN?
	 JRST NGCC14		;YES...
	JRST NGCC36		;DON'T ADJUST FKPAGE, BUT COLLECT THIS PAGE.


;				; THIS PAGE DOES NOT HAVE A VALID AGE.
NGCC50:	TRZ T1,7		; SCRAPE OFF AGE BIT REMNANTS
	CAIE T1,20		;IS THIS PAGE IN READ COMP MODE?
	 JRST NGCC14		;NO...DON'T ADJUST FKPAGE AND DON'T COLLECT.
	HRRZ FX,CST0(P2)	;YES, GET FORK NUMBER THAT INITIATED READ
	CAIL FX,NFKS		;IS THIS FORK A LEGAL FORK?
	 JRST NGCC40		;NO.  FORK GONE, SO GET PAGE
	SKIPL FKPT(FX)		;YES...IS THIS FORK A DELETED FORK?
	 JRST NGCC12		;NO...ADJUST FKPAGE, AND DON'T COLLECT THIS PAGE.
	JRST NGCC40		; DELETED FORK, SO GET PAGE

GCBLBS::MOVSI T2,-NLDGCB	;21 adjust GC balset bias for load
	HRRZ T1,LDGCB(T2)	;21 Get break-over LA
	CAIGE T3,(T1)		;21 Is LA greater than break-over point?
	AOBJN T2,.-2		;21 No, look at next break-over point
	HLRZ T1,LDGCB(T2)	;22 Yes, get GC balset bias
	MOVEM T1,GCBALB		;21 Set GC balset bias
	RET			;21

LDGCB:	^D100,,^D10		;21
	^D10,,5			;21
	^D2,,0			;21
NLDGCB==.-LDGCB			;21
	END			;END OF PAGEM.MAC
