Trailing-Edge
-
PDP-10 Archives
-
AP-D483B-SB_1978
-
qsrmem.mac
There are 28 other files named qsrmem.mac in the archive. Click here to see a list.
TITLE QSRMEM -- Memory Manager for QUASAR
SUBTTL Chuck O'Toole 12 Nov 76
;***Copyright (C) 1974, 1975, 1976, 1977, Digital Equipment Corp., Maynard, MA.***
SEARCH QSRMAC ;PARAMETER FILE
PROLOGUE(QSRMEM) ;GENERATE THE NECESSARY SYMBOLS
COMMENT\
Entry points found in QSRMEM
M$INIT Initialization entry point
M$ACQP Acquire a page from the page map
M$RELP Return page 'AP' to the page map
M$IPSN Notification that IPCF send of page 'AP' is about to occur
M$NXPG Get a non-existant page for an IPCF receive
M$IPRC Notification that IPCF receive of a page has occurred
M$IPRM Make room for IPCF page we couldn't fit in core
M$GCOL A "Preventive" Garbage Collector for the Top Level
M$GFRE Get a cell from the free list for queue 'H'
M$PFRE Put cell 'AP' back on the free list for queue 'H'
M$RFRE Remove cell 'AP' from the queue 'H' and return it to the free list
M$DLNK Remove cell 'AP' from the queue 'H'
M$LINK Link cell 'AP' into the queue 'H' before entry 'E'
M$ELNK Link cell 'AP' at the end of the queue 'H'
M$FLNK Link cell 'AP' at the front of the queue 'H'
M$MOVE Move cell 'AP' from queue 'H' to queue 'S1'
M$PCNT Determine whether 'S1' pages can be acquired
STOPCDs found in QSRMEM
ASE ADDRESSING SPACE EXHAUSTED
BPN BAD PAGE NUMBER
CCC CELL COUNTS CONFUSED
CCP CANNOT CREATE PAGE
CGA CANNOT GIVE ACCESS TO PAGE
CRC CANNOT REDUCE CORE
FCE FREE COUNT EXCEEDS FREINI
FCN FREE COUNT NEGATIVE
MDL MOVING DIFFERENT LEVEL
NTS NOTHING TO SWAP OUT
PAF PAGE ACCESS CHECK FAILED
PDF PAGE DESTROY FAILED
PIF PAGE IN FAILURE
PLL PAGE LINK LOST
POF PAGE OUT FAILURE
QSZ QUEUE SIZE ZERO
RFP RELEASING FREE PAGE
RNP RECEIVED NON-EXISTANT PAGE
UPF UNKNOWN PAGE FAULT TYPE
\
LVL==M ;LEVEL (CLASS) FOR FREE SPACE
LVLMAX==1 ;MAXIMUM LEVEL. ( 0 = IPCF, 1 = ANYTHING ELSE )
; FOLLOWING SYMBOLS REFERENCE "LVLTAB(LVL)"
LVLNFC==777B35 ; ORIGINAL FREE COUNT PER PAGE THIS CLASS
LVLSIZ==777B26 ; SIZE OF A QUEUE ENTRY THIS CLASS
LVLFPG==777B17 ; FIRST PAGE IN THE CHAIN FOR THIS CLASS
LVLXXX==777B8 ; UNUSED
PADING==5 ;NUMBER OF PAGES TO LEAVE FREE FOR EMERGENCIES
SUBTTL Initialization Entry Point
;CALLED BY QUASAR AT FIRST START-UP TO INITIALIZE THE MEMORY MANAGER
INTERN M$INIT
M$INIT: PUSHJ P,.SAVE1## ;SAVE P1
PUSHJ P,I$MFFP## ;GET FIRST FREE PAGE
MOVEM S1,PAGSTA ;STORE FOR PAGE SEARCHING LOOPS
MOVEI S2,^D512 ;NOW COMPUTE THE REMAINING ADDRESS SPACE
SUB S2,S1 ;OFFSET FOR CODE
MOVEM S2,FREPGS ;SAVE FOR M$NXPG CHECK
MOVEM S2,FREINI ;SAVE INITIAL VALUE FOR CHECKS
ZERO ZERLOC ;START WITH A CLEAR PAGE MAP
MOVE S1,[ZERLOC,,ZERLOC+1] ;SET UP FOR THE BLT
BLT S1,ZERLAS ;CLEAR THE WHOLE THING
IFN FTUUOS,< ;TOPS10 INITIALIZATION
MOVE S1,[PFHEND,,PFHBGN] ;PAGE FAULT HANDLER POINTERS
MOVE S2,PFHBGN ;TOUCH THE FIRST LOCATION AND THE LAST
MOVE S2,PFHEND ;TO GUARANTEE PFH IS IN CORE
MOVEM S1,.JBPFH## ;NOW SET UP OUR OWN HANDLER
MOVE S1,[.STTVM,,0] ;SET VIRTUAL TIME TRAP = NONE
SETUUO S1, ;SET TO NOT GIVE TIMER TRAPS
JFCL ;OH WELL!!
MOVE AP,PAGSTA ;GET THE STARTING PAGE NUMBER
DECR AP ;IT GETS AOS'ED LATER
MOVEM AP,SWPSTA ;START OF THE SWAPPING TABLE
PG2ADR AP ;CONVERT TO ADDRESS
MOVEI AP,777(AP) ;LAST LOCATION WE KNOW ABOUT
CORE AP, ;DON'T CARE ABOUT ANYTHING ELSE
STOPCD(CRC,FATAL) ;++CANNOT REDUCE CORE
> ;END OF IFN FTUUOS
MOVEI H,TBLHDR## ;START OF THE QUEUE HEADERS
MOVEI P1,NQUEUE## ;AND THE NUMBER OF THEM
INIT.1: PUSHJ P,SETLVL ;SET UP CLASS FOR THIS QUEUE
LOAD S1,.QHPAG(H),QH.SIZ ;SIZE OF AN ENTRY IN THIS QUEUE
JUMPN LVL,INIT.2 ;JUMP IF NOT AN IPCF QUEUE (=0)
ADD S1,G$MPS## ;ADD IN MAXIMUM PACKET SIZE
STORE S1,.QHPAG(H),QH.SIZ ;UPDATE QUEUE SIZE
INIT.2: LOAD S2,LVLTBL(LVL),LVLSIZ ;CURRENT SIZE IN THIS LEVEL
CAMGE S2,S1 ;THIS QUEUE LARGER THAN CURRENT
MOVE S2,S1 ;YES, GET S2 = LARGEST SIZE SO FAR
STORE S2,LVLTBL(LVL),LVLSIZ ;REMEMBER LARGEST IN CLASS
SKIPN S2 ;ERROR CHECK IT NOW
STOPCD(QSZ,FATAL) ;++QUEUE SIZE ZERO
MOVEI S1,777 ;FREE WORDS PER PAGE
IDIVI S1,(S2) ;COMPUTE FREE CELLS PER PAGE
STORE S1,LVLTBL(LVL),LVLNFC ;REMEMBER FOR FREE SPACE ROUTINES
MOVEI H,QHSIZE(H) ;STEP TO NEXT QUEUE HEADER
SOJG P1,INIT.1 ;GET ALL QUEUES
POPJ P, ;AND RETURN
SUBTTL Free Space Management Subroutines
;ROUTINE TO GET A FREE CELL FOR A QUEUE
;CALL H = QUEUE HEADER POINTER
; PUSHJ P,M$GFRE
; RETURNS AP = CELL ADDRESS
;DESTROYS S1,S2
;CALLS M$ACQP, BLDFRE
INTERN M$GFRE
M$GFRE: SAVE LVL ;SAVE CALLERS
PUSHJ P,SETLVL ;SET UP QUEUE CLASS
SKIPN LVL ;IPCF TYPE (=0)
PUSHJ P,I$NOIN## ;YES, TURN OFF IPCF INTERRUPTS
SKIPN LVFCNT(LVL) ;ANY FREE CELLS LEFT FOR LEVEL?
JRST GFRE.3 ;NO, GET A PAGE WORTH
LOAD AP,LVLTBL(LVL),LVLFPG ;GET FIRST PAGE IN THE CHAIN
ZERO S2 ;CLEAR IN CASE NO FREE SPACE
GFRE.1: LOAD S1,PAGTBL(AP),PT.CNT ;CELLS REMAINING IN THIS PAGE
JUMPE S1,GFRE.2 ;THIS PAGE IS FULL, TRY THE NEXT
TRNE S2,-1 ;IS THIS THE FIRST PAGE WE'VE LOOKED AT
CAIGE S1,(S2) ;NO, USE THE ONE WITH THE LEAST FREE SPACE
SKIPA ;THIS ONE IS BETTER (OR THE FIRST)
JRST GFRE.2 ;SKIP THIS PAGE
HRLI S2,(AP) ;SAVE PAGE NUMBER OF THE BEST
HRRI S2,(S1) ;AND ITS COUNT
GFRE.2: LOAD AP,PAGTBL(AP),PT.LNK ;GET CHAIN TO THE NEXT PAGE
JUMPN AP,GFRE.1 ;LOOK AT THE NEXT PAGE IF ANY
HLRZ AP,S2 ;GET THE NUMBER OF THE BEST PAGE
JUMPN AP,GFRE.4 ;THERE WAS ONE, TAKE A CELL
STOPCD (LCC,FATAL) ;++LEVEL COUNT CONFUSED
GFRE.3: PUSHJ P,M$ACQP ;ACQUIRE A FRESH PAGE
PUSHJ P,BLDFRE ;GENERATE THE FREE SPACE IN THIS NEW PAGE
GFRE.4: DECR PAGTBL(AP),PT.CNT ;DECREMENT THE FREE COUNT FOR THIS PAGE
SOS LVFCNT(LVL) ;AND TOTAL FREE SPACE IN THIS CLASS
PG2ADR AP ;CONVERT TO AN ADDRESS
HRRZ S1,(AP) ;GET THE CELL FROM THIS PAGE
LOAD S2,.QELNK(S1),QE.PTN ;FIND THE NEXT
HRRM S2,(AP) ;DISSOLVE THE LINK
MOVEI AP,(S1) ;RETURN CELL ADDRESS IN AP
POPJ P, ;AND RETURN
;ROUTINES TO RETURN A CELL TO THE CORRECT FREE LIST
;CALL AP = CELL ADDRESS (MAY BE DESTROYED)
; H = QUEUE HEADER POINTER
; PUSHJ P,M$PFRE (M$RFRE IF ENTRY MUST BE DE-LINKED)
;DESTROYS S1,S2,AP,TEMP
;CALLS M$DLNK, M$RELP
INTERN M$PFRE,M$RFRE
M$RFRE: PUSHJ P,M$DLNK ;DE-LINK THIS ENTRY BEFORE RETURNING IT
M$PFRE: SAVE LVL ;SAVE CALLERS
PUSHJ P,SETLVL ;SET UP QUEUE CLASS
SKIPN LVL ;IPCF TYPE (=0)
PUSHJ P,I$NOIN## ;YES, TURN OFF IPCF INTERRUPTS
MOVEI S1,(AP) ;COPY THE CELL ADDRESS
ADR2PG S1 ;CONVERT TO A PAGE NUMBER
EXCH AP,S1 ;SET UP FOR VALIDITY CHECKS
PUSHJ P,VALPAG ;SEE IF 'AP' IS A GOOD PAGE NUMBER
EXCH AP,S1 ;OK, GET THEM BACK IN THE RIGHT ORDER
INCR PAGTBL(S1),PT.CNT ;BUMP FREE COUNT FOR THIS PAGE
AOS LVFCNT(LVL) ;AND TOTAL FOR THIS CLASS
LOAD TEMP,PAGTBL(S1),PT.CNT ;GET THE COUNT NOW
PG2ADR S1 ;BACK TO THE ADDRESS OF THIS PAGE
HRRZ S2,(S1) ;GET THE LINK TO THE FIRST FREE IN THIS PAGE
HRRM AP,(S1) ;STORE THIS ENTRY AS THE FIRST NOW
STORE S2,.QELNK(AP),QE.PTN ;LINK THIS ENTRY TO THE NEXT
LOAD S2,LVLTBL(LVL),LVLNFC ;GET THE COUNT IF THIS PAGE IS EMPTY
CAMGE S2,LVFCNT(LVL) ;MORE THAN 1 PAGE WORTH OF FREE SPACE
SETOM DOGCOL ;YES, GARBAGE COLLECTION WILL WIN
CAIE TEMP,(S2) ;IS IT EMPTY NOW
POPJ P, ;NO, JUST RETURN
ADR2PG AP ;BACK TO A PAGE NUMBER
ZERO S2 ;CLEAR IN CASE THIS IS THE FIRST PAGE
LOAD S1,LVLTBL(LVL),LVLFPG ;GET FIRST PAGE IN THE CHAIN
PFRE.1: CAIN AP,(S1) ;FIND THE PAGE THAT POINTS TO ME
JRST PFRE.2 ;THIS IS IT
MOVE S2,S1 ;COPY THE PAGE NUMBER
LOAD S1,PAGTBL(S2),PT.LNK ;LINK TO THE NEXT PAGE IN THE CHAIN
JUMPN S1,PFRE.1 ;LOOK AT THIS ONE
STOPCD (PLL,FATAL) ;++PAGE LINK LOST
PFRE.2: LOAD S1,PAGTBL(AP),PT.LNK ;GET WHERE I POINT TO
JUMPE S2,PFRE.3 ;JUMP IF I AM THE FIRST
STORE S1,PAGTBL(S2),PT.LNK ;REMOVE ME FROM THE CHAIN
JRST PFRE.4 ;ADJUST COUNTS AND RETURN PAGE
PFRE.3: PJUMPE S1,.POPJ## ;RETURN IF I AM THE ONLY
STORE S1,LVLTBL(LVL),LVLFPG ;THAT IS NOW THE FIRST
PFRE.4: LOAD S1,LVLTBL(LVL),LVLNFC ;GET A PAGE WORTH OF FREE SPACE
MOVNS S1 ; - THAT
ADDM S1,LVFCNT(LVL) ;DECREMENT TOTAL FOR THIS CLASS
PJRST M$RELP ;RETURN THE PAGE AND RETURN
;THE GARBAGE COLLECTOR IS CALLED FROM THE TOP LEVEL AND IS "PREVENTIVE"
; RATHER THAN "CORRECTIVE". IT MUST NOT BE CALLED IN AN ATTEMPT
; TO ACQUIRE MORE CORE IN CASE THERE IS NONE AVAILABLE SINCE THE
; STATE OF QUEUES AND LISTS ARE UNCERTAIN AT THOSE TIMES.
INTERN M$GCOL
M$GCOL: SKIPN DOGCOL ;IS THERE ANYTHING TO COLLECT?
POPJ P, ;NO, JUST RETURN
PUSHJ P,I$NOIN## ;TURN OFF IPCF INTERRUPTS
PUSHJ P,.SAVE3## ;SAVE P1-P3
$COUNT (NGCC) ;COUNT GARBAGE COLLECTION CALLS
MOVEI P1,LVLMAX ;DRIVE LOOP FROM LVLMAX TO 0
GCOL.1: MOVE LVL,P1 ;COPY CURRENT LEVEL NUMBER
PUSHJ P,CHKELM ;CHECK IF WE CAN ELIMINATE A PAGE
JUMPE S1,GCOL.4 ;CAN'T, TRY THE NEXT LEVEL
$COUNT (NPGC) ;COUNT COLLECTED PAGES
MOVEI H,TBLHDR## ;THE START OF THE QUEUE HEADERS
MOVEI P2,NQUEUE## ;AND THE NUMBER OF QUEUES DEFINED
MOVX P3,PT.USE ;GET THE IN USE BIT FOR CHECKS
MOVE AP,S1 ;COPY THE PAGE TO ELIMINATE
GCOL.2: PUSHJ P,SETLVL ;LEVEL OF THIS QUEUE
SKIPE .QHLNK(H) ;QUEUE EMPTY
CAME LVL,P1 ;NO, SAME CLASS AS FOR THIS PASS
JRST GCOL.3 ;EMPTY OR NOT SAME LEVEL, TRY NEXT QUEUE
PUSHJ P,DOELIM ;TRY TO ELIMINATE THE PAGE HERE
TDNN P3,PAGTBL(AP) ;PAGE GONE YET
JRST GCOL.1 ;YES, TRY FOR ANOTHER PAGE IN THIS CLASS
GCOL.3: MOVEI H,QHSIZE(H) ;BUMP TO THE NEXT QUEUE HEADER
SOJG P2,GCOL.2 ;AND DO THAT ONE
STOPCD(CCC,FATAL) ;++CELL COUNTS CONFUSED
GCOL.4: SOJGE P1,GCOL.1 ;TRY THE NEXT CLASS (LEVEL)
SETZM DOGCOL ;WE'VE COLLECTED
POPJ P, ;THEN RETURN
;ROUTINES TO LINK AN ENTRY INTO A QUEUE
;CALL AP = ENTRY TO LINK
; H = QUEUE HEADER POINTER
; E = SUCCESSOR OF THIS ENTRY (FOR ORDERING IF CALLING M$LINK)
; PUSHJ P,M$xxxx
; WHERE xxxx IS
; 'LINK' TO LINK ENTRY BEFORE 'E'
; 'ELNK' TO LINK AT THE END OF THE QUEUE
; 'FLNK' TO LINK AT THE BEGINNING OF THE QUEUE
;DESTROYS S1
INTERN M$LINK,M$ELNK,M$FLNK
M$ELNK: CAIN H,HDRIPC## ;LINKING THE IPCF QUEUE
PUSHJ P,I$NOIN## ;YES, TURN OFF IPCF INTERRUPTS
LOAD S1,.QHLNK(H),QH.PTL ;FIND THE LAST
STORE AP,.QHLNK(H),QH.PTL ;THIS IS NOW THE LAST
STORE S1,.QELNK(AP),QE.PTP ;POINT BACK AT THE OLD LAST
ZERO .QELNK(AP),QE.PTN ;LAST HAS NO NEXT
JUMPE S1,ELNK.1 ;JUMP IF THIS IS THE FIRST
STORE AP,.QELNK(S1),QE.PTN ;LINK THE OLD LAST TO THIS ONE
POPJ P, ;AND RETURN
ELNK.1: STORE AP,.QHLNK(H),QH.PTF ;STORE AS FIRST IN QUEUE ALSO
POPJ P, ;AND RETURN
M$FLNK: CAIN H,HDRIPC## ;LINKING THE IPCF QUEUE
PUSHJ P,I$NOIN## ;YES, TURN OFF IPCF INTERRUPTS
LOAD S1,.QHLNK(H),QH.PTF ;FIND THE FIRST
STORE AP,.QHLNK(H),QH.PTF ;THIS IS NOW THE FIRST
STORE S1,.QELNK(AP),QE.PTN ;POINT TO THE OLD FIRST
ZERO .QELNK(AP),QE.PTP ;FIRST HAS NO PREVIOUS
JUMPE S1,FLNK.1 ;JUMP IF THIS IS THE LAST
STORE AP,.QELNK(S1),QE.PTP ;LINK THE OLD FIRST BACK TO THIS
POPJ P, ;AND RETURN
FLNK.1: STORE AP,.QHLNK(H),QH.PTL ;STORE THIS AS LAST IN QUEUE ALSO
POPJ P, ;AND RETURN
M$LINK: JUMPE E,M$ELNK ;USE THE SPECIAL CASE IF THIS IS TO BE THE LAST
CAIN H,HDRIPC## ;LINKING THE IPCF QUEUE
PUSHJ P,I$NOIN## ;YES, TURN OFF IPCF INTERRUPTS
LOAD S1,.QELNK(E),QE.PTP ;LOAD SUCCESSORS PREVIOUS
JUMPE S1,M$FLNK ;JUMP IF THIS IS TO BE THE FIRST
STORE S1,.QELNK(AP),QE.PTP ;THAT IS MY PREVIOUS
STORE AP,.QELNK(S1),QE.PTN ;AND I AM ITS NEXT
STORE E,.QELNK(AP),QE.PTN ;POINT TO THE SUCESSOR
STORE AP,.QELNK(E),QE.PTP ;I AM ITS PREVIOUS
POPJ P, ;AND RETURN
;ROUTINE TO DISSOLVE THE LINKS OF AN ENTRY
;NORMALLY CALLED BEFORE THE CALL TO M$PFRE AND IS CALLED BY M$RFRE
;CALL AP = CELL TO REMOVE
; H = QUEUE HEADER POINTER
; PUSHJ P,M$DLNK
;DESTROYS S1,S2
INTERN M$DLNK
M$DLNK: CAIN H,HDRIPC## ;DELINKING THE IPCF QUEUE
PUSHJ P,I$NOIN## ;YES, TURN OFF IPCF INTERRUPTS
LOAD S1,.QELNK(AP),QE.PTP ;GET LINKS OF THE ENTRY TO BE REMOVED
LOAD S2,.QELNK(AP),QE.PTN ;S1 = PREVIOUS, S2 = SUCCESSOR
JUMPE S1,DLNK.1 ;JUMP IF REMOVING THE FIRST
JUMPE S2,DLNK.3 ;JUMP IF REMOVING THE LAST
STORE S1,.QELNK(S2),QE.PTP ;LINK THE REMAINING ENTRIES TOGETHER
STORE S2,.QELNK(S1),QE.PTN ;TO COMPLETELY DISSOLVE THE OLD LINKS
POPJ P, ;AND RETURN
DLNK.1: JUMPE S2,DLNK.2 ;JUMP IF REMOVING THE ONLY
STORE S2,.QHLNK(H),QH.PTF ;STORE SUCCESSOR AS THE NEW FIRST
ZERO .QELNK(S2),QE.PTP ;AND CLEAR ITS BACKWARD LINK
POPJ P, ;AND RETURN
DLNK.2: ZERO .QHLNK(H) ;IF REMOVING THE ONLY, CLEAR THE HEADER
POPJ P, ;AND RETURN
DLNK.3: STORE S1,.QHLNK(H),QH.PTL ;STORE PREVIOUS AS NEW LAST
ZERO .QELNK(S1),QE.PTN ;AND CLEAR ITS FORWARD LINK
POPJ P, ;AND RETURN
;ROUTINE TO MOVE A CELL FROM ONE QUEUE TO ANOTHER (PROCESSING TO USE, ETC..)
;CALL H = CURRENT QUEUE
; AP = THE CELL TO MOVE
; S1 = NEW QUEUE
; PUSHJ P,M$MOVE
;RETURNS AP & H UPDATED TO REFLECT NEW CELL
;DESTROYS S1,S2
INTERN M$MOVE
M$MOVE: SAVE LVL ;SAVE CALLERS
PUSH P,S1 ;SAVE NEW HEADER
PUSHJ P,M$DLNK ;REMOVE CELL FROM OLD QUEUE
PUSHJ P,SETLVL ;DETERMINE LEVEL (CLASS) OF OLD QUEUE
MOVE S1,LVL ;SAVE LEVEL OF OLD QUEUE
POP P,H ;NEW HEADER
PUSHJ P,SETLVL ;FIND LEVEL OF NEW QUEUE
CAIE S1,(LVL) ;MOVING ACROSS LEVELS
STOPCD(MDL,FATAL) ;++MOVING DIFFERENT LEVEL
LOAD S1,.QHPAG(H),QH.SCH ;BASE SCHEDULER VECTOR FOR NEW QUEUE
PJUMPE S1,M$ELNK ;IF NO VECTOR TACK IT TO THE END
PJRST SCHLNK(S1) ;LINK IT IN AND RETURN
;ROUTINE TO BUILD THE FREE LIST IN A PAGE
;NORMALLY CALLED AFTER THE RETURN FROM M$ACQP
;CALL AP = THE NEWLY ACQUIRED PAGE NUMBER
; H = QUEUE HEADER POINTER
; LVL= QUEUE CLASS (LEVEL)
; PUSHJ P,BLDFRE
;DESTROYS S1,S2
BLDFRE: PUSHJ P,.SAVE2## ;SAVE P1,P2
LOAD S1,LVLTBL(LVL),LVLFPG ;GET FIRST PAGE IN THE CHAIN
STORE AP,LVLTBL(LVL),LVLFPG ;START WITH THE NEW ONE ACQUIRED
STORE S1,PAGTBL(AP),PT.LNK ;AND LINK NEW ONE TO OLD FIRST
MOVEI S1,(AP) ;COPY THE PAGE NUMBER
PG2ADR S1 ;MAKE AN ADDRESS FROM IT
MOVEI S1,1(S1) ;WORD 0 IS THE LINK FOR FUTURE FREE SPACE
MOVEM S1,-1(S1) ;STORE AS A LINK TO WORD 1
LOAD S2,LVLTBL(LVL),LVLSIZ ;GET SIZE OF AN ENTRY IN THIS CLASS
LOAD P1,LVLTBL(LVL),LVLNFC ;GET NUMBER OF FREE CELLS IN A PAGE
ADDM P1,LVFCNT(LVL) ;INCLUDE NEW PAGE IN THE TOTAL
STORE P1,PAGTBL(AP),PT.CNT ;STORE THE COUNT OF FREE CELLS IN THIS PAGE
SOJE P1,BLDF.2 ;DECREMENT FOR LOOP, JUMP IF ONLY ONE FITS
MOVEI P2,(S1) ;START COMPUTATIONS THE NEXT IN THIS PAGE
BLDF.1: ADDI P2,(S2) ;P2 = NEXT ENTRY
STORE P2,.QELNK(S1),QE.PTN ;LINK OF THIS POINTS TO NEXT
MOVEI S1,(P2) ;NOW POINT TO NEXT ENTRY
SOJG P1,BLDF.1 ;AND LOOP FOR ALL ENTRIES - 1
BLDF.2: ZERO .QELNK(S1),QE.PTN ;LAST LINKS TO NOWHERE
POPJ P, ;AND RETURN
;ROUTINE TO ESTABLISH THE QUEUE CLASS (LEVEL) FOR QUEUE 'H'
;CALL H = THE QUEUE HEADER
; SAVE LVL
; PUSHJ P,SETLVL
;RETURNS LVL = THE QUEUE CLASS (CALLER MUST SAVE IT FIRST)
SETLVL: LOAD LVL,.QHTYP(H),QH.IPC ;GET 'IPCF' QUEUE BIT
TRC LVL,1 ;FLIP SO 0 = IPCF, 1 = ANYTHING ELSE
POPJ P, ;AND RETURN
;ROUTINE TO CHECK IF GARBAGE COLLECTION WILL ACCOMPLISH ANYTHING
;CALL LVL= CURRENT QUEUE CLASS (LEVEL)
;RETURNS S1 = PAGE THAT CAN BE ELIMINATED OR 0 IF CANT ELIMINATE ANYTHING
;THE DEPENDENCE ON THE METHODS USED BY M$PFRE AND M$GFRE MUST BE NOTED.
; IN THE DETERMINATION OF THE PAGE TO BE ELIMINATED, THE PAGE WITH THE
; "MOST" AMOUNT OF FREE SPACE IS USED, SINCE M$GFRE USES THE PAGE WITH
; THE "LEAST" AMOUNT. IF MULTIPLE PAGES HAVE THE SAME AMOUNT, M$GFRE USES
; THE FIRST IN THE CHAIN, THEREFORE, TO ELIMINATE ONE, PICK THE LAST ONE.
; M$PFRE (M$RFRE) WILL M$RELP A PAGE WHEN IT BECOMES COMPLETELY EMPTY.
CHKELM: PUSHJ P,.SAVET## ;SAVE THE T REGS
LOAD T1,LVLTBL(LVL),LVLFPG ;GET FIRST PAGE IN THE CHAIN
JUMPE T1,.FALSE## ;RETURN 0 IF EMPTY
SETZB T2,T3 ;FOR FINDING FREE SPACE AND TOTALS
CHKE.1: LOAD T4,PAGTBL(T1),PT.CNT ;COUNT OF FREE CELLS IN THIS PAGE
CAIGE T4,(T2) ;THIS HAVE THE MOST YET
JRST CHKE.2 ;EQUAL CASE MUST BE CONSISTANT WITH M$GFRE
MOVEI S1,(T1) ;REMEMBER "BEST" PAGE
MOVEI T2,(T4) ;AND ITS CELL COUNT
CHKE.2: ADDI T3,(T4) ;INCLUDE IN THE TOTAL FREE
LOAD T1,PAGTBL(T1),PT.LNK ;FIND THE NEXT IN THE CHAIN
JUMPN T1,CHKE.1 ;KEEP GOING IF THERE'S ANOTHER
JUMPE T3,.FALSE## ;RETURN 0 IF NO FREE CELLS LEFT
CAME T3,LVFCNT(LVL) ;COMPUTED AND RUNNING TALLIES AGREE
STOPCD(FNA,FATAL) ;++FREE TALLIES DO NOT AGREE
LOAD T1,LVLTBL(LVL),LVLNFC ;NUMBER OF FREE CELLS PER PAGE
CAMG T3,T1 ;MOVE THAN 1 PAGE OF FREE SPACE
JRST .FALSE## ;NO, CANNOT REDUCE
POPJ P, ;YES, RETURN WITH S1 = THE PAGE NUMBER
;SUBROUTINE TO ELIMINATE A PAGE FOR THE GARBAGE COLLECTOR
;CALL AP = THE PAGE TO ELIMINATE (OUTPUT FROM CHKELM)
; H = THE QUEUE HEADER
; LVL= THE QUEUE LEVEL(CLASS)
DOELIM: PUSHJ P,.SAVET## ;SAVE ALL THE T REGS
SAVE E ;AND E
SAVE AP ;AND THE PAGE NUMBER
MOVE T1,AP ;SAVE THE PAGE NUMBER
LOAD T2,LVLTBL(LVL),LVLSIZ ;GET SIZE OF AN ENTRY THIS CLASS
LOAD E,.QHLNK(H),QH.PTF ;FIND FIRST IN THIS QUEUE
DOEL.1: JUMPE E,.POPJ## ;RETURN IF AT END OF LIST
MOVEI T3,(E) ;COPY CELL ADDRESS
ADR2PG T3 ;CONVERT TO A PAGE NUMBER
CAIE T3,(T1) ;PAGE TRYING TO ELIMINATE
JRST DOEL.2 ;NO, TRY ANOTHER
PUSHJ P,M$GFRE ;YES, GET A NEW FREE CELL
HRLI T3,(E) ;SOURCE IS OLD ENTRY
HRRI T3,(AP) ;DESTINATION IS NEW ONE
MOVEI T4,(AP) ;NOW FIND HOW MUCH TO MOVE
ADDI T4,-1(T2) ;AS NEW + LENGTH OF ENTRY - 1
BLT T3,(T4) ;MOVE THE ENTRY TO ANOTHER PAGE
MOVEI T3,(E) ;COPY CELL ADDRESS AGAIN
LOAD E,.QELNK(E),QE.PTN ;FIND THE NEXT NOW
PUSHJ P,M$LINK ;PUT NEW IN CORRECT ORDER
MOVEI AP,(T3) ;NOW GET OLD CELL ADDRESS
PUSHJ P,M$RFRE ;AND UNLINK AND RETURN IT
MOVX AP,PT.USE ;THE IN USE BIT
TDNN AP,PAGTBL(T1) ;DID THE PAGE GO AWAY AFTER THAT RETURN
POPJ P, ;YES, HAVE ELIMINATED IT
JRST DOEL.1 ;NO, TRY ANOTHER CELL
DOEL.2: LOAD E,.QELNK(E),QE.PTN ;LINK TO THE NEXT ENTRY
JRST DOEL.1 ;AND TRY THAT ONE
SUBTTL Page Management Subroutines
;ROUTINE TO ACQUIRE A FRESH PAGE FROM THE PAGE MAP
;CALL PUSHJ P,M$ACQP
; RETURNS AP = PAGE NUMBER
;DESTROYS S1
;CALLS FNDPAG, PGSOUT, PGSDES, ANYOUT
INTERN M$ACQP
M$ACQP: PUSHJ P,I$NOIN## ;TURN OFF IPCF INTERRUPTS
PUSHJ P,FNDPAG ;FIND THE BEST AVAILABLE PAGE
SKIPN AP ;SKIP IF ONE FOUND
STOPCD(ASE,FATAL) ;++ADDRESSING SPACE EXHAUSTED
IFN FTJSYS,<
ACQP.1: MOVX S1,PT.USE!PT.WRK!PT.ADR ;GET ALL THE BITS
IORM S1,PAGTBL(AP) ;INCLUDE THEM
PJRST REDUCE ;REDUCE COUNT OF FREE CORE AND RETURN
> ;END OF IFN FTJSYS
IFN FTUUOS,<
ACQP.1: PUSHJ P,REDUCE ;REDUCE COUNT OF FREE PAGES
MOVX S1,PT.USE ;GET THE INUSE BIT
IORB S1,PAGTBL(AP) ;SET IN USE, GET THE OTHERS
TXNE S1,PT.ADR ;IS IT ADDRESSABLE
POPJ P, ;YES, RETURN (MAY PAGE FAULT IT IN LATER)
PUSHJ P,.SAVE3## ;SAVE P1-P3
ACQP.2: MOVEI P3,(AP) ;ARGUMENT FOR CREATE A PAGE
MOVEI P2,1 ;ONLY 1 ARGUMENT
MOVE P1,[.PAGCD,,P2] ;FUNCTION CREATE/DESTROY,,ARGUMENTS
PAGE. P1, ;TRY THE CREATE
JRST ACQP.3 ;ANALYZE THE ERROR
MOVX S1,PT.WRK!PT.ADR ;IN THE WORKING SET, ADDRESSABLE
IORM S1,PAGTBL(AP) ;INCLUDE THE FLAG
POPJ P, ;AND RETURN
ACQP.3: PUSH P,AP ;SAVE THE PAGE WE'RE TRYING TO CREATE
CAIE P1,PAGNS% ;OUT OF SWAPPING SPACE
JRST ACQP.4 ;NO, LOOK AGAIN
MOVEI AP,5 ;TAKE A QUICK NAP FIRST
SLEEP AP, ;IN CASE SOME FREES UP
PUSHJ P,PGSDES ;FREE SOME SWAPPING SPACE
POP P,AP ;RESTORE AP
JRST ACQP.2 ;AND RETRY THE CREATE
ACQP.4: CAIE P1,PAGLE% ;MY LIMIT EXCEEDED
STOPCD(CCP,FATAL) ;++CANNOT CREATE PAGE
PUSHJ P,ANYOUT ;SWAP OUT ANYTHING
POP P,AP ;RESTORE AP
JRST ACQP.2 ;RETRY THE CREATE
> ;END OF IFN FTUUOS
;ROUTINE TO ACQUIRE A FRESH (UNADDRESSABLE) PAGE FROM THE PAGE MAP FOR IPCF
;CALL PUSHJ P,M$NXPG
; RETURNS AP = THE PAGE NUMBER AVAILABLE FOR IPCF RECEIVE
; 0 IF NONE AVAILABLE (NO CORE AVB)
; NORMALLY, A CALL TO M$IPRC FOLLOWS THE RECEIVE AND THE PAGE IS INCLUDED
; IN FACT, THE CALL TO M$IPRC IS REQUIRED TO KEEP FREPGS STRAIGHT
;DESTROYS S1
;CALLS FNDPAG, PGSOUT, PGSDES
INTERN M$NXPG
M$NXPG: PUSHJ P,I$NOIN## ;TURN OFF IPCF INTERRUPTS
MOVE S1,FREPGS ;GET FREE CORE LEFT
CAIL S1,PADING ;INSURE IPCF WON'T FILL OUR SPACE
JRST NXPG.1 ;GO TRY TO GET ONE
NXPG.0: ZERO AP ;RETURN A ZERO
POPJ P, ;THAT WILL SHUT IT OFF
IFN FTJSYS,< ;TOPS20 WILL REPLACE ANY EXISTING PAGE WITH THE MESSAGE
NXPG.1: PUSHJ P,FNDPAG ;ESSENTUALLY DUPLICATE M$ACQP
PJUMPE AP,.POPJ## ;RETURN 0 IF CANT GET ONE NOW
MOVX S1,PT.USE ;SET THE TEMP STATE
IORM S1,PAGTBL(AP) ;OF INUSE BUT NOT ADDRESSABLE
POPJ P, ;AND RETURN
> ;END OF IFN FTJSYS
IFN FTUUOS,< ;TOPS10 REQUIRES A NON-EXISTANT PAGE
NXPG.1: PUSHJ P,NXPG.3 ;FIND A COMPLETELY MISSING PAGE
JUMPN AP,NXPG.2 ;TAKE THIS ONE
PUSHJ P,.SAVE3## ;SAVE P1-P3
PUSHJ P,PGSDES ;DESTROY ALL I CAN
PUSHJ P,NXPG.3 ;NOW TRY TO FIND ONE
PJUMPE AP,.POPJ## ;RETURN 0 IF CANT GET ONE NOW
NXPG.2: MOVX S1,PT.USE ;SET THE TEMP STATE
IORM S1,PAGTBL(AP) ;OF INUSE BUT NOT ADDRESSABLE
POPJ P, ;AND RETURN
NXPG.3: MOVE AP,PAGSTA ;START AT THE FIRST AVAILABLE PAGE
NXPG.4: CAIL AP,^D512 ;END OF THE ADDRESSING SPACE
JRST NXPG.0 ;YES, RETURN A ZERO
MOVE S1,PAGTBL(AP) ;GET THE TABLE ENTRY
TXNN S1,PT.USE!PT.WRK!PT.ADR ;IS THIS PAGE THERE
POPJ P, ;NO BITS MEANS NON-EXISTANT
AOJA AP,NXPG.4 ;WELL, TRY THE NEXT
> ;END OF IFN FTUUOS
;ROUTINE TO RETURN A PAGE TO THE PAGE MAP
;CALL AP = PAGE NUMBER
; PUSHJ P,M$RELP
;DESTROYS S1
INTERN M$RELP
M$RELP: PUSHJ P,VALPAG ;CONSISTENCY CHECK 'AP'
MOVE S1,PAGTBL(AP) ;GET THE FLAGS
TXZN S1,PT.USE ;CLEAR IN USE
STOPCD(RFP,FATAL) ;++RELEASING FREE PAGE
TXNE S1,PT.ADR ;IS THIS THE ONE IPCF'ED AWAY
JRST RELP.1 ;NO, GO FIX THE COUNTS
ZERO PAGTBL(AP) ;CLEAR THE ENTRY
POPJ P, ;AND RETURN
RELP.1: MOVEM S1,PAGTBL(AP) ;STORE NEW SETTINGS
TXNE S1,PT.WRK ;THIS PAGE LEFT IN CORE
AOS AVBPGS ;YES, COUNT IT
PJRST INCLUD ;BUMP FREE PAGE COUNT AND RETURN
;ROUTINE TO SET NOTIFICATION OF A PAGE BEING IPCF'ed FROM OUR ADDRESSING SPACE
;CALL AP = PAGE NUMBER
; PUSHJ P,M$IPSN
;DESTORYS S1
INTERN M$IPSN
M$IPSN: PUSHJ P,VALPAG ;CONSISTENCY CHECK 'AP'
MOVX S1,PT.WRK!PT.ADR ;CLEAR IN THE WORKING SET, ADDRESSABLE
ANDCAM S1,PAGTBL(AP) ;SO THAT WE DON'T GET CONFUSED
PJRST INCLUD ;BUMP FREE PAGE COUNT AND RETURN
;ROUTINE TO INCLUDE A PAGE RECEIVED BY IPCF INTO OUR ADDRESSING SPACE
;CALL AP = THE PAGE NUMBER
; PUSHJ P,M$IPRC
;DESTROYS S1,S2
INTERN M$IPRC
IFN FTUUOS,< ;NOW NEED TO KNOW IF THE PAGE IS IN THE WORKING SET
M$IPRC: PUSHJ P,VALPAG ;CONSISTENCY CHECK 'AP'
MOVEI S2,(AP) ;FOR PAGE 'AP'
HRLI S2,.PAGCA ;CHECK ITS ACCESS BITS
PAGE. S2, ;SEE IF THE PAGE IS SWAPPED OUT
STOPCD(PAF,FATAL) ;++PAGE ACCESS CHECK FAILED
MOVX S1,PT.WRK!PT.ADR ;IN THE WORKING SET, ADDRESSABLE
TXNE S2,PA.GNE ;PAGE DOESN'T EXIST
STOPCD(RNP,FATAL) ;++RECEIVED NON-EXISTANT PAGE
TXNE S2,PA.GPO ;IS IT PAGED OUT
TXZ S1,PT.WRK ;YES, CLEAR IN THE WORKING SET
IORM S1,PAGTBL(AP) ;INCLUDE THE FLAG(S)
PJRST REDUCE ;REDUCE COUNT OF FREE PAGES AND RETURN
> ;END OF IFN FTUUOS
IFN FTJSYS,<
M$IPRC: PUSHJ P,VALPAG ;CONSISTENCY CHECK 'AP'
MOVX S1,PT.WRK!PT.ADR ;IN THE WORKING SET, ADDRESSABLE
IORM S1,PAGTBL(AP) ;INCLUDE THE FLAGS
PJRST REDUCE ;REDUCE COUNT OF FREE PAGES AND RETURN
> ;END OF IFN FTJSYS
;ROUTINE TO DETERMINE WHETHER A PARTICULAR NUMBER OF PAGES CAN BE
; ACQUIRED.
;CALL S1 = NUMBER OF PAGES
; PUSHJ P,M$PCNT
; RETURN TRUE OR FALSE
;
;NOTE: UNLESS THE CALLER DISABLES INTERRUPTS THE NUMBER OF AVAILABLE
; PAGES IS VERY VOLATILE.
INTERN M$PCNT
M$PCNT: ADDI S1,PADING ;INCLUDE BUILD IN PADING
CAMLE S1,FREPGS ;CAN WE GET IT?
PJRST .FALSE## ;NO, TELL HIM HE LOSES
PJRST .TRUE## ;YUP, WIN!!
;ROUTINE TO SEARCH THE PAGE MAP FOR THE BEST PAGE FOR M$ACQP TO USE
;CALL PUSHJ P,FNDPAG
; RETURNS AP = THE PAGE OR 0 IF OUT OF ADDRESSING SPACE
;DESTROYS S1
FNDPAG: MOVE AP,PAGSTA ;FIRST AVAILABLE PAGE
FNDP.1: CAIL AP,^D512 ;OFF THE END
JRST FNDP.2 ;YES, DIDN'T FIND ANY, RETURN 0
MOVE S1,PAGTBL(AP) ;GET THE TABLE ENTRY
TXNE S1,PT.USE ;THIS ONE IN USE
AOJA AP,FNDP.1 ;YES, DON'T EVEN BOTHER
TXC S1,PT.WRK!PT.ADR ;FLIP
TXCN S1,PT.WRK!PT.ADR ;BACK, P.S. IS IT INCORE AND FREE
JRST FNDP.3 ;CAN'T GET ANY BETTER THAN THAT
SKIPN AVBPGS ;WILL ANOTHER PASS FIND ANYTHING
POPJ P, ;NO, TAKE THIS FREE PAGE NOW
AOJA AP,FNDP.1 ;YES IT WILL, GO FIND IN CORE PAGE
FNDP.2: TDZA AP,AP ;NO PAGES, RETURN 0
FNDP.3: SOS AVBPGS ;DECREMENT COUNT OF IN CORE PAGES
POPJ P, ;AND RETURN
;CONSISTENCY CHECKS ON THE NUMBER OF FREE PAGES IN OUR ADDRESSING SPACE
;"REDUCE" DECREMENTS THE FREE PAGE COUNT , "INCLUD" ADDS A FREE PAGE
;
;INCLUD DESTROYS S1
REDUCE: SOSGE FREPGS ;DECREMENT COUNT OF FREE PAGES
STOPCD(FCN,FATAL) ;++FREE COUNT NEGATIVE
POPJ P, ;RETURN IF OK
INCLUD: AOS S1,FREPGS ;ADD A FREE PAGE
CAMLE S1,FREINI ;MORE THAN WE STARTED OUT WITH
STOPCD(FCE,FATAL) ;++FREE COUNT EXCEEDS FREINI
POPJ P, ;RETURN IF OK STILL
;CONSISTENCY CHECK ON 'AP', THE PAGE NUMBER ARGUMENT TO
; M$RELP, M$IPSN, M$IPRC
VALPAG: CAIG AP,^D511 ;OVER THE TOP OF THE WORLD
CAMGE AP,PAGSTA ;OR UNDER THE INITIAL VALUE
STOPCD(BPN,FATAL) ;++BAD PAGE NUMBER
POPJ P, ;RETURN, 'AP' IS IN RANGE
SUBTTL The Page Fault Handler
;THIS IS THE ROUTINE CALLED BY THE TOPS10 SYSTEM SO THAT A USER MAY PROCESS
;HIS OWN PAGE FAULTS. .JBPFH CONTAINS THE STARTING ADDRESS OF THE ROUTINE
;AND IS CALLED WHEN EITHER A FAGE FAULT OCCURS OR THE .STTVM TIMER HAS EXPIRED
IFN FTUUOS,< ;THIS CODE EXISTS ONLY FOR THE TOPS10 MONITOR
PFHBGN: JRST PFHSTA ;ENTERED HERE
PFH.PC: 0 ;PC AT TIME OF TRAP
PFH.PN: 0 ;PAGE FAULT WORD
PFH.TI: 0 ;VIRTUAL AGE OF THE PAGE FAULT HANDLER
PFH.RA: 0 ;CURRENT PAGING RATE
BLOCK 4 ;ROOM FOR FUTURE EXPANSION
PFHSTA: MOVEM P,PFHS.P ;SAVE SOMEBODY'S P
MOVE P,[IOWD PF.PSZ,PF.PDL] ;GET MY OWN PDL
PUSH P,P1 ;BEGIN TO SAVE SEVERAL REGISTERS
PUSH P,P2 ;CAUSE I'M GOING TO CALL SUBROUTINES
PUSH P,P3 ;FOR SWAPPING AND SEARCHING
PUSH P,AP ;AND THESE ARE THE ARGUMENTS
LOAD P2,PFH.PN,PF.HFC ;THE FAULT TYPE
CAIG P2,PFHDCT ;RANGE CHECK
JRST PFHDSP(P2) ;DISPATCH THE FAULT
PFHDSP: JRST PFHILL ;PAGE FAULT CODE = 0 OR TOO BIG
JRST PFHGVA ;.PFHNA = 1 = NO ACCESS
JRST PFHSWI ;.PFHNI = 2 = NOT IN CORE
JRST PFHSWI ;.PFHUU = 3 = NOT IN CORE FOR UUO
JRST PFHXIT ;.PFHTI = 4 = IGNORE TIMER TRAPS
PFHDCT==.-PFHDSP-1 ;DISPATCH LENGTH (0-n)
PFHILL: STOPCD (UPF,FATAL) ;++UNKNOWN PAGE FAULT TYPE
PFHSWI: LOAD P3,PFH.PN,PF.HPN ;GET THE PAGE THAT CAUSED THE FAULT
MOVEI P2,1 ;ONLY 1 PAGE
MOVE P1,[.PAGIO,,P2] ;FUNCTION PAGE IO,,ARGUMENT BLOCK
PAGE. P1, ;SWAP IT IN
JRST PFHSWF ;FAILED, SEE WHY
MOVX P1,PT.WRK ;THE WORKING SET BIT
IORM P1,PAGTBL(P3) ;PAGE IS NOW IN CORE
JRST PFHXIT ;DISMISS THE FAULT
PFHSWF: CAIE P1,PAGLE% ;IS MY CORE LIMIT EXCEEDED
STOPCD(PIF,FATAL) ;++PAGE IN FAILURE
PUSHJ P,ANYOUT ;SWAP OUT SOMETHING (ANYTHING)
JRST PFHSWI ;TRY THE SWAPIN NOW
;;;CODE IS CONTINUED ON THE NEXT PAGE AND STILL UNDER FTUUOS CONDITIONAL
;HERE TO GIVE ACCESS TO A PAGE (CAN ONLY HAPPEN IF LOADED VIA GET.SHR)
PFHGVA: LOAD P3,PFH.PN,PF.HPN ;GET THE PAGE NUMBER WE CAN'T ACCESS
TXO P3,1B0 ;SET TO ALLOW ACCESS
MOVEI P2,1 ;ONLY ONE ARG
MOVE P1,[.PAGAA,,P2] ;GIVE ACCESS,,ARGS
PAGE. P1, ;SET ACCESS ALLOWED ON THAT PAGE
STOPCD(CGA,FATAL) ;++CANNOT GIVE ACCESS TO PAGE
PFHXIT: POP P,AP ;RESTORE AP
POP P,P3 ;...
POP P,P2 ;...
POP P,P1 ;...
MOVE P,PFHS.P ;RESTORE THE OLD AC P
JRSTF @PFH.PC ;DISMISS THE FAULT
PFHS.P: BLOCK 1 ;SAVED P
PF.PDL: BLOCK ^D12 ;PDL FOR USE IN THE PAGE FAULT HANDLER
PF.PSZ==.-PF.PDL ;SIZE OF THE LIST
;ROUTINE TO DESTROY AS MANY PAGES THAT ARE SWAPPED OUT OR UNUSED
;CALL PUSHJ P,PGSDES
; RETURNS AFTER DESTROYING AS MANY AS POSSIBLE
;DESTORYS AP,P1-P3 WITHOUT SAVING
PGSDES: MOVE AP,PAGSTA ;THE FIRST AVAILABLE PAGE
PGSD.1: CAIL AP,^D512 ;OFF THE END OF THE WORLD
POPJ P, ;YES, RETURN
MOVE P1,PAGTBL(AP) ;GET THE TABLE ENTRY
TXC P1,PT.ADR ;NEED CHECK FOR BOTH SO FLIP
TXNN P1,PT.USE!PT.ADR ;USED OR NOT ADDRESSABEL
PUSHJ P,DESTRY ;DESTROY THE PAGE (COULD BE PAGED OUT)
AOJA AP,PGSD.1 ;AND CONTINUE LOOPING
DESTRY: MOVEI P3,(AP) ;WANT IT IN P3
TXO P3,1B0 ;SET TO DESTROY
MOVEI P2,1 ;1 ARGUMENT
MOVE P1,[.PAGCD,,P2] ;CREATE/DESTROY,,ARGUMENT
PAGE. P1, ;TRY TO DESTROY IT
STOPCD(PDF,FATAL) ;++PAGE DESTROY FAILED
ZERO P1 ;CLEAR A REG
EXCH P1,PAGTBL(AP) ;CLEAR PAGE MAP ENTRY, GET FLAGS
TXNE P1,PT.WRK ;JUST WIPE OUT AN INCORE PAGE
SOS AVBPGS ;YES, REDUCE COUNTERS ACCORDINGLY
POPJ P, ;RETURN
;;;CODE IS CONTINUED ON THE NEXT PAGE AND STILL UNDER FTUUOS CONDITIONAL
;ROUTINE TO SWAP OUT ANYTHING POSSIBLE SO THAT A PAGEIN CAN OCCUR
;CALL PUSHJ P,ANYOUT
; RETURNS AFTER A PAGE HAS BEEN SUCCESSFULLY PAGED OUT
;DESTROYS AP, P1-P3 WITHOUT SAVING
;COULD EXIT THROUGH DESTRY
INTERN M$IPRM
M$IPRM: PUSHJ P,.SAVE3## ;SAVE P1-P3
SAVE AP ;AND AP AND FALL INTO ANYOUT
ANYOUT: MOVE AP,PAGSTA ;FIRST MAKE A PASS LOOKING FOR ANY FREE
ANYO.1: PUSHJ P,ANYO.4 ;PAGES THAT CAN BE DESTROYED
JUMPE AP,ANYO.2 ;NONE, PAGE SOMETHING OUT
TXNE P1,PT.USE ;IS THIS IN-CORE PAGE USED
AOJA AP,ANYO.1 ;YES, LOOK FOR ANOTHER
PJRST DESTRY ;NO, DESTROY IT NOW AN SAVE A SWAP
ANYO.2: AOS AP,SWPSTA ;START WHERE WE LEFT OFF
PUSHJ P,ANYO.4 ;FIND A SWAPPED IN PAGE
JUMPN AP,ANYO.3 ;SWAP IT OUT
MOVE AP,PAGSTA ;RE-START AT THE FIRST
PUSHJ P,ANYO.4 ;TRY NOW
JUMPN AP,ANYO.3 ;FOUND ONE, SWAP IT OUT
STOPCD (NTS,FATAL) ;++NOTHING TO SWAP OUT
ANYO.3: MOVEM AP,SWPSTA ;REMEMBER FOR LATER
MOVEI P3,(AP) ;COPY THE PAGE NUMBER
TXO P3,1B0 ;SET TO SWAP OUT INSTEAD OF SWAP IN
MOVEI P2,1 ;ONLY 1 PAGE FOR NOW
MOVE P1,[.PAGIO,,P2] ;FUNCTION SWAP,,ARGUMENT BLOCK
PAGE. P1, ;OUT IT GOES
STOPCD(POF,FATAL) ;++PAGE OUT FAILURE
MOVX P1,PT.WRK ;GET THE WORKING SET BIT
ANDCAB P1,PAGTBL(P3) ;NOT THERE ANY MORE, GET NEW FLAGS
TXNN P1,PT.USE ;WAS SOMEBODY USING IT
SOS AVBPGS ;NO, REDUCE COUNT OF INCORE FREE PAGES
POPJ P, ;AND RETURN FOR ANY RETRIES
ANYO.4: CAIL AP,^D512 ;OVER THE TOP
JRST ANYO.5 ;YES, RETURN A ZERO
MOVE P1,PAGTBL(AP) ;GET THE STATUS FLAGS
TXNE P1,PT.ADR ;IS IT ADDRESSABLE
TXNN P1,PT.WRK ;YES, IS IT IN THE WORKING SET
AOJA AP,ANYO.4 ;TRY THE NEXT PAGE
POPJ P, ;YES, A CANDIDATE FOR SWAP OUT
ANYO.5: ZERO AP ;RETURN 0 IF NONE FOUND
POPJ P, ;RETURN
SWPSTA: BLOCK 1 ;PAGE NUMBER FOR START OF SWAP OUT SEARCH
PFHEND: ;THE LAST LOCATION WITHIN THE PAGE FAULT HANDLER
> ;END OF IFN FTUUOS
SUBTTL Constants and Other Things
XLIST ;FORCED OUT LITERAL POOL HERE
LIT
LIST
SALL
FREPGS: BLOCK 1 ;COUNT OF FREE PAGES LEFT IN ADDRESSING SPACE
FREINI: BLOCK 1 ;THE INITIAL VALUE OF FREPGS FOR CONSISTENCY CHECKS
PAGSTA: BLOCK 1 ;THE STARTING POINT FOR PAGSRC SEARCHES
ZERLOC: ; BEGIN BLOCK ZERO'ED AT INITIALIZATION
AVBPGS: BLOCK 1 ;COUNT OF INCORE PAGES THAT AREN'T USED
DOGCOL: BLOCK 1 ;-1 IF GARBAGE COLLECTION WILL DO ANY GOOD
LVLTBL: BLOCK LVLMAX+1 ;LH = MAX ENTRY SIZE, RH = FIRST PAGE IN CHAIN
LVFCNT: BLOCK LVLMAX+1 ;CURRENT FREE CELL COUNTS PER LEVEL(CLASS)
PAGTBL:: BLOCK ^D512 ;THE PAGE MAP
ZERLAS==.-1 ; END OF THE BLOCK ZERO'ED AT ONCE ONLY
END