(FILECREATED " 7-Mar-85 17:05:38" {ERIS}<LISPCORE>SOURCES>LLFAULT.;20 345464Q

      changes to:  (VARS LLFAULTCOMS)
		   (FNS 32MBADDRESSABLE)

      previous date: "19-Feb-85 14:52:12" {ERIS}<LISPCORE>SOURCES>LLFAULT.;19)


(* Copyright (c) 1982, 1983, 1984, 1985 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT LLFAULTCOMS)

(RPAQQ LLFAULTCOMS [(FNS \FAULTHANDLER)
	(VARS (FAULTTEST T))
	(FNS \FAULTINIT \D01.FAULTINIT \D01.ASSIGNBUFFERS)
	(FNS \DL.FAULTINIT \DL.NEWFAULTINIT \DL.UNMAPPAGES \DL.MARK.PAGES.UNAVAILABLE 
	     \DL.ASSIGNBUFFERS \CHAIN.UP.RPT)
	(FNS \PAGEFAULT \INVALIDADDR \INVALIDVP \FLUSHPAGE \LOADVMEMPAGE \LOOKUPPAGEMAP \LOCKEDPAGEP 
	     \MARKPAGEVACANT \SELECTREALPAGE \SPECIALRP \TRANSFERPAGE \MOVEPAGE \ZEROPAGE 
	     \UPDATECHAIN)
	(FNS \NEWPAGE \DONEWPAGE \MAKESPACEFORLOCKEDPAGE \MOVEVMEMFILEPAGE \NEWEPHEMERALPAGE 
	     \DONEWEPHEMERALPAGE \LOCKPAGES \DOLOCKPAGES \TEMPLOCKPAGES \TEMPUNLOCKPAGES \UNLOCKPAGES 
	     \FLUSHVM \LOGOUT0 \DOFLUSHVM \RELEASEWORKINGSET \WRITEDIRTYPAGE \WRITEDIRTYPAGE1 
	     \COUNTREALPAGES)
	(FNS \DOCOMPRESSVMEM VMEM.PURE.STATE)
	(FNS 32MBADDRESSABLE \SET.VMEM.FULL.STATE \DOVMEMFULLINTERRUPT \FLUSHVMOK?)
	(INITVARS (\UPDATECHAINFREQ 100)
		  (\PAGEFAULTCOUNTER 0)
		  (\DIRTYPAGECOUNTER 0)
		  (\DIRTYPAGEHINT 0)
		  (\LASTACCESSEDVMEMPAGE 0)
		  (\MAXSHORTSEEK 1000)
		  (\MINSHORTSEEK 20)
		  (\MAXCLEANPROBES 20)
		  (\VMEM.INHIBIT.WRITE)
		  (\VMEM.PURE.LIMIT)
		  (\VMEM.FULL.STATE)
		  (\GUARDVMEMFULL 500)
		  (VMEM.COMPRESS.FLG)
		  (\DOFAULTINIT 0)
		  (\VMEMACCESSFN)
		  (\SYSTEMCACHEVARS)
		  (\MAXSWAPBUFFERS 1)
		  (\EXTENDINGVMEMFILE))
	(INITVARS (\LASTDIRTYCNT)
		  (\LASTDIRTYFOUND)
		  (\LASTDIRTYSCANPTR)
		  (\DIRTYSEEKMAX 50))
	(COMS (* Errors)
	      (FNS \MP.ERROR))
	(COMS (* Debugging)
	      (FNS \ACTONVMEMFILE \SHOWPAGETABLE CHECKPAGEMAP CHECKFPTOVP CHECKFPTOVP1 \LOCKED?STRING 
		   \PRINTFPTOVP \PRINTVP))
	(E (RESETSAVE (RADIX 8)))
	(DECLARE: EVAL@COMPILE DONTCOPY (MACROS \ACTONVMEMFILE .VMEM.CONSISTENTP.)
		  (COMS (* Virtual page flags)
			(CONSTANTS \VMAP.DIRTY \VMAP.CLEAN \VMAP.REF \VMAP.VACANT \VMAP.FLAGS 
				   \VMAP.NOTFLAGS)
			(RECORDS VMEMFLAGS)
			(MACROS LOGNOT16))
		  (COMS (* RPT constants)
			(CONSTANTS \RPT.EMPTY \RPT.UNAVAILABLE \PAGETABLESTOPFLG \RPTENTRYLENGTH)
			(RECORDS RPT RPT1)
			(MACROS RPFROMRPT RPTFROMRP NPAGESMACRO))
		  (COMS (* Virtual to file pagemap)
			(EXPORT (CONSTANTS \MAXFILEPAGE))
			(CONSTANTS \EMPTYPMTENTRY)
			(RECORDS VP)
			(MACROS .PAGEMAPBASE.))
		  (COMS (* FP to VP stuff)
			(RECORDS FPTOVP)
			(CONSTANTS \NO.VMEM.PAGE)
			(MACROS DLRPFROMFP DLFPFROMRP))
		  (PROP DOPVAL \TOUCHPAGE TIMES3)
		  (COMS (* Locked page table)
			(MACROS .LOCKEDVPBASE. .LOCKEDVPMASK.))
		  (CONSTANTS \MAXDIRTYSCANCOUNT \MINVMEMSPAREPAGES \DLBUFFERPAGES)
		  (CONSTANTS 2MBPAGES)
		  (GLOBALVARS \UPDATECHAINFREQ \REALPAGETABLE \RPTLAST \RPOFFSET \RPTSIZE 
			      \LOCKEDPAGETABLE \EMBUFBASE \EMBUFVP \EMBUFRP \PAGEFAULTCOUNTER 
			      \LASTDIRTYCNT \LASTDIRTYFOUND \LASTDIRTYSCANPTR \MACHINETYPE 
			      \LASTACCESSEDVMEMPAGE \MAXSHORTSEEK \MAXCLEANPROBES \MINSHORTSEEK 
			      \DIRTYSEEKMAX \DIRTYPAGECOUNTER \DIRTYPAGEHINT \VMEM.INHIBIT.WRITE 
			      \VMEM.PURE.LIMIT \VMEM.FULL.STATE \GUARDVMEMFULL VMEM.COMPRESS.FLG 
			      \KBDSTACKBASE \MISCSTACKBASE \DOFAULTINIT \FPTOVP \VMEMACCESSFN 
			      \SYSTEMCACHEVARS \LASTVMEMFILEPAGE \EXTENDINGVMEMFILE)
		  (GLOBALVARS \#SWAPBUFFERS \#EMUBUFFERS \#DISKBUFFERS \MAXSWAPBUFFERS 
			      \EMUSWAPBUFFERS \EMUBUFFERS \TELERAIDBUFFER \EMUDISKBUFFERS 
			      \EMUDISKBUFEND))
	[COMS (* * MAKEINIT stuff)
	      (FNS ADDPME CHECKIFPAGE DUMPINITPAGES MAKEROOMFORPME MAPPAGES READPAGEMAP 
		   READPAGEMAPBLOCK SETUPPAGEMAP)
	      (DECLARE: DONTCOPY (MACROS CHECKIF)
			(ADDVARS (INEWCOMS (FNS DUMPINITPAGES)
					   (VARS INITCONSTANTS)
					   (FNS SETUPPAGEMAP ADDPME MAKEROOMFORPME MAPPAGES))
				 (RDCOMS (FNS READPAGEMAP READPAGEMAPBLOCK CHECKIFPAGE \LOCKEDPAGEP 
					      \LOOKUPPAGEMAP CHECKPAGEMAP CHECKFPTOVP CHECKFPTOVP1 
					      \SHOWPAGETABLE \PRINTFPTOVP))
				 (EXPANDMACROFNS CHECKIF .LOCKEDVPBASE. .LOCKEDVPMASK. .PAGEMAPBASE.)
				 (MKI.SUBFNS (\NEWPAGE . MKI.NEWPAGE)
					     (\LOCKPAGES . MKI.LOCKPAGES))
				 (RD.SUBFNS (\NEWPAGE . VNEWPAGE)
					    (\LOCKPAGES . VLOCKPAGES))
				 (RDPTRS (\REALPAGETABLE))
				 (RDVALS (\RPTSIZE)))
			EVAL@COMPILE
			(ADDVARS (DONTCOMPILEFNS DUMPINITPAGES SETUPPAGEMAP ADDPME MAKEROOMFORPME 
						 MAPPAGES READPAGEMAP READPAGEMAPBLOCK CHECKIFPAGE]
	(FNS \LOCKFN \LOCKCODE \LOCKVAR \LOCKCELL \LOCKWORDS)
	[DECLARE: DONTCOPY
		  (ADDVARS (INEWCOMS (FNS \LOCKFN \LOCKVAR \LOCKCELL \LOCKWORDS \LOCKCODE)
				     (ALLOCAL (ADDVARS (LOCKEDFNS \FAULTHANDLER \FAULTINIT 
								  \D01.FAULTINIT \DL.FAULTINIT 
								  \CHAIN.UP.RPT 
								  \MAKESPACEFORLOCKEDPAGE \PAGEFAULT 
								  \READRP \READFLAGS \WRITEMAP 
								  \LOOKUPPAGEMAP \LOCKEDPAGEP 
								  \LOADVMEMPAGE \INVALIDADDR 
								  \INVALIDVP \SELECTREALPAGE 
								  \TRANSFERPAGE \SPECIALRP 
								  \UPDATECHAIN \MARKPAGEVACANT 
								  \FLUSHPAGE \CLEARWORDS \MOVEPAGE 
								  \ZEROPAGE \FLUSHVM \DONEWPAGE 
								  \DONEWEPHEMERALPAGE 
								  \WRITEDIRTYPAGE1 \COPYSYS0 
								  \COPYSYS0SUBR \RELEASEWORKINGSET 
								  \DOFLUSHVM \DOLOCKPAGES 
								  \TEMPLOCKPAGES \TEMPUNLOCKPAGES 
								  \MP.ERROR RAID \DL.NEWFAULTINIT 
								  \DL.MARK.PAGES.UNAVAILABLE 
								  \DL.UNMAPPAGES \DL.ASSIGNBUFFERS 
								  \D01.ASSIGNBUFFERS \DOCOMPRESSVMEM 
								  \MOVEVMEMFILEPAGE)
						       (LOCKEDVARS \REALPAGETABLE \RPTLAST 
								   \PAGEFAULTCOUNTER \UPDATECHAINFREQ 
								   \RPOFFSET \RPTSIZE 
								   \LOCKEDPAGETABLE \EMBUFBASE 
								   \EMBUFVP \EMBUFRP 
								   \LASTACCESSEDVMEMPAGE 
								   \MAXSHORTSEEK \MAXCLEANPROBES 
								   \MINSHORTSEEK \DIRTYPAGECOUNTER 
								   \DIRTYPAGEHINT \VMEM.INHIBIT.WRITE 
								   \VMEM.PURE.LIMIT \VMEM.FULL.STATE 
								   \GUARDVMEMFULL VMEM.COMPRESS.FLG 
								   \KBDSTACKBASE \MISCSTACKBASE 
								   \DOFAULTINIT \FPTOVP \MACHINETYPE 
								   \VMEMACCESSFN \TELERAIDBUFFER 
								   \EMUDISKBUFFERS \EMUDISKBUFEND 
								   \MAXSWAPBUFFERS \EMUBUFFERS 
								   \#EMUBUFFERS \#SWAPBUFFERS 
								   \#DISKBUFFERS \RCLKSECOND 
								   \RCLKMILLISECOND \VALSPACE 
								   \EMUSWAPBUFFERS \EM.CURSORBITMAP 
								   \PAGEMAP \PageMapTBL \IOCBPAGE 
								   \IOPAGE \MISCSTATS \DEFSPACE 
								   \InterfacePage \LASTVMEMFILEPAGE]
	[COMS (* Clock stuff)
	      (FNS \CLOCK0 \DAYTIME0 \GETINTERNALCLOCK \SETDAYTIME0 CLOCKDIFFERENCE 
		   \SECONDSCLOCKGREATERP \CLOCKGREATERP \RCLOCK0)
	      (FNS CLOCK0)
	      (MACROS \RCLOCK0)
	      (DECLARE: DONTCOPY (EXPORT (MACROS \UPDATETIMERS)))
	      [DECLARE: DONTEVAL@LOAD DOCOPY (P (MOVD (QUOTE \DAYTIME0)
						      (QUOTE DAYTIME0]
	      (VARS (\RCLKMILLISECOND 1680))
	      (GLOBALVARS \RCLKSECOND \RCLKMILLISECOND)
	      (DECLARE: DONTCOPY (* Locations in alto emulator)
			(EXPORT (CONSTANTS (\RTCSECONDS 378)
					   (\RTCMILLISECONDS 380)
					   (\RTCBASE 382)
					   (\OFFSET.SECONDS 0)
					   (\OFFSET.MILLISECONDS 2)
					   (\OFFSET.BASE 4)
					   (\ALTO.RCLKSECOND 1680000)
					   (\ALTO.RCLKMILLISECOND 1680)
					   (\DLION.RCLKMILLISECOND 35)
					   (\DLION.RCLKSECOND 34746))
				(MACROS RWMufMan))
			(* Locked stuff. Have to lock anything used by pagefault code, including the 
			   ufns that they use until all microcodes have them)
			(ADDVARS (INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS \CLOCK0 \GETINTERNALCLOCK 
									\BOXIDIFFERENCE \BOXIPLUS 
									\BLT \SLOWIQUOTIENT)
							     (LOCKEDVARS \RCLKSECOND \RCLKMILLISECOND 
									 \MISCSTATS]
	(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDVARS (NLAMA)
									      (NLAML)
									      (LAMA VMEM.PURE.STATE])
(DEFINEQ

(\FAULTHANDLER
  [LAMBDA NIL                                                (* bvm: "31-MAR-83 17:34")
    (PROG NIL
      LP  [OR (AND \DOFAULTINIT (\FAULTINIT))
	      (\PAGEFAULT (\VAG2 (fetch (IFPAGE FAULTHI) of \InterfacePage)
				 (fetch (IFPAGE FAULTLO) of \InterfacePage]
          (\CONTEXTSWITCH \FAULTFXP)
          (GO LP])
)

(RPAQQ FAULTTEST T)
(DEFINEQ

(\FAULTINIT
  [LAMBDA NIL                                                (* bvm: "13-Feb-85 19:18")

          (* * retrieves some constants from Interface page for the swapper and performs other initialization that must happen
	  immediately. Called when starting up, and also when \FAULTHANDLER context starts, in case init hasn't happened yet, 
	  as e.g. from MAKEINIT)


    (OR (NEQ (fetch FPTOVPStart of \InterfacePage)
	     0)
	(\MP.ERROR \MP.OBSOLETEVMEM "No FPTOVP"))
    (SETQ \MACHINETYPE (fetch MachineType of \InterfacePage))
    (COND
      ((AND (NEQ 0 (fetch (IFPAGE FullSpaceUsed) of \InterfacePage))
	    (SELECTC \MACHINETYPE
		     (\DORADO NIL)
		     (\DANDELION (EQ 0 (fetch (IFPAGE DL24BitAddressable) of \InterfacePage)))
		     T))
	(\MP.ERROR \MP.32MBINUSE "Sysout contains virtual pages not addressable by machine")))
    (SETQ \LASTDIRTYSCANPTR)
    (SELECTC \MACHINETYPE
	     (\DANDELION (\DL.FAULTINIT))
	     (\D01.FAULTINIT))
    (COND
      ((IGREATERP (fetch (IFPAGE NActivePages) of \InterfacePage)
		  (IDIFFERENCE \LASTVMEMFILEPAGE \GUARDVMEMFULL))
                                                             (* Vmem getting full!)
	(\SET.VMEM.FULL.STATE)))
    (COND
      ((EQ (PROG1 \DOFAULTINIT (SETQ \DOFAULTINIT NIL))
	   T)                                                (* true after \FLUSHVM. Need to rebuild some contexts)
	(replace (IFPAGE KbdFXP) of \InterfacePage with (\MAKEFRAME (COND
								      ((fetch (LITATOM CCODEP)
									  of (QUOTE \KEYHANDLER))
									(FUNCTION \KEYHANDLER))
								      (T (QUOTE \DUMMYKEYHANDLER)))
								    \KBDSTACKBASE
								    (IPLUS \KBDSTACKBASE 
									   \StackAreaSize)
								    0 0))
	(replace (IFPAGE MiscFXP) of \InterfacePage with (\MAKEFRAME (FUNCTION \DOMISCAPPLY)
								     \MISCSTACKBASE
								     (IPLUS \MISCSTACKBASE 
									    \StackAreaSize)
								     0 0))
	T])

(\D01.FAULTINIT
  [LAMBDA NIL                                                (* bvm: " 5-Feb-85 12:42")
    (SETQ \VMEMACCESSFN (FUNCTION \M44ACTONVMEMFILE))
    (SETQ \REALPAGETABLE (fetch (IFPAGE REALPAGETABLEPTR) of \InterfacePage))
                                                             (* Note: these SETQ's do not reference count, since the
							     values are all smallp's and emulator addresses 
							     (in atom space))
    (SETQ \RPOFFSET (SIGNED (fetch (IFPAGE RPOFFSET) of \InterfacePage)
			    BITSPERWORD))
    (SETQ \RPTSIZE (fetch (IFPAGE RPTSIZE) of \InterfacePage))
                                                             (* Initialize the software clocks from alto emulator)
    (\BLT (LOCF (fetch SECONDSCLOCK of \MISCSTATS))
	  (EMADDRESS \RTCSECONDS)
	  (UNFOLD 3 WORDSPERCELL))
    [SETQ \RCLKMILLISECOND (CONSTANT (OR (SMALLP \ALTO.RCLKMILLISECOND)
					 (ERROR \ALTO.RCLKMILLISECOND 
						"\ALTO.RCLKMILLISECOND isn't a SMALLP???"]

          (* * \ALTO.RCLKMILLISECOND must be a SMALLP here so as not to cause any refcnt or pagefault activity.
	  \RCLKSECOND is large and has to live on \MISCSTATS, since there is no convenient way to lock a random cell.)


    (SETQ.NOREF \RCLKSECOND (LOCF (fetch RCLKSECOND of \MISCSTATS)))

          (* * Note the SETQ.NOREF for \RCLKSECOND in order to guarantee no refcnt'ing (which might pagefault) Note that these
	  LOADBYTE expressions are compiled as constants)


    (replace (FIXP HINUM) of \RCLKSECOND with (LOADBYTE \ALTO.RCLKSECOND 16 16))
    (replace (FIXP LONUM) of \RCLKSECOND with (LOADBYTE \ALTO.RCLKSECOND 0 16))
    [if (AND (EQ \MACHINETYPE \DORADO)
	     (ILEQ 5124 (fetch RVersion of \InterfacePage)))
	then (replace NSHost0 of \InterfacePage with 0)
	     (replace NSHost1 of \InterfacePage with 21898)
	     (replace NSHost2 of \InterfacePage
		with (IPLUS (MASK.1'S 15 1)
			    (for I (N ← 0) from 1168 to 1175
			       do                            (* Mufflers "2220Q" thru "2227Q" hold the bits of the 
							     basic serial number)
				  (SETQ N (IPLUS (LLSH N 1)
						 (if (BITTEST (RWMufMan I)
							      (MASK.1'S 15 1))
						     then 0
						   else 1)))
			       finally (RETURN N]
    (\CHAIN.UP.RPT)
    (\D01.ASSIGNBUFFERS])

(\D01.ASSIGNBUFFERS
  [LAMBDA NIL                                                (* bvm: "12-JUL-83 18:25")
    (PROGN                                                   (* Assign swap buffer)
	   (SETQ \EMBUFVP (fetch (IFPAGE EMBUFVP) of \InterfacePage))
	   (SETQ \EMBUFBASE (EMPOINTER (UNFOLD \EMBUFVP WORDSPERPAGE)))
	   (SETQ \EMBUFRP (\READRP \EMBUFVP)))
    (PROG ((EMBUF (fetch (IFPAGE EMUBUFFERS) of \InterfacePage))
	   (EMLEN (fetch (IFPAGE EMUBUFLENGTH) of \InterfacePage))
	   EXTRALEN NPAGES)
          [add EMLEN (IDIFFERENCE EMBUF (SETQ EMBUF (CEIL EMBUF WORDSPERPAGE]
                                                             (* Round up to a page boundary and throw out the excess)
          (SETQ EXTRALEN (IMOD EMLEN WORDSPERPAGE))
          (add EXTRALEN (COND
		 ((ILESSP EXTRALEN 100)
		   (TIMES 2 WORDSPERPAGE))
		 (T WORDSPERPAGE)))
          (SETQ NPAGES (FOLDLO (SETQ EMLEN (IDIFFERENCE EMLEN EXTRALEN))
			       WORDSPERPAGE))
          (OR (IGEQ NPAGES 4)
	      (RAID "No swap buffer space"))
          (SETQ \TELERAIDBUFFER (EMPOINTER EMBUF))
          (SETQ \EMUBUFFERS (\ADDBASE \TELERAIDBUFFER WORDSPERPAGE))
          (SETQ \#EMUBUFFERS (SETQ NPAGES (SUB1 NPAGES)))
          (SETQ \#SWAPBUFFERS (IMIN \MAXSWAPBUFFERS (IQUOTIENT NPAGES 2)))
          (SETQ \#DISKBUFFERS (IDIFFERENCE \#EMUBUFFERS \#SWAPBUFFERS))
          (SETQ \EMUDISKBUFFERS \EMUBUFFERS)
          (SETQ \EMUDISKBUFEND (\ADDBASE \EMUDISKBUFFERS (UNFOLD \#DISKBUFFERS WORDSPERPAGE)))
          (SETQ \EMUSWAPBUFFERS \EMUDISKBUFEND)
          (\INITBFS (\ADDBASE \EMUBUFFERS (UNFOLD NPAGES WORDSPERPAGE))
		    EXTRALEN T])
)
(DEFINEQ

(\DL.FAULTINIT
  [LAMBDA NIL                                                (* bvm: "13-Feb-85 20:10")
    (SETQ \VMEMACCESSFN (FUNCTION \DL.ACTONVMEMFILE))
    (SETQ \IOCBPAGE (create POINTER
			    PAGE# ← \VP.IOCBS))
    (COND
      ((NOT (.VMEM.CONSISTENTP.))
	(\MP.ERROR \MP.INVALIDVMEM)))
    (\DL.NEWFAULTINIT)
    (SETQ \RCLKMILLISECOND \DLION.RCLKMILLISECOND)           (* These are fortunately both small)
    (SETQ \RCLKSECOND \DLION.RCLKSECOND)
    (\RCLK (LOCF (fetch BASECLOCK of \MISCSTATS)))           (* Reset base clock)
    [COND
      ((EQ (fetch DLTODVALID of \IOPAGE)
	   0)                                                (* Time not valid, so store zero in the clock)
	(\PUTBASEPTR (LOCF (fetch SECONDSCLOCK of \MISCSTATS))
		     0 NIL))
      (T (bind TMP (BASE ←(LOCF (fetch SECONDSCLOCK of \MISCSTATS)))
	    do                                               (* Loop until clock reads the same as we wrote, in case
							     it was being updated)
	       (\PUTBASE BASE 1 (SETQ TMP (fetch DLTODLO of \IOPAGE)))
	       (\PUTBASE BASE 0 (fetch DLTODHI of \IOPAGE))
	    repeatuntil (EQ (fetch DLTODLO of \IOPAGE)
			    TMP]
    (\PUTBASEPTR (LOCF (fetch MILLISECONDSCLOCK of \MISCSTATS))
		 0 NIL)                                      (* Clear the milliseconds timer)
    (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE)
		       \DL.PROCESSORBUSY))                   (* Wait for IOP readiness)
    (replace DLPROCESSORCMD of \IOPAGE with \DL.READPID)     (* Ask it to give the processor ID 
							     (3 words))
    (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE)
		       \DL.PROCESSORBUSY))
    (replace NSHost0 of \InterfacePage with (fetch DLPROCESSOR0 of \IOPAGE))
    (replace NSHost1 of \InterfacePage with (fetch DLPROCESSOR1 of \IOPAGE))
    (replace NSHost2 of \InterfacePage with (fetch DLPROCESSOR2 of \IOPAGE))
    (SETQ \LASTVMEMFILEPAGE (fetch (IFPAGE DLLastVmemPage) of \InterfacePage))
    (\DL.DISKINIT T])

(\DL.NEWFAULTINIT
  [LAMBDA NIL                                                (* bvm: " 5-Feb-85 11:56")

          (* We have just started up on a DLion. Boot code has loaded the first n pages of the sysout into pages 2 thru n-3, 
	  except for the area covered by the map and IO page, and has built the map accordingly. Our principal task is to 
	  build \REALPAGETABLE)


    (PROG ((NREALPAGES (fetch (IFPAGE NRealPages) of \InterfacePage))
	   (FIRSTBUFFERRP \RP.STARTBUFFERS)
	   (SCRATCHVP \VP.INITSCRATCH)
	   (SCRATCHBASE (create POINTER
				PAGE# ← \VP.INITSCRATCH))
	   (DISPLAYBASE (create POINTER
				PAGE# ← \VP.DISPLAY))
	   FIRSTUSEFULRP IFPAGERP IOCBRP RPTBASE VP DEBUGGING)
          [do (COND
		((for I from 0 to (SUB1 \DLBUFFERPAGES) as (FPBASE ←(\ADDBASE \FPTOVP (DLFPFROMRP
										FIRSTBUFFERRP)))
		    by (\ADDBASE FPBASE 1)
		    do (COND
			 ([OR (NOT (fetch FPOCCUPIED of FPBASE))
			      (\LOCKEDPAGEP (SETQ VP (fetch FPVIRTUALPAGE of FPBASE]
                                                             (* Can't use as buffer. This is just a check for 
							     consistency; you should pick \RP.STARTBUFFERS so that 
							     this isn't a problem)
			   (RETURN T)))                      (* Unmap this page so we can use it for buffers)
		       (\WRITEMAP VP 0 \VMAP.VACANT))        (* Bad starting place, try again)
		  (add FIRSTBUFFERRP 1))
		(T (RETURN]
          (SETQ FIRSTUSEFULRP (IPLUS FIRSTBUFFERRP \DLBUFFERPAGES))
          (PROGN                                             (* Copy vital info that booting left in page 1)
		 (SETQ IOCBRP (IPLUS (LOGAND (SUB1 (IMIN NREALPAGES 3072))
					     65280)
				     \VP.IOCBS))

          (* Put IOCB page near the end of memory, but in the first 1.5 mb so that Burdock can see it.
	  Temporary until Steve fixes swap code to not care what RP contains IOCB's)


		 [SETQ VP (fetch FPVIRTUALPAGE of (\ADDBASE \FPTOVP (DLFPFROMRP IOCBRP]
		 (COND
		   ((\LOCKEDPAGEP VP)
		     (\MP.ERROR \MP.IOCBPAGE))
		   (T (\WRITEMAP VP 0 \VMAP.VACANT)))        (* Unmap whoever lived in our target page)
		 (\WRITEMAP \VP.IOCBS IOCBRP \VMAP.CLEAN)
		 (\WRITEMAP SCRATCHVP 1 \VMAP.CLEAN)
		 (\BLT \IOCBPAGE SCRATCHBASE WORDSPERPAGE))
          (PROGN                                             (* Copy InterfacePage out of segment zero)
		 (\WRITEMAP SCRATCHVP FIRSTBUFFERRP \VMAP.CLEAN)
		 (\BLT SCRATCHBASE \InterfacePage WORDSPERPAGE)
		 (\WRITEMAP \VP.IFPAGE (SETQ IFPAGERP FIRSTBUFFERRP)
			    \VMAP.CLEAN)
		 (add FIRSTBUFFERRP 1))
          (\DL.UNMAPPAGES (ADD1 \FP.IFPAGE)
			  (DLFPFROMRP \RP.IOPAGE))           (* Unmap everything that might have been mapped into 
							     real segment zero or to map or IOPAGE)
          (for NEXTBANK0 from 2MBPAGES by 2MBPAGES until (IGREATERP NEXTBANK0 NREALPAGES)
	     do                                              (* All the "shadows of the display bank" in higher 
							     memory have restricted use; take them out of commission
							     for now)
		(\DL.UNMAPPAGES NEXTBANK0 (IPLUS NEXTBANK0 PAGESPERSEGMENT -1)))
          (PROGN                                             (* Copy Display into segment zero)
		 (for I from 0 to (SUB1 \NP.DISPLAY) do (\WRITEMAP (IPLUS SCRATCHVP I)
								   (IPLUS \RP.DISPLAY I)
								   \VMAP.CLEAN))
                                                             (* Point scratch area at real segment zero)
		 (\BLT SCRATCHBASE DISPLAYBASE (UNFOLD \NP.DISPLAY WORDSPERPAGE))
                                                             (* Copy display from wherever boot put it)
		 (for I from 0 to (SUB1 \NP.DISPLAY)
		    do (\WRITEMAP (IPLUS SCRATCHVP I)
				  0 \VMAP.VACANT)
		       (\WRITEMAP (IPLUS \VP.DISPLAY I)
				  (IPLUS \RP.DISPLAY I)
				  \VMAP.CLEAN))              (* Display is now where hardware wants it, so enable 
							     display)
		 (replace (IOPAGE DLDISPCONTROL) of \IOPAGE with 0))
          (PROG ((RPSIZE (IDIFFERENCE NREALPAGES (SETQ \RPOFFSET -1)))
		 (FIRSTRP \RP.AFTERDISPLAY)
		 (FIRSTVP \VP.RPT)
		 RPTPAGES)                                   (* Construct real page table in segment zero after the 
							     display)
	        (SETQ RPTPAGES (FOLDHI (TIMES3 RPSIZE)
				       WORDSPERPAGE))
	        [COND
		  [(IGREATERP (IPLUS RPTPAGES FIRSTRP)
			      PAGESPERSEGMENT)

          (* No space in bank zero, so put RPT in first segment after 2 megabytes, where the first "shadow" display bank 
	  lives. Anyone mapped into there is out by now.)


		    (SETQ FIRSTRP 2MBPAGES)
		    (COND
		      ((IGREATERP (IPLUS FIRSTVP RPTPAGES)
				  \VP.BUFFERS)               (* Move virtual assignment backwards if necessary)
			(SETQ FIRSTVP (IDIFFERENCE \VP.BUFFERS RPTPAGES]
		  ((SETQ DEBUGGING (EQ (\GETBASE \InterfacePage 255)
				       7))                   (* hack for staging this change)
		    (SETQ FIRSTRP (IDIFFERENCE NREALPAGES RPTPAGES))
		    (\DL.UNMAPPAGES (DLFPFROMRP FIRSTRP)
				    (DLFPFROMRP (IPLUS FIRSTRP RPTPAGES -1]
	        (for I from 0 to (SUB1 RPTPAGES)
		   do                                        (* Assign pages to real page table now)
		      (\WRITEMAP (IPLUS FIRSTVP I)
				 (IPLUS FIRSTRP I)
				 \VMAP.CLEAN))
	        (SETQ \REALPAGETABLE (create POINTER
					     PAGE# ← FIRSTVP))
	        (\CLEARWORDS \REALPAGETABLE (TIMES3 RPSIZE))
	        (AND DEBUGGING (\DL.MARK.PAGES.UNAVAILABLE FIRSTRP (IPLUS FIRSTRP RPTPAGES -1)))
	        (SETQ \RPTSIZE RPSIZE))
          [PROGN                                             (* Fill in RPT with info from \FPTOVP)
		 (SETQ RPTBASE \REALPAGETABLE)
		 [for I from 0 to (SUB1 \NP.DISPLAY)
		    do (SETQ RPTBASE (\ADDBASE RPTBASE \RPTENTRYLENGTH)) 
                                                             (* Fill in Display pages)
		       (replace (RPT VP) of RPTBASE with (IPLUS \VP.DISPLAY I))
		       (replace (RPT FILEPAGE) of RPTBASE with (DLFPFROMRP (IPLUS \RP.TEMPDISPLAY I]
		 (\DL.MARK.PAGES.UNAVAILABLE \NP.DISPLAY \RP.IOPAGE)
                                                             (* Mark rest of segment zero plus Map and IOPAGE 
							     unavailable)
		 (for NEXTBANK0 from 2MBPAGES by 2MBPAGES until (IGREATERP NEXTBANK0 NREALPAGES)
		    do                                       (* Mark the shadow display bank pages unavailable)
		       (\DL.MARK.PAGES.UNAVAILABLE NEXTBANK0 (IPLUS NEXTBANK0 PAGESPERSEGMENT -1)))
		 (for I from (ADD1 \RP.IOPAGE) to (SUB1 NREALPAGES)
		    as [FPBASE ←(\ADDBASE \FPTOVP (DLFPFROMRP (ADD1 \RP.IOPAGE]
		    by (\ADDBASE FPBASE 1) as [RPTBASE ←(fetch RPTRBASE of (RPTFROMRP (ADD1 
										       \RP.IOPAGE]
		    by (\ADDBASE RPTBASE \RPTENTRYLENGTH) bind LASTREALPAGE ←(DLRPFROMFP
								 (fetch (IFPAGE NActivePages)
								    of \InterfacePage))
		    do 

          (* Fill in rest of RPT from \FPTOVP. Could optimize this a little by special casing the area occupied by the 
	  display, but this is simpler)


		       (COND
			 ((fetch (RPT UNAVAILABLE) of RPTBASE))
			 ((AND (ILEQ I LASTREALPAGE)
			       (fetch FPOCCUPIED of FPBASE)
			       [NOT (fetch (VMEMFLAGS VACANT) of (\READFLAGS (SETQ VP
									       (fetch FPVIRTUALPAGE
										  of FPBASE]
			       (EQ I (\READRP VP)))

          (* There is a VP assigned to this filepage, and it is still there. False for display that got moved and any real 
	  pages that didn't get filled. LASTREALPAGE is in case the real memory is larger than the sysout -- FPTOVP does not 
	  exist all the way)


			   (replace (RPT VP) of RPTBASE with VP)
			   (replace (RPT FILEPAGE) of RPTBASE with (DLFPFROMRP I)))
			 (T (replace (RPT EMPTY) of RPTBASE with T]
          (PROGN                                             (* Touch up RPT with the exceptions)
		 (SETQ RPTBASE (fetch RPTRBASE of (RPTFROMRP IFPAGERP)))
                                                             (* Interface Page)
		 (replace (RPT VP) of RPTBASE with \VP.IFPAGE)
		 (replace (RPT FILEPAGE) of RPTBASE with \FP.IFPAGE)
		 (replace (RPT UNAVAILABLE) of (fetch RPTRBASE of (RPTFROMRP IOCBRP)) with T)
                                                             (* \IOCBPAGE)
		 (\DL.MARK.PAGES.UNAVAILABLE FIRSTBUFFERRP (SUB1 FIRSTUSEFULRP))
                                                             (* buffer pages unavailable to swapper)
		 )
          (\CHAIN.UP.RPT)
          (PROG ((NBUFFERS (IDIFFERENCE FIRSTUSEFULRP FIRSTBUFFERRP)))
                                                             (* Allocate buffers)
	        (for I from 0 to (SUB1 NBUFFERS) do (\WRITEMAP (IPLUS \VP.BUFFERS I)
							       (IPLUS FIRSTBUFFERRP I)
							       \VMAP.CLEAN))
	        (\DL.ASSIGNBUFFERS (create POINTER
					   PAGE# ← \VP.BUFFERS)
				   NBUFFERS])

(\DL.UNMAPPAGES
  [LAMBDA (FIRSTFP LASTFP)                                   (* bvm: "14-Jan-84 14:20")

          (* * At initialization time, unmap anything that originally lived in filepages FIRSTFP thru LASTFP)


    (for FP from FIRSTFP to LASTFP as (FPBASE ←(\ADDBASE \FPTOVP FIRSTFP)) by (\ADDBASE FPBASE 1)
       when (fetch FPOCCUPIED of FPBASE) do (\WRITEMAP (fetch FPVIRTUALPAGE of FPBASE)
						       0 \VMAP.VACANT])

(\DL.MARK.PAGES.UNAVAILABLE
  [LAMBDA (FIRSTRP LASTRP)                                   (* bvm: "14-Jan-84 14:32")
    (for I from FIRSTRP to LASTRP as (RPTBASE ←(fetch RPTRBASE of (RPTFROMRP FIRSTRP)))
       by (\ADDBASE RPTBASE \RPTENTRYLENGTH) do (replace (RPT UNAVAILABLE) of RPTBASE with T])

(\DL.ASSIGNBUFFERS
  [LAMBDA (BASE NPAGES)                                      (* bvm: "29-Jan-85 19:05")
    (PROGN                                                   (* Allocate a page to hold name and password, and 
							     perhaps other ephemeral things)
	   (\CLEARWORDS BASE WORDSPERPAGE)
	   (replace (IFPAGE UserNameAddr) of \InterfacePage with (\LOLOC (\ADDBASE BASE 1)))
	   (replace (IFPAGE UserPswdAddr) of \InterfacePage with (\LOLOC (\ADDBASE BASE 33)))
	   (SETQ BASE (\ADDBASE BASE WORDSPERPAGE))
	   (add NPAGES -1))
    (PROGN                                                   (* Assign swap buffer)
	   (SETQ \EMBUFBASE BASE)
	   (SETQ \EMBUFVP (fetch (POINTER PAGE#) of BASE))
	   (SETQ \EMBUFRP (\READRP \EMBUFVP))
	   (SETQ BASE (\ADDBASE BASE WORDSPERPAGE))
	   (add NPAGES -1))
    (PROGN                                                   (* Assign ether buffers)
	   (replace (IFPAGE MDSZoneLength) of \InterfacePage with (UNFOLD 2 WORDSPERPAGE))
	   (replace (IFPAGE MDSZone) of \InterfacePage with (\LOLOC BASE))
	   (SETQ BASE (\ADDBASE BASE (UNFOLD 2 WORDSPERPAGE)))
	   (SETQ \TELERAIDBUFFER BASE)
	   (SETQ BASE (\ADDBASE BASE WORDSPERPAGE))
	   (add NPAGES -3))
    (PROGN                                                   (* Divvy up buffer space)
	   (SETQ \#SWAPBUFFERS (SETQ \#EMUBUFFERS NPAGES))
	   (SETQ \#DISKBUFFERS 0)
	   (SETQ \EMUSWAPBUFFERS (SETQ \EMUBUFFERS BASE])

(\CHAIN.UP.RPT
  [LAMBDA NIL                                                (* bvm: "18-Dec-84 16:07")

          (* * Maps over the Real Page Table as constructed so far and fleshes it out. Assumes that the table is built, has 
	  all its VP and FILEPAGE entries set, and that the empty and unavailable entries are so marked.
	  Finishes the job by chaining together the available pages and setting the LOCKED bits)


    (PROG ((RPTBASE \REALPAGETABLE)
	   (LASTEMPTY \REALPAGETABLE)
	   (LASTUSED (\ADDBASE \REALPAGETABLE 1))
	   FIRSTUSED)
          (SETQ FIRSTUSED LASTUSED)

          (* The "entry" \REALPAGETABLE is a dummy that points to the least recently used entry. We use the second word of 
	  that dummy as a temporary chain head for the used pages, so that we can put all the empty pages at the front of the 
	  queue.)


          [for I from 1 to (SUB1 \RPTSIZE)
	     do (SETQ RPTBASE (\ADDBASE RPTBASE \RPTENTRYLENGTH))
		(COND
		  ((fetch (RPT UNAVAILABLE) of RPTBASE))
		  ((fetch (RPT EMPTY) of RPTBASE)
		    (replace (RPT NEXTRP) of LASTEMPTY with I)
		    (replace (RPT LOCKED) of RPTBASE with NIL)
		    (SETQ LASTEMPTY RPTBASE))
		  (T (replace (RPT NEXTRP) of LASTUSED with I)
		     (replace (RPT LOCKED) of RPTBASE with (\LOCKEDPAGEP (fetch (RPT VP)
									    of RPTBASE)))
		     (SETQ LASTUSED RPTBASE]                 (* Finally, link the end of empty chain to front of in 
							     use chain)
          (replace (RPT NEXTRP) of LASTEMPTY with (fetch (RPT NEXTRP) of FIRSTUSED))
          (replace (RPT NEXTRP) of (SETQ \RPTLAST LASTUSED) with \PAGETABLESTOPFLG)
          (replace (RPT UNAVAILABLE) of \REALPAGETABLE with T)
                                                             (* Dummy first entry)
      ])
)
(DEFINEQ

(\PAGEFAULT
  [LAMBDA (PTR)                                              (* bvm: "17-Nov-84 17:44")
    (\CLOCK0 (LOCF (fetch SWAPTEMP0 of \MISCSTATS)))         (* Note time of start)
    (PROG ((VP (fetch (POINTER PAGE#) of PTR))
	   FLAGS FILEPAGE)
          (COND
	    ((fetch (VP INVALID) of VP)                      (* Map out of bounds on Dolphin always produces -1 as 
							     the vp. Don't know about other machines)
	      (\MP.ERROR \MP.MOB "Page Fault: Map out of bounds" (AND (NEQ VP 65535)
								      PTR)
			 T))
	    ([NOT (fetch (VMEMFLAGS VACANT) of (SETQ FLAGS (\READFLAGS VP]
	      (\MP.ERROR \MP.RESIDENT "Fault on resident page" PTR T))
	    ((EQ (SETQ FILEPAGE (\LOOKUPPAGEMAP VP))
		 0)
	      (\INVALIDADDR PTR))
	    (T (COND
		 ((EQ (\HILOC PTR)
		      \STACKHI)                              (* should never happen. For debugging)
		   (\MP.ERROR \MP.STACKFAULT "Fault on stack" PTR T)))
	       (\LOADVMEMPAGE VP FILEPAGE)))
          [\BOXIPLUS (LOCF (fetch SWAPWAITTIME of \MISCSTATS))
		     (\BOXIDIFFERENCE (\CLOCK0 (LOCF (fetch SWAPTEMP1 of \MISCSTATS)))
				      (LOCF (fetch SWAPTEMP0 of \MISCSTATS]
                                                             (* Count the time used.)
          (RETURN PTR])

(\INVALIDADDR
  [LAMBDA (ADDR)                                             (* bvm: " 6-AUG-83 22:25")
    (\MP.ERROR \MP.INVALIDADDR "Invalid address" ADDR T])

(\INVALIDVP
  [LAMBDA (VP)                                               (* bvm: " 6-AUG-83 22:25")
    (\MP.ERROR \MP.INVALIDVP "Invalid VP" VP])

(\FLUSHPAGE
  [LAMBDA (RPTINDEX FROMFLUSHVM)                             (* bvm: "13-Feb-85 20:11")

          (* * Write out real page RPTINDEX if it is dirty.)


    (PROG ((RPTR (fetch RPTRBASE of RPTINDEX))
	   VP FP NEWFP)
          (COND
	    ([AND (fetch (RPT OCCUPIED) of RPTR)
		  (fetch (VMEMFLAGS DIRTY) of (\READFLAGS (SETQ VP (fetch (RPT VP) of RPTR]
                                                             (* Yes, page is dirty)
	      (SETQ FP (fetch (RPT FILEPAGE) of RPTR))
	      [COND
		[(AND \VMEM.PURE.LIMIT (NOT FROMFLUSHVM))    (* Don't sully vmem; write page out beyond the original
							     end of vmem)
		  (COND
		    ((ILEQ FP \VMEM.PURE.LIMIT)
		      (COND
			((fetch (RPT LOCKED) of RPTR)
			  (\MP.ERROR \MP.WRITING.LOCKED.PAGE)))
		      (SETQ NEWFP (add (fetch NActivePages of \InterfacePage)
				       1))
		      (COND
			((IGREATERP NEWFP (IDIFFERENCE \LASTVMEMFILEPAGE \GUARDVMEMFULL))
			  (\SET.VMEM.FULL.STATE)))
		      (\PUTBASE (.PAGEMAPBASE. VP)
				0 NEWFP)
		      (\PUTBASE \FPTOVP NEWFP VP)
		      (\PUTBASE \FPTOVP FP \NO.VMEM.PAGE)
		      (replace (RPT FILEPAGE) of RPTR with (SETQ FP NEWFP]
		((.VMEM.CONSISTENTP.)
		  (replace (IFPAGE Key) of \InterfacePage with (LOGNOT16 \IFPValidKey))
                                                             (* Invalidate vmem and write out the Interface page)
		  (SETQ \DIRTYPAGEHINT 0)                    (* So that the dirty page background writer wakes up)
		  (PROG ((IFVP (fetch (POINTER PAGE#) of \InterfacePage)))
		        (\TRANSFERPAGE IFVP \FirstVmemBlock (RPTFROMRP (\READRP IFVP))
				       T NIL]                (* Write it out)
	      (COND
		((IGREATERP \DIRTYPAGEHINT 0)
		  (add \DIRTYPAGEHINT -1)))
	      (\TRANSFERPAGE VP FP RPTINDEX T NIL])

(\LOADVMEMPAGE
  [LAMBDA (VPAGE FILEPAGE NEWPAGEFLG LOCK? DONTMOVETOPFLG)   (* bvm: "17-Nov-84 21:50")

          (* Fault in virtual page VPAGE known to live in FILEPAGE on the vmem. NEWPAGEFLG is true if the page is new, so 
	  should just be cleared, not loaded from vmem file. If LOCK? is true, locks down the page as well.
	  In this case, if on Dandelion, we also check for page wanting to live in a particular real page.
	  If DONTMOVETOPFLG is true, the real page we put this page in is not promoted to the front of the LRU queue of pages)


    (COND
      ((IGREATERP \PAGEFAULTCOUNTER \UPDATECHAINFREQ)
	(\UPDATECHAIN)))
    (add \PAGEFAULTCOUNTER 1)
    (PROG ((PREVRP (\SELECTREALPAGE FILEPAGE))
	   RPTINDEX RPTRBASE SPECIALRP)
          (SETQ RPTINDEX (fetch (RPT NEXTRP) of PREVRP))
          (SETQ RPTRBASE (fetch RPTRBASE of RPTINDEX))
          (COND
	    ((NOT DONTMOVETOPFLG)
	      (replace (RPT NEXTRP) of PREVRP with (fetch (RPT NEXTRP) of RPTRBASE))
                                                             (* Splice RPTINDEX out of chain)
	      (replace (RPT NEXTRP) of \RPTLAST with RPTINDEX)
                                                             (* Put new page at end of chain)
	      (replace (RPT NEXTRP) of (SETQ \RPTLAST RPTRBASE) with \PAGETABLESTOPFLG)))
          [COND
	    ((AND LOCK? (EQ \MACHINETYPE \DANDELION)
		  (SETQ SPECIALRP (\SPECIALRP VPAGE)))       (* Must actually put FILEPAGE into special RP, and thus
							     move old contents of SPECIALRP into RPTINDEX)
	      (PROG ((SRINDEX (RPTFROMRP SPECIALRP))
		     SRPTR SVP NEWFLAGS)                     (* SPECIALRP is a "real page", while RPTINDEX is an 
							     index into the real page table)
		    (SETQ SRPTR (fetch RPTRBASE of SRINDEX))
		    (CHECK (NOT (fetch (RPT LOCKED) of SRPTR)))
		    (SETQ SVP (fetch (RPT VP) of SRPTR))
		    (replace (RPT VP) of RPTRBASE with SVP)
                                                             (* Copy info about old occupants of SPECIALRP into 
							     selected RP)
		    (replace (RPT FILEPAGE) of RPTRBASE with (fetch (RPT FILEPAGE) of SRPTR))
		    (replace (RPT LOCKED) of RPTRBASE with NIL)
		    (COND
		      ((fetch (RPT OCCUPIED) of SRPTR)       (* THERE WAS ACTUALLY A PAGE THERE)
			(SETQ NEWFLAGS (\READFLAGS SVP))
			(\WRITEMAP \EMBUFVP (RPFROMRPT RPTINDEX)
				   0)                        (* Map buffer to target page)
			(\MOVEPAGE \EMBUFVP SVP)             (* MOVE DATA TO BUFFER PAGE)
			(\WRITEMAP \EMBUFVP \EMBUFRP 0)      (* Restore buffer to its proper page)
			(\WRITEMAP SVP (RPFROMRPT RPTINDEX)
				   NEWFLAGS)                 (* Set flags for page)
			))
		    (SETQ RPTINDEX SRINDEX)
		    (SETQ RPTRBASE SRPTR]                    (* Fill in new RPTINDEX with appropriate data)
          (replace (RPT VP) of RPTRBASE with VPAGE)
          (replace (RPT FILEPAGE) of RPTRBASE with FILEPAGE)
          (replace (RPT LOCKED) of RPTRBASE with LOCK?)
          (\TRANSFERPAGE VPAGE FILEPAGE RPTINDEX NIL NEWPAGEFLG])

(\LOOKUPPAGEMAP
  [LAMBDA (VP)                                               (* bvm: "13-OCT-82 15:21")

          (* Returns the pagemap entry for VP, which is expected to be in bounds. High bit of result is the lock bit.
	  Zero denotes absence)


    (PROG [(PRIMENTRY (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP]
          (RETURN (COND
		    ((EQ PRIMENTRY \EMPTYPMTENTRY)
		      0)
		    (T (\GETBASE \PAGEMAP (IPLUS PRIMENTRY (fetch (VP SECONDARYKEY) of VP])

(\LOCKEDPAGEP
  [LAMBDA (VP TEMP)                                          (* bvm: "18-Feb-85 18:08")

          (* * True if VP is locked. If TEMP is NIL consults only the locked page table; otherwise, also checks for 
"temporary" locked page)


    (OR (NEQ 0 (LOGAND (.LOCKEDVPMASK. VP)
		       (\GETBASE (.LOCKEDVPBASE. VP)
				 0)))
	(UNLESSRDSYS (AND TEMP (NOT (fetch (VMEMFLAGS VACANT) of (\READFLAGS VP)))
			  (fetch (RPT LOCKED) of (fetch RPTRBASE of (RPTFROMRP (\READRP VP])

(\MARKPAGEVACANT
  [LAMBDA (RPTR)                                             (* bvm: " 8-APR-82 16:06")

          (* * Marks the real page in this pagemap table entry VACANT)


    (CHECK (NOT \INTERRUPTABLE))
    (\WRITEMAP (fetch (RPT VP) of RPTR)
	       0 \VMAP.VACANT)
    (replace (RPT EMPTY) of RPTR with T])

(\SELECTREALPAGE
  [LAMBDA (NEWFP)                                            (* bvm: "13-Feb-85 20:28")

          (* Selects a real page, flushing it if necessary, and returns the pagenumber of the PREVIOUS page in the chain, so 
	  it can be easily spliced out. NEWFP, if supplied, is the filepage that will be read into here.
	  This might influence page choice by minimizing seek time)


    (PROG ((TRIES 0)
	   (CNTR \MAXCLEANPROBES)
	   (DISTANCE \MINSHORTSEEK)
	   LAST RP RPTR FP FLAGS)
      RETRY
          (SETQ LAST \REALPAGETABLE)
          (RETURN
	    (until (EQ (SETQ RP (fetch (RPT NEXTRP) of LAST))
		       \PAGETABLESTOPFLG)
	       do (SETQ RPTR (fetch RPTRBASE of RP))
		  [COND
		    ((fetch (RPT EMPTY) of RPTR)
		      (RETURN LAST))
		    ((NOT (fetch (RPT OCCUPIED) of RPTR))
		      (\MP.ERROR \MP.CHAIN.UNAVAIL "UNAVAILABLE page on Chain"))
		    ([AND (NOT (fetch (RPT LOCKED) of RPTR))
			  (NOT (fetch (VMEMFLAGS REFERENCED) of (SETQ FLAGS
								  (\READFLAGS (fetch (RPT VP)
										 of RPTR]
                                                             (* Page is unlocked and unreferenced, so is good 
							     candidate for flushing)
		      (COND
			([OR (NOT (fetch (VMEMFLAGS DIRTY) of FLAGS))
			     (PROGN (SETQ FP (fetch (RPT FILEPAGE) of RPTR))
				    (COND
				      ((SELECTQ \VMEM.INHIBIT.WRITE
						[NIL (SELECTQ \VMEM.FULL.STATE
							      (NIL 
                                                             (* Normal, can write anything)
								   T)
							      (T 
                                                             (* Vmem is full and clean, don't write anything)
								 NIL)
							      (PROGN 
                                                             (* Vmem is full, but sullied, so might as well write 
							     anything for which there is space)
								     (AND (ILEQ FP \LASTVMEMFILEPAGE)
									  (OR (NULL \VMEM.PURE.LIMIT)
									      (IGREATERP FP 
										 \VMEM.PURE.LIMIT]
						(NEW         (* Only allowed to write old pages, since new pages 
							     might just have to get moved a second time)
						     (ILEQ FP \VMEM.PURE.LIMIT))
						(PROGN       (* We are forbidden from writing any page)
						       NIL))
					(COND
					  ((OR (ILEQ CNTR 0)
					       (NULL NEWFP)
					       (ILESSP (IABS (IDIFFERENCE FP NEWFP))
						       DISTANCE))
                                                             (* Page is near replacement, or we have given up trying
							     for closeness)
					    T)
					  (T                 (* Page is too far away from replacement page)
					     (SETQ CNTR (SUB1 CNTR))
					     [COND
					       ((ILESSP DISTANCE \MAXSHORTSEEK)
                                                             (* Get more liberal)
						 (SETQ DISTANCE (LLSH DISTANCE 1]
					     NIL]
			  (\FLUSHPAGE RP)
			  (\MARKPAGEVACANT RPTR)
			  (RETURN LAST]
		  (SETQ LAST RPTR)
	       finally                                       (* Couldn't find an unreffed page because all pages 
							     were touched since last \UPDATECHAIN.
							     Do another, which clears ref bits, and try again)
		       (COND
			 ((EQ TRIES 0)
			   (SETQ TRIES 1)
			   (\UPDATECHAIN)
			   (GO RETRY))
			 ((AND (EQ TRIES 1)
			       \VMEM.INHIBIT.WRITE)
			   (SETQ \VMEM.INHIBIT.WRITE)
			   (COND
			     ((NEQ \MACHINETYPE \DANDELION)
                                                             (* Don't call RAID on a DLion, since the interface is 
							     so bad. Dorado user might want to know that we're 
							     smashing \VMEM.INHIBIT.WRITE)
			       (RAID "No clean vmem pages to reuse, must write one.  ↑N to continue"))
			     )
			   (GO RETRY))
			 (T (\MP.ERROR \MP.SELECTLOOP "Loop in \SELECTREALPAGE"])

(\SPECIALRP
  [LAMBDA (VP)                                               (* bvm: "29-MAR-83 17:43")
                                                             (* for \DANDELION, some virtual pages must be mapped 
							     into special real pages. This function returns the 
							     corresponding real page)
    (COND
      ((AND (IGEQ VP \VP.STACK)
	    (ILESSP VP (IPLUS \VP.STACK PAGESPERSEGMENT)))
	(IPLUS \RP.STACK (IDIFFERENCE VP \VP.STACK])

(\TRANSFERPAGE
  [LAMBDA (VP FILEPAGE RPTINDEX WRITE? NEWPAGE?)             (* bvm: "13-Feb-85 17:50")

          (* Transfers virtual page VP between page FILEPAGE of the vmem and real page RPTINDEX. WRITE? indicates direction of
	  transfer. If NEWPAGE?, then page does not exist on file, and is simply cleared)


    (PROG (NEWFLAGS)
          (COND
	    (WRITE? (FLIPCURSORBAR 15))
	    (T (FLIPCURSORBAR 0)))
          (SETQ NEWFLAGS (COND
	      (NEWPAGE? \VMAP.DIRTY)
	      (WRITE? (LOGAND (\READFLAGS VP)
			      (LOGNOT16 \VMAP.DIRTY)))
	      (T 0)))
          (COND
	    ((AND WRITE? (fetch (RPT LOCKED) of (fetch RPTRBASE of RPTINDEX)))
                                                             (* Writing a locked page: can't diddle map, because 
							     others might die, so do this in the straightforward 
							     way)
	      (\MOVEPAGE \EMBUFVP VP)                        (* Copy page into buffer, then write the buffer out)
	      (\ACTONVMEMFILE FILEPAGE \EMBUFBASE 1 T)
	      (SETQ \LASTACCESSEDVMEMPAGE FILEPAGE))
	    ((NOT NEWPAGE?)                                  (* Map the buffer page into the target real page, 
							     read/write the page, then set the map back)
	      (\WRITEMAP VP 0 \VMAP.VACANT)                  (* Unmap VP so that we don't have two virtual pages 
							     pointing at same real page)
	      (\WRITEMAP \EMBUFVP (RPFROMRPT RPTINDEX)
			 0)                                  (* Map buffer to target page)
	      (\ACTONVMEMFILE FILEPAGE \EMBUFBASE 1 WRITE?)
                                                             (* Do the i/o)
	      (\WRITEMAP \EMBUFVP \EMBUFRP 0)                (* Restore buffer to its proper page)
	      (SETQ \LASTACCESSEDVMEMPAGE FILEPAGE)))
          (\WRITEMAP VP (RPFROMRPT RPTINDEX)
		     NEWFLAGS)                               (* Set flags for page)
          (COND
	    (NEWPAGE?                                        (* Not on file yet, so clear it.
							     Couldn't do this sooner because the flags weren't set)
		      (\ZEROPAGE VP)))
          (COND
	    (WRITE? (FLIPCURSORBAR 15)
		    (\BOXIPLUS (LOCF (fetch SWAPWRITES of \MISCSTATS))
			       1))
	    (T (FLIPCURSORBAR 0)
	       (\BOXIPLUS (LOCF (fetch PAGEFAULTS of \MISCSTATS))
			  1])

(\MOVEPAGE
  [LAMBDA (TOVP FROMVP)                                      (* bvm: "27-JUN-82 15:56")
    (\BLT (create POINTER
		  PAGE# ← TOVP)
	  (create POINTER
		  PAGE# ← FROMVP)
	  WORDSPERPAGE])

(\ZEROPAGE
  [LAMBDA (VP)                                               (* hts: " 8-Oct-84 15:56")
    (PROG ((BASE (create POINTER
			 PAGE# ← VP)))
          (\PUTBASE BASE (SUB1 WORDSPERPAGE)
		    0)
          (\BLT BASE (\ADDBASE BASE 1)
		(SUB1 WORDSPERPAGE])

(\UPDATECHAIN
  [LAMBDA NIL                                                (* bvm: "17-Nov-84 21:47")
                                                             (* Sorts the page chain by reference bit)
    (CHECK (NOT \INTERRUPTABLE))
    (PROG ((RPTINDEX (fetch (RPT NEXTRP) of \REALPAGETABLE))
	   (CHAIN0 \REALPAGETABLE)
	   (CHAIN1 (\ADDBASE \REALPAGETABLE 2))
	   RPTR VP FLAGS HEAD1)
          (SETQ HEAD1 CHAIN1)

          (* HEAD1 = CHAIN1 is just a holding cell for the second Chain we temporarily create inside here.
	  Use the unused third word of the dummy header entry of \REALPAGETABLE)


          (replace (RPT NEXTRP) of CHAIN0 with \PAGETABLESTOPFLG)
          (replace (RPT NEXTRP) of CHAIN1 with \PAGETABLESTOPFLG)
          (do (SETQ RPTR (fetch RPTRBASE of RPTINDEX))
	      (SETQ VP (fetch (RPT VP) of RPTR))
	      [SETQ FLAGS (COND
		  ((fetch (RPT EMPTY) of RPTR)
		    0)
		  (T (\READFLAGS VP]
	      (COND
		((OR (fetch (VMEMFLAGS REFERENCED) of FLAGS)
		     (fetch (RPT LOCKED) of RPTR))           (* Page referenced or locked, put on CHAIN1)
		  (\WRITEMAP VP (RPFROMRPT RPTINDEX)
			     (LOGAND FLAGS (LOGNOT16 \VMAP.REF)))
                                                             (* Turn off ref bit)
		  (replace (RPT NEXTRP) of CHAIN1 with RPTINDEX)
		  (SETQ CHAIN1 RPTR))
		(T                                           (* Page was not referenced recently, put on CHAIN0)
		   (replace (RPT NEXTRP) of CHAIN0 with RPTINDEX)
		   (SETQ CHAIN0 RPTR)))
	      (SETQ RPTINDEX (fetch (RPT NEXTRP) of RPTR)) 
                                                             (* Look at next page in old chain)
	     repeatuntil (EQ RPTINDEX \PAGETABLESTOPFLG))
          (replace (RPT NEXTRP) of CHAIN1 with \PAGETABLESTOPFLG)
                                                             (* End of the line)
          (replace (RPT NEXTRP) of CHAIN0 with (fetch (RPT NEXTRP) of HEAD1))
                                                             (* Link end of CHAIN0 to beginning of CHAIN1)
          (SETQ \RPTLAST (COND
	      ((EQ HEAD1 CHAIN1)                             (* Nothing on CHAIN1 ??!!)
		CHAIN0)
	      (T CHAIN1)))                                   (* Pointer to end of complete chain)
          (SETQ \DIRTYPAGECOUNTER (SETQ \PAGEFAULTCOUNTER 0])
)
(DEFINEQ

(\NEWPAGE
  [LAMBDA (BASE NOERROR LOCK?)                               (* bvm: "13-Feb-85 16:48")

          (* * Creates and returns a new page located at virtual addr BASE)


    (UNINTERRUPTABLY
        (COND
	  [(NOT (\MISCAPPLY* (FUNCTION \DONEWPAGE)
			     BASE LOCK?))                    (* Failed, page exists)
	    (COND
	      ((NOT NOERROR)
		(\MP.ERROR \MP.NEWPAGE "Attempt to allocate already existing page" BASE T)))
	    (COND
	      (LOCK? (\LOCKPAGES BASE 1]
	  ((IGREATERP (fetch (IFPAGE NActivePages) of \InterfacePage)
		      (IDIFFERENCE \LASTVMEMFILEPAGE \GUARDVMEMFULL))
                                                             (* Vmem getting full!)
	    (\SET.VMEM.FULL.STATE)))
	BASE)])

(\DONEWPAGE
  [LAMBDA (BASE LOCK? INTERNALFLG)                           (* bvm: " 8-Dec-84 15:02")

          (* * Allocates new page at BASE, locking it if LOCK? is true. Returns vmemfile page# on success, NIL if page already
	  exists. Must be run in safe context! because it can cause vmem activity)


    (AND \DOFAULTINIT (\FAULTINIT))                          (* Only an issue when INIT.SYSOUT starts.
							     Perhaps there is a better place to put this)
    (PROG ((VP (fetch (POINTER PAGE#) of BASE))
	   MAPBASE LOCKBASE FILEPAGE NEXTPM ERRCODE)
          (RETURN (COND
		    ((fetch (VP INVALID) of VP)
		      (\INVALIDVP VP)
		      NIL)
		    (T (SETQ MAPBASE (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)))
		       (COND
			 ((EQ MAPBASE \EMPTYPMTENTRY)        (* Need to create a new second-level block)
			   (SETQ NEXTPM (fetch (IFPAGE NxtPMAddr) of \InterfacePage))
			   [COND
			     ((EVENP NEXTPM WORDSPERPAGE)

          (* Need a new secondary pagemap page. This recursion is ok, because we know that SETUPPAGEMAP assures that the 
	  pagemap pages for all the pages in secondary map space were created at MAKEINIT time)


			       (OR (\DONEWPAGE (\ADDBASE \PAGEMAP NEXTPM)
					       T T)
				   (RETURN (\MP.ERROR \MP.NEWMAPPAGE 
						     "\DONEWPAGE failed to allocate new map page"]
			   (\PUTBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)
				     NEXTPM)
			   (replace (IFPAGE NxtPMAddr) of \InterfacePage with (IPLUS NEXTPM 
										     \PMblockSize))
			   (SETQ MAPBASE NEXTPM)))
		       [SETQ MAPBASE (\ADDBASE \PAGEMAP (IPLUS MAPBASE (fetch (VP SECONDARYKEY)
									  of VP]
		       (COND
			 ((NEQ (\GETBASE MAPBASE 0)
			       0)                            (* Page exists)
			   (RETURN NIL)))
		       (SETQ FILEPAGE (add (fetch (IFPAGE NActivePages) of \InterfacePage)
					   1))
		       (replace (IFPAGE NDirtyPages) of \InterfacePage with FILEPAGE)
                                                             (* Currently a redundant field)
		       (COND
			 ((AND (IGREATERP (IMOD FILEPAGE WORDSPERPAGE)
					  (IDIFFERENCE WORDSPERPAGE 4))
			       (NOT INTERNALFLG))

          (* need a new page of \FPTOVP soon -- do it now while there's still maneuvering room. This is a no-op if it's 
	  already been done. Need to check for this 3 pages before end of current \FPTOVP page for worst case: we needed a new
	  pagemap block, then allocated this VP a page, and then the new \FPTOVP page gets the last slot on the current 
	  \FPTOVP page. Alternatively, the new \FPTOVP page needed a new pagemap block. Will never have both needing a new 
	  pagemap block, so it's not 4 pages from end)


			   (\DONEWPAGE (\ADDBASE \FPTOVP (CEIL FILEPAGE WORDSPERPAGE))
				       T T)))
		       [COND
			 (LOCK? (SETQ FILEPAGE (\MAKESPACEFORLOCKEDPAGE VP FILEPAGE))
				(\PUTBASE (SETQ LOCKBASE (.LOCKEDVPBASE. VP))
					  0
					  (LOGOR (.LOCKEDVPMASK. VP)
						 (\GETBASE LOCKBASE 0]
		       (\PUTBASE \FPTOVP FILEPAGE VP)
		       (\PUTBASE MAPBASE 0 FILEPAGE)
		       (\LOADVMEMPAGE VP FILEPAGE T LOCK?)
		       FILEPAGE])

(\MAKESPACEFORLOCKEDPAGE
  [LAMBDA (VP FILEPAGE)                                      (* bvm: " 8-Dec-84 14:29")

          (* VP is a page to be locked, FILEPAGE its home. Returns a possibly new file page where VP will now live, after 
	  having kicked the former resident of the new file page into VP's old FILEPAGE)


    (PROG ((RP (\SPECIALRP VP))
	   DESIREDFP OLDVP FPBASE)
          [SETQ DESIREDFP (COND
	      (RP                                            (* Dlion has constraints about the real page, hence 
							     about FP)
		  (DLFPFROMRP RP))
	      ((AND (ILEQ VP (IPLUS \VP.FPTOVP \NP.FPTOVP))
		    (IGREATERP VP \VP.FPTOVP))               (* A new page of FPTOVP has to be continguous on file 
							     with other such pages)
		(IPLUS VP (IDIFFERENCE (DLFPFROMRP \RP.FPTOVP)
				       \VP.FPTOVP)))
	      ((AND (ILEQ FILEPAGE (fetch LastLockedFilePage of \InterfacePage))
		    (IGREATERP FILEPAGE (DLFPFROMRP \RP.TYPETABLE)))
                                                             (* Page is in a good place already.
							     It probably was once locked, then unlocked)
		(RETURN FILEPAGE))
	      (T                                             (* Put it after all the other locked pages)
		 (add (fetch LastLockedFilePage of \InterfacePage)
		      1]
          (COND
	    ((AND (fetch FPOCCUPIED of (SETQ FPBASE (\ADDBASE \FPTOVP DESIREDFP)))
		  (NEQ (SETQ OLDVP (fetch FPVIRTUALPAGE of FPBASE))
		       VP))                                  (* Someone else lives here, so move it out)
	      (\MOVEVMEMFILEPAGE OLDVP DESIREDFP FILEPAGE)))
          (RETURN DESIREDFP])

(\MOVEVMEMFILEPAGE
  [LAMBDA (VP OLDFP NEWFP)                                   (* bvm: "18-Nov-84 14:14")
    (PROG ((FLAGS (\READFLAGS VP))
	   RP)
          (COND
	    ((fetch (VMEMFLAGS VACANT) of FLAGS)             (* Page not resident, so pull it in)
	      (\LOADVMEMPAGE VP OLDFP)
	      (SETQ FLAGS \VMAP.CLEAN))
	    ((\LOCKEDPAGEP VP)
	      (\MP.ERROR \MP.BADLOCKED "Locked page is in the way" VP)))
          (\WRITEMAP VP (SETQ RP (\READRP VP))
		     (LOGOR FLAGS \VMAP.DIRTY))              (* Mark page dirty, so that it will eventually be 
							     written to its new home)
          (replace (RPT FILEPAGE) of (fetch RPTRBASE of (RPTFROMRP RP)) with NEWFP)
                                                             (* Tell RPT where VP now lives)
          (\PUTBASE (.PAGEMAPBASE. VP)
		    0 NEWFP)                                 (* Tell \PAGEMAP about it)
          (\PUTBASE \FPTOVP NEWFP VP)                        (* ... and \FPTOVP)
      ])

(\NEWEPHEMERALPAGE
  [LAMBDA (BASE NOERROR)                                     (* bvm: "26-NOV-82 15:40")

          (* * Creates and returns a new page located at virtual addr BASE, mapping it permanently into some real page but 
	  leaving it out of the vmem file)


    (\MISCAPPLY*(FUNCTION \DONEWEPHEMERALPAGE)
      BASE NOERROR])

(\DONEWEPHEMERALPAGE
  [LAMBDA (BASE NOERROR)                                     (* bvm: "18-Nov-84 15:56")

          (* * Creates and returns a new page located at virtual addr BASE, mapping it permanently into some real page but 
	  leaving it out of the vmem file)


    (PROG ((VP (fetch (POINTER PAGE#) of BASE))
	   MAPBASE PREVRP RPTINDEX RPTR)
          (RETURN (COND
		    ((fetch (VP INVALID) of VP)
		      (\INVALIDVP VP)
		      NIL)
		    (T (SETQ MAPBASE (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)))
                                                             (* First check that the page doesn't exist)
		       (COND
			 ([OR (AND (NEQ MAPBASE \EMPTYPMTENTRY)
				   (NEQ (\GETBASE \PAGEMAP (IPLUS MAPBASE (fetch (VP SECONDARYKEY)
									     of VP)))
					0))
			      (NOT (fetch (VMEMFLAGS VACANT) of (\READFLAGS VP]
                                                             (* Page is in the vmem already, so no hope)
			   (COND
			     ((NOT NOERROR)
			       (\MP.ERROR \MP.NEWPAGE "Page already exists " BASE T)))
			   (RETURN BASE)))
		       (COND
			 ((IGREATERP \PAGEFAULTCOUNTER \UPDATECHAINFREQ)
			   (\UPDATECHAIN)))
		       (add \PAGEFAULTCOUNTER 1)
		       (SETQ PREVRP (\SELECTREALPAGE))       (* Find a page to put this in)
		       (SETQ RPTINDEX (fetch (RPT NEXTRP) of PREVRP))
		       (SETQ RPTR (fetch RPTRBASE of RPTINDEX))
		       (replace (RPT NEXTRP) of PREVRP with (fetch (RPT NEXTRP) of RPTR))
                                                             (* Splice RPTINDEX out of chain)
		       (replace (RPT NEXTRP) of RPTR with 0)
                                                             (* Fill in new RPTINDEX with appropriate data)
		       (replace (RPT VP) of RPTR with \RPT.UNAVAILABLE)
		       (replace (RPT FILEPAGE) of RPTR with VP)
                                                             (* For debugging only)
		       (FLIPCURSORBAR 0)
		       (\WRITEMAP VP (RPFROMRPT RPTINDEX)
				  \VMAP.DIRTY)               (* Set flags for page)
		       (\ZEROPAGE VP)                        (* Clear new page)
		       (FLIPCURSORBAR 0)
		       (\BOXIPLUS (LOCF (fetch PAGEFAULTS of \MISCSTATS))
				  1)
		       BASE])

(\LOCKPAGES
  [LAMBDA (BASE NPAGES)                                      (* bvm: "26-NOV-82 15:17")
                                                             (* Needs to be done in safe stack context because might 
							     cause vmem transfer)
    (\MISCAPPLY*(FUNCTION \DOLOCKPAGES)
      BASE NPAGES)
    BASE])

(\DOLOCKPAGES
  [LAMBDA (BASE NPAGES)                                      (* bvm: " 6-Dec-84 15:06")
    (for I from 0 to (SUB1 NPAGES) bind (VP ←(fetch (POINTER PAGE#) of BASE))
					FILEPAGE MAPBASE RPTBASE RP MASK LOCKBASE
       do [COND
	    ((fetch (VP INVALID) of VP)
	      (\INVALIDVP VP))
	    [(EQ (SETQ MAPBASE (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)))
		 \EMPTYPMTENTRY)
	      (\INVALIDADDR (ADDBASE BASE (UNFOLD I WORDSPERPAGE]
	    (T [SETQ MAPBASE (\ADDBASE \PAGEMAP (IPLUS MAPBASE (fetch (VP SECONDARYKEY) of VP]
	       (SETQ FILEPAGE (\GETBASE MAPBASE 0))
	       (COND
		 ((EQ 0 (LOGAND (SETQ MASK (.LOCKEDVPMASK. VP))
				(\GETBASE (SETQ LOCKBASE (.LOCKEDVPBASE. VP))
					  0)))               (* Not locked yet)
		   (COND
		     ((fetch VACANT of (\READFLAGS VP))      (* Bring locked page into core so we can move it if 
							     necessary)
		       (\LOADVMEMPAGE VP FILEPAGE NIL T)))
		   [SETQ RPTBASE (fetch RPTRBASE of (RPTFROMRP (SETQ RP (\READRP VP]
		   (COND
		     ((NEQ FILEPAGE (SETQ FILEPAGE (\MAKESPACEFORLOCKEDPAGE VP FILEPAGE)))

          (* Moving to a new page, so have to mark this locked page dirty so that it will eventually get written to its new 
	  home)


		       (\WRITEMAP VP RP (LOGOR \VMAP.DIRTY \VMAP.REF))
		       (replace (RPT FILEPAGE) of RPTBASE with FILEPAGE)
		       (\PUTBASE \FPTOVP FILEPAGE VP)
		       (\PUTBASE MAPBASE 0 FILEPAGE)))
		   (\PUTBASE LOCKBASE 0 (LOGOR MASK (\GETBASE LOCKBASE 0)))
                                                             (* Set lock bit in page map)
		   (replace (RPT LOCKED) of RPTBASE with T]
	  (add VP 1])

(\TEMPLOCKPAGES
  [LAMBDA (BASE NPAGES)                                      (* bvm: "31-MAR-83 15:01")

          (* "Temporarily" locks BASE for NPAGES, i.e. ensures that the swapper will not move the pages.
	  Information vanishes at logout etc. This function must be locked because it manipulates the page table)


    (while (IGREATERP NPAGES 0) bind (VP ←(fetch (POINTER PAGE#) of BASE))
				     RPTR
       do (UNINTERRUPTABLY
              (\TOUCHPAGE BASE)                              (* Touch page in case not resident)
	      (COND
		((AND (NEQ (SETQ RPTR (\READRP VP))
			   0)
		      (EQ [fetch (RPT VP) of (SETQ RPTR (fetch RPTRBASE of (RPTFROMRP RPTR]
			  VP))
		  (replace (RPT LOCKED) of RPTR with T))
		(T (HELP "Page table changed out from under me!" VP))))
	  (add VP 1)
	  (add NPAGES -1)
	  (SETQ BASE (\ADDBASE BASE WORDSPERPAGE])

(\TEMPUNLOCKPAGES
  [LAMBDA (BASE NPAGES)                                      (* bvm: "31-MAR-83 15:01")
                                                             (* Unlocks pages that were locked by \TEMPLOCKPAGES.
							     This function must be locked because it manipulates the 
							     page table)
    (while (IGREATERP NPAGES 0) bind (VP ←(fetch (POINTER PAGE#) of BASE))
				     RPTR
       do (UNINTERRUPTABLY
              (\TOUCHPAGE BASE)                              (* Touch page in case not resident.
							     Should only happen if page wasn't locked to begin with)
	      (COND
		((AND (NEQ (SETQ RPTR (\READRP VP))
			   0)
		      (EQ [fetch (RPT VP) of (SETQ RPTR (fetch RPTRBASE of (RPTFROMRP RPTR]
			  VP))
		  (replace (RPT LOCKED) of RPTR with NIL))
		(T (HELP "Page table changed out from under me!" VP))))
	  (add VP 1)
	  (add NPAGES -1)
	  (SETQ BASE (\ADDBASE BASE WORDSPERPAGE])

(\UNLOCKPAGES
  [LAMBDA (BASE NPAGES)                                      (* bvm: " 6-Dec-84 15:08")

          (* * Unlocks NPAGES virtual pages from BASE onward)


    (UNINTERRUPTABLY
        (for I from 0 to (SUB1 NPAGES) bind (VP ←(fetch (POINTER PAGE#) of BASE))
					    MASK LOCKBASE
	   do (COND
		((fetch (VP INVALID) of VP)
		  (\INVALIDVP VP))
		((NEQ 0 (LOGAND (SETQ MASK (.LOCKEDVPMASK. VP))
				(\GETBASE (SETQ LOCKBASE (.LOCKEDVPBASE. VP))
					  0)))               (* Yes, page was locked, so turn the bit off now)
		  (\PUTBASE LOCKBASE 0 (LOGXOR MASK (\GETBASE LOCKBASE 0)))
                                                             (* Update pagemap, then update real page table)
		  (replace (RPT LOCKED) of (fetch RPTRBASE of (RPTFROMRP (\READRP VP))) with NIL)))
	      (add VP 1)))])

(\FLUSHVM
  [LAMBDA NIL                                                (* bvm: "13-Feb-85 19:55")
                                                             (* Writes out all dirty pages to vmem, making it 
							     consistent. Returns NIL now, T if Bcpl starts up the 
							     vmem)
    (COND
      ((\FLUSHVMOK?)
	(UNINTERRUPTABLY                                     (* Write stuff out from a safe place)
	    (PROG1 (COND
		     ((\MISCAPPLY* (FUNCTION \DOFLUSHVM))    (* Return from Bcpl startup.
							     Need to rebuild the context, since it was not written 
							     out consistently)
		       (SETQ \DOFAULTINIT T)                 (* Tell pagefault handler to initialize itself.
							     Want the initialization to happen in Fault context to 
							     avoid stack overflow messiness)
		       (\CONTEXTSWITCH \FAULTFXP)
		       (for VAR in \SYSTEMCACHEVARS do (SET VAR NIL))
		       T))
		   (SETQ \DIRTYPAGEHINT 32767)))])

(\LOGOUT0
  [LAMBDA (FAST)                                             (* bvm: "13-Feb-85 20:11")
    [COND
      ((NEQ (fetch MachineType of \InterfacePage)
	    \DANDELION)                                      (* update alto clock)
	(\BLT (EMADDRESS \RTCSECONDS)
	      (LOCF (fetch SECONDSCLOCK of \MISCSTATS))
	      (UNFOLD 3 WORDSPERCELL]
    (UNINTERRUPTABLY
        (OR (AND [OR (NOT FAST)
		     (AND (EQ FAST (QUOTE ?))
			  (NOT (.VMEM.CONSISTENTP.]
		 (\FLUSHVM))
	    (\LISPFINISH)))])

(\DOFLUSHVM
  [LAMBDA NIL                                                (* bvm: "13-Feb-85 20:11")

          (* * Write everything out in a resumable way. Value is NIL if returned from directly, T if from saved state.
	  Always invoked via \MISCAPPLY*)


    (CHECK (NOT \INTERRUPTABLE))                             (* NOTE: need stats gathering off in here.
							     Also avoid touching pages)
    (PROG ((IFPVP (fetch (POINTER PAGE#) of \InterfacePage))
	   (SCRATCHBUF \EMUSWAPBUFFERS)
	   (SCRATCHVP (fetch (POINTER PAGE#) of \EMUSWAPBUFFERS))
	   IFPRPT)
          (replace (IFPAGE MISCSTACKRESULT) of \InterfacePage with T)
                                                             (* This will make it look like we have returned from 
							     BCPL if caller gets control from the saved state)
          [COND
	    ((EQ \MACHINETYPE \DANDELION)                    (* Mark all active stack pages dirty, since the 
							     microcode doesn't)
	      (for VP from \VP.STACK to (IPLUS \VP.STACK (fetch HIBYTE of (fetch EndOfStack
									     of \InterfacePage)))
		 as RP from \RP.STACK do (\WRITEMAP VP RP (LOGOR \VMAP.REF \VMAP.DIRTY)))
                                                             (* Similarly, the GC table does not get marked dirty)
	      (for VP from \VP.GCTABLE to (IPLUS \VP.GCTABLE (SUB1 \NP.GCTABLE)) as RP from 
										      \RP.GCTABLE
		 do (\WRITEMAP VP RP (LOGOR \VMAP.REF \VMAP.DIRTY]
          [COND
	    (\VMEM.PURE.LIMIT                                (* Maintaining file consistency: move high water mark 
							     up)
			      (COND
				(VMEM.COMPRESS.FLG (\DOCOMPRESSVMEM)))
			      (SETQ \VMEM.PURE.LIMIT (fetch (IFPAGE NActivePages) of \InterfacePage]
          (COND
	    ((.VMEM.CONSISTENTP.)
	      (replace (IFPAGE Key) of \InterfacePage with (LOGNOT16 \IFPValidKey))
                                                             (* Invalidate vmem and write out the Interface page)
	      (\TRANSFERPAGE IFPVP \FirstVmemBlock (RPTFROMRP (\READRP IFPVP))
			     T NIL)))
          (SETQ IFPRPT (RPTFROMRP (\READRP IFPVP)))
          (for RPTINDEX from 1 to (SUB1 \RPTSIZE) do (\FLUSHPAGE RPTINDEX T) unless (EQ RPTINDEX 
											IFPRPT))
          (replace (IFPAGE Key) of \InterfacePage with \IFPValidKey)
          (\MOVEPAGE SCRATCHVP IFPVP)                        (* Make its current fx point at user context, i.e. the 
							     \FLUSHVM frame)
          (replace (IFPAGE CurrentFXP) of SCRATCHBUF with (fetch (IFPAGE MiscFXP) of \InterfacePage))
          (\ACTONVMEMFILE (\LOOKUPPAGEMAP IFPVP)
			  SCRATCHBUF 1 T)                    (* Write the page out from a safe place)
          (RETURN NIL])

(\RELEASEWORKINGSET
  [LAMBDA NIL                                                (* bvm: "29-Nov-84 10:56")
    (COND
      ((\FLUSHVM)                                            (* Returning from Lisp startup)
	T)
      (T                                                     (* Unmap any unlocked page)
	 (for RPTINDEX from 1 to (SUB1 \RPTSIZE) bind RPTR
	    when (AND (fetch (RPT OCCUPIED) of (SETQ RPTR (fetch RPTRBASE of RPTINDEX)))
		      (NOT (fetch (RPT LOCKED) of RPTR)))
	    do (\WRITEMAP (fetch (RPT VP) of RPTR)
			  (RPFROMRPT RPTINDEX)
			  \VMAP.VACANT)
	       (replace (RPT EMPTY) of RPTR with T])

(\WRITEDIRTYPAGE
  [LAMBDA (MINDIRTY)                                         (* bvm: "15-Feb-85 00:00")
    (COND
      ((OR (NOT (.VMEM.CONSISTENTP.))
	   (AND \VMEM.PURE.LIMIT (NOT \VMEM.FULL.STATE)))
	(PROG ((RPTR (OR \LASTDIRTYSCANPTR \REALPAGETABLE))
	       (NUMDIRTY (OR \LASTDIRTYCNT 0))
	       (CNT \MAXDIRTYSCANCOUNT)
	       RP FP FLAGS)
	      [COND
		((AND (NULL \LASTDIRTYSCANPTR)
		      (IGREATERP (IPLUS (add \DIRTYPAGECOUNTER 1)
					\PAGEFAULTCOUNTER)
				 \UPDATECHAINFREQ))          (* Take this time to update the page chain instead)
		  (RETURN (UNINTERRUPTABLY
                              (\MISCAPPLY* (FUNCTION \UPDATECHAIN)))]
	      (OR MINDIRTY (SETQ MINDIRTY 1))
	  LP  [COND
		[(EQ (SETQ RP (fetch (RPT NEXTRP) of RPTR))
		     \PAGETABLESTOPFLG)                      (* Hit end of chain. Write out what we found if enough 
							     were dirty)
		  (COND
		    ((AND (IGEQ NUMDIRTY MINDIRTY)
			  (NEQ NUMDIRTY 0)
			  (SETQ RP \LASTDIRTYFOUND))
		      (GO GOTPAGE))
		    (T (SETQ \LASTDIRTYSCANPTR (SETQ \LASTDIRTYCNT (SETQ \LASTDIRTYFOUND NIL)))
		       [COND
			 ((AND (NEQ NUMDIRTY 0)
			       (ILESSP \DIRTYSEEKMAX (LRSH MAX.SMALL.INTEGER 1)))
                                                             (* Failed because page not close enough, so widen the 
							     tolerance)
			   (SETQ \DIRTYSEEKMAX (LLSH \DIRTYSEEKMAX 1]
		       (RETURN]
		((fetch (RPT EMPTY) of (SETQ RPTR (fetch RPTRBASE of RP)))
                                                             (* Page is empty. Should never happen if key is valid)
		  (RETURN))
		((NOT (fetch (RPT LOCKED) of RPTR))          (* Don't bother writing out locked pages, since they 
							     don't help us in our swapping quest)
		  (SETQ FLAGS (\READFLAGS (fetch (RPT VP) of RPTR)))
		  (COND
		    ((NOT (fetch (VMEMFLAGS DIRTY) of FLAGS))
                                                             (* Page not dirty; skip)
		      )
		    [(PROGN (SETQ FP (fetch (RPT FILEPAGE) of RPTR))
			    (IGREATERP (IABS (IDIFFERENCE (COND
							    ((AND \VMEM.PURE.LIMIT (ILESSP FP 
										 \VMEM.PURE.LIMIT))
                                                             (* We'd have to write page to a new place, not here)
							      (fetch (IFPAGE NActivePages)
								 of \InterfacePage))
							    (T FP))
							  \LASTACCESSEDVMEMPAGE))
				       \DIRTYSEEKMAX))       (* Page too far away, don't write it)
		      (COND
			((fetch (VMEMFLAGS REFERENCED) of FLAGS)
                                                             (* but still count it)
			  (add NUMDIRTY 1]
		    ((IGREATERP FP \LASTVMEMFILEPAGE)        (* Can't write it)
		      )
		    ((fetch (VMEMFLAGS REFERENCED) of FLAGS)
                                                             (* Page dirty but referenced.
							     Note it, but keep looking for a better one)
		      (COND
			((EQ NUMDIRTY 0)
			  (SETQ \LASTDIRTYFOUND RP)))
		      (add NUMDIRTY 1))
		    (T                                       (* Dirty, not referenced: do it)
		       (GO GOTPAGE]
	      (COND
		((EQ (add CNT -1)
		     0)                                      (* Scanned for long enough; don't lock user out)
		  (SETQ \LASTDIRTYSCANPTR RPTR)
		  (SETQ \LASTDIRTYCNT NUMDIRTY)
		  (RETURN)))
	      (GO LP)
	  GOTPAGE
	      (UNINTERRUPTABLY
                  (SETQ \LASTDIRTYSCANPTR (SETQ RPTR (fetch RPTRBASE of RP)))
                                                             (* Keep traveling pointer)
		  (SETQ \LASTDIRTYCNT (SETQ \LASTDIRTYFOUND NIL))
		  (COND
		    ((ILEQ (IABS (IDIFFERENCE (fetch (RPT FILEPAGE) of RPTR)
					      \LASTACCESSEDVMEMPAGE))
			   \DIRTYSEEKMAX)                    (* Could fail if swapping since the selection has moved
							     the disk arm too far)
		      (\MISCAPPLY* (FUNCTION \WRITEDIRTYPAGE1)
				   RP RPTR)))
		  (SETQ \DIRTYSEEKMAX \MAXSHORTSEEK))
	      (RETURN T])

(\WRITEDIRTYPAGE1
  [LAMBDA (RP RPTR)                                          (* bvm: "20-APR-82 15:21")
                                                             (* Write out buffer RP. This fn is locked and 
							     uninterruptable)
    (COND
      ([AND (NOT (fetch (RPT LOCKED) of RPTR))
	    (fetch (VMEMFLAGS DIRTY) of (\READFLAGS (fetch (RPT VP) of RPTR]
                                                             (* Verify that the page is still a candidate, so 
							     previous loop could be interruptable)
	(\FLUSHPAGE RP])

(\COUNTREALPAGES
  [LAMBDA (TYPE)                                             (* bvm: "18-Dec-84 15:31")
    (SELECTQ TYPE
	     [(DIRTY REF)
	       (PROG [(FLAGBITS (COND
				  ((EQ TYPE (QUOTE DIRTY))
				    \VMAP.DIRTY)
				  (T \VMAP.REF]
		     (RETURN (NPAGESMACRO (NEQ (LOGAND (\READFLAGS VP)
						       FLAGBITS)
					       0]
	     (LOCKED (NPAGESMACRO (fetch (RPT LOCKED) of RPTR)))
	     (OCCUPIED (NPAGESMACRO T))
	     (\ILLEGAL.ARG TYPE])
)
(DEFINEQ

(\DOCOMPRESSVMEM
  [LAMBDA NIL                                                (* bvm: " 7-Apr-84 17:53")

          (* * Called underneath \DOFLUSHVM to write the pages above the high water mark back to the places vacated below 
	  that mark)


    (PROG ((EMPTYFP (DLFPFROMRP \RP.GCTABLE))
	   (LASTFP (fetch NActivePages of \InterfacePage))
	   (OLDVIW \VMEM.INHIBIT.WRITE)
	   VP)
          [COND
	    ((NULL OLDVIW)                                   (* Encourage \SELECTREALPAGE to select only "old" file 
							     pages for displacement, so that we don't needlessly 
							     write the same page twice)
	      (SETQ \VMEM.INHIBIT.WRITE (QUOTE NEW]
      LP  (COND
	    ((IGEQ EMPTYFP LASTFP)
	      (SETQ \VMEM.INHIBIT.WRITE OLDVIW)
	      (RETURN)))
          [COND
	    ((EQ (\GETBASE \FPTOVP EMPTYFP)
		 \NO.VMEM.PAGE)
	      (while (EQ (SETQ VP (\GETBASE \FPTOVP LASTFP))
			 \NO.VMEM.PAGE)
		 do (SETQ LASTFP (SUB1 LASTFP)))
	      (\MOVEVMEMFILEPAGE VP LASTFP EMPTYFP)
	      (replace NActivePages of \InterfacePage with (SETQ LASTFP (SUB1 LASTFP]
          (add EMPTYFP 1)
          (GO LP])

(VMEM.PURE.STATE
  [LAMBDA FLG                                                (* bvm: " 7-Apr-84 16:59")
    (PROG1 (NOT (NULL \VMEM.PURE.LIMIT))
	   (COND
	     ((IGREATERP FLG 0)

          (* Set \VMEM.PURE.LIMIT appropriately. If turning on, and it wasn't on before, set it to -1 so that it takes 
	  effect only at the next FLUSHVM)


	       (SETQ \VMEM.PURE.LIMIT (AND (ARG FLG 1)
					   (OR \VMEM.PURE.LIMIT (SETQ \VMEM.PURE.LIMIT -1])
)
(DEFINEQ

(32MBADDRESSABLE
  [LAMBDA NIL                                                (* bvm: " 7-Mar-85 17:03")
    (SELECTC \MACHINETYPE
	     (\DORADO T)
	     (\DOLPHIN NIL)
	     (NEQ 0 (fetch (IFPAGE DL24BitAddressable) of \InterfacePage])

(\SET.VMEM.FULL.STATE
  [LAMBDA NIL                                                (* bvm: "13-Feb-85 20:12")
                                                             (* We are running out of vmem, try to extend file.
							     Do this at next convenient time)
    (COND
      ((NOT \VMEM.FULL.STATE)                                (* Get an interrupt to handle this)
	(replace VMEMFULL of \INTERRUPTSTATE with T)
	(SETQ \PENDINGINTERRUPT T)))
    (SETQ \VMEM.FULL.STATE (COND
	((ILESSP (fetch (IFPAGE NActivePages) of \InterfacePage)
		 \LASTVMEMFILEPAGE)                          (* Not completely full, allow normal things to happen)
	  0)
	((.VMEM.CONSISTENTP.)
	  T)
	(T (QUOTE DIRTY])

(\DOVMEMFULLINTERRUPT
  [LAMBDA NIL                                                (* bvm: "15-Feb-85 00:08")

          (* * Called while interruptable when vmem is full or nearly so. Tries to extend vmem file, or gives error if it 
	  can't)


    (COND
      (\EXTENDINGVMEMFILE 

          (* Another interrupt happened while we are extending file. Don't try to do this one twice, but repost the interrupt 
	  in the hopes that it will happen after vmem extension is finished)


			  (SETQ \PENDINGINTERRUPT T))
      (T (RESETVARS ((\EXTENDINGVMEMFILE T))
		    (COND
		      ((NULL (SELECTC \MACHINETYPE
				      ((LIST \DOLPHIN \DORADO)
					(\M44EXTENDVMEMFILE (IPLUS (IMAX \LASTVMEMFILEPAGE
									 (fetch (IFPAGE NActivePages)
									    of \InterfacePage))
								   \GUARDVMEMFULL 1)))
				      T))                    (* Disk declines to do it now, try later)
			(SETQ \PENDINGINTERRUPT T))
		      ((IGREATERP (IDIFFERENCE \LASTVMEMFILEPAGE \GUARDVMEMFULL)
				  (fetch (IFPAGE NActivePages) of \InterfacePage))
			(SETQ \VMEM.FULL.STATE NIL)          (* All is okay, dismiss alarm.
							     Can't disable interrupt until now to assure consistent 
							     value for \VMEM.FULL.STATE)
			(replace VMEMFULL of \INTERRUPTSTATE with NIL))
		      (T (PROG ((HELPFLAG (QUOTE BREAK!)))
			       (replace VMEMFULL of \INTERRUPTSTATE with NIL)
                                                             (* Very slight chance of losing the break if ↑E right 
							     here. Don't know how to fix this)
			       (ERROR (CONCAT "Your virtual memory backing file is "
					      (COND
						((IGEQ (fetch (IFPAGE NActivePages) of \InterfacePage)
						       \LASTVMEMFILEPAGE)
						  "complete")
						(T "near"))
					      "ly full.")
				      "Save your work & reload a.s.a.p."])

(\FLUSHVMOK?
  [LAMBDA (TYPE NOERROR)                                     (* bvm: "13-Feb-85 19:54")
    (COND
      ((SELECTQ \VMEM.FULL.STATE
		((T DIRTY)
		  T)
		NIL)
	(COND
	  ((NOT NOERROR)
	    (ERROR (CONCAT "Can't " (OR TYPE (QUOTE LOGOUT)))
		   "-- virtual memory backing file too small")))
	NIL)
      (T T])
)

(RPAQ? \UPDATECHAINFREQ 100)

(RPAQ? \PAGEFAULTCOUNTER 0)

(RPAQ? \DIRTYPAGECOUNTER 0)

(RPAQ? \DIRTYPAGEHINT 0)

(RPAQ? \LASTACCESSEDVMEMPAGE 0)

(RPAQ? \MAXSHORTSEEK 1000)

(RPAQ? \MINSHORTSEEK 20)

(RPAQ? \MAXCLEANPROBES 20)

(RPAQ? \VMEM.INHIBIT.WRITE )

(RPAQ? \VMEM.PURE.LIMIT )

(RPAQ? \VMEM.FULL.STATE )

(RPAQ? \GUARDVMEMFULL 500)

(RPAQ? VMEM.COMPRESS.FLG )

(RPAQ? \DOFAULTINIT 0)

(RPAQ? \VMEMACCESSFN )

(RPAQ? \SYSTEMCACHEVARS )

(RPAQ? \MAXSWAPBUFFERS 1)

(RPAQ? \EXTENDINGVMEMFILE )

(RPAQ? \LASTDIRTYCNT )

(RPAQ? \LASTDIRTYFOUND )

(RPAQ? \LASTDIRTYSCANPTR )

(RPAQ? \DIRTYSEEKMAX 50)



(* Errors)

(DEFINEQ

(\MP.ERROR
  [LAMBDA (CODE STRING ARG1 ARG2)                            (* bvm: " 1-APR-83 15:03")
    (COND
      ((EQ \MACHINETYPE \DANDELION)
	((OPCODES RAID)
	 CODE))
      (T (RAID STRING ARG1 ARG2])
)



(* Debugging)

(DEFINEQ

(\ACTONVMEMFILE
  [LAMBDA (FILEPAGE BUFFER NPAGES WRITEFLAG)                 (* bvm: "28-MAR-83 16:17")
    (COND
      ((EQ \MACHINETYPE \DANDELION)
	(\DL.ACTONVMEMFILE FILEPAGE BUFFER NPAGES WRITEFLAG))
      (T (\M44ACTONVMEMFILE FILEPAGE BUFFER NPAGES WRITEFLAG])

(\SHOWPAGETABLE
  [LAMBDA (MODE FILE)                                        (* bvm: "19-Feb-85 14:47")
    (RESETLST (RESETSAVE (OUTPUT FILE))
	      (RESETSAVE (RADIX 10Q))
	      (PROG ((RPTR \REALPAGETABLE)
		     (RP 0)
		     FLAGS VP STATE FIRSTONE LASTONE)
		    (printout NIL "     RP      VP           FilePage  Status" T)
		    (until (SELECTQ MODE
				    (CHAIN (EQ (SETQ RP (fetch (RPT NEXTRP) of RPTR))
					       \PAGETABLESTOPFLG))
				    (NIL (add RP 1)
					 (IGEQ RP \RPTSIZE))
				    (\ILLEGAL.ARG MODE))
		       do (SETQ RPTR (fetch RPTRBASE of RP))
			  (SETQ VP (fetch (RPT VP) of RPTR))
			  (COND
			    ((AND (NULL MODE)
				  (EQ VP STATE))
			      (SETQ LASTONE RP))
			    (T (COND
				 (LASTONE (printout NIL "ditto thru " LASTONE T)
					  (SETQ LASTONE NIL)))
			       (SETQ FIRSTONE RP)
			       (SETQ STATE VP)
			       (printout NIL .I7.8 (RPFROMRPT RP))
			       [COND
				 ((fetch (RPT EMPTY) of RPTR)
				   (PRIN1 " Empty"))
				 ((NOT (fetch (RPT OCCUPIED) of RPTR))
				   (PRIN1 " Unavailable"))
				 (T (printout NIL .I8.8 VP , # (\PRINTVP VP)
					      34Q .I6.8 (fetch (RPT FILEPAGE) of RPTR)
					      ,,)
				    (COND
				      ((fetch (RPT LOCKED) of RPTR)
					(COND
					  ((NOT (\LOCKEDPAGEP VP))
                                                             (* not permanently locked)
					    (PRIN1 "Temp")))
					(PRIN1 "Locked ")))
				    (UNLESSRDSYS (PROGN (COND
							  ((fetch (VMEMFLAGS REFERENCED)
							      of (SETQ FLAGS (\READFLAGS VP)))
							    (PRIN1 "Ref ")))
							(COND
							  ((fetch (VMEMFLAGS DIRTY) of FLAGS)
							    (PRIN1 "Dirty"]
			       (TERPRI])

(CHECKPAGEMAP
  [LAMBDA NIL                                                (* bvm: "10-Dec-84 12:40")
    (RESETFORM (RADIX 10Q)
	       (PROG ((NUMOCCUPIED 0)
		      (NUMLOCKED 0)
		      (CHAINOCCUPIED 0)
		      (CHAINLOCKED 0)
		      RPTR FPBASE FP VP RP)
		     (CHECKFPTOVP)
		     [for RPTINDEX from 1 to (SUB1 \RPTSIZE) when (fetch (RPT OCCUPIED)
								     of (SETQ RPTR
									  (fetch RPTRBASE
									     of RPTINDEX)))
			do (add NUMOCCUPIED 1)
			   (SETQ VP (fetch (RPT VP) of RPTR))
			   (SETQ FP (fetch (RPT FILEPAGE) of RPTR))
			   (COND
			     ((CHECKFPTOVP1 FP VP RPTINDEX))
			     ([NEQ VP (fetch FPVIRTUALPAGE of (SETQ FPBASE (\ADDBASE \FPTOVP FP]
			       (printout T "RPT for RP " (RPFROMRPT RPTINDEX)
					 " says VP ")
			       (\PRINTVP VP T)
			       (printout T " lives in FP " FP "; but FP Map says that FP contains ")
			       (\PRINTVP (fetch FPVIRTUALPAGE of FPBASE)
					 T)
			       (printout T T))
			     ((\LOCKEDPAGEP VP)
			       (add NUMLOCKED 1)
			       (COND
				 ((NOT (fetch (RPT LOCKED) of RPTR))
				   (printout T "VP " VP ", living in RP " (RPFROMRPT RPTINDEX)
					     " should be locked but isn't." T))
				 ((IGREATERP FP (DLRPFROMFP (fetch (IFPAGE LastLockedFilePage)
							       of \InterfacePage)))
				   (printout T "VP " VP " is locked, but living in FP " FP 
					     ", which is not in the locked page area"
					     T]
		     (PROGN (SETQ RPTR \REALPAGETABLE)       (* Check pagetable chain)
			    [while (NEQ (SETQ RP (fetch (RPT NEXTRP) of RPTR))
					\PAGETABLESTOPFLG)
			       when (fetch (RPT OCCUPIED) of (SETQ RPTR (fetch RPTRBASE of RP)))
			       do (add CHAINOCCUPIED 1)
				  (COND
				    ((fetch (RPT LOCKED) of RPTR)
				      (add CHAINLOCKED 1]
			    (COND
			      ((ILESSP CHAINOCCUPIED NUMOCCUPIED)
				(printout T NUMOCCUPIED " occupied pages, but only " CHAINOCCUPIED 
					  " are on page chain.  "
					  NUMLOCKED " pages are permanently locked; " CHAINLOCKED 
					  " pages on chain are locked somehow."
					  T])

(CHECKFPTOVP
  [LAMBDA NIL                                                (* bvm: "10-Dec-84 12:39")
    (for FP from 1 to (fetch NActivePages of \InterfacePage) as (FPBASE ←(\ADDBASE \FPTOVP 1))
       by (\ADDBASE FPBASE 1) when (fetch FPOCCUPIED of FPBASE) do (CHECKFPTOVP1 FP
										 (fetch FPVIRTUALPAGE
										    of FPBASE])

(CHECKFPTOVP1
  [LAMBDA (FP VP RPTINDEX)                                   (* bvm: "10-Dec-84 12:36")
    (PROG ((FP2 (\LOOKUPPAGEMAP VP)))
          (RETURN (COND
		    ((NEQ FP2 FP)
		      (COND
			((UNLESSRDSYS RPTINDEX)
			  (printout T "RPT for RP " (RPFROMRPT RPTINDEX)))
			(T (printout T "FP map")))
		      (printout T " says FP " FP " contains VP ")
		      (\PRINTVP VP T)
		      (printout T "; but PageMap says that page is in FP " FP2 T)
		      T])

(\LOCKED?STRING
  [LAMBDA (LOCKEDP)                                          (* bvm: "31-MAR-83 14:20")
    (COND
      (LOCKEDP " (locked)")
      (T " (unlocked)"])

(\PRINTFPTOVP
  [LAMBDA (BASE NWORDS STREAM)                               (* bvm: "19-Feb-85 13:10")
    (SETQ STREAM (GETSTREAM STREAM (QUOTE OUTPUT)))
    (OR BASE (SETQ BASE \FPTOVP))
    (OR NWORDS (SETQ NWORDS (fetch (IFPAGE NActivePages) of \InterfacePage)))
    (RESETFORM (RADIX 10Q)
	       (PROG ((LASTVP -2)
		      (NEXTFP 0)
		      FIRSTFP FIRSTVP NEXTVP LOCKEDP NEXTLOCKED)
		     (while (IGEQ NWORDS 0)
			do (add NEXTFP 1)
			   [COND
			     ((EQ NWORDS 0)
			       (SETQ NEXTVP -1))
			     ((NEQ (SETQ NEXTVP (\GETBASE (SETQ BASE (\ADDBASE BASE 1))
							  0))
				   \NO.VMEM.PAGE)
			       (SETQ NEXTLOCKED (\LOCKEDPAGEP NEXTVP]
			   [COND
			     ([COND
				 ((EQ NEXTVP \NO.VMEM.PAGE)
				   (NEQ LASTVP \NO.VMEM.PAGE))
				 (T (OR (NEQ NEXTVP (ADD1 LASTVP))
					(NEQ NEXTLOCKED LOCKEDP]
			       [COND
				 ((IGEQ LASTVP 0)
				   (COND
				     (FIRSTFP (printout STREAM FIRSTFP "-")))
				   (printout STREAM (SUB1 NEXTFP)
					     14Q)
				   (COND
				     ((EQ LASTVP \NO.VMEM.PAGE)
				       (printout STREAM "empty"))
				     (T (COND
					  (FIRSTFP (\PRINTVP FIRSTVP STREAM)
						   (PRIN1 "-" STREAM)))
					(\PRINTVP LASTVP STREAM)
					(COND
					  (LOCKEDP (PRIN1 (QUOTE *)
							  STREAM]
			       (SETQ FIRSTFP)
			       (TERPRI STREAM)
			       (SETQ FIRSTVP NEXTVP))
			     (T                              (* in a run)
				(OR FIRSTFP (SETQ FIRSTFP (SUB1 NEXTFP]
			   (SETQ LASTVP NEXTVP)
			   (SETQ LOCKEDP NEXTLOCKED)
			   (add NWORDS -1])

(\PRINTVP
  [LAMBDA (VP STREAM)                                        (* bvm: "28-MAR-83 12:40")
    (printout STREAM "{" (LRSH VP 8)
	      ","
	      (LOGAND VP 255)
	      "}"])
)
(DECLARE: EVAL@COMPILE DONTCOPY 
(DECLARE: EVAL@COMPILE 

(PUTPROPS \ACTONVMEMFILE MACRO ((X . Y)
				(SPREADAPPLY* \VMEMACCESSFN X . Y)))

(PUTPROPS .VMEM.CONSISTENTP. MACRO (NIL (EQ (fetch (IFPAGE Key) of \InterfacePage)
					    \IFPValidKey)))
)




(* Virtual page flags)

(DECLARE: EVAL@COMPILE 

(RPAQQ \VMAP.DIRTY 10000Q)

(RPAQQ \VMAP.CLEAN 0)

(RPAQQ \VMAP.REF 100000Q)

(RPAQQ \VMAP.VACANT 30000Q)

(RPAQQ \VMAP.FLAGS 170000Q)

(RPAQQ \VMAP.NOTFLAGS 7777Q)

(CONSTANTS \VMAP.DIRTY \VMAP.CLEAN \VMAP.REF \VMAP.VACANT \VMAP.FLAGS \VMAP.NOTFLAGS)
)
[DECLARE: EVAL@COMPILE 

(ACCESSFNS VMEMFLAGS ((VACANT (EQ (LOGAND DATUM \VMAP.VACANT)
				  \VMAP.VACANT))
		      (DIRTY (NEQ (LOGAND DATUM \VMAP.DIRTY)
				  0))
		      (REFERENCED (NEQ (LOGAND DATUM \VMAP.REF)
				       0))))
]
(DECLARE: EVAL@COMPILE 

(PUTPROPS LOGNOT16 MACRO ((X)
			  (LOGXOR X 177777Q)))
)




(* RPT constants)

(DECLARE: EVAL@COMPILE 

(RPAQQ \RPT.EMPTY 177776Q)

(RPAQQ \RPT.UNAVAILABLE 177777Q)

(RPAQQ \PAGETABLESTOPFLG 0)

(RPAQQ \RPTENTRYLENGTH 3)

(CONSTANTS \RPT.EMPTY \RPT.UNAVAILABLE \PAGETABLESTOPFLG \RPTENTRYLENGTH)
)
[DECLARE: EVAL@COMPILE 

(BLOCKRECORD RPT ((LOCKED FLAG)
		  (NEXTRP BITS 17Q)                          (* rp of next entry in page chain)
		  (VP WORD)                                  (* Virtual page number occupying this real page)
		  (FILEPAGE WORD)                            (* Page in Lisp.VirtualMem)
		  )
		 [ACCESSFNS RPT ([EMPTY (EQ (fetch (RPT VP) of DATUM)
					    \RPT.EMPTY)
					(COND
					  (NEWVALUE (replace (RPT VP) of DATUM with \RPT.EMPTY))
					  (T (ERROR "Invalid replace of RPT.EMPTY" DATUM]
			     [UNAVAILABLE (EQ (fetch (RPT VP) of DATUM)
					      \RPT.UNAVAILABLE)
					  (COND
					    (NEWVALUE (replace (RPT VP) of DATUM with 
										 \RPT.UNAVAILABLE))
					    (T (ERROR "Invalid replace of RPT.UNAVAILABLE" DATUM]
			     (OCCUPIED (ILESSP (fetch (RPT VP) of DATUM)
					       \RPT.EMPTY])

(ACCESSFNS RPT1 (RPTRBASE (\ADDBASE \REALPAGETABLE (TIMES3 DATUM)))
                                                             (* Given a RP, RPTRBASE produces a pointer to its entry
							     in the real page table)
		)
]
(DECLARE: EVAL@COMPILE 

(PUTPROPS RPFROMRPT MACRO ((RPTINDEX)
			   (IPLUS RPTINDEX \RPOFFSET)))

(PUTPROPS RPTFROMRP MACRO ((RP)
			   (IDIFFERENCE RP \RPOFFSET)))

(PUTPROPS NPAGESMACRO MACRO ((FORM)
			     (PROG ((RESULT 0)
				    (CNTR \RPTSIZE)
				    (RPTR \REALPAGETABLE)
				    VP)                      (* Note order of loop: \REALPAGETABLE is dummy entry, 
							     so don't look at it, start at next entry)
			       LP  (COND
				     ((NEQ (SETQ CNTR (SUB1 CNTR))
					   0)
				       (SETQ RPTR (\ADDBASE RPTR \RPTENTRYLENGTH))
				       (COND
					 ((AND (fetch (RPT OCCUPIED) of RPTR)
					       (PROGN (SETQ VP (fetch (RPT VP) of RPTR))
						      FORM))
					   (add RESULT 1)))
				       (GO LP)))
			           (RETURN RESULT))))
)




(* Virtual to file pagemap)

(* FOLLOWING DEFINITIONS EXPORTED)


(DECLARE: EVAL@COMPILE 

(RPAQQ \MAXFILEPAGE 177776Q)

(CONSTANTS \MAXFILEPAGE)
)


(* END EXPORTED DEFINITIONS)

(DECLARE: EVAL@COMPILE 

(RPAQQ \EMPTYPMTENTRY 177777Q)

(CONSTANTS \EMPTYPMTENTRY)
)
[DECLARE: EVAL@COMPILE 

(ACCESSFNS VP ((PRIMARYKEY (LRSH DATUM 5))
	       (SECONDARYKEY (LOGAND DATUM 37Q))
	       (INVALID (PROGN NIL))))
]
(DECLARE: EVAL@COMPILE 

(PUTPROPS .PAGEMAPBASE. MACRO [OPENLAMBDA (VPAGE)
					  (\ADDBASE \PAGEMAP (IPLUS (\GETBASE \PageMapTBL
									      (fetch (VP PRIMARYKEY)
										 of VPAGE))
								    (fetch (VP SECONDARYKEY)
								       of VPAGE])
)




(* FP to VP stuff)

[DECLARE: EVAL@COMPILE 

(BLOCKRECORD FPTOVP ((FPVIRTUALPAGE WORD))
		    [ACCESSFNS FPTOVP ((FPOCCUPIED (NEQ (\GETBASE DATUM 0)
							\NO.VMEM.PAGE])
]
(DECLARE: EVAL@COMPILE 

(RPAQQ \NO.VMEM.PAGE 177777Q)

(CONSTANTS \NO.VMEM.PAGE)
)
(DECLARE: EVAL@COMPILE 

(PUTPROPS DLRPFROMFP MACRO ((FP)
			    (ADD1 FP)))

(PUTPROPS DLFPFROMRP MACRO ((RP)
			    (SUB1 RP)))
)


(PUTPROPS \TOUCHPAGE DOPVAL (1 GETBASE.N 0))

(PUTPROPS TIMES3 DOPVAL (1 COPY LLSH1 IPLUS2))




(* Locked page table)

(DECLARE: EVAL@COMPILE 

(PUTPROPS .LOCKEDVPBASE. MACRO ((VP)
				(\ADDBASE \LOCKEDPAGETABLE (FOLDLO VP BITSPERWORD))))

(PUTPROPS .LOCKEDVPMASK. MACRO ((VP)
				(LLSH 1 (IMOD VP BITSPERWORD))))
)

(DECLARE: EVAL@COMPILE 

(RPAQQ \MAXDIRTYSCANCOUNT 144Q)

(RPAQQ \MINVMEMSPAREPAGES 144Q)

(RPAQQ \DLBUFFERPAGES 20Q)

(CONSTANTS \MAXDIRTYSCANCOUNT \MINVMEMSPAREPAGES \DLBUFFERPAGES)
)

(DECLARE: EVAL@COMPILE 

(RPAQQ 2MBPAGES 10000Q)

(CONSTANTS 2MBPAGES)
)

(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \UPDATECHAINFREQ \REALPAGETABLE \RPTLAST \RPOFFSET \RPTSIZE \LOCKEDPAGETABLE \EMBUFBASE 
	    \EMBUFVP \EMBUFRP \PAGEFAULTCOUNTER \LASTDIRTYCNT \LASTDIRTYFOUND \LASTDIRTYSCANPTR 
	    \MACHINETYPE \LASTACCESSEDVMEMPAGE \MAXSHORTSEEK \MAXCLEANPROBES \MINSHORTSEEK 
	    \DIRTYSEEKMAX \DIRTYPAGECOUNTER \DIRTYPAGEHINT \VMEM.INHIBIT.WRITE \VMEM.PURE.LIMIT 
	    \VMEM.FULL.STATE \GUARDVMEMFULL VMEM.COMPRESS.FLG \KBDSTACKBASE \MISCSTACKBASE 
	    \DOFAULTINIT \FPTOVP \VMEMACCESSFN \SYSTEMCACHEVARS \LASTVMEMFILEPAGE \EXTENDINGVMEMFILE)
)

(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \#SWAPBUFFERS \#EMUBUFFERS \#DISKBUFFERS \MAXSWAPBUFFERS \EMUSWAPBUFFERS \EMUBUFFERS 
	    \TELERAIDBUFFER \EMUDISKBUFFERS \EMUDISKBUFEND)
)
)
(* * MAKEINIT stuff)

(DEFINEQ

(ADDPME
  [LAMBDA (VP NEWPAGEOK)                                     (* bvm: " 6-Dec-84 14:07")
                                                             (* add an entry for VP to the PAGEMAP.
							     Called only under MAKEINIT)
    (PROG (PX PMP LOCKBASE)
          [COND
	    ((IEQ (SETQ PMP (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)))
		  \EmptyPMTEntry)                            (* empty entries in the PageMapTBL have 177777q as 
							     their value)
	      (COND
		((EVENP NEXTPM WORDSPERPAGE)                 (* must add a new page map page)
		  (SETQ PX (\ADDBASE \PAGEMAP NEXTPM))
		  (OR NEWPAGEOK (IGREATERP (PAGELOC PX)
					   VP)
		      (HELP "page map needs new page after page map written out"))
		  (\NEWPAGE PX NIL T)))
	      (\PUTBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)
			(SETQ PMP NEXTPM))
	      (SETQ NEXTPM (IPLUS NEXTPM \PMblockSize]
          (SETQ PX (IPLUS PMP (fetch (VP SECONDARYKEY) of VP)))
          (COND
	    ((NEQ (\GETBASE \PAGEMAP PX)
		  0)
	      (HELP "page already in pagemap" VP))
	    (T (\PUTBASE \PAGEMAP PX NEXTVMEM)
	       [COND
		 ((LOCKEDPAGEP VP)                           (* Set lock bit in locked page table)
		   (\PUTBASE (SETQ LOCKBASE (.LOCKEDVPBASE. VP))
			     0
			     (LOGOR (.LOCKEDVPMASK. VP)
				    (\GETBASE LOCKBASE 0]
	       (SETQ NEXTVMEM (ADD1 NEXTVMEM])

(CHECKIFPAGE
  [LAMBDA NIL                                                (* mjs "19-Jul-84 13:24")
    (CHECKIF Key EQUAL \IFPValidKey "Interface page key"])

(DUMPINITPAGES
  [LAMBDA (CODEFIRSTPAGE CODENEXTPAGE VERSIONS)              (* bvm: "14-Jan-85 12:51")
                                                             (* called only under MAKEINIT)
    (ADDPME (PAGELOC \InterfacePage)
	    T)                                               (* THE INTERFACE PAGE MUST BE THE FIRST PAGE)
    (for I from CODEFIRSTPAGE to (SUB1 CODENEXTPAGE)
       do                                                    (* add the pagemap entries for the pages which were 
							     written directly to the file)
	  (ADDPME I T))
    (MAPPAGES 0 (ADD1 \MAXVMPAGE)
	      (FUNCTION MAKEROOMFORPME))
    (MAPPAGES 0 (ADD1 \MAXVMPAGE)
	      (FUNCTION ADDPME))
    (PROGN                                                   (* set interface page locations -
							     stack pointers already set up IN SETUPSTACK)
	   (replace (IFPAGE NxtPMAddr) of \InterfacePage with NEXTPM)
	   (replace (IFPAGE NActivePages) of \InterfacePage with (SUB1 NEXTVMEM))
	   (replace (IFPAGE NDirtyPages) of \InterfacePage with (SUB1 NEXTVMEM))
	   (replace (IFPAGE filePnPMP0) of \InterfacePage with (\GETBASE \PAGEMAP 0))
	   (replace (IFPAGE filePnPMT0) of \InterfacePage with (\GETBASE (.PAGEMAPBASE. (PAGELOC
											  \PageMapTBL)
											)
									 0))
	   [COND
	     (VERSIONS (replace (IFPAGE LVersion) of \InterfacePage with (CAR VERSIONS))
		       (replace (IFPAGE MinBVersion) of \InterfacePage with (CADDR VERSIONS))
		       (replace (IFPAGE MinRVersion) of \InterfacePage with (CADR VERSIONS]
	   (replace (IFPAGE Key) of \InterfacePage with \IFPValidKey))
    (MAPPAGES 0 (ADD1 \MAXVMPAGE)
	      (FUNCTION DUMPVP))
    (ALLOCAL (PROG ((FILE (OUTPUT)))
	           [COND
		     ((NOT (RANDACCESSP FILE))               (* SYSOUT file is sequential;
							     have to get it random access for this)
		       (OUTPUT (SETQ FILE (OPENFILE (CLOSEF FILE)
						    (QUOTE BOTH]
	           (SETFILEPTR FILE MKI.Page0Byte)))
    (DUMPVP (PAGELOC \InterfacePage])

(MAKEROOMFORPME
  [LAMBDA (VP)                                               (* bvm: "29-MAR-83 17:11")
                                                             (* make sure that the pagemap-page for page VP exists;
							     we later will want to add it to the pagemap)
    (COND
      ((IEQ (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP))
	    \EmptyPMTEntry)                                  (* empty entries in the PageMapTBL have 177777q as their
							     value)
	(COND
	  ((EVENP NEXTPM WORDSPERPAGE)                       (* must add a new page map page)
	    (\NEWPAGE (\ADDBASE \PAGEMAP NEXTPM)
		      NIL T)))
	(\PUTBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)
		  NEXTPM)
	(SETQ NEXTPM (IPLUS NEXTPM \PMblockSize])

(MAPPAGES
  [LAMBDA (BOT TOP FN)                                       (* lmm "26-MAR-81 12:23")
    (PROG ((VP BOT)
	   (IVP (PAGELOC \InterfacePage)))
      LP  (COND
	    ((AND (SETQ VP (MKI.NEXTPAGE VP))
		  (IGREATERP TOP VP))
	      (COND
		((NOT (IEQ VP IVP))
		  (APPLY* FN VP)))
	      (SETQ VP (ADD1 VP))
	      (GO LP])

(READPAGEMAP
  [LAMBDA NIL                                                (* bvm: "10-Dec-84 21:54")
                                                             (* called only under READSYS -- reads in pagemap so 
							     that SETVMPTR can work)
    (PROG (D)
          (LOCAL (MAPVMPAGE (fetch (POINTER PAGE#) of \InterfacePage)
			    1))                              (* Install interface page by magic)

          (* PROGN (SETQ FPSTART (fetch (IFPAGE LastDominoFilePage) of \InterfacePage)) (SETQ NPAGES (fetch 
	  (IFPAGE NActivePages) of \InterfacePage)) (* Note: have to do these fetches before the SETFILEPTR since they 
	  indirectly do SETFILEPTR themselves) (SETFILEPTR VMEMFILE (IPLUS (UNFOLD (SUB1 (fetch (IFPAGE FPTOVPStart) of 
	  \InterfacePage)) BYTESPERPAGE) (UNFOLD FPSTART BYTESPERWORD))) (for I from FPSTART to NPAGES bind VP when 
	  (NEQ (SETQ VP (VBIN2)) \NO.VMEM.PAGE) do (* Read in all of FPTOVP) (MAPVMPAGE VP (SUB1 I))))


          [LOCAL (MAPVMPAGE (PAGELOC \PAGEMAP)
			    (SUB1 (fetch (IFPAGE filePnPMP0) of \InterfacePage]
                                                             (* map in first page of secondary page map, which is 
							     where all the secondary map pages themselves live)
          (LOCAL (SETVMPTR \PAGEMAP))
          (for I from 0 to (SUB1 (FOLDHI PAGESPERSEGMENT \PMblockSize)) as VP from (PAGELOC \PAGEMAP)
	     by \PMblockSize
	     do                                              (* Have to read all the addresses of secondary map 
							     pages themselves before we can read their contents)
		(READPAGEMAPBLOCK VP))
          (for J from 0 to (SUB1 \NumPMTpages) as FP from (SUB1 (fetch (IFPAGE filePnPMT0)
								   of \InterfacePage))
	     do                                              (* read in all the primary map table pages)
		(LOCAL (MAPVMPAGE (IPLUS (PAGELOC \PageMapTBL)
					 J)
				  FP)))
          (for I from 0 to (SUB1 (UNFOLD \NumPMTpages WORDSPERPAGE))
	     do (COND
		  ((IEQ (SETQ D (GETBASE \PageMapTBL I))
			\EmptyPMTEntry))
		  (T (LOCAL (SETVMPTR (ADDBASE \PAGEMAP D)))
		     (READPAGEMAPBLOCK (UNFOLD I \PMblockSize])

(READPAGEMAPBLOCK
  [LAMBDA (VP)                     (* lmm " 4-MAY-82 21:12")
    (PROG ((B VP)
	   P)
          (FRPTQ \PMblockSize [COND
		   ((NEQ (SETQ P (VBIN2))
			 0)
		     (LOCAL (MAPVMPAGE B (SUB1 P]
		 (SETQ B (ADD1 B])

(SETUPPAGEMAP
  [LAMBDA NIL                                                (* bvm: " 8-Dec-84 14:52")
                                                             (* called only from MAKEINIT to initialize the page 
							     map)
    (PROG NIL                                                (* set up page map)
          (\NEWPAGE \PAGEMAP NIL T)
          (CREATEPAGES \PageMapTBL \NumPMTpages NIL T)       (* init PageMapTBL pages to 177777q)
          (for I from 0 to (SUB1 (UNFOLD \NumPMTpages WORDSPERPAGE)) do (\PUTBASE \PageMapTBL I 
										  \EmptyPMTEntry))
          (SETQ NEXTPM 0)
          (for I from 0 to (SUB1 (fetch (VP PRIMARYKEY) of \NumPageMapPages))
	     bind (PAGEMAPKEY ←(fetch (VP PRIMARYKEY) of (PAGELOC \PAGEMAP)))
	     do 

          (* Assign pagemap pages to cover all pagemap pages, so that \DONEWPAGE can guarantee that when it needs to allocate 
	  a new pagemap page, that the pagemap page for the new page already exists)


		(\PUTBASE \PageMapTBL (IPLUS PAGEMAPKEY I)
			  NEXTPM)
		(SETQ NEXTPM (IPLUS NEXTPM \PMblockSize)))
          (SETQ NEXTVMEM \FirstVmemBlock)                    (* add entry for InterfacePage which must be on 
							     FirstVMemBlock)
          (CREATEPAGES \LOCKEDPAGETABLE \NumLPTPages NIL T])
)
(DECLARE: DONTCOPY 
(DECLARE: EVAL@COMPILE 

(PUTPROPS CHECKIF MACRO [(FLD COMPARISON VALUE STR)
			 (COND
			   ((NOT (COMPARISON VALUE (fetch (IFPAGE FLD) of \InterfacePage)))
			     (printout T "Warning: " STR "= " (PROGN VALUE)
				       ", but \InterfacePage says "
				       (fetch (IFPAGE FLD) of \InterfacePage)
				       T])
)


(ADDTOVAR INEWCOMS (FNS DUMPINITPAGES)
		   (VARS INITCONSTANTS)
		   (FNS SETUPPAGEMAP ADDPME MAKEROOMFORPME MAPPAGES))

(ADDTOVAR RDCOMS (FNS READPAGEMAP READPAGEMAPBLOCK CHECKIFPAGE \LOCKEDPAGEP \LOOKUPPAGEMAP 
		      CHECKPAGEMAP CHECKFPTOVP CHECKFPTOVP1 \SHOWPAGETABLE \PRINTFPTOVP))

(ADDTOVAR EXPANDMACROFNS CHECKIF .LOCKEDVPBASE. .LOCKEDVPMASK. .PAGEMAPBASE.)

(ADDTOVAR MKI.SUBFNS (\NEWPAGE . MKI.NEWPAGE)
		     (\LOCKPAGES . MKI.LOCKPAGES))

(ADDTOVAR RD.SUBFNS (\NEWPAGE . VNEWPAGE)
		    (\LOCKPAGES . VLOCKPAGES))

(ADDTOVAR RDPTRS (\REALPAGETABLE))

(ADDTOVAR RDVALS (\RPTSIZE))
EVAL@COMPILE 

(ADDTOVAR DONTCOMPILEFNS DUMPINITPAGES SETUPPAGEMAP ADDPME MAKEROOMFORPME MAPPAGES READPAGEMAP 
				       READPAGEMAPBLOCK CHECKIFPAGE)
)
(DEFINEQ

(\LOCKFN
  [LAMBDA (FN)                                               (* bvm: "22-NOV-82 17:39")
    [\LOCKCELL (SETQ FN (fetch (LITATOM DEFINITIONCELL) of (EVQ FN]
    (COND
      ((fetch (DEFINITIONCELL CCODEP) of FN)
	(\LOCKCODE (fetch (DEFINITIONCELL DEFPOINTER) of FN])

(\LOCKCODE
  [LAMBDA (CODEBLOCK)                                        (* rmk: "15-Aug-84 13:35")
    (\LOCKWORDS CODEBLOCK (UNFOLD (\#BLOCKDATACELLS CODEBLOCK)
				  WORDSPERCELL])

(\LOCKVAR
  [LAMBDA (VAR)                    (* lmm " 5-APR-82 00:43")
    (\LOCKCELL (fetch (LITATOM VCELL) of (EVQ VAR])

(\LOCKCELL
  [LAMBDA (X NPGS)                                           (* bvm: "22-NOV-82 17:54")
    (\LOCKPAGES (PAGEBASE X)
		(OR NPGS 1])

(\LOCKWORDS
  [LAMBDA (BASE NWORDS)                                      (* bvm: "22-NOV-82 17:35")
    (\LOCKPAGES (PAGEBASE BASE)
		(COND
		  (NWORDS (FOLDHI (IPLUS (fetch (POINTER WORDINPAGE) of BASE)
					 NWORDS)
				  WORDSPERPAGE))
		  (T 1])
)
(DECLARE: DONTCOPY 

(ADDTOVAR INEWCOMS (FNS \LOCKFN \LOCKVAR \LOCKCELL \LOCKWORDS \LOCKCODE)
	  (ALLOCAL (ADDVARS (LOCKEDFNS \FAULTHANDLER \FAULTINIT \D01.FAULTINIT \DL.FAULTINIT 
				       \CHAIN.UP.RPT \MAKESPACEFORLOCKEDPAGE \PAGEFAULT \READRP 
				       \READFLAGS \WRITEMAP \LOOKUPPAGEMAP \LOCKEDPAGEP \LOADVMEMPAGE 
				       \INVALIDADDR \INVALIDVP \SELECTREALPAGE \TRANSFERPAGE 
				       \SPECIALRP \UPDATECHAIN \MARKPAGEVACANT \FLUSHPAGE \CLEARWORDS 
				       \MOVEPAGE \ZEROPAGE \FLUSHVM \DONEWPAGE \DONEWEPHEMERALPAGE 
				       \WRITEDIRTYPAGE1 \COPYSYS0 \COPYSYS0SUBR \RELEASEWORKINGSET 
				       \DOFLUSHVM \DOLOCKPAGES \TEMPLOCKPAGES \TEMPUNLOCKPAGES 
				       \MP.ERROR RAID \DL.NEWFAULTINIT \DL.MARK.PAGES.UNAVAILABLE 
				       \DL.UNMAPPAGES \DL.ASSIGNBUFFERS \D01.ASSIGNBUFFERS 
				       \DOCOMPRESSVMEM \MOVEVMEMFILEPAGE)
			    (LOCKEDVARS \REALPAGETABLE \RPTLAST \PAGEFAULTCOUNTER \UPDATECHAINFREQ 
					\RPOFFSET \RPTSIZE \LOCKEDPAGETABLE \EMBUFBASE \EMBUFVP 
					\EMBUFRP \LASTACCESSEDVMEMPAGE \MAXSHORTSEEK \MAXCLEANPROBES 
					\MINSHORTSEEK \DIRTYPAGECOUNTER \DIRTYPAGEHINT 
					\VMEM.INHIBIT.WRITE \VMEM.PURE.LIMIT \VMEM.FULL.STATE 
					\GUARDVMEMFULL VMEM.COMPRESS.FLG \KBDSTACKBASE \MISCSTACKBASE 
					\DOFAULTINIT \FPTOVP \MACHINETYPE \VMEMACCESSFN 
					\TELERAIDBUFFER \EMUDISKBUFFERS \EMUDISKBUFEND 
					\MAXSWAPBUFFERS \EMUBUFFERS \#EMUBUFFERS \#SWAPBUFFERS 
					\#DISKBUFFERS \RCLKSECOND \RCLKMILLISECOND \VALSPACE 
					\EMUSWAPBUFFERS \EM.CURSORBITMAP \PAGEMAP \PageMapTBL 
					\IOCBPAGE \IOPAGE \MISCSTATS \DEFSPACE \InterfacePage 
					\LASTVMEMFILEPAGE))))
)



(* Clock stuff)

(DEFINEQ

(\CLOCK0
  [LAMBDA (BOX)                                              (* lmm "11-Sep-84 11:58")

          (* Stores millisecond clock in BOX. Do this by fetching the current millisecond clock and adding in the number of 
	  milliseconds since the clock was last updated)


    (SETQ BOX (\DTEST BOX (QUOTE FIXP)))
    (UNINTERRUPTABLY
        (\GETINTERNALCLOCK \OFFSET.MILLISECONDS BOX)
	[bind (EXCESS ←(LOCF (fetch EXCESSTIMETMP of \MISCSTATS))) while (OR (IGREATERP EXCESS 
										      \RCLKSECOND)
									     (ILESSP EXCESS 0))
	   do 

          (* Excess time. unsigned, is more than a second, so clock has not been updated in ages (perhaps someone sat in 
	  Raid for a while). We don't want IQUOTIENT here to do a CREATECELL, so do some of the division by subtraction.
	  Instead of \RCLKSECOND, it would really be better to use \RCLKMILLISECOND*MAX.SMALL.INTEGER, but this is a rare 
	  case already, so be lazy)


	      (\BOXIPLUS BOX 1750Q)
	      (\BOXIDIFFERENCE EXCESS \RCLKSECOND)
	   finally                                           (* Now it is safe to use IQUOTIENT)
		   (RETURN (\BOXIPLUS BOX (IQUOTIENT (if (IGREATERP EXCESS MAX.SMALL.INTEGER)
							 then EXCESS
						       else (fetch (FIXP LONUM) OF EXCESS))
						     \RCLKMILLISECOND])])

(\DAYTIME0
  [LAMBDA (BOX)                                              (* bvm: "24-JUN-82 15:39")
    (UNINTERRUPTABLY
        (\GETINTERNALCLOCK \OFFSET.SECONDS (\DTEST BOX (QUOTE FIXP))))])

(\GETINTERNALCLOCK
  [LAMBDA (CLOCKOFFSET BOX)                                  (* bvm: "24-JUN-82 15:39")

          (* Stores in BOX the contents of internal timer denoted by CLOCKOFFSET (0 = SECONDS, 2 = MILLISECONDS). Excess 
	  time is in EXCESSTIMETEMP. Must be called UNINTERRUPTABLY)


    (\BLT (LOCF (fetch SECONDSTMP of \MISCSTATS))
	  (LOCF (fetch SECONDSCLOCK of \MISCSTATS))
	  (UNFOLD 3 WORDSPERCELL))                           (* Copy system clocks into scratch area, so there is no 
							     update conflict)
    (\BLT BOX (\ADDBASE (LOCF (fetch SECONDSTMP of \MISCSTATS))
			CLOCKOFFSET)
	  WORDSPERCELL)                                      (* Copy clock to caller)
    (\BOXIDIFFERENCE (\RCLK (LOCF (fetch EXCESSTIMETMP of \MISCSTATS)))
		     (LOCF (fetch BASETMP of \MISCSTATS)))   (* Compute processor time since clock was updated)
    BOX])

(\SETDAYTIME0
  [LAMBDA (BOX)                                              (* bvm: "17-Nov-84 17:44")
                                                             (* Sets the seconds calendar to contents of BOX)
    (SETQ BOX (\DTEST BOX (QUOTE FIXP)))
    (UNINTERRUPTABLY
        (\RCLK (LOCF (fetch BASETMP of \MISCSTATS)))         (* Reset the base; clocks will not be adjusted for at 
							     least a second after this)
	(\BLT (LOCF (fetch SECONDSTMP of \MISCSTATS))
	      BOX WORDSPERCELL)
	(\BLT (LOCF (fetch SECONDSCLOCK of \MISCSTATS))
	      (LOCF (fetch SECONDSTMP of \MISCSTATS))
	      (UNFOLD 3 WORDSPERCELL))                       (* Finally store them all at once, uninterruptably)
	[COND
	  ((EQ \MACHINETYPE \DANDELION)                      (* Tell the iop the new time, too)
	    (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE)
			       \DL.PROCESSORBUSY))
	    (replace DLPROCESSOR2 of \IOPAGE with (\GETBASE BOX 1))
	    (replace DLPROCESSOR1 of \IOPAGE with (\GETBASE BOX 0))
	    (replace DLPROCESSORCMD of \IOPAGE with \DL.SETTOD)
	    (replace DLTODVALID of \IOPAGE with 0)
	    (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE)
			       \DL.PROCESSORBUSY))
	    (repeatwhile (EQ (fetch DLTODVALID of \IOPAGE)
			     0])
    BOX])

(CLOCKDIFFERENCE
  [LAMBDA (OLDCLOCK)                                         (* bvm: "24-JUN-82 15:40")
    (UNINTERRUPTABLY
        (IPLUS (\BOXIDIFFERENCE (\CLOCK0 (LOCF (fetch CLOCKTEMP0 of \MISCSTATS)))
				OLDCLOCK)))])

(\SECONDSCLOCKGREATERP
  [LAMBDA (OLDCLOCK SECONDS)                                 (* bvm: " 7-Dec-83 15:27")
    (UNINTERRUPTABLY
        (\BLT (LOCF (fetch CLOCKTEMP0 of \MISCSTATS))
	      (LOCF (fetch SECONDSCLOCK of \MISCSTATS))
	      WORDSPERCELL)
	(IGREATERP (\BOXIDIFFERENCE (LOCF (fetch CLOCKTEMP0 of \MISCSTATS))
				    OLDCLOCK)
		   SECONDS))])

(\CLOCKGREATERP
  [LAMBDA (OLDCLOCK MSECS)                                   (* bvm: "17-Dec-83 16:38")

          (* * True if more than MSECS milliseconds have elapsed since OLDCLOCK was set)


    (UNINTERRUPTABLY
        (IGREATERP (\BOXIDIFFERENCE (\CLOCK0 (LOCF (fetch CLOCKTEMP0 of \MISCSTATS)))
				    OLDCLOCK)
		   MSECS))])

(\RCLOCK0
  (LAMBDA (BOX)                                              (* JonL "19-APR-83 01:47")
    (\RCLK (\DTEST BOX (QUOTE FIXP)))))
)
(DEFINEQ

(CLOCK0
  [LAMBDA (BOX)                                              (* bvm: " 1-APR-83 15:26")

          (* Store millisecond clock at BOX. Unfortunately, there are still a few folks that call this without a true box, 
	  so accomodate them for now)


    (COND
      ((EQ (NTYPX BOX)
	   \FIXP)
	(\CLOCK0 BOX))
      (T (\MP.ERROR \MP.CLOCK0 "Call to CLOCK0 with arg not a number box.  ↑N to continue." BOX)
	 (UNINTERRUPTABLY
             (\BLT BOX (\CLOCK0 (LOCF (fetch CLOCKTEMP0 of \MISCSTATS)))
		   WORDSPERCELL))
	 BOX])
)
(DECLARE: EVAL@COMPILE 

(PUTPROPS \RCLOCK0 DMACRO [(BOX)
			   (\RCLK (\DTEST BOX (QUOTE FIXP])
)
(DECLARE: DONTCOPY 
(* FOLLOWING DEFINITIONS EXPORTED)


(DECLARE: EVAL@COMPILE 

(PUTPROPS \UPDATETIMERS MACRO [NIL 

          (* * Moves excess time from the processor clock to our software clocks. Needs to be run often, uninterruptably, 
	  preferably from the vertical retrace interrupt)

                                                             (* Get processor clock)
				   (PROG [(EXCESS (\BOXIDIFFERENCE (\RCLK (LOCF (fetch RCLKTEMP0
										   of \MISCSTATS)))
								   (LOCF (fetch BASECLOCK
									    of \MISCSTATS]
				         (RETURN (COND
						   ((OR (IGEQ EXCESS \RCLKSECOND)
							(ILESSP EXCESS 0))
                                                             (* More than one second has elapsed since we updated 
							     clocks)
						     (\BOXIPLUS (LOCF (fetch BASECLOCK of \MISCSTATS))
								\RCLKSECOND)
                                                             (* Increment base by one second)
						     (\BOXIPLUS (LOCF (fetch MILLISECONDSCLOCK
									 of \MISCSTATS))
								1750Q)
                                                             (* Increment clocks by 1 second)
						     (\BOXIPLUS (LOCF (fetch SECONDSCLOCK
									 of \MISCSTATS))
								1)
						     T])
)


(* END EXPORTED DEFINITIONS)

)
(DECLARE: DONTEVAL@LOAD DOCOPY 
(MOVD (QUOTE \DAYTIME0)
      (QUOTE DAYTIME0))
)

(RPAQQ \RCLKMILLISECOND 3220Q)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \RCLKSECOND \RCLKMILLISECOND)
)
(DECLARE: DONTCOPY 
(* FOLLOWING DEFINITIONS EXPORTED)


(DECLARE: EVAL@COMPILE 

(RPAQQ \RTCSECONDS 572Q)

(RPAQQ \RTCMILLISECONDS 574Q)

(RPAQQ \RTCBASE 576Q)

(RPAQQ \OFFSET.SECONDS 0)

(RPAQQ \OFFSET.MILLISECONDS 2)

(RPAQQ \OFFSET.BASE 4)

(RPAQQ \ALTO.RCLKSECOND 6321200Q)

(RPAQQ \ALTO.RCLKMILLISECOND 3220Q)

(RPAQQ \DLION.RCLKMILLISECOND 43Q)

(RPAQQ \DLION.RCLKSECOND 103672Q)

(CONSTANTS (\RTCSECONDS 572Q)
	   (\RTCMILLISECONDS 574Q)
	   (\RTCBASE 576Q)
	   (\OFFSET.SECONDS 0)
	   (\OFFSET.MILLISECONDS 2)
	   (\OFFSET.BASE 4)
	   (\ALTO.RCLKSECOND 6321200Q)
	   (\ALTO.RCLKMILLISECOND 3220Q)
	   (\DLION.RCLKMILLISECOND 43Q)
	   (\DLION.RCLKSECOND 103672Q))
)
(DECLARE: EVAL@COMPILE 

(PUTPROPS RWMufMan DMACRO ((X)
			   (* Note that this is the MISC1 opcode with 11Q as the alpha byte.)
			   ((OPCODES 170Q 11Q)
			    X)))
)


(* END EXPORTED DEFINITIONS)



(ADDTOVAR INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS \CLOCK0 \GETINTERNALCLOCK \BOXIDIFFERENCE \BOXIPLUS 
						\BLT \SLOWIQUOTIENT)
				     (LOCKEDVARS \RCLKSECOND \RCLKMILLISECOND \MISCSTATS))))
)
(DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS 

(ADDTOVAR NLAMA )

(ADDTOVAR NLAML )

(ADDTOVAR LAMA VMEM.PURE.STATE)
)
(PUTPROPS LLFAULT COPYRIGHT ("Xerox Corporation" 3676Q 3677Q 3700Q 3701Q))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (17276Q 20071Q (\FAULTHANDLER 17310Q . 20067Q)) (20123Q 34505Q (\FAULTINIT 20135Q . 
24256Q) (\D01.FAULTINIT 24260Q . 31263Q) (\D01.ASSIGNBUFFERS 31265Q . 34503Q)) (34506Q 75000Q (
\DL.FAULTINIT 34520Q . 41064Q) (\DL.NEWFAULTINIT 41066Q . 64172Q) (\DL.UNMAPPAGES 64174Q . 65143Q) (
\DL.MARK.PAGES.UNAVAILABLE 65145Q . 65703Q) (\DL.ASSIGNBUFFERS 65705Q . 71027Q) (\CHAIN.UP.RPT 71031Q
 . 74776Q)) (75001Q 142017Q (\PAGEFAULT 75013Q . 77641Q) (\INVALIDADDR 77643Q . 100116Q) (\INVALIDVP 
100120Q . 100356Q) (\FLUSHPAGE 100360Q . 104336Q) (\LOADVMEMPAGE 104340Q . 113125Q) (\LOOKUPPAGEMAP 
113127Q . 114120Q) (\LOCKEDPAGEP 114122Q . 115170Q) (\MARKPAGEVACANT 115172Q . 115727Q) (
\SELECTREALPAGE 115731Q . 126076Q) (\SPECIALRP 126100Q . 127033Q) (\TRANSFERPAGE 127035Q . 133671Q) (
\MOVEPAGE 133673Q . 134222Q) (\ZEROPAGE 134224Q . 134701Q) (\UPDATECHAIN 134703Q . 142015Q)) (142020Q 
224725Q (\NEWPAGE 142032Q . 143460Q) (\DONEWPAGE 143462Q . 152231Q) (\MAKESPACEFORLOCKEDPAGE 152233Q
 . 155623Q) (\MOVEVMEMFILEPAGE 155625Q . 157726Q) (\NEWEPHEMERALPAGE 157730Q . 160471Q) (
\DONEWEPHEMERALPAGE 160473Q . 165424Q) (\LOCKPAGES 165426Q . 166146Q) (\DOLOCKPAGES 166150Q . 171734Q)
 (\TEMPLOCKPAGES 171736Q . 173603Q) (\TEMPUNLOCKPAGES 173605Q . 175562Q) (\UNLOCKPAGES 175564Q . 
177443Q) (\FLUSHVM 177445Q . 201477Q) (\LOGOUT0 201501Q . 202603Q) (\DOFLUSHVM 202605Q . 210512Q) (
\RELEASEWORKINGSET 210514Q . 212064Q) (\WRITEDIRTYPAGE 212066Q . 222562Q) (\WRITEDIRTYPAGE1 222564Q . 
223714Q) (\COUNTREALPAGES 223716Q . 224723Q)) (224726Q 230105Q (\DOCOMPRESSVMEM 224740Q . 227165Q) (
VMEM.PURE.STATE 227167Q . 230103Q)) (230106Q 236604Q (32MBADDRESSABLE 230120Q . 230525Q) (
\SET.VMEM.FULL.STATE 230527Q . 232127Q) (\DOVMEMFULLINTERRUPT 232131Q . 236030Q) (\FLUSHVMOK? 236032Q
 . 236602Q)) (240114Q 240454Q (\MP.ERROR 240126Q . 240452Q)) (240503Q 257431Q (\ACTONVMEMFILE 240515Q
 . 241140Q) (\SHOWPAGETABLE 241142Q . 244776Q) (CHECKPAGEMAP 245000Q . 251453Q) (CHECKFPTOVP 251455Q
 . 252306Q) (CHECKFPTOVP1 252310Q . 253314Q) (\LOCKED?STRING 253316Q . 253574Q) (\PRINTFPTOVP 253576Q
 . 257124Q) (\PRINTVP 257126Q . 257427Q)) (273027Q 314677Q (ADDPME 273041Q . 276041Q) (CHECKIFPAGE 
276043Q . 276315Q) (DUMPINITPAGES 276317Q . 302666Q) (MAKEROOMFORPME 302670Q . 304316Q) (MAPPAGES 
304320Q . 305042Q) (READPAGEMAP 305044Q . 311516Q) (READPAGEMAPBLOCK 311520Q . 312077Q) (SETUPPAGEMAP 
312101Q . 314675Q)) (317107Q 321214Q (\LOCKFN 317121Q . 317613Q) (\LOCKCODE 317615Q . 320117Q) (
\LOCKVAR 320121Q . 320337Q) (\LOCKCELL 320341Q . 320573Q) (\LOCKWORDS 320575Q . 321212Q)) (324401Q 
336415Q (\CLOCK0 324413Q . 327133Q) (\DAYTIME0 327135Q . 327451Q) (\GETINTERNALCLOCK 327453Q . 331326Q
) (\SETDAYTIME0 331330Q . 334217Q) (CLOCKDIFFERENCE 334221Q . 334606Q) (\SECONDSCLOCKGREATERP 334610Q
 . 335417Q) (\CLOCKGREATERP 335421Q . 336170Q) (\RCLOCK0 336172Q . 336413Q)) (336416Q 337520Q (CLOCK0 
336430Q . 337516Q)))))
STOP