Google
 

Trailing-Edge - PDP-10 Archives - BB-M080E-SM - monitor-sources/pagem.mac
There are 55 other files named pagem.mac in the archive. Click here to see a list.
;Edit 3005 to PAGEM.MAC by MOSER on Mon 29-Aug-83, for SPR #19362
;		FIX PTNIC1 AND OTHER PROBLEMS
;EDIT 3005 - FIX PTNIC1 AND OTHER PROBLEMS
;Edit 2960 to PAGEM.MAC by WEETON on Tue 10-May-83, for SPR #18539
;		Allow abortions of DA%INI without doing DA%WRTs
;Edit 2958 to PAGEM.MAC by LOMARTIRE on Wed 4-May-83, for SPR #18449
;		Add new NOOFN BUGINF.  Also, clean up NOFN definition.
;EDIT 2915 - ASGOFN - Set OFNDUD if opener requests it.
; UPD ID= 287, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.13,  10-Jan-83 10:00:30 by DONAHUE
;Edit 2895 - Remove previous edit
; UPD ID= 282, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.12,   6-Jan-83 11:54:04 by DONAHUE
;Edit 2893 - Remove NRPLQ check in PREPG5
; UPD ID= 267, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.11,  14-Dec-82 08:07:57 by DONAHUE
;Edit 2887 - Don't zero TRPDSP at ILRF2
; UPD ID= 243, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.10,   7-Dec-82 21:58:22 by COBB
;EDIT 2877 - MSETST - Don't compress out indirect ptrs.
; UPD ID= 191, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.9,  26-Oct-82 15:07:45 by COBB
;EDIT 2850 - Handle page faults in skeds 20 ms cycle properly [PGRTRP]
; UPD ID= 184, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.8,  26-Oct-82 10:53:56 by COBB
;EDIT 2844 - Put calls to NBNSB in SKEDSW conditional.
; UPD ID= 162, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.7,   4-Oct-82 16:48:34 by MOSER
;EDIT 2829 - MORE OF 2826
; UPD ID= 151, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.5,   1-Oct-82 11:55:27 by MOSER
;EDIT 2826 - ADD ADDITIONAL DATA TO SWPDIR
; UPD ID= 144, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.4,  27-Sep-82 16:11:52 by MOSER
;EDIT 2820 - FIX RACE IN DDMP WHICH CAUSES J0NRUNS WITH STRLOK LOCKED
; UPD ID= 141, FARK:<5-1-WORKING-SOURCES.MONITOR>PAGEM.MAC.3,  27-Sep-82 13:30:11 by MOSER
;EDIT 2818 - BUGCHK SWPDIR - SWAP ERROR IN DIRECTORY FILE
; UPD ID= 71, FARK:<5-WORKING-SOURCES.MONITOR>PAGEM.MAC.2,  27-Jul-82 08:53:27 by DONAHUE
;Edit 2634 - Prevent SWPSTL Bugchk's
; UPD ID= 496, SNARK:<5.MONITOR>PAGEM.MAC.59,   4-Mar-82 12:09:24 by COBB
;TCO 5.1743 - Update access flags in SPTH when returning good from CHKACC
; UPD ID= 419, SNARK:<5.MONITOR>PAGEM.MAC.58,  19-Jan-82 12:25:11 by MURPHY
;DITTO
; UPD ID= 410, SNARK:<5.MONITOR>PAGEM.MAC.57,  18-Jan-82 17:24:46 by MURPHY
;TCO 5.1686 - reduce SPC0 threshold to prevent SPT full situations.
; UPD ID= 406, SNARK:<5.MONITOR>PAGEM.MAC.56,  17-Jan-82 20:54:47 by PAETZOLD
;TCO 5.1682 - change ILSN to generate ILLX05 as TWWRT is not valid
;TCO 5.1683 - fix GETTPD to generate correct error dispatch for
;	      non-existant section references
; UPD ID= 381, SNARK:<5.MONITOR>PAGEM.MAC.55,   7-Jan-82 16:57:47 by MURPHY
;More 5.1616 - don't wait in RELP3.
; UPD ID= 334, SNARK:<5.MONITOR>PAGEM.MAC.54,   2-Dec-81 13:30:35 by MURPHY
;TCO 5.1623
;Change GNPBAS to BALSHC around NICCKS (old fix).  Get rid of GNPBAS completely.
; UPD ID= 333, SNARK:<5.MONITOR>PAGEM.MAC.53,   1-Dec-81 11:15:18 by GRANT
;TCO 5.1621 - fix cause of MONPDL BUGHLT in SETP6 routine
; UPD ID= 332, SNARK:<5.MONITOR>PAGEM.MAC.52,  30-Nov-81 14:27:23 by MURPHY
;fix previous
; UPD ID= 327, SNARK:<5.MONITOR>PAGEM.MAC.51,  19-Nov-81 11:48:26 by MURPHY
;ditto
; UPD ID= 324, SNARK:<5.MONITOR>PAGEM.MAC.50,  18-Nov-81 17:38:01 by MURPHY
;TCO 5.1616 - Check page locked in core in MOVDSK and elsewhere.
; UPD ID= 320, SNARK:<5.MONITOR>PAGEM.MAC.49,  16-Nov-81 17:34:52 by MURPHY
;TCO 5.1615 - call SETPCV at ILRF
; UPD ID= 310, SNARK:<5.MONITOR>PAGEM.MAC.48,   4-Nov-81 10:34:38 by GRANT
;TCO 5.1605 - Fix bug in SWPEX6
; UPD ID= 279, SNARK:<5.MONITOR>PAGEM.MAC.47,  21-Oct-81 13:50:21 by PAETZOLD
;TCO 5.1591 - Have MSETPT unlock the correct OFN when cleaning up during
; failure code
; UPD ID= 264, SNARK:<5.MONITOR>PAGEM.MAC.46,  15-Oct-81 22:40:43 by PAETZOLD
;TCO 5.1574 - Check for overflowing the SPT SHARE COUNT before
; incrementing it
; UPD ID= 243, SNARK:<5.MONITOR>PAGEM.MAC.45,   4-Oct-81 23:45:45 by PAETZOLD
;TCO 5.1554 - ADD CODE TO TRACE SPTLKB STUFF UNDER CONTROL OF SPTDSW
; UPD ID= 141, SNARK:<5.MONITOR>PAGEM.MAC.44,   3-Sep-81 08:40:08 by PAETZOLD
;Add semicolins to comments in previous edit
; UPD ID= 139, SNARK:<5.MONITOR>PAGEM.MAC.43,   2-Sep-81 16:48:37 by HALL
;Comments
; UPD ID= 135, SNARK:<5.MONITOR>PAGEM.MAC.42,   1-Sep-81 17:31:07 by HALL
;Comments
; UPD ID= 111, SNARK:<5.MONITOR>PAGEM.MAC.41,  20-Aug-81 17:28:03 by MURPHY
;TCO 5.1006X - Set OFNWRB in RELADR to prevent DEAUNA bugchks.
;TCO 5.1007X - Fix reference to flags word at PGUNT0.
; UPD ID= 74, SNARK:<5.MONITOR>PAGEM.MAC.40,  24-Jul-81 16:01:55 by SCHMITT
;TCO 5.1433 - Insert page map and section map loop checking in MSETST & SETPT0
; UPD ID= 47, SNARK:<5.MONITOR>PAGEM.MAC.39,  17-Jul-81 16:19:45 by MURPHY
;DITTO - SKIP/NOSKIP RETURN FROM MSETPT
; UPD ID= 29, SNARK:<5.MONITOR>PAGEM.MAC.38,  13-Jul-81 15:23:16 by MURPHY
;YET MORE TCO 5.1398
; UPD ID= 26, SNARK:<5.MONITOR>PAGEM.MAC.37,  13-Jul-81 13:18:20 by MURPHY
;MORE TCO 5.1398
; UPD ID= 15, SNARK:<5.MONITOR>PAGEM.MAC.36,  10-Jul-81 09:19:28 by MOSER
;TCO 5.1406 - IF WCPY IS CALLED FOR A LOCKED PAGE GENERATE AN ILLEGAL MEMORY
; WRITE.
; UPD ID= 9, SNARK:<5.MONITOR>PAGEM.MAC.35,   9-Jul-81 17:13:22 by MURPHY
;TCO 5.1398 - SEPARATE DISK FULL FROM OVER QUOTA, ETC.
; UPD ID= 2187, SNARK:<5.MONITOR>PAGEM.MAC.34,  11-Jun-81 15:55:55 by MURPHY
;CHANGE TQNx TO TMNx REFLECTING CHANGE IN MACSYM
; UPD ID= 1892, SNARK:<5.MONITOR>PAGEM.MAC.33,  27-Apr-81 13:17:01 by GRANT
;Undo REPEAT 0 around GETCPA
; UPD ID= 1887, SNARK:<5.MONITOR>PAGEM.MAC.32,  24-Apr-81 17:33:53 by MURPHY
;TCO 5.1298 - COUNT INDIRECT POINTERS SEEN IN GETTPD AND ELSEWHERE
; UPD ID= 1611, SNARK:<5.MONITOR>PAGEM.MAC.31,  27-Feb-81 18:23:20 by MURPHY
;ASOFN, BUG FROM OF%RDU
; UPD ID= 1601, SNARK:<5.MONITOR>PAGEM.MAC.30,  27-Feb-81 09:51:59 by FLEMMING
;TCO 5.1265 - fix RMAP returning wrong access information
; UPD ID= 1561, SNARK:<5.MONITOR>PAGEM.MAC.29,  13-Feb-81 16:44:11 by MURPHY
;NEW OPENF MODE - OF%RDU - READ-UNRESTRICTED
; UPD ID= 1475, SNARK:<5.MONITOR>PAGEM.MAC.28,  22-Jan-81 12:16:37 by MURPHY
;Fix PM%ABT in new page case
; UPD ID= 1447, SNARK:<5.MONITOR>PAGEM.MAC.27,  15-Jan-81 15:59:22 by FLEMMING
;add code for SMAP/RSMAP
; UPD ID= 1371, SNARK:<5.MONITOR>PAGEM.MAC.26,  22-Dec-80 08:52:24 by GRANT
;TCO 5.1217 - Fix bug in YESBAT
; UPD ID= 1311, SNARK:<5.MONITOR>PAGEM.MAC.25,  24-Nov-80 17:36:57 by MURPHY
;BUG - PREPG1 not returning page number in T1
; UPD ID= 1295, SNARK:<5.MONITOR>PAGEM.MAC.24,  19-Nov-80 12:22:18 by MURPHY
;IN SECMAP - REMEMBER FORKX OF FORK OWNING PRIVATE PAGE
; UPD ID= 1220, SNARK:<5.MONITOR>PAGEM.MAC.23,   2-Nov-80 11:48:23 by HALL
;MORE ON TCO 5.1180 - REMOVE SE1CAL'S FROM SWPOML,GCCOR,REMFPA,DDMP --
;MADE POSSIBLE BY RUNNING SCHED0, GSMDX, AND CHKR IN SECTION 1
; UPD ID= 1219, SNARK:<5.MONITOR>PAGEM.MAC.22,  31-Oct-80 16:58:19 by HALL
;MORE ON TCO 5.1180 - MAKE REMFPA ENTER SECTION 1 BECAUSE EXEC0 CALLS IT
;	VIA SETMPG
; UPD ID= 1209, SNARK:<5.MONITOR>PAGEM.MAC.21,  29-Oct-80 14:24:37 by MURPHY
;DITTO
; UPD ID= 1206, SNARK:<5.MONITOR>PAGEM.MAC.20,  28-Oct-80 17:35:14 by MURPHY
;FIX VERY OLD BUG WITH PM%ABT (IN REMFP1)
; UPD ID= 1200, SNARK:<5.MONITOR>PAGEM.MAC.19,  26-Oct-80 16:59:30 by HALL
;MORE ON TCO 5.1180 -- ADD RETURN TO SETDST
; UPD ID= 1194, SNARK:<5.MONITOR>PAGEM.MAC.18,  25-Oct-80 12:14:45 by HALL
;TCO 5.1180 - MOVE DST TO NON-ZERO SECTION
;	MAKE ALL CALLERS OF GDSTX EXPECT IT TO RETURN AN ADDRESS RATHER THAN AN
;		OFFSET
;	GCCOR - ENTER SECTION 1
;	DDMP - ENTER SECTION 1
;	ADDED SETDST TO SET UP PAGE MAP AND DSTLOC
;	TEMPORARILY MAKE SWPOML DO SE1CAL
; UPD ID= 1137, SNARK:<5.MONITOR>PAGEM.MAC.17,   7-Oct-80 11:50:55 by HALL
;ASFSB - CHANGE ACVAR TO SAVEAC
; UPD ID= 1104, SNARK:<5.MONITOR>PAGEM.MAC.16,   2-Oct-80 09:28:17 by MURPHY
;DITTO
; UPD ID= 1089, SNARK:<5.MONITOR>PAGEM.MAC.15,   1-Oct-80 12:13:57 by MURPHY
;FIX ACVAR
; UPD ID= 1013, SNARK:<5.MONITOR>PAGEM.MAC.14,  13-Sep-80 16:11:29 by HALL
;MAKE PGRTRP RUN IN SECTION 1
;	CLEAR LEFT HALF OF INDEX REGISTERS
;	DO SECTION-RELATIVE JRST AT TRPRST
;	IN XGCCHK, START PROCESS AT PGRTRP IN SECTION 1
; UPD ID= 990, SNARK:<5.MONITOR>PAGEM.MAC.13,   4-Sep-80 18:42:53 by ENGEL
;ADD TABSEC AS SECTION FOR MONITOR TABLES
; UPD ID= 922, SNARK:<5.MONITOR>PAGEM.MAC.12,  20-Aug-80 09:40:34 by MURPHY
;Use open NOSKED/OKSKED in MULK1 because runs at interrupt level
; UPD ID= 912, SNARK:<5.MONITOR>PAGEM.MAC.11,  18-Aug-80 21:41:52 by MURPHY
;NOSKD1 required in MULK1 to prevent possuble SUMNR1, SUMNR2 bugchks
; UPD ID= 898, SNARK:<5.MONITOR>PAGEM.MAC.10,  14-Aug-80 10:36:21 by LYONS
;tco 5.1062 - change swppsb, swppt, swpptp, swpupt into delayed bugchk
; UPD ID= 880, SNARK:<5.MONITOR>PAGEM.MAC.9,  12-Aug-80 16:16:33 by MURPHY
;Private page count; fix INTDF checks at ILRF
; UPD ID= 810, SNARK:<5.MONITOR>PAGEM.MAC.8,  30-Jul-80 10:53:25 by MURPHY
;ADD CHECK OF WEFLAG - 1=DON'T WRITE-PROTECT RES MON
; UPD ID= 809, SNARK:<5.MONITOR>PAGEM.MAC.7,  30-Jul-80 10:34:49 by HALL
;IN PGRINI, IF DBUGSW=1, WRITE-PROTECT THE RESIDENT CODE
; UPD ID= 614, SNARK:<5.MONITOR>PAGEM.MAC.6,   6-Jun-80 16:56:18 by KONEN
;TCO 5.1061 - Add call to STROFL from DDMP to see if structure off-line
; UPD ID= 510, SNARK:<5.MONITOR>PAGEM.MAC.5,   7-May-80 20:47:07 by ENGEL
;ADD THE LCS SECTIN DEFINITIONS
; UPD ID= 420, SNARK:<5.MONITOR>PAGEM.MAC.4,  11-Apr-80 13:50:55 by HALL
;CHANGES TO WRITE-PROTECT THE RESIDENT MONITOR:
;	ADD RSDAT PSECT TO PGRINI (CREATE ENTRY IN MMAP, LOCK PAGE IN
;	MEMORY, AND ADD RSDAT TO DDT'S ALTERNATE MAP)
; UPD ID= 407, SNARK:<5.MONITOR>PAGEM.MAC.3,   3-Apr-80 16:15:37 by HALL
;CHANGES TO WRITE-PROTECT THE RESIDENT MONITOR:
;	NEW ENTRY TO PGRIGR TO SET UP MAP WRITE-PROTECTED
;	PGRINI - SET UP RSCOD WRITE-PROTECTED IF DBUGSW IS 2
;	MAKE SWPMWP WRITE-PROTECT RSCOD, TOO
; UPD ID= 289, SNARK:<4.1.MONITOR>PAGEM.MAC.199,  21-Feb-80 10:58:45 by MURPHY
;NEW FKINT BIT DEFS
; UPD ID= 221, SNARK:<4.1.MONITOR>PAGEM.MAC.198,  24-Jan-80 16:11:19 by HALL
;repeat 0 around code at upgbpp because it wasn't called
; UPD ID= 212, SNARK:<4.1.MONITOR>PAGEM.MAC.197,  21-Jan-80 12:34:44 by HALL
;BUGHLT'S UBANXM AND ILMNRF - FIX NAMES OF OPTIONAL DATA
; UPD ID= 208, SNARK:<4.1.MONITOR>PAGEM.MAC.196,  18-Jan-80 09:18:56 by ENGEL
;CORRECT COUNT AT ASOF6A+1
;<4.1.MONITOR>PAGEM.MAC.195, 12-Nov-79 17:24:14, EDIT BY MURPHY
;NEW SWAP SPACE LEVEL FOR NEW JOB CUTOFF
;<4.MONITOR>PAGEM.MAC.194,  5-Nov-79 12:45:09, EDIT BY MILLER
;tco 4.2562. FIX PROBLEM IN MVPT THAT CASUES PTNIC1 BUGHLTS
;<4.MONITOR>PAGEM.MAC.193,  3-Nov-79 08:23:30, EDIT BY R.ACE
;ADD CHKMPS ROUTINE
;<4.MONITOR>PAGEM.MAC.192,  3-Nov-79 07:15:50, EDIT BY R.ACE
;ADD OKSKED AND CALL RELCPT TO ERROR-EXIT FROM SECMAP
;<4.MONITOR>PAGEM.MAC.191, 29-Oct-79 14:01:48, EDIT BY MILLER
;CODE AT RELP3 THAT HANDLES WIP MUST BE OKSKED BEFORE LOOPING
; BACK TO RELP6.
;<4.MONITOR>PAGEM.MAC.190, 26-Oct-79 17:33:16, EDIT BY MILLER
;BE NOINT WHILE DDMP IS RUNNING SO PAGE CREATES WILL ALWAYS WORK
;<4.MONITOR>PAGEM.MAC.189, 24-Oct-79 17:09:10, EDIT BY MURPHY
;TRPDSP
;<4.MONITOR>PAGEM.MAC.187, 23-Oct-79 12:28:14, EDIT BY MURPHY
;NEW APSKED CALL
;<4.MONITOR>PAGEM.MAC.186, 22-Oct-79 11:41:02, EDIT BY MURPHY
;EXT ADR, AND FIX PROBLEM AT ILRF
;<4.MONITOR>PAGEM.MAC.185,  9-Oct-79 09:51:42, EDIT BY MILLER
;CHECK FOR CSTPST=PSTERR IN SWPOUT. IF SO, DON'T SWAP PAGE
;<4.MONITOR>PAGEM.MAC.184, 11-Sep-79 16:54:34, EDIT BY MURPHY
;FIX XGAGE BUGS
;<OSMAN.MON>PAGEM.MAC.1, 10-Sep-79 15:56:16, EDIT BY OSMAN
;TCO 4.2412 - Move definition of BUGHLTs, BUGCHKs, and BUGINFs to BUGS.MAC
;<4.MONITOR>PAGEM.MAC.182, 29-Aug-79 15:20:04, EDIT BY MURPHY
;REMOVE ILMADR, BADBTB BUGHLTS.
;<4.MONITOR>PAGEM.MAC.181, 29-Aug-79 15:00:09, EDIT BY MILLER
;CHECK FOR LON FILE XB IN ASGOFN WITH ENTTYP
;<4.MONITOR>PAGEM.MAC.180, 29-Aug-79 12:00:01, EDIT BY HEMPHILL
;TCO 4.2428  ARTIFICIALLY INCREMENT THE OFN SHARE COUNT THAT DDMP IS WORKING ON
;<4.MONITOR>PAGEM.MAC.179, 28-Aug-79 16:50:24, EDIT BY MURPHY
;ADD XGAGE HANDLING; REMOVE SECGXX BUGHLTS AND IMPROVE ILLEG REF HANDLING
;<4.MONITOR>PAGEM.MAC.178, 28-Aug-79 13:47:37, EDIT BY MURPHY
;FIX PGRIG4+3 TO SETUP CST2 CORRECTLY
;<4.MONITOR>PAGEM.MAC.177, 17-Aug-79 03:40:29, EDIT BY GILBERT
;TCO 4.2408:  MAP NPVAR PSECT IN SYMBOL ADDRESS SPACE.
;<4.MONITOR>PAGEM.MAC.176, 16-Aug-79 13:44:08, EDIT BY OSMAN
;CHANGE RELBAD TO RLBAD SO IT DOESN'T CONFLICT WITH RELBAD BUGCHK IN FREE
;<4.MONITOR>PAGEM.MAC.175, 14-Aug-79 15:07:27, EDIT BY HALL
;MAKE SECMAP HANDLE DELETING PRIVATE SECTIONS
;<4.MONITOR>PAGEM.MAC.174, 12-Aug-79 19:14:14, EDIT BY GILBERT
;TCO 4.2388: DELETE ALL REFERENCES TO SWPCOR.
;PUT PAGES IN GAPS BETWEEN PSECTS ONTO THE RPLQ IN PGRINI.
;<4.MONITOR>PAGEM.MAC.173, 11-Aug-79 08:07:45, EDIT BY HALL
;CHANGES FOR USER MODE EXTENDED ADDRESSING - IN RELMPG, EXPECT
;CALLER TO BE LAST UNSHARER OF PAGE TABLE
;ADD SCNPT TO CLEAR POINTERS IN A PAGE TABLE
;<4.MONITOR>PAGEM.MAC.172,  1-Aug-79 15:53:03, EDIT BY MURPHY
;FIX FOR FIGURE 6 SWAPOUT LIST (CMU) XGCRK+20 APPROX
;<4.MONITOR>PAGEM.MAC.171, 26-Jul-79 11:06:35, EDIT BY MILLER
;CHANGE FRCSPM TO DO RANGE CHECK CORRECTLY
;<4.MONITOR>PAGEM.MAC.170, 17-Jul-79 16:26:16, Edit by KONEN
;SET UP FX FOR SETSP6 IN FNDLDA TO AVOID SECG37 BUGHLT
;<4.MONITOR>PAGEM.MAC.169, 16-Jul-79 14:10:44, EDIT BY HALL
;SECMAP - FIX TYPO
;<4.MONITOR>PAGEM.MAC.168, 13-Jul-79 16:15:30, EDIT BY HALL
;SECMAP - CREATE PRIVATE SECTIONS
;<4.MONITOR>PAGEM.MAC.167,  3-Jun-79 14:47:39, EDIT BY MILLER
;BE SURE TO TURN OFF FPD WHEN ILLEGAL MEM REFERENCE EXITS.
;<4.MONITOR>PAGEM.MAC.166,  1-Jun-79 14:07:29, EDIT BY DBELL
;TCO 4.2266 - CREATE OLD STYLE PC FOR MODEL A'S IN XGCCHK.
;<4.MONITOR>PAGEM.MAC.165, 12-May-79 13:28:49, EDIT BY MILLER
;USE LESS STACK IN AGECKN
;<4.MONITOR>PAGEM.MAC.164, 10-May-79 12:38:02, EDIT BY MILLER
;FIX CODE AT RELP4 AGAIN
;<4.MONITOR>PAGEM.MAC.163,  4-May-79 12:52:09, EDIT BY MILLER
;REMOVE SETZM AT RELP4. DOESN'T APPEAR TO BE NEEDED, AND
; IS A BUG THE WAY IT IS NOW CODED
;<4.MONITOR>PAGEM.MAC.162,  4-May-79 12:04:52, EDIT BY MILLER
;CHECK FOR REG REFERENCE AT GETTPD
;<4.MONITOR>PAGEM.MAC.161, 28-Mar-79 11:11:13, EDIT BY ENGEL
;CHKLAC ERROR - CHECK AGAINST ACCESS REQUESTED
;<4.MONITOR>PAGEM.MAC.160, 23-Mar-79 15:57:38, EDIT BY MURPHY
;CHECK DRMTPG AT GCCOR
;<4.MONITOR>PAGEM.MAC.159, 15-Mar-79 10:46:52, EDIT BY MILLER
;CHECK FOR INNER XB AROUND ASOF5 AND IF SO, DON'T CHECK ACCESS
;<4.MONITOR>PAGEM.MAC.158,  6-Mar-79 14:13:53, EDIT BY MILLER
;MAKE GPAC INTERNAL
;<4.MONITOR>PAGEM.MAC.157,  5-Mar-79 19:38:33, EDIT BY BOSACK
;REPLACE DELETED PGRON IN PGRINI
;<4.MONITOR>PAGEM.MAC.156,  4-Mar-79 18:45:44, EDIT BY KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
;<4.MONITOR>PAGEM.MAC.155, 27-Feb-79 10:30:35, EDIT BY HALL
;SOSWSP - ADD OPTIONAL DATA (FORK NUMBER, WSP) TO BUGCHK WSPNEG
;<4.MONITOR>PAGEM.MAC.154, 19-Feb-79 23:23:37, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.153, 19-Feb-79 15:48:26, EDIT BY ENGEL
;ENSURE ENTTYP IS CORRECT FOR ASGOFP
;<4.MONITOR>PAGEM.MAC.152, 13-Feb-79 17:58:28, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.151,  4-Feb-79 23:41:42, EDIT BY MURPHY
;PERFORMANCE TUNING; FIX CORE-DEPENDENT VARIABLES
;<4.MONITOR>PAGEM.MAC.150,  1-Feb-79 10:04:20, EDIT BY MILLER
;REMOVE NOSKD1 AND OKSKD1 FROM FRCRRM. CALL IT NOSKED ALWAYS
;<4.MONITOR>PAGEM.MAC.149, 30-Jan-79 12:38:21, EDIT BY MILLER
;CHANGE TRP0B TO GO TO TRPRST IF AGE IS ON SPMQ
;<4.MONITOR>PAGEM.MAC.148, 29-Jan-79 17:16:38, EDIT BY MURPHY
;MAKE SYMBAS AND MMSPTN LOCK COUNTS CORRECT
;<4.MONITOR>PAGEM.MAC.147, 29-Jan-79 10:39:06, EDIT BY MILLER
;FIX PIPTRP TO FETCH PROPER PAGE FAIL WORD
;<4.MONITOR>PAGEM.MAC.146, 29-Jan-79 03:57:04, EDIT BY DBELL
;CHANGE SYMBOL HIDING SETUP TO SET UP HSYBLK AND HSYSWP INSTEAD OF SYMEPT
;<4.MONITOR>PAGEM.MAC.145, 22-Jan-79 16:12:47, EDIT BY ENGEL
;ADD ASGOFP FOR ASSIGNING PAGE TABLE TABLE'S (PART OF LONG FILE BUG FIX)
;<4.MONITOR>PAGEM.MAC.144, 19-Jan-79 18:25:34, EDIT BY MURPHY
;XGC REVISIONS
;<4.MONITOR>PAGEM.MAC.141, 15-Jan-79 08:27:17, EDIT BY GILBERT
;TCO 4.2162: Don't set PA%CPY in RPACS% unless no write-locked ptrs seen.
;<4.MONITOR>PAGEM.MAC.140, 15-Jan-79 07:45:21, EDIT BY GILBERT
;More TCO 4.2155:
;	Make BSMGP/BSMGG always handle the right number of pages.
;	Clear access bits from pointer before setting up HSYPAG.
;<4.MONITOR>PAGEM.MAC.139, 10-Jan-79 18:12:12, EDIT BY GILBERT
;Correct usage of HSYPAG in LCKINI
;<4.MONITOR>PAGEM.MAC.138,  9-Jan-79 07:00:37, EDIT BY GILBERT
;Make MRPAC% JSYS complain about very large illegal addresses.
;<4.MONITOR>PAGEM.MAC.137,  8-Jan-79 06:54:09, EDIT BY GILBERT
;TCO 4.2155 - Implement hidden symbol tables:
;	Make PGRINI understand how to hide the symbol table.
;	Move several paging-related routines here from MEXEC.
;	Fix several assumptions about PSECT ordering.
;<4.MONITOR>PAGEM.MAC.136,  5-Jan-79 12:46:39, EDIT BY MURPHY
;HANDLE READ COMPLETED PAGES IN GCCOR
;REMOVE PUFLD, USE FORK IDENT IN CST0; USE SRPLQ ONLY
;<4.MONITOR>PAGEM.MAC.133, 20-Dec-78 14:18:35, EDIT BY MILLER
;CHANGE SETSSP TO NEVER COUNT PAGES IN EXCESS OF 512K
;<4.MONITOR>PAGEM.MAC.132, 13-Dec-78 15:58:05, EDIT BY MILLER
;FIX FRCRMP AND FRCRRM TO HANDLE LOCKED RESIDENT PAGES CORRECTLY
;<4.MONITOR>PAGEM.MAC.131, 11-Dec-78 22:02:22, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.130,  7-Dec-78 16:51:29, EDIT BY DBELL
;TCO 4.2113 - USE RIGHT AC AT ASOF4+1
;<4.MONITOR>PAGEM.MAC.129,  7-Dec-78 14:29:42, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.128,  6-Dec-78 12:16:33, EDIT BY MURPHY
;DON'T BE NOSKED WHEN ITRSIM IS CALLED. PREVENTS KEEP ALIVE CEASURE.
;<4.MONITOR>PAGEM.MAC.126, 10-Nov-78 17:36:36, EDIT BY BOSACK
;<4.MONITOR>PAGEM.MAC.125,  3-Nov-78 16:56:47, EDIT BY MURPHY
;<MURPHY.MON>PAGEM.MAC.10,  6-Dec-78 12:15:44, EDIT BY MURPHY
;NEW SWAP LOGIC
;<4.MONITOR>PAGEM.MAC.124, 25-Oct-78 16:43:39, EDIT BY DBELL
;TCO 4.2065 USE RIGHT ERROR CODE AT SETP5 WHEN SPT SHARE COUNT IS FULL
;<4.MONITOR>PAGEM.MAC.123, 24-Oct-78 18:51:22, EDIT BY MILLER
;FIX RELBAD TO OUTPUT OFN. FIX RELOFN TO UNLOCK OFN IF SCNOFN FAILS
;<4.MONITOR>PAGEM.MAC.122, 24-Oct-78 13:31:08, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.121, 23-Oct-78 12:08:49, EDIT BY MILLER
;REMOVE ILRNSK BUGHLT
;<4.MONITOR>PAGEM.MAC.120,  6-Oct-78 16:15:35, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.114, 26-Sep-78 12:14:01, EDIT BY MILLER
;FIX CHECK ON NSKED AT ILRFX
;<MURPHY.MON>PAGEM.MAC.13, 22-Sep-78 16:25:17, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.113, 14-Sep-78 16:55:21, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.111, 14-Sep-78 13:13:42, EDIT BY MILLER
;FIX CHECK FOR NOINT AND ILRFX. BUGHLT IF ILLEGAL REF AND NOSKED
;<MURPHY.MON>PAGEM.MAC.5, 11-Sep-78 17:58:26, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.107, 30-Aug-78 15:41:11, EDIT BY MURPHY
;FIX POTENTIAL UNLOCK OF BAD PTR AT SETIOP+4
;<4.MONITOR>PAGEM.MAC.103, 28-Aug-78 07:59:23, EDIT BY MILLER
;FIX XGCCHK TO FORM PCS PROPERLY
;<4.MONITOR>PAGEM.MAC.102, 25-Aug-78 18:24:53, EDIT BY MURPHY
;GLOBAL PAGE AGING
;<2MCLEAN>PAGEM.MAC.94, 10-Aug-78 00:26:29, Edit by MCLEAN
;<2MCLEAN>PAGEM.MAC.93,  9-Aug-78 23:39:54, Edit by MCLEAN
;FORCE DIRECTORY CACHE FLUSH BEFORE CHECKING FOR OPEN OFN'S
;<MURPHY.MON>PAGEM.MAC.3, 25-Aug-78 14:19:46, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.99, 15-Aug-78 17:07:37, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.98, 15-Aug-78 11:35:23, EDIT BY MILLER
;LOAD AGE AT TRPSPM
;<4.MONITOR>PAGEM.MAC.96, 13-Aug-78 11:50:34, EDIT BY MILLER
;BE NOSKED IN SETPST WHEN CALLING OFRQ
;<4.MONITOR>PAGEM.MAC.95, 13-Aug-78 11:25:41, EDIT BY MILLER
;CHECK IN OFFSPQ FOR MANGLED SPMQ
;<4.MONITOR>PAGEM.MAC.94, 12-Aug-78 16:03:16, EDIT BY MILLER
;<4.MONITOR>PAGEM.MAC.93, 12-Aug-78 15:59:36, EDIT BY MILLER
;FIX CODE AT NIC TO CLEAR UNASSIGNED ADDRESS
;<4.MONITOR>PAGEM.MAC.92,  9-Aug-78 13:52:55, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.91,  9-Aug-78 13:50:20, EDIT BY MILLER
;ADD ADDITIONAL DATA TO UBANXM BUGHLT
;<4.MONITOR>PAGEM.MAC.90,  9-Aug-78 07:52:10, EDIT BY MILLER
;FIX CODE AT FRCSP3 TO BE NOSKED
;<4.MONITOR>PAGEM.MAC.89,  8-Aug-78 16:32:23, EDIT BY MILLER
;BE SURE PAGE IS NOT ON RPLQ AT BADCPG
;<4.MONITOR>PAGEM.MAC.88,  8-Aug-78 11:16:14, EDIT BY MILLER
;FIX CODE AT BKUP3 THAT LOOKS FOR THE OFN
;<4.MONITOR>PAGEM.MAC.87,  3-Aug-78 17:44:35, EDIT BY MILLER
;MAKE SURE OFNWRB IS SET IN THE OFN WHEN DSKNB PAGE IS SWAPPED OUT
;<4.MONITOR>PAGEM.MAC.86,  3-Aug-78 07:58:24, EDIT BY MILLER
;<4.MONITOR>PAGEM.MAC.85,  1-Aug-78 13:42:56, EDIT BY MILLER
;ADD SWPIN4 FOR FAST GET
;<4.MONITOR>PAGEM.MAC.84, 31-Jul-78 12:18:51, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.83, 31-Jul-78 11:41:29, EDIT BY MILLER
;<4.MONITOR>PAGEM.MAC.82, 31-Jul-78 11:39:14, EDIT BY MILLER
;ADD MUPSHR
;<4.MONITOR>PAGEM.MAC.81, 31-Jul-78 11:11:41, EDIT BY MILLER
;DON'T UPDATE OFN IN RELOFN IF NOT THE FINAL CLOSE
;<4.MONITOR>PAGEM.MAC.80, 27-Jul-78 10:45:57, EDIT BY MILLER
;<4.MONITOR>PAGEM.MAC.79, 27-Jul-78 08:47:58, EDIT BY MILLER
;REMOVE NEW CODE FROM RELCXB FOR NOW
;<4.MONITOR>PAGEM.MAC.78, 26-Jul-78 11:22:11, EDIT BY MILLER
;DON'T COUNT PAGES ON SPMQ IN BSHC1 DURING GCCOR
;<4.MONITOR>PAGEM.MAC.77, 26-Jul-78 10:37:03, EDIT BY MILLER
;FIX UP NEW RPLQ CODE. MAKE IT SLIGHTLY MORE EFFICIENT
;<4.MONITOR>PAGEM.MAC.76, 26-Jul-78 10:20:07, EDIT BY MILLER
;FIX RPLQ LOGIC TO ALWAYS PUT XB PAGE ON TAIL OF DRLPQ
;<4.MONITOR>PAGEM.MAC.75, 26-Jul-78 07:27:12, EDIT BY MILLER
;CALL ADJSWP FROM NICCKS IF PAGES ADDED OR DELETED RECENTLY
;<4.MONITOR>PAGEM.MAC.72, 25-Jul-78 10:35:10, EDIT BY MILLER
;MORE
;<4.MONITOR>PAGEM.MAC.71, 25-Jul-78 10:08:02, EDIT BY MILLER
;FIX UP HANDLING A "HOLES" IN MEMORY
;<4.MONITOR>PAGEM.MAC.70, 24-Jul-78 08:01:31, EDIT BY MILLER
;FIX CODE AT NICCKS TO CORRECTLY COMPUTE SYSTEM FREE PAGES
;<4.MONITOR>PAGEM.MAC.69, 20-Jul-78 18:24:44, EDIT BY MILLER
;FIX BAD TEST FOR DELOF AT RELOF7
;<4.MONITOR>PAGEM.MAC.68, 20-Jul-78 15:05:47, EDIT BY MILLER
;UPDOFI HAS TO CHECK UPDOFI
;<4.MONITOR>PAGEM.MAC.67, 19-Jul-78 15:24:47, EDIT BY MILLER
;MORE EDITS FOR RELOFN
;<4.MONITOR>PAGEM.MAC.66, 19-Jul-78 15:18:34, EDIT BY MILLER
;FIX UP TO UPDOFI
;<4.MONITOR>PAGEM.MAC.65, 19-Jul-78 15:09:19, EDIT BY MILLER
;<4.MONITOR>PAGEM.MAC.64, 19-Jul-78 15:04:49, EDIT BY MILLER
;FIX UP RELOFN
;<4.MONITOR>PAGEM.MAC.63, 18-Jul-78 15:06:15, EDIT BY MURPHY
;SEPARATE RPLQ INTO SWAP RPLQ AND DISK RPLQ (SRPLQ, DRPLQ)
;<4.MONITOR>PAGEM.MAC.60, 14-Jul-78 12:11:45, EDIT BY MILLER
;FIX UP MRPAC JSYS TO HANDLE ANY SECTION
;<4.MONITOR>PAGEM.MAC.59, 13-Jul-78 13:50:10, EDIT BY MILLER
;FIX CHECK ON NSSUN. IT WAS BACKWARDS
;<3A.MONITOR>PAGEM.MAC.689, 12-Jul-78 17:37:51, EDIT BY MILLER
;CHECK FOR IMMEDIATE POINTER IN ULDPAG
;<4.MONITOR>PAGEM.MAC.57, 12-Jul-78 17:06:33, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.56, 11-Jul-78 16:43:44, EDIT BY MILLER
;FIX CODE AT ILWR
;<4.MONITOR>PAGEM.MAC.55, 10-Jul-78 11:59:19, EDIT BY MILLER
;FIX TYPEO
;<4.MONITOR>PAGEM.MAC.54, 10-Jul-78 11:28:11, EDIT BY MILLER
;TCO 1937. IMPLEMENT "NO WAIT" IN UFPGS
;<4.MONITOR>PAGEM.MAC.53, 10-Jul-78 07:34:19, EDIT BY MILLER
;CHECK FOR WRITE ACCESS IN PAGE POINTER AT RELMP5 IN ORDER TO DO ABORT
;<4.MONITOR>PAGEM.MAC.52,  9-Jul-78 14:26:30, EDIT BY MILLER
;REMOVE CODE AT SWPIK THAT TURNS OFF DSKNB.
;<4.MONITOR>PAGEM.MAC.51,  9-Jul-78 13:14:40, EDIT BY MILLER
;MORE FIXES FOR ABORT UNMAP
;<4.MONITOR>PAGEM.MAC.50,  8-Jul-78 16:13:25, EDIT BY MILLER
;MORE...
;<4.MONITOR>PAGEM.MAC.49,  8-Jul-78 15:49:14, EDIT BY MILLER
;MORE FIXES FOR "ABORT" UNMAP.
;<4.MONITOR>PAGEM.MAC.48,  8-Jul-78 15:37:02, EDIT BY MILLER
;FIX UP CODE AR RELMI1 TO CHECK FOR SHARE OR IMMEDIATE POINTER IN OFN
;<4.MONITOR>PAGEM.MAC.47,  8-Jul-78 14:27:05, EDIT BY MILLER
;TCO 1934 (AS PROMISED). CHECK PM%ABT FOR "ABORT" UNMAP
;<4.MONITOR>PAGEM.MAC.46,  8-Jul-78 13:56:45, EDIT BY MILLER
;CLEAN UP LISTING. MAKE MINOR EDITS TO NEW "ABORT" CODE
;<4.MONITOR>PAGEM.MAC.45,  8-Jul-78 13:15:11, EDIT BY MILLER
;MAKE ALL CALLERS OF RELMPG AND RELMP5 LOAD ACCESS FLAGS INTO T3
;<4.MONITOR>PAGEM.MAC.44,  8-Jul-78 12:58:28, EDIT BY MILLER
;FIX UP NEW CODE AT RELMP5.
;<4.MONITOR>PAGEM.MAC.43,  7-Jul-78 17:57:24, EDIT BY MILLER
;ADD CODE TO RELMP5 TO DO "ABORT" UNMAP. REST OF CODE (AND TCO) TO FOLLOW)
;<4.MONITOR>PAGEM.MAC.42,  7-Jul-78 14:18:54, EDIT BY MILLER
;ALLOCATE A BIT IN UPDPGS LOCAL FLAGS FOR "NO WAIT FOR WRITE"
;<4.MONITOR>PAGEM.MAC.41, 30-Jun-78 16:41:27, EDIT BY MURPHY
;<4.MONITOR>PAGEM.MAC.37, 22-Jun-78 14:50:07, EDIT BY MILLER
;LOCK STRLOK AT DDMP
;<4.MONITOR>PAGEM.MAC.36, 20-Jun-78 16:07:25, EDIT BY BOSACK
;<4.MONITOR>PAGEM.MAC.35, 20-Jun-78 12:39:22, EDIT BY MILLER
;FIX UP XJRSTFS THAT SET PCU TO PRESEVE ALL OTHER PC FLAGS
;<4.MONITOR>PAGEM.MAC.34, 20-Jun-78 02:33:25, EDIT BY BOSACK
;<4.MONITOR>PAGEM.MAC.33, 20-Jun-78 02:13:52, EDIT BY BOSACK
;<4.MONITOR>PAGEM.MAC.32, 20-Jun-78 00:55:04, EDIT BY BOSACK
;<1BOSACK>PAGEM.MAC.1001,  5-Jun-78 21:37:56, EDIT BY BOSACK
;<1BOSACK>PAGEM.MAC.1000,  5-Jun-78 19:23:50, EDIT BY BOSACK
;<3A.MONITOR>PAGEM.MAC.686, 13-Jun-78 08:22:51, EDIT BY MILLER
;CHANGE CODE AT NGP1 TO CHECK FOR NOINT MONITOR CORRECTLY
;<4.MONITOR>PAGEM.MAC.29,  1-Jun-78 13:55:16, EDIT BY MILLER
;DECLARE CLRMPE AS EXTERNAL
;<3A.MONITOR>PAGEM.MAC.684,  1-Jun-78 12:46:12, EDIT BY MILLER
;ADD CALL MEMSTR AFTER ALL MEMORY IS FOUND
;<4.MONITOR>PAGEM.MAC.27,  1-Jun-78 11:45:43, EDIT BY MILLER
;MAKE SURE PGRINI CLEARS PARITY ERRORS
;<3A.MONITOR>PAGEM.MAC.681, 30-May-78 08:12:28, EDIT BY MILLER
;FIX FRCRMP SO NRPLQ IS MAINTAINED PROPERLY
;<3A.MONITOR>PAGEM.MAC.680, 26-May-78 16:12:02, EDIT BY MILLER
;FIX CODE AT NPG THAT CHECKS NOINT. BE SURE PC IS IN MONITOR
;<4.MONITOR>PAGEM.MAC.24, 16-May-78 14:33:53, EDIT BY MURPHY
;<3A.MONITOR>PAGEM.MAC.679, 14-May-78 14:27:43, EDIT BY MILLER
;FIX AT RELP4. CLEAR MAPPING AT APPROPRIATE TIME
;<3A.MONITOR>PAGEM.MAC.678,  4-May-78 12:04:09, EDIT BY MILLER
;DON'T BE NOSKED WHILE GETTING IN XB IN ASGOFN
;<MURPHY.MON>PAGEM.MAC.22, 16-May-78 13:16:19, EDIT BY MURPHY
;TCO #1904 - WORKING SET SWAPPING
;<4.MONITOR>PAGEM.MAC.21, 19-Apr-78 16:58:23, EDIT BY MILLER
;CLEAR PAGER IN MSPACS
;<4.MONITOR>PAGEM.MAC.20,  7-Apr-78 21:44:12, Edit by BORCHEK
;DO NOT DO SETUP IF ANBSEC=0
;<4.MONITOR>PAGEM.MAC.19,  5-Apr-78 12:25:09, EDIT BY MILLER
;FIX TYPEO IN SETPST
;<3A.MONITOR>PAGEM.MAC.674,  4-Apr-78 13:25:46, EDIT BY MILLER
;MAKE SETPST RETURN PREVIOUS STATE. ADD LODPPS TO DECLARE SPECIAL
;PREVIOUS STATE
;<4.MONITOR>PAGEM.MAC.17, 23-Mar-78 08:19:59, EDIT BY MILLER
;CHANGE NAME OF ASLOFN TO ASGOFL
;<3A.MONITOR>PAGEM.MAC.672, 23-Mar-78 08:12:46, EDIT BY MILLER
;MERGE ASLOFN INTO ASGOFN. MAKE CODE AS "SMART" AS POSSIBLE
;<3A.MONITOR>PAGEM.MAC.671, 16-Mar-78 09:28:34, EDIT BY MILLER
;WHEN ALL OFN'S EXHAUSTED, TRY FREEING "UNSHARED" ONES
;<3A.MONITOR>PAGEM.MAC.670,  3-Mar-78 15:29:11, EDIT BY MILLER
;SCAN OFN AT RELMI1 IF SHARE COUNT IS ZERO
;<3A.MONITOR>PAGEM.MAC.669,  3-Mar-78 12:20:52, Edit by MCLEAN
;<4.MONITOR>PAGEM.MAC.12,  3-Mar-78 12:14:15, EDIT BY MILLER
;REMOVE "STRUCTURE" CHECK FROM QCHK. MOVED TO DSKASN
;<4.MONITOR>PAGEM.MAC.11,  3-Mar-78 11:28:44, EDIT BY MILLER
;DON'T CHECK SYSSPC IN QCHK IF NOT PS
;<4.MONITOR>PAGEM.MAC.10,  1-Mar-78 08:21:08, EDIT BY MILLER
;REMOVE CHECK AT PGTCA. NOT NEEDED
;<4.MONITOR>PAGEM.MAC.9, 28-Feb-78 16:04:40, EDIT BY MILLER
;CHECK FOR DISMOUNTED OFN IN PGTCAL
;<4.MONITOR>PAGEM.MAC.8, 28-Feb-78 15:26:32, EDIT BY MILLER
;RELEASE ALOC ENTRY IN INVOFN
;<4.MONITOR>PAGEM.MAC.7, 17-Feb-78 09:29:32, EDIT BY MILLER
;PASS CP FLAGS TO ITRSIM AT ILRFU
;<4.MONITOR>PAGEM.MAC.6, 16-Feb-78 13:31:04, EDIT BY MILLER
;MODIFY SECMAP SO IT WILL BUILD INDIRECT SECTION POINTERS
;<4.MONITOR>PAGEM.MAC.5, 14-Feb-78 15:02:32, EDIT BY MILLER
;FIX SECJFN TO RETURN BOTH OFN AND JFN
;<4.MONITOR>PAGEM.MAC.4, 13-Feb-78 13:22:12, EDIT BY MILLER
;FIX UP SECTION MAPPING ROUTINES
;<4.MONITOR>PAGEM.MAC.3, 13-Feb-78 08:08:40, EDIT BY MILLER
;FIX CHKMAP TO TEST FOR PRIVATE SECTION
;<4.MONITOR>PAGEM.MAC.2, 11-Feb-78 11:03:28, EDIT BY MILLER
;FIX TYPEOS
;<4.MONITOR>PAGEM.MAC.1, 11-Feb-78 10:51:01, EDIT BY MILLER
;ADD SUPPRT ROUTINE FOR USER SECTION MAPPING
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

	SEARCH PROLOG
	TTITLE PAGEM

EXTN <LCSSEC,TABSEC,SPCRES,MEMSTR,CLRMPE,NXTAJB>
DEFAC (FX,Q3)			;FORK INDEX

;STORAGE

RS BTSTRT,1			;START OF BITTABLE
RS BTEND,1			;END OF BITTABLE
RS PAGDIF,1			;COUNT OF NEW PAGES IN THE SYSTEM
RS NHIPG,1			;HIGEST PAGE USED BY SWAPPER
RS SPTC,1			;COUNT OF SPT (EXCLUDING OFN) ENTRIES IN SPT
RS NOF,1			;COUNT OF ENTRIES IN OFN PART OF SPT
RS FRESPT,1			;FREE SPT LIST
RS MAXSPL,1			;MAX NUMBER OF PROBES TO SPTH
RS MMSPTN,1			;OFN OF MONITOR MAP
RS LOKPGS,1			;COUNT OF LOCKED PAGES, VIA MLKPG
RS LOKSUM,1			;NET NUMBER OF LOCKS, MLKPG-MULKPG
RS DDTIME,1			;TIME NEXT DDMP DUE
RS IOIP,1			;SWAP WRITES IN PROGRESS
RS DRMIN0,1			;DRUM SPACE LEVEL FOR DDMP ACTION
RS DRMIN1,1			;DRUM SPACE LEVEL FOR NO NEW JOBS
RS DRMLV0,1			;DRUM SPACE LEVEL FOR NO NEW PRIV PAGES
RS PRELRQ,1			;PRELOADING SWAPIN IF NON-0
RS DELPGQ,1			;QUEUE OF DELETED PAGES
RS JOBBAS,1			;JOB BASE (SPT INDEX)
RS PSBBAS,1			;FORK BASE (SPT INDEX)
RS BTBBAS,1			;BIT TABLE BASE
RS SYMBAS,1			;HIDDEN SYMBOL TABLE MAP SPT INDEX
RS NBADCP,1			;NUMBER CORE PAGES DECLARED BAD
RS BSHC1,1			;GCCOR - NEW BALSHC

RS BSHC2,1			;GCCOR - DESCRETIONARY SHARED PAGES
RS GCCLPG,1			;GCCOR - LAST PAGE COLLECTED
RS NSWAPF,1			;NO SWAPPING IF NON-0
;**;[2958]  Add 1 line after RS NSWAPF,1		DML	4-MAY-83
RS INFTMR,1			;[2958] TIME OF NEXT NOOFN BUGINF

;GLOBAL PAGE AGE VALUES

RS CURAGE,1			;CURRENT VALUE FOR AGE
RS CUTAGE,1			;CUTOFF AGE FOR "OLD"
RS LSTAGE,1			;TIME (TODCLK) OF LAST GCCOR

;VARIABLES FOR SWPOM (SWPOMI, SWPOML, SWPOMG)

RS SWPLST,1			;LIST OF PAGES FOR SWAP
RS SWPLSI,1			;IN PTR TO SWAP LIST
RS SWPRC0,1			;COUNT OF PAGES ON LIST
RS SWPDAD,1			;NEXT SEQUENTIAL SWAP ADDRESS TO USE

SPC0::	EXP <SSPT-NOFN-3*NFKS>	;SPT LEVEL FOR USING INDIRECT PTRS
SPC1::	EXP SSPT-NOFN-100	;SPT LEVEL FOR NO NEW JOBS
SPC2::	EXP SSPT-NOFN-10	;SPT LEVEL FOR NO NEW FORKS

;AGE FIELD VALUES

LGATOP==1000			;LEGAL AGE "TOP"
LGABOT==100			;LEGAL AGE "BOTTOM"
AGEWRP==LGATOP-LGABOT		;WRAPAROUND OFFSET FOR AGE
;INDEX BLOCK DEFINTIONS

XBBAT==1B0			;BAT BIT
XBBWRD==4			;WORD FOR XBBAT

;CANONICAL POINTERS

IMMPTR::FLD(IMMCOD,PTRCOD)+PTWR+PTCACH
SHRPTR::FLD(SHRCOD,PTRCOD)+PTWR+PTCACH
INDPTR::FLD(INDCOD,PTRCOD)+PTWR+PTCACH


;BOUND PAIRS, CONTAINING FIRST PAGE ADDR,,LAST PAGE ADDR
;USED AS ARGUMENTS TO BSMGG/BSMGP

RSVABP:	RSVAR,,RSVARZ		;RESIDENT VARS
INCOBP:	INCOD,,INCODZ		;INIT CODE
RSDABP:	RSDAT,,RSDATZ		;RESIDENT DATA, NON-ZEROED
SYTBBP:	BLOCK 1			;SYMBOL TABLE - FILLED IN BY PGRINI
SWPMBP:	BLOCK 1			;SWAPPABLE MONITOR - FILLED IN BY PGRINI
	MAXIND==1000		;MAXIMUM INDIRECT POINTERS ALLOWED
				; BEFORE MONITOR GIVES UP

;BOUNDARY TO ARTIFICIALLY LIMIT CORE

NLOWPG:: 0			;PAGES BELOW HERE CONSIDERED NXM
NMAXPG:: MAXCOR-1		;PAGES ABOVE HERE CONSIDERED NXM

;ADMINISTRATIVE LIMIT OF PROGRAM (FORK) SIZE.  ACTUAL LIMIT MAY BE LOWER
;IF INSUFFICIENT CORE.  SYSTEM ADMINISTRATOR MAY ADJUST THIS PARAMETER
;TO LIMIT SIZE OF LARGE JOBS THEREBY ALLOWING MORE IN CORE.

PGMMAX:: MAXFKS			;FORK SIZE LIMIT SPECIFIED IN PARAMS

IPTIM::	IPTIMF			;FLAG FOR PAGE TRAP TIME FROM PARAMS

GCMIN0==^D64			;MIN PAGES FOR GCCOR TO COLLECT

NRPMX:	NFKSPP+2		;RPLQ MIN, SHOULD BE .G. MINNR

MONCOR::RSCODL+1		;NUMBER PAGES OF RES MON

;PARAMETERS FOR WORKING SET ADDRESS CACHE

WSCIDX==177000			;INDEX INTO CACHE - LOW ORDER 7 PAGE NUMBER BITS
WSCASS==37600000		;ASSOCIATIVE BITS - SECTION AND HIGH ORDER PAGE
WSCUSR==200			;USER/EXEC MODE BIT
WSCVAL==400			;VALID BIT
WSCFLD==777			;ONE FIELD IN CACHE

WSCNBF==<WID WSCFLD>		;SIZE OF FIELD
WSCNCW==:1B<35-<WID WSCIDX>>		;NUMBER OF CACHE WORDS

WSCVAM==0			;VALID MASK
WSCMS1==0			;LOW ORDER 1'S MASK
..X2==1B<WSCNBF-1>		;LEFT JUSTIFIED LOW ORDER 1
..X1==<WSCVAL>B<WSCNBF-1>	;LEFT JUSTIFIED WSCVAL
REPEAT ^D36/WSCNBF,<		;REPEAT FOR NUMBER FIELDS IN WORD
  WSCVAM=WSCVAM!..X1		;PUT VALID BIT IN ALL FIELDS
  WSCMS1=WSCMS1!..X2		;PUT 1 IN ALL FIELDS
  ..X1=..X1_-WSCNBF		;RIGHT SHIFT ONE FIELD
  ..X2=..X2_-WSCNBF
   >
;INITIALIZATION, SPT, CST, ETC.

PGRINI::
	SAVEAC <Q1>
	HRR T1,SWCEND		;BUILD SWPMON BOUND PAIR
	LSH T1,PGSFT
	HRLI T1,NRCOD
	MOVEM T1,SWPMBP		;STORE
	HLRE T1,.JBSYM		;BUILD BOUND PAIR TO SYMBOL TABLE
	MOVN T1,T1		;USED BY LCKINI/ULKINI
	ADD T1,.JBSYM		;POINT TO END OF SYMBOL TABLE
	SKIPN T1		;ANY SYMBOLS?
	MOVEI T1,SYVARZ+1	;NO, USE END OF SYVAR PSECT
	SUBI T1,1		;CONVERT FIRST FREE TO LAST USED
	ANDCMI T1,PGSIZ-1	;POINT TO START OF THAT PAGE
	HRLI T1,SYVAR		;FIRST ADDRESS IS BASE OF PSECT
	MOVEM T1,SYTBBP		;STORE BOUND PAIR FOR SYMBOLS
	SETZM SPTC
	SETZM NOF
	SETZM MAXSPL
	MOVEI T1,SPT+NOFN
	MOVEI T2,SSPT-NOFN
	CALL ILIST		;MAKE LIST OF FREE SPT ENTRIES
	MOVEM T1,FRESPT
	SETZM SPTH
	MOVE T1,[XWD SPTH,SPTH+1]
	BLT T1,SPTH+NOFN-1	;ZERO OUT SPTH
	CALL ASSPT		;ASSIGN SPT SLOT FOR JOB BASE REG
	MOVEM T1,JOBBAS
	CALL UPSHR		;INIT SHARE COUNT
	CALL ASSPT		;ASSIGN SPT SLOT FOR FORK BASE REG
	MOVEM T1,PSBBAS
	CALL UPSHR		;INIT SHARE COUNT
	CALL ASSPT		;GET ANOTHER ONE
	MOVEM T1,BTBBAS		;MAKE THIS THE BIT TABLE BASE
	MOVX T2,UAAB		;SET UP ACCESS TO NULL
	MOVEM T2,SPT(T1)	;TO THE SPT
	CALL UPSHR		;INIT SHARE COUNT
	SETZM SPTH(T1)		;SET NO CORRESPONDENCE
	MOVE T1,[MMAP,,MMAP+1]	;CLEAR MONITOR MAP
	SETZM MMAP
	BLT T1,MMAP+PGSIZ-1
	MOVSI T1,-MAXSEC	;SET UP TO INIT FPTA TARNSFER TABLE
	MOVE T2,[IFIW ILLFPT]	;ASSUME ALL ARE ILLEGAL
PGR00:	MOVEM T2,FPTABL(T1)	;INIT THIS ENTRY
	AOBJN T1,PGR00		;DO ALL OF THE TABLE
	; ..
;SET UP MSECTB AND FPTABL TABLES FOR SECTIONS 0. MAKE SECTION 1
;BE IDENTICAL TO 0

	CALL ASSPT		;ASSIGN SPT SLOT FOR MMAP
	MOVE T2,SHRPTR		;CONSTRUCT SHARE PTR TO MMAP
	STOR T1,SPTX,T2
	MOVEM T2,MSECTB		;SETUP POINTER FOR MON SECTION 0
	MOVE T3,[IFIW FPTA0]	;ROUTINE FOR MONITOR SECTION
	MOVEM T3,FPTABL		;SET UP SECTION 0
	SKIPE [MSEC1]
	JRST [	MOVEM T2,MSECTB+MSEC1	;SET UP POINTER FOR MON SEC1 ALSO
		MOVEM T3,FPTABL+MSEC1	;INIT FOR OTHER CODE SECTION
		JRST .+1]
	MOVEI T2,MMAP/PGSIZ	;GET ADDRESS FIELD
	MOVEM T2,SPT(T1)
	CALL UPSHR		;SET SHARE COUNT
	MOVEM T1,MMSPTN		;SAVE SPT OFFSET FOR MMAP
	SKIPN [MSEC1]		;DOING EXTENDED ADDRESSING?
	JRST PGRI10		;NO. SKIP EPT SET UP THEN

;SET UP POINTERS FOR DATA SECTIONS

	MOVE T3,INDPTR		;GET INDIRECT POINTER
	MOVE T2,PSBBAS		;GET BASE POINTER
	STOR T2,SPTX,T3		;STORE SPT POINTER
	MOVEI T2,DRMAP		;FIND INDEX
	STOR T2,IPPGN,T3
	MOVEM T3,MSECTB+DRSECN
	MOVE T4,[IFIW FPTA6]	;DISPATCH FOR DIRECTORY
	MOVEM T4,FPTABL+DRSECN	;SET IT UP
	MOVEI T2,IDXMAP		;SET UP POINTER TO IDXTAB
	STOR T2,IPPGN,T3
	MOVEM T3,MSECTB+IDXSEC	;SET IDX SECTION
	MOVE T4,[IFIW FPTA7]	;IDX ADDRESS
	MOVEM T4,FPTABL+IDXSEC	;TO THE TABLE
	MOVE T4,[IFIW FPTA8]	;BIT TABLE HANDLER
	MOVEM T4,FPTABL+BTSEC	;TO THE TABLE
	MOVE T4,[IFIW FPTAAN]	;APRPANET BUFFER HANDLER
	SKIPE [ANBSEC]		;NO SPECIAL SECTION FOR NET
	 MOVEM T4,FPTABL+ANBSEC	;TO THE TABLE
	MOVE T4,[IFIW FPTACI]	;SET LCS AND CI SECTION
	MOVEM T4,FPTABL+LCSSEC	;SET IN TABLE
	CALL ASSPT		;GET AN SPT SLOT FOR SECTION TABLE
	MOVE T2,SHRPTR		;CONSTRUCT SHARE PTR TO SECTION TABLE
	STOR T1,SPTX,T2
	MOVEM T2,MSECTB+TABSEC	;SETUP POINTER FOR DATA SECTION
	MOVE T4,[IFIW FPTATB]	;GET THE MONITOR TABLES SECTION
	MOVEM T4,FPTABL+TABSEC	;SET IN TABLE

;ASSIGN SPT SLOT FOR SYMMAP

PGRI10:	SKIPN HIDSYF		;HIDING SYMBOLS?
	JRST PGRI19		;NO, DON'T ASSIGN SPT SLOT STC
	CALL ASSPT		;GET AN SPT SLOT FOR THE SYMBOL MAP
	MOVEM T1,SYMBAS		;SAVE IN GLOBAL LOCATION
	MOVEI T2,SYMMAP_-PGSFT	;GET PHYSICAL PAGE # OF SYMMAP
	MOVEM T2,SPT(T1)	;SAVE IN SPT
	CALL UPSHR		;BUMP SHARE COUNT
	MOVE T1,[SYMMAP,,SYMMAP+1]	;CLEAR SYMMAP BEFORE FILLING BELOW
	SETZM SYMMAP		; ..
	BLT T1,SYMMAP+PGSIZ-1	; ..
	; ..
;NOW INIT CSTS AND MMAP.  WE ONLY PUT KNOWN PSECTS INTO MMAP, SO
;SPACE BETWEEN PSECTS WILL NOT BE MAPPED.  LATER WE WILL SCAN CST0,
;AND PUT ALL UNMAPPED PAGES ON RPLQ.

;IF HIDSYMING, THE SYMBOL TABLE WILL GO INTO SYMMAP INSTEAD OF MMAP.

PGRI19:	MOVE P2,MMSPTN		;LOAD PGRIGR'S CONSTANTS: OWNING MAP
	MOVE P3,[IFIW MMAP(P1)]	;INDIRECT POINTER TO OWNING MAP
	MOVEI P4,MMAP_-PGSFT	;PAGE NUMBER OF MMAP

	MOVSI P1,-RSCODP	;MAP PAGES BELOW RSCOD
	CALL PGRIGR		;MAP GROUP
	MOVE P1,[RSCODP-RSCODL-1,,RSCODP]	;RESIDENT CODE
	MOVE T1,DBUGSW		;GET DEBUGGING FLAG
	SKIPN WEFLAG		;WANT MONITOR WRITE-ENABLED?
	CAIN T1,2		;ARE WE IN DEBUGGING MODE?
	JRST [	CALL PGRIGR	;YES. WRITE-ENABLE RESIDENT MONITOR
		JRST PGRI20]
	CALL PGRIGP		;WRITE-PROTECT RESIDENT MONITOR
PGRI20:	MOVE P1,[INCODP-INCODL-1,,INCODP]	;INIT CODE
	CALL PGRIGR		;MAP GROUP

;DON'T MAP PPVAR, SINCE THEY'RE JUST TEMP MAP SLOTS
	MOVE P1,[RSDATP-RSDATL-1,,RSDATP]	;RESIDENT DATA, NON-ZEROED
	CALL PGRIGR		;MAP IT
	MOVE P1,[RSVARP-RSVARL-1,,RSVARP]	;RESIDENT VARS
	CALL PGRIGR		;MAP GROUP
	SKIPN HIDSYF		;HIDING SYMBOLS?
	JRST PGRI1		;NO, SYMS GO IN MMAP TOO
	MOVE P2,SYMBAS		;SPT INDEX OF SYMMAP
	MOVE P3,[IFIW SYMMAP(P1)] ;INDIRECT POINTER TO IT
	MOVEI P4,SYMMAP_-PGSFT	;PAGE NUMBER OF SYMMAP
PGRI1:	HRRZ P1,SYTBBP		;GET ADDRESS OF LAST PAGE OF SYMBOL TABLE
	ADDI P1,PGSIZ		;FORM FIRST ADDRESS BEYOND TABLE
	LSH P1,-PGSFT		;FORM FIRST FREE PAGE BEYOND SYMBOLS
	SUBI P1,SYVARP		;NUMBER OF PAGES IN SYMBOL AREA
	HRLZ P1,P1		;PUT IN LH
	MOVN P1,P1		;-COUNT,,0
	HRRI P1,SYVARP		;-COUNT,,FIRST PAGE
	CALL PGRIGR		;MAP GROUP

	SKIPE HIDSYF		;HIDING THE SYMBOLS?
	JRST PGRI11		;YES, GO SET UP SYMMAP
	JRST PGRI76		;NO, DON'T BOTHER
;PGRIGR - SET UP MMAP/SYMMAP AND CSTS FOR A GROUP OF PAGES
;CALL:
; P1/ AOBJN PTR TO PAGES
; P2/ SPT INDEX OF OWNER MAP
; P3/ INDIRECT WORD TO OWNER MAP INDEXED BY P1
; P4/ PAGE # OF OWNING MAP
;
;	CALL PGRIGR (FOR WRITE-ENABLED)
;		OR
;	CALL PGRIGP (FOR WRITE-PROTECTED)

;RETURN +1 ALWAYS


PGRIGR:	TDZA T3,T3		;WANT TO LEAVE FULL ACCESS
PGRIGP:	MOVX T3,PTWR		;WANT TO TURN OFF WRITE ACCESS
	ANDCA T3,IMMPTR		;MAKE IMMEDIATE POINTER WITH OR WITHOUT
				; WRITE ACCESS
PGRIG2:	JUMPGE P1,R		;DONE IF GROUP IS EMPTY
	MOVX T1,PSASM		;INIT CST0
	MOVEM T1,CST0(P1)	;UNASSIGNED
	MOVX T1,UAAB		;UNASSIGNED
	MOVEM T1,CST1(P1)	;SET BACKUP ADDR TO UNASSIGNED
	HRRZ T1,P1		;PAGE NUMBER ONLY
	CAML T1,MONCOR		;RESIDENT MONITOR?
	JRST PGRIG4		;NO, PROCEED
	MOVX T1,PLKV		;YES, ALWAYS LOCKED
	ADDM T1,CST1(P1)	;LOCK THE PAGE


;*** NOTE THAT THIS MAKES MMAP AND SYMMAP ALWAYS BE LOCKED.
;*** THE ADDM BELOW SHOULD PROPERLY BE ABOVE THE LABEL, BUT
;*** PGRI7/LCKINI/ULKINI DON'T KEEP UP THE LOCK COUNT OF THE
;*** OWNING PT, AND A HIGH LOCK COUNT IS BETTER THAN A LOW ONE...

PGRIG4:	MOVX T1,PLKV		;MAKE SURE SET UP
	ADDM T1,CST1(P4)	;COUNT ANOTHER LOCKED PAGE IN MAP
	HRL T1,P2		;FORM PTN.PN
	HRR T1,P1
	MOVEM T1,CST2(P1)	;STORE OWNER
	MOVX T1,<FLD(OFNUL,CSTOFK)>	;UNASSIGNED
	MOVEM T1,CST3(P1)	;SET PAGE
	HRRZ T1,P1		;GET PAGE NUMBER ONLY
	STOR T1,STGADR,T3	;ADD PAGE NUMBER TO ACCESS BITS
	MOVEM T3,@P3		;STORE POINTER IN APPROPRIATE MAP
	AOBJN P1,PGRIG2		;LOOP OVER GROUP OF PAGES
	RET			;DONE
;SINCE SYMMAP IS OWNED BY THE SPT, MAKE THE POINTER TO ITSELF
;IN SYMMAP BE A SHARED POINTER INSTEAD OF THE IMMEDIATE PTR ABOVE.

PGRI11:	MOVE T3,SYMBAS		;GET SPT INDEX OF SYMMAP
	MOVEM T3,CST2+SYMMAP_-PGSFT	;TELL CST2 OF TRUE OWNER
	MOVE T4,SHRPTR		;FORM A SHARE POINTER
	STOR T3,SPTX,T4		;  TO SYMMAP
	MOVEM T4,SYMMAP+SYMMAP_-PGSFT	;STORE SHARE PTR IN DDT'S MAP
	MOVX T4,-PLKV		;DECREMENT SYMMAP'S LOCK COUNT BY ONE
	ADDM T4,CST1+SYMMAP_-PGSFT	;SINCE WE JUST OVERWROTE AN IMM PTR


;PUT INDIRECT POINTER IN SYMMAP TO PUT PAGE 0, THE INIT CODE (EDDT),
;AND THE RESIDENT VARS (THE SPT AND CST) INTO THE SYMBOL ADDRESS SPACE.
;THE NPVAR PSECT NEEDS TO BE MAPPED TOO, SO THE RESIDENT FREE POOL
;WILL BE IN BOTH ADDRESS SPACES, AND DTE TRANSFERS WILL NOT BE DISRUPTED
;BY SWITCHING TO THE OTHER ADDRESS SPACE.
;ALSO SET UP THE RESIDENT CODE FOR THE EDV AND THE PAGE FAULT HANDLER

	MOVE T4,INDPTR		;FETCH CANONICAL INDIRECT PTR
	MOVE T3,MMSPTN		;GET MMAP'S SPT INDEX FOR INDIRECTING
	STOR T3,SPTX,T4		;FORM @ PTR TO MMAP'S PAGE 0
	MOVEM T4,SYMMAP		;STORE IN SYMMAP'S PAGE 0

	MOVE T1,[INCODP-INCODL-1,,INCODP]	;LOOP OVER INIT CODE
PGRI12:	STOR T1,IPPGN,T4	;FOR @ PTR TO NEXT PAGE OF INIT CODE
	MOVEM T4,SYMMAP(T1)	;STORE IN CORRESPONDING LOC IN SYMMAP
	AOBJN T1,PGRI12		;LOOP OVER ALL INIT CODE

	MOVE T1,[RSVARP-RSVARL-1,,RSVARP]	;SAME LOOP OVER RES VARS
PGRI13:	STOR T1,IPPGN,T4	;USUAL @ PTR
	MOVEM T4,SYMMAP(T1)	;PUT RESIDENT VARS IN SAME PLACE AS IN MMAP
	AOBJN T1,PGRI13		;LOOP OVER ALL RESIDENT VARS

	MOVE T1,[RSCODP-RSCODL-1,,RSCODP]	;SAME LOOP OVER RES COD
PGRI14:	STOR T1,IPPGN,T4	;USUAL @ PTR
	MOVEM T4,SYMMAP(T1)	;PUT RESIDENT CODE IN SAME PLACE AS IN MMAP
	AOBJN T1,PGRI14		;LOOP OVER ALL RESIDENT CODE

	MOVE T1,[NPVARP-NPVARL-1,,NPVARP]	;SAME LOOP OVER NON-RES P VARS
PGRI15:	STOR T1,IPPGN,T4	;USUAL @ PTR
	MOVEM T4,SYMMAP(T1)	;PUT NPVAR IN SAME PLACE AS IN MMAP
	AOBJN T1,PGRI15		;LOOP OVER ALL NPVARS

	MOVE T1,[RSDATP-RSDATL-1,,RSDATP]	;SAME LOOP OVER RESIDENT DATA
PGRI16:	STOR T1,IPPGN,T4	;USUAL @ PTR
	MOVEM T4,SYMMAP(T1)	;PUT RSDAT IN SAME PLACE AS IN MMAP
	AOBJN T1,PGRI16		;LOOP OVER ALL RSDAT


;SET UP LOCATIONS FOR BIT TABLE

PGRI76:	CALL INITBT		;SETUP INITIAL BTB SIZES
	SKIPE EXADDR		;IF EXTENDED ADDRESSING MAP NOT IN MMAP
	JRST PGRIBT
	MOVE T1,INDPTR		;GET INDIRECT POINTER FOR MAP
	MOVE T2,BTBBAS		;THE SPTN FOR THE BITTABLE
	STOR T2,SPTX,T1		;FORM REST OF POINTER WORD
PGRI77:	MOVEM T1,MMAP(T4)	;STORE NEXT POINTER
	ADD T1,[<FLD 1,IPPGN>]	;NEXT PAGE
	AOBJN T4,PGRI77		;DO ALL OF ADDRESS SPACE
	; ..
;SET UP THE JSB TO INDIRECT THROUGH JOBBAS

PGRIBT:	MOVE T4,[JSVARP-JSVARL-1,,JSVARP]
	MOVE T1,INDPTR		;CONSTRUCT INDIRECT PTR
	MOVE T2,JOBBAS
	STOR T2,SPTX,T1
	MOVEI T2,JOBMAP-JSBPGA
	STOR T2,IPPGN,T1
PGRI3:	MOVEM T1,MMAP(T4)	;STORE IN MON MAP
	AOS T2			;BUMP POINTER
	STOR T2,IPPGN,T1
	AOBJN T4,PGRI3		;DO ALL JOB AREA


;SETUP PSB TO INDIRECT THROUGH PSBBAS

	MOVE T4,[PSVARP-PSVARL-1,,PSVARP]
	MOVE T2,PSBBAS		;CONSTRUCT INDIRECT PTR
	STOR T2,SPTX,T1
	MOVEI T2,PSBMAP-PSBPGA
	STOR T2,IPPGN,T1
PGRI5:	MOVEM T1,MMAP(T4)	;STORE IN MON MAP
	AOS T2			;BUMP POINTER
	STOR T2,IPPGN,T1
	AOBJN T4,PGRI5		;DO ALL PROCESS AREA
	SKIPN HIDSYF		;HIDSYM'ING?
	JRST PGRI50		;NO, SKIP SYMMAP SETUP


;EDDT NEEDS THE UPT, SO PUT AN INDIRECT POINTER IN SYMMAP.
;PUT IT IN ANY FREE PAGE, SINCE ITS HOME MAY OVERLAP THE SYMBOLS.

	MOVE T2,MMSPTN		;GET MMAP SPT INDEX
	STOR T2,SPTX,T1		;STORE IN INDIRECT POINTER
	MOVEI T2,PSBPG		;PAGE NUMBER OF UPT
	STOR T2,IPPGN,T1	;SET UP AN INDIRECT POINTER
	MOVSI T3,-PGSIZ		;LOOP OVER SYMMAP
	SKIPE SYMMAP(T3)	;FIND A SLOT
	AOBJN T3,.-1		;WILL ALWAYS BE ONE
	MOVEM T1,SYMMAP(T3)	;STORE FOR EDDT
	; ..
;NOW SET UP SHARE POINTERS TO THE MAP PAGES OF THE JSB AND PSB

PGRI50:	MOVE T1,SHRPTR		;SETUP SHARE POINTER TO PSB AND JSB
	MOVE T2,PSBBAS		; VIA SPECIAL BASE ADDRESS WORDS
	STOR T2,SPTX,T1
	MOVEM T1,MMAP+PSBPG
	MOVE T2,JOBBAS
	STOR T2,SPTX,T1
	MOVEM T1,MMAP+JSBPG


;SET UP ARPANET BUFFER SECTION PAGE MAP

	SKIPE [ANBSEC]		;NO SPECIAL SECTION FOR NET
	 SKIPG [NHOSTS]		;IS IT AN ARPA SYSTEM
	JRST PGRI5A		;NO  SKIP SET UP
	CALL ASSPT		;GET AN SPT SLOT
	MOVE T2,SHRPTR		;SET UP SHARE PONITER FOR PAGE MAP
	STOR T1,SPTX,T2
	MOVEM T2,MSECTB+ANBSEC	;SET UP POINTER FOR ARPANET BUFFER SEC.
	MOVEI T2,NTBFIX/PGSIZ	;GET PAGE NUMBER OF MAP PAGE
	MOVEM T2,SPT(T1)	;SET UP SPT POINTER
	CALL UPSHR		;SET SHARE COUNT


;SETUP HSYSWP BLOCK.

PGRI5A:	SKIPN HIDSYF		;HIDING THE SYMBOL TABLE?
	JRST PGRI7		;NO, SKIP SETUP OF SYMSWP
	MOVE T1,SHRPTR		;FORM SHARE PTR TO SYMMAP
	MOVE T2,SYMBAS		; ..
	STOR T2,SPTX,T1		; ..
	MOVEM T1,SSECTB		;SET UP SECTION 0 MAP
	SKIPE [MSEC1]		;EXTENDED ADDRESSING?
	MOVEM T1,SSECTB+MSEC1	;YES, SET OTHER MONITOR SECTION TOO
	; ..
;NOW LOCK INIT CODE, SYMBOL TABLE, AND RESIDENT VARS.
;INIT CODE AND SYMBOL TABLE UNLOCKED IF NOT NEEDED AT GETSWM.

PGRI7:	MOVE T1,RSVABP		;BOUND PAIR TO RESIDENT VARS
	MOVEI P2,MLKCP		;LOCK ROUTINE TO CALL
	CALL BSMGP		;LOCK THE RESIDENT VARS
	MOVE T1,INCOBP		;BOUND PAIR FOR INIT CODE
	CALL BSMGP		;LOCK THE INIT CODE
	MOVE T1,RSDABP		;BOUND PAIR FOR RESIDENT DATA
	CALL BSMGP		;LOCK RESIDENT DATA, NON-ZEROED
	MOVE T1,SYTBBP		;BOUND PAIR FOR SYMBOL TABLE
	CALL BSMGP		;LOCK THE SYMBOL TABLE
	SKIPN HIDSYF		;SYMBOLS HIDDEN?
	JRST PGRI8		;NO, CONTINUE

	MOVE T1,.JBSYM		;GET SYMBOL POINTER
	MOVEM T1,HSYPTR		;PUT IN EDV
	MOVE T1,.JBUSY		;SAME FOR UNDEFINED POINTER
	MOVEM T1,HUSPTR		;PUT IN EDV
	MOVEI T1,HSYSWP		;GET ADDRESS OF SYMBOL SWAPPING BLOCK
	MOVEM T1,HSYBLK		;**** TURN ON ALTERNATE SYMBOL PROCESSING ****
	SETZM .JBSYM		;THESE WILL BE INVALID AFTER CALLING PGRON
	SETZM .JBUSY		;  ..


;SET TO KNOWN UPT SO NXM FAULTS BELOW WILL WORK

PGRI8:	CALL SETPSK		;SET TO SCHED CONTEXT
	CALL PGRON		;ENABLE PAGER

;FIND ALL EXISTENT PHYSICAL CORE AND CONSTRUCT RPLQ

	SETZM TOTRC		;INIT TOTRC
	SETZM NSPMQ		;INITIALIZE SPMQ
	MOVSI T1,SPMQ		;SET TAIL POINTER
	MOVEM T1,SPMQ		; ...
	SETOM SPMLCK		;SPMQ USER INTERLOCK
	SETOM SPMONR		;FORK OWNING SPMLCK
	SETZM NRPLQ
	CONO APR,APFCLR+APNXM+APRCHN	 ;CLEAR NXM
	MOVE Q1,MONCOR		;START SCAN AT END OF RSCOD
	MOVE T2,[SRPLQ,,SRPLQ]
	MOVEM T2,SRPLQ		;INIT RPLQ'S
	MOVE T2,[DRPLQ,,DRPLQ]
	MOVEM T2,DRPLQ
PGRI2:	SKIPE CST0(Q1)		;PAGE MAPPED BY PGRINI?
	JRST PGRI4A		;YES, NOT AVAILABLE FOR RPLQ
	MOVX T2,PSASM		;SET LEGAL AGE FOR TEST REFERENCE
	MOVEM T2,CST0(Q1)
	SETZM CST1(Q1)		;CLEAR CST ENTRIES
	SETZM CST2(Q1)
	SETZM CST3(Q1)
	MOVE T1,Q1		;GET PHYS PAGE NUMBER
	CALL MAPRCA		;MAP IT
	; ..
PGRI2A::MOVE T2,0(T1)		;TRY TO REFERENCE IT
	CONSZ APR,APNXM		;NXM?
	JRST PGRI6		;YES
	MOVE T2,1(T1)		;TRY 3 OTHER WORDS IN CASE INTERLEAVED
	MOVE T2,2(T1)
	MOVE T2,3(T1)
PGRI6::	CAML Q1,NLOWPG		;EXCLUDE PAGES BELOW BOUNDARY
	CONSZ APR,APNXM		;NXM?
	SKIPA			;YES
	CAMLE Q1,NMAXPG		;ABOVE MAX?
	JRST [	CONO APR,APFCLR+APNXM+APRCHN	 ;YES, CLEAR FLAG
		MOVX T2,<FLD(PSDEL,CSTAGE)+FLD(PSTOFL,CSTPST)>
		MOVEM T2,CST0(Q1)	;CALL IT DELETED
		MOVE T1,Q1		;AND PLACE ON SPMQ
		CALL ONSPMQ		;LIKE ONRQ, RETURNS
		PIOFF
		JRST PGRI4]
	SETZM CST0(Q1)		;NO, PAGE EXISTS
	MOVEM Q1,NHIPG		;REMEMBER HIGHEST PAGE FOUND
	MOVE T1,Q1
	CLRMPE			;CLEAR ANY PARITY ERRORS
	CALL ONRQ		;PUT PAGE ON REPLACABLE QUEUE
	PIOFF
PGRI4A:	AOS TOTRC		;COUNT PAGES OF CORE FOUND
PGRI4:	CAIGE Q1,MAXCOR-1	;CHECK ALL POSSIBLE CORE
	AOJA Q1,PGRI2
	SETZM PAGDIF		;NO PAGE DIFFERENCES AS OF NOW
	CALL MEMSTR		;SET UP MEM CONTROLLERS IF APPROPRIATE
	; ..
;SETUP VARIOUS CONSTANTS FOR CORE MGT

	CALL MEMMGT		;SET UP PAGING PARAMETERS
	MOVEI T1,LGABOT
	MOVEM T1,CURAGE		;SET INITIAL GCCOR VALUES
	MOVEM T1,CUTAGE
	CALL LDAGER		;LOAD AGE REGISTER
PGRRST::CALL PGRON
	CALL PGRCLD
	RET
;SETDST - SET UP MAP FOR DST, POINTER TO IT, ETC.

;ACCEPTS:
;	NO ARGUMENTS

;	CALL SETDST

;RETURNS +1: ALWAYS

SETDST::
	SE1CAL
	SAVEAC <T1,T2,T3,T4,P1,P2,P3>
	SKIPN EXADDR		;RUNNING ON MODEL B?
	JRST SETDS2		;NO.
	HRRZ T1,MSECTB+TABSEC	;GET SPT SLOT
	CALL SWPIN1		;GET A CORE PAGE FOR IT
	HRLZ P3,MSECTB+TABSEC	;GET SPT INDEX FOR SECTION MAP
	MOVEI P1,NDST_-PGSFT	;GET NUMBER OF WORDS IN DST
	AOS P1			;ROUND UP TO NEXT PAGE
	MOVNS P1		;SET UP AOBJN POINTER WITH
	HRLZS P1		; (SPT INDEX,,PAGE NUMBER)
SETDS1:	MOVE T1,P3		;T1/ (SPT,,PAGE NUMBER)
	CALL MLKPG		;GET A CORE PAGE AND LOCK IT
	AOS P3			;INCREMENT PAGE COUNT
	AOBJN P1,SETDS1		;DONE WITH ALL PAGES?
	MOVSI T2,TABSEC		;GET START OF DST
	SETOM (T2)		;INITIALIZE TO FREE
	MOVEI T1,NDST		;NUMBER OF WORDS TO COPY
	MOVE T3,T2		;DESTINATION
	AOS T3			; IS ONE PAST SOURCE
	XBLT. T1		;INITIALIZE DST

	MOVSI T1,TABSEC		;SET UP ADDRESS OF START OF DST
	MOVEM T1,DSTLOC		;TELL SWPALC WHERE IT IS
	RET

;HERE WHEN RUNNING ON MODEL A. THE DST HAS BEEN ALLOCATED IN
;PSECT RSVAR. MAKE DSTLOC POINT TO IT.

SETDS2:	MOVE T1,[DST,,DST+1]	;INIT DST TO -1
	SETOM -1(T1)
	BLT T1,DST+NDST-1
	MOVEI T1,DST
	MOVEM T1,DSTLOC
	RET
;ROUTINES TO COMPUTE PAGE MANAGEMENT PARAMETERS

MEMMGT:	MOVE T1,TOTRC		;TOTAL REAL MEM FOUND
	SUB T1,NRPMX		;LESS 2 TIMES MARGIN
	SUB T1,NRPMX
	MOVEM T1,MAXNR		;MAX VALUE OF SUMNR
	SUBI T1,10
	SKIPE T2,PGMMAX		;CUSTOMER-SPECIFIED LIMIT?
	JRST [	CAMLE T2,T1	;YES, BELOW CORE LIMIT?
		MOVE T2,T1	;NO, MUST USE CORE LIMIT
		MOVEM T2,NPMAX	;USE FOR BOTH REGULAR AND SMALL LIMIT
		MOVEM T2,SNPMAX
		JRST PGRI9]
	MOVEM T1,NPMAX
	CAIL T1,140		;REASONABLY LARGE SYSTEM?
	SUBI T1,40		;YES, SET SNPMAX 16K SMALLER
	MOVEM T1,SNPMAX		;SMALL NPMAX
PGRI9:	MOVE T1,NRPMX		;INIT NRPMIN
	MOVEM T1,NRPMIN
	MOVE T1,TOTRC
	LSH T1,-3
	MOVEM T1,MAXBP
	RET			;DONE

;SET SWAP SPACE PARAMETERS - CALLED FROM DRMINI AFTER DRUM SPACE KNOWN
;ALSO CALLED WHEN NEW PAGES APPAEAR IN SYSTEM
; A/ NUMBER PAGES AVAILABLE FOR SWAPPING

SETSSP::MOVE B,TOTRC		;PREVENT NEW PRIVATE PAGES
	CAIL B,^D1024		;A VERY LARGE SYSTEM?
	MOVEI B,^D1024		;YES. USE CUTOFF THEN
	MOVEM B,DRMLV0		;WHEN FREE DRUM EQUALS TOTAL CORE
	MOVEM B,DRMIN1		;NEW JOB CUTOFF WILL BE 1.5 ABOVE
	ASH B,-1
	ADDM B,DRMIN1
	ADD B,DRMIN1		;DDMP START LEVEL WILL BE 2 TIMES
	MOVEM B,DRMIN0		;TO CAUSE DDMP ACTIVITY
	ASH B,1			;SEE IF ACTUAL SWAP SPACE AT LEAST
	CAMGE A,B		; TWICE DDMP LEVEL
	BUG(SWPSTL)
	RET
;INIT NEW FORK

FKSETP::MOVE T2,SHRPTR		;CONSTRUCT SHARE PTR
	LOAD T1,FKUPT		;GET UPT IDENT
	STOR T1,SPTX,T2		;CONSTRUCT SHARE PTR
	MOVEM T2,PSBM0+UPTPG	;MAP UPT
	MOVEM T2,USECTB		;SET AS USER SECTION 0 ALSO
	LOAD T1,FKPSB
	STOR T1,SPTX,T2		;BUILD SHARE PTR TO PSB
	MOVEM T2,PSBM0+PSBPG	;SET IT IN MON MAP
	LOAD T1,FSSPTN		;GET STACK PAGE I.D.
	STOR T1,SPTX,T2		;MAKE A SHARE POINTER TO IT
	MOVEM T2,PSBM0+PSB1	;POINT TO THE STACK PAGE FROM THE UPT
	RET

;ROUTINE TO CHECK IF A PAGE CAN BE USED (DOESNT NXM)
;T1/ PHYSICAL PAGE
;	CALL CHKPAG
;RETURNS+1(FAILURE):
;	PAGE NOT USEABLE
;RETURNS+2(SUCCESS):
;	PAGE APPEARS OK

CHKPAG:	PIOFF		;PREVENT ANY INTERRUPTS
	PUSH P,CST0(T1)		;SAVE PRESENT STATE
	PUSH P,T1		;SAVE PAGE NUMBER AS WELL
	MOVX T2,PSASM		;ALLOW REFERENCE
	IORM T2,CST0(T1)	; ...
	CALL MAPRCA		;MAP PAGE
	POP P,T2		;RESTORE PAGE NUMBER
	SKIP 0(T1)		;REFERENCE FIRST WORD
	CONSZ APR,APNXM		;NXM?
	JRST CHKPG1		;YES - LOSE QUICKLY
	SKIP 1(T1)		;NO - TRY NEXT 3 WORDS
	SKIP 2(T1)		;IN CASE INTERLEAVE
	SKIP 3(T1)		;DEFECTIVE
	CONSZ APR,APNXM		;STILL NO NXM?
	JRST CHKPG1		;NXM - NOT SUITABLE
	POP P,CST0(T2)		;RESTORE ORIGINAL STATE
	CALL UNMRCA		;CLEAR TEMP MAPPING
	PION
	RETSKP			;SUCCESS RETURN

CHKPG1:	CONO APR,APFCLR+APNXM+APRCHN	;RESET NXM FLAG
	POP P,CST0(T2)		;RESTORE ORIGINAL STATE
	CALL UNMRCA		;RELEASE TEMP MAPPING
	PION
	RET			;FAILURE
;ROUTINES FOR SAVING AND RESTORING SWAPPABLE MONITOR MAP
;AROUND RESTARTS

;SAVE SWAP MON MAP

SAVSMM::MOVEI Q1,NRCODP-1
	SUB Q1,SWCEND		;COMPUTE NUMBER PAGES IN SWAP MON
	HRLZ Q1,Q1		;SETUP AOBJN PTR
SAVSM1:	MOVE T1,MMAP+NRCODP(Q1)	;GET CURRENT MAP PTR
	TXNN T1,NCORTM		;IN CORE?
	JRST [	HRRZS T1	;MASK OFF HIGH BITS
		MOVE T1,CST1(T1)	;YES, GET DRUM ADDRESS
		JRST .+1]
	MOVEM T1,TMPSMM(Q1)	;SAVE DRUM ADDRESS
	AOBJN Q1,SAVSM1
	RET

;RESTORE SWAP MON MAP FROM TEMP AREA IN LOW CORE

RESSMM::MOVEI Q1,NRCODP-1	;COMPUTE NUMBER PAGES IN SWAP MON
	SUB Q1,SWCEND
	HRLZ Q1,Q1
RESSM1:	LOAD T1,STGADR,TMPSMM(Q1) ;GET DRUM ADR FOR THIS PAGE
	CALL DRMASA		;ASSIGN IT
	 BUG(RSMFAI)
	LOAD T1,STGADR,TMPSMM(Q1)
	IOR T1,IMMPTR		;MAKE NEW PTR
	MOVEM T1,MMAP+NRCODP(Q1) ;SETUP MON MAP
	AOBJN Q1,RESSM1
	RET
;RESTART SWAPPER - REINITIATE IO OPERATIONS IN PROGRESS AT TIME OF CRASH

SWPRST::SETZM IOIP
	MOVE 6,MONCOR		;SCAN CST AND CHECK STATE OF PAGES
SWPRS1:	LOAD 1,CSTAGE,(6)	;GET STATE CODE
	CAIN 1,PSRIP		;READ IN PROGRESS?
	JRST SWPRSR		;YES, GO RESTART IT
	CAIN 1,PSWIP		;WRITE?
	JRST SWPRSW		;YES
	CAIL 1,PSASN		;PAGE ASSIGNED TO PROCESS?
	JRST [	MOVE 2,CST3(6)	;YES, SEE IF BEING WRITTEN
		TLNE 2,(DWRBIT)
		JRST SWPRSW	;WAS BEING WRITTEN, RESTART WRITE
		JRST .+1]	;NOT BEING WRITTEN
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,(DSKAB)		;DISK?
	JRST SWPRS3		;YES
	TLNN 2,(DRMAB)		;DRUM?
	BUG(ILCST1)
	CALL DRMIO
	JRST SWPRS2

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

DDMPLF==1B0			;LOCAL FLAG IN F, DRUM SP LOW IF 1

;**;[2820] CHANGE 2 LINES AT DDMP:+0L	TAM	27-SEP-82
DDMP::	NOINT			;[2820] DON'T TOUCH THAT DIAL
	LOCK STRLOK		;[2820] PREVENT DISMOUNTS
	SETZ F,			;CLEAR FLAGS
	MOVE 1,DRMFRE
	SKIPE DDTIME		;SYSTEM SHUTDOWN?
	CAMGE 1,DRMIN0		;OR INSUFFICIENT DRUM SPACE?
	TLO F,(DDMPLF)		;YES, TAKE SPECIAL ACTION
	MOVSI P1,-NOFN		;SETUP TO SCAN ALL OFN'S
	AOBJN P1,.+1		;0 NOT USED
DDMP9:	NOSKED
	SKIPN SPTH(P1)		;OFN IN USE?
	JRST DDMP2		;NO
	SETCM 1,SPTH(P1)	;GET THAW AND WRITE BITS
	TXNN 1,FILWB+THAWB	;BOTH 1? (I.E. THAW MODE)
	JRST DDMP3		;YES, UPDATE
	TXNN F,DDMPLF		;DRUM FULL?
	JRST DDMP2		;NO, BYPASS OFN
DDMP3:	MOVX 2,OFNDMO!OFNDUD	;CHECK IF THIS OFN IS DISMOUNTED
				; OR DDMP BEING SUPPRESSED
	TDNE 2,SPTH(P1)		;IS IT?
	JRST DDMP2		;YES. SKIP IT
	LOAD A,STRX,(P1)	;GET STRUCTURE NUMBER
	CALL STROFL		;IS THIS STRUCTURE OFF-LINE
	JRST DDMP2		;YES. SKIP IT
	MOVX 2,SPTLKB		;TRY TO LOCK OFN
	TDNE 2,SPTH(P1)
	JRST DDMP2		;ALREADY LOCKED, SKIP IT THIS TIME
	IORM 2,SPTH(P1)		;SET LOCK
IFN SPTDSW,<			;ONLY IF DEBUGING SPTLKB PROBLEMS
	EXCH T1,P1		;GET THE OFN INDEX
	CALL SPTRAC		;TRACE WHO LOCKED THIS
	EXCH T1,P1		;RESTORE THE ACS
 >				;END OF IFN SPTDSW
	HRRZ A,P1		;GET THE OFN IN A
	CALL UPSHR		;ARTIFICIALLY UP THE SHARE COUNT
	OKSKED			;WILL UPDATE OFN, NOW SAFELY LOCKED
	LOAD A,STRX,(P1)	;GET STRUCTURE NUMBER
	CALL UPDBTB		;UPDATE BIT TABLE
	HRLZ 1,P1		;CONSTRUCT IDENT OF FIRST PAGE
	MOVEI 2,PGSIZ		;DO ALL PAGES
	TXNN F,DDMPLF		;DOING DRUM LOW ACTIONS?
	CALL UPDPGS		;NO, REGULAR UPDATE PAGES
	TXNE F,DDMPLF
	CALL UPDPG0		;YES, FLUSH ALL PAGES TO DISK
	HRRZ 1,P1		;GET OFN
	CALL UPDOF0		;UPDATE THE INDEX BLOCK
	HRRZ A,P1		;GET THE OFN IN A
	CALL DWNSHR		;DECREMENT THE SHARE COUNT
	MOVX 1,SPTLKB
	ANDCAM 1,SPTH(P1)	;CLEAR LOCK
	JRST DDMP1		;DONE WITH THIS OFN

DDMP2:	OKSKED
DDMP1:	AOBJN P1,DDMP9		;SCAN ALL OFN'S
	SETOM STRLOK		;RELEASE LOCK
	OKINT			;NOW OKAY TO INTERRUPT, ETC.
	RETSKP			;AND RETURN SUCCESSFULLY
;UPDATE OFN--GET INDEX BLOCK WRITTEN TO DISK
; 1/ OFN
;	CALL UPDOFN
; RETURN +1 ALWAYS, BIT TABLE AND INDEX BLOCK UPDATED

UPDOFN::STKVAR <OFN>
	MOVEM A,OFN
	HRRZ B,A		;GET OFN
	CALL CHKDMO		;SEE IF DISMOUNTED
	 RET			;IT IS. IGNORE REQUEST.
	HRRZ A,OFN		;GET OFN
	CALL LCKOFN		;LOCK OFN AGAINST CHANGES
	MOVX B,OFNWRB		;SEE IF OFN MODIFIED
	TDNN B,SPTH(A)
	JRST UPDOFX		;NOT MODIFIED, DO NOTHING
	LOAD A,STRX,(A)		;GET STRUCTURE NUMBER
	CALL UPDBTB		;UPDATE BIT TABLE
	HRRZ A,OFN		;GET OFN AGAIN
	CALL UPDOF0		;WRITE INDEX BLOCK
UPDOFX:	MOVE A,OFN
	CALL ULKOFN		;UNLOCK OFN
	RET

;UPDATE OFN IF NECESSARY.
;OFN LOCKED. T1/ OFN
;RETURNS: +1 ALWAYS
;	RH OF T1 PRESERVED (I.E. THE OFN)

UPDOFI:	HRRZS T1		;GET RH ONLY
	MOVX T2,OFNWRB		;SEE IF OFN NEEDS UPDATING
	TDNN T2,SPTH(T1)	;DOES IT?
	RET			;NO
	MOVE T2,T1		;YES. GET OFN
	CALL CHKDMO		;SEE IF STILL MOUNTED
	 RET			;NO. ALL DONE THEN
	PUSH P,T1		;YES. SAVE OFN
	LOAD T1,STRX,(T1)	;GET STRUCTURE NUMBER
	CALL UPDBTB		;UPDATE THE BTB
	MOVE T1,0(P)		;GET BACK OFN
	CALL UPDOF0		;UPDATE THE OFN
	CALLRET PA1		;AND DONE
;SCAN INDEX BLOCK AND WRITE IMAGE TO DISK
;ASSUMES OFN LOCKED AGAINST CHANGES
; A/ OFN
;	CALL UPDOF0
; RETURN +1 ALWAYS
;AC USAGE:
; P1 - OFN
; P2 - AOBJN PTR FOR SCANNING PAGE TABLE
; P3, P4 - TEMPS
; P5 - CHECKSUM

UPDOF0:	SAVEP			;SAVE P1-P6
	CAILE A,0		;ENSURE LEGAL OFN
	CAIL A,NOFN
	BUG(NOTOFN)
	MOVEM A,P1		;KEEP OFN AROUND
	LOAD A,STGADR,SPT(P1)	;GET CURRENT ADR OF XB
	TXNE A,DSKAB		;ON DISK?
	RET			;YES, NOTHING TO DO
	MOVX A,OFNWRB
	TDNN A,SPTH(P1)		;CHANGED SINCE LAST UPDATE?
	RET			;NO, NOTHING TO DO
	ANDCAM A,SPTH(P1)	;NOTE OFN NOW UPDATED
	MOVE A,P1
	MOVE B,[PTRW+FPG2A]
	CALL SETMPG		;MAP XB
	MOVEI A,0
	MOVEI B,FPG3A
	CALL SETMPG		;CLEAR A PAGE TO RECEIVE XB IMAGE
	SETZM FPG3A		;MAKE IT EXIST
	MOVEI P5,0		;INIT CHECKSUM
	JCRY0 .+1
	MOVSI P2,-PGSIZ		;SETUP TO SCAN XB
UOFN1:	SKIPE FPG2A(P2)	;ENTRY EXISTS?
	JRST UOFN2		;YES, GO TRACK DOWN DISK ADR
	ADDI P5,0(P2)		;USE XB INDEX FOR 0 WORD IN CHECKSUM
	JCRY0 [AOJA P5,.+1]	;WRAPAROUND CARRY
UOFN6:	AOBJN P2,UOFN1		;SCAN ALL XB
	MOVX A,OFNBAT		;SEE IF OFN HAS BAT BIT
	MOVX B,XBBAT		;IN CASE IT DOES
	TDNE A,SPTH(P1)		;IS IT SET?
	IORM B,XBBWRD+FPG3A	;YES. MARK XB
	; ..
;UPDOFN...
;HAVE FINISHED SCAN OF XB

	MOVEI A,P5		;POINT TO CHECKSUM
	MOVE B,[XBCKSM+FPG3A]	;PUT IT IN FIRST FOUR WORDS OF XB
	CALL STXBD		;STORE CHECKSUM IN XB
	MOVEI A,FPG3A		;GET IDENT FOR IMAGE PAGE
	CALL FPTA
	MOVEM A,P3		;SAVE IT
	CALL MLKPG		;LOCK IMAGE PAGE IN CORE FOR DSKIO
	MOVEM A,P4		;SAVE CORE PAGE NUMBER
	LOAD A,STGADR,SPTH(P1)	;GET DSK ADR OF XB
	MOVX B,DOP%WR+PGSIZ	;SAY WRITE ONE PAGE
	HRRZ C,P4		;SETUP PHYSICAL CORE ADR
	LSH C,PGSFT
	LOAD D,STRX,(P1)	;GET STRUCTURE NUMBER
	CALL UDSKIO		;WRITE TO DISK
	AOS DSKWR		;COUNT WRITES FOR STATISTICS
	EXCH A,P3		;SAVE ERROR BITS, GET CORE PAGE
	CALL MULKPG		;UNLOCK PAGE
	SKIPE P3		;ERROR ON WRITE?
	BUG(XBWERR)
UOFNX:	MOVEI A,0
	MOVEI B,FPG2A
	MOVEI C,2
	CALL MSETMP		;UNMAP BOTH PAGES
	RET
;UPDOFN...
;FIND DISK ADDRESS FOR PAGE IN XB

UOFN2:	NOSKED
	MOVE A,FPG2A(P2)	;GET POINTER
	LOAD B,PTRCOD,A		;GET PTR TYPE
	CAIE B,SHRCOD		;SHARE?
	JRST [	LOAD A,STGADR,A	;NO, PRIVATE. GET ADR.
		JRST UOFN3]
	LOAD A,SPTX,A		;GET SPT INDEX
	LOAD A,STGADR,SPT(A)	;GET ADDRESS OF PAGE
UOFN3:	TXNE A,DSKAB		;HAVE DISK ADDRESS?
	JRST UOFN4		;YES, DONE
	TXNE A,DRMAB		;HAVE DRUM ADDRESS?
	JRST UOFN5		;YES
	TXNE A,NCORTM		;CORE ADDRESS?
	JRST [	SETZ A,		;NO, UNASSIGNED. USE 0
		JRST UOFN4]
	CAML A,MONCOR		;LEGAL PAGE NUMBER?
	CAMLE A,NHIPG
	JRST UOFBPP		;NO
	HRRZS A
	LOAD A,STGADR,CST1(A)	;GET NEXT LEVEL ADDRESS
	JRST UOFN3		;GO SEE WHAT IT IS

;HAVE DRUM ADDRESS. FIND THE BACKUP ON DISK AND STORE THAT INTO WORK
;COPY OF INDEX BLOCK

UOFN5:	MOVE B,A
	CALL GDSTX		;GET ADDRESS IN DST FOR THIS PAGE
	LOAD A,STGADR,(B)	;GET NEXT LEVEL ADDRESS FROM DST
	TXNN A,DSKAB		;IT MUST BE DISK
	JRST UOFBPP		;LOSSAGE
UOFN4:	OKSKED
	TXNE A,DSKNB		;ADDRESS NOT WRITTEN YET?
	SETZ T1,		;YES, DON'T PUT IT ON DSK
	STOR A,STGADR,FPG3A(P2) ;PUT DSK ADR IN IMAGE PAGE
	SKIPN A			;PAGE EXISTS?
	HRRZ A,P2		;NO, USE XB INDEX FOR CHECKSUM
	JCRY0 .+1		;CLEAR CARRY FLAG
	ADD P5,A		;DO CHECKSUM
	JCRY0 [AOJA P5,.+1]	;WRAPAROUND CARRY
	JRST UOFN6		;CONTINUE SCAN

;CASES OF BAD POINTER

UOFBPP:	BUG(ILPPT1)
	OKSKED
	JRST UOFNX		;RETURN WITHOUT WRITING XB
;LOAD/STORE DATA IN INDEX BLOCK.
;SINCE THE STORAGE ADDRESS IS ONLY 23 BITS, THE REMAINING PORTION
;OF EACH WORD CAN BE USED TO STORE USEFUL INFORMATION, E.G. A
;CHECKSUM OF THE INDEX BLOCK.  THESE ROUTINES PACK AND UNPACK
;THE DATA FROM THE XB USING B0-8 OF SUCCESSIVE WORDS.

; A/ ADDRESS OF WORD(S)
; B/ NUMBER OF XB WORDS,,XB ADDRESS + OFFSET
;	CALL STXBD/LDXBD
; RETURN +1 ALWAYS, DATA MOVED BETWEEN XB AND C(C(A))

;STORE DATA INTO INDEX BLOCK

STXBD:	HRLI A,(<POINT 9,0>)	;INIT PTR TO CALLERS DATA
STXBD1:	ILDB C,A		;GET BYTE FROM CALLER
	DPB C,[POINT 9,0(B),8]	;PUT IT IN XB
	AOBJN B,STXBD1		;INCREMENT THROUGH XB
	RET

;LOAD FROM XB

LDXBD:	HRLI A,(<POINT 9,0>)	;INIT PTR TO CALLERS STORAGE
LDXBD1:	LDB C,[POINT 9,0(B),8]	;GET BYTE FROM XB
	IDPB C,A		;PUT IT IN CALLERS STORAGE
	AOBJN B,LDXBD1		;SCAN THROUGH XB
	RET

;ITEMS IN INDEX BLOCK VECTOR

XBCKSM==<-4,,0>			;CHECKSUM--4 WORDS BEGINNING AT 0
;UPDATE FILE PAGES--CAUSE CHANGED PAGES TO BE WRITTEN TO DISK
; 1/ IDENT OF FIRST FILE PAGE, OFN,,PN
; 2/ FLAGS,,NUMBER OF SEQUENTIAL PAGES TO UPDATE
;	CALL UPDPGS
; RETURN +1 ALWAYS, ALL WRITES COMPLETED

;AC USAGE:
; P1 - OFN
; P2 - AOBJN PTR FOR SCANNING PT
; P3 - FLAGS
; P4 - COPY OF INITIAL AOBJN PTR

;LOCAL FLAGS

UPGSF0==1B1			;0=WRITE PAGES, 1=WAIT FOR COMPLETION
UPGSLF==1B2			;1=DRUM SPACE LOW, FORCE PAGES TO DSK
UPGKPF==1B3			;0 = USE OFRQ, 1 = USE ONRQ ON SWPOUT
UPGNOW==1B4			;NO WAIT. DON'T DO PASS 2

;ROUTINE SCANS PAGE TABLE TWICE.  FIRST TIME TO REQUEST WRITES ON
;ALL CHANGED PAGES, SECOND TIME TO WAIT FOR COMPLETION OF WRITES.
;THIS IS FASTER THAN WAITING FOR EACH WRITE TO COMPLETE AS IT
;IS REQUESTED.

UPDPGS::SAVEP			;SAVE P1-P6
	MOVX P3,UPGKPF		;KEEP PAGES
	TXNE T2,UF%NOW		;WANT "NO WAIT"?
	TXO P3,UPGNOW		;YES. SET BIT THEN
	JRST UPGS0

UPDPGR::SAVEP			;ENTRY TO REMOVE PAGES QUICKLY
	MOVX P3,0		;CLEAR FLAGS
	JRST UPGS0

;SPECIAL ENTRY FOR DDMP, SET FLAG TO FORCE PAGES TO DSK WHEN DRUM FULL

UPDPG0:	SAVEP
	MOVX P3,UPGSLF+UPGKPF	;SET FULL FLAG AND KEEP PAGES
UPGS0:	MOVEI B,0(B)		;GET COUNT ONLY
	HLRZM A,P1		;SAVE OFN
	HRRM A,P2		;SETUP INITIAL PAGE NUMBER
	HRRZ A,A
	ADD A,B			;COMPUTE FINAL PAGE NUMBER
	CAILE A,PGSIZ		;BEYOND END OF PT?
	BUG(PTOVRN)
	MOVN B,B
	HRLM B,P2		;CONSTRUCT AOBJN PTR TO SCAN PT
	MOVE B,P1		;GET PT
	CALL CHKDMO		;SEE IF IT IS A DISMOUNTED OFN
	 CALLRET DMOINT		;IT IS. GIVE AN ERROR
	MOVEM P2,P4		;SAVE COPY FOR SECOND PASS
	LOAD A,STGADR,SPT(P1)	;GET CURRENT ADR OF INDEX BLOCK
	TXNE A,DSKAB		;ON DISK?
	RET			;YES, NOTHING TO DO
	MOVE A,P1		;MAP PAGE TABLE
	MOVE B,[PTRW+FPG2A]
	CALL SETMPG
UPGS1:	SKIPE FPG2A(P2)	;PAGE EXISTS?
	JRST UPGS2		;YES, GO CHECK IT OUT
UPGS3:	AOBJN P2,UPGS1		;DO ALL PAGES
	MOVE P2,P4		;REINIT AOBJN PTR
	TXOE P3,UPGSF0		;DONE PASS 2?
	JRST UPGSX		;YES. ALL DONE THEN
	TMNN OFNWRB,SPTH(P1) ;IF OFN NEEDS UPDATING, MUST WAIT
	TXNN P3,UPGNOW		;OFN SET, WANT TO WAIT?
	JRST UPGS1		;YES. GO DO PASS 2 THEN
UPGSX:	MOVEI A,0
	MOVEI B,FPG2A
	CALL SETMPG		;RELEASE PT MAPPING
	RET
;UPDPGS...
;INVESTIGATE SPECIFIC PAGE
;	P1/ OFN
;	P2/ PAGE NUMBER

UPGS2:	NOSKED
UPGS7:	MOVE A,FPG2A(P2)	;GET POINTER
	LOAD B,PTRCOD,A		;GET PTR TYPE
	CAIN B,SHRCOD		;SHARE?
	JRST [	LOAD D,SPTX,A	;YES, GET SPT INDEX
		LOAD A,STGADR,SPT(D) ;GET PAGE ADR FROM SPT
		JRST UPGS9]	;GO PROCESS IT
	MOVE D,P2		;IS PRIVATE. FORM ID
	HRL D,P1		; AS OFN.PN
UPGS9:	TXNE A,DSKAB		;ON DISK?
	JRST UPGS4		;YES, NO UPDATE NEEDED
	TXNN A,DRMAB		;ON DRUM?
	JRST UPGS5		;NO
	TXNE P3,UPGSF0		;YES, PASS 2?
	JRST UPGS4		;YES, WRITE, IF ANY, MUST HAVE COMPLETED
	MOVE B,A		;GET DRUM ADDRESS TO B FOR GDSTX
	CALL GDSTX		;GET ADDRESS IN DST FOR THIS PAGE
	MOVE C,(B)		;GET DRUM INFO
	TXNN C,BWRBIT		;PAGE MODIFIED?
	JRST [	TXNN P3,UPGSLF ;NO, DRUM FULL?
		JRST UPGS4	;NO, BYPASS PAGE
		SETOM (B)	;DRUM FULL, SO PUT PAGE BACK ON DSK
		TLNE D,-1	;IN SPT OR XB?
		CALL [	HRRZ B,D
			STOR C,STGADR,FPG2A(B) ;IN XB
			RETSKP]	;DONE
		STOR C,STGADR,SPT(D) ;SPT
		CALL DASDRM	;ADJUST POINTER AND DEASSN DRM ADR
		JRST UPGS4]
	MOVE A,D		;MUST SWAPIN PAGE, GET SPT INDEX
UPGS6:	CALL SWPINW		;SWAPIN THE PAGE
	JRST UPGS7		;NOW SHOULD BE IN CORE
;PAGE NOT ON DISK OR DRUM

UPGS5:	TXNE A,NCORTM		;IN CORE?
	JRST UPGS4		;NO, UNASSIGNED. IGNORE.
	TXNE P3,UPGSF0	;PASS 2?
	JRST [	CALL SKPNWR	;YES, WRITE STILL IN PROGRESS?
		 JRST UPGS7	;YES, WAITED FOR COMPLETION
		JRST UPGS4]	;NO, COMPLETED
	MOVX B,CORMB
	HRRZ C,A
	TDNN B,CST0(C)		;PAGE IN CORE MODIFIED?
	TXNE P3,UPGSLF		;OR SWAPPING BECAUSE DRUM FULL?
	JRST UPGS8		;YES, SWAPOUT PAGE
	LOAD B,STGADR,CST1(C)	;NO, SEE IF MODIFIED ON DRUM
	TXNN B,DSKAB		;PAGE BACKUP ON DRUM?
	TXNN B,DRMAB
	JRST UPGS4		;NO, DON'T SWAPOUT
	CALL GDSTX		;YES, GET DRUM INFO
	MOVX C,BWRBIT
	TDNN C,(B)		;MODIFIED ON DRUM?
	JRST UPGS4		;NOT MODIFIED, NO UPDATE NEEDED
UPGS8:	CALL SKPNWR		;WRITE IN PROGRESS?
	 JRST UPGS7		;YES, RECHECK PAGE
	CALL AGECHK		;ASSIGN PAGE
	CALL SKPNLK		;SKIP IF PAGE NOT LOCKED IN CORE
	 JRST UPGS4		;LOCKED, SKIP IT
	MOVX B,DSKSWB
	IORM B,CST3(A)		;REQUEST SWAP TO DISK
	JXN P3,UPGKPF,[CALL SWPOTK ;SWPOUT AND USE ONRQ
		JRST UPGS4]
	CALL SWPOT0		;WRITE PAGE
UPGS4:	OKSKED
	JRST UPGS3		;CONTINUE SCAN OF PT

repeat 0,<
;CASES OF BAD POINTER

UPGBPP:	BUG(ILPPT2)
	OKSKED
	JRST UPGSX		;QUIT WITHOUT FURTHER ADO
>
;ASSIGN OFN
; AC1/ (STGADR) INDEX BLOCK FILE ADDRESS (DISK, DRUM OR CORE)
;	   0 UNRESTRICTED BIT (FILUB)
;          1 WRITE BIT (FILWB)
;          2 THAWED BIT (THAWB)
;	   3 NEW FILE BIT (FILNB)
;	     DON'T UPDATE BIT (OFNDUD)
;	     SUBINDEX BLOCK FOR LONG FILE (OFN2XB)
; AC2/ STRUCTURE NUMBER
; AC3/ DIRECTORY NUMBER
; AC4/ REMAINING PAGES (DRLIQ - DRDCA)
;RETURN SKIP WITH OFN IN AC1 IF PROPER OPENING
;RETURN NO-SKIP IF ILLEGAL SHARED OPENING (ILLEGAL CONFIGURATION
;      OF THAWED AND WRITE BITS)
;FILWB AND THAWB PROVIDE FOR 4 MODES OF OPENING:
; 00 - OPEN FOR READ, OTHER READERS AND 1 OTHER WRITER ALLOWED
; 10 - OPEN FOR WRITE, OTHER READERS ALLOWED BUT NO OTHER WRITERS
; 11 - OPEN 'THAWED' - ARBITRARY OTHER READERS AND WRITERS ALLOWED
; 01 - OPEN 'RESTRICTED' - NO OTHER OPENS ALLOWED
;AC USAGE:
; Q1 - XB ADDRESS/CHECKSUM OF XB
; Q2 - OFN
; FX - STRUCTURE NUMBER
;ENTRY AT ASLOFN ASSIGNS OFN ONLY IF IT ALREADY EXISTS OR
;CURRENT OFN USAGE IS BELOW LONG FILE CUTOFF

ASGOFP::TLO T3,-1		;ENTRY POINT FOR PAGE TABLE TABLES (SUPER XB)
	JRST ASGOF3		;JOIN COMMON CODE

ASGOFL::TXO T1,OFN2XB		;REMEMBER SUBINDEX BLOCK ENTRY
ASGOFN::TLZ T3,-1		;SHOW NOT A PAGE TABLE TABLE
ASGOF3:	SAVEQ
	HRRZ FX,T2		;SAVE STRUCTURE NUMBER
	HRRZ Q2,T3		;COPY DIRECTORY NUMBER
ASGOF1:	CAIGE FX,STRN		;A VALID STRUCTURE NUMBER?
	SKIPN STRTAB(FX)	;YES. DOES THE STRUCTURE EXIST?
	BUG (STRBAD)
	TRVAR <PGASG,DNASG,SVX,ENTTYP,TBLTYP,ACCB>
	MOVEM T1,ACCB		;SAVE ALL ACCESS BITS
	HLLZM T3,TBLTYP		;SAVE PAGE TABLE TYPE
	HRRZ T3,T3		;CLEAR INDICATOR
	SETZM ENTTYP		;CLEAR FLAG
	TXNE T1,OFN2XB		;SUB XB?
	HRRZM P,ENTTYP		;YES, NOTE POSITVE NON-0 FLAG
	MOVEM T4,PGASG		;PAGE ALLOCTION
	MOVEM Q2,DNASG		;DIR NUMBER
ASOFC:	LOAD Q1,STGADR,1	;GET ADDRESS ONLY
	AND 1,[FILWB+THAWB+FILNB+OFNDUD+OFN2XB] ;GET BITS CALLER ALLOWED TO SPECIFY
	IOR 1,Q1		;CONSTRUCT COMPOSIT WORD FOR SPTH
	NOSKED
	TLNN 1,(DSKAB)		;DISK?
	JRST [	MOVEI 1,OPNX16	;NO, RETURN BAD
		JRST ASOFXB]
	MOVEM 1,SVX		;SAVE ADDRESS
ASGOF2:	CALL OFNSRC		;SEARCH SPTH FOR GIVEN DSK ADR
	 JRST ASOF4		;NOT FOUND, GO ADD TO TABLE
	HRRZ Q2,1		;FOUND, GET OFN
	MOVX 2,SPTLKB
	TDNE 2,SPTH(Q2)		;OFN LOCKED?
	JRST [	HRLZ 1,1	;YES, MUST WAIT
		CALL WTOFNL
		MOVE 1,SVX	;RECOVER ADDRESS
		JRST ASOFC]	;START OVER
	IORM 2,SPTH(Q2)		;LOCK IT
IFN SPTDSW,<			;ONLY IF DEBUGING SPTLKB PROBLEMS
	EXCH T1,Q2		;GET OFN INDEX
	CALL SPTRAC		;TRACE WHO LOCKED THIS
	EXCH T1,Q2		;RESTORE ACS
 >				;END OF IFN SPTDSW
	NOINT			;NOINT FOR EACH SPT LOCK
	; ..
;SHARED OPEN, CHECK WRITE AND THAWED BITS FOR LEGAL COMBINATION

	SKIPE ENTTYP		;LONG FILE OFN?
	IFSKP. <
	 BLCAL. CHKACC,<Q2,ACCB> ;NO, CHECK FOR LEGAL SIMUL OPEN
	  JRST ASOFB>		;NOT LEGAL, RETURN BUSY
	TMNE ALOCX,(Q2)		;HAVE AN ALLOC ENTRY YET?
	IFSKP. <CALL ASGALC>	;NO, GO GET ONE FOR THIS OFN
	TMNE FILUB,ACCB		;AN UNRESTRICTED OPEN?
	IFSKP. <INCR OFOPC,(Q2)> ;NO, COUNT REGULAR OPENS
;**;[2915] Insert 3 lines at ASGOF2: + 22L	DSC	22-Feb-83

	MOVX T1,OFNDUD		;[2915]GET "DON'T UPDATE DISK" BIT
	TDNE T1,ACCB		;[2915]DOES THIS OPENER WANT IT?
	IORM T1,SPTH(Q2)	;[2915]YES, SET IT

	MOVE T1,Q2		;RETURN OFN
	CALL UPSHR		;INCREMENT SHARE COUNT
	CALL ULKOFN		;UNLOCK
	JRST ASOFXG		;RETURN GOOD

ASOFB:	HRRZ 1,Q2
	CALL ULKOFN		;UNLOCK OFN
	MOVEI 1,OPNX9		;ERROR NUMBER FOR FILE BUSY
	JRST ASOFXB

;EXITS FROM ASOFN

ASOFXB:	TDZA 2,2		;EXIT "BAD"
ASOFXG:	SETO 2,			;EXIT "GOOD"
	OKSKED
	JUMPE 2,R		;BAD = NOSKIP RETURN
	RETSKP			;GOOD = SKIP RETURN

;**;[2958]  Add 8 lines after ASOFXG:+3		DML	4-MAY-83
BGCTYP:	GTAD			;[2958] GET TIME
	CAMGE T1,INFTMR		;[2958] IS IT TIME TO ISSUE BUGINF AGAIN?
	RET			;[2958] NO, RETURN
	ADDI T1,^D5461		;[2958] ADD 30 MINUTES TO CURRENT TIME
	MOVEM T1,INFTMR		;[2958] STORE AS TIME OF NEXT BUGINF
	BUG (NOOFN)		;[2958] ISSUE BUGINF
	RET			;[2958] RETURN
;COULD NOT FIND MATCHING OFN. CREATE ONE.

ASOF4:	SKIPE ENTTYP		;ASLOFN ENTRY?
	JRST [	MOVE Q2,NOF	;YES. GET "OPEN FILE COUNT"
		CAIGE Q2,NOFN-NROFN-1 ;CAN WE OPEN ANOTHER LONGY?
		JRST .+1	;YES. PROCEED
		SKIPG ENTTYP	;FIRST TIME?
;**;[2958]  Replace 1 line with 2 at ASOF4:+5		DML	4-MAY-83
		JRST [	CALL BGCTYP  ;[2958] NO, ISSUE NOOFN BUGINF
			MOVEI T1,OPNX10  ;[2958] BOMB
			JRST ASOFXB] ;GIVE UP
		CALL FREOFN	;YES. CLEAN UP OFNS AND TRY AGAIN
		 JFCL
		SETOM ENTTYP	;SAY DONE IT ONCE
		MOVE T1,SVX	;GET BACK ARG
		JRST ASGOF2]	;AND TRY AGAIN
	JUMPN 1,ASOF6		;JUMP IF HAVE DELETED ENTRY TO REUSE
	MOVE 1,MAXSPL		;MUST MAKE NEW ENTRY
	CAIL 1,NOFN-1		;ROOM?
	JRST [	CALL FREOFN	;TRY RELEASING ALL "UNSHARED" OFN
		 SKIPA		;NONE FOUND
		JRST [	MOVE T1,SVX ;GET BACK OFN
			JRST ASGOF2] ;AND TRY AGAIN
;**;[2958]  Add 1 line after ASOF6:-4			DML	4-MAY-83
		CALL BGCTYP	;[2958] ISSUE NOOFN BUGINF
		MOVEI 1,OPNX10	;SAY 'NO ROOM'
		JRST ASOFXB]	;RETURN BAD
	AOS 1,MAXSPL		;GET NEXT FREE ENTRY
ASOF6:	HRRZ Q2,1
	MOVE 1,SVX		;RECOVER CLASS AND BITS
	TLZE 1,(FILNB)		;NEWLY ASSIGNED XB?
	TLO Q1,(DSKNB)		;YES, INDICATE IN DISK ADDRESS
	MOVEM 1,SPTH(Q2)
	MOVEM Q1,SPT(Q2)	;PUT ADDRESS IN SPT
	STOR FX,STRX,(Q2)	;PUT IN STRUCTURE NUMBER
	CALL ASGALC		;GET ALLOC ENTRY FOR OFN
	AOS NOF			;COUNT OPEN FILES
	MOVEI 1,1		;SHARE COUNT WILL BE ONE
	STOR 1,OFNSHC,(Q2)	;STORE IT
	SETZRO OFOPC,(Q2)	;INIT COUNT OF REGULAR OPENS
	TMNE FILUB,ACCB		;AN UNRESTRICTED OPEN?
	IFSKP. <INCR OFOPC,(Q2)> ;NO, COUNT REGULAR OPENS
	; ...
	; ..
	HRRZ 3,Q2		;COPY OFN
	CALL SETXB1		;MAP XB
	HRRZ T1,Q2		;GET OFN AGAIN
	CALL LCKOFN		;LOCK THE OFN (SOULDN'T BE LOCKED YET
	OKSKED			;NOW ALLOW OTHERS TO  RUN
	SKIP CXBPGA		;GET XB IN MEMORY
	NOSKED			;TAKE OVER MACHINE AGAIN
	CALL ULKOFN		;AND UNLOCK THE OFN
	SKIP CXBPGA		;MUST BE SURE IT IS STILL IN MEMORY
	HRRZ 1,SPT(Q2)		;CORE ADDRESS
	MOVSI 2,(SWPERR)
	TDNE 2,CST3(1)		;DISK ERROR IN XB?
	JRST ASCHK3		;YES, DON'T OPEN
	TXNE Q1,DSKNB		;NEW XB?
	JRST [	MOVX 1,OFNWRB	;YES, NOTE CHANGE FOR NEXT UPDATE
		IORM 1,SPTH(Q2)
		JRST ASCHK4]	;NO CHECKSUM TO COMPUTE
	MOVE A,CXBPGA+XBBWRD	;SEE IF XB HAS A BAD ENTRY
	MOVX B,OFNBAT		;IN CASE IT DOES
	TXZE A,XBBAT		;IS IT SET?
	IORM B,SPTH(Q2)		;YES. REMEMBER THIS IN SPT
	MOVEM A,CXBPGA+XBBWRD	;STORE NEW XB WORD
	MOVEI A,Q1		;POINT TO Q1 TO STORE CHECKSUM
	MOVE B,[XBCKSM+CXBPGA]	;CHECKSUM IS IN FIRST 4 WDS OF XB
	CALL LDXBD		;GET CHECKSUM FROM XB
	SETCA Q1,		;COMPLEMENT IT, SHOULD THEN ADD TO 0
	JCRY0 .+1
	MOVSI 1,-PGSIZ		;SETUP TO SCAN XB
ASCHK1:	LOAD 2,STGADR,CXBPGA(1)	;GET ADDR FROM XB
	JUMPE 2,[ADDI Q1,0(1)	;USE XB INDEX IF WORD EMPTY FOR CHECKSUM
		JCRY0 [AOJA Q1,ASCHK2] ;WRAPAROUND CARRY
		JRST ASCHK2]
	ADD Q1,2		;DO CHECKSUM
	JCRY0 [AOJA Q1,.+1]	;WRAPAROUND CARRY
	IOR 2,IMMPTR		;CONSTRUCT IMMED PTR
ASCHK2:	MOVEM 2,CXBPGA(1)
	AOBJN 1,ASCHK1
	CAME Q1,[-1]		;CHECKSUM OK? (0 OR -0)
	JUMPN Q1,ASCHK3		;JUMP IF CHECKSUM BAD
ASCHK4:	SKIPE TBLTYP		;ASGOFP ENTRY? (IS THIS A PAGE TABLE TABLE?)
	JRST [	CALL CHKLAC	;YES - CHECK ACCESS FOR LONG FILES
		 JRST ASCHK5	;INVALID ACCESS - TELL USER
		JRST .+1]	;ACCESS ALL RIGHT
	CALL RELCXB		;OK, RELEASE XB
	HRRZ 1,Q2		;RETURN OFN IN 1
	JRST ASOFXG
;ASOFN...
;HANLDE RELEASING OF OBTAINED INDEX BLOCK

ASCHK5:	MOVEI 1,OPNX9		;SHOW INVALID ACCESS
	SKIPA
ASCHK3:	MOVEI 1,OPNX16		;INDICATE BAD PAGE ENTRY
	MOVEM 1,ENTTYP		;AND SAVE
	CALL RELCXB		;FILE NO GOOD, RELEASE XB
	PUSH P,SPT(Q2)		;SAVE CORE ADR
	MOVE 1,Q2
	CALL DASOFN		;DEASSIGN OFN SLOT
	POP P,1			;RECOVER CORE ADR
	CALL DECOR
	HRRZS 1
	SETZM CST2(1)
	CALL OFRQ		;PUT ON TOP OF RPLQ SINCE PAGE IS USELESS
	MOVE 1,ENTTYP		;GET ERROR INDICATOR
	JRST ASOFXB

;ERROR IN ALLOCATION TABLE

ASG6X:	BUG (OVFLOW)
;ROUTINE TO LOOK FOR AN APPROPRIATE ALLOC ENTRY

ASGALC:	MOVE T1,DNASG		;DIRECTORY NUMBER
	MOVE T2,FX		;STRUCTURE NUMBER
	CALL GETCAL		;SEE IF CURRENT ENTRY
	 JRST ASOF6A		; NO - MAKE NEW ENTRY
	JRST ASOF6B		;JUST INCREMENT COUNT

;HERE TO CREATE NEW DIRECTORY ALLOCATION ENTRY

ASOF6A:	MOVE T2,[-<NOFN-1>,,1]	;PREPARE AOBJN PNTR
	TMNE ALCWD,(T2)		;LOOK FOR EMPTY SLOT
	AOBJN T2,.-1		;...
	JUMPGE T2,ASG6X		;ERROR IF NO ROOM
	MOVE T1,DNASG		;GET DIRECTORY NUMBER
	STOR T1,ADIRN,(T2)	;SAVE IN TABLE
	MOVE T1,PGASG		;PAGES LEFT IN QUOTA
	STOR T1,PGLFT,(T2)	;STORE
ASOF6B:	STOR T2,ALOCX,(Q2)	;TABLE INDEX TO SPT
	SETZM OFNLEN(Q2)	;CLEAR EOF INFO
	INCR ODIRC,(T2)		;INCREMENT OFN DIRECTORY COUNT
	RET			;ALL DONE.
;ROUTINE TO CHECK THE EXISTANCE AND ACCESS OF THE FIRST OFN
;OF A LONG FILE.  THIS CHECK FIXES A BUG THAT ALLOWS A LONG
;FILE TO BE OPENED WHILE IT'S BEING ACCESSED BY AN OFN WHICH
;KNOWS IT ONLY AS A SHORT FILE.  CHECKING FOR THE EXISTENCE OF
;THE "SHORT" FILE AND IT'S ACCESS GUARANTEES PROPER ACCESS.

;MUST BE CALLED NOSKED
;ACCEPTS:	Q2/ OFN OF LONG FILE

;RETURNS:	+1, INVALID ACCESS
;		+2, ACCESS OK

CHKLAC:	SAVEAC <Q1>		;GET A REG
	LOAD Q1,STGADR,CXBPGA	;GET GET DISK ADDRESS OF FIRST FILE SECTION
	CALL OFNSRC		;SEE IF ANYONE HAS IT OPEN AS A SHORT FILE
	 RETSKP			;NO - ACCESS VALID
	BLCAL. CHKACC,<T1,SVX>	;DO GENERAL ACCESS CHECK
	 RET			;FAILED
	RETSKP			;OK

	ENDTV.			;END OF TRVAR AT ASGOFN
;GENERAL FILE ACCESS CHECK
; BLCAL. CHKACC,<OFN,BITS FOR THIS OPEN>

CHKACC:	BLSUB. <EOFN,NEWB>
	SAVEAC <Q1>
	HRRZ Q1,EOFN		;KEEP OFN FOR INDEX
	MOVE T2,NEWB
	TXNE T2,FILUB		;UNRESTRICTED OPEN?
	RETSKP			;YES, ALWAYS WORKS
	LOAD T1,OFOPC,(Q1)	;COUNT OF EXISTING REGULAR OPENS
	JUMPE T1,[XOR T2,SPTH(Q1) ;IF NONE, THIS IS LIKE A FIRST OPEN
		ANDX T2,FILWB+THAWB+OFNDUD+OFN2XB
		XORM T2,SPTH(Q1) ;SET ALL BITS
		RETSKP]		;OK
	MOVE T1,SPTH(Q1)
	TLNE 1,(THAWB)		;FILE NOW OPEN THAWED OR RESTRICTED?
	JRST [	XOR 1,2		;YES, COMPARE EXISTING AND NEW MODES
		TLNN 1,(FILWB+THAWB) ;BOTH THE SAME?
		TLNN 2,(FILWB)	;AND NOT RESTRICTED?
		RET		;NO, REPORT BUSY
		RETSKP]		;THIS OPEN OK
	TLNE 2,(THAWB)		;NEW OPEN CONSISTENT?
	RET			;NO, REPORT BUSY
	TLNN 2,(FILWB)		;NEW OPEN WANTS WRITE?
	RETSKP			;NO, MUST BE OK
	TLOE 1,(FILWB)		;YES, FILE ALREADY HAS WRITER?
	RET			;YES, REPORT BUSY
	MOVEM T1,SPTH(Q1)	;UPDATE FILE STATUS
	RETSKP			;NO - ACCESS OK

	ENDBS.
;ROUTINE TO FREE ALL "UNSHARED" OFNS. CALLED WHEN OFN'S
;RUN OUT
;MUST BE CALLED NOSKED
;RETURNS:	+1 NONE FOUND. OFN'S STILL EXHAUSTED
;		+2 AT LEAST ONE FOUND AND FREED

FREOFN:	SAVEAC <Q1>		;GET A WORK REG
	HRLZ T1,MAXSPL		;GET HIGHEST OFN
	MOVN T1,T1		;MAKE AOBJN POINTER
	HRRI T1,1		;START AT FIRST OFN
	SETZM Q1		;NONE FOUND YET
FREOF1:	SKIPN SPTH(T1)		;THIS ONE IN USE?
	JRST FREOF3		;NO. GO ON
	PUSH P,T1		;SAVE AOBJN WORD
	CALL GETSHR		;SEE IF SHARED
	JUMPN T1,FREOF2		;IF SO, JUMP OFF
;**;[3005] ADD 7 LINES AT FREOF1:+5L	TAM	29-AUG-83
	HRRZ T1,0(P)		;[3005] GET OFN AGAIN
	LOAD T1,STGADR,SPT(T1)	;[3005] GET STORAGE ADDRESS
	MOVX T2,-PLKV		;[3005] GET LOCK MASK
	TXNN T1,NCORTM		;[3005] IN CORE NOW?
	TDNN T2,CST1(1)		;[3005] YES. LOCKED IN CORE?
	SKIPA			;[3005] NOT IN CORE OR NOT LOCKED. COLLECT IT
	JRST FREOF2		;[3005] LOCKED IN CORE. LEAVE IT
	HRRZ T1,0(P)		;NOT SHARED.
	CALL CLROFN		;COLLECT IT
	AOS Q1			;FOUND ONE
FREOF2:	POP P,T1		;RESTORE AOBJN POINTER
FREOF3:	AOBJN T1,FREOF1		;DO THEM ALL
	JUMPE Q1,R		;IF NONE FOUND. +1
	RETSKP			;IF SOME FOUND. +2
;CHECK OFN -- SEE IF FILE IN USE BUT DO NOT OPEN
; A/ DISK ADR OF XB (SAME AS ASOFN)
; B/ STRUCTURE NUMBER
;	CALL CHKOFN
; RETURN +1, FILE ALREADY OPEN
; RETURN +2, FILE NOT OPEN

CHKOFN::SAVEQ
	LOCK DIRCLK
	CALL DIRCFL		;FLUSH DIRECTORY CACHE
	MOVE FX,B		;SAVE STRUCTURE NUMBER
	LOAD Q1,STGADR,1	;SETUP XB ADR
	CALL OFNSRC		;SEARCH FOR IT
	JRST [	UNLOCK DIRCLK
		RETSKP]		;NOT FOUND
	UNLOCK DIRCLK		;UNLOCK DIR CACHE
	RET			;FOUND


;LOCAL ROUTINE TO SEARCH SPTH FOR GIVEN XB ADR
; Q1/ DISK ADR
; FX/ STRUCTURE NUMBER
;	CALL OFNSRC
; RETURN +1, NOT FOUND; 1/ FIRST FREE ENTRY OR 0
; RETURN +2, FOUND; 1/ INDEX

OFNSRC:	HRLZ 1,MAXSPL		;GET COUNT OF ENTRIES IN USE
	MOVN 1,1		;SETUP AOBJN PTR
	HRRI 1,1		;START WITH ENTRY 1 OF SPT
	SETZ 3,			;INIT PLACE TO HOLD DELETED ENTRY IF FOUND
	JUMPGE 1,OFNSR3		;QUIT NOW IF TABLE EMPTY
OFNSR1:	MOVX 2,OFNDMO		;GET DISMOUNTED BIT
	TDNE 2,SPTH(1)		;IS THIS A DISMOUNTED OFN?
	JRST OFNSR2		;YES. DON'T CONSIDER IT
	LOAD 2,STGADR,SPTH(1)	;GET ADR
	JUMPE 2,[SKIPN 3	;ENTRY NOT IN USE, KEEP IT?
		HRRZ 3,1	;YES
		JRST OFNSR2]
	LOAD D,STRX,(1)		;GET THIS ENTRY'S STRUCTURE NUMBER
	CAIN D,0(FX)		;SAME AS REQUESTED?
	CAME B,Q1		;YES. IS DISK ADDRESS THE SAME?
	SKIPA			;NO. LOOK AT MORE
	RETSKP			;YES, DONE
OFNSR2:	AOBJN 1,OFNSR1		;SEARCH ALL EXTANT ENTRIES
OFNSR3:	MOVE 1,3		;NOT FOUND, RETURN FIRST FREE SEEN
	RET
;LOCAL ROUTINE TO DELETE OFN SLOT
; T1/ OFN
;	CALL DASOFN
; RETURN +1 ALWAYS, REDUCE END OF TABLE IF POSSIBLE

DASOFN:	SETZM SPTH(T1)		;FLUSH GIVEN ENTRY
	CALL DASALC		;CLEAR ALLOC DATA
	SETZRO OFNSHC,(T1)	;CLEAR SHARE COUNT IN THE OFN
	SOS NOF			;NOTE ONE LESS OPEN FILE
	CAME T1,MAXSPL		;THIS ENTRY LAST ONE IN TABLE?
	RET			;NO, DONE
DASOF2:	SOSE T2,MAXSPL		;YES, REDUCE LENGTH OF TABLE
	SKIPE SPTH(T2)		;NEW LAST ENTRY ALSO FREE?
	RET
	JRST DASOF2		;YES, REDUCE AGAIN

;ROUTINE TO CLEAR ALLOC DATA FROM OFN
;	T1/ OFN

DASALC:	LOAD T2,ALOCX,(T1)	;GET INDEX TO ALLOCATION INFO
	JUMPE T2,R		;IF NO TABLE, RETURN
	SETZM OFNLEN(T1)	;ZERO LENGTH INFO
	SETZRO ALOCX,(T1)	;ZERO IT
	DECR ODIRC,(T2)		;DECREMENT OFN COUNT
	JN ODIRC,(T2),R		;OK IF STILL OPEN OFN'S
	SETZRO ALCWD,(T2)	;CLEAR SLOT IF COUNT =0
	SETZRO PGLFT,(T2)	; ...
	RET			;AND DONE
;LOCK/UNLOCK OFN
;LOCKING OFN PREVENTS ANY CHANGE TO IT, E.G. ADDING OR DELETING PAGES

;LOCK OFN
; A/ OFN
;	CALL LCKOFN
; RETURN +1 ALWAYS, BLOCK AND WAIT IF ALREADY LOCKED

LCKOFN:
LCKOF1:	MOVX 2,SPTLKB
	NOSKED
	TDNE 2,SPTH(1)		;LOCK NOW CLEAR?
	JRST [	HRLZ 1,1	;SETUP SCHED TEST
		CALL WTOFNL	;OKSKED AND DISMISS
		HLRZ 1,1	;RECOVER OFN
		JRST LCKOF1]	;TRY AGAIN
	IORM 2,SPTH(1)		;SET LOCK
IFN SPTDSW,<			;ONLY IF DEBUGING SPTLKB PROBLEMS
	CALL SPTRC2		;RECORD WHO LOCKED SPTLKB
 >				;END OF IFN SPTDSW
	NOINT			;NOINT FOR EACH SPT LOCK
	OKSKED
	RET

;ROUTINE TO DO OKSKED AND DISMISS FOR OFN LOCK
; A/ OFN,,0
;	CALL WTOFNL
; RETURN +1 ALWAYS

WTOFNL:	OKSKED
	HRRI A,OFNLKT
	MDISMS
	RET

;SCHED TEST FOR OFN UNLOCKED

OFNLKT:	MOVX 2,SPTLKB
	TDNE 2,SPTH(1)
	JRST 0(4)
	JRST 1(4)

;UNLOCK OFN
; A/ OFN
;	CALL ULKOFN
; RETURN +1 ALWAYS

;**;[2960]Change one line at ULKOFN: +0L	RWW	9-May-83
ULKOFN:	MOVX 2,SPTLKB		;[2960]Make ULKOFN global
	ANDCAM 2,SPTH(1)	;CLEAR LOCK
	OKINT
	RET

IFN SPTDSW,<			;ONLY IF DEBUGING SPTLKB PROBLEMS

SPTRAC:				;TRACE WHO LOCKED SPTLKB
	PUSH P,T2		;SAVE AC T2
	HRR T2,-1(P)		;GET OUR CALLING PC
SPTRC3:
	HRL T2,FORKX		;GET OUR FORK INDEX
	MOVEM T2,SPTO3(T1)	;SAVE FORKX,,PC
	POP P,T2		;GET T2 BACK
	RET			;AND RETURN TO CALLER

SPTRC2:				;TRACE WHO CALLED ROUTINE TO LOCK SPTLKB
	PUSH P,T2		;SAVE T2
	HRR T2,-2(P)		;GET CALLERS CALLERS PC
	JRST SPTRC3		;JOIN COMMON CODE

 >				;END OF IFN SPTDSW
;LOCK/UNLOCK FOR CONVENIENCE WHERE PAGE ID IN A

;LOCK OFN

LCKOFI:	SAVET
	HLRZ A,A		;GET OFN
	CAIGE A,NOFN		;REALLY AN OFN?
	CALL LCKOFN		;YES, LOCK IT
	RET

;UNLOCK

ULKOFI:	SAVET
	HLRZ A,A		;GET OFN
	CAIGE A,NOFN		;REALLY AN OFN?
	CALL ULKOFN		;YES, UNLOCK IT
	RET
;RELEASE/DELETE OFN
; A/ FILWB+FILUB,,OFN
;	CALL RELOFN/DELPT
; RETURN +1 ALWAYS, A/ PAGE COUNT IN XB IF FILE COMPLETELY CLOSED,
;		-1 IF FILE NOT COMPLETELY CLOSED.

DELOF==1B0			;LOCAL FLAG IN Q1 FOR DELETE/RELEASE

DELPT::	SAVEQ
	MOVX Q1,DELOF		;SAY DELETE
	JRST RELOF0

RELOFN::SAVEQ
	MOVEI Q1,0		;SAY RELEASE
RELOF0:	TRVAR <OFNX,XBX,ACCB>
	HLLZM T1,ACCB		;SAVE ACCESS BITS
	HRRZ T1,T1		;OFN ONLY
	MOVEM T1,OFNX		;SAVE IT
	CALL LCKOFN		;LOCK THE OFN
	MOVE 2,1		;MOVE OFN
	CALL GETSHR		;GET OFN SHARE COUNT
	EXCH 1,2		;COUNT TO 2 AND OFN TO 1
	CAIE 2,1		;IS THIS FINAL CLOSE?
	JRST RELOF6		;NO
	NOSKED
	MOVX 2,OFNDMO		;CHECK IF DISMOUNTED
	TDNE 2,SPTH(1)		;IS IT?
	JRST [	CALL DASOFN	;YES. DEASSIGN THE OFN
		OKSKED		;ALLOW SCHEDULING AGAIN
		OKINT		;ALLOW INTS AGAIN
		RET]		;AND DONE
	MOVEI 3,0(1)
	CALL SETXB1		;MAP INDEX BLOCK
	OKSKED
	SKIP CXBPGA		;TOUCH XB WHILE OKSKED
	NOSKED
RLOF00:	SKIP CXBPGA		;SWAP IN XB, IF NECESSARY
	LOAD T1,STGADR,SPT(T1)	;GET CORE PAGE
	CALL SKPNWR		;MAKE SURE NOT BEING WRITTEN
	 JRST [	MOVE T1,OFNX	;IT WAS. GET OFN AGAIN
		JRST RLOF00]	;AND TRY IT AGAIN
	MOVX T3,PLKV		;GET A UNIT OF LOCK COUNT
	ADDM T3,CST1(T1)	;LOCK XB FOR REST OF RELOFN
	MOVE T1,OFNX		;GET THE OFN
	CALL SCNOFN		;MOVE ALL OF THE PAGES TO DISK
	 JRST [	EXCH T1,OFNX	;SAVE COUNT. GET OFN
		CALL ULKOFN	;UNLOCK THE OFN
		MOVE T1,OFNX	;RESTORE COUNT
		JRST RELOF4]	;AND GIVE UP.
	SKIPE Q2,T1		;FOUND SOME PAGES
	TXNN Q1,DELOF		;YES. WANT DELETE?
	JRST RELOF7		;NO. GO ON
	MOVEM Q2,XBX		;YES. SAVE COUNT OF PAGES
	MOVE 2,OFNX		;GET OFN
	LOAD 3,ALOCX,(2)	;GET INDEX
	OPSTRM <ADDM Q2,>,PGLFT,(3) ;UPDATE COUNT OF PAGES
	MOVE 2,SPTH(2)
	TXNN 2,OFNBAT		; A BAD OFN?
	JRST OFNDLN		;NO. DO A FAST DELETE THEN
	JRST DELBAD		;YES, GO DELETE BAD OFN
RELOF7:	TXNN Q1,DELOF
	JRST [	MOVE T1,OFNX	;NOT DELETE. GET OFN
		OKSKED		;ALLOW INTERRUPTION
		CALL UPDOFI	;UPDATE OFN AND BTB IF NECESSARY
		NOSKED
		JRST .+1]	;DONE
	MOVE 1,OFNX		;RECOVER OFN
	CALL DWNSHR		;DECREMENT SHARE COUNT
	MOVE 3,SPTH(1)		;SAVE FLAGS
	MOVEM 3,XBX		;SAVE FLAGS
	LOAD C,STRX,(1)		;GET STRUCTURE NUMBER
	MOVEM C,OFNX		;SAVE IT FOR LATER
	CALL DASOFN		;RELEASE SPT SLOT
	LOAD 1,STGADR,SPT(1)	;GET (CORE) ADDRESS OF XB
	MOVSI T2,(-PLKV)	;GET A NEGATIVE UNIT OF LOCK COUNT
	ADDM T2,CST1(T1)	;UNLOCK XB
	OKINT			;MATCH NOINT DONE BY LCKOFN
	CALL REMFP1		;FLUSH CORE AND DRUM ADDRESSES
	SKIPN 1
	BUG(NOADXB)
	MOVE 2,XBX		;RESTORE FLAGS
	MOVE C,OFNX		;GET STRUCTURE NUMBER
	TXNE Q1,DELOF		;DELETING FILE?
	CALL DEDSKC		;YES, DELETE DISK ADR OF XB
	MOVE 1,Q2		;RETURN PAGE COUNT
RELOF4:	CALL RELCXB		;RELEASE TEMP MAPPING
	OKSKED
	RET
;THIS ROUTINE IS GOTTEN TO WHEN THE CALLER WANTS TO DELETE THE
;OFN AND IT DOES NOT CONTAIN A BAT BLOCK.

OFNDLN:	MOVSI Q2,-PGSIZ		;SCAN WHOLE XB
OFNDL1:	SKIPN CXBPGA(Q2)	;AN ENTRY HERE?
	JRST OFNDL2		;NO
	LOAD 1,STGADR,CXBPGA(Q2) ;GET DISK ADDRESS
	MOVE B,OFNX		;GET OFN
	LOAD B,STRX,(B)		;GET STRUCTURE NUMBER
	CALL DEDSK		;RELEASE THE PAGE
	SETZM CXBPGA(Q2)	;CLEAN UP
OFNDL2:	AOBJN Q2,OFNDL1		;DO WHOLE XB
	JRST RELOF7		;NOW GO DO XB ITSELF

;RETURN WHEN FILE NOT CLOSED BECAUSE SHARE COUNT NOT 0

RELOF6:	CALL DWNSHR		;DECREMENT SHARE COUNT
	TMNE FILUB,ACCB		;CLOSING AN UNRESTRICTED ACCESS?
	JRST RELOF1		;YES, NO CHANGE
	DECR OFOPC,(T1)		;COUNT REGULAR OPENS
	MOVE 2,SPTH(1)		;GET CURRENT BITS
	TXNN 2,OFNDMO		;DISMOUNTED?
	TLNE 2,(THAWB)		;OPEN IN RESTRICTED OR THAWED MODE?
	JRST RELOF1		;YES, NO UPDATE OF BITS NEEDED
	TMNE FILWB,ACCB		;NO, IS THIS THE WRITER?
	TLZ 2,(FILWB)		;YES, AFTER THIS CLOSE, FILE HAS NO WRITER
	MOVEM 2,SPTH(1)		;UPDATE BITS
RELOF1:	CALL ULKOFN		;UNLOCK OFN
	SETO 1,			;RETURN -1 FOR COUNT
	RET


;CLEAR OFN FOUND WHEN SWAPPING OUT PAGE
; A/ OFN

CLROFN:	CALL DASOFN		;RELEASE OFN SLOT
	LOAD 1,STGADR,SPT(1)	;GET CORE ADR
	CALLRET REMFP1		;RELEASE STORAGE
;ROUTINE TO SCAN AN XB AND MOVE ALL OF ITS PAGES TO DISK.
;CALLED WITH T1/ THE OFN
;AND THE XB MAPPED INTO CXBPGA
; RETURNS +1 WITH T1/ COUNT OF PAGES

SCNOFN:	ACVAR <W1,W2,W3>	;GET SOME WORK REGS
	MOVE W3,T1		;SAVE THE OFN
	MOVSI W1,-PGSIZ		;SCAN XB
	SETZ W2,		;INIT COUNT OF IN-USE PAGES
SCNOF3:	MOVE 2,CXBPGA(W1)	;GET PTR
	JUMPE 2,SCNOF2		;JUMP IF EMPTY
	LOAD T1,PTRCOD,T2	;GET PTR TYPE
	CAIE T1,IMMCOD		;PRIVATE?
	JRST RLBAD		;NO, LOSSAGE
	TXNE 2,DSKAB		;ON DSK?
	JRST SCNOF5		;YES
	TXNE 2,NCORTM		;IN CORE?
	JRST [	TXNE 2,DRMAB ;NO, PRIVATE UNASSIGNED?
		JRST .+1	;NO. MUST MOVE IT TO DISK THEN
		SETZM CXBPGA(W1) ;FLUSH UNASSIGNED PTR
		JRST SCNOF2]
	MOVE 4,W1		;SET UP ARGUMENT FOR CALL
	HRL 4,W3		;PROVIDE THE OFN AS WELL
	CALL MOVDSK		;MOVE THE PAGE TO DISK
SCNOF4:	MOVE T1,CXBPGA(W1)	;GET PRESENT ADDRESS
	TXNE T1,NCORTM		;STILL IN CORE?
	JRST SCNOF3		;NO
	LOAD T1,STGADR,T1	;GET JUST PAGE NUMBER IN T1
	CALL SKPNWR		;WAIT FOR WRITE TO COMPLETE
	 JRST SCNOF4		;RECHECK
	LOAD T2,CSTAGE,(T1)	;CHECK STATUS
	CAIE T2,PSRPQ		;ON RPLQ?
	CALL OFRQ		;NO, PUT IT ON
	CALL RPCST		;FORCE DISK ADR BACK TO XB
	JRST SCNOF3		;LOOK AT PTR AGAIN, SHOULD BE DSK ADR

SCNOF5:	AOS W2			;COUNT THE PAGE
SCNOF2:	AOBJN W1,SCNOF3		;SCAN XB
	MOVE T1,W2		;RETURN COUNT OF PAGES FOUND
	RETSKP			;AND DONE

;BAD PAGE FOUND IN OFN
RLBAD:	BUG(ILIBPT,<<W1,D>>)
	SETO 1,			;SAY FILE NOT CLOSED
	RET			;RETURN BAD


	ENDAV.			;END ACVAR
;HERE TO DELETE A FILE (OFN) WHICH HAS ONE OR MORE BAT PAGES IN IT

DELBAD:	OKSKED			;ALLOW SCHEDULING FOR A WHILE
	NOINT			;BUT PREVENT LOCAL INTERRUPTS
	MOVEI 1,FPG3A		;YES. LOCK DOWN A PAGE
	CALL MLKMA		;GET IT
	LSH 1,PGSFT		;MAKE IT A CORE ADDRESS
	MOVE P3,1		;AND SAVE IT
OFNFIN:	SETZ P5,		;NO ERROR HERE
	MOVSI P1,-PGSIZ		;SIZE OF XB
	SETO P2,		;NO DRIVE FOUND YET
	NOSKED			;PROTECT XB SCANNING
TOPOFN:	LOAD 1,STGADR,CXBPGA(P1) ;GET ENTRY
	JUMPE 1,NOPGH		; ANYTHING HERE?
	TXZ 1,DSKAB		;CLEAR DEVICE TYPE
	MOVE B,OFNX		;GET OFN
	LOAD D,STRX,(B)		;GET STRUCTURE NUMBER
	MOVE B,STRTAB(D)	;GET SDB INDEX
	IDIV A,SDBSIZ(B)	;COMPUTE UNIT NUMBER AND LOCAL ADDRESS
	MOVE P4,2		;SAVE DISK ADDRESS
	SKIPL P2		;HAVE A DRIVE YET?
	JRST HAVBAT		;YES. GO LOOK AT IT
	OKSKED			;ALLOW INTS FOR BAT BLOCK LOGIC
	MOVE P2,1		;ESTABLISH THIS DRIVE
	MOVE B,P3		;CORE ADDRESS
	MOVEI C,FPG3A		;VIRTUAL ADDRESS
	CALL RDBAT		;GO READ THE BAT BLOCKS
	 JRST BUMBAT		;NO THERE
	MOVE B,P4		;RESTORE LOCAL DISK ADDRESS
	NOSKED			;PROTECT THE SCANNING
	JRST YESBAT
;HAVE BAT BLOCKS IN FOR THIS UNIT. NOW GO DO COMPARE

HAVBAT:	CAIE A,0(P2)		;IS THIS THE PROPER UNIT?
	JRST NOPGH		;NO
YESBAT:	JUMPN P5,NOTBD1		;IS OK.
	MOVE A,B		;GET LOCAL ADDRESS
	MOVEI B,FPG3A		;WHERE THE BAT BLOCK IS
	MOVE C,OFNX		;GET OFN
	LOAD C,STRX,(C)		;GET STRUCTURE NUMBER
	MOVE C,STRTAB(C)	;GET SDB ENTRY
	LOAD C,STRUDB,(C)	;GET A UDB ADDRESS FOR ONE OF THIS TYPE
	CALL SEEADR		;SEE IF THIS IS THERE
	 JRST NOTBD1		;NO
	JRST BADD		;YES.

NOTBD1:	LOAD 1,STGADR,CXBPGA(P1) ;GET DISK ADDRESS
	MOVE B,OFNX		;GET OFN
	LOAD B,STRX,(B)		;GET STRUCTURE NUMBER
	CALL DEDSK		;RELEASE PAGE
BADD:	SETZM CXBPGA(P1)	;CLEAR SLOT
	SOSG XBX		;ALL DONE?
	JRST ALLDNE		;YES.
NOPGH:	AOBJN P1,TOPOFN		;GO DO REST
	OKSKED			;ALLOW SCHEDULING
	JRST OFNFIN		;AND DONE

BUMBAT:	MOVEI P5,1		;SAY NO BAT BLOCKS HERE
	NOSKED			;PREVENT SCHEDULING
	JRST NOTBD1		;GO FREE THE PAGE

;FINISHED THE SCAN OF THE BAD INDEX BLOCK. NOW RELEASE WORK
;PAGE AND PROCEED TO FREE THE INDEX BLOCK ITSELF.

ALLDNE:	OKSKED			;ALLOW SCHEDULING
	MOVE A,P3		;GET PHYSICAL ADDRESS
	LSH A,-PGSFT		;MAKE IT A PAGE NUMBER
	CALL MULKCR		;AND RELEASE IT
	OKINT			;PAGE IS RELEASED, ALLOW INTERRUPTS AGAIN
	NOSKED			;PROTECT THE XB RELEASE
	JRST RELOF7
;ROUTINE TO MARK THAT AN OFN IS ON A DISMOUNTED STRUCTURE.
;ACCEPTS:	A/ THE OFN
;MUST BE CALLED WITH THE OFN LOCKED AND THE PROCESS NOINT.
;THIS ROUTINE WILL RELEASE ALL LOCAL STORAGE ASSOCIATED WITH THE
;OFN AND WITH ANY SHARE POINTERS ASSOCIATED WITH THE OFN. IN
;ADDITION IT WILL MARK THE OFN AS INVALID SO THAT SUBSEQUENT PAGE
;FAULTS ON IT OR ANY OF ITS PAGES CAN BE CONVERTED INTO MEMORY
;TRAPS.

	SWAPCD			;CALLED FROM PROCESS CONTEXT

INVOFN:	SAVEP			;GET SOME WORK REGISTERS
	HRRZ P2,A		;SAVE OFN HERE

;NOW MAP OFN AND SCAN IT RELEASING ALL PRIVATE STORAGE

	MOVEI T3,0(P2)		;GET OFN IN T3
	CALL SETXB1		;MAP INDEX BLOCK
INVRTY:	MOVSI P1,-PGSIZ		;SCAN ENTIRE INDEX BLOCK
	SKIP CXBPGA		;FAULT IN PAGE BEFORE NOSKED
	NOSKED			;PROTECT THE XB
INOF2:	SKIPN T1,CXBPGA(P1)	;ANYTHING HERE?
	JRST INOF3		;NO. GO ON
	LOAD T2,PTRCOD,T1	;GET POINTER
	CAIN T2,IMMCOD		;IMMEDIATE?
	JRST [	LOAD T1,STGADR,T1 ;GET STORAGE ADDRESS
		CALL REMPGI	;GO ZAP THE PAGE
		 JRST INVRTY	;HAD TO BLOCK. GO CHECK IT AGAIN
		STOR T1,STGADR,CXBPGA(P1) ;PUT SOMETHING BACK
		JRST INOF3]	;AND PROCEED
	LOAD P3,SPTX,T1		;GET SPT INDEX
	LOAD T1,STGADR,SPT(P3)	;GET SPT ADDRESS
	CALL REMPGI		;GO ZAP THE PAGE
	 JRST INVRTY		;HAD TO BLOCK. GO TRY IT AGAIN
	STOR T1,STGADR,SPT(P3)	;PUT IN A NEW ADDRESS
INOF3:	AOBJN P1,INOF2		;DO ENTIRE INDEX BLOCK

;NOW RELEASE STORAGE ASSOCIATED WITH THE OFN

	LOAD A,STGADR,SPT(P2)	;GET CURRENT LOCATION
	CALL REMPGI		;RELEASE THE STORAGE
	 JRST INVRTY		;HAD TO BLOCK. TRY AGAIN
	STOR A,STGADR,SPT(P2)	;PUT IN HOME ADDRESS
	MOVX T2,OFNDMO		;GET DISMOUNTED BIT
	IORM T2,SPTH(P2)	;MARK THE OFN
	MOVE A,P2		;GET OFN
	CALL DASALC		;RELEASE ALOC ENTRY
	OKSKED			;ALLOW SCHEDULING AGAIN
	CALLRET RELCXB		;RELEASE XB MAPPING

;ROUTINE TO RELEASE STORAGE FOR INVOFN. WAITS FOR ANY WRITES TO COMPLETE
;BEFORE CALLING REMFP1

REMPGI:	TXNE T1,DSKAB!DRMAB	;IS THIS A CORE PAGE?
	JRST REMPG2		;NO. GO RELEASE IT NOW
	PUSH P,T1		;YES. SAVE I.D.
REMPG1:	CALL SKPNWR		;WAIT FOR WRITE TO COMPLETE
	IFSKP.
	  CALL SKPNLK		;PAGE LOCKED?
	ANSKP.
	ELSE.
	  CALL WTNLK		;LOCK OR WRITE WAS IN PROGRESS, WAIT FOR UNLOCK
	  POP P,0(P)
	  OKSKED
	  RET			;RETURN FOR RETRY
	ENDIF.
	POP P,T1		;RESTORE I.D.
REMPG2:	CALL REMFP1		;GO RELEASE STORAGE
	RETSKP			;AND RETURN SUCCESSFULLY
;ROUTINE CALLED FROM JSYS CODE TO SCAN OFN'S AND MARK EACH ONE
;ON THE STRUCTURE IN QUESTION DISMOUNTED.
;ACCEPTS:	A/ STRUCTURE NUMBER
;RETURNS:	+1 ALWAYS. WITH ALL OFN'S MARKED AND ALL
;		   LOCAL STORAGE RELEASED

MRKOFN::ASUBR<STRMRK>		;SAVE STRUCTURE NUMBER
	STKVAR <LOOPER>		;SAVE LOOP COUNTER
	MOVSI A,-NOFN		;SEARCH ALL OFN'S
MRKOF3:	MOVEM A,LOOPER		;REMEMBER CURRENT LOOPER
MRKOF4:	NOSKED			;GAIN CONTROL OF THE SYSTEM
	SKIPN SPTH(A)		;THIS OFN IN USE?
	JRST [	OKSKED		;NO. SKIP IT
		JRST MRKOF1]	;""
	MOVX B,SPTLKB		;SEE IF LOCKED
	TDNE B,SPTH(A)		;IS IT?
	JRST [	HRLZS A		;GET OFN TO LH
		CALL WTOFNL	;WAIT FOR OFN TO UNLOCK
		MOVE A,LOOPER	;GET BACK INDEX
		JRST MRKOF4]	;GO RECHECK IT
	IORM B,SPTH(A)		;NO. LOCK IT
IFN SPTDSW,<			;ONLY IF DEBUGING SPTLKB PROBLEMS
	CALL SPTRAC		;RECORD WHO LOCKED THIS
 >				;END OF IFN SPTDSW
	NOINT			;PREVENT INTERRUPTION
	OKSKED			;AND ALLOW SCHEDULING AGAIN
	LOAD B,STRX,(A)		;GET ITS STRUCTURE NUMBER
	CAME B,STRMRK		;THE SAME AS THE ONE DSIMOUNTING?
	JRST MRKOF2		;NO. SKIP IT
	MOVX B,OFNDMO		;SEE IF DISMOUNTED
	TDNE B,SPTH(A)		;IS IT?
	JRST MRKOF2		;YES. SKIP IT
	CALL INVOFN		;MARK IT AND ITS SHARE POINTERS
	MOVE A,LOOPER		;RESTORE OFN
MRKOF2:	CALL ULKOFN		;FREE THIS OFN
	MOVE A,LOOPER		;GET BACK LOOP CONTROL
MRKOF1:	AOBJN A,MRKOF3		;DO ALL OF THEM
	RET			;DONE

	RESCD			;RETURN TO RESIDENT CODE
;ROUTINE TO SEARCH FOR THE QUOTA ALLOCATION ENTRY FOR
;A GIVEN DIRECTORY.
;CALL:
; T1/ DIRECTORY NUMBER
; T2/ STRUCTURE NUMBER
;	CALL GETCAL
; RETURN +1, DIRECTORY NOT OPENED
; RETURN +2, FOUND, T1/ CURRENT QUOTA, T2/ INDEX INTO ALCWD

GETCAL::SAVEQ			;SAVE Q1-FX
	HRRZ Q2,T1
	HRRZ FX,T2
	HRLZ T3,MAXSPL		;GET CURRENT SPT LENGTH
	JUMPE T3,R		;RETURN IF EMPTY
	MOVNS T3		;MAKE AOBJN PNTR
	HRRI T3,1
GETC1:	LOAD T2,ALOCX,(T3)	;GET INDEX
	JUMPE T2,GETCN		;SKIP NULL ENTRIES
	LOAD T1,ADIRN,(T2)	;GET DIR #
	CAME T1,Q2		;WANT THIS ONE?
	JRST GETCN		;NO - TRY NEXT
	LOAD T1,STRX,(T3)	;GET STR #
	CAME T1,FX		;CORRECT STR?
	JRST GETCN		;NO - TRY SOME MORE
	LOAD T1,PGLFT,(T2)	;YES - GET QUOTA LEFT
	RETSKP			;GIVE GOOD RETURN

GETCN:	AOBJN T3,GETC1		;LOOP TILL DONE
	RET			;FAILED (NOT FOUND)
;ADJALC - ADJUST ALLOCATION TABLE ENTRY FOR THIS DIRECTORY

;ACCEPTS:
;	T1/ DIRECTORY NUMBER
;	T2/ STRUCTURE NUMBER
;	T3/ AMOUNT TO ADD TO THE ALLOCATION FOR THIS DIRECTORY

;	CALL ADJALC

;RETURNS +1: ALWAYS

ADJALC::STKVAR <ADJADL>
	MOVEM T3,ADJADL		;SAVE CHANGE
	NOSKED			;NOSKED WHILE FINDING AND CHANGING SLOT
	CALL GETCAL		;GET CURRENT AVAILABLE PAGE COUNT
	 JRST ADJAL1		;NO OPEN FILES IN THIS DIRECTORY
	ADD T1,ADJADL		;ADD THE INCREMENT
	STOR T1,PGLFT,(T2)	;STORE UPDATED VALUE IN ALLOCATION ENTRY
ADJAL1:	OKSKED			;ALLOW SCHEDULING AGAIN

	RET
;ASSIGN PAGE TABLE USING LOCAL VALUES. CALLED FROM DSKALC TO
;ASSIGN AN SPT FOR THE NASCENT BITTABLE.

ASSPTL::SAVEQ			;SAVE REGISTERS
	MOVE FX,FORKX		;USE LOCAL FORK INDEX

;ASSIGN PSB FOR NEW PROCESS
; FX/ FORK INDEX

ASSPT::	SKIPG 1,FRESPT		;ANY FREE CELLS?
	BUG(SPTFL1)
	HRRZ 1,0(1)
	EXCH 1,FRESPT
	SUBI 1,SPT
	AOS SPTC		;ASSIGN SPT SLOT
	MOVX 2,UAAB		;NO ACCESS
	MOVEM 2,SPT(1)		;SHARE COUNT OF 1, NO ADDRESS
	CALL UPSHR		;SET SHARE COUNT TO ONE
	HRRZM FX,SPTH(1)	;SPTH HOLD OWNER FORK INDEX
	RET

;DEASSIGN SPT AND RELEASE STORAGE

DESPT::	CALL DWNSHR		;DECREMENT SHARE COUNT
	PUSH P,1		;SAVE SPT INDEX
	CALL GETSHR		;GET CURRENT SHARE COUNT
	SKIPE 1			;IS IT NOW UNSHARED?
	BUG(SHRNO0)
	POP P,1			;YES. RESTORE SPT
	LOAD 2,STGADR,SPT(1)	;GET STORAGE ADDRESS
	TXNN 2,NCORTM		;PAGE IN CORE?
	JRST [	MOVSI 3,(-PLKV)	;YES
		TDNE 3,CST1(2)	;LOCKED?
		JRST DESPX1
		JRST .+1]	;NO, OK
	PUSH P,1
	MOVE 1,2		;MOVE STORAGE ADDRESS
	CALL REMFP1		;RELEASE CORE AND/OR DRUM
	SKIPE 1			;BE SURE NOTHING LEFT TO DELETE
	BUG(PTDEL)
	POP P,1
	MOVEI 1,SPT(1)		;CONSTRUCT PTR
	EXCH 1,FRESPT		;PUT ON FREE LIST
	EXCH 1,@FRESPT
	SOS SPTC
	RET

DESPX1:	BUG(PAGLCK)

;ASSIGN FORK STORAGE BLOCK (JSB, PSB, UPT)

ASFSB::CALLRET ASSPT		;ASSIGN SPT SLOT ONLY
   REPEAT 0,<			;FOLLOWING NOT PRESENTLY USED
	SAVEAC <Q1>
	CALL ASSPT		;ASSIGN SPT SLOT
	MOVEM T1,Q1		;SAVE IT
	CALL DRMASN		;ASSIGN SWAP STORAGE
	 BUG(DRMFL1)
	STOR T1,STGADR,SPT(Q1)	;PUT ADR IN SPT
	MOVEM T1,T2
	CALL GDSTX		;GET DST INDEX
	MOVX T1,UAAB		;SET DST
	MOVEM T1,(T2)
	MOVE T1,Q1		;RETURN SPT INDEX
	RET

	ENDAV.			;END ACVAR
   >				;END REPEAT 0

;SPECIAL ROUTINE USED BY SCHEDULER TO DELETE SECOND PSB PAGE.
;CALLED FROM HLTFK1.

   REPEAT 0,<
DESSTK::SKIPN T1,PSBM0+PSB1 ;SEE IF PAGE EXISTS
	RET			;NO. NOTHING TO DO THEN
	LOAD T1,STGADR,T1	;GET STORAGE ADDRESS ONLY
	SETZM PSBM0+PSB1	;ASSUME IT IS NOW CLEARED
	CALLRET REMFP1		;AND GET RID OF IT
   >				;END OF REPEAT 0
;READ MAP GIVEN VIRTUAL ADDRESS

MRMAP::	CALL FPTA		;GET PAGE TABLE ADDRESS
;**********
;TEMP FIX TO FPTA RETURNING A ZERO....
;************
	JUMPE T1,RDMQ5

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

MRPT::	SAVEQ
	HLRZ 2,1		;GET PTN
	CALL CHKDMO		;SEE IF A DISMOUNTED OFN
	 CALLRET DMOINT		;IT IS. GIVE ERROR AND RETURN
	CALL SETCPT
	HRRZ Q2,1
	MOVE 2,CPTPGA(Q2)	;GET MAP WORD
	JUMPE 2,RDMQ5		;EMPTY
	LOAD Q1,PTRCOD,2	;GET PTR TYPE
	CAIN Q1,IMMCOD		;PRIVATE?
	JRST MRM1		;YES
	CAIE Q1,SHRCOD		;SHARED OR INDIRECT?
	JRST [	LOAD 1,IPPGN,2	;INDIRECT, CONSTRUCT IDENT
		LOAD 2,SPTX,2
		HRL 1,2
		JRST MRM1]
	LOAD 2,SPTX,2		;GET SPT INDEX
	MOVE 1,SPTH(2)		;NO, GET OFN.PN
MRM1:	HLRZ 2,1
	CAIGE 2,NOFN		;OWNED BY OFN?
	AOS 0(P)		;YES, SKIP RETURN
	PUSH P,T1		;SAVE IDENT
	MOVE T1,CPTPGA(Q2)	;GET POINTER
	CALL GPAC		;TRANSLATE ACCESS BITS
	MOVE T2,T1		;RETURN ACCESS IN T2
	POP P,T1
	CALLRET RELCPT

RDMQ5:	SETZB 1,2		;RETURN 0
	CALLRET RELCPT
;FIND NON-0 PAGE IF ANY, AND RETURN ITS ACCESS DATA
; 1/ IDENT
; 2/ COUNT OF NUMBER OF PAGES TO SCAN
; RETURNS +1 WITH ACCESS DATA IN 1, UPDATED COUNT IN 2.  IF NO
;  NON-0 PAGE FOUND, 2 WILL CONTAIN 0.

MSCANP::PUSH P,B		;SAVE ARG
	HLRZ B,A		;GET SPTN
	CALL CHKDMO		;SEE IF DISMOUNTED
	 JRST [	POP P,B		;YES. IT IS
		CALLRET DMOINT]	;AND GIVE ERROR
	POP P,B			;GET BACK ARG
	HLRZ 3,1		;GET OFN
	CAIG 3,0		;LEGAL?
	BUG(ILOFN1)
	CALL SETXB1		;MAP INDEX BLOCK
	HRRZ T4,T1
MSCAN1:	SKIPE 3,CXBPGA(4)	;EMPTY?
	JRST MSCAN2		;NO
	ADDI T4,1		;YES, BUMP IDENT TO NEXT PAGE
	SOJG 2,MSCAN1		;COUNTDOWN MAX PAGES
	HRR T1,T4		;FIX IDENT
	CALLRET RELCXB		;COUNT DONE, ALL PAGES EMPTY

MSCAN2:	HRR T1,T4		;FIX IDENT
	PUSH P,2		;SAVE UPDATED COUNT
	CALL MRPACF		;GET ACCESS DATA
	POP P,2
	RET
;READ PAGE ACCESSIBILITY
; 1/ IDENT
; RETURNS +1 WITH ACCESS INFORMATION IN RPACS FORMAT IN 1

;MRPACS - GENERAL VERSION
;MRPACF - "FAST" VERSION, DOESN'T TRACE INDIRECT PTRS AND DOESN'T GO NOSKED

MRPACF:	SAVEAC <Q1,Q2,P1>
	SETZ Q2,		;INIT ACCESS
	SETO P1,		;FLAG NO INDIRECT TRACING
	JRST MRP1

MRPACS::SAVEAC <Q1,Q2,P1>
	SETZB Q2,P1		;NO PTR AND NO INDIRECT COUNT
	NOSKED			;PREVENT CHANGES WHILE TRACING IND PTRS
MRP1:	MOVX T4,PTWR+PTCPY 	;ACCESS BITS TO COMPUTE
MRP4:	HLRZ 2,1		;GET PT IDENTIFIER
	CALL CHKDMO		;SEE IF A DISMOUNTED OFN
	 JRST [	CALL DMOINT	;DELIVER ERROR
		JRST MRPCX]	;AND LEAVE
	HLRZ T3,T1		;GET PTN
	CAMN T3,BTBBAS		;IS THIS THE BIT TABLE IDENT?
	JRST [	MOVX T2,UAAB	;YES. SEE IF IT IS MAPPED
		TDNN T2,SPT(T3)	;IS IT?
		JRST .+1	;YES. PROCEED
		SETZ T1,	;NO. RETURN NONEX PAGE
		JRST MRPCX]	;AND DONE
	CAIG T3,0
	BUG(ILPTN1)
	CALL SETXB1		;MAP PT
	HRRZS T1
	MOVE T3,CXBPGA(T1)	;GET PTR
	SKIPN Q2		;FIRST PTR?
	MOVEM T3,Q2		;YES, SAVE IT
	JUMPE T3,MRP2		;JUMP IF EMPTY
	TXNN T4,PTWR		;ACCUMULATING COMPOSITE STILL HAVE WRITE SET?
	TXOA T3,PTCPY		;NO, IGNORE ALL FUTURE COPY-ON-WRITE PTRS
	TXC T3,PTCPY		;'AND' 0S FOR THIS BIT
	ANDM T3,T4		;COMPUTE COMPOSIT ACCESS
	JUMPL P1,MRP2		;DONE IF NOT TRACING IND PTRS
	LOAD Q1,PTRCOD,T3	;GET PTR TYPE
	CAIE Q1,INDCOD		;INDIRECT?
	JRST MRP2		;NO, DONE
	CAIL P1,MAXIND		;ALREADY SAW TOO MANY OF THESE?
	JRST [	SETZ T1,	;YES. SAY PAGE DOES NOT EXIST
		JRST MRPCX]	;AND RETURN NON-EX PAGE
	ADDI P1,1		;SAW ANOTHER INDIRECT POINTER
	LOAD T1,IPPGN,T3	;YES, CONSTRUCT IDENT
	LOAD T3,SPTX,T3
	HRL T1,T3
	JRST MRP4		;CONTINUE TRACE

;TRACED ALL PTRS,
; Q2/ FIRST PTR
; T4/ COMPOSIT ACCESS
; T3/ LAST PTR

MRP2:	JUMPE Q2,[SETZ T1,	;FIRST PTR NULL, RETURN 0
		JRST MRPCX]
	MOVE T1,T4
	TXC T1,PTCPY+PTRCOD	;NOT (AND (NOT ..))
	CALL GPAC		;TRANSLATE ACCESS TO USER BITS
	MOVEM T1,T4
	LOAD Q1,PTRCOD,Q2	;GET FIRST PTR TYPE
	CAIN Q1,INDCOD		;INDIRECT?
	TXO T4,PA%IND		;YES
	CAIN Q1,IMMCOD		;PRIVATE?
	TXO T4,PA%PRV		;YES
	MOVE T1,Q2
	CALL GPAC		;TRANSLATE ACCESS OF FIRST PTR
	HLRZ T1,T1		;RETURN IT IN RH
	HLL T1,T4		;RETURN COMPOSIT IN LH
	JUMPE T3,MRPCY		;CLEAR 'EXISTS' IF LAST PTR EMPTY
	LOAD Q1,PTRCOD,T3	;GET TYPE OF LAST PTR
	CAIE Q1,SHRCOD		;SHARED?
	JRST MRPCX		;NO
	LOAD T3,SPTX,T3		;YES, CHECK ADDRESS
	LOAD T3,STGADR,SPT(T3)
	TXNN T3,DSKAB+DRMAB	;UNASSIGNED?
	TXNN T3,UAAB
	JRST MRPCX		;NO, ELSE CLEAR EXISTS
MRPCY:	TXZ T1,PA%PEX		;CLEAR 'EXISTS'
MRPCX:	SKIPL P1		;NOSKED ABOVE?
	OKSKED			;YES, UNDO
	CALLRET RELCXB		;RELEASE TEMP MAPPING AND RETURN

;TRANSLATE POINTER ACCESS BITS TO USER ACCESS BITS
; T1/ POINTER
;	CALL GPAC
; RETURN +1 ALWAYS, T1/ USER ACCESS BITS

GPAC::	JUMPE T1,R		;NULL PTR YEILDS 0
	MOVE T2,T1
	MOVX T1,PA%RD+PA%EX+PA%PEX ;SAY POINTER EXISTS
	TXNE T2,PTWR		;WRITE?
	TXO T1,PA%WT		;YES
	TXNE T2,PTCPY		;COPY?
	TXO T1,PA%CPY		;YES
	RET

;TRANSLATE USER ACCESS BITS TO POINTER ACCESS BITS
; T2/ USER BITS
; T3/ POINTER TO BE SET
;	CALL SPAC
; RETURN +1, T3/ MODIFIED POINTER

SPAC:	TXZ T3,PTWR+PTCPY	;SET THESE BITS...
	TXNE T2,PA%WT		;WRITE?
	TXO T3,PTWR		;YES
	TXNE T2,PA%CPY		;COPY?
	TXO T3,PTCPY		;YES
	RET
;SET PAGE ACCESSIBILITY
; T1/ IDENT
; T2/ ACCESS

MSPACS::PUSH P,2
	CALL SETCPT		;MAP PT
	HRRZ T4,T1
	POP P,2
	SKIPN CPTPGA(T4)		;PAGE EXISTS?
	JRST MRSPX		;NO, IGNORE CALL
	HLRZ 3,1
	CAIGE 3,NOFN		;FILE?
	JRST MRSPX		;YES, DO NOTHING
	NOSKED
	MOVE 3,CPTPGA(T4)	;GET PTR
	CALL SPAC		;SET POINTER BITS PER USER REQUEST
	MOVEM 3,CPTPGA(T4)	;STORE MODIFIED PTR
	CALL MONCLA		;MAKE PAGER NOTICE
	OKSKED
MRSPX:	CALLRET RELCPT

;MRPAC - JSYS FOR MONITOR DDT

.MRPAC::MCENT
	MOVE 2,0(P)		;RETURN PC
	TLNE 2,(UMODF)		;FROM MONITOR?
	ITERR(ILINS1)		;NO, ILLEGAL FROM USER
	TXZ T1,1B0		;CANNOT ASK ABOUT A USER ADDRESS
	HLRZ T2,T1		;GET SECTION NUMBER AND ILLEGAL BITS
	CAILE T2,MAXSEC		;LEGAL SECTION?
	JRST MRPC1		;NO. CAN'T ACCESS IT THEN
	SKIPE T2		;YES. MONITOR PC SECTION?
	CAIN T2,MSEC1		;OR THIS ONE?
	TLZA T1,-1		;YES. PROCESS MONITOR PC SECTION
	JRST MRPC4		;NO. CHECK OUT ADDRESS THEN
	CAIL T1,PPVAR		;IN PPVAR AREA?
	CAILE T1,PPVARZ!777	;IS IT?
	CAIA			;NO, CHECK OTHER PLACES
	JRST MRPC1		;YES, SAY NO ACCESS
	CAIL T1,PSSPSA		;IN PSB SPECIAL PAGES?
	CAIL T1,PSSPEA		;SETPT ETC.
	CAIA			;NO, KEEP CHECKING
	JRST	MRPC1		;YES, SAY NO ACCESS
MRPC4:	CALL FPTA
	JUMPE T1,MRPC1		;IF NO SECTION, RETURN NO-ACCESS
MRPC3:	CALL MRPACS
MRPC2:	UMOVEM 1,2		;RETURN RESULT IN 2 LIKE RPACS
	JRST MRETN

MRPC1:	MOVSI 1,(PA%PRV)		;NO-ACCESS
	JRST MRPC2
;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
;	1-17 - ACCESS

SETMPG::TRVAR <SID,ADR,ARG3,ARG4,DEST>
	DMOVEM T1,SID		;SAVE ARGS
	DMOVEM T3,ARG3
	CALL VERPT		;GO VERIFY NO DISMOUNTED OFN
	 RET			;USER REQUESTED BAD OFN. IGNORE IT
	HLLZ 3,2		;GET ACCESS
	MOVE 1,2
	CALL FPTA		;CONVERT ADDRESS TO PTN.PN
	JUMPE T1,SETMPX		;IF NO SECTION, ERROR
	MOVEM T1,DEST		;SAVE DEST I.D.
	CALL SETCPT		;SETUP PAGE TABLE
	CALL LCKOFI		;LOCK DEST IF OFN
	MOVE 2,SID		;GET SOURCE IDENT
	HLLZ T3,ADR		;GET ACCESS BITS
	CALL RELMP5		;RELEASE OLD CONTENTS
	SKIPGE ADR		;CHANGING EXEC OR USER MAP?
	IFSKP.
	  CALL MONCLA		;EXEC, CLEAR EXEC SCRATCHPAD
	ELSE.
	  CALL PGRCLD		;USER, CLEAR ALL PAGE TABLE
	ENDIF.
	SKIPE T2,SID		;DELETING ONLY?
	IFSKP.
	  MOVE T1,ADR		;YES, CLEAR VA FROM WS CACHE
	  ANDX T1,TWUSR+777777 	;CLEAR ACCESS BITS
	  CALL DELWSC
	  MOVE T1,DEST		;RESTORE DEST ID
	  CALLRET MSETM2
	ENDIF.
	MOVE T1,DEST
	HLLZ T3,ADR		;GET ACCESS BITS
	CALL SETPT0		;SET NEW CONTENTS
	 CALL MSEINT		;FAILED, INTERRUPT
MSETM2:	CALL RELCXB		;RELEASE SOURCE PT
	CALL RELCPT		;RELEASE DESTINATION PT
	CALL ULKOFI		;UNLOCK DEST IF OFN
	DMOVE T1,SID		;RESTORE TEMPS
	DMOVE T3,ARG3
	RET

;FAILURE TO SET PAGE, GENERATE INTERRUPT

MSEINT:	MOVEI 2,.ICILI		;ERROR CHANNEL
	CAIN 1,IOX11		;QUOTA EXCEEDED?
	MOVEI 2,.ICQTA		;YES - USE THIS CHL
	MOVE 1,2		;COPY CHL TO T1
	CALL PSIRQ0		;REQUEST PSI
	CHKINT			;GET IT SEEN
	RET
;MULTIPLE SET PAGE IN MAP - SAME AS ABOVE EXCEPT
; 3/ NUMBER OF SUCCESSIVE PAGES TO BE SET

MSETMP::TRVAR <SID,ADR,PCT,ARG4,DEST,PCT2>
	DMOVEM T1,SID		;SAVE ARGS
	DMOVEM T3,PCT
	MOVEM T3,PCT2		;SAVE SECOND COPY OF COUNT
	CALL VERPT		;GO VERIFY NOT USING DISMOUNTED OFN
	 RET			;CAN'T MAP DISMOUNTED OFN
	HLLZ 3,2		;ACCESS BITS
	MOVE 1,2
	CALL FPTA		;CONVERT DESTINATION TO PTN.PN
	JUMPE T1,SETMPX		;IF NO SECTION, ERROR
	MOVEM T1,DEST		;SAVE DEST I.D.
	CALL SETCPT		;MAP DESTINATION PT
	CALL LCKOFI		;LOCK DEST IF OFN
	MOVE 2,SID		;GET SOURCE PTN.PN
MSETM1:	HLLZ T3,ADR		;GET ACCESS BITS
	CALL RELMP5		;RELEASE EXISTING CONTENTS OF DEST
	MOVE T2,SID
	MOVE T1,DEST		;RESTORE ARGS
	HLLZ T3,ADR		;GET ACCESS BITS
	CALL SETPT0		;SET NEW CONTENTS
	 CALL MSEINT		;FAILED, INTERRUPT
	AOS T1,DEST		;NEXT DEST ADDRESS
	SKIPE 2			;SOURCE 0?
	AOS T2,SID		;NEXT SOURCE IF APPROPRIATE
	SOSLE PCT		;COUNT PAGES DONE
	JRST MSETM1
	SKIPL ADR		;CHANGING EXEC OR USER MAP?
	IFSKP.
	  CALL PGRCLD		;USER, CLEAR ALL
	ELSE.
	  CALL MONCLA		;EXEC, CLEAR EXEC ONLY
	ENDIF.
	SKIPE ADR		;DELETING ONLY?
	CALLRET MSETM2		;NO
MSETM3:	MOVE T1,ADR		;YES, FLUSH PAGES FROM WS CACHE
	ANDX T1,TWUSR+777777	;CLEAR ACCESS BITS FROM ADR
	CALL DELWSC
	MOVEI T1,PGSIZ
	ADDM T1,ADR		;STEP ADDRESS BY ONE PAGE
	SOSLE PCT2		;COUNT PAGES
	JRST MSETM3
	MOVE T1,DEST		;RESTORE DEST ID
	CALLRET MSETM2
;LOCAL ROUTINE USED BY SETMPG AND MSETMP TO VERIFY THAT REQUESTOR
;IS NOT SELECTING A DISMOUNTED OFN.

VERPT:	JUMPE 1,RSKP		;IF DELETING, ALLOW IT
	SAVEAC <T2>		;DON'T CLOBBER ANY ARGS
	HLRZ 2,1		;GET OFN
	SKIPN 2			;WAS THIS AN OFN.PN?
	MOVEI 2,0(1)		;NO. IS 0,,OFN. SO GET THE OFN
	CALL CHKDMO		;SEE IF DISMOUNTED
	 CALLRET DMOINT		;YES. PROVIDE AN INTERRUPT
	RETSKP			;NO. ALLOW MAP

;LOCAL ROUTINE USED BY SETPT AND MSETPT TO VERIFY THAT REQUESTOR
;IS NOT SELECTING A DISMOUNTED OFN.

PTVER:	JUMPE 1,RSKP		;IF DELETING, ALLOW IT
	SAVEAC <T2>		;DON'T CLOBBER ANY ARGS
	STKVAR <AR2>		;SAVE DESTINATION HERE
	MOVEM 2,AR2		;SAVE DESTINATION
	HLRZ 2,1		;GET OFN OF SOURCE
	SKIPN 2			;WAS THIS OFN.PN?
	MOVEI 2,0(1)		;NO. IS 0,,OFN. SO GET THE OFN
	CALL CHKDMO		;SEE IF DISMOUNTED
	 CALLRET DMOINT		;YES. PROVIDE INTERRUPT
	HLRZ 2,AR2		;GET OFN OF DESTINATION
	CALL CHKDMO		;SEE IF IT IS DISMOUNTED
	 CALLRET DMOINT		;YES. GIVE INTERRUPT
	RETSKP			;NO. ALLOW MAP

;ROUTINE TO DELIVER A PSEUDO INTERRUPT TO PROCESS. THIS ROUTINE
;IS CALLED WHENEVER A PROCESS ATTEMPTS TO ILLEGALLY MAP A PAGE
;FROM A DISMOUNTED OFN.

DMOINT:	SAVET
	MOVEI A,PMAPX7		;PROVIDE CHARACTERISTIC CODE
	MOVEM A,LSTERR		; FOR PROCESS TO SEE
	MOVEI A,.ICIRD		;GENERATE ILLEGAL MEM READ
	CALL PSIRQ0		; TO THIS PROCESS
	CHKINT			;MAKE SURE PROCESS SEES IT ASAP
	RET			;AND DONE

;ATTEMPT TO MAP A NON-EXISTANT SECTION

SETMPX:	BUG (SECEX1)
;MAP PHYSICAL CORE PAGE
; T1/ DESTINATION IDENT
; T2/ PHYSICAL PAGE NUMBER
;	CALL MAPPHP
; RETURN +1: FAILURE, PAGE LOCKED OR OTHERWISE INACCESSIBLE
; RETURN +2: SUCCESS, PRIVATE POINTER SETUP

MAPPHP::ASUBR <ID,PGNO>
	CAMLE T2,NHIPG		;WITHIN KNOWN RANGE?
	BUG(XSCORE)
	CALL SETCPT		;MAP DESTINATION PT
	SETZM T3		;NO SPECIAL ACCESS BITS
	CALL RELMP5		;CLEAR PREVIOUS CONTENTS
	CALL MONCLA		;CLEAR PAGE MEMORY
	NOSKED
	MOVE T1,PGNO
	CAMGE T1,MONCOR		;RES MONITOR PAGE?
	JRST [	CALL RESPCK	;CHECK RESMON PAGE
		 JRST .+1	;NOT PART OF RESMON
		MOVE T2,ID	;YES, DON'T CHANGE CST
		JRST MAPPH1]
	MOVX T2,-PLKV
	TDNE T2,CST1(T1)	;PAGE LOCKED?
	JRST MAPPHX		;YES, CAN'T GRAB IT
	CALL RPCST		;RELEASE PAGE FROM PRESENT USE
	CALL AGECHK		;ASSIGN PAGE  HERE
	MOVX T2,UAAB		;SET UNASSIGNED BACKUP ADDRESS
	MOVEM T2,CST1(T1)
	MOVE T2,ID
	MOVEM T2,CST2(T1)	;SET OWNER ID
MAPPH1:	IOR T1,IMMPTR		;CONSTRUCT PRIVATE PTR
	HRRZS T2		;PREVENT PAGE FAULT
	MOVEM T1,CPTPGA(T2)	;PUT IN DEST MAP
	HLRZ T1,ID		;GET PT I.D.
	LOAD T1,STGADR,SPT(T1)	;GET MEMORY PAGE NUMBER
	MOVX T2,PLKV		;ONE UNIT OF LOCK COUNT
	ADDM T2,CST1(T1)	;ONE MORE PAGE IN MEMORY
	CALL UPSWP		;UPDATE PARAMETERS
	OKSKED
	CALL RELCPT		;RELEASE DEST MAP
	MOVE T2,PGNO		;RESTORE ARG
	RETSKP

MAPPHX:	OKSKED
	CALLRET RELCPT
;MAP PHYSICAL PAGE INTO MONITOR ADDRESS
; T1/ PHYSICAL CORE PAGE NUMBER
; T2/ MONITOR VIRTUAL ADDRESS
;	CALL MAPPHA
; SAME AS MAPPHP EXCEPT TAKES MONITOR VIRTUAL ADDRESS

MAPPHA::EXCH T1,T2
	CALL FPTA		;TRANSLATE ADDRESS TO IDENT
	JUMPE T1,SETMPX		;SECTION MUST EXIST
	CALLRET MAPPHP		;DO THE WORK

;ROUTINE TO SEE IF A PAGE LESS THAN MONCOR IS STILL PART
;OF MONITOR MAP.
;ACCEPTS:	T1/ PAGE NUMBER
;RETURNS:	+1 NOT PART OF MONITOR MAP
;		+2 PART OF MONITOR MAP

RESPCK:	HLRZ T2,CST2(T1)	;GET PRESENT OWNER
	CAME T2,MMSPTN		;OWNED BY MONITOR MAP?
	RET			;NO
	RETSKP			;YES
;ROUTINES TO ADJUST SWPMON (THESE ROUTINES MUST BE INTERLOCKED)

RS (SWPMLF,1)			;COUNT OF LOCKERS OF SWP MON
RS (SWPMWF,1)			;COUNT OF WRITE ENABLERS OF SWP MON

;LOCK/UNLOCK SWPMON IN CORE

SWPMLK::AOSE SWPMLF		;FIRST LOCKER?
	RET			;NO, DONT LOCK IT AGAIN
	PUSH P,P2		;SAVE AC
	MOVEI P2,MLKPG		;SUBR TO MAP
SWPML1:	MOVE T1,SWPMBP		;GET BOUND PAIR
	CALL BSMGP		;MAP PAGES
	POP P,P2		;RESTORE AC
	RET

SWPMUL::SKIPL SWPMLF		;ALREADY UNLOCKED?
	SOSL SWPMLF		;NO, LAST ONE TO UNLOCK SWP MON?
	RET			;NO, LEAVE IT LOCKED
	PUSH P,P2		;SAVE AC
	MOVEI P2,MULKPG		;UNLOCK PAGES
	JRST SWPML1		;JOIN ABOVE

;WRITE ENABLE/PROTECT SWPMON

SWPMWE::AOSE SWPMWF		;FIRST TIME THRU
	RET			;NO, DONT NEED TO GO ON
	ACVAR <W1>		;GET A WORK REGISTER
	MOVEI W1,MMAPWE		;W1/ADDRESS FOR WRITE-ENABLING
	JRST SWPM0		;GO WRITE ENABLE

SWPMWP::SKIPL SWPMWF		;ALREADY WRITE PROTECTED?
	SOSL SWPMWF		;NO, LAST TIME THRU?
	RET			;NO, LEAVE IT WRITE ENABLED
	SAVEAC <W1>		;GET A WORK REGISTER *MATCHES ACVAR ABOVE*
	MOVEI W1,MMAPWP		;W1/ADDRESS FOR WRITE-PROTECTING

;AC W1 HAS ADDRESS FOR FUNCTION DESIRED.  SET UP ARGUMENTS FOR MMAPWP OR MMAPWE

SWPM0:	MOVEI 1,NRCOD		;1/STARTING ADDRESS OF SWAPPABLE MONITOR
	MOVE 2,SWCEND		;2/LENGTH OF SWAPPABLE MONITOR
	SUBI 2,NRCODP-1
	CALL 0(W1)		;CALL MMAPWE OR MMAPWP TO DO FUNCTION REQUESTED
	MOVEI T1,RSCOD		;T1/ ADDRESS OF RESIDENT CODE
	MOVEI T2,RSCODL-RSCODP+1 ;T2/ NUMBER OF PAGES
	CALL 0(W1)		;CALL ROUTINE TO DO PROPER FUNCTION
	RET

	ENDAV.			;END ACVAR
;LOCK/UNLOCK EDDT, SYMTAB, AND INITIALIZATION CODE

ULKINI::SETZM DDTPRS		;INDICATE NO EDDT
	MOVEI T1,MULKPG		;ROUTINE TO USE
	JRST LKINI0		;JOIN COMMON CODE
LCKINI::MOVEI T1,MLKPG		; ROUTINE TO LOCK
	SETOM DDTPRS		;INDICATE EDDT PRESENT
LKINI0:	PUSH P,P2		;SAVE AC
	MOVE P2,T1		;COPY ARG
	MOVE T1,INCOBP		;GET INIT CODE PAIR
	CALL BSMGP		;MAP PAGES ONTO ROUTINE
	SKIPN HSYBLK		;ARE SYMBOLS IN NORMAL ADDRESS SPACE?
	SKIPA T2,MMSPTN		;YES, SET UP TO ACT ON MMAP
	MOVE T2,SYMBAS		;NO, GET SPT INDEX OF SYMBOL TABLE MAP
	MOVE T1,SYTBBP		;GET SYMBOL PAIR NOW
	CALL BSMGG		;MAP PAGES ONTO ROUTINE
	POP P,P2		;RESTORE AC
	RET			;ALL DONE
;MMAPWE AND MMAPWP- ROUTINES TO WRITE ENABLE OR WRITE PROTECT THE MONITOR'S MAP

;ACCEPTS:
;	T1/VIRTUAL ADDRESS OF FIRST PAGE AFFECTED
;	T2/COUNT OF NUMBER OF PAGES TO AFFECT

;CALL MMAPWE OR CALL MMAPWP

;RETURNS +1 ALWAYS

;THIS ROUTINE MODIFIES THE ACCESS FOR CONSECUTIVE PAGES IN THE MONITOR'S MAP.
;IT MODIFIES MMAP FOR PAGES BELOW THE JSB, JOBMAP FOR PAGES IN THE JSB, AND
;PSBMAP FOR PAGES IN THE PER PROCESS REGION.  IT ASSUMES THAT THE RANGE
;SPECIFIED DOES NOT EXTEND BEYOND THE STARTING REGION.  THAT IS, ALL PAGES
;ARE BETWEEN 0 AND 577, OR 600 AND 677, OR 700 AND 777.

MMAPWE::SKIPA T3,[IORM T4,0(T1)] ;T3/INSTRUCTION TO WRITE-ENABLE
MMAPWP::MOVE T3,[ANDCAM T4,0(T1)] ;T3/INSTRUCTION TO WRITE-PROTECT
	LOAD T1,VPGNO,T1	;GET PAGE NUMBER
	CAIL T1,PSVARP		;BELOW THE PSB?
	CAILE T1,PSVARL		;OR ABOVE IT?
	JRST MM1		;YES, CHECK NEXT AREA
	ADDI T1,PSBMAP-PSVAR	;IN THE PSB.  POINT TO PSBMAP SLOT FOR 1ST PAGE
	JRST MM3		;GO LOOP THROUGH THE PAGES

MM1:	CAIL T1,JSVARP		;BELOW THE JSB?
	CAILE T1,JSVARL		;OR ABOVE IT?
	JRST MM2		;YES, MUST BE IN MMAP
	ADDI T1,JOBMAP-JSVARP	;IN THE JSB. POINT TO JOBMAP SLOT FOR 1ST PAGE
	JRST MM3		;GO LOOP THROUGH THE PAGES

MM2:	ADDI T1,MMAP		;IN MMAP. POINT TO ENTRY FOR THE FIRST PAGE

;T1 HAS THE ADDRESS OF THE FIRST WORD OF THE MAP.  LOOP THROUGH ENTRIES
;ACCORDING TO COUNT IN T2

MM3:	MOVX T4,PTWR		;T4/WRITE ACCESS
MM4:	SKIPE 0(T1)		;IGNORE NON-EXISTANT PAGE
	XCT T3			;WRITE ENABLE OR PROTECT ACCORDING TO T3
	AOS T1			;POINT TO NEXT WORD
	SOJG T2,MM4		;AT THE END?
	CALLRET MONCLA		;YES. MAKE THE PAGER SEE THE CHANGES
;SET PAGE TABLE (FOR PROCESS OR FILE)
; AC1/ SOURCE IDENTIFIER
; AC2/ DESTINATION IDENTIFIER
; T3/ 0-17 ACCESS INFO

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

SETPT::	CALL PTVER		;VERIFY ARGS
	 RET			;CAN'T USED A DISMOUNTED OFN
	EXCH 1,2
	CALL RELMPG		;RELEASE EXISTING PAGE
	CALL SETPT0
	 CALL MSEINT		;FAILED, INTERRUPT
	CALL RELCXB		;RELEASE SOURCE PT
	CALL RELCPT		;RELEASE DESTINATION PT
	CALL ULKOFI		;UNLOCK DEST IF OFN
	EXCH 1,2
	RET

;MULTIPLE SET PAGE TABLE - SAME AS SETPT, EXCEPT
; 4/ COUNT OF NUMBER OF SUCCESSIVE PAGES TO SET
; RETURN +1: FAILURE, T1/ ERROR CODE
;	+2: SUCCESS

MSETPT::SASUBR <SID,DID,ARG3,ARG4>
	CALL PTVER		;VERIFY ARGS
	 RET			;CAN'T USE A DISMOUNTED OFN
	MOVE 1,2
	CALL SETCPT		;SETUP DESTINATION MAP
	CALL LCKOFI		;LOCK DEST IF OFN
	MOVE 2,SID		;GET SOURCE PTR
MSETP1:	MOVE T3,ARG3		;GET ACCESS BITS
	CALL RELMP5		;RELEASE OLD CONTENTS
	MOVE T2,SID
	MOVE T1,DID		;RESTORE ARGS
	MOVE T3,ARG3		;ACCESS BITS
	CALL SETPT0		;SET NEW CONTENTS
	IFNSK.
	  MOVEM T1,SID		;FAILED, SAVE ERROR CODE
	  MOVE T1,DID		;GET THE DESTINATION ID
	  CALL MSETXX		;CLEAN UP
	  RET
	ENDIF.
	AOS T1,DID			;NEXT DEST PAGE
	SKIPE 2
	AOS T2,SID		;NEXT SOURCE IF APPROPRIATE
	SOSLE ARG4		;MORE TO DO?
	JRST MSETP1		;DO IT
	CALL PGRCLD		;CLEAR PAGER SCRATCHPAD
	CALL MSETXX		;CLEAN UP
	RETSKP

;LOCAL FINISH UP - RELEASE MAPS, ETC.
; T1/ DEST ID

MSETXX:	CALL RELCXB		;RELEASE SOURCE PT
	CALL RELCPT		;RELEASE DESTINATION PT
	CALL ULKOFI		;UNLOCK DEST IF OFN
	RET
;SET NEW CONTENTS OF PT
; T1/ DEST ID
; T2/ SOURCE ID
; T3/ ACCESS BITS
;RETURN +1: FAILURE, T1/ ERROR CODE
;	+2: SUCCESS
;ASSUMES SOURCE AND DEST PT'S ALREADY MAPPED

SETPT0:	JUMPE 2,RSKP		;CHECK FOR NO NEW PAGE TO SET
	SASUBR <ARG1,ARG2,ARG3,ARG4>
	NOSKED
SETP5A:	CAME 1,2		;DON'T ALLOW MAP TO SELF
	IFSKP.
	  MOVEI T1,PMAPX8	;ILLEGAL TO MAP TO SELF
	  JRST SETPTE
	ENDIF.
	HLRZ 3,2		;GET OFN
	JUMPE 3,SETMXB		;OFN=0 MEANS SPTN IN RH
	TXNE 2,<<^-SPTM>B17+777000> ;LEGAL PTN AND PN?
	BUG(ILSRC)
	MOVE 3,ARG3		;GET FLAGS
	TXNE 3,PM%MVP		;MOVE OF PAGE REQUESTED?
	JRST [	CALL MVPT	;YES, DO IT
		 JRST SETPTE	;FAILED
		JRST SETPT2]
	HLRZ 4,1		;GET DESTINATION PTN
	CAIGE 4,NOFN		;FILE?
	JRST [	CALL MVPT	;YES, **SHOULD BE CHANGED TO SETPF1**
		 JRST SETPTE
		JRST SETPT2]
	HLRZ T3,T2		;GET SOURCE PTN
	CALL SETXB1		;MAP SOURCE XB
	OKSKED
	HRRZ T3,T2
	SKIP CXBPGA(T3)		;REFERENCE PAGE WHILE OKSKED
	NOSKED
	MOVE T3,CXBPGA(T3)	;GET WORD FROM XB
	JUMPE 3,SETP5		;JUMP IF PAGE NONEXISTENT
	HLRZ 4,2		;GET SOURCE PTN
	CAIL 4,NOFN		;PROCESS?
	JRST SETP5		;YES, GO SETUP INDIRECT POINTER
	MOVE T4,ARG3		;GET FLAGS
	TXNE T4,PM%IND		;INDIRECT PTR REQUESTED?
	JRST SETP5		;YES
	LOAD 4,PTRCOD,3		;GET PTR TYPE
	CAIN 4,INDCOD		;INDIRECT?
	BUG(ILXBP)
	CAIN 4,SHRCOD		;ALREADY SHARED?
	JRST SETMP3		;YES, GO USE SAME POINTER
	MOVE 4,SPTC		;YES
	CAMGE 4,SPC0		;ROOM IN SPT? (SPT .L. C FULL)
	JRST SETMP6		;YES, SETUP SHARE PTR
	JRST SETP5		;USE IND PTR

;ERROR RETURNS

SETPF1:	MOVEI 1,PMAPX2		;PMAP-ILLEGAL CASE
SETPTE:	MOVEM 1,LSTERR
	MOVEM 1,ARG1		;AND SAVE THE ERROR
	OKSKED
	RET
;HERE TO CONSTRUCT INDIRECT PTR TO SOURCE

SETP5:  LOAD T4,PTRCOD,T3	;GET TYPE CODE
	CAIE T4,INDCOD		;INDIRECT?
	IFSKP.
	CALL SETP6		;YES, CHECK FOR INDIRECT LOOP
	 JRST SETPTE		;THERE IS A LOOP GIVE ERROR
	ENDIF.
	HLRZ T3,T2		;GET SPTN
	MOVE T4,T1		;SAVE STORAGE ADDRESS
	MOVEI T1,0(T3)		;GET SPTN
	CALL GETSHR		;GET SHARE COUNT
	EXCH T1,T4		;RESTORE VALUES
	CAIGE T4,MAXSC0		;TOO MUCH?
	IFSKP.
	  CAIGE T3,NOFN		;IS THIS AN OFN?
	ANSKP.
	  MOVEI T1,CFRKX3	;NO. SHARE COUNT TOO LARGE
	  JRST SETPTE
	ENDIF.
	MOVE 4,INDPTR		;CONSTRUCT IND PTR
	STOR 3,SPTX,4		;PUT SPTN IN PTR
	STOR 2,IPPGN,4		;PUT PN IN PTR
	MOVE 2,4
SETMP4:	LOAD 3,SPTX,2		;GET OFN OF INDEX BLOCK
SETMP5:	JUMPE T3,SETMP2		;JUMP IF NO SPT
	CALL SETSHR		;LOCAL CALL TO INCREMENT SHARE COUNT
SETMP2:	MOVE T3,T2		;INITIAL POINTER...
	MOVE T2,ARG3		;GET USER ACCESS BITS
	CALL SPAC		;SET POINTER ACCESS BITS FROM USER
	HRRZS T1
	SKIPE CPTPGA(T1)		;BE SURE PREVIOUS CONTENTS NULL
	BUG(PTNON0)
	MOVEM T3,CPTPGA(1)	;PUT MAP WORD IN MAP
SETPT2:	OKSKED
	RETSKP

;SETP6 -
;Routine to check for potential page pointer loop.
;
;   T1/   Destination Page ID ( SPTN,,Page # )
;   T2/   Source Page ID
;
;Returns
;   +1    Failure, mapping of source page to destination
;         would build a page pointer loop
;   +2    Success, OK to map pages
;
;Preserves all ACs

SETP6:	SAVEAC <T2,T3,T4>
SETP6A:	HLRZ T3,T2		;GET SOURCE PTN
	CALL SETXB1		;MAP SOURCE XB
	OKSKED			;REFERENCE PAGE WHILE OKSKED
	HRRZ T3,T2		;...
	SKIP CXBPGA(T3)		;...
	NOSKED			;GO NOSKED AGAIN
	MOVE T3,CXBPGA(T3)	;GET WORD FROM XB
	LOAD T4,PTRCOD,T3	;GET PTR TYPE
	CAIE T4,INDCOD		;INDIRECT?
	 RETSKP			;NO, DONE WITH TRACE
	LOAD T4,SPTX,T3		;YES, GET SPTN
	CAIGE T4,NOFN		;VIA INDEX BLOCK?
	 RETSKP			;YES, OK
	CALL RELCXB		;NO, TRACE DOWN
	LOAD T2,IPPGN,T3	;CONSTRUCT ID OF PAGE POINTED
	HRLI T2,0(T4)		; TO BY INDIRECT PTR
	CAMN T1,T2		;HAVE WE DETECTED A LOOP?
	 RETBAD (PMAPX8)	;YES, TIME FOR AN ERROR
	JRST SETP6A		;NO LOOP YET, TRACE ANOTHER LEVEL

SETMXB:	CAIL 2,SSPT		;LEGAL NUMBER?
	BUG(ILSPTI)
	HLRZ 3,1		;GET DESTINATION PTN
	CAIGE 3,NOFN		;FILE?
	BUG(ILDEST)
	HRRZ 3,2
	MOVE 2,SHRPTR		;CONSTRUCT SHARE PTR TO INDEX BLOCK
	STOR 3,SPTX,2
	JRST SETMP5
;SETUP NEW SHARED PAGE

SETMP6:	SKIPG 4,FRESPT		;ASSIGN NEW SPT SLOT
	BUG(SPTFL2)
	HRRZ 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,(NCORTM)		;IN CORE?
	JRST SETP2
	PUSH P,5
	PUSH P,6
	HRRZ 6,3
	CAME 2,CST2(6)		;CHECK OLD OWNERSHIP
	BUG(CST2I1)
	MOVEM 4,CST2(6)		;RECORD NEW LOCATION OF CORE ADDRESS
	HLRZ 6,2		;YES, UPDATE LOCK COUNT FOR
	HRRZ 6,SPT(6)		;OWNING PT
	MOVSI 5,(-PLKV)		;REDUCE IT, BECAUSE IT WILL HAVE
	ADDM 5,CST1(6)		;ONE LESS CORE ADDRESS IN IT
	POP P,6
	POP P,5
SETP2:	ANDX 3,STGADM
	MOVEM 3,SPT(4)		;PUT IT IN SPT
	MOVEM 2,SPTH(4)		;PUT OFN.PN IN SPTH
	MOVE 3,SHRPTR		;MAKE SHARE PTR
	STOR 4,SPTX,3
	HRRZ T4,T2
	MOVEM 3,CXBPGA(T4)	;STORE IT IN XB
	HLRZ 3,2		;GET OFN
	EXCH T1,T3		;GET SPT INDEX IN CORRECT PLACE
	CALL CHKSHC		;CHECK THE SHARE COUNT FOR OVERFLOW
	 JRST [	EXCH T1,T3	;GET ACS BACK IN PROPER STATE
		MOVEI T1,CFRKX3	;WILL OVERFLOW SO GET ERROR CODE
		JRST SETPTE]	;AND PASS THE FAILURE DOWN
	EXCH T1,T3		;GET ACS BACK IN STATE
	CALL SETSHR		;LOCAL INCREMENT SHARE COUNT
SETMP3:	HRRZ T3,T2
	LOAD 3,SPTX,CXBPGA(T3)	;GET SPT INDEX
	CAME 2,SPTH(3)		;ALL OK?
	BUG(ILSPTH)
	EXCH T1,T3		;GET ACS MOVED AROUND
	CALL CHKSHC		;CHECK THE CURRENT SHARE COUNT
	 JRST [	EXCH T1,T3	;GET ACS BACK
		MOVEI T1,CFRKX3	;WILL OVERFLOW SO GET THE ERROR CODE
		JRST SETPTE]	;AND PASS THE FAILURE DOWN
	EXCH T1,T3		;GET ACS BACK IN STATE
	CALL SETSHR		;LOCAL INCREMENT SHARE COUNT
	HLRZ 3,2		;GET OFN
	HRRZS 2
	MOVE 2,CXBPGA(2)	;GET THE POINTER
	JRST SETMP5		;GO PUT IT IN PT

;LOCAL ROUNTINE TO INCREMENT SHARE COUNT OF SPT INDEX IN 3

SETSHR:	EXCH T1,T3		;SAVE CONTENTS OF 1. GET ARG
	CALL UPSHR		;INCREMENT SHARE COUNT
	EXCH T1,T3		;RESTORE REGS
	RET			;AND DONE
;MOVE PAGE.  PAGE IS REMOVED FROM SOURCE RATHER THAN BECOMING SHARED
; 1/ DESTINATION ID, PT MAPPED INTO CPTPG
; 2/ SOURCE ID, PT MAPPED INTO CXBPG
;	CALL MVPT
; RETURN +1, FAILURE, ERROR CODE IN A
; RETURN +2, SUCCESS.

MVPT:	ASUBR <MVPTA1,MVPTA2>
	SAVEAC <Q1>
MVPT0:	DMOVE T1,MVPTA1		;RESTORE ACS IF RESTART
	HLRZ T3,T2		;GET SOURCE PTN
	CALL SETXB1		;MAP INDEX BLOCK
	OKSKED
	SKIP CXBPGA		;REFERENCE PAGE WHILE OKSKED
	SKIP CPTPGA		;FORCE IN DESTINATION PT AS WELL
	NOSKED
	HLRZ 4,2		;GET SOURCE AND DEST PTN'S
	HLRZ 3,1
	CAIL 3,NOFN		;DEST IS FILE?
	IFSKP.
	  CAIL 4,NOFN		;YES, SOURCE ALSO?
	  JRST SETP7		;NO, DO FORK-TO-FILE CASE
	  HRRZ T3,T2
	  LOAD 3,PTRCOD,CXBPGA(3) ;FILE-TO-FILE CASE,
	  CAIE 3,IMMCOD		;PAGE NOW PRIVATE?
	  RETBAD(PMAPX3)	;NO, ERROR
	ELSE.
	  CAIGE 4,NOFN 		;DEST IS FORK, SOURCE ALSO?
	  RETBAD(PMAPX4)		;NO, FILE-TO-FORK ILLEGAL
	ENDIF.
	HRRZ T3,T2
	MOVE 3,CXBPGA(3)	;GET PTR
	JUMPE 3,MVPT3		;NOP IF NULL
	LOAD 4,PTRCOD,3		;GET PTR TYPE
	CAIN 4,IMMCOD		;PRIVATE AND IN CORE?
	TLNE 3,(NCORTM)
	JRST MVPT2
	HRRZ 4,3		;GET ADDRESS ONLY
	CAME 2,CST2(4)		;YES, CHECK CST CONSISTENCY
	BUG(CST2I2)
	MOVEM 1,CST2(4)		;NOTE NEW LOCATION OF POINTER
	CALL MVLK		;MOVE THE PT LOCK COUNT
	HRRZ 1,2
	MOVE 1,CXBPGA(1)	;GET CORE PAGE NUMBER
	CALL DECOR		;DEASSIGN PAGE FROM WS
	MOVE T1,MVPTA1		;RESTORE DEST
MVPT2:	SETZ 3,
	HRRZ 4,2
	EXCH 3,CXBPGA(4)	;REMOVE PTR FROM OLD LOCATION
	HLRZ T4,T1
	HRRZS T1
	CAIGE T4,NOFN		;DEST IS FILE?
	JRST [	ANDX T3,STGADM	;YES, EXTRACT STG ADR FROM PRIV PTR
		IOR T3,IMMPTR	;MAKE STANDARD POINTER
		MOVEM T3,CPTPGA(T1) ;PUT IN XB
		JRST MVPT3]
	MOVE T2,ARG3		;GET USER ACCESS BITS
	CALL SPAC		;SET THEM INTO POINTER
	MOVEM 3,CPTPGA(1)	;PUT IT IN NEW LOCATION
MVPT3:	RETSKP

;LOCAL ROUTINE TO MOVE PT LOCK COUNT WHEN MOVING CORE PTR
;CODE FORCES DEST PAGE IN. SOURCE PAGE MUST BE IN MEMORY
;SINCE A POINTER IS FETCHED FROM IT WHILE THE PROCESS IS NOSKED.

MVLK:	SAVEAC <T3,T4>
	SKIP CPTPGA		;MAKE SURE DEST PT IN MEMORY
	HLRZ 4,2		;SOURCE PTN
	HRRZ 4,SPT(4)
	MOVSI 3,(-PLKV)
	ADDM 3,CST1(4)		;REDUCE LOCK COUNT OF PT
	HLRZ 4,1
	HRRZ 4,SPT(4)
	MOVSI 3,(PLKV)
	ADDM 3,CST1(4)		;INCREASE LOCK COUNT OF XB
	RET
;DESTINATION IS FILE, SOURCE FORK

SETP7:	HRRZ T3,T2
	MOVE 3,CXBPGA(3)	;GET PTR
	JUMPE 3,SETP73		;JUMP IF PAGE NON-EXISTENT
	LOAD 4,PTRCOD,3		;GET PTR TYPE
	CAIE 4,IMMCOD		;NOT PRIVATE?
	RETBAD(PMAPX3)		;YES, ERROR
	HRRZ Q1,3		;ELIMINATE LEFT HALF OF 3
	TLNE 3,(DSKAB)		;NOW ON DISK?
	JRST SETP71		;YES
	TLNE 3,(DRMAB)		;NOW ON DRUM?
	JRST SETP7D		;YES, GO ADJUST DRUM BACKUP ADR
	LOAD 4,STGADR,3		;IN CORE, GET PAGE NUMBER
	CAML 4,MONCOR		;NORMAL SWAPPING PAGE?
	CAMLE 4,NHIPG
	RETBAD(PMAPX5)		;NO, CAN'T MAP INTO FILE
	MOVEI 1,0(Q1)
	CALL AGECHK		;FIX PAGE
	CALL SKPNLK		;PAGE LOCKED?
	IFNSK.
	  CALL WTNLK		;YES, WAIT FOR UNLOCK
	  JRST MVPT0		;RESTART
	ENDIF.
	MOVE T1,MVPTA1		;RESTORE DEST
	MOVSI 4,(PLKV)		;IN CORE,
	ADDB 4,CST1(Q1)		;GET BACKUP ADR AND LOCK PAGE
	TLNE 4,(DSKAB)		;DISK?
	JRST SETP7C		;YES
	TLNE 4,(DRMAB)		;DRUM?
	JRST SETP7E		;YES
	MOVEI 4,CST1(Q1)	;NOT ASSIGNED, PUT BACKUP ADR IN CST1
	CALL SETP7A		;ASSIGN BACKUP ADR AND STORE IT
	 JRST [	MOVEM T1,LSTERR
		HRRZ Q1,T3	;FAILED. GET CORE ADDRESS
		MOVSI T1,(-PLKV)
		ADDM T1,CST1(Q1) ;UNLOCK PAGE
		MOVE T1,LSTERR
		RET]		;FAIL RETURN, NO ROOM
SETP7C:	HRRZ Q1,3
	MOVEM 1,CST2(Q1)	;IN CORE, ADJUST CST
	MOVSI 4,(-PLKV)
	ADDM 4,CST1(Q1)		;UNLOCK PAGE
	CALL MVLK		;MOVE PT LOCK COUNT
SETP71:	HRRZ Q1,2
	SETZM CXBPGA(Q1)	;PUT SOURCE PTR IN DEST MAP
	ANDX 3,STGADM		;EXTRACT STORAGE ADDRESS
	IOR 3,IMMPTR		;MAKE PRIVATE PTR
	HRRZS 1
	MOVEM 3,CPTPGA(1)
SETP72:	MOVE 1,MVPTA1		;BE SURE WE HAVE IDENT
	HRRZ 3,1
	MOVE 3,CPTPGA(3)	;GET CURRENT ADR OF PAGE
	TLNE 3,(DSKAB)		;PAGE NOW ON DSK?
	JRST SETP73		;YES, DONE
	TLNE 3,(DRMAB)		;ON DRUM?
	JRST [	CALL SWPINW	;YES, GET IT IN CORE
		JRST SETP72]	;RECHECK ADDRESS
	HRRZS 1
	MOVE 1,CPTPGA(1)	;GET CURRENT ADDRESS OF PAGE
	CALL SKPNWR		;WRITE IN PROGRESS?
	 JRST SETP72		;YES, RECHECK ADDRESS
	MOVX 2,DSKSWB		;GET DISK BIT
	IORM 2,CST3(1)		;AND SET DISK BIT IN CST
	CALL SWPOT0		;SWAP PAGE TO DISK
SETP73:	MOVE T1,MVPTA1		;IDENT
	HLRZ 3,1		;GET DEST OFN
	MOVX 4,OFNWRB		;NOTE CHANGE TO IT
	IORM 4,SPTH(3)
	RETSKP
SETP7D:	MOVE 4,3
SETP7E:	PUSH P,3
	MOVE 2,4		;DRUM ADDRESS
	CALL GDSTX		;GET DST INDEX
	MOVE 4,2		;WHERE TO STORE ADDRESS
	POP P,3
	MOVE T2,MVPTA2		;RESTORE
	MOVE Q1,0(4)		;PRESENT BACKUP
	TLNE Q1,(DSKAB)		;DISK?
	JRST SETPE1
	CALL SETP7A		;NO, ASSIGN DISK ADDRESS AND STORE IT
	 JRST [	MOVEM T1,LSTERR
		HRRZ Q1,T3	;FAILED. GET CORE ADDRESS (IF ONE)
		MOVSI T1,(-PLKV)
		TLNN T3,(NCORTM) ;CORE PAGE?
		ADDM T1,CST1(Q1) ;UNLOCK PAGE
		MOVE T1,LSTERR
		RET]		;FAIL RETURN
SETPE1:	TLNN 3,(NCORTM)
	JRST SETP7C
	JRST SETP71

	ENDAS.

;ASSIGN DISK ADR AND STORE IT
; T1/ IDENT OF XB
; T4/ ADR OF PTR TO BE SET
; RETURN +1: FAILED, T1/ ERROR CODE
;	+2: SUCCESS

SETP7A:	SASUBR <P71,P72,P73,P74>
	HLRZ T1,P71
	CALL QCHK		;SEE IF OK TO ASSIGN DISK PAGE
      IFSKP.
	MOVE T1,P71		;GET DEST IDENT
	CALL FNDLDA		;GET LAST DISK ADR ASSIGNED FOR DSKASN
	HLRZ T2,P71		;GET OFN
	LOAD T2,STRX,(T2)	;GET STRUCTURE NUMBER
	CALL DSKASN		;ASSIGN DISK ADDRESS FOR PAGE
      ANSKP.
	HLRZ T3,P71		;GET OFN AGAIN
	LOAD T3,ALOCX,(T3)	;INDEX INTO QUOTA TABLE
	DECR PGLFT,(T3)		;ONE LESS PAGE LEFT
	MOVE T4,P74
	STOR T1,STGADR,0(T4)	;STORE ADDRESS PER ARG
	RETSKP
      ENDIF.
	MOVEM T1,P71		;RETURN ERROR CODE
	RET

	ENDSA.
;PUT INDEX BLOCK IN FIXED PAGE (CXBPG) OF PP MAP FOR TEMP USE
; 3/ SPTN

SETXB1:	PUSH P,SHRPTR		;CONSTRUCT SHARE PTR
	STOR 3,SPTX,0(P)
	POP P,3
	CAMN 3,PSBM0+CXBPG	;ALREADY THERE?
	RET			;YES
	CALL RELCXB		;RELEASE CURRENT ONE
	NOINT			;NO INTERRUPTS WHILE XB MAPPED
	MOVEM 3,PSBM0+CXBPG	;PUT INTO CURRENT X BLOCK PAGE
	RET

;RELEASE INDEX BLOCK NOW IN FIXED PAGE

RELCXB:	SKIPN PSBM0+CXBPG
	RET			;NONE THERE NOW
	PUSH P,T1
	NOSKED
	LOAD T1,SPTX,PSBM0+CXBPG ;GET ID
	MOVE T1,SPT(T1)		;GET ADDRESS
	CALL DECOR		;DEASSIGN PAGE (IF CORE)
	OKSKED
	SETZM PSBM0+CXBPG		;CLEAR MAP
	MOVEI 1,CXBPGA
	CALL MONCLR		;CLEAR MAP ENTRY
	POP P,1
	OKINT
	RET

;MAP CURRENT PAGE TABLE FOR TEMP USE
; 1/ SPTN,,PN			;PN IGNORED

SETCPT:	HLRZ 2,1		;GET PTN
	PUSH P,SHRPTR		;CONSTRUCT SHARE PTR
	STOR 2,SPTX,0(P)
	POP P,2
	CAMN 2,PSBM0+CPTPG	;ALREADY THERE?
	RET			;YES
	CALL RELCPT		;RELEASE CURRENT ONE
	NOINT
	MOVEM 2,PSBM0+CPTPG
	RET

;RELEASE CURRENT PT MAPPING

RELCPT:	SKIPN PSBM0+CPTPG		;ANYTHING THERE?
	RET			;NO
	SETZM PSBM0+CPTPG		;CLEAR MAP
	PUSH P,1
	MOVEI 1,CPTPGA
	CALL MONCLR		;CLEAR MAP ENTRY
	POP P,1
	OKINT
	RET
;RELEASE PAGE FROM MAP
; AC1/ OFN.PN OF PAGE
;AC3/ ACCESS BITS

RELMPG:	SAVET			;SAVE TEMPS
	HLRZ T2,T1
	CALL CHKDMO		;STR DISMOUNTED?
	 RET			;YES, DO NOTHING
	CALL SETCPT
	CALL LCKOFI		;LOCK IF OFN
	CALL RELMP5
	CALL PGRCLD
	RET

;RELEASE ASSUMING PT ALREADY MAPPED AND THAT PAGER CLEAR WILL
;BE DONE FOLLOWING.

RELMP5:	SAVEAC <Q1>		;HOLD FLAGS HERE
	HLLZ Q1,T3		;GET FLAGS.

RELMP6:	HRRZ T4,T1
	SKIPN CPTPGA(4)		;REF PAGE BEFORE GOING NOSKED
	RET			;ALREADY EMPTY
	NOSKED
	MOVE 2,CPTPGA(4)	;GET MAP WORD
	JUMPE 2,RELMPS		;EMPTY
	LOAD 3,PTRCOD,2		;GET PTR TYPE
	CAIN 3,IMMCOD		;PRIVATE?
	JRST RELP3		;YES
	TXNN T2,PTWR		;THIS POINTER HAVE WRITE ACCESS?
	TXZ Q1,PM%ABT		;NO. DON'T HONOR "ABORT" REQUEST THEN
	CAIN T3,INDCOD		;INDIRECT?
	JRST RELMI1		;YES
	; ..
;PROCESS A SHARE POINTER

	HLRZ T3,T1		;GET PTN
	CAIGE T3,NOFN		;OWNED BY FILE?
	JRST RELMP4		;CAN'T DELETE FILE PAGE STILL SHARED
	SETZM CPTPGA(T4)	;CLEAR MAP WORD
	MOVE T3,T2		;SAVE POINTER
	LOAD T2,SPTX,T2
	CAIGE 2,NOFN		;OFN?
	JRST RELP1		;YES
	HLRZ 3,SPTH(2)		;IS SHARE POINTER, GET OFN
	JUMPE 3,RELP1		;IF UNOWNED SPTN
	TXNE Q1,PM%ABT		;WANT "ABORT" UNMAP?
	JRST [	MOVX T4,OFNDUD	;GET DUD BIT
		TDNE T4,SPTH(T3) ;OPENED "DUD"?
		CALL CHKDMO	;SEE IF MOUNTED
		 JRST .+1	;NOT. DON'T "ABORT"
		PUSH P,T2
		PUSH P,T3	;SAVE CRITICAL ACS
		LOAD T1,STGADR,SPT(T2) ;GET STORAGE ADDRESS
		HRRZ T2,T3	;PASS OFN
		CALL RELADR	;GO RELEASE PAGES
		POP P,T3
		POP P,T2	;RESTORE CRITICAL ACS
		STOR T1,STGADR,SPT(T2) ;STORE DISK ADDRESS
		JRST .+1]	;DONE
	MOVEI 1,0(3)		;GET OFN
	CALL DWNSHR		;DECREMENT OFN SHARE COUNT
	MOVEI 1,0(2)		;GET PAGE ID
	CALL DWNSHR		;DECREMENT PAGE SHARE COUNT
	CALL GETSHR		;GET PAGE SHARE COUNT
	JUMPN 1,[LOAD 1,STGADR,SPT(2) ;NO. GET STORAGE ADDRESS
		TLNN 1,(NCORTM)	;PAGE NOW IN CORE?
		CALL DECOR	;YES, DEASSIGN IT
		JRST RELMPS]	;DONE
	LOAD 1,STGADR,SPT(2)	;GET STORAGE ADDRESS
	TLNE 1,(NCORTM)		;CORE?
	JRST RELMP2		;NO
	CALL AGESET		;IN CORE, SET AGE
	MOVSI 4,(PLKV)
	ADDM 4,CST1(1)		;AND LOCK WHILE ADJUSTING
	; ..
RELMP2:	CALL SETXB1		;MAP OWNING XB
   REPEAT 0,<	;THIS WOULD BE DESIRABLE EXCEPT IT'S RACE-PRONE
	OKSKED
	SKIP CXBPGA		;TOUCH IT WHILE OKSKED
	NOSKED
   >
	PUSH P,1		;SAVE CORE NUMBER
	HRRZS T1,T3		;GET XB INDEX
	CALL DWNSHR		;DECREMENT SHARE COUNT
	POP P,1			;RESTORE CORE PAGE NUMBER
	MOVE 4,SPTH(2)		;GET OWNING PTN.PN
	PUSH P,3		;SAVE OWNING OFN
	MOVE 3,2
	MOVEI 2,SPT(2)		;CONSTRUCT PTR
	EXCH 2,FRESPT		;RETURN SPT SLOT TO FREE LIST
	MOVEM 2,@FRESPT
	SOS SPTC
	POP P,2			;GET BACK OWNING OFN
	CALL CHKDMO		;SEE IF THIS OFN IS DISMOUNTED
	 JRST CHKRLO		;IT IS. SEE IF OFN NEEDS TO BE RELEASED
	ANDX 1,STGADM		;FLUSH ACCESS AND PTR BITS
	IOR 1,IMMPTR		;CONSTRUCT STANDARD XB PTR
	HRRZ 2,4
	MOVEM 1,CXBPGA(2)	;PUT PRIV PTR BACK INTO XB
	TLNE 1,(NCORTM)		;PAGE IN CORE?
	JRST RELP4		;NO
	HRRZS 1
	CAME 3,CST2(1)		;CONFIRM OLD OWNERSHIP
	BUG(CST2I3)
	MOVEM 4,CST2(1)		;YES, CHANGE RECORD OF OWNING PT
	HLRZ 3,4		;PTN OF OWNING PT
	HRRZ 3,SPT(3)		;CORE ADDRESS OF IT
	MOVSI 2,(PLKV)
	ADDM 2,CST1(3)		;INCREMENT LOCK COUNT
	MOVSI 3,(-PLKV)
	ADDM 3,CST1(1)		;UNLOCK PAGE
	JRST RELP4

RELP1:	MOVEI 1,0(2)
	CALL DWNSHR		;DECREMENT SHARE COUNT
	JRST RELMPS

RELMP4:	MOVEI 1,PMAPX2		;ILLEG UNMAPPING
	MOVEM 1,LSTERR
	MOVEI 1,.ICDAE
	CALL PSIRQ0		;GENERATE ITRAP
	JRST RELMPS
;HERE TO RELEASE INDIRECT PTR

RELMI1:	SETZM CPTPGA(T4)	;CLEAR MAP
	MOVE T3,T2		;SAVE PTR
	LOAD T2,SPTX,T3		;GET PTN FROM PTR
	MOVE T1,T2
	CALL DWNSHR		;REDUCE SHARE COUNT OF PT
	CAIL 2,NOFN		;IS IT A PT
	JRST RELMI5		;YES. GO HANDLE PT
	CALL CHKDMO		;SEE IF A DISMOUNTED OFN
	 JRST CHKRLO		;IT IS. GO CHECK IT OUT
	MOVX 1,OFNDUD		;SEE IF NO UPDATE REQUESTED
	TDNE 1,SPTH(2)		;IS IT?
	JRST [	TXNE Q1,PM%ABT	;WANT "ABORT"?
		CALL RELMI2	;YES. GO DO IT THEN
		MOVE 1,2	;COPY OFN
		CALL GETSHR	;GET ITS SHARE COUNT
		JUMPE 1,.+1	;IF ZERO, SCAN IT ANYWAY
		JRST RELMPS]	;NON-ZERO. SKIP THE SCAN
	LOAD 4,IPPGN,3		;NO. GET PAGE NUMBER IN FILE
	HRLI 4,0(2)		;FORM ID FOR PAGE
	MOVE 3,2		;MOVE OFN
	CALL SETXB1		;MAP THE OFN
	JRST RELP4		;AND MOVE THE PAGE TO DISK

;HERE IF POINTER IS TO OFN ON DISMOUNTED STRUCTURE

CHKRLO:	MOVEI 1,0(2)		;SEE IF NEED TO RELEASE OFN
	CALL GETSHR		;SEE WHAT ITS SHARE COUNT IS
	JUMPN 1,RELMPR		;CAN'T RELEASE IT YET. GO ON
	MOVEI 1,0(2)		;GET OFN IN 1
	CALL DASOFN		;FREE IT
	JRST RELMPR		;AND GO WRAP UP

;HERE IF INDIRECT POINTER TO A PAGE TABLE. IF THIS IS NOT THE
;LAST SHARER, DECREMENT THE SHARE COUNT AND CONTINUE. IF IT IS
;THE LAST SHARER, THE SPT SLOT MUST HAVE BEEN A SECTION POINTER FOR
;ANOTHER PROCESS THAT HAS SINCE UN-SMAP'D IT. THE CALLING PROCESS
;MAY HAVE TOUCHED SOME PAGES SINCE THEN, BUT ONLY IMMEDIATE POINTERS
;CAN EXIST IN THE MAP. GO RELEASE THE PAGES AND THE SPT SLOT.

RELMI5:	MOVEI T1,0(T2)		;GET SPTN
	CALL GETSHR		;GET THE SHARE COUNT
	JUMPN T1,RELMPS		;IF NOT THE LAST ONE, FINISHED
	MOVE T3,T2		;GET SPTN
	CALL SETXB1		;MAP THE PAGE TABLE
	CALL SCNPT		;RELEASE ALL POINTERS IN P.T.
	MOVE T1,T2		;GET SPT INDEX
	CALL UPSHR		;INCREMENT SHARE COUNT FOR DESPT
	CALL DESPT		;DEASSIGN THE SPT SLOT
	CALL RELCXB		;UNMAP THE PAGE TABLE
	JRST RELMPS		;DONE
;RELMI2 - LOCAL ROUTINE TO DO "ABORT" UNMAP.

RELMI2:	SAVEAC <T2,T3,Q1>	;SAVE CRITICAL REGS
	EXCH T2,T3		;OFN TO T3. POINTER TO T2
	CALL SETXB1 		;MAP XB
	LOAD Q1,IPPGN,T2	;GET PAGE NUMBER IN XB
	MOVEI Q1,CXBPGA(Q1) 	;GET ADDRESS OF POINTER
	LOAD T1,PTRCOD,0(Q1) 	;GET POINTER
	JUMPE T1,RELMI3		;IF NULL, GO ON
	CAIE T1,IMMCOD		;IMMEDIATE POINTER?
	JRST [	LOAD Q1,SPTX,0(Q1) ;NO. SHARED. GET SPT INDEX
		MOVEI Q1,SPT(Q1) ;GET ADDRESS OF NEW POINTER
		JRST .+1]	;PROCEED
	LOAD T1,STGADR,0(Q1) 	;GET STORAGE ADDRESS
	HRRZ T2,T3		;PASS OFN
	CALL RELADR		;RELEASE PAGES
	STOR T1,STGADR,0(Q1) 	;PUT ADDRESS BACK
RELMI3:	CALLRET RELCXB 		;RELEASE XB
;RELMP5 CONTINUED ...
;PAGE BECOMING UNSHARED, MUST MAKE IT BE ON DISK

RELP4:	HLRZ T1,T4		;GET THE OFN
	CALL UPSHR		;ARTIFICIALLY INCREMENT OFN
	PUSH P,T1		;SAVE OFN
	CALL MOVDSK		;MOVE IT TO DISK NOW
	MOVE T1,0(P)		;GET BACK OFN
	CALL GETSHR		;GET THE OFN SHARE COUNT
	SOJG T1,RLMPR2		;ARE WE THE ONLY SHARER?
	MOVE T1,0(P)		;YES. GET OFN AGAIN
	CALL DASALC		;CLEAR ALLOC ENTRY IN THE OFN
	LOAD T3,SPTX,PSBM0+CPTPG ;GET CURRENT MAPPING IN CPTPGA
	PUSH P,T3		;SAVE IT FOR LATER
	MOVX T3,OFNDUD		;CHECK IF DUD IS SET
	TDNN T3,SPTH(T1)	;IS IT?
	JRST RLMPR1		;NO. DON'T NEED TO SCAN THE OFN THEN
	CALL LCKOFN		;LOCK THE OFN AGAINST MODIFICATION
	CALL SCNOFN		;GET XB'S PAGES TO DISK
	 JFCL			;SHOULDN'T HAPPEN
	MOVE T1,-1(P)		;GET BACK OFN
	CALL ULKOFN		;UNLOCK THE OFN
RLMPR1:	MOVX T4,OFNWRB		;SEE IF MODIFIED
	TDNE T4,SPTH(T1)	;WAS IT?
	CALL UPDOFN		;YES. PUT OFN ON THE DISK ALSO
	POP P,T1		;RESTORE PAGE TABLE MAPPING
	HRLZS T1		;MAKE IT SPTN.PN
	SKIPE T1		;MAKE SURE SOMETHING IS HERE
	CALL SETCPT		;REMAP IT
RLMPR2:	POP P,T1		;GET OFN
	CALL DWNSHR		;RESTORE ORIGINAL SHARE COUNT
RELMPR:	CALL RELCXB		;RELEASE XB MAPPING
RELMPS:	OKSKED
	RET

;ROUTINE USED TO RELEASE PRIVATE STORAGE IF "ABORT" UNMAP REQUESTED
;	T1/ STORAGE ADDRESS TO RELEASE
;	T2/ OFN

RELADR:	CALL [	SAVEAC <T2>	;SAVE OFN
		CALLRET REMFP1]	;RELEASE STORAGE
	TXNN T1,DSKNB		;NEW DISK PAGE?
	IFSKP.
	  LOAD T3,ALOCX,(T2) 	;YES, MUST DELETE IT
	  INCR PGLFT,(T3)	;ADJUST QUOTAS
	  SETONE OFNWRB,SPTH(T2) ;NOTE OFN MODIFIED
	  LOAD T3,STRX,(T2) 	;GET STRUCTURE NUMBER
	  MOVE T2,SPTH(T2) 	;PASS OFN BITS
	  CALL DEDSKC		;DEALLOCATE THE DISK PAGE
	  SETZ T1,		;SAY NOTHING LEFT
	ENDIF.
	SKIPN T1		;ANYTHING LEFT?
	MOVX T1,UAAB		;NO. SAY UNASSIGNED THEN
	RET			;DONE
;HERE IF PRIVATE PAGE -- PAGE WILL BE DELETED

RELP3:	TLNE 2,(NCORTM)		;IN CORE?
	JRST RELP32		;NO, CAN RELEASE ALL.
	PUSH P,1
	HRRZ T1,T2
	CALL SKPNWR		;WAIT FOR WRITE COMPLETION
	IFNSK.
	  POP P,1
	  OKSKED		;RELMP6 GOES NOSKED AGAIN
	  JRST RELMP6		;GO TRY AGAIN
	ENDIF.
	POP P,1
RELP32:	SOS NPRIVP		;ADJUST PRIVATE PAGE COUNT
	PUSH P,1		;SAVE IDENT
	HRRZS 1
	MOVE 2,CPTPGA(1)	;GET POINTER
	SETZM CPTPGA(1)		;CLEAR MAP SLOT
	LOAD 1,STGADR,2		;GET ADDR ONLY
	TXNN 1,NCORTM		;IN CORE?
	CALL AGECHK		;YES, ENSURE ACCESS
	TXNE 2,PTLOK		;LOCKED POINTER?
	CALL [	LOAD 1,STGADR,2
		CAMGE 1,MONCOR	;RESMON PAGE?
		JRST [	SAVEAC <T2>
			CALL RESPCK ;YES. SEE IF PART OF RESMON
			 RET	;NO. SKIP UNLOCK THEN
			CALLRET MULKCR] ;YES.
		CALLRET MULKCR]	;NO. UNLOCK IT
	LOAD 1,STGADR,2		;GET ADDR ONLY AGAIN
	CALL REMFP1		;DELETE CORE AND DRUM STORAGE
	JUMPE 1,[POP P,1	;DONE IF NOTHING LEFT
		JRST RELMPS]
	PUSH P,1		;HAVE DSK ADR LEFT TO DELETE, SAVE IT
	HLRZ 1,-1(P)		;GET OFN OF DEST
	MOVX 2,OFNWRB		;NOTE CHANGE TO XB
	IORM 2,SPTH(1)
	OKSKED
	NOINT			;STAY NOINT WHILE CPT RELEASED
	CALL RELCPT		;RELEASE CPT CAUSE UPDOF0 USES IT
	CALL UPDOF0		;UPDATE IT TO DSK
	POP P,1			;RECOVER DSK ADDRESS
	HLRZ 2,0(P)		;RECOVER OFN
	LOAD C,ALOCX,(2)	;GET ALLOCATION PNTR
	INCR PGLFT,(C)		;ADJUST PAGES LEFT UP
	LOAD C,STRX,(2)		;GET STRUCTURE NUMBER
	MOVE 2,SPTH(2)		;SEND DEDSK THE OFN BITS
	NOSKED			;MUST CALL IT NOSKED
	CALL DEDSKC		;DELETE IT
	POP P,1			;RECOVER IDENT
	CALL SETCPT		;MAP PT AGAIN
	OKINT			;UNDO NOINT ABOVE
	JRST RELMPS		;DONE
;SCNPT - SCAN A PAGE TABLE AND CLEAR ALL POINTERS

;ACCEPTS:
;	NO AC'S, BUT PAGE TABLE MAPPED IN CXBPG

;	CALL SCNPT

;RETURNS +1: ALWAYS
;	PRESERVES ALL AC'S

;ENTRIES MUST ALL BE IMMEDIATE POINTERS TO CORE

SCNPT:	SAVET
	ACVAR<W1>
	MOVSI W1,-PGSIZ		;SET UP TO STEP THROUGH PAGE
SCNPT1:	SKIPN T1,CXBPGA(W1)	;GET MAP ENTRY
	JRST SCNPT4		;ZERO. SKIP IT
	LOAD T2,PTRCOD,T1	;GET THE POINTER TYPE
	CAIE T2,IMMCOD		;IS IT IMMEDIATE?
	JRST SCNPT8		;NO. BUG
	ANDX T1,STGADR		;GET JUST THE ADDRESS
	CALL REMFP1		;GO DEASSIGN THE PAGE
	JUMPN T1,SCNPT9		;FAILED TO DEASSIGN. MUST BE ON DISK
SCNPT4:	AOBJN W1,SCNPT1		;LOOP THROUGH THE PAGE
	RET
SCNPT8:	BUG (SCPT01)
SCNPT9:	BUG (SCPT02)

	ENDAV.			;END ACVAR
;SUPPORT ROUTINES FOR SECTION MAPPING. ALLOWS A PROCESS
;TO MAP OR UNMAP NON-ZERO SECTIONS OF ITS ADDRESS SPACE

;SET/CLEAR MAP
;	T1/ SOURCE SPTN (SPT INDEX FOR SOURCE -- OFN OR FORK'S PSB)
;		OR
;	T1/ -1 TO CREATE PRIVATE SECTION
;		OR
;	T1/ 0 TO CLEAR SECTION POINTER
;	T2/ PTN,,SECTION
;	T3/ACCESS BITS,,FORKX OF DESTINATION FORK

;RETURNS +1: ERROR, CODE IN T1
;	 +2: SUCCESS

;USECTO IS OFFSET IN PSB FOR SECTION POINTER. PSB GETS MAPPED INTO
;CPTPGA. SECADR IS THE ADDRESS WHERE THE SECTION 0 POINTER IS MAPPED.

SECADR==CPTPGA+USECTO		;WHERE TO FIND SECTION POINTER

;SECTION POINTER CAN BE ONE OF THE FOLLOWING:
;	SHARE POINTER TO ANOTHER FORK'S SECTION MAP (PTSECM IS SET)
;	SHARE POINTER TO A FILE'S OFN (PTSECM IS SET)
;	PRIVATE SECTION (SHARE POINTER TO SPT, PTSECM IS OFF)
;	SECTION DOESN'T EXIST (0)

SECMAP::ASUBR<SID,SECN,SECACS,SECSPT>	;SAVE ARGS
	NOSKED			;PREVENT INTERRUPTION
	MOVE T1,T2		;GET DESTINATION PT
	CALL SETCPT		;MAP IT
	HRRZ T1,SECN		;GET DESIRED SECTION
	SKIPN T2,SECADR(T1)	;NOW EXIST?
	JRST SECMA2		;NO. GO ON THEN
	LOAD T3,PTRCOD,T2	;CHECK PTR TYPE
	CAIE T3,SHRCOD		;SHARE?
	JRST [	CAIE T3,INDCOD	;NO, MUST BE INDIRECT
		BUG(BADPTR)
		LOAD T1,SPTX,T2	;CAN ALWAYS DELETE
		CALL DWNSHR
		JRST SECMA1]
	TXNE T2,PTSECM		;YES, IS THE SECTION MAPPED?
	JRST [	LOAD T1,SPTX,T2	;YES, GET SPT INDEX
		CALL DWNSHR	;DECREMENT SHARE COUNT
		JRST SECMA1]	;DELETE THE SECTION POINTER AND GO AWAY
;SECTION IS PRIVATE AND CAN ONLY BE DELETED IF NOT SHARED
	LOAD T1,SPTX,T2		;CHECK SHARE COUNT
	CALL GETSHR
	CAIE T1,1		;ANY OTHER USERS?
	RETBAD (SMAPX1,<OKSKED
		CALL RELCPT>)	;YES, CAN'T DELETE
	LOAD T1,SPTX,T2
	CALL DESPT		;DELETE THE PT
SECMA1:	HRRZ T1,SECN		;VANISH THE PTR
	SETZM SECADR(T1)
	; ..
	; ..

;DELETE DONE. SET MAP

SECMA2:	SKIPN T1,SID		;WANT TO SET A NEW MAP?
	JRST SECMA5		;NO. DONE THEN
	JUMPL T1,SECMA3		;CREATE PRIVATE SECTION IF DESIRED
	MOVE T3,SHRPTR		;ASSUME A SHARE POINTER
	TXO T3,PTSECM		;SAY IS MAPPED
	TLNE T1,-1		;PTN.PN?
	JRST [	MOVE T3,INDPTR	;YES. GET IND POINTER THEN
		ADDI T1,USECTO	;ORIGIN OF SECTION TABLE
		STOR T1,IPPGN,T3 ;STORE PAGE NUMBER
		HLRZS T1	;GET PTN
		JRST .+1]	;AND PROCEED
	CALL UPSHR		;SHARE IT
	JRST SECMA4		;GO CLEAN UP AND EXIT

;HERE TO CREATE A PRIVATE SECTION.

SECMA3:	CALL ASSPTL		;GET AN SPT SLOT
	MOVEM T1,SECSPT		;SAVE SPT INDEX
	HRRZ T3,SECACS		;GET FORKX OF OWNING FORK
	MOVEM T3,SPTH(T1)	;REMEMBER IT
	CALL SWPIN1		;GET A PHYSICAL PAGE
	MOVSI T2,(-PLKV)	;GET ONE UNIT OF LOCK COUNT
	ADDM T2,CST1(T3)	;UNLOCK IT
	MOVE T3,SHRPTR		;CONSTRUCT SHARE PTR TO NEW SPT SLOT
	MOVE T1,SECSPT		;GET SPT SLOT
SECMA4:	STOR T1,SPTX,T3		;MAKE THE SHARE POINTER
	HLLZ T2,SECACS		;GET DESIRED ACCESS
	CALL SPAC		;CONVERT TO INTERNAL BITS
	HRRZ T1,SECN		;GET SECTION NUMBER
	MOVEM T3,SECADR(T1)	;STORE SHARE POINTER IN PSB
SECMA5:	CALL MONCLA		;CLEAR PAGER
	OKSKED			;ALLOW SCHEDULING AGAIN
	CALL RELCPT		;AND DONE
	RETSKP
;SAME AS SECMAP SETS/CLEARS MULTIPLE SECTIONS IN THE MAP
;ACCEPTS:
;	T1/ SOURCE I.D. (PSB,,SECN)
;	T2/ DESTINATION I.D. (PSB,,SECN)
;	T3/ ACCESS
;	T4/ COUNT (NUMBER OF SECTIONS TO MAP)

;	CALL MSETST

;RETURNS:	+1 FAILURE. T1/ ERROR CODE
;		+2 SUCCESS

MSETST::SAVEQ			;SAVE ACS
	DMOVE Q1,T1		;PUT ARGUMENTS IN A SAFE PLACE
	HLLZ FX,T3		;ACCESS
	HRR FX,T4		;COUNT
MSETS1:	MOVE T1,Q1		;SOURCE (PSB,,SECN)
	TXNN FX,SM%IND		;CALLER REQUEST INDIRECT MAPPING?
	IFSKP.
	  CALL SETS6		;CHECK TO SEE IF WE WOULD MAP A LOOP
	    RETBAD ()		;YES, PASS UP ERROR
	  MOVE T1,Q1		;GET BACK SOURCE ID
	  JRST MSETS3
	ENDIF.
	CALL SECJFN		;A FILE?
	 JRST MSETS2		;NO, JUST STORE A SHARE POINTER TO THE FORK
	CALL [	<SAVEQ>		;SAVE VOLATILE ACS
		HRRZ T1,T2	;PAGE NUMBER WITHIN THE FILE
		LSH T1,-PGSFT	;CONVERT TO SECTION NUMBER
		HLL T1,T2	;JFN,,SECN
		HRRZ Q1,T1	;SOURCE SECTION NUMBER
		HRRI FX,1	;MAP ONE SECTION
		CALLRET SMFILE]	;MAP IT AND UPDATE OFN SHARE COUNTS
	 RETBAD ()		;A LOSER
	JRST MSETS4		;LOOP OVER ENTIRE ARGUMENT LIST

;**;[2877] Replace 1 line with 2 at MSETS2:	DSC	7-DEC-82
MSETS2:	MOVE T1,Q1		;[2877]GET BACK SOURCE ID, MAP INDIRECT ANYHOW
MSETS3:	DMOVE T2,Q2		;DESTINATION (PSB,,SECN)
	TXZ T3,<<-1>^!<PM%RD!PM%WR>> ;ACCESS
	CALL SECMAP		;MAP DESTINATION TO SOURCE
	 RETBAD ()		;FAILURE
MSETS4:	ADDI Q1,1		;NEXT SOURCE SECTION
	ADDI Q2,1		;NEXT DESTINATION SECTION
	TRNE FX,777776		;MAPPED ALL SECTIONS?
	SOJA FX,MSETS1		;NO, DECREMENT COUNT AND MAP NEXT SECTION
	RETSKP			;GOOD RETURN

;SETS6 -
;Routine to check for potential section pointer loop.
;
;   T1/   Source Section ID ( PSB,,Section # )
;   T2/   Destination Page ID
;
;Returns
;   +1    Failure, mapping of source page to destination
;         would build a page pointer loop
;	     T1/   Error code (SMAPX2)
;   +2    Success, OK to map pages
;
;Preserves all ACs but T1

SETS6:	SAVEAC <T2,T3>		;PRESERVE THESE ACS
SETS6A:	CAMN T1,T2		;ARE SOURCE AND DESTINATION THE SAME?
	 RETBAD (SMAPX2)	;YES, ILLEGAL TO MAP SECTIONS IN A LOOP
	PUSH P,T2		;SAVE DESTINATION ID
	CALL SECPTR		;GET THE POINTER FOR SOURCE ID
	POP P,T2		;GET DISTINATION ID BACK
	LOAD T3,PTRCOD,T1	;GET POINTER TYPE
	CAIE T3,INDCOD		;INDIRECT?
	 RETSKP			;NO, THIS IS THE END OF THE LINE.
	LOAD T3,SPTX,T1		;GET SPT INDEX
	LOAD T1,IPPGN,T1	;GET INDEX INTO SECTION TABLE
	SUBI T1,USECTO		;GET SECTION NUMBER
	HRL T1,T3		;PSB,,SECN
	JRST SETS6A		;TRY TO TRACE ANOTHER LEVEL
;ROUTINE TO RETURN A SECTION POINTER
;ACCEPTS:
;	T1/ PSB,,SECN

;	CALL SECPTR

;RETURNS:
;	+1 ALWAYS
;		T1/ SECTION POINTER
;

SECPTR:	NOSKED			;PREVENT INTERRUPTION
	CALL SETCPT		;MAP PT
	HRRZS T1		;GET SECTION ONLY
	MOVE T1,SECADR(T1)	;ANYTHING HERE?
	CALL RELCPT		;FREE TABLE
	OKSKED			;ALLOW SCHEDULING
	RET

;ACCEPTS:
;	T1/ PSB,,SECN

;	CALL SECJFN

;RETURNS:
;	+1 NOT A FILE SECTION
;		T1/ SECTION POINTER
;	+2 A FILE,
;		T1/ OFN
;		T2/ JFN,,PAGE NUMBER

	SWAPCD			;IS SWAPPABLE
SECJFN::STKVAR <SECSAV>
	CALL SECPTR		;GET SECTION POINTER
	TXNN T1,PTSECM		;MAPPED SECTION?
	RET			;NO. CAN'T BE A FILE THEN
	LOAD T2,STGADR,T1	;GET SPTN
	CAIL T2,NOFN		;YES. AN OFN THEN?
	RET			;NO.
	MOVEM T2,SECSAV		;SAVE OFN
	HRLZ T1,T2		;OFN TO LH
	CALL OFNJFX		;GET MATCHING JFN
	 RETBAD()		;NONE FOUND
	MOVE T2,T1		;JFN,,PAGE NUMBER
	MOVE T1,SECSAV		;RECOVER OFN
	RETSKP			;AND INDICATE FILE

	RESCD
;CHKMAP - ROUTINE TO CHECK IF SECTION IS "MAPPED"
;ACCEPTS:
;	T1/ PT,,SECN

;	CALL CHKMAP

;RETURNS: +1 NOT MAPPED.
;		T1/ 0 IF NO MAP ENTRY
;		T1/ SECTION POINTER IF PRIVATE SECTION
;	+2 MAPPED (PTSECM OR INDIRECT)
;		T1/ SECTION POINTER AFTER FOLLOWING INDIRECTION

CHKMAP::CALL SECPTR		;GET SECTION POINTER
	TXNE T1,PTSECM		;MAPPED SECTION?
	RETSKP			;YES
	STKVAR <PTRSAV>		;MAYBE
	MOVEM T1,PTRSAV		;SAVE THE POINTER
	CALL SECIN1		;SEE IF INDIRECT AND IF SO, FOLLOW POINTERS
	CAMN T1,PTRSAV		;INDIRECT?
	RET			;NO, PRIVATE POINTER
;HERE THE POINTER IS KNOWN TO BE INDIRECT. IF ANYONE NEEDS TO KNOW, MARK IT
; AS SUCH HERE
	RETSKP			;YES, THEN ITS ALSO MAPPED

;CHKMPS - SAME AS CHKMAP, EXCEPT FOR CURRENT FORK
;ACCEPTS:
;	T1/ SECTION #

;	CALL CHKMPS

;RETURNS: +1 NOT MAPPED.
;		T1/ 0 IF NO MAP ENTRY
;		T1/ NON-ZERO IF PRIVATE SECTION
;	+2 MAPPED

CHKMPS::MOVE T1,USECTB(T1)	;GET SECTION POINTER
	TXNN T1,PTSECM		;A MAPPED SECTION?
	RET			;NO
	RETSKP			;YES
;SECIND - ROUTINE TO CHASE INDIRECT SECTION POINTERS
;ACCEPTS:
;	T1/ INDEX INTO USECTB (MAPPED IF NOT CURRENT FORK'S CONTEXT)

;	CALL SECIND

;RETURNS:	+1 ALWAYS. T1/ 0 IF NON-EXISTENT SECTION
;			   T1/ FIRST NON-INDIRECT SECTION POINTER
;			       LEFT HALF = AND OF ACCESS BITS

SECIND::SKIPN T1,USECTB(T1)	;SECTION EXIST?
	RET			;NO
	SAVEAC <T2>		;YES, SAVE A WORKING AC
SECIN1:	LOAD T2,PTRCOD,T1	;GET POINTER TYPE
	CAIE T2,INDCOD		;INDIRECT?
	RET			;NO
	PUSH P,T1		;SAVE ACCESS BITS
	LOAD T2,SPTX,T1		;GET SPT INDEX
	LOAD T1,IPPGN,T1	;INDEX INTO INDIRECT SECTION TABLE
	SUBI T1,USECTO
	HRL T1,T2		;PSB,,SECN
	CALL SECPTR		;GET SECTION POINTER
	POP P,T2		;RESTORE ACCESS BITS SO FAR
	TXO T2,-1-PTACB		;PRESERVE ALL EXCEPT ACCESS BIT FIELD
	AND T1,T2		;RUNNING AND OF ACCESS BITS SO FAR
				; ACTUALLY, ONLY PTWR MATTERS
	JRST SECIN1		;LOOP
;ROUTINE TO MOVE A PAGE TO ITS HOME ON THE DISK AND DELETE ANY
;LOCAL STORAGE. CALLED FROM RELOFN AND RELMPG.
;ACCEPTS:	4/ OFN.PN  WITH THE OFN MAPPED INTO CXBPGA
;RETURNS:	+1 ALWAYS, WITH PAGE EITHER ON THE DISK OR
;		   A WRITE IN PROGRESS
;CLOBBERS ALL TEMP REGISTERS

MOVDSK:	HRRZ 2,4
	MOVE 1,CXBPGA(2)	;GET CURRENT ADR OF PAGE
	JUMPE 1,R		;MAY BE EMPTY
	LOAD 2,PTRCOD,1
	CAIN 2,SHRCOD		;BECAME SHARED AGAIN?
	RET			;YES, NOTHING TO DO OR CAN BE DONE
	TXNN 1,NCORTM		;IN CORE?
	JRST MOVDS1		;YES. GO CHECK IT
	TXNE 1,DSKAB		;ON DISK?
	RET			;YES. ALL DONE
	TXNN 1,DRMAB		;ON DRUM?
	JRST [	HRRZ 2,4
		SETZM CXBPGA(2)	;NO, UNNASSIGNED. FLUSH IT
		RET]		;AND DONE
	MOVE 2,1		;PAGE ON DRUM, GET DRUM ADR
	CALL GDSTX		;GET DST INDEX
	MOVE 3,(2)		;CHECK DRUM STATUS WORD
	TLNE 3,(BWRBIT)		;HAS PAGE BEEN MODIFIED SINCE DISK?
	JRST [	MOVE 1,4	;YES, MUST WRITE IT BACK ON DISK
		PUSH P,4
		CALL SWPINW	;SO FIRST GET IT INTO CORE
		POP P,4
		JRST MOVDSK]	;NEXT SWPOUT WILL GO TO DISK
	SETOM (2)		;PAGE NOT MODIFIED, NO WRITING NEEDED
	HRRZ 2,4
	STOR 3,STGADR,CXBPGA(2)	;RELEASE DST SLOT, PUT DSK ADR BACK IN XB
	CALL DASDRM		;DEASSIGN DRUM ADDRESS
	RET			;PAGE NOW ON DISK

;HERE IF PAGE IN CORE

MOVDS1:	CALL SKPNWR		;WRITE IN PROGRESS?
	 JRST MOVDSK		;YES. RECHECK PAGE ID
	CALL SKPNLK		;LOCKED?
	IFNSK.
	  CALL WTNLK		;YES, WAIT FOR UNLOCK
	  JRST MOVDSK		;RECHECK
	ENDIF.
	LOAD T2,STGADR,CST1(T1)	;CHECK BACKUP ADR
	TXNN T2,DSKAB		;ON DISK ALREADY?
	JRST MOVDS2		;NO
	LOAD T2,CSTAGE,(T1)	;YES, CHECK STATE
	CAIN T2,PSRPQ		;ON RPLQ ALREADY?
	RET			;YES, DONE
MOVDS2:	CALL AGECHK		;MAKE PAGE IN USE
	MOVX 3,DSKSWB		;MAKE SURE IT GOES TO DISK
	IORM 3,CST3(1)		;BY REQUESTING THIS EXPLICITLY
	CALL SWPOT0		;SWAP IT OUT
	RET			;DONE
;ROUTINES TO ADJUST AND FETCH SPT SHARE COUNTS.
;ACCEPTS:	1/ SPT INDEX (EITHER PT OR OFN)
;RETURNS:	+1 ALWAYS

;INCREASE SHARE COUNT

UPSHR::	SAVEAC <Q1,Q2>		;GET A WORK REGISTER
	HRRZ Q2,T1		;GET THE SPT INDEX
	CAIL Q2,NOFN		;AN OFN?
	JRST SHRSPT		;NO
	MOVX Q1,OFSHR		;YES. GET BIT FOR OFN
	ADDB Q1,SPTO(Q2)	;INCREMENT SHARE COUNT
	TLNN Q1,(-OFSHR)	;DID IT OVERFLOW?
UPSHRX:	BUG (SHROFN) ;YES
	RET			;NO. RETURN GOOD

SHRSPT:	MOVX Q1,USHR		;GET SHARE BIT FOR SPT
	ADDB Q1,SPT(Q2)		;INCREMENT IT
	TLNN Q1,(-USHR)		;DID IT OVERFLOW?
	BUG (SPTSHR)
	RET			;DONE

;DECREMENT SHARE COUNT

DWNSHR::SAVEAC <Q1,Q2>		;GET A WORK REGISTER
	HRRZ Q1,T1		;GET SPT INDEX
	CAIL Q1,NOFN		;AN OFN
	JRST [	DECR SPTSHC,(Q1) ;NO. DECREMENT SPT SHARE COUNT
		RET]		;AND DONE
	MOVSI Q2,(-OFSHR)	;GET DECREMENTER
	TDNN Q2,SPTO(Q1)	;FIRST CHECK FOR OVER DECREMENTING
	BUG (SHROFD)
	ADDM Q2,SPTO(Q1)	;DO THE DECREMENT
	RET			;AND DONE

;GET CURRENT VALUE OF SHARE COUNT

GETSHR::SAVEAC <Q1>		;GET A WORK REGISTER
	HRRZ Q1,T1		;GET SPT INDEX
	CAIL Q1,NOFN		;AN OFN?
	JRST [	LOAD T1,SPTSHC,(Q1) ;NO. GET SPT SHARE COUNT
		RET]		;AND DONE
	LOAD T1,OFNSHC,(Q1)	;YES. GET OFN SHARE COUNT
	RET			;AND DONE

; CHECK CURRENT VALUE OF SHARE COUNT
; T1/ SPT INDEX ... NO ACS ARE DESTROYED
; NON-SKIP RETURN IF COUNT WILL OVERFLOW ON AN INCREMENT
; SKIP RETURN IF COUNT WILL NOT OVERFLOW

CHKSHC:				;CHECK THE SHARE COUNT
	SAVEAC <T1,T2>		;SAVE SOME WORK ACS
	HRRZS T1		;ZERO THE LEFT HALF OF SPT INDEX
	CAIGE T1,NOFN		;IS THIS AN OFN?
	 RETSKP			;YES SO SKIP RETURN
	LOAD T2,SPTSHC,(T1)	;NOT AN OFN...SO GET SHARE COUNT
	CAIL T2,MAXSHC		;IS COUNT AT THE MAX VALUE?
	 RET			;AT MAX VALUE SO NON SKIP RETURN
	RETSKP			;NOT AT MAX VALUE SO SKIP RETURN

;SPECIAL ROUTINE TO DO MULTIPLE COUNT
;	T1/ OFN
;	T2/ COUNT

MUPSHR::SAVEAC <Q1,Q2>
	MOVE Q2,T2		;SAVE COUNT
	CALL LCKOFN		;LOCK THE OFN
	LOAD Q1,OFNSHC,(T1)	;GET CURRENT COUNT
	ADD Q1,Q2		;NEW COUNT
	TLNE Q1,-1		;OVERFLOW?
	JRST UPSHRX		;YES.
	STOR Q1,OFNSHC,(T1)	;NO. STORE NEW COUNT
	CALL ULKOFN		;UNLOCK THE OFN
	MOVE T2,Q2		;RESTORE COUNT
	RET			;AND DONE
;SKIP IF NO WRITE IN PROGRESS ON CORE PAGE.  OTHERWISE RESCHEDULE
;UNTIL WRITE IS COMPLETED.
; 1/ CORE PAGE NUMBER
;	CALL SKPNWR
; RETURN +1, PAGE WAS BEING WRITTEN, WRITE HAS COMPLETED.
; RETURN +2, PAGE WAS NOT BEING WRITTEN.
;UNLESS THE PAGE IS LOCKED, IT MAY CHANGE STATE ON A RESCHED.  HENCE
;THE +1 RETURNS MEANS THAT THE POINTER TO THE PAGE MUST BE RECHECKED.
;CLOBBERS NO AC'S

SKPNWR::HRRZS A
	SKIPL CST3(A)		;WRITE IN PROGRESS?
	RETSKP			;NO, SKIP
	SAVEAC <A,B>
	MOVE B,FORKX		;REMEMBER FORK WAITING
	STOR B,CFXRD,(A)
	HRLZ A,A		;SETUP SCHED TEST
	HRRI A,DWRTST
	RDISMS			;OKSKED AND DISMISS
	NOSKED			;RESTORE NOSKED STATE
	RET			;RETURN NOSKIP

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

;SKIP IF PAGE NOT LOCKED IN CORE.  CAN'T DINK WITH LOCKED PAGE.
; T1/ PAGE NUMBER
;	CALL SKPNLK
; RETURN +1: PAGE LOCKED
;	+2: PAGE NOT LOCKED

SKPNLK:	TMNE PLKMSK,CST1(A)	;PAGE LOCKED?
	RET			;YES
	RETSKP

;WAIT FOR PAGE TO BE NOT LOCKED.
; T1/ PAGE NUMBER
;	CALL WTNLK
; RETURN +1 ALWAYS WHEN PAGE UNLOCKED.  GOES OKSKED WHILE DISMISSED.

WTNLK:	TMNN PLKMSK,CST1(T1)	;LOCKED NOW?
	RET			;NO, RETURN QUICK
	SAVEAC <T1>
	HRL T1,T1
	HRRI T1,NLKTST
	RDISMS			;OKSKED AND BLOCK IN BALSET
	NOSKED
	RET

;SCHEDULER TEST
; T1/ PAGE NUMBER
; CALLED WITH JSP T4,

NLKTST::TMNE PLKMSK,CST1(T1)
	JRST 0(T4)
	JRST 1(T4)		;UNLOCKED
;ROUTINE CALLED PERIODICALLY TO FINISH DELETING PAGES LEFT BY
;REMFP1 BECAUSE OF A WRITE IN PROGRESS.
;	CALL REMFPB
; RETURN +1 ALWAYS, ALL PAGES DELETED FROM QUEUE

REMFPB::SKIPN DELPGQ		;ANY PAGES ON DELETED QUEUE?
	RET			;NO, DONE
	PIOFF			;YES, PREVENT INTERRUPTS WHILE REMOVING
	HRRZ 1,DELPGQ
	HRRZ 1,0(1)
	EXCH 1,DELPGQ		;REMOVE PAGE FROM QUEUE
	PION
	SUBI 1,CST3		;TRANSLATE TO CORE PAGE NUMBER
	CALL REMFB1		;FINISH UP DELETE
	SKIPE 1			;COMPLETELY DELETED?
	BUG(PGNDEL)
	JRST REMFPB		;DO ALL PAGES
;REMOVE PAGE FROM SYSTEM (DELETE PERMANENT AND TEMPORARY ADDRESSES)
; 1/ STORAGE ADDRESS
;If address is disk or drum, deassignment proceeds immediately.
;If address is core, deassignment must wait in the one case that
;a write is in progress to the disk.  If a write is in progress to
;the drum, CST2 is left 0 and SWPDON cleans up.

REMFP1:	SAVEAC <Q1>
REMFPA:	HRRZ Q1,1
	TLNE 1,(DSKAB)		;DISK?
	RET			;YES, LEAVE IT IN 1
	TLNE 1,(DRMAB)		;DRUM?
	JRST REMFD		;YES
	TLNE 1,(NCORTM)		;CORE?
	JRST [	SETZ T1,	;UNASSIGNED, DONE
		RET]
	CAMG 1,NHIPG		;LEGAL PAGE?
	CAMGE 1,MONCOR
	JRST [	CALL RESPCK	;SEE IF PART OF RESMON
		 JRST .+1	;NO. ASSUME WE WANT TO GET RID OF IT
		SETZ T1,	;IGNORE
		RET]
	LOAD 2,CSTAGE,(Q1)	;GET PAGE STATE CODE
	CAIL 2,PSASN		;ASSIGNED TO PROCESS?
	CALL DECOR		;YES, DEASSIGN
	HLRZ 2,CST2(Q1)		;GET PTN OF OWNING PT
	IFN. T2
	  HRRZ 3,SPT(2)		;GET ADR OF OWNING PT
	  MOVSI 4,(-PLKV)
	  ADDM 4,CST1(3)	;DECREMENT LOCK COUNT
	ENDIF.
	MOVE T2,CST1(Q1)	;GET BACKUP
	TXNE T2,DSKAB		;DISK?
	JRST [	NOSKED		;YES, STAY NOSKED FOR WRITE CHECK
		CALL SKPNWR	;BEING WRITTEN?
		 NOP		;DONE NOW
		OKSKED
		JRST REMFB2]	;FINISH UP
	TXNN T2,DRMAB		;DRUM?
	JRST REMFB2		;NO, UNASSIGNED. GO FINISH UP
	CALL GDSTX		;GET DST INDEX
	MOVX T1,UAAB
	EXCH T1,(T2)		;RESET BACKUP
	TXNN T1,DSKAB		;WAS DISK?
	SETZ T1,		;NO, UNASSIGNED
	PIOFF
	SETZM CST2(Q1)		;FLUSH BACKUP PTR
	MOVE T3,CST3(Q1)	;GET CURRENT DWRBIT
	PION
	TXNE T3,DWRBIT		;WRITE STILL IN PROGRESS?
	RET			;YES, COMPLETION HANDLED BY SWPDON
	SAVEAC <T1>		;NO, FINISH UP NOW, RETURN ADR NOW IN T1
	MOVE T1,Q1
REMFB2:	HRRZ Q1,T1
	SETZM CST2(Q1)		;FLUSH BACK PTR
	MOVSI 4,(-PLKV)
	LOAD 3,CSTAGE,(Q1)	;GET STATE CODE
	CAIE 3,PSRPQ		;ON RPLQ?
	TDNE 4,CST1(Q1)		;OR LOCKED IN CORE?
	SKIPA			;YES, LEAVE IT
	CALL OFRQ		;PUT ON TOP OF RPLQ SINCE NOT TO BE REUSED
	MOVSI T1,(-PLKV)
	AND T1,CST1(Q1)		;FLUSH BACKUP ADDRESS, LEAVE LK CNT
	EXCH T1,CST1(Q1)	;GET BACKUP ADDRESS
	JRST REMFPA

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

;ALTERNATE ENTRY - FROM REMFPB ONLY, ASSUMES CORE PAGE AND CST2 ALREADY 0
; T1/ CORE PAGE NUMBER

REMFB1:	SAVEAC <Q1>
	JRST REMFB2		;JOIN REGULAR SEQUENCE
;HANDLE BAD CORE PAGE--CALLED AS RESULT OF PARITY ERROR OR OTHER
;PROBLEM WITH PHYSICAL PAGE.
; T1/ CORE PAGE NUMBER
;	CALL BADCPG
; RETURN +1, CONTENTS NOT RECOVERABLE
; RETURN +2, CONTENTS RECOVERABLE.

;THE CONTENTS ARE RECOVERABLE IF THE PAGE IS UNMODIFIED, I.E. THE
;DATA CAN BE READ FROM DISK OR DRUM AGAIN.  IN THIS CASE, THE
;POINTERS ARE RESET AND THE NEXT PROCESS REFERENCE SHOULD CAUSE
;THE PAGE TO BE READ INTO A DIFFERENT PHYSICAL CORE PAGE.
;IF THE PAGE HAS BEEN MODIFIED OR IF IT IS LOCKED, IT IS LEFT
;MAPPED AND ANY PROCESSES WHICH REFERENCE THE BAD DATA SHOULD GET
;INTERRUPTS.  IN EITHER CASE, THE PAGE IS LOCKED SO THAT IT WILL
;NOT BE USED AGAIN.

BADCPG::CAMGE T1,MONCOR		;RESIDENT PAGE?
	BUG(RPGERR)
	NOSKED
	MOVX T2,-PLKV
	MOVX T3,CORMB
	TDNN T2,CST1(T1)	;PAGE LOCKED?
	TDNE T3,CST0(T1)	;OR MODIFIED?
	JRST BADCP3		;YES
	MOVEI T2,PSTERR		;NO, SET PAGE TO ERROR STATUS
	STOR T2,CSTPST,(T1)	; ...
	CALL RPCST		;RESET POINTERS
	LOAD T2,CSTAGE,(T1)	;GET PRESENT AGE
	CAIN T2,PSRPQ		;ON RPLQ (CANN HAPPEN, BUT IS RARE)
	JRST [	MOVE T2,T1	;YES
		CALL PRLDEQ	;DEQUEUE THE PAGE
		MOVE T1,T2	;GET BACK PAGE NUMBER
		JRST .+1]	;PROCEED
	PIOFF			;INTERLOCK CALL
	CALL ONSPMQ		;PLACE ON SPMQ, RETURNS PION
	AOS NBADCP		;COUNT LOSSAGE
	OKSKED
	RETSKP

;HERE IF CANNOT RELEASE PAGE BECAUSE MODIFIED OR LOCKED

BADCP3:	MOVE T2,CST2(T1)	;GET OWNER IDENT, FIND OFN IF ANY...
	HLRZ T3,T2
	JUMPN T3,[CAIL T3,NOFN	;HAVE PTN, IS OFN?
		JRST BADCP2	;NO, FORK PAGE
		MOVE T2,T3	;YES
		JRST BADCP1]	;GO MARK OFN
	CAIL T2,NOFN		;IS PAGE AN XB?
	JRST [	HLRZ T2,SPTH(T2) ;NO, GET OWNING PT
		JUMPN T2,BADCP1	;GO MARK IT
		BUG(FRKPTE)]
BADCP1:	MOVX T3,OFNERR		;MARK ERROR IN OFN, REPORTED ON CLOSF
	IORM T3,SPTH(T2)
BADCP2:	MOVEI T2,PSTERR		;INDICATE ERROR IN PAGE
	STOR T2,CSTPST,(T1)	; ...
	AOS NBADCP
	OKSKED
	RET			;RETURN NOT RECOVERABLE
;FPTA and FPTAX -- construct ID corresponding to address

;Accepts:
;	T1/ virtual address plus bit TWUSR (bit 0) if user mode
;	FX/ Fork handle (if calling FPTAX)

;	CALL FPTA or CALL FPTAX

;Returns +1: always
;		T1/ PTN,,PN if section exists
;		    0 if section does not exist

FPTA::	SAVEQ
	MOVE FX,FORKX
	JRST FPTAX1

;FPTAX - SAME AS ABOVE BUT ASSUMES FX ALREADY SETUP

FPTAX:	SAVEAC <Q1,Q2>
FPTAX1:	LOAD Q2,VSECNO,T1	;GET SECTION NUMBER
	LOAD Q1,LPGNO,T1	;GET PAGE NUMBER WITHIN SECTION
	JXN T1,TWUSR,[MOVE T1,Q2 ;YES. GET SECTION POINTER
		CALL SECIND
		JUMPE T1,R	;JUMP IF NON-EX SECTION
		ANDX T1,STGADM	;GET SPT INDEX ONLY
		JRST FPTAR]

;Address is in monitor. Crash if illegal section. Transfer according to section
;number. PGRINI sets up FPTABL

	CAILE Q2,MAXSEC		;IF GREATER THAN MAXSEC SOMBODY HAS BAD SECTION
ILLFPT:	BUG(ILFPTE)
	SKIPN MSECTB(Q2)	;IS THE SECTION POINTER PRESENT?
	JRST RFALSE		;NO. QUITE IRREGULAR! RETURN A ZERO
	JRST @FPTABL(Q2)	;GO TO PROPER PAGE ROUTINE

;Section 0 or 1. Determine page number. If PSB, return
;(SPT index for PSB,,offset for page).

FPTA0:	CAIL Q1,PSVARP		;WHICH PART OF MONITOR?
	CAILE Q1,PSVARL		;PRIVATE PER PROCESS (PSB) ?
	JRST FPTA1		;NO, GO CHECK NEXT AREA
	ADDI Q1,-PSVARP+PSBMAP-PSBPGA ;OFFSET INTO PSBMAP
	LOAD T1,FKPSB		;GET PSB IDENT
	JRST FPTAR

;If JSB, return (SPT index for JSB,,offset for page)

FPTA1:	CAIL Q1,JSVARP
	CAILE Q1,JSVARL		;PRIVATE PER JOB (JSB) ?
	JRST FPTA2		;NO, TRY NEXT AREA
	ADDI Q1,-JSVARP+JOBMAP-JSBPGA ;FIRST JOB PAGE MAPPED BY JOBMAP+0
	LOAD T1,FKJSB		;GET JSB IDENT
	JRST FPTAR

;See if in bit table. If not, return (SPT index for MMAP,,page number)

FPTA2:	CAML Q1,BTSTRT		;WITHIN BIT TABLE
	CAMLE Q1,BTEND		;STILL?
FPTA4:	SKIPA T1,MMSPTN		;NO. IN MONITOR MAP
	JRST FPTA3

;Here to exit. Construct (PTN,,PN) in T1. T1 already has PN. Get PTN from Q1.

FPTAR:	HRLM T1,Q1		;CONSTRUCT PAGE IDENT
	MOVE T1,Q1		;RETURN RESULT
	RET
;In bit table in section 0 (model A only).

FPTA3:	MOVE T1,BTBBAS		;GET SPTN FOR BIT TABLE
	MOVX Q2,UAAB		;GET NO ACCESS BIT
	TDNE Q2,SPT(T1)		;ACCESSIBLE?
	JRST FPTA4		;NO. RETURN MMAP DATA
	SUB Q1,BTSTRT		;GET PAGE NUMBER
	MOVE T1,SPTH(T1)	;YES. GET TRUE ID
	JRST FPTAR		;AND DONE

;Section reserved for directories. Return (OFN for currently mapped directory,,PN)

FPTA6:	HRRZ T1,DRMAP		;MAP DIRECTORY
FPTAS:	JUMPE T1,R		;IF NO SECTION POINTER, RETURN 0
	JRST FPTAR		;GO FORM CORRECT POINTER

;Section reserved for index table. Return (OFN for currently mapped index
;table,,PN)

FPTA7:	HRRZ T1,IDXMAP		;FIND IDXMAP
	JRST FPTAS		;GO FINISH UP

;Section reserved for bittable. Return (OFN for currently mapped bittable,,PN)

FPTA8:	HRRZ T1,MSECTB+BTSEC	;FIND BITMAP
	JRST FPTAS		;GO FINISH UP

FPTAAN:	HRRZ T1,MSECTB+ANBSEC	;FIND ARPANET BUFFER MAP
	JRST FPTAS		;GO FINISH UP

FPTACI:	HRRZ T1,MSECTB+LCSSEC	;FIND LCS SECTION
	JRST FPTAS		;JOIN COMMON FINISH

;Section reserved for the DST. Return (SPT index for section map,,PN)

FPTATB:	HRRZ T1,MSECTB+TABSEC	;FIND TABLES SECTION
	JRST FPTAS		;JOIN COMMON FINISH
;SETUP IO PAGE -- LOCKED AND MAPPED VIA MON MAP
; 1/ IDENT OF SOURCE
; 2/ ACCESS,,MON ADR
;	CALL SETIOP
; RETURN +2, PAGE LOCKED AND MAPPED

SETIOP::ASUBR <SOURCE,BFRP>
	LOAD 2,VPGNO,2		;GET PAGE NUMBER
	HRRM 2,BFRP
	SKIPE 1,MMAP(2)		;PREVIOUS CONTENTS?
	JRST [	SETZM MMAP(2)	;YES, REMOVE
		TXNE T1,NCORTM	;CORE?
		JRST .+1	;NO, FORGET IT
		HRRZ 1,1	;GET CORE PAGE NUMBER
		MOVX T3,-PLKV
		TDNN T3,CST1(T1) ;LOCKED?
		JRST .+1	;NO, FORGET IT
		CALL MULKCR	;UNLOCK IT
		JRST .+1]
	SKIPN 1,SOURCE		;GET SOURCE ID
	JRST SETIO1		;NONE, JUST RESETTING PREVIOUS PAGE
	CALL MLKPG		;LOCK PAGE AND GET CORE PAGE NUMBER
	IOR 1,IMMPTR		;CONSTRUCT POINTER
	MOVE 2,BFRP		;GET ACCESS REQUEST
	TXNN 2,PA%WT		;WRITE WANTED?
	TXZ 1,PTWR		;NO, CLEAR IT
	MOVEM 1,MMAP(2)		;PUT PAGE IN MON MAP
	HRRZS T1		;MAKE ADDRESS FOR CST0(T1)
	MOVX T3,CORMB
	TXNE T2,PA%WT		;PAGE WRITABLE?
	IORM T3,CST0(T1)	;YES, ASSUME IT WILL BE WRITTEN
	CALL KICLKP		;PUT PAGE IN KI MAP
SETIO1:	RETSKP

;MARK MODIFIED PAGE - USED WHEN PAGE IS BEING MODIFIED BY OTHER
;THAN PROCESSOR REFERENCE, E.G. BY IO VIA CHANNEL.
; T1/ CORE PAGE NUMBER
;	CALL MRKMPG
; RETURN +1 ALWAYS, MODIFIED BIT SET FOR SPECIFIED PAGE

MRKMPG::CAML T1,MONCOR		;VALIDATE PAGE
	CAMLE T1,NHIPG
	BUG(ILPAGN)
	SETONE CORMB,CST0(T1)	;MARK IT
	RET
;CREATE A GROUP OF PAGES AND LOCK IN CORE
;CALL
;T1/ START ADDR,,END ADDR
;	CALL CGPLK
;RETURNS+1: ERROR IN LOCKING A PAGE
;	+2: ALL OK

CGPLK::	PUSH P,P2		;SAVE AC
	MOVEI P2,[SKIP (P4)	;CREATE PAGE
		CALL MLKPG	;LOCK IT
		JUMPE T1,[POP P,(P) ;SCRAP RETURN
			JRST BSMGPX] ;EXIT
		RET]
	CALL BSMGP		;MAP THE REGION ONTO SUBR IN P2
	POP P,P2		;RESTORE AC
	JUMPE T1,R		;FAILURE?
	RETSKP			;NO.

;SUBROUTINE TO UNLOCK A GROUP OF PAGES
;T1/ START ADDR,,END ADDR
;	CALL GPULK
;RETURNS+1:	ALWAYS

GPULK::	PUSH P,P2		;SAVE AC
	MOVEI P2,MULKPG		;SUBR TO CALL
	CALL BSMGP		; MAP ONTO SUBR
	POP P,P2		;RESTORE AC
	RET
;LOCK, UNLOCK PAGE ON REQUEST (FOR DTA IO, ETC.)
; 1/ ADDRESS (+1B0 IF USER)
;RETURN +1: 1/ CORE PAGE NUMBER

MLKMA::	TLNN 1,(1B0)		;LOCK PAGE GIVEN ADDRESS. USER?
	SKIPA 0(1)		;NO, MON. REF PAGE TO ENSURE EXISTS
	XCTU [SKIP 0(1)]
	CALL FPTA		;TRANSLATE ADDRESS TO OFN.PN
;	JUMPE T1,SETMPX		;CAN'T HAPPEN SINCE REFERENCE TO PAGE
				;SUCCEEDED

;LOCK PAGE GIVEN OFN.PN
; 1/ OFN,,PN

MLKPG::	SKIPE INSKED		;IN SCHED CONTEXT?
	JRST MLKPGM		;YES, SPECIAL HANDLING
	PUSH P,1
	CALL GETONT		;GET PTN.PN OR OWNING PT
	JUMPE T2,MLKPG2		;JUMPE IF PAGE DOES NOT EXIST
	TLNN 2,(NCORTM)		;PAGE NOW IN CORE?
	JRST MLKPG1		;YES.
MLKPG4:	CALL SWPINW		;INITIATE SWAP AND WAIT FOR COMPL.
	POP P,1
	OKSKED
	JRST MLKPG		;TRY AGAIN

MLKPG2:	TLNN T1,-1		;IN SPT?
	JRST [	MOVX T2,UAAB	;YES, SETUP ADDRESS
		STOR T2,STGADR,SPT(T1)
		JRST MLKPG4]
	CALL SETCPT		;IN A PAGE TABLE - MAP IT
	HRRZ T2,T1
	MOVE T3,IMMPTR		;CONSTRUCT PTR WITH UNASSIGNED ADR
	TXO T3,UAAB
	MOVEM T3,CPTPGA(T2)	;PUT IT IN PT
	CALL RELCPT
	AOS NPRIVP		;ADJUST PRIVATE PAGE COUNT
	JRST MLKPG4

;MLKPG IN SCHED CONTEXT - NONX PAGE IN MONMAP ONLY

MLKPGM:	HLRZ T2,T1		;GET PT IDENT
	HRRZ T3,T1		;GET PAGE NUMBER
	CAMN T2,MMSPTN		;IN MONMAP?
	SKIPE MMAP(T3)		;PAGE IS NON-EXISTENT?
	BUG(ILPLK1)
	MOVE T2,IMMPTR		;CONSTRUCT PTR WITH UNASSIGNED ADR
	TXO T2,UAAB
	MOVEM T2,MMAP(T3)	;PUT IN MON MAP
	CALL SWPIN		;ASSIGN CORE AND CLEAR IT
	HLRZ T1,T1		;GET CORE PAGE NUMBER ASSIGNED
	MOVEI T3,PSASN
	STOR T3,CSTAGE,(T1)	;SET STATE TO IN-USE
	MOVEI T3,OFNUL
	STOR T3,CSTOFK,(T1)	;SET OWNERSHIP TO UNASSIGNED
	MOVX T3,CFXNUL
	STOR T3,CFXRD,(T1)
	JRST MLKCP		;LOCK AND ADJUST VARIABLES
;LOCK PAGE GIVEN CORE PAGE NUMBER
; T1/ PAGE NUMBER
;	CALL MLKCP
; RETURN +1 ALWAYS, T1 PRESERVED

;LOCK PAGE COMMON CODE

MLKCP::	NOSKD1
	SKIPA T2,T1
MLKPG1:	POP P,1
	HRRZS T1,T2
	CAMGE T2,MONCOR		;WITHIN RANGE?
	JRST MLKPG5
	MOVE 1,CST1(2)
	TLNE 1,(-PLKV)		;PAGE LOCKED NOW?
	JRST MLKPG3
	AOS LOKPGS		;NO, COUNT IT
	AOS BALSHC
	AOS SUMNR
	AOS SUMBNR
	TLO 2,(1B0)		;SET LOCAL FLAG FOR TEST BELOW
MLKPG3:	MOVSI 1,(PLKV)
	ADDM 1,CST1(2)		;INCREMENT LOCK COUNT
	AOS LOKSUM
	SKIPE INSKED		;IN SCHED CONTEXT?
	RET			;YES, DONE
	HRRZ T1,T2
	CALL AGESET		;SET AGE
	CALL DECOR
	CALL MONCLA
MLKPG5:	OKSKD1
	RET
;UNLOCK PAGE
; 1/ PAGE IDENT (OFN,,PN)
;	CALL MULKPG
; RETURN +1 ALWAYS, BUGHLT IF PAGE NOT PREVIOUSLY LOCKED

MULKPG::PUSH P,2
	CALL GETONM		;GET OWNING PT
	CAIE T2,0		;PAGE EXISTING?
	TLNE 2,(NCORTM)		;PAGE NOW IN CORE?
	BUG(ILULK1)
	CALL MULK1
	POP P,2
	OKSKED
	RET

MULK1:	MOVSI 1,(-PLKV)
	HRRZS 2
	CAMGE T2,MONCOR		;WITHIN RANGE?
	RET			;NO, IGNORE
	TDNN 1,CST1(2)		;LOCK COUNT NON-ZERO?
	BUG(ILULK2)
	SKIPN INSKED
	AOS NSKED		;PREVENT SCHED WHILE COUNTS BEING ADJUSTED
	ADDB 1,CST1(2)		;DECREMENT LOCK COUNT
	TLNE 1,(-PLKV)		;NOW UNLOCKED?
	JRST MULK2		;NO
	SOS LOKPGS
	CALL UPSWP		;ONE MORE SWAPPING PAGE
	SKIPE CST2(2)		;STILL EXISTS?
	JRST MULK2		;YES
	MOVEI 1,0(2)		;HAS BEEN DELETED, PUT ON RPLQ
	CALL OFRQ		;PUT ON TOP OF RPLQ FOR IMMEDIATE REUSE
MULK2:	SOS LOKSUM
	SKIPN INSKED
	SOS NSKED		;OKSKED
	RET

;UNLOCK PAGE GIVEN MONITOR ADDRESS
;ASSUMED NOSKED OR INSKED

MULKMP::
	CALL FPTA		;GET PTN.PN
	HLRZ T3,T1		;GET OWNING PT
	CAME T3,MMSPTN		;AN MMAP PAGE?
	BUG(ILULK3)
	TLZ T1,-1		;SO INDEX BELOW WORKS
	LOAD T1,STGADR,MMAP(T1)	;GET CORE ADDRESS
	JRST MULKCR

;UNLOCK PAGE GIVEN CORE PAGE NUMBER IN 1
;MAY BE CALLED AT INTERRUPT LEVEL

MULKCR::CAML 1,MONCOR		;LEGAL?
	CAMLE 1,NHIPG
	BUG(ILULK4)
	PUSH P,2
	MOVEI 2,0(1)
	CALL MULK1
	POP P,2
	RET
;MULKSP - UNLOCK A PAGE IN NON-ZERO SECTION.  THIS ROUTINE  MAY BE
;CALLED AT ANY INTERRUPT LEVEL.

;ACCEPTS:  T1/  VIRTUAL ADDRESS

;RETURNS: +1  ALWAYS

MULKSP::PUSH P,T2		;SAVE T2
	CALL GETCPA		;GET REAL PAGE ADDRESS
	POP P,T2		;RESTORE T2
	HRRZS T1		;RETAIN JUST PAGE NUMBER
	CALLRET MULKCR		;GO UNLOCK THE PAGE

;ROUTINE TO ADJUST SWAPPING WHEN PAGES ARE LOCKED OR
;UNLOCKED

;FIRST. ROUTINE TO ADJUST PARAMETERS ON UNLOCK

UPSWP:	SOS BALSHC		;ONE LESS OVERHEAD PAGE
	SOS SUMNR		;AND REMOVE LIEN FROM BALSET
	SOS SUMBNR
	RET			;DONE

;ROUTINE TO ADJUST SWAPPING/SCHEDULING PARAMETERS
;CALLED BY SCHEDULER OR PAGER  WHENEVER NEW PAGES APPEAR IN SYSTEM
;RECOMPUTES ALL VALUES BASED ON TOTRC (E.G. MAXNR, DRMLV0, ...)

ADJSWP::PIOFF			;PROTECT ALL STRUCTURES
	CALL MEMMGT		;RECOMPUTE BASIC SWAPPING PARAMETERS
	SETZM PAGDIF		;NO NEW PAGES
	PION			;OKAY NOW
;**;[2634] Add 1 line at ADJSWP:+4L	PED	27-JUL-82
	MOVE T1,DRMTPG		;[2634] GET NUMBER OF SWAPPING PAGES
	CALLRET SETSSP		;AND RECOMPUTE "DRUM" USAGE
;COMMON SUBROUTINE TO MAP A GROUP OF PAGES FROM LH(T1) TO RH(T1)
;ONTO A SUBR. WHOSE ADDRESS IN IN P2.  IF MMAP IS OWNER OF PAGES,
;CALL BSMGP.  OTHERWISE PUT SPT INDEX IN T2 AND CALL BSMGG.
;T1/ FIRST PAGE ADDRESS,,LAST PAGE ADDRESS
;T2/ SPT INDEX OF PAGE TABLE OWNING PAGES
;P2/ SUBROUTINE TO BE CALLED

BSMGP::	MOVE T2,MMSPTN		;GET MMAP'S SPT INDEX FOR USUAL CASE
BSMGG:	TDZ T1,[PGSIZ-1,,PGSIZ-1]	;ROUND BOTH ARGS DOWN TO PAGE BOUNDARY
	PUSH P,P3		;SAVE ACS
	PUSH P,P4		; ...
	PUSH P,T2		;SAVE SPT INDEX TOO
	MOVE P3,T1		;COPY ARG
	HLRZ P4,T1		;INITIALIZE CURRENT PAGE
BSMGP1:	HRRZ T1,P4		;BUILD PT.PN
	LSH T1,-PGSFT		; ...
	HRL T1,0(P)		; ...
	CALL (P2)		;CALL SUBR
	ADDI P4,1000		;GO ON TO NEXT PAGE
	CAIG P4,(P3)		;DONE?
	JRST BSMGP1		;NO, LOOP BACK
BSMGPX:	POP P,T2		;RESTORE ACS
	POP P,P4		; ...
	POP P,P3		; ...
	RET
;GET CORE PAGE GIVEN ADDRESS OR IDENTIFIER
;CLOBBERS T2

GETCPA::CALL FPTA		;CONVERT ADDRESS TO IDENTIFIER
	JUMPE T1,GETCPX		;IF NOT EXISTANT, NOT IN CORE
GETCPP::SAVEQ
	MOVEI Q2,MAXIND		;MAX INDIRECT LEVELS PERMITTED
	HLRZ 2,1		;PT IDENT
	MOVE 2,SPT(2)		;ADR OF IT
	TLNE 2,(NCORTM)		;IN CORE?
GETCPX:	BUG(PAGNIC)
	HRRZS 1
	HRRZS T2		;SAVE ONLY PAGE NUMBER
	CALL MOVRCA		;MOVE 1,PT(1)
	LOAD Q1,PTRCOD,1	;GET PTR TYPE
	CAIN Q1,IMMCOD		;PRIVATE?
	RET			;YES
	CAIE Q1,INDCOD		;INDIRECT?
	JRST [	LOAD 2,SPTX,1	;SHARED, GET SPT IDX
		MOVE 1,SPT(2)
		RET]
	LOAD Q1,SPTX,2		;GET PT NUMBER
	LOAD 1,IPPGN,2		;GET PAGE NUMBER
	HRL 1,Q1		;CONSTRUCT IDENT
	SOJG Q2,GETCPP		;LOOP, COUNT INDIRECT LEVELS
	JRST GETCPX		;TOO MANY INDIRECTS

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

GETONM:	SAVEQ			;THIS ENTRY ALLOWS NO IND PTRS
	MOVEI Q2,0
	JRST GETON0

GETONT:	SAVEQ
	MOVEI Q2,MAXIND		;MAX NUMBER INDIRECTS PERMITTED
GETON0:	CALL SETCPT		;MAP GIVEN PAGE TABLE
	NOSKED
	HRRZ 2,1
	MOVE 2,CPTPGA(2)	;GET PTR
	JUMPE T2,GETONX		;RETURN IF NONX PAGE
	LOAD Q1,PTRCOD,2	;GET PTR TYPE
	CAIN Q1,IMMCOD		;PRIVATE?
	JRST GETONX
	CAIE Q1,INDCOD		;INDIRECT?
	JRST GETON1		;NO, SHARE POINTER.
	OKSKED
	HRRZ T1,T1
	CAME T1,MMSPTN		;INDIRECT PTR IN MON MAP?
	SOJLE Q2,[SETZ T2,	;NO, COUNT IT
		JRST GETONX]
	LOAD 1,IPPGN,2		;GET PAGE NUMBER
	LOAD 2,SPTX,2		;GET PT NUMBER
	HRL 1,2			;CONSTRUCT IDENT
	CALL RELCPT		;RELEASE CPT
	JRST GETON0		;LOOP

GETON1:	LOAD 1,SPTX,2		;FOR SHARE POINTER, RETURN SPTN
	MOVE 2,SPT(1)		;AND CURRENT ADDRESS
GETONX:	CALLRET RELCPT		;RELEASE CPT AND RETURN
;LODPPG - LOAD VIRTUAL PAGE INTO PHYSICAL LOCATION
;CALL WITH:
;T1/	PTN.PN
;T2/	BITS,,PHY. PAGE
;T3/	PREVIOUS STATE IF ENTERED AT LODPPS
;BITS ARE:
;LK%NCH		DON'T CACHE PAGE
;LK%PHY IF OFF, FREE CHOICE OF PAGE
;LK%AOL ALLOW LOCKING IN OFF-LINE MEMORY
;	CALL LODPPG
;	 ERROR RETURN, CAN'T LOAD PAGE, CODE IN 1
;	SUCCESS PAGE IS LOADED AND LOCKED
;SHOULD ALWAYS BE CALLED NOINT
;VIRTUAL PAGE MUST BE PRIVATE OR NON-EXISTANT
;POINTER WILL HAVE PTLOK SET WHICH WILL CAUSE IT TO BE UNLOCKED
;BY RELMPG.

LODPPG::TXO T3,1B0		;NO SPECIAL "PREVIOUS STATE"
LODPPS::ASUBR <LODSRC,LODDST,LODPST>
	TXNN T2,LK%PHY		;FREE CHOICE?
	JRST LODFRE		;YES. GO CHOOSE
LODPP3:	HRRZ T1,LODDST		;GET PHY PAGE
	LOAD T2,CSTPST,(T1)	;GET CURRENT PAGE STATE
	SKIPGE LODPST		;ALREADY HAVE A "PREVIOUS STATE"?
	MOVEM T2,LODPST		;NO. SAVE HERE
	LOAD T2,CSTAGE,(T1)	;GET AGE
	CAIN T2,PSSPQ		;ALREADY ON SPMQ?
	JRST [	MOVX T3,LK%AOL	;YES. SEE IF OFF-LINE LOCKING ALLOWED
		TDNE T3,LODDST	;IS IT?
		JRST LODPP1	;YES. PAGE WILL RETURN TO SPMQ
		RETBAD (LOCKX1)] ;NO. CAN'T DO IT THEN
	MOVEI T2,PSTOFL		;PLACE PAGE OFF LINE
	CALL SETPST		;PUT INTO SPMQ
	 RETBAD(LOCKX2)		;ERROR, CODE IN 1
LODPP1:	NOSKED			;OWN MACHINE FOR A WHILE
	HLRZ T3,LODSRC		;GET SOURCE PAGE
	CALL SETXB1		;MAP IT
	HRRZ T1,LODSRC		;GET PAGE NUMBER
	SKIPN T1,CXBPGA(T1)	;GET POINTER
	JRST LODPP0		;NON-EX. OKAY
	LOAD T2,PTRCOD,T1	;GET TYPE
	CAIE T2,IMMCOD		;PRIVATE?
LODBAD:	RETBAD (LOCKX1,<CALL RELCXB
			OKSKED>)
	ANDX T1,STGADM		;GET ADDRESS ONLY
	MOVX T2,-PLKV		;LOCK FIELD
	TXNN T1,NCORTM		;IN MEMORY?
	TDNN T2,CST1(T1)	;YES. LOCKED?
	SKIPA			;NO. OKAY TO REPLACE IT
	JRST LODBAD		;LOCKED. CAN'T DO IT. SORRY!
	; ..
LODPP0:	CALL RELCXB		;FREE INDEX BLOCK
	HRRZ T1,LODDST		;GET PHY PAGE NUMBER
	CALL OFFSPQ		;REMOVE FROM SPMQ
	MOVEI T2,PSASN		;GET A GOOD AGE
	STOR T2,CSTAGE,(T1)	;MAKE BLT WORK
	MOVE T1,LODSRC		;GET SOURCE ADDRESS
	MOVE T2,[PTRW+FPG2A]	;MAP PAGE
	CALL SETMPG		;DO IT
	SKIP FPG2A		;GET DATA
	PIOFF			;OWN MACHINE
	HRRZ T1,LODDST		;GET DEST PAGE
	CALL MAPRCA		;MAKE IT ADDRESSABLE
	MOVE T2,T1		;SAVE ADDRESS
	HRLI T1,FPG2A		;SOURCE DATA
	BLT T1,PGSIZ-1(T2)	;MOVE DATA
	CALL UNMRCA		;CLEAR MAPPING
	PION			;BREATH A LITTLE NOW
	MOVEI T2,FPG2A		;WHERE WE PUT DATA
	SETZM T1		;UNMAP
	CALL SETMPG		;FREE IT
	MOVE T1,LODSRC		;WHERE NEW DATA IS TO GO
	HRRZ T2,LODDST		;PHYSICAL PAGE NUMBER
	CALL MAPPHP		;MAKE THEM ONE AND THE SAME
	 JFCL			;CAN'T FAIL
	HRRZ T1,LODDST		;GET PHY PAGE
	MOVE T2,LODPST		;GET OLD STATE BACK
	STOR T2,CSTPST,(T1)	;WILL RETURN TO STATE WHEN RELEASED
	CALL MLKCP		;LOCK PAGE, SET AGE (REMOVE FROM FORK WS)
	OKSKED			;WE CAN REST NOW
	HLRZ T3,LODSRC		;GET PTN
	CALL SETXB1		;MAP IT
	HRRZ T1,LODSRC		;GET PN
	MOVX T2,PTLOK		;FLAG AS LOCKED POINTER
	IORM T2,CXBPGA(T1)	;IN PAGE TABLE
	JE LK%NCH,LODDST,LODPP2	;JUMP IF NO-CACHE NOT REQUESTED
	MOVX T2,PTCACH		;GET CACHE BIT
	ANDCAM T2,CXBPGA(T1)	;CLEAR IT
	HRRZ T1,LODDST		;GET PAGE #
	CALL CASHFP		;FLUSH FROM CACHE
LODPP2:	CALL RELCXB		;RELEASE PAGE TABLE
	RETSKP			;RETURN SUCCESS
;ULDPAG - UNLOAD PAGE IF LOCKED
;CALL WITH:
;T1/	PTN.PN
;	CALL ULDPAG
;	 ERROR, PAGE NOT LOCKED OR CAN'T BE SWAPPED, CODE IN 1
;	SUCCESS, PAGE SWAPPED OUT OF MEM.
;PAGE ALWAYS UNLOCKED IF WAS LOCKED AND CACHE BIT TURNED ON AGAIN

ULDPAG::STKVAR <ULDSRC,ULDDST>
	MOVEM T1,ULDSRC		;SAVE PTN.PN
	HLRZ T3,ULDSRC		;GET PTN
	CALL SETXB1		;MAP IT (RETURNS NOINT)
	HRRZ T2,ULDSRC		;USER PAGE
	MOVX T1,PTLOK		;LOCKED POINTER BIT
	NOSKED			;PROTECT THE PAGE POINTER
	LOAD T3,PTRCOD,CXBPGA(T2) ;GET POINTER TYPE
	CAIN T3,IMMCOD		;IMMEDIATE?
	TDNN T1,CXBPGA(T2)	;IS IT STILL LOCKED?
	JRST ULDPG1		;NO, JUST RETURN
	ANDCAM T1,CXBPGA(T2)	;CLEAR LOCKED POINTER BIT
	MOVX T1,PTCACH		;TURN CACHE BIT BACK ON (IF OFF)
	IORB T1,CXBPGA(T2)	;AND PICKUP POINTER
	ANDX T1,STGADM		;GET PHY ADDR ONLY
	MOVEM T1,ULDDST		;SAVE PAGE NUMBER
	CAML T1,MONCOR		;RES MON PAGE?
	CALL MULKCR		;NO, UNLOCK PAGE
	MOVE T1,ULDDST		;GET PAGE NUMBER AGAIN
ULDPG3:	MOVX T2,-PLKV		;SEE IF STILL LOCKED
	TDNN T2,CST1(T1)	;IS IT?
	CALL SWPOT0		;NO. SWAP IT OUT THEN
ULDPG2:	MOVE T1,ULDDST		;GET PAGE NUMBER AGAIN
	CALL SKPNWR		;WAIT FOR IT TO FINISH
	 JRST ULDPG2		;TRY AGAIN
	HRRZ T2,ULDSRC		;PAGE NUMBER AGAIN
	LOAD T1,STGADR,CXBPGA(T2) ;GET STORAGE ADDRESS NOW
	TXNE T1,NCORTM		;IM MEMORY?
	JRST ULDPG1		;NO. ALL DONE
	LOAD T2,CSTAGE,(T1)	;YES. GET ITS AGE THEN
	CAIN T2,PSRPQ		;ON RPLQ YET?
	JRST ULDPG1		;YES. DONE THEN
	MOVEM T1,ULDDST		;NO. SAVE MEM PAGE NUMBER
	JRST ULDPG3		;AND DO IT AGAIN
   REPEAT 0,<			;FOR NOW, WAIT FOR SWAP OUT
	MOVE T1,ULDSRC		;GET PTN.PN
	CALL SWPPAG		;SWAP PAGE OUT (CXBPG ALREADY HAS PTN)
	 RETBAD()		;RETURN ERROR (ALREADY RELEASED PTN)
	OKSKED			;RETURNED NOSKED
   >				;END OF REPEAT 0
ULDPG1:	OKSKED			;ALLOW SCHEDULING AGAIN
	CALL RELCXB		;RELEASE UPT (DOES OKINT)
	RETSKP

;HERE FROM LODPPG ON FREE CHOICE OF PAGE

LODFRE:	NOSKED			;PROTECT RPLQ
	CALL CHKRPQ		;WAIT FOR PAGES TO SHOW UP
	 JRST .-1		;WAIT SOME MORE
	HRRZ T1,SRPLQ		;GET TOP PAGE
	CAIN T1,SRPLQ		;SRPLQ EMPTY?
	HRRZ T1,DRPLQ		;YES, USE DRPLQ
	SUBI T1,CST3		;COMPUTE PAGE NUMBER
	HRRM T1,LODDST		;MAKE IT THE TARGET PAGE
	OKSKED			;NO NEED FOR THIS NOW
	JRST LODPP3		;AND PROCEED
;SWPPAG - SWAP USER PAGE OUT AND WAIT UNTIL COMPLETE
;CALL WITH:
;T1/	PTN.PN
;	CALL SWPPAG
;	 ERROR, PAGE CAN'T BE SWAPPED, CODE IN 1
;	SUCCESS, PAGE IS NOW SWAPPED (RETURNS NOSKED)
;MUST BE CALLED NOINT
;PAGE MUST BE PRIVATE OR NOT EXIST.
;PAGE MUST NOT BE LOCKED

   REPEAT 0,<			;NOT PRESENTLY NEEDED
SWPPAG::STKVAR <SWPSRC,SWPTRY>
	MOVEM T1,SWPSRC
	MOVEI T2,10		;TRY THIS MANY TIMES
	MOVEM T2,SWPTRY
SWPPG1:	HLRZ T3,SWPSRC		;GET PTN
	CALL SETXB1		;MAP PAGE TABLE (GOES NOINT)
	SKIP CXBPGA		;SWAP IN IF NECESSARY
	NOSKED			;DON'T LET PAGE STATE CHANGE
	HRRZ T1,SWPSRC		;GET PAGE NUMBER
	SKIPN T1,CXBPGA(T1)	;GET POINTER
	JRST SWPPG4		;NON-EX
	CALL RELCXB		;RELEASE MAP (OKINT)
	LOAD T2,PTRCOD,T1	;GET POINTER CODE
	CAIE T2,IMMCOD		;PRIVATE?
	RETBAD(LOCKX1,OKSKED)	;NO, ILLEGAL
	TLNE T1,(NCORTM)	;IN CORE?
	RETSKP			;NO, SKIP RETURN NOSKED
	ANDX T1,STGADM		;GET ADDR ONLY
	MOVSI T2,(-PLKV)	;GET LOCK MASK
	TDNE T2,CST1(T1)	;IS PAGE LOCKED?
	RETBAD(LOCKX2,OKSKED)	;YES, ERROR
	CALL SKPNWR		;WAIT FOR ANY WRITES TO FINISH
	 JRST SWPPG2		;HAD TO WAIT, CHECK EVERYTHING AGAIN
	LOAD T2,CSTAGE,(T1)	;GET AGE
	CAIGE T2,PSASN		;ASSIGNED TO PROCESS?
	JRST SWPPG3		;NO, DEASSIGN
	CALL SWPOT0		;SWAP PAGE OUT
SWPPG2:	OKSKED
	JRST SWPPG1		;AND CHECK AGAIN

SWPPG3:	CALL RPCST		;DEASSIGN CST USAGE (SO WE CAN SWAP IN)
	RETSKP			;RETURN SUCCESS (NOW SWAPPED OUT) (NOSKED)

SWPPG4:	HRRZ B,SWPSRC		;GET VIRT PAGE #
	MOVE A,IMMPTR		;GET IMMEDIATE POINTER
	TXO A,UAAB		;SET UNASSIGNED ADDR BIT
	MOVEM A,CXBPGA(B)	;STORE IN PAGE TABLE
	CALL RELCXB		;RELEASE TEMP MAPPING
	RETSKP			;AND INDICATE SUCCESS
   >				;END OF REPEAT 0
;SETUP PAGER VARIABLES FOR NEW PROCESS
; FORKX/ FORK INDEX
;	CALL SETPPG
; RETURN +1 ALWAYS

SETPPG::MOVE FX,FORKX
SETPP1:	LOAD T1,FKPSB		;GET CORE ADR OF PSB
	MOVE T1,SPT(T1)
	TXNE T1,NCORTM
	BUG(PSBNIC)
	STOR T1,PAGUBA		;PUT IT IN DATAO WORD
	MOVE T2,PSBBAS
	STOR T1,STGADR,SPT(T2)	;PUT IT IN MMAP BASE
	LOAD T1,FKJSB		;GET CORE ADR OF JSB
	MOVE T1,SPT(T1)
	TXNE T1,NCORTM
	BUG(JSBNIC)
	MOVE T2,JOBBAS
	STOR T1,STGADR,SPT(T2)	;PUT IT IN MMAP BASE
	MOVE T1,TODCLK		;COMPUTE AGE REGISTER
	IDIVI T1,GLATCK		;GET TIME IN GLOBAL AGE TICK UNITS
	IDIVI T1,AGEWRP	;REM = VALUE IN RANGE FOR AGE REG
	MOVEI T1,LGABOT(T2)	;ADD BIAS
	MOVEM T1,CURAGE		;SAVE FOR GCCOR
	SETZ T2,
	STOR FX,CFXRM,T2	;PUT FX IN CST UPDATE DATA
	STOR T1,AGEMSK,T2	;CONSTRUCT CST UPDATE WORD
	CALL MVAGER		;SET NEW AGE WORD
	RET
;PRELOAD PAGES ON REQUEST
; 1/ IDENT OF FIRST PAGE
; 2/ NUMBER OF SUCCESSIVE PAGES
;	CALL PREPG
; RETURN +1: NOT ALL PAGES DONE
; RETURN +2: ALL PAGES DONE, SWAPIN REQUESTED FOR ALL PAGES NOT IN CORE

PREPG::	SAVEAC <FX>
	MOVE FX,FORKX
	PUSH P,2		;SAVE COUNT
	CALL SETCPT		;MAP PAGE TABLE
PREPG4:	MOVE 2,NRPLQ		;CHECK FOR SUFFICIENT FREE PAGES
	CAMG 2,NRPMX		;BELOW MIN?
	JRST [	CALL RELCPT	;YES, RELEASE PAGE TABLE
		POP P,2
		RET]		;RETURN FAIL
	NOSKED
	PUSH P,1		;SAVE IDENT
	HRRZ 2,1
	SKIPE 2,CPTPGA(2)	;GET PTR FROM MAP
	CALL PREPG1		;INITIATE SWAP
	 NOP			;IGNORE INCOMPLETE
	POP P,1			;RECOVER IDENT
	OKSKED
	SOSLE 0(P)		;DONE ALL PAGES?
	AOJA 1,PREPG4		;NO, BUMP IDENT AND GO DO NEXT ONE
	POP P,2
	CALL RELCPT		;RELEASE PT
	RETSKP
;PRELOAD PAGES FOR FORK, FORKX IN 7

PRENRF==1B0			;PAGE NOT READY FLAG
PRERST==1B1			;WS HAS BEEN RESET

PRELD::	TRVAR <PREOKF>
	SETOM PRELRQ		;NOTE PRELOADING REQUESTS FOR SWAPPER
	SETZM PREOKF		;CLEAR FLAGS
	CALL SETPP1		;SETUP MAP FOR FORK
	LOAD T1,FKWSS		;SEE IF FKNR HAS BEEN RESET, I.E.
	CAMGE T1,NWSCE		;.L. NWSEC AND .LE. MINWSS
	CAMLE T1,MINWSS
	JRST PRELD1		;NO, PRELOAD
	MOVX T1,PRERST		;YES, FLAG RESET
	IORM T1,PREOKF
PRELD1:	MOVE T1,[CALL PRELW1]	;MAP ALL PAGES IN WS
	CALL MAPWSC
	CALL SETPSK		;RESET TO SCHED CONTEXT
	SETZM PRELRQ
	MOVE T1,PREOKF
	TXNN T1,PRENRF		;ALL PAGES READY?
	RETSKP			;YES
	HRLZ T1,T1		;NO, RETURN TEST FOR NOT READY PAGE
	HRRI T1,PRELWT
	RET

PRELWT::JUMPN T1,SWPRT		;CHECK PAGE IF HAVE PAGE NUMBER
	MOVE T2,NRPLQ		;OTHERWISE, CHECK RPLQ
	CAMG T2,NRPMX
	JRST 0(T4)
	JRST 1(T4)

;ROUTINE CALLED FOR EACH PAGE OF WS
; T1/ VIRTUAL ADDRESS IN PAGE FAIL FORMAT

PRELW1:	MOVE T2,PREOKF
	TXNE T2,PRERST		;WS RESET?
	JRST [	CALLRET DELWSC]	;YES, REMOVE ENTRY FROM WS CACHE
	MOVE T2,NRPLQ
	CAMG T2,NRPMX		;ROOM FOR ANOTHER PAGE?
	JRST PRELW2		;NO
	TXNE T1,TWUSR		;USER SECTION 0?
	TXNE T1,VSECNO
	JRST [	CALL FPTAX	;NO, GET ID
		JUMPE T1,R	;QUIT IF NO SECTION PTR
		CALL PREPGP	;LOAD THE PAGE
		 JRST PRELW3	;NOT COMPLETE
		RET]
	LOAD T1,LPGNO,T1	;GET PAGE NUMBER
	MOVE T2,UPTPGA(T1)	;GET PTR
	LOAD T3,FKUPT		;CONSTRUCT ID FOR USER SECTION 0 PAGE
	HRL T1,T3
	CALL PREPG1		;LOAD THE PAGE
	 JRST PRELW3		;NOT COMPLETE
	RET

PRELW3:	HRRM T1,PREOKF		;SAVE PAGE NUMBER
PRELW2:	MOVX T1,PRENRF
	IORM T1,PREOKF		;NOTE SAW A PAGE NOT READY
	RET
;PRELOAD A PAGE - INITIATE SWAPIN IF PAGE NOT ALREADY IN CORE
; T1/ IDENT
;	CALL PREPGP
; RETURN +1: PAGE BEING LOADED, T1/ PAGE NUMBER
; RETURN +2: PAGE READY NOW

PREPGP::STKVAR <PREPID,ICNT>
	MOVEI T3,MAXIND		;SETUP INDIRECT COUNT
	MOVEM T3,ICNT
	MOVEM T1,PREPID
	HLRZ T1,T1
	JUMPN T1,PREPP1		;JUMP IF HAVE PTN
	HRRZ T1,PREPID		;SPTN GIVEN
	LOAD T2,STGADR,SPT(T1)	;GET ADR
	JRST PREPG5

;SAME AS ABOVE BUT FASTER IF PTR ALREADY FETCHED
; 1/ IDENT OF PAGE
; 2/ PTR
;	CALL PREPG1
; RETURN +1: ALWAYS

PREPG1:	STKVAR <PREPID,ICNT>
	MOVEI T3,MAXIND		;SETUP INDIRECT COUNT
	MOVEM T3,ICNT
	MOVEM T1,PREPID
PREPG0:	JUMPE T2,PREPG2		;JUMP IF NO PAGE
	LOAD 3,PTRCOD,2		;GET PTR TYPE
	CAIN 3,INDCOD		;AN INDIRECT POINTER?
	JRST PREPG3		;YES
	CAIN 3,SHRCOD		;SHARED?
	JRST [	LOAD 1,SPTX,2	;YES, GET SPT INDEX
		MOVE 2,1	;SPTN TO 2
		CALL CHKDMO	;SEE IF A DISMOUNTED OFN
		 JRST PREPG2	;IT IS, IGNORE IT
		LOAD 2,STGADR,SPT(1) ;AND ADDRESS FROM SPT
		JRST .+1]
PREPG5:	TLNE 2,(NCORTM)		;PAGE NOW IN CORE?
	JRST [	TLNN 2,(DSKAB+DRMAB) ;PAGE IS ASSIGNED?
		JRST PREPG2	;NO
;**;[2895] Replace line deleted by 2893	PED	10-JAN-83
		SKIPLE NRPLQ
		CALL SWPIN	;YES, SWAP IT IN
		HLRZ T1,T1	;LEAVE PAGE ONLY IN T1
		JRST PREPGX]	;PAGE NOT READY YET
	CALL PRELSC		;SET CST APPROPRIATELY
	 JRST PREPGX		;PAGE NOT READY YET
PREPG2:	RETSKP			;RETURN PAGE READY FOR USE

PREPGX:	RET			;RETURN PAGE NOT READY
;INDIRECT PTR

PREPG3:	LOAD T1,SPTX,T2		;PTN
	LOAD T2,IPPGN,T2	;PAGE NUMBER
	HRL T2,T1		;CONSTRUCT NEW IDENT
	MOVEM T2,PREPID		;SAVE IT
PREPP1:	MOVE T2,T1
	CALL CHKDMO		;CHECK DISMOUNTED
	 JRST PREPG2		;YES, IGNORE IT
	LOAD T2,STGADR,SPT(T1)	;PT ADDRESS
	TXNE T2,NCORTM		;IN CORE?
	JRST PREPG5		;NO, GO LOAD IT
	CALL PRELSC		;YES, CHECK CST, ETC.
	 JRST PREPGX		;NOT READY, CAN'T GET PTR FROM IT
	HRRZ T1,PREPID		;CAN FETCH PTR FROM IT
	CALL MOVRCA
	MOVE T2,T1
	MOVE T1,PREPID
	SOSLE ICNT		;COUNT INDIRECT PTRS SEEN
	JRST PREPG0		;TRY AGAIN
	JRST PREPG2		;INDIRECT LOOP, INGORE IT

;CHECK AND FIXUP CST AS APPROPRIATE FOR PAGE BEING PRELOADED

PRELSC:	HRRZ T1,T2		;FLUSH LH, LEAVE PN IN T1
	LOAD T3,CSTAGE,(T1)	;PAGE IS IN CORE, SEE WHAT STATE
	CAIL T3,PSASN		;ASSIGNED?
	RETSKP			;YES, CAN BE USED NOW
	CAIN T3,PSRIP		;READ IN PROGRESS?
	RET			;YES, CANNOT BE USED
	CALL AGESN		;OTHERWISE CAN BE ASSIGNED
	RETSKP			;CAN BE USED NOW
;CHECK AGE FIELD OF PAGE TO ENSURE TEMPORARY ACCESS.  IF PAGE MUST
;BE ASSIGNED, DEASSIGN IT IMMEDIATELY SO GCCOR WILL CATCH IT.
; T1/ CORE PAGE NUMBER
;	CALL AGECHK
; RETURN +1 ALWAYS

AGECHK:	PUSH P,FX
	MOVE FX,FORKX		;GET SELF
	CALL AGECKN		;DO THE WORK
	POP P,FX
	RET

;SAME AS ABOVE BUT EXPECTS FX ALREADY SETUP
; T1/ CORE PAGE NUMBER
; FX/ FORK INDEX
;	CALL AGECKN
; RETURN +1 ALWAYS

AGECKN::PUSH P,T2		;MUST PRESERVE THIS
	HRRZ T1,T1
	LOAD T2,CSTAGE,(T1)
	CAIL T2,PSASN		;NOW ASSIGNED?
	JRST [	LOAD T2,CSTOFK,(T1) ;YES, CHECK OWNER
		CAIL T2,NFKS	;OWNED?
		JRST PB2	;NO
		JRST AGECK0]	;YES, DEASSIGN
	CALL AGESN		;MAKE ACCESSABLE
AGECK0:	CALL XDECR0		;DEASSING
	CALLRET PB2		;AND DONE
;DEASSIGN CORE
; T1/ CORE PAGE NUMBER
;RETURN +1 ALWAYS, LH OF T1 CLEARED

DECOR:	TLNE T1,(NCORTM)	;GIVEN MAP WORD, NOW IN CORE?
	RET			;NO, NOTHING TO DO
	SAVEAC <T2>
	HRRZ T1,T1
	LOAD T2,CSTAGE,(T1)	;GET STATE CODE
	CAIGE T2,PSASN		;NOW ASSIGNED?
	RET			;NO
	LOAD T2,CSTOFK,(T1)	;GET PROCESS ASSIGNMENT
	CAIL T2,NFKS		;ASSIGNED?
	RET			;NO
	CALL SOSWSP		;REDUCE N FOR THIS PROCESS
	MOVX T2,OFNUL		;MARK PAGE UNASSIGNED
	STOR T2,CSTOFK,(T1)
   REPEAT 0,<			;LEAVE PAGE UNCHARGED UNTIL NEXT GCCOR
	MOVX T2,-PLKV
	TDNE T2,CST1(T1)	;LOCKED?
	JRST [	AOS BALSHC	;YES, CHARGE TO SYSTEM
		AOS SUMNR
		AOS SUMBNR
		JRST .+1]
   >				;END REPEAT 0
	RET

;DECOR AND RESET LAST REFERENCE
;AS ABOVE BUT ASSUMING ASSIGNED CORE PAGE AND T2 AVAILABLE

XDECOR:	LOAD T2,CSTOFK,(T1)	;OWNER?
	CAIL T2,NFKS
	RET			;NO
XDECR0:	CALL SOSWSP		;REDUCE FKWSP
	MOVX T2,CFXNUL
	STOR T2,CFXRD,(T1)	;RESET LAST REF
	MOVX T2,OFNUL
	STOR T2,CSTOFK,(T1)	;RESET OWNER
	RET
;DECREMENT WSP AND RELEASE CORE NUMBER IF WSP 0
; T1/ CORE PAGE NUMBER
;RETURN +1 ALWAYS, ALL ACS PRESERVED

SOSWSP:	SAVEAC <T2,FX>
	LOAD FX,CSTOFK,(T1)	;GET FORK ASSIGNMENT
	LOAD T2,FKCSIZ		;GET CURRENT COUNT
	SOJL T2,[BUG(WSPNEG,<<FX,D>,<T2,D>>)
		JRST SOSWS1]	;DON'T ALLOW NEGATIVE
	STOR T2,FKCSIZ		;UPDATE COUNT
SOSWS1:	RET
;GARBAGE COLLECT CORE, REMOVE PAGES OF PROCESSES NOT IN BAL SET

;TEST FOR GCCOR NEEDED - CALLED FROM SCHED.  IF GCCOR NEEDED, OVERHEAD
;CHARGING IS SWITCHED BEFORE CALL TO GCCOR

TSTGCC::SKIPE SKEDFC		;FORCED CLEAR?
	RETSKP			;YES, DO GCCOR
	SKIPG DRMTPG		;SWAPPING INITIALIZED?
	RET			;NO, DO NOTHING
	MOVE T2,TODCLK
	SUB T2,LSTAGE		;COMPUTE TIME SINCE LAST GCCOR
	CAIL T2,<AGEWRP-200>*GLATCK	;NEAR END OF RANGE?
	RETSKP			;YES, COLLECT
	RET			;NO, DO NOTHING

GLATCK==:^D100			;MS PER TICK OF GLOBAL PAGE AGE CLOCK
SHRWND:	^D1000/GLATCK		;SHARED PAGE AGE WINDOW
;MAIN ROUTINE - FUNCTIONS SOMEWHAT DIFFERENTLY DEPENDING ON POSPGF.
;UPDATES BALSHC BASED ON NUMBER OF PAGES BEING KEPT IN CORE BECAUSE
;THEY ARE LOCKED OR BECAUSE THEY ARE IN USE BY BALSET FORKS.
;AC USE:
; P1/ RUNNING COUNT OF AVAILABLE PAGES
; P2/ MASK OF CORE NUMBERS OF BALSET FORKS
; P3/ MASK OF RECENTLY RELEASED CORE NUMBERS TO BE CLEARED FROM CST0
; P4/ AOBJN PTR TO CST

GCCOR::	SKIPG DRMTPG		;DRUM INITED?
	RET			;NO, DO NOTHING
	SAVEP
	AOS NGCCOR		;COUNT OCCURRANCES
	SETZ P2,
	MOVE 1,NRPMX
	SKIPN SKEDFC		;DEPG ALL IF FORCED CLEAR
	CAMLE 1,NRPLQ
	MOVE 1,NRPLQ		;INSPECT N PAGES
	JUMPE 1,GCWS4		;N MAY BE 0 ...
	HRRZ P3,SRPLQ		;GET FIRST PAGE
GCPC1:	CAIN P3,SRPLQ
	HRRZ P3,DRPLQ
	MOVEI 3,0(P3)
	SUBI 3,CST3		;GET PAGE NUMBER
	CALL DEPGS		;UNDO POINTER AND FLUSH BACK PTR,
	SETZM CST2(3)		;THUS UNLOCKING OWNING PT
	HRRZ P3,0(P3)
	SOJG 1,GCPC1
GCWS4:	MOVE P1,NRPLQ
	ADD P1,IOIP		;WRITES NOW IN PROGRESS
	MOVE T1,TODCLK		;UPDATE CURAGE
	IDIVI T1,GLATCK
	IDIVI T1,AGEWRP		;REM = VALUE IN RANGE FOR AGE REG
	MOVEI T1,LGABOT(T2)	;ADD BIAS
	MOVEM T1,CURAGE
	MOVE T2,NWSMEM
	CAIG T2,1		;ONLY 1 FORK IN MEM?
	JRST GCWS5		;YES, FLUSH ALL SHARED PAGES
	MOVE T2,NGOJOB
	CAME T2,NBPROC		;ALL RUNNABLE FORKS IN MEM?
	JRST [	SUB T1,SHRWND	;NO, FIXED 1 SEC WINDOW
		JRST GCWS5]
	MOVE T2,TOTRC		;ESTIMATE CORE DEMAND
	SUB T2,SUMBNR
	IMULI T2,^D10
	CAMGE T2,TOTRC		;MIN LIMIT
	MOVE T2,TOTRC
	IDIV T2,TOTRC
	IMUL T2,SHRWND
	SUB T1,T2		;COMPUTE START OF WINDOW
GCWS5:	MOVEM T1,CUTAGE		;SAVE IT
	; ..
	; ..
GCCOR2:	CALL SWPOMI		;INIT SWAPOUT LIST
	SETZM BSHC2
	MOVE P4,MONCOR
	SUB P4,NHIPG		;COMPUTE MAX NUMBER PAGES TO CHECK
	MOVSI P4,-1(P4)
	HRR P4,MONCOR		;SETUP AOBJN PTR
GCC2:	LOAD 1,CSTAGE,(P4)	;CODE FIELD
	CAIGE 1,PSASN		;PAGE IN USE?
	JRST [	CAIE T1,PSRDN	;NO, READ COMPLETED?
		JRST GCC1	;NO, LEAVE IT
		SKIPE SKEDFC	;COLLECT ALL?
		JRST GCCS	;YES, COLLECT READ COMPLETED PAGE
		LOAD FX,CFXRD,(P4) ;GET FX OF FORK WHICH INITIATED READ
		CAIGE FX,NFKS	;IF NOT A FORK,
		SKIPGE FKPT(FX)	;OR FORK DELETED?
		JRST GCCS	;FLUSH PAGE
		HRRZ T1,P4
		CALL AGESN	;ASSIGN PAGE AND SET AGE
		JE FKWSL,,GCCS	;COLLECT PAGE IF WS NOT IN MEM
		JRST GCC1]	;LEAVE PAGE
	SKIPE SKEDFC		;COLLECT ALL?
	JRST GCCS		;YES
	CAMLE T1,CURAGE		;PAGE AGE .G. CURRENT AGE?
	SUBI T1,AGEWRP		;YES, WRAPAROUND
	LOAD FX,CSTOFK,(P4)	;GET OWNING FORK
	CAIL FX,NFKS
	JRST [	MOVX T3,-PLKV	;NONE, PAGE LOCKED?
		TDNN T3,CST1(P4)
		JRST GCCA3	;NO, CHECK AGE
		AOS BSHC1	;YES, CHARGE TO SYSTEM
		JRST GCC1]	;DONE WITH PAGE
	SKIPGE FKPT(FX)		;OWNER DELETED? (NOT SUPPOSED TO HAPPEN)
	JRST GCCS		;YES, COLLECT
	MOVE T2,FKSWP(FX)
	JXE T2,FKWSL,GCCS	;COLLECT IF FORK WS NOT LOADED
	LOAD T1,FKXAGE		;GET AGE AT LAST XGC OR WSSWPO
	ANDX T1,<.RTJST XGAGE,XGAGE>
	LOAD T3,XGAGE,(P4)	;GET AGE AT WHICH PAGE LAST INSPECTED
	CAME T3,T1		;SAME?
	JRST GCCS		;NO, PAGE LOST FROM WS CACHE, COLLECT IT
	JRST GCC1		;KEEP

GCCA3:	CAMG T1,CUTAGE		;OLD?
	JRST GCCS		;YES, COLLECT
	LOAD FX,CFXRD,(P4)	;GET IDENT OF LAST REF
	CAIL FX,NFKS
	JRST GCCS		;NONE, COLLECT
	MOVE T2,FKSWP(FX)
	JXE T2,FKWSL,GCCS	;COLLECT IF WS NOT LOADED
	AOS BSHC2		;COUNT DESCRETIONARY SHARED PAGES
	AOS BSHC1		;YES, CHARGE TO SCHED
	JRST GCC1		;DONE WITH PAGE
GCCS:	HRRZ 1,P4
	CALL DECOR		;DEASSIGN PAGE FROM FORK
	MOVE 2,CST1(P4)		;BACKUP ADDRESS
	TLNE 2,(-PLKV)		;PAGE LOCKED?
	JRST [	AOS BSHC1	;YES, LEAVE IT AND CHARGE TO SCHED
		JRST GCC1]
	MOVSI 2,(DWRBIT)
	TDNE 2,CST3(P4)		;PAGE BEING WRITTEN?
	JRST GCC1		;YES, LEAVE IT
	HRRZ T1,P4		;SWAPOUT
	MOVX 2,CORMB
	TDNE 2,CST0(1)		;PAGE WAS WRITTEN?
	SKIPG SWRSAF		;REASSIGNING SWAP STORAGE?
	JRST [	CALL SWPOUT	;NO, DO SINGLE-PAGE SWAPOUT
		JRST .+2]
	CALL SWPOML		;YES, PUT PAGE ON LIST
	ADDI P1,1		;COUNT PAGES COLLECTED
	AOS SGCCWR		;SYSTEM TOTAL
GCC1:	AOBJN P4,GCC2
	HRRZ T1,P4
	CAMLE T1,NHIPG		;REACHED END OF CORE?
	CALL GCECOR		;YES, WRAPAROUND, UPDATE VARIABLES, ETC.
	MOVEM P4,GCCLPG		;REMEMBER LAST PAGE DONE
	CALL SWPOMG		;DO ALL SWAPS QUEUED ABOVE
	SETZM CGFLG
	MOVE T2,TODCLK		;NOTE TIME OF LAST GCCOR
	MOVEM T2,LSTAGE
GCCZ:	RET

GCECOR:	HRR P4,MONCOR		;RESET TO LOWEST PAGE
	MOVE T1,BSHC1		;GET NEW BALSHC VALUE
	PIOFF			;PROTECT AGAINST CHANGES AT PI LEVEL
	SUBM T1,BALSHC		;COMPUTE NEW-OLD
	EXCH T1,BALSHC		;SET NEW VALUE
	ADDM T1,SUMNR		;UPDATE SUMNR AND SUMBNR BY DIFFERENCE
	ADDM T1,SUMBNR
	PION
	SETZM BSHC1		;RESET NEW SHARE COUNT
	RET

;UPDATE SUMNR AND SUMBNR
; T1/ DIFFERENCE
; FX/ FORKX

UPDSNR:	ADDM T1,FKNR(FX)
	ADDM T1,SUMNR
	JE FKIBS,,R		;DONE IF FORK NOT IN BALSET
	ADDM T1,SUMBNR
	RET
;FORK GC - COLLECT PAGES FOR SPECIFIED PROCESS
; FX/ FORK INDEX
;	CALL FKGC

FKGC::	SAVEAC <P1>
	MOVE T1,MONCOR		;SETUP AOBJN PTR
	SUB T1,NHIPG
	MOVSI P1,-1(T1)
	HRR P1,MONCOR
	CALL SWPOMI		;INIT SWAPOUT LIST
FGC1:	LOAD T1,CSTOFK,(P1)
	CAMN T1,FX		;SAME FORK
	JRST FGC2		;YES, COLLECT IT
FGC3:	AOBJN P1,FGC1		;DO ALL PAGES
	CALL SWPOMG		;SWAPOUT LIST
	RET			;DONE OK

FGC2:	LOAD T1,CSTAGE,(P1)
	CAIGE T1,PSASN		;PAGE ASSIGNED?
	JRST FGC7		;NO
	HRRZ T1,P1
	CALL XDECR0		;DEASSIGN
	MOVX T1,-PLKV
	MOVX T2,DWRBIT
	TDNN T1,CST1(P1)	;PAGE LOCKED?
	TDNE T2,CST3(P1)	;PAGE BEING WRITTEN?
	JRST FGC7
	HRRZ T1,P1
	MOVX T2,CORMB
	TDNE T2,CST0(P1)	;PAGE MODIFIED?
	SKIPG SWRSAF		;REASSIGN SWAP ADDRESSES?
	JRST [	CALL SWPOUT	;NO, SINGLE PAGE SWPOUT
		JRST FGC7]
	CALL SWPOML		;YES, YES - BUILD SWAP LIST
FGC7:	JRST FGC3
;MULTIPLE-PAGE SWAPOUT ROUTINES.  PROCEDURE:
; 1. CALL SWPOMI TO INIT LIST
; 2. CALL SWPOML FOR EACH PAGE TO BE SWAPPED
; 3. CALL SWPOMG TO BEGIN IO FOR ALL PAGES

;INIT SWAPOUT LIST
;	CALL SWPOMI
; RETURN +1: ALWAYS

SWPOMI:	SETZM SWPRC0		;INIT COUNT
	MOVEI 1,SWPLST		;INIT END PTR
	MOVEM 1,SWPLSI
	SETZM SWPLST		;INIT LIST PTR
	RET

;ADD PAGE TO SWAPOUT LIST IF POSSIBLE.  IF PAGE WOULD NOT BE SWAPPED
;TO DRUM THEN CALL REGULAR SWAPOUT.  OTHERWISE, DEASSIGN
;EXISTING DRUM ADDRESS AND PUT PAGE ON LIST.

SWPOML:
	TMNN CSTPST,(T1) ;PAGE AVAILABLE?
	SKIPN 2,CST2(1)		;PTR BACKUP EXISTS?
	JRST SWPOM1		;NO, EXCEPTION CASE.
	HLRZ 3,2		;CHECK IF IN SPT
	JUMPN 3,[CAIGE 3,NOFN	;PAGE LIVES IN FILE XB?
		JRST SWPOM1	;YES, EXCEPTION CASE.
		JRST SWPOM2]	;NO, PAGE LIVES IN FORK PAGE TABLE
	MOVE T3,T1		;SAVE STORAGE ADDRESS
	MOVEI T1,0(T2)		;SPT INDEX
	CALL GETSHR		;GET SHARE COUNT
	EXCH T1,T3		;RESTORE REGS
	JUMPE 3,SWPOM1		;IF SHARE COUNT 0, THEN EXCEPTION CASE
SWPOM2:	MOVE 2,CST1(1)		;CHECK EXISTING BACKUP ADDRESS
	TLNN 2,(DSKAB)		;HAS DRUM ADDRESS NOW?
	TLNN 2,(DRMAB)
	JRST SWPOM1		;NO, EXCEPTION CASE
	CALL GDSTX		;GET DST INDEX FOR DRUM ADDRESS
	MOVE 3,(2)		;GET NEXT LEVEL BACKUP ADDRESS
	MOVX 4,CORMB
	TLZE 3,(BWRBIT)		;MODIFIED ON DRUM?
	IORM 4,CST0(1)		;YES, NOTE
	SETOM (2)		;FLUSH DST SLOT
	EXCH 3,CST1(1)		;REPLACE BACKUP ADDRESS FOR PAGE
	PUSH P,1
	MOVE 1,3		;GET DRUM ADDRESS
	CALL DASDRM		;DEASSIGN IT
	POP P,1
	MOVEI 2,CST3(1)		;PUT PAGE ON SWAPOUT LIST
	HLLZS 0(2)		;MARK END OF LIST WITH 0
	HRRM 2,@SWPLSI		;APPEND TO END OF LIST
	MOVEM 2,SWPLSI		;UPDATE END PTR
	AOS SWPRC0		;COUNT PAGES ON LIST
	MOVX T2,DWRBIT
	IORM T2,CST3(T1)	;NOTE WRITE IN PROGRESS
	RET

;EXCEPTION CASE - PAGE CANNOT BE WRITTEN ON DRUM OR HAS NO DRUM ADDRESS

SWPOM1:	CALLRET SWPOUT		;USE SINGLE-PAGE SWPOUT
;ASSIGN NEW DRUM STORAGE AND INITIATE I/O FOR ALL PAGES ON SWAPOUT LIST.

SWPOMG:	SKIPG SWPRC0		;ANY PAGES ON LIST?
	RET			;NO
	PUSH P,P1
	PUSH P,P2
SWPOG2:	HRRZ P1,SWPLST		;GET LIST OF PAGES TO DO
	MOVE 1,SWPRC0		;GET COUNT OF PAGES LEFT ON LIST
	CALL DRMAM		;TRY TO GET THAT MANY SEQUENTIAL PAGES
	MOVEM 2,SWPDAD		;REMEMBER FIRST ADDRESS OF GROUP
	CAMLE 1,SWPRC0		;GOT MORE THAN NEEDED?
	MOVE 1,SWPRC0		;YES
	MOVEM 1,P2		;REMEMBER COUNT OF CURRENT GROUP
	MOVN 1,1
	ADDM 1,SWPRC0		;REDUCE NUMBER LEFT BY THIS GROUP SIZE
SWPOG1:	JUMPE P1,SWPOG3		;JUMP IF END OF LIST
	MOVE 1,SWPDAD		;HAVE ANOTHER PAGE TO DO, GET NEXT DRUM
	CALL DRMASA		; ADDRESS IN SEQUENCE AND ASSIGN IT
	 BUG(ASGSW2)
	MOVEI 1,0(P1)		;GET PAGE NUMBER
	SUBI 1,CST3
	MOVE 2,SWPDAD		;GET NEW DRUM ADDRESS
	MOVE 4,CST1(1)		;GET PRESENT BACKUP ADR FOR PAGE
	MOVEM 2,CST1(1)		;SET DRUM ADR AS NEW BACKUP
	CALL GDSTX		;GET DST INDEX FOR DRUM ADDRESS
	MOVX 3,CORMB
	TDNE 3,CST0(1)		;PAGE WAS MODIFIED IN CORE?
	TLO 4,(BWRBIT)		;YES, MEANS MODIFIED RELATIVE TO DISK TOO
	MOVEM 4,(2)		;SAVE DISK ADR OF PAGE
	ANDCAM 3,CST0(1)	;CLEAR MODIFIED BIT IN CORE
	SETO T3,
	STOR T3,CFXRD,(T1)	;SAY NO FORK WAITING FOR PAGE
	MOVEI 3,PSWIP		;GET WRITE-IN-PROGRESS CODE
	STOR 3,CSTAGE,(1)	;SET STATUS OF PAGE
	AOS IOIP		;NOTE 1 MORE WRITE IN PROGRESS
	AOS DRMWR		;NOTE 1 MORE DRUM WRITE
	MOVE 1,SWPDAD		;BUMP DRUM ADDRESS TO NEXT PAGE
	CALL DRMIAD
	MOVEM 1,SWPDAD
	SOJG P2,[HRRZ P1,0(P1)	;DO CDR IF HAVE MORE PAGES IN THIS GROUP
		JRST SWPOG1]	;GO DO NEXT ONE
SWPOG3:	HRRZ 1,0(P1)		;END OF GROUP, GET PTR TO NEXT GROUP
	HLLZS 0(P1)		;TIE OFF LIST
	EXCH 1,SWPLST		;SET NEXT LIST, GET CURRENT LIST
	SUBI 1,CST3		;MAKE PTR RELATIVE
	TXO 1,DWRBIT		;SAY WRITE
	CALL DRMIOM		;DO MULTI-PAGE WRITE
	SKIPLE SWPRC0		;DONE ALL OF GROUP, STILL PAGES ON LIST?
	JRST SWPOG2		;YES, DO ANOTHER GROUP
	POP P,P2
	POP P,P1
	RET
;SWAP OUT PAGE REQUESTED BY PROCESS
; A/ CORE PAGE NUMBER
;	CALL SWPOT0
; RETURN +1, SWAPOUT OF PAGE INITIATED.

SWPKPF==1B0			;LOCAL FLAG: 0 = USE OFRQ, 1 = USE ONRQ

SWPOTK:	SAVEAC <Q1>
	MOVX Q1,SWPKPF		;KEEP PAGE
	JRST SWPOT1

SWPOT0:	SAVEAC <Q1>
	MOVX Q1,0
SWPOT1:	TLNE 1,(NCORTM)		;IN CORE?
	JRST SWPTBD		;NO
	HRRZ 2,1
	CAML 2,MONCOR		;NO, LEGAL PAGE NUMBER?
	CAMLE 2,NHIPG
	JRST [	CALL RESPCK	;PART OF RESMON?
		 JRST .+1	;NO. SWAP IT OUT THEN
		JRST SWPTBD]	;YES. ERROR OF SOME SORT
	CALL AGECHK		;CHECK AND DEASSIGN PAGE
	MOVE 2,CST1(1)
	TLNE 2,(-PLKV)		;CAN SWAP IT OUT?
	JRST SWPTBD		;NO, LOCKED
	MOVSI 2,(DWRBIT)
	TDNE 2,CST3(1)		;BEING WRITTEN?
	JRST SWPTBD		;YES
	CALLRET SWPOU0		;ALL OK, SWAPOUT THE PAGE

;HERE IF ANYTHING WRONG WITH PAGE

SWPTBD:	BUG(ILPAG1)
;INITIATE SWAPOUT OF SINGLE PAGE
; 1/ CORE PAGE NUMBER
;	CALL SWPOUT
; RETURN +1: ALWAYS, IO REQUESTED OR PAGE PUT ON REPLACABLE QUEUE

SWPOUT:	SAVEAC <Q1>
	MOVX Q1,0		;CLEAR FLAGS
SWPOU0:	SKIPN 2,CST2(1)		;GET BACKUP
	JRST BKUPN		;PAGE HAS NO BACKUP, FLUSH IT
	HLRZ 3,2		;CHECK PT OF SOURCE
	JUMPN 3,[CAIGE 3,NOFN	;PAGE LIVES IN FILE XB?
		JRST BKUPC	;YES. GO CHECK FOR DISK OR DRUM
		JRST BKUPS]	;NO, PAGE LIVES IN FORK PT, SEND TO DRUM
	MOVE T3,T1		;SAVE STORAGE ADDRESS
	MOVEI T1,0(T2)		;GET SPTN
	CALL GETSHR		;GET SHARE COUNT
	EXCH T1,T3		;RESTORE REG VALUES
	CAIGE 2,NOFN		;OFN?
	JRST SWPOF1		;YES
	JUMPE 3,BKUPD		;IF SHARE COUNT 0, SWAP TO DISK
BKUPC:	MOVE 2,CST3(1)
	TLNE 2,(DSKSWB)		;SWAP TO DISK REQUESTED BY DDMP?
	JRST BKUPD		;YES
BKUPS:	MOVE 2,CST1(1)		;CORE PAGE NUMBER IN 1, GET BACKUP ADR
	TLNN 2,(DSKAB)		;DISK OR UNASSIGNED?
	TLNN 2,(DRMAB)
	JRST SWPO4		;YES
BKUP0:	MOVE 3,CST0(1)		;HAVE DRUM ADDRESS
	TXNN 3,CORMB		;PAGE WRITTEN INTO?
	JRST BKUPN		;NO, PUT IT ON RPLQ
	CALL GDSTX
SWPO5:	MOVSI 3,(BWRBIT)	;SET BACKUP WRITTEN BIT
	IORM 3,(2)
SWPO2:	CALL CHPERR		;SEE IF PAGE HAS PARITY ERROR
	 RET			;IT DOES. GIVE UP NOW
	MOVX 3,CORMB
	ANDCAM 3,CST0(1)	;CLEAR WRITTEN BIT
	SETO T3,
	STOR T3,CFXRD,(T1)	;SAY NO FORK WAITING FOR PAGE
	MOVEI 3,PSWIP
	STOR 3,CSTAGE,(1)	;SET CODE TO WRITE IN PROGRESS
	AOS IOIP		;NOTE WRITE IN PROGRESS
	HRLI 1,(DWRBIT)		;WRITE REQUEST BIT
	CALL DRMIO		;INITIATE DRUM WRITE
	AOS DRMWR		;COUNT DRUM WRITES FOR STATISTICS
	RET

;OFN - MUST ALWAYS SWAP TO DRUM

SWPOF1:	SKIPG 3			;SHARE COUNT OK?
	 JRST [	MOVE 1,2	;NO. OFN IS UNUSED
		CALLRET CLROFN]	;SO GET RID OF IT
	MOVE 2,CST1(1)		;YES, CHECK BACKUP ADDRESS
	TLNN 2,(DSKAB)		;DISK?
	JRST BKUP0		;NO, DRUM ADR ALREADY ASSIGNED
	SKIPGE DRUMP		;YES, MUST ENSURE SWAP OF XB TO DRUM
	RET			;CAN'T SWAP TO DRUM, LEAVE IN CORE
	JRST SWOFN		;GO ASN DRM ADR, EVEN IF DRM SPC LOW
;HERE IF NEED TO ASSIGN DRUM ADDRESS FOR PAGE GOING TO DRUM

SWPO4:	MOVSI 3,(SWPERR)
	TDNE 3,CST3(1)		;ERROR READING FROM DISK?
	JRST BKUPN		;YES, DON'T WRITE IT
	MOVE 3,DRMFRE
	SKIPN NSWAPF		;SWAPPING ALLOWED?
	CAMGE 3,DRMIN0		;YES. HAVE ROOM ON THE SWAPPING?
	JRST [	TXNN T2,DSKAB	;NO. HAVE A BACK UP DISK ADDRESS?
		JRST SWOFN	;NO. PUT IT ON THE SWAP SPACE ANYWAY
		HLRZ T3,CST2(T1) ;YES. GET HOME FOR THIS PAGE
		SKIPN T3	;DOES IT LIVE IN AN OFN?
		HRRZ T3,CST2(T1) ;NO. GET SPT INDEX THEN
		CAIL T3,NOFN	;IS THIS THE OFN?
		HLRZ T3,SPTH(T3) ;NO. GET IT FROM THE SHARE POINTER THEN
		JUMPE T3,SWOFN	;IF A FORK PT PAGE, PUT IT ON THE SWAP SPACE
		MOVE T3,SPTH(T3) ;GET OFN FLAGS
		TXNE T3,OFNDUD	;SUPPRESSING DISK UPDATE?
		JRST SWOFN	;YES. PUT IT ON SWAP SPACE
		JRST BKUPD]	;NO. PUT IT ON THE DISK THEN
SWOFN:	SKIPE NSWAPF		;SWAPPING ALLOWED?
	RET			;NO, LEAVE PAGE
	PUSH P,1
	CALL DRMASN		;ASSIGN DRUM ADDRESS
	 JRST [	BUG(DRMFUL)
		POP P,T1	;NO ROOM, LEAVE PAGE
		RET]
	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,(2)		;PREVIOUS BACKUP ADDRESS TO DST
SWPP1:	MOVE 3,CST0(1)
	TXNE 3,CORMB		;PAGE WRITTEN WHILE IN CORE?
	JRST SWPO5		;YES, SET BACKUP WRITTEN BIT ALSO
	JRST SWPO2		;NO
;SWAP PAGE TO DISK

BKUPD:
BKUPD1:	MOVE 2,CST1(1)		;GET BACKUP ADDRESS
	TLNN 2,(DSKAB+DRMAB)	;NONE?
	JRST BKUP7		;YES
	TLNE 2,(DSKAB)		;DISK?
	JRST BKUP3		;YES
	CALL GDSTX		;DRUM
	MOVE 3,(2)		;GET NEXT LEVEL BACKUP ADDRESS
	MOVX 4,CORMB
	TLZE 3,(BWRBIT)		;WRITTEN SINCE BACKUP?
	IORM 4,CST0(1)		;YES, SET CORE WRITTEN BIT
	SETOM (2)		;RELEASE DST SLOT
	EXCH 3,CST1(1)
	PUSH P,1
	MOVE 1,3
	CALL DASDRM		;DEASSIGN DRUM ADDRESS
	POP P,1
	JRST BKUPD1

BKUP7:	BUG(BKUPDF)

BKUP3:	MOVX T3,SWPERR
	TDNE T3,CST3(T1)	;ERROR IN PAGE?
	JRST BKUPN		;YES, DON'T WRITE IT
	CALL CHPERR		;CHECK FOR PARITY ERROR IN PAGE
	 RET			;IS. LEAVE IT ALONE THEN
	MOVX T3,CORMB
	TDNN T3,CST0(T1)	;PAGE MODIFIED?
	JRST [	TXNN Q1,SWPKPF	;NO, WHICH END OF RPLQ?
		JRST BKUPF	;TOP
		JRST BKUPN]	;END
	ANDCAM 3,CST0(1)
	HRLI 1,(DWRBIT)		;REQUEST WRITE
	AOS DSKWR		;COUNT IT FOR STATISTICS
	AOS IOIP		;NOTE WRITE IN PROGRESS
	MOVSI 3,(DSKNB)
	TDNE 3,CST1(1)		;IS THIS A NEW ADDRESS?
	JRST [	ANDCAM 3,CST1(1) ;YES. TURN IT OFF
		HLRZ 3,CST2(1)	;GET OFN
		SKIPN 3		;THIS IT?
		HRRZ 3,CST2(1)	;NO. THIS IS IT THEN
		CAIL 3,NOFN	;IS THIS AN OFN?
		HLRZ T3,SPTH(3)	;NO. GET THE OFN
		SETONE OFNWRB,SPTH(3) ;SET MODIFIED BIT IN THE OFN
		JRST .+1]	;AND PROCEED
	SETO T3,
	STOR T3,CFXRD,(T1)	;SAY NO FORK WAITING FOR PAGE
	MOVEI 3,PSWIP		;INDICATE WRITE IN PROGRESS
	STOR 3,CSTAGE,(1)
	LOAD T3,SWPKPF,Q1	;SAVE KEEP FLAG FOR SWPDON
	STOR T3,DSKSWB,CST3(T1)
	CALLRET DSKIO

;HERE IF PAGE CAN BE PUT DIRECTLY ON RPLQ.

BKUPF:	CALLRET OFRQ		;TOP

BKUPN:	CALLRET ONRQ		;END

;LOCAL ROUTINE OF SWPOUT TO SEE IF MEM PAGE HAS A PARITY ERROR
;IN IT.
;	T1/ PAGE NUMBER
;RETURNS: +1 YES. DON'T SWAP IT
;	  +2 NO. OK TO SWAP IT

CHPERR:	LOAD T3,CSTPST,(T1)	;GET STATE OF PAGE
	CAIN T3,PSTERR		;PAGE HAS ERROR?
	RET			;YES. CAN'T SWAP IT THEN
	RETSKP			;NO. ALLOW SWAP
;WHAT YOU'LL FIND ON THE TRAPSK STACK FOR VARIOUS FLAVORS OF PAGE FAULT:

;Reference from USER mode, first trap

;TRAPSK   /	? (APPEARS TO BE SOME SORT OF RUN TIME)
;TRAPSK+1 /	PC AT TIME OF TRAP
;TRAPSK+2 /	FLAGS AT TIME OF TRAP


;Reference from USER mode, nested trap

;TRAPSK /	PC AT TIME OF TRAP
;TRAPSK+1 /	FLAGS AT TIME OF TRAP




;Reference from MONITOR mode, first trap

;TRAPSK   /	AC 1
;TRAPSK+1 /	AC 2
;TRAPSK+2 /	AC 3
;TRAPCK+3 /	AC 4
;TRAPSK+4 /	AC 7
;TRAPSK+5 /	AC CX
;TRAPSK+6 /	TRAPSW
;TRAPSK+7 /	? (SAME TIME AS ABOVE)
;TRAPSK+10/	PC AT TIME OF TRAP
;TRAPSK+11/	FLAGS AT TIME OF TRAP




;Reference from MONITOR mode, nested trap

;TRAPSK+N   /	AC 1
;TRAPSK+N+1 /	AC 2
;TRAPSK+N+2 /	AC 3
;TRAPSK+N+3 /	AC 4
;TRAPSK+N+4 /	AC 7
;TRAPSK+N+5 /	AC CX
;TRAPSK+N+6 /	TRAPSW
;TRAPSK+N+7 /	PC AT TIME OF TRAP
;TRAPSK+N+10/	FLAGS AT TIME OF TRAP

;"N" DEPENDS ON WHERE THE STACK POINTER WAS WHEN THE PAGE FAULT OCCURS
	SUBTTL Page fault Handler

;PAGER TRAP. Here on page fault. Microcode has stored the following locations
;in the UPT:
;	TRAPS0/ page fail word
;	TRAPFL/ flags at time of trap
;	TRAPPC/ PC at time of trap

PGRTRP::DATAO PAG,SETMON	;SET MON AC BLOCK
	AOSGE INTDF		;MUST BE NOINT
	JRST [	BUG (NSKDT2)
		SETZM INTDF	;FIX THE BAD VALUE
		JRST .+1]	;AND PROCEED

;**;[2850]ADD 2 LINES AT PGRTRP:+5L	DSC	26-OCT-82

	SKIPE INSKED		;[2850]IN SCHEDULER?
	JRST KIPFS		;[2850]YES...HANDLE IN PROPER CONTEXT

	SKIPE EXADF1		;EXTENDED ADDRESS?
	JRST PGRTE1		;YES
	EXCH T1,TRAPFL		;SAVE T1
	MOVEM T1,TRAPS0		;SAVE TRAP REASON
	HLLZ T1,TRAPPC		;GET FLAGS
	HRRZS TRAPPC		;ZERO HIGH PC
	EXCH T1,TRAPFL		;STORE FLAGS

;Check for interrupt in progress

PGRTE1:	CONSZ PI,177B27		;FROM PI ROUTINE?
	JRST PIPTRP		;YES. GO HANDLE IT THEN

;Count nested traps. If this is the top level, save the stack pointer and
;set up P to point to TRAPSK stack.

	AOSE TRAPC		;FIRST TRAP?
	JRST PGRT2		;NO, RECURSIVE
	MOVEM P,TRAPAP		;SAVE AC-P
	MOVE P,TRAPSP		;SETUP TRAP STACK
	AOS UTRPCT		;COUNT TRAPS (BUT NOT RECURSIVE ONES)
	AOS STRPCT		;SYSTEM TOTAL

;If reference is from the monitor, save work AC's and previous page fail
;word

PGRT2:	EXCH A,TRAPFL		;SAVE WORK AC, GET FLAGS
	TXNE A,UMODF		;USER?
	JRST [	EXCH A,TRAPFL	;YES, DON'T NEED TO SAVE ACS
		JRST PGRT3]	;AND PROCEED
	EXCH A,TRAPFL
	ADD P,BHC+4		;SAVE ACS 1-4
	DMOVEM 1,-3(P)
	DMOVEM 3,-1(P)
	PUSH P,7
	PUSH P,CX
	PUSH P,TRAPSW		;SAVE PREVIOUS PAGE FAIL WORD
	;..
	;..

PGRT3:
;**;[2844]ADD 1 LINE AT PGRT3:+1L	DSC	26-OCT-82
IFN SKEDSW,<			;[2844]Save the PC if NOSKED

	HRRZ T1,TRAPPC
	SKIPE NSKED		;A NOSKED PAGE FAULT?
	CALL NBNSB		;YES, REMEMBER PC OF IT
;**;[2844]ADD 1 LINE AT PGRT3:+5L	DSC	26-OCT-82
>				;[2844]END SKEDSW CONDITIONAL

	NOSKED			;NOSKED AND NOINT FOR DURATION OF TRAP

;Save the page fail word in TRAPSW. GETTPD looks at this word. Callers of GETTPD
;sometimes modify TRAPSW to test the effect of a different type of reference.
;If not charging user for page fault time, save
;current time base so trap time can be subtracted out.

	MOVE 1,TRAPS0		;MOVE TRAP STATUS FROM TEMP
	MOVEM 1,TRAPSW		;TO SAFE PLACE
	SKIPE TRAPC
	JRST PGRT5		;NESTED TRAP, DON'T COUNT TIME TWICE
	SKIPE IPTIM		;INCLUDE PAGE TRAP TIME?
	JRST [	CALL GETHRT	;NO, GET CURRENT RUNTIME
		PUSH P,T1	;SAVE IT
		JRST PGRT5]
	CALL FRTOFF		;TURN OFF CLOCK
	PUSH P,T1		;HOLD STACK SLOT

;Push flags and PC onto the stack. If user mode, save them at the top of
;UPDL, too. RFSTS looks at the top of UPDL for flags and PC if process is
;in monitor mode.

PGRT5:	DMOVE 1,TRAPFL		;RETURN
	PUSH P,2		;SAVE TRAP PC
	PUSH P,1		;SAVE FLAGS
	EXCH 1,2
	TLNN 2,(UMODF)		;FROM USER?
	JRST SIMT2		;NO
	DMOVEM 1,UPDL		;YES, LEAVE IT WHERE IT CAN BE FOUND

;If page fail code indicates "hard" failure, go handle separately.

SIMT2:	MOVE FX,FORKX
	MOVE T1,TRAPSW
	TXNE T1,TWHPFF		;'HARD' FAILURE?
	JRST [	LOAD T1,TWCOD,T1 ;YES, GET CODE
		CAIL T1,PECOD0	;MPE GROUP?
		JRST PGMPE	;YES
		CAIGE T1,KLCOD0	;PROBLEM GROUP?
		JRST PFDSPT-TWCOD0(T1) ;YES, DISPATCH TO HANDLER
		JRST .+1]
	CALL PGTACC		;ACCOUNT FOR ONE PAGE TRAP AND CALL XGC

;GETTPD will determine cause of trap and return next address to go to in T1.
;If it returns PGUNTP, the reference should succeed.

TRPRST:	CALL GETTPD		;DETERMINE CAUSE OF TRAP
	CAIN T1,PGUNTP		;ACTION NECESSARY?
	JRST 0(T1)		;NO

;Action is required. Go do it.

	PUSH P,T1		;YES, SAVE DISPATCH ADDRESS
	MOVE T1,TRAPSW
	CALL ADDWSC		;INCLUDE ADDRESS IN WORKING SET
	POP P,T1		;RESTORE ADDRESS TO GO TO (SECTION-RELATIVE)
	JRST 0(T1)		;AND GO THERE
;PAGE FAIL AT PI LEVEL. SEE IF AR/ARX AND IF SO, DO ANALYSIS.
;IN ALL CASES, BUGHLT
;NOTA BENE... THE SAVING OF T1 IN MEMPA DOES NOT INSURE THAT
;THE REGISTER'S INITITAL CONTENTS WILL ALWAYYS BE AVAILABLE IN
;A SUBSEQUENT DUMP. IF MULTIPLE PI LEVELS TRIP THROUGH THIS CODE,
;OR IF A MEMORY PARITY OCCURS FOLLOWS CLOE UPON A PI PAGE FAIL
;FROM A BUG, THEN THE CONTENTS OF MEMPA IS NOT WHAT IS NEEDED.
;IN THE UNLIKELY EVENT THAT THIS HAPPENS, WAIT FOR THE NEXT
;OCCURRENCE OF THE BUG.

PIPTRP:	MOVEM T1,MEMPA		;SAVE AN AC FOR DUMP ANALYSIS
	MOVE T1,UPTPFW		;GET PAGE FAIL WORD
	TXNN T1,TWHPFF		;ONE OF THE "HARD" FAILURES?
	JRST PIPTR1		;NO. BAD CODING THEN
	LOAD T2,TWCOD,T1	;YES. GET REASON
	CAIL T2,PECOD0		;AR OR ARX?
	JSP T2,PFAID		;YES. GO ANALYIZE IT
PIPTR1:	BUG(PITRAP)
;MEMORY DATA PARITY - DETECTED IN AR/ARX
;Code is 36 or 37 (AR or ARX parity error). Handle it in APRSRV, and
;give interrupt to user.

PGMPE:	CALL PGMPE0		;HANDLE IN APRSRV
	 SKIPA			;NOT RECOVERABLE
	JRST PGRTH1		;RETRY. GET NEW PC AND FLAGS FIRST
	MOVEI T1,ILLX03		;PARITY ERROR
	MOVEM T1,LSTERR
	MOVX T1,.ICDAE		;INITIATE PSI ON DATA ERROR CHANNEL
	JRST ILRF		;HANDLE AS ILLEG REFERENCE

;DISPATCH FOR PAGE FAIL CODES
;These codes are associated with "hard" failures as indicated by bit 1
;in the page fail word. Code in bits 2-5 indicates the particular failure

TWCOD0==20			;FIRST 'HARD' PAGE FAIL CODE
KLCOD0==30			;START OF KL PAGING CODES
PECOD0==36			;MPE GROUP
PFDSPT::JRST PGRTH		;UNUSED (20)
	JRST ILRD		;PROPRIETARY (21)
	JRST PGRTH		;REFILL ERROR (22)
	JRST ADRCMP		;ADDRESS COMPARE (23)
	JRST ILIND		;ILLEGAL INDIRECT (24)
	JRST PGRTH		;PAGE TABLE PARITY (25)
	JRST ILWR		;UNUSED (26)
	JRST ILSN		;ILLEGAL SECTION (27)

;Handle certain errors in APRSRV. Resume at the failing instruction.

PGRTH:	MOVE T1,TRAPSW
	JSP T2,PFAID		;HANDLE HARD PAGE FAIL
PGRTH1:	DMOVE T1,TRAPFL		;GET FLAGS AND PC (IN CASE MODIFIED)
	EXCH T1,T2
	DMOVEM T1,-1(P)		;AND MAKE IT THE ONES WE WILL USE
	JRST PGUNTP		;RETRY

;Here on address compare. Previously-defined address break was hit.
;Give interrupt to the user.

ADRCMP:	SKIPE INSKED		;WEED OUT BUGS
	BUG(ABKSKD)
	MOVX T1,PC%AFI		;SET ADDRESS BREAK INHIBIT
	IORM T1,0(P)		; SO FORK CAN CONTINUE AFTER SUSPENSION
	MOVE T2,TRAPPC		;GET ADDR OF FAULTING INSTR
	MOVEM T2,ADRBK1		;SAVE FOR THE EXEC
	MOVX T1,FKPSI0+ADRBK%	;FLAG REQUEST FOR SCHEDULER
	IORM T1,FKINT(FX)	; ..
	MOVE T2,FORKX		;THIS FORK
	CALL PSIR4		;GET IT SEEN
	CHKINT			;MAKE IT HAPPEN
	JRST PGUNTP

   REPEAT 0,<
;BAD NSKED OR INTDF - FIX BEFORE PROCEEDING

PGRT4:	BUG(NSKDT2)
	JRST -2(T1)		;REDO AOS UNTIL IT WORKS
   >				;END OF REPEAT 0

;Bits 0 and 1 are set in an indirect word. If user mode, handle as
;illegal read. If monitor, crash.

ILIND:	MOVE T1,TRAPSW		;FIND TRAP REASON
	JXN T1,TWUSR,ILRD	;DECLARE ILLEGAL READ
	BUG(ILLIND)

UBPGF::	SKIPN SMFLAG		;CHECK FOR KS10
	JRST PGUNTP		;NOT A KS10 IGNORE IT
	MOVE T1,TRAPFL		;FIND TRAP WORD
	TLNE T1,(UMODF)		;CHECK TO SEE IF USER MODE
	JRST ILWR		;YES -- ILLEGAL WRITE ERROR
	BUG(UBANXM,<<UPTPFW,PFW>,<UPTPFO,PC>>)
;RESUME PROCESS AFTER PAGER TRAP

PGUNT0:	MOVX CX,FPD		;ON ERROR
	ANDCAM CX,0(P)		; CLEAR FPD BEFORE PROCEEDING
PGUNTP:	SKIPE TRAPC		;OUTER LEVEL TRAP?
	JRST PGU4		;NO

;Here if returning from top level trap. Handle user runtime.

	SKIPE IPTIM		;INCLUDE PAGE TRAP TIME?
	JRST [	CALL GETHRT	;YES, READ CURRENT TIME
		SUB T1,-2(P)	;COMPUTE DIFFERENCE
		JRST PGU5]
	CALL FRTON		;TURN CLOCK ON, GET TIME OFF
PGU5:	ADDM T1,PTTIM		;ACCUMULATE FORK TIME
	ADDB T1,HSPTTM		;ACCUMULATE SYSTEM TIME
	IDIVI T1,NTMS		;CONVERT UNITS
	MOVEM T1,SPTTIM		;MAINTAIN 1 MS UNITS

;Get flags and PC at time of trap in order to resume the instruction. If
;returning to user, store them in FFL and FPC and go to the user.

PGU4:	POP P,T3		;flags and pc
	POP P,T4
	SKIPN TRAPC		;top level trap?
	POP P,T1		;yes, flush runtime
	TLNN 3,(UMODF)		;TO USER?
	JRST PGU3		;NO, MONITOR
	DMOVEM 3,FFL		;USER, CAN PUT RETURN IN FFL
	SETOM TRAPC
	SOSG NSKED		;DO OKSKED
	XCT RSKED		;ALLOW CHANNEL 7 INTERRUPT IF PENDING
	SETOM INTDF		;FOR USER, MUST BE -1
	JRST GOUSR		;RETURN TO USER

;Trapped from monitor. Restore work AC's. Store flags and PC at time of
;trap in TRAPFL and TRAPPC and go there.

PGU3:	DMOVEM 3,TRAPFL
	POP P,TRAPSW
	POP P,CX		;RESTORE AC'S
	POP P,7
	DMOVE 3,-1(P)
	DMOVE 1,-3(P)
	SUB P,BHC+4		;CLEAN UP THE STACK
	SOSGE TRAPC		;UNDOING TOP LEVEL TRAP?
	MOVE P,TRAPAP		;YES, RESTORE P ALSO
	SOSG NSKED		;DO OKSKED
	XCT RSKED		;ALLOW CHANNEL 7 INTERRUPT IF PENDING
	SOS INTDF
	OKINT
	XJRSTF TRAPFL
;UNTRAP AND DISPATCH TO SPECIFIED ADDRESS
; T1/ MONITOR ADDRESS

PGUNTD:	SKIPE TRAPC		;NESTED TRAP?
	BUG(PGUNDX)		;YES, ILLEGAL
	DMOVE T3,-1(P)		;GET PC AND FLAGS OF TRAP
	EXCH T3,T4		;IN PROPER ORDER
	TXNN T3,UMODF		;FROM USER?
	IFSKP.
	  DMOVEM T3,KIMUFL	;YES, SIMULATE MUUO
	  MOVEM T1,KIMUEF	;WITH DISPATCH ADR AS UUO WORD
	  XMOVEI T1,MENTP	;UNTRAP TO ENTER JSYS CONTEXT
	  MOVX T2,PCU		;INIT FLAGS AT UNTRAP
	  DMOVEM T1,-1(P)
	ELSE.
	  MOVE T2,TRAPAP	;FROM MONITOR, SIMULATE CALL
	  PUSH T2,T4		;PUSH PC
	  MOVEM T1,-1(P)	;SET UNTRAP ADDRESS
	ENDIF.
	JRST PGUNTP

;ENTER JSYS CONTEXT AND DISPATCH

MENTP:	MCENTR			;ENTER JSYS CONTEXT
	CALL @KIMUEF		;CALL ROUTINE
	 JRST MRETN		;RETURN TO USER
	SMRETN
;CHECK FOR XGC DUE - CALLED BY SCHED
;This routine causes XGC to be run by forcing the process to simulate a page
;fault.

XGCCHK::MOVE T2,FKRT
	SUB T2,LSTXGR		;TIME SINCE LAST XGC
	SKIPN FKINT(FX)		;OK TO INTERRUPT NOW?
	CAMGE T2,GCRATE		;GC DUE?
	RET			;NO, NO

;Don't do this if the process can't take an interrupt or is the initial
;stages of a page fault.

	MOVE T1,PFL		;GET PC FLAGS
	CALL PITEST		;OK TO INTERRUPT NOW?
	 RET			;NO
	DMOVE T1,PFL
	TXNN T1,UMODF		;USER MODE?
	JRST [	HRRZ T3,T2	;NO, SEE IF PGRTRP ENTRY OR EXIT
		CAIL T3,PGRTRP
		CAIL T3,GETTPD
		JRST .+1	;NOT CRITICAL SECTION
		RET]		;CRITICAL - DEFER

;Copy flags and PC at last unscheduling to trap locations. Store the PC
;in the page fail word, setting TWUSR if process was in user mode. Set
;the new PC to PGRTRP. The process will resume at PGRTRP as if a page fault
;had occurred. This will cause PGTACC to be called, which will call XGC.

	SKIPN EXADF1		;MODEL A?
	JRST [	HLL T2,T1	;YES, BUILD SINGLE WORD PC WITH FLAGS
		HRRZ T1,T2	;USE PC AS TRAP FAIL WORD
		TXNE T2,UMODF	;USER MODE?
		TXO T1,TWUSR	;YES
		DMOVEM T1,TRAPFL	;STORE PAGE FAULT WORD AND PC
		JRST XGCCHC]	;AND PROCEED
	DMOVEM T1,TRAPFL	;SIMULATE PGR TRAP
	TXNE T1,UMODF
	TXO T2,TWUSR		;USE PC AS PAGE FAIL WORD
	MOVEM T2,TRAPS0
XGCCHC:	LOAD T1,VSECNO,T2	;GET PCS
	MOVE T2,[MSEC1,,PGRTRP] ;MAKE THE PROCESS GO TO PGRTRP
	DMOVEM T1,PFL
	RET
;DETERMINE CAUSE OF TRAP AND GET TRAP INFORMATION.  START FROM
;VIRTUAL ADDRESS IN TRAPSW.
;	CALL GETTPD
; RETURNS +1 ALWAYS,
;	T1/ ADDRESS TO GO TO (EFFECTIVELY A REASON CODE)
;	TRPID/ IDENT OF PAGE CAUSING TRAP
;	TRPPTR/ POINTER BITS AND/OR STORAGE ADDRESS

;This routine effectively simulates the action of the microcode and
;determines the reason for the page fault. It traces page pointers and
;exits when it finds a reason for failure.

GETTPD:	MOVE T2,TRAPSW		;START WITH TRAP ADDRESS
	LOAD T1,TWVADR,T2
	TRNN T1,777760		;POSSIBLY A REG?
	TLNE T1,36		;YES. IS IT SEC 0 OR 1?
	SKIPA			;NO. NOT A REG THEN
	JRST GETTGD		;YES. IS A REG. ALLOW IT

;Not an AC. Convert address in page fail word to PTN,,PN.

	TXNE T2,TWUSR		;USER?
	JRST [	TXO T1,TWUSR	;YES
		CALL FPTAX	;GET I.D. OF PAGE
		JUMPE T1,GETT1G	;NON-EX SECTION. ILLEGAL
		JRST GETTP1]	;GOT IT.
	CALL FPTAX		;GET IDENT OF FIRST POINTER
	JUMPE T1,GETTPX		;IF NO IDENTIFIER, GO TO ILSN

;T1/ PTN,,PN. If page is on a dismounted structure, give illegal read.

GETTP1:	HLRZ T2,T1		;GET PT IDENT
	CALL CHKDMO		;SEE IF THIS IS A DISMOUNTED OFN
	 JRST GETT1F		;IT IS
	MOVEM T2,TRPID		;SAVE IT UNTIL VERIFIED
	LOAD T2,STGADR,SPT(T2)	;GET ADR OF PT
	MOVEM T2,TRPPTR		;SAVE IT

;See if this map is accessible. If not in core, or age is invalid, quit.
;	TRPID/ SPT index for page map (PTN)
;	TRPPTR/ Contents of SPT for page map

	TXNE T2,NCORTM		;IN CORE?
	JRST GETT1A		;NO
	HLL T3,CST0(T2)		;CHECK AGE
	TXNN T3,PSASM		;ASSIGNED?
	JRST GETT1B		;NO
	MOVEM T1,TRPID		;PT OK, SAVE PAGE IDENT
	HRRZS T1
	CALL MOVRCA		;FETCH POINTER
	MOVEM T1,TRPPTR		;SAVE IT

;Map is accessible. If entry for this page is 0, quit.
;If write reference, handle possible illegal reference.
;	TRPID/ PTN,,PN
;	TRPPTR/ Map entry for offset PN

	JUMPE T1,GETT1C		;JUMP IF NULL POINTER
	MOVE T2,TRAPSW		;CHECK ACCESS AGAINST REFERENCE
	TXNE T2,TWWRT		;WRITE REFERENCE?
	JRST [	TXNE T1,PTCPY	;YES, COPY?
		JRST GETT1D	;YES
		TXNN T1,PTWR	;WRITE LEGAL?
		JRST GETT1E	;NO
		TXNN T2,TWUSR	;USER FAULT?
		JRST .+1	;NO, FAULT IS NOT AN ILL WRITE
		LOAD T1,VSECNO,T2 ;GET SECTION NUMBER
		CALL SECIND	;SECTION POINTER + AND OF ACCESS BITS IF IND
		TXNN T1,PTWR	;SECTION POINTER ALLOW WRITE?
		JRST GETT1E	;NO, THATS ILLEGAL AS WELL
		MOVE T1,TRPPTR	;RESTORE T1
		JRST .+1]
	;..
;Look at page pointer. If indirect pointer, follow the chain and get the
;next page table.

	;..
	LOAD T2,PTRCOD,T1	;CHECK POINTER TYPE
	CAIN T2,INDCOD		;INDIRECT?
	JRST [	LOAD T2,SPTX,T1	;YES, CONSTRUCT IDENT OF PAGE POINTED TO
		LOAD T1,IPPGN,T1 ;GET PN
		HRL T1,T2	;CONSTRUCT PTN,,PN
		JRST GETTP1]	;LOOP

;If shared pointer, update TRPID and TRPPTR to reflect shared SPT slot

	CAIN T2,SHRCOD		;SHARED PTR?
	JRST [	LOAD T2,SPTX,T1	;YES, GET IDENT
		MOVEM T2,TRPID	;SAVE IT
		LOAD T1,STGADR,SPT(T2) ;GET ADDRESS
		MOVEM T1,TRPPTR	;SAVE IT
		CALL CHKDMO	;SEE IF DISMOUNTED OFN
		 JRST GETT1F	;IT IS
		JRST .+1]

;Have immediate pointer or contents of SPT slot. Quit if it is not in core or
;age is bad.

	TXNE T1,NCORTM		;IN CORE?
	JRST GETT1A		;NO
	HRRZS T1		;GET ADDRESS ONLY
	LOAD T2,CSTAGE,(T1)	;CHECK AGE
	CAIGE T2,PSASN
	JRST GETT1B		;NOT ASSIGNED

;No reason for page fault. Probably the condition has been cleared. Try the
;reference again.

GETTGD:	MOVEI T1,PGUNTP		;PAGE OK, MAY BE REFERENCED
	RET
;Error returns from GETTPD. Caller will go to the routine returned in T1.

;PAGE OR PAGE TABLE NOT IN CORE

GETT1A:	MOVEI T1,NIC
	RET

;PAGE OR PAGE TABLE AGE .L. 100

GETT1B:	MOVEI T1,TRP0
	RET

;NULL POINTER. PAGE DOESN'T EXIST

GETT1C:	MOVEI T1,NPG
	RET

;WRITE-COPY

GETT1D:	MOVEI T1,WCPY
	RET

;ILLEGAL WRITE

GETT1E:	MOVEI T1,ILWR
	RET

;ATTMEPT TO CREATE PAGE TABLE IN NON-ZERO SECTION

GETTPX:	MOVEI T1,ILSN		;RETURN TO HANDLE ILLEG SECTION
	RET

;ILLEGAL REFERENCE BECAUSE OF DISMOUNTED OFN

GETT1F:	MOVEI T1,PMAPX7		;GET CHARACTERISITIC ERROR
	MOVEM T1,LSTERR		;LET PROCESS KNOW WHY MEM FAILED
	MOVEI T1,ILRD1		;GET DISPATCH FOR CALLER
	RET			;AND DONE

GETT1G:	MOVEI T1,ILWR		;ASSUME ILLEGAL WRITE
	TXNN T2,TWWRT		;WAS IT A WRITE REFERENCE?
	 MOVEI T1,ILRD		;OF COURSE NOT
	RET			;AND DONE
;CHKDMO - ROUTINE TO CHECK IF PAGE FAULT HAS OCCURRED ON A DISMOUNTED OFN
;ACCEPTS:	T2/ SPTN OF PAGE TABLE
;RETURNS:	+1 IF PAGE BELONGS TO A FILE ON A DISMOUNTED STRUCTURE
;		+2 IF PAGE IS OK TO FAULT ON

CHKDMO::SAVEAC <Q1,Q2>		;GET SOME REGS
	HRRZ Q2,T2		;GET SPTN FOR CHECKING
	CAIL Q2,NOFN		;AN OFN?
	JRST [	HLRZ Q2,SPTH(Q2) ;NO. SEE IF PAGE BELONGS TO A FILE
		SKIPN Q2	;DOES IT?
		RETSKP		;NO. OK TO USE IT
		JRST .+1]	;YES. MUST LOOK AT IT
	MOVX Q1,OFNDMO		;GET DISMOUNTED BIT
	TDNE Q1,SPTH(Q2)	;IS THIS A DISMOUNTED OFN?
	RET			;YES. SAY SO
	RETSKP			;NO
;AGE LESS THAN 100 TRAP

TRP0::	HRRZ T2,TRPPTR		;GET CORE ADR
	LOAD T1,CSTAGE,(T2)	;GET STATE CODE
	CAILE T1,TRP0BM		;WITHIN RANGE?
	JRST TRPRST		;NO. START TRAP OVER, PAGE PROBABLY
				; HAS COMPLETED WRITING
	XCT TRP0B(T1)		;DISPATCH PER PAGE STATE CODE

;Transfer according to age.

TRP0B:	JRST TRP0C		;ON RPLQ (PSRPQ)
	JRST BADAGE		;DELETED (PSDEL)
	JRST TRP2R		;READ COMPLETED (PSRDN)
	JRST BADAGE		;NOT USED
	JRST TRP0C		;WRITE IN PROGRESS (PSWIP)
	JRST BADAGE		;NOT USED
	JRST TRP0R		;READ IN PROGRESS (PSRIP)
	JRST TRPRST		;NOW ON SPMQ. RESTART TRAP (PSSPQ)
TRP0BM==.-TRP0B-1		;MAXIMUM LEGAL VALUE

;AGE IS EITHER "ON REPLACEABLE QUEUE" OR "WRITE IN PROGRESS"
;IF PAGE HAS HAD AN ERROR, PLACE IT ON THE SPECIAL MEMORY QUEUE.
;OTHERWISE, UPDATE ITS AGE AND FINISH THE PAGE FAULT

TRP0C:	HRRZ T1,TRPPTR		;GET PHYSICAL PAGE
	LOAD T2,CSTPST,(T1)	;GET SPECIAL PAGE STATE
	CAIE T2,PSTAVL		;STILL AVAILABLE?
	JRST TRPSPM		;NO - ATTEMPT TO PLACE ON SPMQ
	CALL CHKRPQ		;MAKE SURE ENOUGH PAGES
	 JRST TRPRST		;RESCHEDULED, RESTART TRAP

;Here if read completed, on replaceable queue, or write in progress.

TRP2R:	HRRZ T1,TRPPTR		;GET CORE PAGE NUMBER
	LOAD T2,CSTPST,(T1)	;GET SPECIAL PAGE STATE
	CAIE T2,PSTAVL		;STILL AVAILABLE?
	JRST TRPSPM		;NO - ATTEMPT TO PLACE ON SPMQ
	CALL AGESN		;ASSIGN PAGE
	JRST PGUNTP		;UNTRAP AND CONTINUE

;AGE IS "READ IN PROGRESS". WAIT FOR THE READ TO COMPLETE.

TRP0R:	MOVSI T1,0(T2)		;SET PAGE NUMBER OF SCHEDULER TEST
	HRRI T1,SWPRT		;SCHEDULER TEST. RETURNS WHEN PSRIP NOT SET
	MOVE T3,CST1(T2)
	TXNE T3,DSKAB		;USE APPROPRIATE TEST
	HRRI T1,DSKRT		;DISK READ (ACTUALLY SAME AS SWPRT)
	RDISMS			;WAIT FOR PAGE
	NOSKED
	JRST TRPRST		;RECHECK TRAP
TRAPSP:	IOWD NTSK,TRAPSK	;POINTER TO LOCAL STACK

BADAGE:	BUG(ILAGE)

;HERE WHEN PAGE FAULTED ON WANTS TO BE REMOVED FROM AVAILABLE POOL
;Deassign it in the CST and add to replaceable queue. Copy the backup
;address to the primary address. When the faulting
;instruction is reexecuted, a new page will be assigned.

TRPSPM:	LOAD T2,CSTAGE,(T1)	;GET AGE
	CAIN T2,PSWIP		;WRITE IN PROGRESS?
	JRST TRPSP2		;YES - WAIT FOR COMPLETION
TRPSP1:	CALL RPCST		;NO - RPLQ OR READ DONE, REMOVE FROM CST
	PIOFF
	CALL ONSPMQ		;PLACE ON SPMQ
	JRST PGUNTP		;TRY REFERENCE AGAIN

TRPSP2:	CALL SKPNWR		;STILL BEING WRITTEN?
	  JRST TRPRST		;RESCHEDULED - RESTART TRAP
	JRST TRPSP1		;NO - FREE PAGE NOW
;ASSIGN PAGE AND SET AGE

AGESET:	PUSH P,FX
	MOVE FX,FORKX
	CALL AGESN
	POP P,FX
	RET

;AGESN -- assign a valid age to a page, and add it to a process's working set

;Accepts:
;	T1/ pointer to page
;	FX/ fork handle

;	CALL AGESN

;Returns +1: always

AGESN::	SAVET			;TRANSPARENT TO ALL ACS
	HRRZ T2,T1		;CORE PAGE NUMBER
AGES1:	LOAD 1,CSTAGE,(2)	;GET AGE CODE
	CAIL 1,PSASN		;NOW ASSIGNED?
	JRST [	LOAD 1,CSTOFK,(2) ;YES, FIND OUT WHERE
		CAML 2,MONCOR	;NOT SWAPPABLE PAGE? OR
		CAIN 1,0(7)	;THIS PROCESS?
		JRST AGES2	;YES, OK
		CAIL 1,NFKS	;ANY PROCESS?
		JRST ATP1	;NO
		SKIPE PRELRQ	;PRELOAD REQUEST?
		JRST AGES2	;YES, DON'T REASSIGN
		HRRZ T1,T2	;PASS PAGE NUMBER
		CALL SOSWSP	;REDUCE WSP
		JRST ATP1]	;GO ASSIGN TO THIS PROCESS
	CAILE 1,TRP0TM		;WITHIN TABLE RANGE?
	JRST BADAGE		;NO - BOMB
	XCT TRP0T(1)
AGES2:	RET

;Transfer according to age of page

TRP0T:	JRST ATP0		;AVAILABLE AND ON REPLACABLE QUEUE (PSRPQ)
	JRST BADAGE		;READ COMPLETED (PSRDN)
	JRST ATP1R		;READ COMPLETED (PSRDN)
	JRST BADAGE		;NOT USED
	JRST ATP4		;WRITE IN PROGRESS (PSWIP)
	JRST BADAGE		;NOT USED
	JRST ATP2		;READ IN PROGRESS (PSRIP)
	JRST BADAGE		;ON SPECIAL MEMORY QUEUE (PSSPQ)
TRP0TM==.-TRP0T-1		;MAXIMUM LEGAL ENTRY
;Read done. If there was an error, interrupt this fork

ATP1R:	MOVSI 1,(SWPERR)	;CHECK FOR ERROR ON READ
	TDNN 1,CST3(2)
	JRST ATP1		;NO ERROR
	PUSH P,2
;**;[2818] ADD 12 LINES AT ATP1R:+4L	TAM	27-SEP-82
	HLRZ T1,CST2(T2)	;[2818] GET OWNING SPTN
	JUMPN T1,[CAIL T1,NOFN	;[2818] OFN?
		  JRST ATP1R2	;[2818] NO, FORGET IT
		  JRST ATP1R1]	;[2818] YES
	HRRZ T1,CST2(T2)	;[2818] SPTN OF PAGE
	CAIL T1,NOFN		;[2818] OFN?
	HLRZ T1,SPTH(T1)	;[2818] NO, GET OFN
	JUMPE T1,ATP1R2		;[2818] NONE FORGET IT
ATP1R1:	LOAD T2,DIROFN		;[2818] GET OFN OF CURRENT DIRECTORY
	CAMN T1,T2		;[2818] SAME?
;**;[2826]MAKE CHANGES TO EDIT 2818 AT ATP1R:+4L	TAM	1-OCT-82
	JRST [LOAD T1,STRX,(T1)	;[2826] GET STRUCTURE NUMBER
;**;[2829]CHANE 1 2818 LINE AT ATP1R:+4L	TAM	4-OCT-82
	      BUG (SWPDIR,<<T1,STRX>>) ;[2818][2829] REPORT ERROR
	      JRST .+1]		;[2826] AND CONTINUE
ATP1R2:				;[2818]
	MOVEI T1,IOX5		;STORE ERROR CODE
	MOVEM T1,LSTERR
	MOVX 1,.ICDAE		;FILE DATA ERROR PSI CHANNEL
	MOVEI 2,0(7)		;GET FORK NUMBER
	CALL PSIRQ		;INTERRUPT THE FORK
	CHKINT			;GET IT SEEN
	POP P,2
	JRST ATP1

;Read in progress. Wait for completion and recheck age

ATP2:	MOVSI 1,0(2)
	HRRI 1,SWPRT		;READ NOW IN PROGRESS OR COMPLETED
	MOVE T3,CST1(T2)
	TXNE T3,DSKAB		;USE APPROPRIATE TEST
	HRRI T1,DSKRT
	PDISMS			;RESCHEDULE UNTIL AVAILABLE
	JRST AGES1		;CHECK AGE AGAIN

;Write in progress. Clear age so SWPDON won't put page on replaceable
;queue.

ATP4:	PIOFF
	LOAD 1,CSTAGE,(2)	;GET CURRENT STATE OF PAGE
	CAIE 1,PSWIP		;WRITE IN PROGRESS?
	JRST [	PION		;NO, GO LOOK AT STATE AGAIN
		JRST AGES1]
	SETZRO <CSTAGE,CFXRD>,(2) ;INHIBIT COMPLETION ACTION
	PION
	SOS IOIP
	JRST ATP1

;Page is on the replaceable queue. remove it.

ATP0:	SOS NRPLQ		;ONE LESS PAGE ON REPLACABLE
	PUSH P,3
	PIOFF
	MOVE 1,CST3(2)		;UNQUEUE PAGE FROM REPLACABLE
	HRRZ 3,1
	HLLM 1,0(3)
	HLRZ 3,1
	HRRM 1,0(3)
	PION
	POP P,3
	SETZM CST3(2)
	AOS SRPQSC		;SYSTEM COUNT OF "SAVES"
	;..
;Here to add the page to the process's working set.

	;..
ATP1:	AOS 1,FKWSP(7)		;INCREASE OWNERSHIP COUNT
	MOVEI 1,0(1)
	PUSH P,1
	LOAD 1,FKWSS		;GET CURRENT RESERVE
	CAML 1,0(P)		;LESS THAN CURRENT SIZE?
	JRST ATP1A		;NO, OK
	SUB 1,0(P)		;YES, CALCULATE DIFFERENCE
	MOVN 1,1
	CALL UPDSNR		;UPDATE SUMNR
	JN FKWSL,,ATP1A		;MAKE SURE WS IN MEM
	BUG(FRKBAL)
ATP1A:	SUB P,BHC+1		;FLUSH GARBAGE
	MOVE T1,CUTAGE		;SET AGE TO VERY OLD SO THAT PAGE WILL
	CAIGE T1,LGABOT		;WITHIN RANGE?
	ADDI T1,AGEWRP		;NO UNWRAP IT
	STOR 1,CSTAGE,(2)	; BE COLLECTED IF NOT ACTUALLY TOUCHED
	STOR FX,CSTOFK,(2)	;SET OWNERSHIP
	STOR FX,CFXRD,(T2)
	LOAD T1,FKXAGE		;INIT LAST XGC TIME
	STOR T1,XGAGE,(T2)
	MOVX T1,DSKSWB		;CLEAR MISC FLAGS
	ANDCAM T1,CST3(T2)
	JRST AGES2
;ILLEGAL REFERENCE TRAPS

;Illegal write. Set up error code and interrupt channel

ILWR::	MOVEI T1,ILLX02		;SET ERROR CODE
	MOVEM T1,LSTERR
	MOVX T1,.ICIWR		;MW INTERRUPT CHANNEL
	JRST ILRF

;Illegal section. Can be non-existent section or section > 37.

ILSN:	MOVEI T1,ILLX05		;ERROR CODE
	MOVEM T1,LSTERR		;SET THE ERROR CODE
	JRST ILRD1		;GO CAUSE ILLEGAL READ INTERRUPT

;Illegal write. Save error code in LSTERR and set up interrupt channel.

ILRD::	MOVEI T1,ILLX01		;SET ERROR CODE
	MOVEM T1,LSTERR
ILRD1:	MOVX 1,.ICIRD		;MR TRAP CHANNEL

;Common code for illegal reference. LSTERR contains last error, and
;	T1/ channel on which to interrupt

ILRF:	MOVEM T1,UTRSW		;SAVE CHANNEL TEMPORARILY
	DMOVE T1,-1(P)		;GET FLAGS AND PC
	EXCH T1,T2		;IN CORRECT ORDER
	CALL SETPCV		;MAKE SURE PCU AND PCS CORRECT
	MOVE T1,TRAPSW		;SAVE TRAPSW FOR USER
	EXCH T1,UTRSW		;RECOVER CHANNEL NUMBER TOO
	DMOVE 2,-1(P)		;GET FLAGS AND PC
	AOS 2			;INCREMENT TO NEXT INSTR
	TLNE 3,(UMODF)		;USER OR KERNEL
	JRST ILRFU		;USER MODE TRAP

;Error occurred in monitor. See if instruction is followed by an ERJMP or
;ERCAL, or an address to dispatch to was provided. If not, BUGHLT.

	HLLZ 4,0(2)		;GET INSTRUCTION AFTER TRAP
	CAMN 4,[ERJMP]		;WANT JUMP SIMULATION?
	JRST ILRF1		;YES - EASY CASE
	CAME 4,[ERCAL]		;PUSHJ?
	JRST [	SKIPE T4,TRPDSP	;TRAP DISPATCH SET?
		JRST ILRF2	;YES
		MOVE T3,TRAPSW	;NO, CHECK REFERENCE
		JXN T3,TWUSR,ILRFX ;OK IF REF TO USER MODE
		DMOVE T2,-1(P)	;FLAGS AND PC
		EXCH T2,T3	;(IN PROPER ORDER)
		MOVE T1,TRAPSW	;PAGE FAIL WORD
		BUG(ILMNRF,<<T1,PFW>,<T2,FLAGS>,<T3,PC>>)]

;Here for ERCAL. Set up the monitor's stack to simulate a call to the routine.

	MOVE 4,BHC+1		;SIMULATE PUSHJ
	ADDB 4,TRAPAP		;UPDATE PDL PNTR
	TLNN 4,-1		;CHECK OVERFLOW
	BUG (ILRFPD)
	MOVEM 2,0(4)		;SAVE RETURN PC ON STACK
	AOS 0(4)		;ADJUST AFTER ERCAL

;Fix the return PC to go to target of ERJMP or ERCAL.

ILRF1:	MOVE 4,0(2)		;GET ADDRS TO XFER TO
	HRRM 4,-1(P)		;ALTER RETURN ADDRESS (CAN'T CROSS SEC BOUND HERE!)
	JRST PGUNT0		;EXIT TRAP
;User made the illegal reference. Follow the ERJMP or ERCAL if any.

ILRFU:	PUSH P,1		;SAVE INTERUPT CHL CODE
	PUSH P,T2		;NEED A WORK PC
	XSFM T1			;GET PRESENT FLAGS
	XMOVEI T2,ILRFU1	;WHERE TO PROCEED
	TXO T1,PCU		;NEED TO MAKE USER PREVIOUS CONTEXT
	XJRSTF T1		;SET IT
ILRFU1:	POP P,T2		;GET BACK USER PC
	MOVE T1,-1(P)		;GET PC FLAGS
	SOSG NSKED		;DON'T BE NOSKED FOR THIS, BUT BE NOINT
	XCT RSKED		;CHECK IF SCHEDULER NEEDS ATTENTION
	CALL ITRSIM		;CHECK FOR ERJMP/ERCAL (PC IN 2)
	 JRST [	POP P,1		;NONE - POST INTERUPT
		AOS NSKED	;BE NOSKED AGAIN
		JRST ILRFX]
	AOS NSKED		;BE NOSKED AGAIN
	SUB P,BHC+1		;PRUNE PDL
	MOVEM 3,-1(P)		;ALTER RETURN ADDRESS
	JRST PGUNT0		;EXIT TRAP

;HERE IF ILLEG REF FROM MONITOR AND DISPATCH WORD SET

;**;[2887] Delete one line at ILRF2:+0L	PED	13-DEC-82
ILRF2:	STOR T4,EXPCBT,-1(P)	;PUT ADR ON STACK FOR RETURN
	TXNN T4,TRPIRF		;WANTS INTERRUPT TOO?
	JRST PGUNTP		;NO
	CALL PSIRQ0		;YES, DO IT
	CHKINT
	JRST PGUNTP		;DONE

;HERE IF REF TO USER ADR SPACE AND NO ERJMP/ERCAL
;If monitor mode and NOINT, skip over instruction that failed.
;Give an interrupt.
;	T1/ channel

ILRFX:	CALL PSIRQ0		;REQUEST INTERRUPT, THIS FORK
	CHKINT			;GET IT SEEN
	MOVE 2,0(P)		;FLAGS
	TLNN 2,(UMODF)		;USER?
	SKIPG INTDF		;OR INTERRUPTABLE?
	JRST PGUNTP		;YES
	AOS -1(P)		;NO, SKIP OVER INSTRUCTION CAUSING TRAP
	JRST PGUNT0
;Here when map entry is zero. This code creates the page and assigns an
;address of "unassigned".

;PAGE NOT IN EXISTANCE TRAPS

NPG::	MOVE 1,TRAPSW
	HLLZ 2,1		;CHECK FOR SECTION
	TXZ 2,EXFLBT		;ZERO FLAGS JUNK
	JXN T1,TWUSR,NPG1	;ALWAYS HONOR USER REQUEST

;See if the monitor is trying to touch an illegal section.

	JUMPE T2,[HRRZ 1,1	;IF MONITOR SECTION 0
		CAIL 1,PSSPSA
		CAIL 1,PSSPEA
		JRST NPG1	;YES
		JRST MILRF1]	;MONITOR MALFUNCTION
	CAMLE 2,[MAXSEC,,0]	;CHECK FOR ILLEGAL SECTION
	JRST MILRF1		;YES -- ERROR

;Decide whether to create page based on room in the swapping space.

NPG1:	MOVE T1,TRPID		;GET PAGE IDENT
	HLRZ 2,1		;GET PT NUMBER
	CAIGE 2,NOFN		;OFN OR PT?
	IFSKP.
	  MOVE T3,DRMFRE	;PT, SEE IF ENOUGH DRUM SPACE
	  CAML T3,DRMLV0	;ABOVE MINIMUM?
	ANSKP.
	  MOVE T3,TRAPFL	;NO. GET FLAGS OF TRAP
	  TXNE T3,UMODF		;MONITOR PC?
	  JRST NIC6E		;NO, BOMB OUT
	  MOVE T3,INTDF		;YES. SEE IF NOW NOINT
	  JUMPE T3,NIC6E	;NOT. ERROR THEN
	ENDIF.

;Map the page table and create the entry, indicating "unassigned"

	CALL SETSPG		;MAP IT
	HRRZS T1		;CLEAR LEFT HALF FOR INDEXED REFERENCE
	SKIPE CSWPGA(1)		;BE SURE PT SLOT NOW EMPTY
	JRST NPGBAD		;IT'S NOT, PROBABLY SPURIOUS TRAP
	MOVE 2,IMMPTR
	TXO 2,UAAB
	MOVEM 2,CSWPGA(1)	;SETUP NULL POINTER
	CALL RELSPG		;RELEASE MAP

;If reference was from user mode, and the user wants an interrupt for
;creating a page, give it. Then prcoess the page as not in core.

	AOS NPRIVP		;ADJUST PRIVATE PAGE COUNT
	MOVE 1,PSICHM
	MOVE 2,TRAPSW
	JXE T2,TWUSR,NIC	;JUMP IF NOT USER REFERENCE
	TXNN 1,1B<.ICNXP>	;USER MAP AND NON-X PAGE CHANNEL ON?
	JRST NIC		;NO
	MOVEI T1,ILLX04		;SET ERROR CODE
	MOVEM T1,LSTERR
	MOVX 1,.ICNXP		;YES, REQUEST INTERRUPT
	CALL PSIRQ0
	CHKINT
	MOVE 1,TRAPSW
	MOVEM 1,UTRSW
	JRST NIC

;Monitor tried to create page illegally. Go handle that

MILRF1:	JRST ILSN
;SWAPPING SPACE INSUFFICIENT FOR NEW PRIVATE PAGE TO BE CREATED
;PRINT MESSAGE AND WAIT.
;(CODE TO GENERATE INTERRUPT IF CHANNEL ON NOT USED NOW)

NIC6E:	MOVEI T2,IOX12		;SWAPPING SPACE FULL
	MOVEM T2,LSTERR
	;MOVE T1,PSICHM		;SEE IF INTERRUPT ENABLED
	;IFXE. T1,<1B<.ICMSE>>
	  XMOVEI T1,NIC6H	;NO, UNTRAP TO CODE TO DO BLOCK
	  JRST PGUNTD
	;ENDIF.
	MOVX 1,.ICMSE		;MACH SIZE EXCEEDED INT CHANNEL
	JRST ILRF		;GENERATE INT

;HERE IN JSYS CONTEXT TO HANDLE SWAPPING SPACE FULL

;CALL NIC6H

;Returns +1: always

NIC6H:	SAVEAC <T1>
	HRROI T1,[ASCIZ /
[MONITOR: Swapping space exhausted, waiting.../]
	PSOUT
	MOVEI T1,DRMSPC		;SCHED TEST TO WAIT FOR SPACE
	HRL T1,DRMLV0		;REQUIRED LEVEL
	MDISMS
	HRROI T1,[ASCIZ /OK]
/]
	PSOUT
	RET			;TRY AGAIN

;SCHED TEST FOR SWAPPING SPACE AVAILABLE
; T1/ MINIMUM SWAP SPACE LEVEL FOR WAKEUP

DRMSPC:	CAML T1,DRMFRE		;ENOUGH NOW?
	JRST 0(T4)		;NO
	JRST 1(T4)

NPGBAD:	BUG(ILPPT3)
;Here when write reference failed, and process has copy-on-write access.

WCPY::	PUSH P,TRPID		;SAVE ORIGIANL IDENT

;Analyze the reference without "write reference" to see if a read would succeed.
;If not, go handle the reason it failed.

	MOVX T4,TWWRT
	ANDCAM T4,TRAPSW	;CLEAR WRITE REF
	CALL GETTPD		;SEE IF PAGE READABLE
	CAIE T1,PGUNTP		;PAGE READY FOR COPYING?
	JRST [	POP P,0(P)	;CLEAN UP STACK
		JRST 0(T1)]	;AND GO HANDLE OTHER CAUSE

;Read would have succeeded.
;	TRPID/ PTN,,PN for page to be copied
;	TRPPTR/ Map word for the page
;Lock the page in core

	HRRZ T1,TRPPTR		;GET ADDRESS OF SOURCE PAGE
	MOVE T2,CST1(T1)	;GET CST1 ENTRY FOR PAGE
	TLNE 2,(-PLKV)		;LOCKED ALREADY?
	JRST [POP P,T1		;CLEAN UP STACK
	      JRST ILWR]	;ILLEGAL WRITE.
	MOVSI 3,(PLKV)		;NOW LOCK IT IN CORE
	ADDM 3,CST1(1)

;Get original map. Store immediate pointer in user's map, indicating
;"unassigned and copy".

	EXCH T1,0(P)		;SAVE CORE PAGE NUMBER, RESTORE IDENT
	HLRZ 2,1		;PTN
	CAIG 2,NOFN
	BUG(IBCPYW)
	CALL SETSPG		;MAP THE PT
	HRRZ T3,T1		;ALLOW INDEXED REFERENCE IN SECTION 1
	MOVX T2,PTPUB		;SELECT ACCESS BITS
	AND T2,CSWPGA(T3)	;GET ACCESS OF SOURCE PAGE
	IOR T2,IMMPTR		;MAKE PRIVATE PTR
	TXO T2,UAACB		;WITH 'COPY' ADDRESS
	EXCH T2,CSWPGA(T3)	;EXCH IT WITH THE WC POINTER
	LOAD T4,PTRCOD,T2	;CHECK PTR TYPE
	CAIN T4,IMMCOD		;PRIVATE?
	JRST WCPY4		;YES, USER PROBABLY CONFUSED

;Store user's original pointer (copy-on-write to source page) in monitor map
;slot for CPYPGA. The call to SWPINP causes the data at CPYPGA to be copied
;to the page pointed to by the contents of T1 when UAACB is set in the
;pointer. T1 contains (PTN,,PN) for the user's original page.

	MOVEM 2,PSBM0+CPYPG	;PUT THE ORIG POINTER IN MON MAP
	CALL RELSPG
	AOS NPRIVP		;INCREASE PRIVATE PAGE COUNT
	SKIP CPYPGA		;REF SOURCE PAGE TO ENSURE ACCESS
	CALL SWPINP		;THIS WILL COPY FROM CPYPG TO A NEW PAGE
	;..
;Determine whether source was fork or file. Remove map entry from monitor
;map.

	;..
	POP P,1			;GET ORIGINAL CORE PAGE
	MOVSI 3,(-PLKV)
	ADDM 3,CST1(1)		;UNLOCK THE SOURCE PAGE
	MOVEI 1,PSBM0-PSBPGA+CPYPG
	HRL 1,FKPGS(7)
	CALL MRPT		;GET IDENT OF SHARE PAGE BEING RELEASED
	 SETZ 1,		;INDIRECT TO FORK (SKIP RETURN MEANS FILE)
	PUSH P,1		;SAVE INDICATOR OF TYPE OF PAGE
	MOVEI 1,PSBM0-PSBPGA+CPYPG
	HRL 1,FKPGS(7)
	SETZM T3		;NO FLAGS
	CALL RELMPG		;RELEASE THE ORIG PAGE FROM MON MAP
	CALL RELCPT		;CLEANUP FROM RELMPG
	OKSKED

;If original source was a file, decrement JFN map count.

	POP P,1
	JUMPE 1,WCPY3		;IGNORE INDIRECT TO FORK PTR
	CALL JFNDCR		;DECREMENT MAP COUNT FOR JFN
WCPY3:	NOSKED
	JRST NIC		;UPDATE STATS AND CONTINUE

;User had private pointer. No need to make another one. Allow write
;access.

WCPY4:	TLZ T2,(PTCPY)		;MAKE IT LOOK LIKE WE COPIED IT
	TLO T2,(PTWR)
	MOVEM T2,CSWPGA(T3)
	CALL RELSPG
	POP P,1
	MOVSI 3,(-PLKV)
	ADDM 3,CST1(1)		;UNLOCK THE SOURCE PAGE
	JRST NIC
;NOT IN CORE TRAP

NIC::
NIC2:	CALL GETTPD		;UPDATE TRAP INFO
	CAIE T1,NIC		;NOT IN CORE?
	JRST 0(T1)		;NO, HANDLE OTHER CAUSE

;Page or page table is not in core. If unassigned disk address, go assign it
;and come back here. Otherwise, swap it in.

	MOVE T1,TRPID		;GET IDENT
	MOVE T2,TRPPTR		;GET ADDRESS
	TLNE 2,(DSKAB+DRMAB)	;UNASSIGNED ADR?
	IFSKP.
	  HLRZ 2,1		;YES. GET PT
	  IFE. T2		;IF FROM SPT...
	    CAMN 1,BTBBAS	;IS THIS THE BIT TABLE?
	    JRST ILSN		;YES, ILLEGAL
	    HLRZ 2,SPTH(1)	;NO. GET PT
	  ENDIF.
	  CAIE 2,0		;OFN OR PT?
	  CAIL 2,NOFN
	ANSKP.

;Unassigned file page. Create it if possible, setting DSKNB in the map entry

	  CALL NIC6A		;OFN, ASSIGN DISK ADR
	   JRST 0(T4)		;COULDN'T
	  JRST NIC2		;OK, REANALYZE
	ENDIF.

;Make sure there are enough core pages left, and swap the data in.

	CALL CHKRPQ		;CHECK FOR ENOUGH PAGES FREE
	 JRST NIC2		;WASN'T, HAD TO RESKED
	CALL SWPINW		;SWAP IN THE PAGE
	JRST NIC2
;HERE IF PAGE HAS UNASSIGNED ADDRESS

;Accepts:
;	T1/ IDENT OF PAGE (either (0,,SPTN) or (PTN,,PN)

;	CALL NIC6A

;Returns +1: page cannot be created
;		T4/ Return address that caller JRST's to
;		T1/ Interrupt channel if T4 contains ILRF
;	 +2: Page on disk has been assigned

;This is the normal mechanism for creating a file page. Page fault
;occurs for "not in core" condition

NIC6A:	SAVEAC <Q2>
	STKVAR <N6ID,N6OF>
	MOVEM T1,N6ID		;SAVE ORIGINAL IDENT

;Original request may have been read or write. If read, see if write would
;be allowed. Simulate write request. If GETTPD returns ILWR or WCPY, write
;would have failed.

	MOVX 1,TWWRT		;GET WRITE BIT
	TDNE 1,TRAPSW		;ORIGINAL REQUEST WAS WRITE?
	JRST NIC62		;YES, ACCESS ALREADY CHECKED
	IORM 1,TRAPSW		;MUST SEE IF WRITE ACCESS POSSIBLE
	CALL GETTPD		;RECOMPUTE AS IF WRITE ACCESS
	MOVX 2,TWWRT		;GET WRITE BIT AGAIN
	ANDCAM 2,TRAPSW		;RESTORE
	CAIE T1,ILWR		;WRITE PROBLEM?
	CAIN T1,WCPY
	IFNSK.

;Here if illegal to write (not copy-on-write). If we have PTN,,PN, then a
;temporary pointer has been stored in the page table. Clear it, because
;this user cannot create the page.

	  MOVE T1,N6ID		;GET ID
	  TLNN T1,-1		;AN OFN TO CLEAR?
	  JRST N6ILRD		;NO
	  HLRZ Q2,T1		;GET THE OFN
	  CALL SETSP6		;MAP THE OFN
	  HRRZS T1		;ALLOW INDEXED REFERENCE IN SECTION 1
	  SETZM CSWPGA(T1) 	;CLEAR MAP SLOT IN THE OFN
	  CALL RELSPG		;CLEAR MAPPING
	  JRST N6ILRD		;AND GIVE ERROR
	ENDIF.

;Here if legal to create page. Lock the page table into core.

NIC62:	HLRZ 2,N6ID		;GET PTN
	IFN. T2			;IF THERE IS ONE...
	  LOAD 1,STGADR,SPT(2)	;GET CORE ADR
	  MOVX 2,PLKV		;LOCK IT IN CORE IN CASE RESKEDS BELOW
	  ADDM 2,CST1(1)
	ENDIF.
	;..
;See if there is room on the disk.

	;..
	HLRZ 1,N6ID		;GET OFN OF IDENT
	MOVE 2,N6ID		;GET IDENT
	SKIPN 1			;HAVE ONE?
	HLRZ 1,SPTH(2)		;NO, GET IT FROM SPTH
	MOVEM T1,N6OF
	CALL QCHK		;CHECK DISK, ETC...
	 JRST NIC6F		;CAN'T CREATE PAGE

;If OFN is locked, wait and dismiss the page fault. Someone else may have
;fixed the problem. Otherwise, lock the OFN

	MOVE 1,N6OF		;GET OFN BACK
	MOVX 2,SPTLKB		;LOCK OFN
	TDNN 2,SPTH(1)
	IFSKP.
	  HRLZ 1,1		;ALREADY LOCKED. BLOCK UNTIL UNLOCKED
	  CALL WTOFNL		;OKSKED AND DISMISS
	  NOSKED
	  MOVE T1,N6ID
	  CALL NIC6UC		;UNLOCK PT PAGE IF ANY
	  RETSKP		;RETURN AND TRY AGAIN
	ENDIF.
	TXO 2,OFNWRB		;NOTE OFN CHANGED
	IORM 2,SPTH(1)		;SET LOCK AND OFN MODIFIED
IFN SPTDSW,<			;ONLY IF DEBUGING SPTLKB PROBLEMS
	CALL SPTRAC		;RECORD WHO LOCKED SPTLKB
 >				;END OF IFN SPTDSW

;Assign a page on the disk and update allocation information for the directory.

	MOVE T1,N6ID		;GET IDENT
	TLNN T1,-1		;IN SPT?
	MOVE T1,SPTH(T1)	;YES, GET REAL IDENT
	CALL FNDLDA		;FIND LAST DISK ADDRESS ASSIGNED IN THIS XB
	MOVE T2,N6OF		;GET OFN
	LOAD T2,STRX,(T2)	;PASS STRUCTURE NUMBER TO DSKASN
	CALL DSKASN		;ASSIGN DISK ADDRESS FOR FILE PAGE
	 JRST NIC6D		;RAN OUT
	MOVE T2,N6OF		;GET OFN
	LOAD T2,ALOCX,(T2)	;INDEX TO QUOTA TABLE
	DECR PGLFT,(T2)		;ONE LESS PAGE LEFT

;Save the disk address. If ID was (0,,SPTN), then it points to the entry in
;the SPT for this page. Fill in the address there. IF ID was (PTN,,PN), map
;the OFN and store the page pointer at offset PN.

	TLO 1,(DSKNB)		;INDICATE PAGE NEVER PREVIOUSLY WRITTEN
	MOVE 2,1
	MOVE T1,N6ID		;ORIG PAGE
	TLNE 1,-1		;IN SPT?
      IFSKP.
	STOR 2,STGADR,SPT(1) 	;YES, STORE NEW ADDRESS
      ELSE.
	HLRZ Q2,1
	CALL SETSP6		;MAP XB
	HRRZ T3,T1		;ALLOW INDEXED REFERENCE IN SECTION 1
	STOR 2,STGADR,CSWPGA(T3) ;STORE NEW ADDRESS IN XB
	MOVSI 2,(-PLKV)
	ADDM 2,CST1(Q2)		;UNDO LOCK ABOVE
	CALL RELSPG
      ENDIF.
	CALL NIC6UL		;UNLOCK OFN
	RETSKP			;PAGE NOW ASSIGNED, RETURN
;HERE WHEN NO ROOM CONDITION

;Unlock the OFN

NIC6D:	MOVE T3,N6OF		;GET OFN
	MOVX 2,SPTLKB		;UNDO SPT LOCK
	ANDCAM 2,SPTH(T3)	;...

;If ID was (OFN,,PN), clear page table entry and unlock the core page for the
;OFN

NIC6F:	MOVEM T1,LSTERR		;SAVE ERROR CODE
	MOVE T1,N6ID		;GET ORIGINAL IDENT
	TLNN 1,-1		;OFN?
      IFSKP.
	HLRZ Q2,1		;YES, OFN TO REG 6
	CALL SETSP6		;MAP THE PT
	HRRZS T1		;ALLOW INDEXED REFERENCE IN SECTION 1
	SETZM CSWPGA(1)		;CLEAR POINTER (NO DSK ADDRS YET)
	MOVX 2,-PLKV		;UNDO PT LOCK
	ADDM 2,CST1(Q2)		;...
	CALL RELSPG		;RELEASE SPECIAL PAGE
      ENDIF.

;Set up address for caller to go to. Set up channel for quota exceeded
;interrupt.

	MOVE T2,LSTERR		;SEE WHICH ERROR
	MOVX 1,.ICQTA		;QUOTA EXCEDED CHL
	CAIN T2,IOX11		;QUOTA EXCEEDED?
	JRST N6ILRF		;YES, DO INTERRUPT
	MOVX T1,.ICMSE		;MACH SIZE CHNL
	CAIN T2,IOX35		;ALLOCATION SCREWED UP?
	JRST N6ILRF		;YES, GENERATE ILLEG REF INT
	MOVE T3,BITS(T1)	;BIT FOR MSE CHANNEL
	TDNE T3,PSICHM		;CHANNEL ON?
	JRST N6ILRF		;YES, DO IT
	;..
	;..
   REPEAT 1,<
	JRST N6ILRF>		;TO ILLEG REF
   REPEAT 0,<
;The following is not now used.  It will cause a fork to wait on
;a 'disk full' condition rather than bombing out.
	XMOVEI T1,N6DSKC	;NO, SET TO WAIT FOR DISK
	XMOVEI T4,PGUNTD
	RET

;UNTRAP TO HERE IF DISK FULL AND MSE INTERRUPT NOT ENABLED

N6DSKC:	SAVET
	HRRZ T2,UTRSW		;SHOULD BE STR NUMBER
	HLRZ T3,UTRSW		;CHECK QUANTITY
	CAIE T3,N6DSKC		;CHANGED?
	RET			;YES, RETURN AND TRY AGAIN
	HRROI T1,[ASCIZ /
[Disk full, waiting.../]
	PSOUT
      DO.
	NOSKED
	SETZ T1,		;SAY FREE CHOICE ASSMT
	CALL [	SAVEAC <T2>	;TRY ASSMT (PRESERVE STR NO IN T2)
		CALLRET DSKASN]
	IFSKP.
	  CALL DEDSK		;IT WORKED, GIVE BACK PAGE AGAIN
	  OKSKED
	  HRROI T1,[ASCIZ /OK]
/]
	  PSOUT
	  RET			;RETURN TO TRY REF AGAIN
	ENDIF.
	OKSKED			;STILL FULL
	MOVEI T1,^D5000		;WAIT 5 SECS
	DISMS
	LOOP.			;TRY AGAIN
      OD.
   >				;END OF REPEAT 0

;EXITS FROM NIC6A

N6ILRD:	XMOVEI T4,ILRD		;DISPATCH AFTER RETURN
	RET

N6ILRF:	XMOVEI T4,ILRF
	RET

;UNLOCK PT PAGE IF ANY

NIC6UC:	HLRZ 2,1		;GET PTN
	JUMPE 2,R		;RETURN IMMED IF NONE
	LOAD 2,STGADR,SPT(2)	;GET ADR OF PT
	MOVX 3,-PLKV
	ADDM 3,CST1(2)		;UNLOCK IT
	RET

;UNLOCK OFN AFTER ASSIGNMENT

NIC6UL:	HLRZ 2,1		;GET OFN
	SKIPN 2			;HAVE ONE?
	HLRZ 2,SPTH(1)		;NO, GET IT FROM SPTH
	MOVX 3,SPTLKB
	ANDCAM 3,SPTH(2)	;UNLOCK
	RET
	ENDSV.
;FIND LAST DISK ADDRESS ASSIGNED IN THIS XB SO THAT DSKASN CAN ASSIGN
;THE NEXT PAGE AT AN OPTIMAL LOCATION
; T1/ IDENT

FNDLDA:	SAVEAC <Q2>
	HLRZ Q2,T1		;SETUP OFN
	JN NCORTM,SPT(Q2),FNDLDX ;IF NOT IN CORE, USE XBADDR
	PUSH P,FX		;SAVE REGISTER
	MOVE FX,FORKX		;GET CURRENT FORK
	CALL SETSP6		;MAP IT
	POP P,FX		;RESTORE REGISTER
FNDLD1:	HRRZ T2,T1		;GET PAGE NUMBER
	SKIPN T2,CSWPGA(T2)	;ANYTHING IN THIS SLOT?
	JRST FNDLD2		;NO
	LOAD T3,PTRCOD,T2	;YES, CHECK PTR TYPE
	CAIN T3,IMMCOD		;IMMEDIATE AND DISK ADDRESS?
	TXNN T2,DSKAB
	JRST FNDLD2		;NO, FORGET IT
	LOAD T1,STGADR,T2	;YES, USE THIS ADDRESS
	JRST FNDLD3

FNDLD2:	HRRI T1,-1(T1)		;SCAN BACKWARDS THROUGH XB
	TRNN T1,-PGSIZ		;RAN OFF TOP?
	JRST FNDLD1		;NO, CHECK THIS SLOT
FNDLDX:	HLRZ T1,T1		;YES, REVERT TO XB ADR ITSELF
	LOAD T1,STGADR,SPTH(T1) ;GET XB DISK ADR
FNDLD3:	CALL RELSPG		;RELEASE XB MAPPING
	RET
;ROUTINE TO CHECK ON DISK QUOTA AND DISK AVAILABILITY
;C(T1) := OFN
;
;RETURN +1	DISK FULL / QUOTA EXCEEDED
;RETURN +2	OK

QCHK:	SKIPN USRSPC		;USER SPACE CHECKING?
	RETSKP			;NO
	LOAD T2,ALOCX,(T1)	;GET INDEX INTO QUOTA TABLES
	SKIPN T2		;GOOD THING TO CHECK
	BUG (NULQTA)
	OPSTR <SKIPG>,PGLFT,(T2)
	JRST QCHK2		;OVER QUOTA - CHECK PRIVS
	RETSKP			;OK

QCHK2:	MOVE T2,CAPENB		;SEE IF USER IS WHEEL/OPR
	TXNE T2,SC%WHL!SC%OPR
	RETSKP			;YES - OK TO CREATE PAGE
	MOVEI T1,IOX11		;NO, FAIL. SETUP ERROR CODE
	RET
;ACCOUNT FOR ONE PAGE TRAP

PGTACC:	MOVE 2,JOBNO
	HRRZ 2,JOBNAM(2)	;GET SUBSYSTEM INDEX
	AOS SPFLTS(2)		;ACCOUNT PAGE FAULTS FOR SUBSYSTEM
	MOVE T2,FKRT
	SUB T2,LSTXGR		;TIME SINCE LAST XGC
	SKIPG TRAPC		;OUTER LEVEL?
	CAMGE 2,GCRATE		;TIME FOR ANOTHER XGC?
	JRST NICMG1		;NO
	CALL SETXAG		;SET CUTOFF FOR XGC
	CALL XGC
	LOAD T1,FKCSIZ		;SEE IF WS ESTIMATE SHOULD BE REDUCED
	ADDI T1,4		;CURRENT SIZE PLUS SMALL INCREMENT
	LOAD T2,FKWSS		;CURRENT ESTIMATE
	CAML T1,T2		;SIZE LESS THAN ESTIMATE?
	JRST NICMG1		;NO, NO CHANGE
	SUB T1,T2		;YES, COMPUTE (NEG) DIFFERENCE
	CALL UPDSNR		;REDUCE NR AND SUMNR ACCORDINGLY
NICMG1:	CALL NICCKS		;CHECK FOR ALLOWABLE SIZE
	RET
;ADD VIRTUAL ADDRESS TO WORKING SET ADDRESS CACHE
; T1/ VIRTUAL ADDRESS IN PAGE FAIL WORD FORMAT
;	CALL ADDWSC
; RETURN +1 ALWAYS

ADDWSC:	TXNN T1,TWUSR+VSECNO	;MON SECTION 0?
	TXO T1,<MSEC1>B17	;YES, MAKE EQUIV TO SEC 1
	LDB T2,[POINTR T1,WSCASS] ;GET ASSOC BITS
	TXNE T1,TWUSR		;USER MODE ADR?
	TXO T2,WSCUSR		;YES
	LDB T1,[POINTR T1,WSCIDX] ;GET INDEX BITS
	IMUL T2,[WSCMS1]	;REPLICATE IN ALL FIELDS OF WORD
	IOR T2,[WSCVAM]		;INCLUDE VALID BIT
	MOVE T3,WSCSH(T1)	;GET CACHE WORD
	XOR T3,T2		;COMPARE ALL FIELDS

..X1==<WSCFLD>B<WSCNBF-1>
REPEAT ^D36/WSCNBF,<		;FOR ALL FIELDS OF WORD...
	TXNN T3,..X1		;FIELD ALL 0 (I.E. EQUAL)?
	RET			;YES, ENTRY ALREADY PRESENT. DO NOTHING
  ..X1=..X1_-WSCNBF		;SHIFT TO NEXT FIELD
   >
	AND T3,[WSCVAM]		;ENTRY NOT PRESENT, EXTRACT VALID BITS
	JFFO T3,[ASH T4,-3	;FIND AN UNUSED ENTRY
		DPB T2,WSCBPT(T4) ;STORE NEW ENTRY IN IT
		AOS NWSCE	;COUNT ENTRIES
		RET]		;DONE
	MOVE T3,WSCSH(T1)	;ALL ENTRIES FULL
	LSH T3,WSCNBF		;FLUSH LEFTMOST ENTRY
	DPB T2,[POINTR T3,WSCFLD] ;STORE NEW ENTRY IN RIGHTMOST FIELD
	MOVEM T3,WSCSH(T1)
	RET

;TABLE OF BYTE POINTERS TO ALL FIELDS OF WORD

WSCBPT:
  ..X==<WSCFLD>B<WSCNBF-1>
  REPEAT ^D36/WSCNBF,<
	POINTR WSCSH(T1),..X
	..X==..X_-WSCNBF
   >
;DELETE VIRTUAL ADDRESS FROM WORKING SET ADDRESS CACHE
; T1/ VIRTUAL ADDRESS IN PAGE FAIL WORD FORMAT
;	CALL DELWSC
; RETURN +1 ALWAYS. DOES NOTHING IF ENTRY NOT PRESENT

DELWSC:	TXNN T1,TWUSR+VSECNO	;MON SECTION 0?
	TXO T1,<MSEC1>B17	;YES, MAKE EQUIV TO SEC 1
	LDB T2,[POINTR T1,WSCASS] ;GET ASSOCIATIVE BITS
	TXNE T1,TWUSR		;USER MODE ADR?
	TXO T2,WSCUSR		;YES
	LDB T1,[POINTR T1,WSCIDX] ;GET INDEX BITS
	TXO T2,WSCVAL		;INCLUDE VALID BIT
	MOVE T3,[POINT WSCNBF,WSCSH(T1)]
DELWS1:	ILDB T4,T3
	CAMN T4,T2		;GIVEN ENTRY?
	JRST [	SETZ T4,	;YES, CLEAR IT
		DPB T4,T3
		SOS NWSCE	;COUNT ENTRIES
		RET]
	TXNE T3,74B5		;CHECKED ALL ENTRIES?
	JRST DELWS1		;NO
	RET			;YES, DO NOTHING
;MAP ALL VALID CACHE ENTRIES USING GIVEN FUNCTION
; T1/ INSTRUCTION TO BE EXECUTED FOR EACH VALID ENTRY
;	CALL MAPWSC
; RETURN +1 ALWAYS

;INSTRUCTION GIVEN IN T1 IS EXECUTED FOR EACH VALID CACHE ENTRY WITH
;THE CORRESPONDING VIRTUAL ADDRESS IN T1 IN PAGE FAIL WORD FORMAT

MAPWSC:	STKVAR <MAPWFN,MAPWC1,MAPWBP>
	MOVEM T1,MAPWFN		;SAVE ARG
	SKIPN PSBM0+PSB1	;WS CACHE PAGE EXISTS?
	RET			;NO, DO NOTHING
	MOVSI T2,-WSCNCW	;INIT NO WORDS TO CHECK
	HRRI T2,WSCSH
MAPWS5:	SKIPE 0(T2)		;WORD EMPTY?
	JRST MAPWS3		;NO, GO CHECK IT
MAPWS6:	AOBJN T2,MAPWS5		;LOOP OVER WORDS
	RET			;DONE

;FOUND NON-EMPTY WORD

MAPWS3:	MOVEM T2,MAPWC1		;SAVE WORD COUNT
	HRLI T2,(POINT WSCNBF,0) ;CONSTRUCT BYTE PTR TO FIRST ENTRY IN WORD
	MOVEM T2,MAPWBP
MAPWS4:	ILDB T2,MAPWBP		;SCAN BYTES
	JUMPN T2,MAPWS2		;JUMP IF VALID BYTE
MAPWS7:	MOVE T1,MAPWBP
	TXNE T1,74B5		;PTR AT END OF WORD?
	JRST MAPWS4		;NO, CONTINUE WORD
	MOVE T2,MAPWC1		;RESTORE AOBJN PTR
	JRST MAPWS6		;YES, STEP WORD

;FOUND VALID ENTRY, CONSTRUCT VIRTUAL ADDRESS

MAPWS2:	SETZ T1,
	HRRZ T3,MAPWBP		;COMPUTE INDEX
	SUBI T3,WSCSH
	DPB T3,[POINTR T1,WSCIDX] ;PUT INDEX IN PLACE
	TXZE T2,WSCUSR		;USER MODE ADR?
	TXO T1,TWUSR		;YES
	DPB T2,[POINTR T1,WSCASS] ;PUT ASSOC BITS IN PLACE
	XCT MAPWFN		;DO THE FUNCTION
	JRST MAPWS7		;CONTINUE WORD
;CHECK FOR SUFFICIENT PAGES ON RPLQ

CHKRPQ:	MOVE 2,NSKED
	CAILE 2,1		;NOSKED PROCESS?
	JRST RSKP		;YES, ALLOW PAGE
	JSP T4,TRP0CT		;DO TEST
	 JRST [	MOVEI T1,TRP0CT	;MUST WAIT FOR ADDITIONAL PAGES
		RDISMS
		NOSKED
		RET]		;RETURN NOTING RESKED DONE
	CAMLE T2,NRPMIN		;GETTING LOW?
	RETSKP			;NO
	CHKINT			;YES, POKE SCHED AFTER TRAP COMPLETED
	RETSKP

TRP0CT:	MOVE T2,NRPLQ		;TEST FOR MEM AVAILABLE
	ADD T2,IOIP
	CAILE T2,NFKSPP		;BELOW MIN?
	SKIPN NRPLQ		;OR 0 IMMED AVAIL?
	JRST 0(T4)		;YES, WAIT
	JRST 1(T4)		;WAKE
;CHECK OVERALL SIZE FOR PHYSICAL CORE LIMITS

NICCKS:	SKIPE PAGDIF		;ANY PAGES ADDED OR DELETED RECENTLY?
	CALL ADJSWP		;YES. GO ADJUST NUMBERS THEN
	MOVE T4,FNPMAX		;DETERMINE CURRENT MAX SIZE
	MOVE T3,IRJAV
	CAIL T3,2		;LOAD ON SYSTEM?
	MOVE T4,SNPMAX		;YES, USE SMALLER LIMIT
	SUB T4,BALSHC		;REDUCE BY LOCKED PAGES, ETC.
	LOAD T1,FKWSS		;GET FORK VARIABLES
	LOAD T2,FKCSIZ
	CAML T2,T4		;CURRENT SIZE WITHIN BOUNDS?
	JRST NIC3		;NO, MUST REDUCE
	CAMG T1,T4		;RESERVE TOO LARGE?
	CAMG T1,T2		;RESERVE SUFFICIENT FOR ADD'L PAGE?
	JRST NIC3E		;YES, NO - RESET IT
	RET			;NO, ALL IS WELL

NIC3E:	LOAD T1,FKCSIZ		;RESET NR TO SIZE + 1
	ADDI T1,1
	LOAD T3,FKWSS
	SUB T1,T3
	CALLRET UPDSNR		;REDUCE SUMNR BY DIFFERENCE

;MUST DO XGC TO REDUCE SIZE OF FORK

NIC3:	SKIPLE TRAPC		;RECURSIVE TRAP?
	JRST NIC3E		;YES, DON'T XGC
	STKVAR <NICCAG>
	MOVE T1,CURAGE		;INIT CUTOFF AGE, 5 SEC WINDOW
	SUBI T1,^D5000/GLATCK
NIC3L:	MOVEM T1,NICCAG		;SAVE CUTOFF AGE
	CALL XGC
	LOAD T1,FKCSIZ
	ADD T1,BALSHC
	CAMGE T1,SNPMAX		;SIZE NOW WITHIN LIMITS?
	CAML T1,FNPMAX
	SKIPA
	JRST NIC3E		;YES, RESET NR AND CONTINUE
	MOVE T1,NICCAG
	CAMN T1,CURAGE		;CUTOFF WAS NOW?
	JRST NIC3E		;YES, CAN DO NO MORE
	ADDI T1,^D1000/GLATCK	;STEP IT BY 1 SEC
	CAMLE T1,CURAGE		;LIMIT TO CURRENT
	MOVE T1,CURAGE
	JRST NIC3L		;TRY AGAIN WITH SMALLER WINDOW
;RELEASE WORKING SET JSYS

.RWSET::MCENT
	NOSKED
	MOVE 7,FORKX
	MOVE T1,CURAGE		;SPECIFY 0 WINDOW
	CALL XGC
	HRRZ 1,FKWSP(7)		;SET NEW NR TO MAX(6,SIZE)
	CAIGE 1,6		;SIZE .GE. 6?
	MOVEI 1,6		;NO, USE 6 AS NEW NR
	LOAD 2,FKWSS
	SUBI 1,0(2)
	CALL UPDSNR
	OKSKED
	JRST MRETN

;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
;XGC, WSSWPO - ROUTINES WHICH SCAN FORK WORKING SET.
;XGC - NORMAL WORKING SET MANAGEMENT.  DEASSIGNS PAGES WHICH HAVE NOT BEEN
;	REFERENCED RECENTLY.  TIME OF LAST REFERENCE IS KNOWN FROM AGE
;	FIELD OF CST0, KEPT IN ELAPSED TIME UNITS.  FIXED BASE WINDOW SIZE
;	IS USED, BUT IS INCREASED IN INVERSE PROPORTION TO FRACTION OF
;	RUNTIME RECEIVED BY THIS PROCESS IN ORDER TO APPROXIMATE A
;	PROCESS TIME CLOCK.
;	XGC MAY BE CALLED MORE FREQUENTLY IF NECESSARY TO KEEP FORK SIZE WITHIN
;	LIMITS, SEE NICCKS.  IF CALLED WITH 0 SIZE WINDOW (CUTAGE=CURAGE),
;	XGC WILL DEASSIGN ALL PAGES FROM THE FORK.
;WSSWPO - SWAP OUT THE CURRENT WORKING SET WHEN DOING POSTPURGING.

GCWND:	^D2000/GLATCK		;BASE WINDOW SIZE
GCRATE:	^D2000			;RECIPROCAL OF GC FREQUENCY
GCMINW:	^D1000			;MINIMUM WINDOW FOR XGC

WSWPF==1B0			;LOCAL FLAG - SWAPOUT FUNCTION
XGSCF==1B1			;LOCAL FLAG - SHORT TIME SINCE LAST XGC

XGC:	SKIPG DRMTPG		;SWAPPING INITIALIZED?
	RET			;NO, DO NOTHING
	TRVAR <XCUTAG,XGCVA,<XGCSQ,2>,XGCIPC>
	MOVEM T1,XCUTAG		;SAVE CUTOFF AGE
	DMOVEM Q1,XGCSQ
	SETZ Q1,		;NO FLAGS
	CALL XGC0		;DO THE WORK
	DMOVE Q1,XGCSQ
	CALLRET PGRCLD		;CLEAR HW PT

;COMPUTE NEW CUTOFF AGE

SETXAG:	MOVE T2,FKRT		;COMPUTE RUNTIME SINCE LAST UPDATE
	SUB T2,LSTXGR
	CAMG T2,GCMINW		;ABOVE MINIMUM?
	JRST [	MOVE T1,CURAGE	;NO, USE MAX WINDOW SIZE
		SUBI T1,AGEWRP-200
		JRST SETXG1]
	MOVE T1,FKRT		;UPDATE RUN AND ELAPSED TIMES
	MOVEM T1,LSTXGR
	MOVE T1,TODCLK		;COMPUTE ELPASED TIME SINCE LAST UPDATE
	SUBM T1,LSTXGT
	EXCH T1,LSTXGT
	IDIV T1,T2		;COMPUTE 1 / FRACTION OF TIME USED
	IMUL T1,GCWND		;SCALE WINDOW SIZE BY RATIO
SETXG1:	CAILE T1,AGEWRP-200	;LIMIT
	MOVEI T1,AGEWRP-200
	MOVN T1,T1		;SUBTRACT FROM CURRENT AGE
	ADD T1,CURAGE
	RET
;SWAPOUT ALL PAGES OF PROCESS.  SIMILAR TO XGC, BUT SWAPS OUT
;PAGES STILL IN WORKING SET.
; FX/ FORK INDEX
;	CALL WSSWPO
; RETURN +1 ALWAYS

WSSWPO::TRVAR <XCUTAG,XGCVA,<XGCSQ,2>,XGCIPC>
	DMOVEM Q1,XGCSQ		;SAVE ACS
	MOVX Q1,WSWPF		;SET FLAG FOR FUNCTION
	CALL SETPP1		;SET PROCESS CONTEXT
	CALL SWPOMI		;INIT SWAPOUT LIST
	CALL SETXAG		;COMPUTE CUTOFF AGE
	MOVEM T1,XCUTAG
	CALL XGC0		;DO THE WORK
	CALL SETPSK		;RESTORE SCHED CONTEXT
	MOVSI Q1,-NFKSPP	;SET TO DO SPECIAL FORK PAGES
WSSWP1:	XCT FKSPPT(Q1)		;GET SPTN OF THE PAGE
	CALL WSSFKP		;COLLECT THE PAGE
	AOBJN Q1,WSSWP1
	CALL SWPOMG		;DO ALL QUEUED SWAPS
	DMOVE Q1,XGCSQ		;RESTORE AC
	RET

;COMMON CODE

XGC0:	MOVE T1,CURAGE
	STOR T1,FKXAGE		;SAVE TIME OF XGC
	MOVE T1,[CALL XGCR]
	CALLRET MAPWSC		;MAP WS PAGES
;ROUTINE CALLED FOR EACH PAGE IN WS
; T1/ VA IN PAGE FAIL FORMAT

XGCR:	MOVX T2,MAXIND		;INIT INDIRECT PTR COUNT
	MOVEM T2,XGCIPC
	MOVEM T1,XGCVA		;SAVE ADR
	TXNE T1,TWUSR		;IS IT A USER ADDRESS IN SECTION 0?
	TXNE T1,VSECNO
	JRST XGCR3		;NO
	LOAD Q2,LPGNO,T1	;USER SECTION 0 PAGE - FETCH PTR
	MOVE T1,UPTPGA(Q2)
	JRST XGCR2

XGCR3:	CALL FPTAX		;GET IDENT
	JUMPE T1,XGCRN		;NONX SECTION
XGCR4:	CALL FETPTR		;FETCH PTR
	 JRST XGCRN		;COULDN'T - DELETE ADR FROM WS
XGCR2:	JUMPE T1,XGCRN		;FLUSH IF NO PTR THERE NOW
	MOVEM T1,Q2
	LOAD T1,PTRCOD,Q2	;GET PTR TYPE
	CAIN T1,INDCOD		;INDIRECT?
	JRST [	LOAD T1,IPPGN,Q2 ;YES, GET NEXT LEVEL PAGE NUMBER
		LOAD T2,SPTX,Q2	;AND PTN
		HRL T1,T2	;CONSTRUCT IDENT
		SOSLE XGCIPC	;INDIRECT LOOP?
		JRST XGCR4	;NO, KEEP TRACING
		JRST XGCRN]	;PROBABLY - IGNORE PAGE
	CAIN T1,SHRCOD		;SHARE?
	JRST [	LOAD T1,SPTX,Q2	;YES, GET SPTN
		LOAD Q2,STGADR,SPT(T1) ;GET ADR
		JRST XGCR1]
XGCR1:	TXNE Q2,NCORTM		;IN CORE?
	JRST XGCRN		;NO, DELETE FROM WS
	HRRZ Q2,Q2
	LOAD T1,CSTAGE,(Q2)
	CAIGE T1,PSASN		;ASSIGNED?
	JRST [	CAIE T1,PSRDN	;NO, READ COMPLETED?
		JRST XGCRN	;NO, FLUSH FROM CACHE
		HRRZ T1,Q2
		CALL AGESN	;YES, ASSIGN IT
		JRST XGCRS]	;AND COLLECT IT
	CAMLE T1,CURAGE		;LEGAL AGE, CHECK FOR WRAPAROUND
	SUBI T1,AGEWRP
	LOAD T2,CSTOFK,(Q2)	;GET OWNING FORK IDENT
	CAME T2,FX		;OUR PAGE?
	JRST XGCRF		;NO
	CAMG T1,XCUTAG		;OLDER THAN CUTOFF?
	JRST XGCRS		;YES, COLLECT
	MOVE T1,CURAGE		;NOTE THAT PAGE HAS BEEN SEEN
	STOR T1,XGAGE,(Q2)
	JRST XGCRK		;NO, KEEP
;CHECK PAGE NOT OWNED BY THIS FORK

XGCRF:	LOAD T3,CFXRD,(Q2)	;GET ID OF LAST REFERENCE
	CAMN T3,FX		;SELF?
	JRST XGCRN1		;YES, KEEP PAGE BUT DON'T SWAP
	JXN Q1,WSWPF,XGCRS	;FLUSH IT IF SWAPOUT
	CAMG T1,XCUTAG		;RECENT REFERENCE?
	JRST XGCRN		;NO, REMOVE FROM OUR WS CACHE
	JRST XGCRN1		;YES, KEEP PAGE

;SWAPOUT AND DEASSIGN PAGE

XGCRS:	MOVE T1,XGCVA
	CALL DELWSC		;DELETE FROM WS CACHE
	JXN Q1,WSWPF,XGCRK1	;USE SWAPOUT LIST
	HRRZ T1,Q2
	CALL DECOR		;DEASSIGN
	CALL RSTLRF		;RESET LAST REF
	CALL CHKSHR		;PROBABLE SHARED PAGE?
	 JRST XGCRN1		;YES, LEAVE IT
	MOVE T2,NBPROC
	CAMN T2,NGOJOB		;ALL RUNNABLE FORKS IN MEM?
	JRST [	MOVE T2,MAXNR	;YES, AND PLENTY OF MEM?
		SUB T2,SUMBNR
		CAIL T2,^D100
		JRST XGCRN1	;YES, LEAVE PAGE AROUND
		JRST .+1]	;COLLECT IT
	MOVE T2,CST1(Q2)	;SWAPOUT PAGE UNLESS LOCKED OR BEING WRITTEN
	TXNE T2,-PLKV
	JRST XGCRN1
	MOVX T2,DWRBIT
	TDNE T2,CST3(Q2)
	JRST XGCRN1
	HRRZ T1,Q2
	CALL SWPOUT		;SWAP IT OUT
	AOS SXGCWR
	OKSKD1			;GIVE OTHER PROCESSES A CHANCE
	NOSKD1
	JRST XGCRN1

XGCRN:	MOVE T1,XGCVA		;REMOVE PAGE FROM WS CACHE
	CALL DELWSC
XGCRN1:	RET
;KEEP PAGE.  DO NOTHING IF XGC, QUEUE FOR WRITE IF WSSWPO

XGCRK:	JXE Q1,WSWPF,XGCRN1	;DONE IF XGC
XGCRK1:	HRRZ T1,Q2
	CALL DECOR		;DEASSIGN
	CALL CHKSHR		;PROBABLY SHARED PAGE?
	 JRST XGCRN1		;YES, LEAVE IT FOR GCCOR
	CALL RSTLRF		;RESET LAST REF
	MOVE T2,CST1(Q2)
	TXNE T2,-PLKV		;LOCKED?
	JRST XGCRN1		;YES, DO NOTHING
	MOVX T2,DWRBIT
	TDNE T2,CST3(Q2)	;BEING WRITTEN?
	JRST XGCRN1		;YES, DO NOTHING
	HRRZ T1,Q2
	MOVX T2,CORMB
	TDNE T2,CST0(T1)	;MODIFIED?
	SKIPG SWRSAF		;REASSIGN SWAP ADDRESSES?
	JRST [	CALL SWPOUT	;NO OR NO - DO REGULAR SWAPOUT
		JRST XGCRK2]
	CALL SWPOML		;YES AND YES - BUILD SWAP LIST
XGCRK2:	AOS SGCCWR
	JRST XGCRN1

;CHECK FOR PROBABLY SHARED PAGE

CHKSHR:	HLRZ T1,CST2(Q2)
	CAMN T1,MMSPTN		;SWAPPABLE MON?
	RET			;YES, ASSUME SHARED
	JUMPN T1,RSKP		;IF NOT IN SPT, ASSUME PRIVATE
	LOAD T3,CFXRD,(Q2)	;IN SPT, CHECK LAST REFERENCE
	CAME T3,FX		;THIS FORK?
	RET			;NO, SHARED
	RETSKP			;YES, PRIVATE

;RESET LAST REFERENCE FIELD IF IT CONTAINS THIS FORK

RSTLRF:	LOAD T2,CFXRD,(Q2)
	CAME T2,FX		;LAST REF BY THIS FORK?
	RET			;NO
	MOVX T2,CFXNUL
	STOR T2,CFXRD,(Q2)	;YES, RESET IT
	RET
;FETCH POINTER FROM PT GIVEN IDENT
; T1/ IDENT
;	CALL FETPTR
; RETURN +1: FAILURE, PT NOT IN CORE, ETC.
; RETURN +2: SUCCESS, T1/ WORD FROM PT OR SPT

FETPTR:	HLRZ T2,T1
	JUMPE T2,[LOAD T1,STGADR,SPT(T1) ;SPT - GET ADDRESS
		RET]
	LOAD T2,STGADR,SPT(T2)	;GET PT ADDRESS
	TXNE T2,NCORTM		;IN CORE?
	RET			;NO
	LOAD T3,CSTAGE,(T2)	;YES, CHECK AGE
	CAIGE T3,PSASN		;ASSIGNED?
	RET			;NO
	HRRZ T1,T1		;GET OFFSET INTO PAGE
	CALL MOVRCA		;GET WORD
	RETSKP

;COLLECT SPECIAL FORK PAGE (PSB, ETC.)
; T1/ ID OF PAGE
;	CALL WSSFKP
; RETURN +1 ALWAYS, PAGE DEASSIGNED AND SWAPOUT STARTED IF POSSIBLE

WSSFKP:	LOAD Q2,STGADR,SPT(T1)	;GET ADR
	TXNE Q2,NCORTM		;IN CORE?
	BUG(WSSPNC)
	LOAD T3,CSTAGE,(Q2)
	CAIGE T3,PSASN		;STILL ASSIGNED?
	BUG(WSSPNA)
	MOVX T2,-PLKV
	ADDM T2,CST1(Q2)	;UNLOCK PAGE
	CALLRET XGCRK1		;COLLECT IT
;ROUTINE CALLED BY BIT TABLE LOGIC TO UNLOCK XB FOR BIT TABLE
;	1/ CORE PAGE NUMBER OF XB

UNLBTB::MOVSI T2,(-PLKV)	;GET ONE UNIT OF LOCK COUNT
	ADDM T2,CST1(T1)	;UNLOCK IT
	CALLRET MONCLA		;AND CLEAR PAGER

;LOCAL ROUTINE TO DO A SWAP IN AND LOCK. CALLED WITH SPTN
;IN 1. MUST BE CALLED FROM PROCESS CONTEXT.

SWPIN1::NOSKED			;GO NOSKED
	PUSH P,FX		;SAVE FX FOR CALLER
	MOVE FX,FORKX		;SAY THIS FORK IS THE TARGET
	CALL SWPIN0		;GO DO THE SWAP IN AND LOCK
	POP P,FX		;RESTORE FX FOR CALLER
	OKSKED			;AND ALLOW SCHEDULING AGAIN
	RET			;AND DONE

;SWAP IN PAGE TABLE OR PSB
;CALLED FROM SCHED OR FROM NOSKED PROCESS

SWPIN0::TLNE 1,-1		;SPTN?
	JRST SWP01		;NO
	MOVE 3,SPT(1)		;YES, GET CURRENT ADDRESS
	TLNE 3,(NCORTM)		;OUT OF CORE?
	JRST SWP01		;YES
	HRRZ 2,3
	LOAD 2,CSTAGE,(2)	;GET PAGE STATE CODE
	CAIE T2,PSRIP		;READ IN PROGRESS?
	CALL APSKED		;NO, SIGNAL THAT PAGE AVAILABLE
	CAIE 2,PSRDN		;BEING READ OR COMPLETED?
	CAIN 2,PSRIP
	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)
	HRRZS 3
	ADDM 2,CST1(3)		;LOCK PAGE
	RET
;SWAPIN AND WAIT AND STAY NOSKED

SWPINP:	NOSKED
	CALL SWPINW
	OKSKED
	RET

;WAIT FOR PAGE AND ACCOUNT
; 1/ SCHED TEST
;	CALL PGIWT
; RETURN +1 ALWAYS AFTER SCHED TEST SATISFIED.

PGIWT::	HLRZ 2,1		;GET PAGE NUMBER
	LOAD 2,CSTAGE,(2)	;GET PAGE STATE CODE
	CAIE 2,PSRIP		;READ IN PROGRESS?
	RET			;NO, NO NEED TO WAIT
	RDISMS
	NOSKED
	RET

;SPECIAL ROUTINE TO SWAP IN AN SPTN AND LEAVE IT UNLOCKED.

SWPIN4::NOSKED			;MUST BE NOSKED
	CALL SWPIN0		;SWAP IN PAGE AND WAIT
	MOVX T2,-PLKV
	ADDM T2,CST1(T3)	;UNLOCK THE PAGE
	OKSKED
	RET			;DONE
;SWAP IN AND WAIT FOR COMPLETION
;SWPINW - SWAP INTO PAGE FROM RPLQ
;SWPINQ - SWAP INTO PAGE FROM SPMQ, PAGE # IN 3

;ACCEPTS:
;	T1/ PTN,,PN OR 0,,PTN

;	CALL SWPINW
;		OR
;	CALL SWPINQ

;RETURNS +1: ALWAYS,
;	T1/ CORE PAGE NUMBER

SWPINW:	SETO 3,
SWPINQ:	PUSH P,FX
	MOVE FX,FORKX
	AOS USWPCT		;COUNT SWAPS
	TLNE 1,-1		;PT?
	JRST SWPIW2		;YES
	CALL SWPIQ1		;SWAPIN AND WAIT FOR COMPLETION
SWPIW1:	CALL PGIWT
	HLRZ 1,1		;RESTORE PAGE NO TO R.H.
	POP P,FX
	RET

SWPIW2:	PUSH P,3		;SAVE PAGE #
	PUSH P,1		;SAVE ORIG REQUEST
	HLRZ 1,1		;GET PT
	MOVE 3,SPT(1)
	TLNE 3,(NCORTM)		;CORE?
	JRST SWPIW3		;NO
	MOVEI 1,0(3)
	CALL AGECKN		;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
	MOVE 3,-1(P)		;GET PAGE #
	CALL SWPIQ1		;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
	POP P,3			;RESTORE PHY PAGE #
	JRST SWPIW1

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

;SWPIN - SWAP INTO PAGE FROM RPLQ
;SWPIQ1 - SWAP INTO PAGE FROM SPMQ, PAGE # IN 3

SWPIQ1:	JUMPL 3,SWPIN		;IF .LT. 0, THEN CHOSE FROM RPLQ
	PUSH P,1
	PUSH P,2
	PUSH P,3
	MOVE 1,3
	CALL OFFSPQ		;REMOVE FROM SPMQ
	POP P,3
	POP P,2
	POP P,1
	CALLRET SWPIQ2		;START THE SWAP

SWPIQ2:	PUSH P,5
	PUSH P,6
	JRST SWPIQ3		;REMOVE PAGE AND SWAP

SWPIN:	MOVE 3,NRPLQ		;NUMBER OF REPLACABLE PAGES
	JUMPE 3,SWPQT		;GO WAIT IF NONE
	PUSH P,5
	PUSH P,6
	TLNE T1,-1		;FROM SPT?
	JRST SWPIC1		;NO, USE SRPLQ
	MOVE T3,SPT(T1)		;YES, CHECK ADDRESS
	TXNE T3,DSKAB		;FROM DISK?
	SKIPA T3,[DRPLQ]	;YES, USE DRPLQ
SWPIC1:	MOVEI T3,SRPLQ		;USE SRPLQ
	HRRZ T4,0(T3)		;GET PAGE FROM HEAD OF SELECTED RPLQ
	CAMN T3,T4		;EMPTY?
	XORI T3,SRPLQ^!DRPLQ	;YES, USE ALTERNATE RPLQ
	HRRZ T3,0(T3)		;NOW REALLY GET THE PAGE
	SUBI 3,CST3
	SOS NRPLQ
	PIOFF
	MOVE 4,CST3(3)
	HRRZ 6,4
	HLLM 4,0(6)
	HLRZ 6,4
	HRRM 4,0(6)
	PION
SWPIQ3:	SETZRO CSTAGE,(3)		;CLEAR AGE CODE
	SETZRO CORMB,CST0(3)	;CLEAR PUR, MODIFIED BIT
	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,(NCORTM)
	BUG(SPTPIC)
	STOR 3,STGADR,SPT(1)	;STORE NEW (CORE) ADDRESS
SWPI4:	ANDX 4,STGADM		;EXTRACT ADDRESS
	MOVEM 4,CST1(3)		;STORE BACKUP ADDRESS
	MOVEM 1,CST2(3)		;STORE LOCATION OF OWNING PT
	TLNE 4,(DSKAB+DRMAB)	;BACKUP ADDRESS ASSIGNED?
	JRST SWPI5		;YES, GO READ IN PAGE
	MOVEI 1,0(3)
	CALL SETSP0		;MAP PAGE INTO CSWPG
	MOVX T1,PSASM		;SET LEGAL AGE FOR LOCAL REF
	IORM T1,CST0(T3)
	SETZM CSWPGA
	MOVE 1,[CSWPGA,,CSWPGA+1]
	TXNE 4,UAACB-UAAB	;'COPY-REQUEST' PTR?
	MOVE 1,[XWD CPYPGA,CSWPGA] ;YES, COPY FROM CPYPG
	BLT 1,CSWPGA+777
	CALL RELSPG
	MOVX 1,PSRDN		;SET TO READ COMPLETED
	STOR 1,CSTAGE,(3)	; ...
	MOVX 1,CORMB		;AND SET MODIFIED BIT
	IORM 1,CST0(3)		; ...
	STOR FX,CFXRD,(3)	;NOTE FORK INDEX
	MOVSI 1,0(3)		;RETURN PAGE NUMBER
	HRRI 1,SWPRT		;RETURN APPROPRIATE SCHED TEST
SWPIX:	POP P,6
	POP P,5
	RET
SWPI3:	HLRZ 6,1		;GET OWNING PT OFN
	CALL SETSP6		;MAP PT
	MOVSI 4,(PLKV)
	ADDM 4,CST1(6)		;INCREMENT LOCK COUNT
	HRRZ 6,1
	MOVE 4,CSWPGA(6)
	TLNN 4,(NCORTM)
	BUG(PTAIC)
	STOR 3,STGADR,CSWPGA(6)	;STORE NEW (CORE) ADDRESS
	CALL RELSPG
	JRST SWPI4

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

SWPWTT:	SKIPLE NRPLQ
	JRST 1(4)
	AOS CGFLG		;REQUEST CORE
	JRST 0(4)

SWPI5:	MOVEI 1,0(3)
	MOVX 2,PSRIP
	STOR 2,CSTAGE,(1)	;SET STATE TO READ IN PROGRESS
	STOR FX,CFXRD,(1)	;REMEMBER INITIATING FORK
	TLNE 4,(DSKAB)		;DISK?
	JRST SWPIK		;YES
	TLNN 4,(DRMAB)		;DRUM?
	BUG(ILSWPA)
	CALL DRMIO		;YES, INITIATE READ
	AOS DRMRD		;COUNT DRUM READS FOR STATISTICS
	MOVSI 1,0(1)
	HRRI 1,SWPRT		;RETURN APPROPRIATE SCHED TEST
	JRST SWPIX

SWPIK:	TLNE 4,(DSKNB)		;NEWLY ASSIGNED PAGE?
	JRST [	CALL SWPZPG	;YES, ZERO IT
;		MOVSI 2,(DSKNB)
;		ANDCAM 2,CST1(1)
		MOVX 2,PSRDN	;SET CODE TO READ COMPLETED
		STOR 2,CSTAGE,(1)
		JRST SWPIK1]
	CALL DSKIO		;INITIATE DISK READ
	AOS DSKRD		;COUNT DISK READS FOR STATISTICS
SWPIK1:	MOVSI 1,0(1)		;RETURN APPROPRIATE SCHED TEST
	HRRI 1,DSKRT
	JRST SWPIX
DEPGS:	SAVEAC <5,6>		;THIS ENTRY PRESERVES ACS PROPERLY
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
	STOR 5,STGADR,SPT(4)	;SPT, RESTORE BACKUP ADDRESS
	RET

SWPI1:	HLRZ 6,4
	CALL SETSP6		;MAP PT
	MOVSI 2,(-PLKV)
	ADDB 2,CST1(6)		;DECREMENT LOCK COUNT
	HRRZ 6,4
	STOR 5,STGADR,CSWPGA(6)	;STORE BACKUP ADDRESS
	CALL RELSPG		;RELEASE TEMPORARY MAP WORD
	RET

;REMOVE PAGE FROM CST
; 1/ PAGE NUMBER
;	CALL RPCST
; RETURN +1 ALWAYS, POINTER TO PAGE UNDONE

RPCST:	SAVEQ
	MOVE 3,1
	CALL DEPG		;DO THE WORK
	SETZM CST2(1)		;FLUSH BACK PTR
	RET

;DEASSIGN PAGE FROM CURRENT CST USAGE, SIMILAR TO RPCST BUT CAN BE
;CALLED AT INTERRUPT LEVEL.

;MUST BE CALLED PIOFF

;T1/ PHYSICAL PAGE
;	CALL DASPAG
;RETURNS+1(ALWAYS):
;POINTERS BACKED UP TO NEXT LEVEL IN THE STORAGE HIERARCHY
;PRESERVES T1

DASPAG:	MOVE T2,CST2(T1)	;GET OWNING PT
	JUMPE T2,DASPGX		;NONE - NOTHING TO DO
	SETZM CST2(T1)		;DELETE BACK POINTER
	MOVE T3,CST1(T1)	;GET NEXT LEVEL ADDRESS
	TLNE T2,-1		;OWNED BY SPT?
	JRST DASPG1		;NO - MUST CLEAR PT SLOT
	STOR T3,STGADR,SPT(T2)	;YES - JUST BACKUP SPT ADDRESS
DASPGX:	RET
DASPG1:	PUSH P,T1		;BE TRANSPARENT FOR T1
	HLRZ T1,T2		;GET PT PHYSICAL PAGE
	LOAD T1,STGADR,SPT(T1)	; ...
	PUSH P,CST0(T1)		;SAVE CURRENT CST
	SETOM CST0(T1)		;PREVENT AGE FAULT
	PUSH P,T1		;SAVE PHYSICAL ADDRESS
	CALL MAPRCA		;MAP PAGE, RETURNS ADDRESS IN T1
	ADDI T1,(T2)		;GET MAP SLOT
	STOR T3,STGADR,(T1)	;STORE NEXT HIGHER LEVEL ADDRESS
	POP P,T1		;RESTORE PHYSICAL ADDRESS
	POP P,CST0(T1)		;RESTORE CST
	CALL UNMRCA		;RELEASE MAPPING
	MOVSI T2,(-PLKV)	;DECREMENT LOCK COUNT
	ADDM T2,CST1(T1)	; ...
	POP P,T1		;RESTORE ACS
	JRST DASPGX		;DONE
;ROUTINE CALLED FROM PHYSIO TO GET STRUCTURE NUMBER FOR GIVEN
;CORE PAGE NUMBER. IT WILL HANDLE EITHER FILE PAGE OR SWAPPING REQUESTS
;ACCEPTS:	A/ CORE PAGE NUMBER
;RETURNS: +1	B/ STRUCTURE NUMBER

FNDSTR::HLRZ B,CST2(A)		;GET PTN FROM CST
	JUMPN B,HAVPT		;IF HAVE ONE GO ANALYZE IT
	HRRZ B,CST2(A)		;GET SPTN
	CAIGE B,NOFN		;IS THIS AN OFN?
	JRST GOTOFN		;YES. GO CONSIDER IT
	HLRZ B,SPTH(B)		;NO. GET OFN FOR THIS SPT
	JUMPN B,GOTOFN		;IF A FILE PAGE JUMP TO LOOK AT IT
RTZRO:	SETZ B,			;IS NOT A FILE PAGE. ASSUME SWAPPING SPACE
	RET			;DONE

HAVPT:	CAIL B,NOFN		;IS THIS AN OFN?
	JRST RTZRO		;NO
GOTOFN:	LOAD B,STRX,(B)		;YES. GET STRUCTURE NUMBER
	RET			;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,SWPRT		;DONE?
	 JRST 0(3)		;NO, RETURN NOT RUNNABLE
	CALL AGESN		;SET AGE
	LOAD T1,FKJSB
	MOVE 1,SPT(1)		;CHECK JSB
	JSP 4,SWPRT
	 JRST 0(3)
	CALL AGESN
	HLRZ 1,FKPGS(7)		;PT
	MOVE 1,SPT(1)
	JSP 4,SWPRT		;PT READY?
	 JRST 0(3)		;NO
	CALL AGESN
	LOAD T1,FSSPTN		;GET STACK PAGE
	MOVE T1,SPT(T1)		;GET CORE PAGE
	JSP 4,SWPRT		;SEE IF IN YET
	 JRST 0(3)		;NOT
	CALL AGESN		;MAKE THE AGE GOOD
	JRST 1(3)

;SCHEDULER TEST FOR READ COMPLETED

DSKRT::	JFCL			;SAME AS SWPRT
SWPRT::	HRRZ 2,1
	LOAD 2,CSTAGE,(2)	;GET PAGE STATE CODE
	CAIN 2,PSRIP		;STILL READ-IN-PROGRESS?
	JRST 0(4)		;YES
	JRST 1(4)
;SWAP COMPLETION ROUTINE, CALLED FROM DRUM AND DISK INTERRUPT CODE
; 1/ PAGE NUMBER

SWPDON::MOVX 2,SWPERR
	TDNE 2,CST3(1)		;SWAP ERROR IN PAGE?
	JRST SWPER1		;YES, GO DIAGNOSE IT
SWPERX:	MOVSI 2,(DWRBIT)	;WRITE BIT
	TDNE 2,CST3(1)		;WAS WRITE?
	JRST SWPD1		;YES
	CALL [	SAVEAC <FX>	;SIGNAL SKED
		LOAD FX,CFXRD,(T1) ;FORK WHICH IS PRESUMABLY WAITING
		CALLRET APSKED]
	MOVX 2,PSRDN
	STOR 2,CSTAGE,(1)
	RET

SWPD1:	ANDCAM 2,CST3(1)	;CLEAR WRITE BIT
	LOAD 2,CSTAGE,(1)	;GET TRAP CODE
	CAIE 2,PSWIP		;STILL WRITE IN PROGRESS?
	JRST SWPD2		;NO
	SOS IOIP		;YES, NOTE COMPLETION
	LOAD T3,CFXRD,(T1)	;GET WAITING FORK
	CAIGE T3,NFKS		;IS ONE?
	CALL [	SAVEAC <FX>	;YES, POKE SCHED
		MOVE FX,T3
		CALLRET APSKED]
SWPD2:	SKIPN CST2(1)		;PAGE DELETED?
	JRST [	MOVEI 2,CST3(1)	;IT WAS DELETED, PUT ON DELETED QUEUE
		EXCH 2,DELPGQ
		HRRM 2,@DELPGQ
		MOVEI 2,PSDEL	;SET PAGE STATE TO DELETED
		STOR 2,CSTAGE,(1)
		RET]
	MOVX T3,SWPERR
	TDNE T3,CST3(T1)	;ERROR ON WRITE?
	JRST [	ANDCAM T3,CST3(T1) ;YES, CLEAR IT
		MOVX T3,CORMB
		IORM T3,CST0(T1) ;NOTE PAGE STILL NEEDS WRITING
		CAIE T2,PSWIP	;PAGE WAS REASSIGNED?
		JRST .+1	;YES, OK
		MOVX T2,OFNUL	;SET IT TO UNASSIGNED
		STOR T2,CSTOFK,(T1)
		STOR T2,CSTAGE,(T1)
		JRST .+1]
	CAIE 2,PSWIP		;PAGE REASSIGNED WHILE WRITING?
	RET			;YES, DO NOTHING ELSE
	MOVE 2,CST1(1)		;GET ADDRESS WHERE PAGE WAS WRITTEN
	TXNN 2,DSKAB		;WAS WRITE TO DISK?
	CALLRET ONRQ		;NO, PUT PAGE ON RPLQ
	MOVX T2,DSKSWB
	TDNN T2,CST3(T1)	;KEEP PAGE REQUESTED?
	CALLRET OFRQ		;NO, PUT ON RPLQ
	CALLRET ONRQ		;YES, TO END OF RPLQ
;DIAGNOSE SWAP ERROR
; A/ PAGE NUMBER

SWPER1:	HLRZ B,CST2(A)		;GET OWNING SPTN
	JUMPN B,SWPER3		;JUMP IF IN PT
	HRRZ B,CST2(A)		;GET SPTN OF PAGE
	CAIGE B,NOFN		;INDEX BLOCK?
	JRST [	CALL SWBOFN	;YES -  FLAG IN SPT
		JRST SWPEX2]	;AND NOTE MILD COMPLAINT
	HLRZ B,SPTH(B)		;GET OFN OF IDENT
	JUMPN B,SWPER3		;JUMP IF OFN PRESENT
	PUSH P,A		;SAVE PAGE NUMBER
	MOVE A,CST2(A)		;SETUP SPTN
	CALL FNDFPG		;GET TYPE OF FORK PAGE
	MOVE B,A		;B = TYPE
	POP P,A			;RECOVER PAGE NUMBER
	XCT [	JRST SWPEX7	; 0 - UNKNOWN OR HWPT
		JRST SWPEX8	;1 - PSB
		JRST SWPEX8	;2 - UPT
		JRST SWPEX8](B)	;3 - JSB

;HERE WHEN HAVE PAGE TABLE IDENT IN B

SWPER3:	CAIGE B,NOFN		;IN ORDINARY FILE?
	JRST [	CALL SWBOFN	;YES - MARK IN SPT
		JRST SWPERX]	;AND DEPART
	CAMN B,MMSPTN		;IN SWAPMON?
	JRST SWPEX3		;YES
	PUSH P,A		;SAVE PAGE NUMBER
	MOVE A,B		;SETUP SPTN
	CALL FNDFPG		;GET TYPE OF FORK PAGE
	MOVE B,A		;B = TYPE
	POP P,A			;RECOVER PAGE NUMBER
	XCT [	JRST SWPEX6	;0 - HWPT OR UNKNOWN
		JRST SWPEX4	;1 - PSB PAGE
		JRST SWPERX	;2 - UPT PAGE
		JRST SWPEX5](B)	;3 - JSB PAGE

;HERE TO INDICATE AN ERROR IN AN OFN

SWBOFN:	MOVX T3,OFNBAT		;GET BAT BIT
	TDNN T3,SPTH(T2)	;ALREADY SET?
	TXO T3,OFNWRB		;YES - INDICATE CHANGED
	IORM T3,SPTH(T2)	; IN SPTH
	RET
;DISPOSITION OF SWAP ERROR CASES

SWPEX1:	BUG(SWPFPE)
	JRST SWPERX		;TRY TO CONTINUE

SWPEX2:	BUG(SWPIBE)
	JRST SWPERX		;SHOULD CONTINUE OK

SWPEX3:	BUG(SWPMNE)

SWPEX4:	AOS ERRSWP
	BUG(SWPPSB)
	RET

SWPEX5:	BUG(SWPJSB)
	JRST SWPERX		;TRY TO CONTINUE

SWPEX6:	AOS ERRSWP
	BUG(SWPPTP)
	RET

SWPEX7:	AOS ERRSWP
	BUG(SWPPT)
	RET

SWPEX8:	AOS ERRSWP
	BUG(SWPUPT)
	RET
;FIND TYPE OF FORK PAGE
; A/ SPTH OF PAGE
;	CALL FNDFPG
; RETURNS +1 ALWAYS,
; A/ 	0 - UNKNOWN PAGE OR HWPT
;	1 - PSB
;	2 - UPT
;	3 - JSB

FNDFPG:	SAVEQ
	SKIPE FX,SPTH(A)	;HAVE GOOD FORX INDEX?
	TLNE FX,-1
	JRST RETZ		;NO, RETURN UNKNOWN
	HRRZ Q1,A		;SAVE SPTH
	MOVSI A,-NFNFT		;SETUP TO SCAN TABLE
FNFP1:	XCT FNFTAB(A)		;GET SPTN FOR A FORK PAGE
	CAMN B,Q1		;SAME AS GIVEN ONE?
	RET			;YES, RETURN INDEX IN A
	AOBJN A,FNFP1		;SCAN TABLE
	JRST RETZ		;NOT FOUND

FNFTAB:	LOAD B,HWPTN
	LOAD B,FKPSB
	LOAD B,FKUPT
	LOAD B,FKJSB
NFNFT==.-FNFTAB
;PUT PAGE ON HEAD OF REPLACABLE QUEUE.  THIS IS DONE WHEN CURRENT
;CONTENTS OF PAGE ARE NOT EXPECTED TO BE REUSED.  THE CORE PAGE THUS
;S PLACED WHERE SWPIN WILL GET TO IT IMMEDIATELY.

OFRQ:	MOVE T2,CST1(T1)	;CHECK BACKUP ADR
	TXNE T2,DSKAB		;DISK?
	JRST ONRQD		;YES, PUT PAGE ON TAIL OF DRPLQ
	SKIPE T2,CST2(T1)	;NO. GET OWNER I.D.
	CAIL T2,NOFN		;YES. AN XB?
	SKIPA			;NO.
	JRST ONRQD		;YES. PUT ON TAIL OF DRPLQ
	MOVEI 2,CST3(1)		;MAKE PTR
	PIOFF			;NO DSK OR DRM INTERRUPTS WHILE DIDDLING PTRS
	LOAD 3,CSTPST,(1)	;CHECK PAGE STATE
	JUMPN 3,ONSPMQ		;OTHER THAN AVAILABLE?
	CAMGE 1,MONCOR		;A RESIDENT MONITOR PAGE?
	JRST [	CALL DASPAG	;DEASSIGN PAGE
		PION		;TURN ON PI'S AGAIN
		CALLRET FRCRRM]	;AND PUT PAGE IN SERVICE AGAIN
	HRRZ 3,SRPLQ		;NO, MAKE PTR FOR NEW PAGE
	HLL 4,0(3)		; ..
	HRLM 2,0(3)		;FIX BACK PTR OF OLD TOP PAGE
	HLL 3,4
	MOVEM 3,0(2)		;SET PTRS FOR NEW TOP PAGE
	HRRM 2,SRPLQ		;SET NEW PTR TO TOP PAGE IN RPLQ
	PION
	JRST ONRQ1		;GO FINISH UP

;PUT PAGE ON REPLACABLE QUEUE (TAIL)
; 1/ PAGE NUMBER
;	CALL ONRQ
; RETURN +1 ALWAYS

ONRQ:	MOVE T2,CST1(T1)	;CHECK BACKUP ADR
	TXNN T2,DSKAB		;DISK?
	JRST [	SKIPE T2,CST2(T1) ;NO. GET OWNER I.D.
		CAIL T2,NOFN	;YES. AN XB?
		JRST ONRQS	;NO. PUT ON SRPLQ
		JRST .+1]	;YES. PUT ON DRPLQ
ONRQD:	JRST ONRQS		;ALWAYS USE SRPLQ

;************* DRPLQ NOT PRESENTLY USED ***********

	MOVEI 2,CST3(1)		;CONSTRUCT ABSOLUTE PTR FOR PAGE
	PIOFF			;NO INTS WHILE DIDDLING LIST
	LOAD 3,CSTPST,(1)	;GET PAGE STATE
	JUMPN 3,ONSPMQ		;OTHER THAN AVAILABLE?
	CAMGE 1,MONCOR		;A RESIDENT MONITOR PAGE?
	JRST [	CALL DASPAG	;DEASSIGN PAGE
		PION		;TURN ON PI'S AGAIN
		CALLRET FRCRRM]	;AND PUT IT BACK IN SERVICE
	HLRZ 3,DRPLQ		;NO, PUT PAGE ON 'IN' END OF QUEUE
	HRL 4,0(3)		; BECAUSE PAGES ARE TAKEN FROM 'OUT'
	HRRM 2,0(3)		; END OF QUEUE.
	HLL 3,4
	MOVSM 3,0(2)
	HRLM 2,DRPLQ
	PION
ONRQ1:	AOS NRPLQ
	MOVEI 2,PSRPQ		;SET PAGE STATE
	STOR 2,CSTAGE,(1)
	RET

ONRQS:	MOVEI 2,CST3(1)		;CONSTRUCT ABSOLUTE PTR FOR PAGE
	PIOFF			;NO INTS WHILE DIDDLING LIST
	LOAD 3,CSTPST,(1)	;GET PAGE STATE
	JUMPN 3,ONSPMQ		;OTHER THAN AVAILABLE?
	CAMGE 1,MONCOR		;A RESIDENT MONITOR PAGE?
	JRST [	CALL DASPAG	;DEASSIGN PAGE
		PION		;TURN ON PI'S AGAIN
		CALLRET FRCRRM]	;AND PUT IT BACK IN SERVICE
	HLRZ 3,SRPLQ		;NO, PUT PAGE ON 'IN' END OF QUEUE
	HRL 4,0(3)		; BECAUSE PAGES ARE TAKEN FROM 'OUT'
	HRRM 2,0(3)		; END OF QUEUE.
	HLL 3,4
	MOVSM 3,0(2)
	HRLM 2,SRPLQ
	PION
	JRST ONRQ1		;FINISH UP
;HERE TO PLACE A PAGE ON THE SPECIAL MEMORY QUEUE
;MUST BE CALLED PIOFF
;T1/ CORE PAGE NUMBER
;	CALL ONSPMQ
;RETURNS+1(ALWAYS):
;PAGE REMOVED FROM CST, ON SPMQ
;**NOTE**: RETURNS PION

ONSPMQ:	CALL DASPAG		;REMOVE PAGE FROM CST
	LOAD T2,CSTAGE,(T1)	;GET STATE CODE
	CAIN T2,PSSPQ		;ALREADY ON SPMQ?
	JRST ONSPQX		;YES - DONE
	MOVEI T2,CST3(T1)	;BUILD POINTER
	HLRZ T3,SPMQ		;GET TAIL POINTER
	HRRM T2,(T3)		;APPEND TO LIST
	HRLZM T3,CST3(T1)	;BACK POINTER
	HRLM T2,SPMQ		;NEW TAIL OF LIST
	MOVEI T2,PSSPQ		;SET PAGE STATE TO ON SPMQ
	STOR T2,CSTAGE,(T1)	; ...
	AOS NSPMQ		;NOTE ANOTHER PAGE
	CAMG T1,NHIPG		;A KNOWN PAGE?
	CAMGE T1,MONCOR		;SWAPPABLE?
	JRST ONSPQX		;NO, ALL DONE
	SOS TOTRC		;ONE LESS REAL PAGE
	AOS PAGDIF		;MAKE SHCEDULER NOTICE THIS
ONSPQX:	PION			;ENABLE INTERRUPTS
	RET			;ALL DONE

;ROUTINE TO REMOVE A PAGE FROM SPMQ
;T1/ PHYSICAL PAGE
;	CALL OFFSPQ
;RETURNS+1(ALWAYS):
;	PAGE REMOVED
;CAUTION - THE CALLER MUST BE SURE THE PAGE IS "STABLE" ON SPMQ

OFFSPQ:	PIOFF			;INTERLOCK
	LOAD T2,CSTAGE,(T1)	;GET CURRENT AGE
	CAIE T2,PSSPQ		;NOW ON THIS QUEUE?
	BUG (OFFSPE)
	HRRZ T2,CST3(T1)	;GET POINTERS
	HLRZ T3,CST3(T1)
	JUMPE T2,[HRLM T3,SPMQ	;IF END-OF-LIST, MAKE NEW TAIL
		JRST OFFSP0]	;PROCEED
	HRLM T3,(T2)		;ADVANCE BACK POINTER
OFFSP0:	HRRM T2,(T3)		;BACKUP FORWARD LINK
	MOVX T2,UAAB		;UNASSIGNED ADDRESS
	STOR T2,STGADR,CST1(T1) ;SET IT
	MOVX T2,<FLD(OFNUL,CSTOFK)>
	MOVEM T2,CST3(T1)	;SET OWNER TO NULL
	SOS NSPMQ		;ONE FEWER PAGE
	CAMGE T1,MONCOR		;A SWAPPABLE PAGE?
	JRST ONSPQX		;NO. DON'T ACCOUNT IT
	CAMLE T1,NHIPG		;A NEW PAGE COMING IN?
	MOVEM T1,NHIPG		;YES. MAKE XGC AND GCCR0 SCAN IT
	AOS TOTRC		;ANOTHER REAL PAGE
	AOS PAGDIF		;NEW PAGE IN THE SYSTEM
	CALLRET ONSPQX		;DONE

;ROUTINE TO RETURN CSTPST FOR A PHYSICAL PAGE
;T1/ PAGE
;	CALL GETPST
;RETURNS+1(ERROR):
;	INVALID PAGE NUMBER
;RETURNS+2(SUCCESS):
;T2/ SPECIAL PAGE STATE

GETPST::CAIL T1,MAXCOR		;CHECK RANGE
	RET			;INVALID PAGE
	LOAD T2,CSTPST,(T1)	;PAGE OK, RETURN CURRENT STATE
	RETSKP

;ROUTINE TO SET THE CSTPST STATE FOR A PHYSICAL PAGE
;ASSUMES PROCESS CONTEXT, AS IT MAY NEED TO BLOCK DEPENDING ON THE
;ACTION TO BE TAKEN

;T1/ PHYSICAL PAGE
;T2/ NEW SPECIAL PAGE STATE
;	CALL SETPST
;RETURNS+1(ERROR):
;	ERROR CODE IN T1
;RETURNS+2(SUCCESS):
;	PAGE ON SPMQ WITH REQUESTED STATE
;	T1/ PREVIOUS STATE OF PAGE

;LOCAL AC USAGE
;Q1/ PHYSICAL PAGE
;Q2/ NEW STATE
SETPST::SAVEQ
	STKVAR <SETOST>		;SAVE ORIGINAL STATE HERE
	MOVE Q1,T1		;COPY ARGUMENTS
	MOVE Q2,T2		; ...
	CAIN T2,PSTSPM		;ATTEMPTING TO USE TRANSITION STATE?
	RETBAD (PMCLX1)		;YES - CANNOT BE SET BY USER
	CAIL T1,MAXCOR		;LEGAL PAGE?
	RETBAD (ARGX06)		;NO - INVALID PAGE
	CALL LCKSPM		;INTERLOCK USER SIDE OF SPMQ LOGIC
				;PRESERVES T,Q,P ACS
	LOAD T3,CSTPST,(T1)	;YES - GET CURRENT PAGE STATE
	MOVEM T3,SETOST		;SAVE ORIGINAL STATE HERE
	LOAD T4,CSTAGE,(T1)	;NOW NOINT, IS PAGE ALREADY ON SPMQ
	CAIE T4,PSSPQ		; ?
	JRST STPST1		;NO
	CAMN T3,T2		;SAME AS REQUESTED STATE?
	JRST STPSTX		;YES - RETURN SUCCESS
STPST1:	LSH T3,2		;NO - FORM TRANSITION TABLE INDEX
	IOR T3,T2		; ...
	ADJBP T3,[POINT 2,STPSTA,1] ;INDEX INTO TRANSITION TABLE
	LDB T3,T3		;GET ACTION CODE
	XCT STPSTB(T3)		;PERFORM ACTION

;COMMON EXIT POINT

STPSTX:	CALL ULKSPM		;RELEASE USER SIDE OF SPMQ
	MOVE T1,SETOST		;RETURN ORIGINAL STATE TO CALLER
	RETSKP			;RETURN SUCCESS

;TRANSITION TABLE

STPSTA:	BYTE (2)0,0,1,1,0,0,0,0,2,0,0,3,2,0,3,0

;ACTION TABLE
;ENTERED WITH T1,Q1 = PAGE; T2,Q2 = REQUESTED STATE

STPSTB:	RETBAD (PMCLX1,<CALL ULKSPM>)	;ILLEGAL TRANSITION
	JRST STPSTF		;TRANSITION TO OFFLINE
	JRST STPSTN		;TRANSITION TO ONLINE
	JRST STPSTC		;CHANGE OFFLINE STATE

;HERE TO PLACE A PAGE OFFLINE

STPSTF:	CALL FRCSPM		;FORCE ONTO SPMQ
	  RETBAD (PMCLX2,<CALL ULKSPM>) ;COULDNT FREE PAGE
	MOVE T1,Q1		;GET PAGE AGAIN
	CALL CASHFP		;FLUSH PAGE FROM CACHE
	MOVX T1,PSTOFL		;SET PAGE OFFLINE
	STOR T1,CSTPST,(Q1)	; ...
	JRST STPSTX		;EXIT

;HERE TO PLACE A PAGE ONLINE

STPSTN:	CALL FRCSPM		;FORCE ONTO SPMQ
	  RETBAD (PMCLX2,<CALL ULKSPM>)
	MOVE T1,Q1		;COPY PAGE
	CALL CHKPAG		;CHECK PAGE FOR NXM
	  RETBAD (PMCLX3,<CALL ULKSPM>) ;ERRORS, DONT PLACE ONLINE
	MOVE T1,Q1		;COPY PAGE
	CALL OFFSPQ		;REMOVE FROM SPMQ
	MOVE T1,Q1		;COPY PAGE
	MOVX T3,PSTAVL		;SET SPECIAL PAGE STATE TO AVAILABLE
	STOR T3,CSTPST,(T1)	; ...
	NOSKED			;PROTECT THIS PAGE
	CAMGE T1,MONCOR		;A RESIDENT MONITOR PAGE?
	JRST [	CALL FRCRRM	;YES. PUT IT BACK IN SERVICE
		JRST STPST0]	;AND DONE
	CALL OFRQ		;PLACE AT HEAD OF RPLQ
STPST0:	OKSKED			;ALL QUEUED
	JRST STPSTX

;HERE TO CHANGE THE STATE OF A PAGE (FROM OFL TO ERR OR ERR TO OFL)

STPSTC:	CALL FRCSPM		;SHOULD BE A NOP
	  RETBAD (PMCLX2,<CALL ULKSPM>)
	STOR Q2,CSTPST,(Q1)	;SET TO NEW STATE
	JRST STPSTX

;COMMON ROUTINES FOR USER SPMQ MANIPULATION

;ROUTINE TO INTERLOCK USER MANIPULATION OF SPMQ
;PRESERVES T,Q,P ACS

LCKSPM:	PUSH P,T1		;SAVE T1
LCKSP1:	NOINT
	AOSE SPMLCK		;TEST/SET LOCK
	JRST LCKSP2		;MUST BLOCK
	MOVE T1,FORKX		;HAVE LOCK, INDICATE OWNER
	MOVEM T1,SPMONR		; ...
	POP P,T1		;RESTORE T1
	RET

LCKSP2:	OKINT			;BLOCK OKINT
	MOVEI T1,SPMLCK		;LOCK WORD
	CALL DISL		;WAIT FOR NEGATIVE
	JRST LCKSP1		;TRY AGAIN


;ROUTINE TO RELEASE SPMQ INTERLOCK
;PRESERVES ALL ACS

ULKSPM:	SETOM SPMONR		;NO OWNER
	SETOM SPMLCK		;FREE LOCK
	OKINT			;ALLOW INTERRUPTS
	RET

;ROUTINE TO FORCE A PAGE ONTO SPMQ
;T1/ PHYSICAL PAGE
;	CALL FRCSPM
;RETURNS+1(FAILURE):
;	UNABLE TO FREE PAGE
;RETURNS+2(SUCCESS):
;	PAGE IS ON SPMQ

FRCSPM:	SAVEAC <Q1,Q2,P1>
	MOVE Q1,T1		;COPY ARGUMENT
	MOVEI Q2,^D5		;NUMBER OF TIMES TO TRY
	LOAD P1,CSTPST,(T1)	;GET PRESENT STATE
FRCSP1:	LOAD T2,CSTAGE,(Q1)	;GET CURRENT STATE
	CAIN T2,PSSPQ		;ON SPMQ NOW?
	RETSKP			;YES - NOTHING TO DO
	MOVX T2,PSTSPM		;SETUP TO CHANGE SPECIAL PAGE STATE
	PIOFF			;INTERLOCK
	LOAD T3,CSTPST,(Q1)	;CHECK CURRENT STATE
	CAIN T3,PSTAVL		;CURRENTLY AVAILABLE?
	STOR T2,CSTPST,(Q1)	;YES - MAKE UNAVAILABLE
	LOAD T2,CSTAGE,(Q1)	;GET SWAPPER STATE CODE
	CAIN T2,PSRPQ		;ON RPLQ?
	JRST FRCSP3		;YES - DIRECTLY TO SPMQ
	CAIGE T2,PSASN		;PAGE IN USE?
	JRST FRCSP4		;NO
	HLRZ T2,CST2(Q1)	;SEE IF PART OF MONITOR MAP
	CAMN T2,MMSPTN		;IS IT?
	JRST [	HRRZ T2,CST2(Q1) ;YES. GET INDEX
		CAIL T2,SYVAR_-PGSFT ;IN OR ABOVE SWAPPABLE CODE?
		JRST .+1	;YES. CAN'T MOVE IT THEN
		CAML T2,MONCOR	;IS IT A RESIDENT PAGE?
		CALL [	MOVX T3,-PLKV ;NO. SEE IF LOCKED THEN
			TDNN T3,CST1(Q1) ;IS IT?
			RETSKP		;NO. LET STANDARD CODE DO IT
			CAIL Q1,<SPCRES+PGSIZ-1>/PGSIZ ;MOVABLE?
			RET		;MAYBE.
			RETSKP]		;NO.
		SKIPA T1,Q1	;YES. CAN TRY TO MOVE IT THEN
		JRST .+1	;NO. CAN'T MOVE IT
		PION		;TURN ON PI'S FOR A WHILE
		CALL FRCRMP	;SEE IF WE CAN DO IT
		 JRST FRCSP0	;CAN'T. RETURN BAD NEWS
		RETSKP]		;DONE. PAGE IS ON SPMQ
	CALL SWPCHK		;CAN PAGE BE SWAPPED OUT?
	  SKIPA			;NO - USE LARGE HAMMER
	JRST FRCSP5		;YES - SWAPOUT JUST THIS PAGE
	PION			;MUST UNLOAD MEMORY
	AOS SKEDFC		;INDICATE FORCED CLEAR
	ISB SCDCHN		;REQUEST SCHEDULER CYCLE
FRCSP2:	MOVEM Q1,SPMTPG		;SAVE REQUESTED PAGE
	MOVEI T1,^D2000		;AND WATCHDOG TIME
	ADD T1,TODCLK		; ...
	MOVEM T1,SPMTIM		;TWO SECONDS FROM NOW
	MOVEI T1,SPMTST		;TEST ROUTINE
	MDISMS			;REGRETABLY NOINT
	MOVE T1,Q1		;PUT PAGE NUMBER BACK IN T1
	SOJG Q2,FRCSP1		;TRY AGAIN
FRCSP0:	STOR P1,CSTPST,(Q1)	;RESTORE ORIGINAL STATE
	RET			;FAILED
;FRCSPM CONTINUED

;ON RPLQ - REMOVE FROM RPLQ AND PLACE ON SPMQ

FRCSP3:	MOVE T2,Q1		;PAGE NUMBER
	NOSKED			;PROTECT ALL STRUCTURES
	CALL PRLDEQ		;GET OFF OF RPLQ
	MOVE T1,Q1		;PAGE NUMBER AGAIN
	PIOFF			;PRLDEQ DID A PION
	CALL ONSPMQ		;PLACE ON SPMQ (RETURNS PION)
	OKSKED			;ALLOW SCHEDULING NOW
	RETSKP			;SUCCESS

;HERE WHEN PAGE IS UNASSIGNED AND NOT ON RPLQ

FRCSP4:	PION
	JRST FRCSP2		;SHOULD BE TRANSIENT STATE

;HERE WHEN PAGE IS ASSIGNED AND CAN BE SWAPPED OUT

FRCSP5:	NOSKED			;FOR CALL TO SWPOUT
	PION
	CALL SWPOT0		;START SWAP
	OKSKED
	JRST FRCSP2		;JUST A MATTER OF TIME NOW...

;ROUTINE USED BY FRCSPM TO DEQUEUE A PAGE FROM RPLQ
;	T2/ PAGE NUMBER

PRLDEQ:	SOS NRPLQ		;TAKE PAGE OFF REPLACABLE
	PIOFF
	MOVE 1,CST3(2)
	HRRZ 3,1
	HLLM 1,0(3)
	HLRZ 3,1
	HRRM 1,0(3)
	PION
	SETZRO CORMB,CST0(2)
	SETZM CST3(2)
	RET			;DONE. PAGE DEQUEUED


;SCHEDULER TEST ROUTINE FOR FRCSPM

SPMTST:	MOVE T1,SPMTPG		;SOUGHT AFTER PAGE
	LOAD T2,CSTAGE,(T1)	;GET STATE CODE
	CAIN T2,PSSPQ		;ON SPMQ?
	JRST 1(T4)		;YES - UNBLOCK
	MOVE T1,SPMTIM		;NO - TIME UP?
	CAML T1,TODCLK		; ???
	JRST 0(T4)		;NO - REMAIN BLOCKED
	JRST 1(T4)		;TIME IS UP - UNBLOCK AND RETRY
;ROUTINE USED BY FRCSPM TO PLACE A RESIDENT MONITOR PAGE OFF-LINE.
;CALLED WITH:	T1/ PAGE NUMBER
;RETURNS:
;		+1 FAILED. CANNOT MOVE THIS PAGE
;		+2 SUCCESS. PAGE MOVED AND MMAP UPDATED
;PAGE MUST BE LOCKED.

FRCRMP:	STKVAR <SRCPAG,SRCADR>	 ;WHERE TO SAVE SOURCE PAGE
	HRRZ T2,CST2(T1)	;GET MONITOR VIRTUAL PAGE NUMBER
	MOVEM T2,SRCADR		;SAVE IT
	CALL RMPCHK		;SEE IF CAN MOVE THIS PAGE
	 RETBAD ()		;CAN'T.
	MOVEM T1,SRCPAG		;SAVE ADDRESS OF SOURCE PAGE
FRCRM1:	NOSKD1			;PROTECT RPLQ
	CALL CHKRPQ		;WAIT FOR RPLQ TO BE OKAY
	 JRST .-1		;REVERIFY IF BLOCKED
	HRRZ T2,SRPLQ		;GET TOP PAGE
	CAIN T2,SRPLQ		;EMPTY?
	HRRZ T2,DRPLQ		;YES, USE ALTERNATE RPLQ
	SUBI T2,CST3		;COMPUTE PAGE NUMBER
	CALL PRLDEQ		;USE COMMON ROUTINE TO DEQUEUE THE PAGE
	PUSH P,T2		;SAVE CORE PAGE NUMBER
	MOVE T3,T2		;COPY PAGE NUMBER
	CALL DEPG		;DEASSIGN OWNERSHIP
	SETZM CST1(T3)		;NO BACKUP NOW
	MOVE T1,T3		;GET CORE PAGE NUMBER IN T1
	MOVX T3,PSRDN		;FAKE AGE
	STOR T3,CSTAGE,(T1)	; SO MLKCP WILL DO RIGHT THING
	CALL MLKCP		;LOCK IT IN CORE
	POP P,T2		;GET DEST CORE PAGE AGAIN
	MOVE T1,SRCPAG		;GET BACK SOURCE PAGE
	MOVE T3,CST2(T1)	;GET OWNERSHIP
	MOVEM T3,CST2(T2)	;NEW PAGE OWNERSHIP
	; ..
;PAGE NOW HAS PROPER I.D. MOVE DATA

	MOVE T3,SRCADR		;GET MONITOR VIRTUAL PAGE NUMBER OF SOURCE
	LSH T3,PGSFT		;AN ADDRESS
	MOVE T1,T2		;GET DEST CORE PAGE
	PIOFF			;OWN THE ENTIRE MACHINE
	CALL MAPRCA		;SET UP MAPPING
	MOVEI T4,PGSIZ-1(T1)	;COMPUTE END OF PAGE
	HRL T1,T3		;SET UP BLT ARG
	BLT T1,0(T4)		;MOVE DATA
	CALL UNMRCA		;UNDO MAPPING NOW THAT DATA IS MOVED
	MOVE T1,SRCADR		;GET BACK SOURCE PAGE
	STOR T2,STGADR,MMAP(T1)	;SET UP NEW MAPPING FOR THIS PAGE
	MOVE T1,T3		;GET SET TO MAKE PAGE USABLE
	CALL MONCLR		;DO IT
	MOVE T1,SRCPAG		;GET SOURCE PAGE # AGAIN
	MOVX T3,-PLKV		;TEST FOR LOCKED
	CAMGE T1,MONCOR		;RESIDENT CODE?
	JRST [	ANDCAM T3,CST1(T1) ;YES. TURN OFF LOCK COUNT
		JRST FRCRM2]	;AND PROCEED
	TDNE T3,CST1(T1)	;NOW LOCKED?
	CALL MULKCR		;YES. UNLOCK IT THEN
	MOVE T1,SRCPAG		;THE PAGE AGAIN
FRCRM2:	SETZM CST2(T1)		;NOW NOT OWNED
   REPEAT 0,<			;DON'T NEED EPT CODE YET
	CALL TSTEPT		;SEE IF SOURCE PAGE IS NOW THE EPT
	JRST [	EXCH T1,T2	;IT IS. MUST CHANGE EPT THEN
		CALL SETEPT	;MAKE NEW PAGE THE EPT
		EXCH T1,T2
		JRST .+1]	;PROCEED
   >				;END OF REPEAT 0
	CALL ONSPMQ		;PUT PAGE ON SPECIAL QUEUE
	OKSKD1			;TURN ON SCHEDULER AGAIN
	RETSKP			;AND DONE
;ROUTINE TO PUT A RESIDENT MONITOR PAGE BACK ON-LINE.
;	T1/ PAGE NUMBER
;PAGE ALREADY OFF OF SPMQ
;MUST BE CALLED NOSKED OR AT DISK PI LEVEL

FRCRRM:	STKVAR <SRCPAG,OLDPAG>	;SAVE PAGE NUMBERS
	MOVEM T1,SRCPAG		;SAVE PAGE TO USE AGAIN
	LOAD T2,STGADR,MMAP(T1)	;GET CURRENT LOC OF DATA
	MOVEM T2,OLDPAG		;SAVE IT TOO
	MOVE T3,CST2(T2)	;I.D OF PAGE
	MOVEM T3,CST2(T1)	;SET UP I.D.
	SETONE CSTAGE,(T1)	;MAKE NEW PAGE ACCESSIBLE
	MOVX T2,PLKV		;GET A UNIT OF LOCK COUNT
	IORM T2,CST1(T1)	;AND LOCK THE PAGE AGAIN
	MOVE T2,T1		;GET ADDRESSABLE VALUE FOR CURRENT DATA
	LSH T2,PGSFT		;GET ADDRESS OF CURRENT DATA
	PIOFF			;PREVENT MISHAPS
	CALL MAPRCA		;GET ACCESS TO NEW PAGE
	MOVEI T4,PGSIZ-1(T1)	;GET END OF PAGE
	HRL T1,T2		;SET UP FOR DATA MOVE
	BLT T1,0(T4)		;MOVE THE DATA
	MOVE T1,SRCPAG		;GET NEW PAGE NUMBER AGAIN
	STOR T1,STGADR,MMAP(T1)	;MAKE MMAP POINT TO NEW PAGE
	MOVE T1,T2		;GET ADDRESS
	CALL MONCLR		;MAKE PAGE BE USED
	MOVE T1,OLDPAG		;GET OLD PAGE I.D.
   REPEAT 0,<			;DON'T NEED EPT CODE NOW
	CALL TSTEPT		;IS IT NOW THE EPT?
	JRST [	MOVE T1,SRCPAG	;YES. GET SOURCE PAGE
		CALL SETEPT	;MAKE IT THE NEW EPT
		MOVE T1,OLDPAG	;RESTORE OLD PAGE
		JRST .+1]	;AND PROCEED
   >				;END OF REPEAT 0
	CALL UNMRCA		;CLEAR TEMP MAPPING
	PION			;ALL IS O.K NOW. LET SYSTEM BREATH AGAIN

;DATA NOW RESTORED AND PAGE IN USE. RELEASE OLD PAGE

	SETZM CST2(T1)		;NO LONGER OWNED
	CALL MULKCR		;UNLOCK PAGE
				;UNLOCKER PUTS PAGE ON RPLQ
	RET			;DONE
;SPECIAL ROUTINES USED BY DIAG MEMORY CONTROL.

;SET MAP TO POINT TO PHYSICAL MEMORY WITHOUT CHANGING STATE
;OF MEMORY PAGES. PROCESS SHOULD BE NOINT AND MUST INSURE
;THAT THE PAGES ARE REFERENCED ONLY WHILE NOSKED.
;ACCEPTS:
;		T1/ SOURCE I.D. (PTN,,PN)
;		T2/ FIRST CORE PAGE (-1 => CLEAR MAP)
;		T3/ COUNT
;RETURNS:	+1 ALWAYS

MAPPV::	ASUBR <SID,CPG,CNT>
	HLRZ T3,T1		;GET PTN OF MAP
	CALL SETXB1		;MAP PT
	MOVE T3,IMMPTR		;FORM AN IMMEDIATE POINTER TO MEMORY
	IOR T3,CPG		;INSERT MEMORY PAGE
	SKIPGE CPG		;WANT TO CLEAR?
	SETZM T3		;YES.
	MOVN T1,CNT		;GET NEG OF COUNT
	MOVSS T1
	HRR T1,SID		;STARTING PAGE IN MAP
MAPPV1:	MOVEM T3,CXBPGA(T1)	;UPDATE MAP
	SKIPE T3		;WANT CLEAR?
	ADDI T3,1		;NO. NEXT PAGE THEN
	AOBJN T1,MAPPV1		;DO ALL OF MAP
	CALL MONCLA		;CLEAR PAGER
	CALLRET RELCXB		;RELEASE PT AND RETURN

;ROUTINE TO SET UP CST0 FOR A PROCESS THAT HAS USED MAPPV.
;THE APPROPRIATE CST0'S ARE SET UP WITH PUFLD=-1 AND
;THE AGE SET TO THE CURRENT AGE OF THE PROCESS.
;MUST BE NOSKED
;ACCEPTS:
;		T1/ FIRST MEMORY PAGE
;		T2/ COUNT
;RETURNS:	+1 ALWAYS

SETCST::MOVX T4,<CFXRD!CORMB>	;PART OF NEW CST0 WORDS
	MOVE T3,FORKX		;CURRENT FORK
	HLRZ T3,FKNR(T3)	;PRESENT AGE
	STOR T3,AGEMSK,T4	;SET AGE
SETCS1:	MOVEM T4,CST0(T1)	;SET NEW CST0
	ADDI T1,1		;NEXT PAGE
	SOJG T2,SETCS1		;DO ALL OF THEM
	CALLRET MONCLA		;CLEAR PAGER
;ROUTINES USED BY LOADBS TO SEE IF THIS FORK'S PT,PSB,ETC
;ARE IN A TRANSITION PAGE.
;ACCEPST:	FX/ FORK HANDLE
;RETURNS:	+1 ONE OR MORE PAGES IN TRANSITION
;		+2 NONE IN TRANSITION

TSTFRP::CAMN FX,SPMONR		;THIS FORK OWN THE LOCK?
	RETSKP			;YES. ALLOW IT THEN
	LOAD T1,FKJSB		;GET JSB
	CALL TSTSPT		;GUILTY?
	 RET			;YES.
	HRRZ T1,FKPGS(FX)	;TRY PSB
	CALL TSTSPT
	 RET			;YES
	HLRZ T1,FKPGS(FX)	;NO. TRY PT
	CALL TSTSPT		;?
	 RET			;YES. GUILTY
	LOAD T1,FSSPTN		;STACK PAGE
	CALLRET TSTSPT		;?

;LOCAL ROUTINE TO TEST A GIVEN FORK PAGE.
;ACCEPTS:	T1/ SPT OFFSET
;RETURNS:	+1 IN TRANSITION
;		+2 NOT

TSTSPT:	LOAD T2,STGADR,SPT(T1) ;GET ADDRESS
	TXNE T2,NCORTM		;IN MEMORY?
	RETSKP			;NO. NOT IN TRANSITION THEN
	JE CSTPST,(T2),RSKP	;IN TRANSITION?
	RET			;YES.

	TNXEND
	END