Trailing-Edge
-
PDP-10 Archives
-
BB-F493Z-DD_1986
-
10,7/703mon/vmser.mac
Click 10,7/703mon/vmser.mac to
see without markup as text/plain
There are 11 other files named vmser.mac in the archive. Click here to see a list.
TITLE VMSER - VIRTUAL MEMORY SERVICE ROUTINE V4636
SUBTTL J. FLEMMING, T. WACHS 5 MAR 86
SEARCH F,S
SALL
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1973,1986>
;COPYRIGHT (C) 1973,1974,1975,1976,1977,1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.
XP VVMSER,4636 ;ASSEMBLY INSTRUCTIONS: VMSER,VMSER/C=F,S,VMSER
ENTRY VMSER
VMSER::
OPDEF PAGE. [CALLI 145]
OPDEF MERGE. [CALLI 173]
SUBTTL BYTE POINTERS
;THESE WILL HAVE TO BE CHANGED IF 30-BIT ADDRESSING IS EVER A REALITY
NVPNP1::POINT P2.SPN,PT2TAB(P1),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNP4::POINT P2.SPN,PT2TAB(P4),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNT1::POINT P2.SPN,PT2TAB(T1),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNT2::POINT P2.SPN,PT2TAB(T2),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNF:: POINT P2.SPN,PT2TAB(F),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
NVPNR:: POINT P2.SPN,PT2TAB(R),<^L<P2.VPN>+P2.SPN-1> ;POINTER TO NEXT
SUBTTL FILIO INTERFACE WITH FILSER
;SUBROUTINE TO SCAN FOR THINGS TO DO FOR THE SWAPPER
;OPTIMIZES ALL SEEK REQUESTS, TRANSFER REQUESTS, STARTS SEEKS GOING
;STARTS DATA TRANSFER GOING IF ON UUO (CHAN 7) LEVEL
SWPSCN::
IFN FTMP,<
SYSPIF
SKIPL T1,SCNOWN## ;IF NO CPU "OWNS" SCNCNT
CAMN T1,.CPCPN## ; OR IF THIS CPU "OWNS" IT
>
AOSE SCNCNT## ;SOMEONE ALREADY DOING THIS?
IFE FTMP,<
PJRST DOPOPJ## ;YES, GO AWAY (AT INTERRUPT LEVEL,
; SWPSCN IS RUNNING AT UUO LEVEL)
>
IFN FTMP,<
JRST [SYSPIN
PJRST DOPOPJ##]
MOVE T1,.CPCPN##
MOVEM T1,SCNOWN##
SYSPIN
>
DSKON
PUSHJ P,SAVE3## ;NO, NOW WE ARE
JUMPE J,SWPSC1 ;GO IF UUO LEVEL
SOS P3,CHNCFS##(P1) ;UPDATE CHANNEL FAIRNESS COUNT FOR SWAPPING
HRR P3,CHNQUE##(P1) ;RH NON-0 IF FILE TRANSFER WAITING
SWPSC1: PUSH P,J ;SAVE J
PUSH P,U ;SAVE U
SWPSC2: SETZB P1,T2 ;INDICATE FIRST CALL TO NEXT
HRLOI T1,377777 ;SET ALL UNITS IN A.S.L. TO HUGE
; TIMES TO BLOCK OR TIMES TO CYLINDER
MOVEI T4,TWCOD##
SWPSC3: SKIPG T3,SWPTAB##(T2) ;UNIT IN ASL?
JRST SWPSC4
CAME T1,UNISWD##(T3) ;TIME ALREADY INFINITY?
CAME T4,UNISTS##(T3) ;NO, IS UNIT IN TRANSFER WAIT?
SKIPA U,T1 ;NO, MAKE TIME = INFINITY
MOVEI U,-1 ;YES, INSURE SWPPIK WILL FIND IT EVEN IF SWPSCN DOESN'T
MOVEM U,UNISWD##(T3) ;SAVE LARGE TIME-TO-BLOCK OR CYLINDER
IFN FTDUAL,<
SKIPE T3,UNI2ND##(T3) ;IN 2ND PORT TOO
MOVEM U,UNISWD##(T3)
>
SWPSC4: CAIGE T2,SWPMAX## ;END OF THE ACTIVE SWAPPING LIST?
AOJA T2,SWPSC3 ;NO, LOOK AT ALL UNITS IN THE ASL
DSKOFF
SWPSC5: PUSHJ P,NEXT ;GET NEXT REQUEST FROM SWPLST
JRST SWPS22 ;DONE
JUMPL U,SWPS10 ;DISK (CPU) GONE, ERROR
HRRZ T2,UNICDA##(U) ;DDB UNIT IS ATTACHED TO
CAIE T2,SWPDDB## ;IF NOT THE SWAPPER
JUMPN T2,SWPSC5 ;LET FILE IO HAPPEN
HRR J,UNIKON##(U) ;SET UP J POINTING TO KONTROLLER
IFN FTDUAL,<
PUSHJ P,RHBP## ;NEED TO REREAD HOME BLOCKS?
JRST SWPSC5 ;YES, DON'T SWAP ON THIS UNIT
CAME J,-1(P) ;IGNORE BUSY IF INT ON THIS KON
SKIPL KONBSY##(J) ;KON BUSY?
JRST SWPSC6 ;IDLE, USE PRIME PORT
SKIPN T3,UNI2ND##(U) ;BUSY, DUAL-PORTED DRIVE?
JRST SWPSC6 ;NO, WAIT FOR PRIME PORT
HRR J,UNIKON##(T3) ;YES, GET 2ND KON
CAME J,-1(P) ;IGNORE BUSY IF INT ON THIS KON
SKIPL KONBSY##(J) ;KON BUSY?
HRRZ U,UNI2ND##(U) ;IDLE, USE 2ND PORT
HRR J,UNIKON##(U) ;GET (NEW) KON
SWPSC6:
IFN FTMP,<
PUSHJ P,SWPCP ;SET U IF OTHER CPU
JFCL
>>;END FTDUAL&FTMP
CAMN J,-1(P) ;IF NOT ON INTERRUPT LEVEL FOR THIS CHAN,
JRST SWPSC7
HRRZ T2,KONCHN##(J)
SKIPE DIADSK##
CAME T2,DIACHN## ;IGNORE REQUEST IF SHUTTING DOWN CHAN
SKIPGE KONBSY##(J) ;IS KONTROLLER IDLE?
JRST SWPSC5 ;NO, TRY NEXT SWPLST ENTRY
JRST SWPSC8 ;YES, THIS REQUEST IS OK
SWPSC7: JUMPGE P3,SWPSC8 ;GO UNLESS BEING FAIR
IFN FTDUAL,<
SKIPE T4,UNI2ND##(U) ;POSITIONS WAITING ON SECOND PORT?
SKIPN UNIQUE##(T4)
>
SKIPE UNIQUE##(U) ;OR PRIME PORT?
JRST SWPSC5 ;YES, DON'T DO THIS REQUEST
SWPSC8: SKIPG KONPOS##(J) ;CAN DO THINGS FOR THIS REQUEST
JRST SWPS12 ;UNIT DOESNT POSITION
MOVE T4,T1 ;POSITIONING UNIT - SAVE BLOCK NUMBER
PUSHJ P,@KONCCM##(J) ;COMPUTE DISTANCE TO BLOCK
JUMPE T1,SWPS11 ;GO IF UNIT ON CYLINDER
MOVMS T1 ;NOT ON CYL, GET + DISTANCE
SKIPE T2,UNISTS##(U) ;IS UNIT IDLE
CAIN T2,O2COD## ; OR OFF-LINE (NEED THIS TO GET TO BADUNI)
JRST SWPSC9 ;YES, SAVE THIS REQUEST
CAIN T2,PWCOD## ;NO, IN POSITION WAIT?
CAML T1,UNISWD##(U) ;YES, IS THIS DISTANCE SHORTER?
JRST SWPSC5 ;NO, TRY NEXT REQUEST
SWPSC9: MOVEI T2,PWCOD## ;MAKE SURE UNIT IS IN POSITION WAIT
PUSHJ P,SETUDB ;SET UNISWA, ETC.
JRST SWPSC5 ;AND TEST NEXT SWPLST ENTRY
;HERE AFTER NUS STOPCD
SWPS10: PUSHJ P,SWPCD1 ;GIVE SWAP READ ERROR
JRST SWPSC5 ;AND PUSH ON
;HERE IF UNIT ON-CYLINDER
SWPS11: MOVE T1,T4 ;RESTORE BLOCK NUMBER
;HERE IF UNIT DOESN'T POSITION OR ON CYLINDER
SWPS12: CAMN J,-1(P) ;INTERRUPT LEVEL FOR THIS KON?
JRST SWPS13 ;YES
SKIPL KONBSY##(J) ;NO, IS KON BUSY?
JRST SWPS14 ;NO, KON IDLE
JRST SWPSC5 ;YES, KON BUSY
SWPS13: TRNE P3,-1 ;TRANSFERS WAITING?
JUMPL P3,SWPSC5 ;YES, IGNORE IF BEING FAIR
SWPS14:
IFN FTDUAL,<
HRRZ T2,UNICHN##(U) ;FILE TRANSFERS WAITING ON THIS CHAN?
SKIPE CHNQUE##(T2)
SKIPN T2,UNI2ND##(U) ;AND DUAL PORTED?
JRST SWPS16 ;NO, OK LET IT HAPPEN
HRR J,UNIKON##(T2) ;YES, IS OTHER KON BUSY?
CAME J,-1(P)
SKIPL KONBSY##(J)
JRST SWPS15 ;IDLE, LET SWAP HAPPEN
HRRZ T2,KONCUA##(J) ;BUSY, IS IT DOING A SWAP?
MOVE T3,UNISTS##(T2)
HRRZ T4,UNICDA##(T2)
CAIN T3,TCOD##
CAIE T4,SWPDDB##
JRST SWPS15 ;NOT A SWAP
JRST SWPSC5 ;DON'T TIE UP BOTH CHANNELS DOING SWAPS
;LEAVE ONE CHANNEL OPEN FOR FILE I/O
SWPS15: HRR J,UNIKON##(U) ;GET KON BACK
SWPS16:>
IFN FTMP,<
MOVE T2,KONCAM##(J)
TDNE T2,.CPBIT##
>
PUSHJ P,@KONLTM##(J) ;COMPUTE TIME TO BLOCK
MOVEI T1,0 ;UNIT OFF-LINE
SKIPE T2,UNISTS##(U) ;IS UNIT IDLE
CAIN T2,PWCOD## ; OR POSITION WAIT?
JRST SWPS17 ;YES, THIS IS THE BEST TIME TO BLOCK
CAIN T2,TWCOD## ;NO, TRANSFER WAIT?
CAMLE T1,UNISWD##(U) ;YES, IS THIS BEST?
JRST SWPSC5 ;NO, TEST NEXT ENTRY
SWPS17: MOVEI T2,TWCOD## ;SET UNIT TO TRANSFER WAIT
PUSHJ P,SETUDB ;SET UNISWA, ETC.
IFN FTCIDSK,<
SKIPL KONMX##(J) ;MULTIPLE XFERS?
JRST SWPSC5 ;NO
PUSHJ P,SWPCH ;PARANOIA
JRST SWPSC5
SKIPL KONCNA##(J) ;CREDITS?
PUSHJ P,THSBLK ;YES, GET BLOCK NUMBER
JRST SWPSC5 ;MEMTAB MESSED UP
IFN FTMP,<
PUSHJ P,SWPCD ;ON THIS CPU?
JRST SWPS18 ;NO, SET SO DSKTIC WILL FIND IT
>
MOVEM T1,DEVBLK##(F) ;SAVE IN SWPDDB
MOVEM U,DEVUNI##(F) ;SAVE U IN DDB
PUSH P,P1 ;SAVE OUR PLACE
MOVE P1,KONCHN##(J) ;CHAN LOC
PUSHJ P,STRTIO## ;GO CRANK UP THE IO
POP P,P1 ;WHERE WERE WE?
DSKOFF ;STRTIO ENABLED INTERRUPTS
IFN FTMP,<
JRST SWPSC5
SWPS18: HRRZM J,.C0SWP##(T4) ;WAKE UP THE OTHER CPU
>
>; END IFN FTCIDSK
IFE FTCIDSK,<
JRST SWPSC5 ;JUST RESCAN IF NO CI DISKS
>
IFN FTMP,<
SWPS20: SETOM .C0SWP##(T4) ;COME BACK AT DSKTIC
>
SWPS21: PUSHJ P,IDLEPW## ;SET IDLE OR PW
JRST SWPS26
;HERE WHEN ALL OF SWPLST HAS BEEN SCANNED. START SEEKS GOING
SWPS22: MOVEI P2,0 ;START AT 1ST UNIT IN ASL
SWPS23: SKIPG U,SWPTAB##(P2) ;GET UNIT
JRST SWPS26 ;NOT THERE, TRY NEXT
DSKOFF ;NO DISK INTERRUPTS HERE
MOVE T1,UNISTS##(U) ;STATE OF UNIT
MOVE T2,UNISWD##(U) ;DISTANCE OR TIME OF BEST
CAME T2,[377777,,-1];IS ANYTHING THERE?
CAIE T1,PWCOD## ;YES, POSITION WAIT?
JRST SWPS26 ;NO
HRR J,UNIKON##(U) ;KONTROLLER
IFN FTCIDSK,<
SKIPGE KONMX##(J) ;IF IT'S PW, WE DIDN'T PUT IT THERE
JRST SWPS26
>
IFN FTDUAL,<
CAME J,-1(P) ;IGNORE BUSY IF INT ON THIS KON
SKIPL KONBSY##(J) ;KON BUSY?
JRST SWPS24 ;IDLE, USE PRIME PORT
SKIPN T3,UNI2ND##(U) ;BUSY, DUAL-PORTED DRIVE?
JRST SWPS24 ;NO, WAIT FOR PRIME PORT
HRR J,UNIKON##(T3) ;YES, GET 2ND KON
CAME J,-1(P) ;IGNORE BUSY IF INT ON THIS KON
SKIPL KONBSY##(J) ;KON BUSY?
HRRZ U,UNI2ND##(U) ;IDLE, USE 2ND PORT
HRR J,UNIKON##(U) ;GET (NEW) KON
SWPS24:>
MOVE P1,UNISWA##(U) ;GET SWPLST ENTRY
IFN FTMP,<
PUSHJ P,SWPCD ;UNIT ON THIS CPU?
JRST SWPS20 ;NO,COME BACK AT DSKTIC
>
CAMN J,-1(P) ;ON INTERRUPT LEVEL?
JRST SWPS25 ;YES, KONTROLLER ISNT REALLY BUSY
MOVSI T2,KOPPWX##
AND T2,KONPOS##(J) ;T2 NON-0 IF KON CAN START SEEKS WHILE BUSY
SKIPE DIADSK## ;IF DIAG IS GOING
SETZ T2, ;REQUIRE KDB TO BE IDLE
SKIPGE KONBSY##(J) ;IS KONTROLLER NOW BUSY?
JUMPE T2,SWPS21 ;YES, TOUGH LUCK
SWPS25:
IFN FTDUAL,<
HRL P1,U ;SAVE U (2ND PORT OF DUAL-PORTED DRIVE)
>
PUSHJ P,THSBLK ;NO, GET BLOCK AND UNIT AGAIN
JRST SWPS26 ;MEMTAB IS MESSED UP
IFN FTDUAL,<
HLRZ U,P1 ;RESTORE U
>
MOVEM T1,DEVBLK##(F) ;SAVE BLOCK IN SWPDDB FOR UNIPOS
MOVEM U,DEVUNI##(F) ;SAVE UNIT IN SWPDDB
MOVE P1,KONCHN##(J) ;IN CASE STRPOS CALLS STRTIO
IFN FTDUAL,<
SKIPE T1,UNI2ND##(U) ;TO DETECT SPURIOUS INTERRUPTS
SETZM UNICDA##(T1)
SETOM UNICDA##(U) ;SAVE F IN ACTIVE UDB
>
PUSHJ P,STRPOS## ;GO START THE SEEK
SWPS26: CAIGE P2,SWPMAX## ;AT END OF SWPTAB?
AOJA P2,SWPS23 ;NO, TEST NEXT UNIT IN ASL
;HERE WHEN ALL UNITS HAVE BEEN STARTED SEEKING
DSKON
SKIPN -1(P) ;INTERRUPT LEVEL?
JRST SWPPI1 ;NO, START IO IF A UNIT IN TW
PJRST SWPPI6 ;YES, EXIT HOLDING SCNLOK (SWPPIK
;WILL BE CALLED SOON)
;ROUTINE TO SAVE STUFF IN UDB
;ENTER T1=UNISWD, T2=UNISTS, P1=UNISWA
SETUDB: MOVEM T1,UNISWD##(U) ;SAVE TIME
MOVEM P1,UNISWA##(U) ;SAVE SWPLST POSITION
IFN FTCIDSK,<
SKIPL KONMX##(J)
>
MOVEM T2,UNISTS##(U) ;SAVE PW/TW
IFN FTDUAL,<
SKIPN T3,UNI2ND##(U) ;IS THERE A SECOND PORT?
POPJ P, ;NO
MOVEM T1,UNISWD##(T3) ;YES, SET UP THAT UDB TOO
MOVEM P1,UNISWA##(T3)
IFN FTCIDSK,<
SKIPL KONMX##(J)
>
MOVEM T2,UNISTS##(T3)
>
POPJ P,
;SUBROUTINE TO SCAN ALL UNITS IN A.S.L., START TRANSFER ON BEST
SWPPIK::
IFN FTMP,<
SKIPL T1,SCNOWN##
CAMN T1,.CPCPN## ;IF THIS CPU "OWNS" SCNCNT
>
SKIPE SCNCNT## ;SOMEONE ALREADY HERE?
POPJ P, ;YES, WAIT A WHILE
PUSHJ P,SAVE2## ;SAVE P1,P2
PUSH P,J ;SAVE J
PUSH P,U
HRRZ P2,P1 ;SAVE LOC OF CHAN DB
MOVSI T1,KOPBSY## ;SET EVERYTHING IDLE SO FILIO WILL DO SOMETHING
ANDCAM T1,KONBSY##(J) ; (THEY REALLY ARE, HAVEN'T YET BEEN MARKED)
SWPPI1: SETZB T1,P1 ;INITIALIZE
HRLOI T2,377777 ;INITIALIZE BEST-SO-FAR
DSKOFF
SWPPI2: SKIPG U,SWPTAB##(T1) ;GET ASL ENTRY
JRST SWPPI4
HRR J,UNIKON##(U) ;SET KONTROLLER
IFN FTDUAL,<
CAIE P2,@KONCHN##(J) ;IGNORE BUSY IF INT ON THIS CHAN
SKIPGE @KONCHN##(J) ;CHAN BUSY?
JRST SWPPI3 ;IDLE, USE PRIME PORT
SKIPN T3,UNI2ND##(U) ;BUSY, DUAL-PORTED DRIVE?
JRST SWPPI3 ;NO, WAIT FOR PRIME PORT
HRR J,UNIKON##(T3) ;YES, GET 2ND KON
CAIE P2,@KONCHN##(J) ;IGNORE BUSY IF INT ON THIS CHAN
SKIPGE @KONCHN##(J) ;CHAN BUSY?
HRRZ U,UNI2ND##(U) ;IDLE, USE 2ND PORT
HRR J,UNIKON##(U) ;GET (NEW) KON
SWPPI3:>
IFN FTMP,<
PUSHJ P,SWPCP ;ON THIS CPU?
JRST [SKIPLE .C0SWP##(T4) ;NO, ALREADY QUEUED AN IO ON OTHER CPU?
JRST SWPPI4 ;YES, IGNORE THIS UNIT
JRST .+1] ;NO, GET 1 TO START ON OTHER CPU
>
IFE FTMP&FTDUAL,<
MOVE T3,UNISTS##(U) ;STATE OF UNIT
>
IFN FTMP&FTDUAL,<
SKIPG T3,SWPTAB##(T1) ;GET UNISTS FROM THE UNIT WHICH IS IN
JRST SWPPI4 ;?
MOVE T3,UNISTS##(T3) ; SWPTAB (MIGHT HAVE CHANGED U TO 2ND PORT)
>
CAIE P2,@KONCHN##(J)
SKIPGE @KONCHN##(J) ;IS CHANNEL IDLE?
CAIE T3,TWCOD## ;YES, UNIT IN TRANSFER WAIT?
JRST SWPPI4 ;NO, TEST NEXT UNIT
CAMLE T2,UNISWD##(U) ;YES, IS THIS BEST SO FAR?
PUSHJ P,SWPCH ;YES, CAN WE DO THIS IO (FRAG'D LIST)?
JRST SWPPI4 ;NO, TRY NEXT
MOVE T2,UNISWD##(U) ;YES, SAVE TIME
MOVE P1,UNISWA##(U) ;SAVE SWPLST POSITION
IFN FTDUAL,<
HRL P1,U ;SAVE ACTUAL UNIT
>
SWPPI4: CAIGE T1,SWPMAX## ;END OF ASL?
AOJA T1,SWPPI2 ;NO, TRY NEXT UNIT
JUMPE P1,SWPPI5 ;RETURN IF NOTHING TO DO
;HERE WHEN BEST TRANSFER HAS BEEN FOUND FOR SOME CHANNEL
PUSHJ P,THSBLK ;GET BLOCK NUMBER
JRST [SETZM (P1) ;MEMTAB MESSED UP
JRST SWPPI5]
IFN FTDUAL,<
HLRZ U,P1 ;GET ACTUAL UNIT BACK
>
HRR J,UNIKON##(U) ;SET UP KONTROLLER
IFN FTMP,<
PUSHJ P,SWPCD ;ON THIS CPU?
JRST SWPPI7 ;NO, SET SO DSKTIC WILL FIND IT
>
MOVEM T1,DEVBLK##(F) ;SAVE IN SWPDDB
MOVEM U,DEVUNI##(F) ;SAVE U IN DDB
MOVE P1,KONCHN##(J) ;AND CHAN LOC
SKIPGE KONBSY##(J) ;IS KONTROLLER BUSY?
JRST SWPPI8 ;YES, CANT USE IT NOW
SETZM (P1) ;CHAN IS BUSY
IFN FTDUAL,<
SKIPE T1,UNI2ND##(U)
SETZM UNICDA##(T1)
SETOM UNICDA##(U)
>
PUSHJ P,STRTIO## ;GO CRANK UP THE IO
CAIN P2,@KONCHN##(J) ;YES, INT ON THIS CHAN?
TLO P2,-1 ;YES, FLAG THAT CHAN IS NOW BUSY
JRST SWPPI1 ;LOOK FOR OTHER CHAN
;HERE WHEN THROUGH
SWPPI5: DSKON
SOSL SCNCNT## ;DECREMENT SCNCNT. DID INTERRUPT LEVEL TRY?
JUMPGE P2,SWPSC2 ;YES, SCAN AGAIN (UNIT IN ASL MAY HAVE CHANGED STATE)
;DON'T RETRY IF STARTED XFER. COULDN'T TELL
;IF KON WAS REALLY BUSY.
SKIPGE P2 ;STARTED XFER ON THIS CHAN?
AOS -2(P) ;YES, TELL FILSER SOMETHING HAPPENED
IFN FTCIDSK,<
;NOTE THAT FOR A CI TYPE DISK WE END UP LYING TO FILIO.
;WE TELL HIM THAT WE DIDN'T START A TRANSFER WHEN ACTUALLY WE DID.
;THIS WILL CONVINCE HIM THAT IT'S OK TO START A FILE.
>
IFN FTMP,<
SETOM SCNOWN##
>
MOVE J,-1(P) ;RESTORE J
JUMPE J,SWPPI6 ;IF ON INTERRUPT LEVEL,
MOVE P1,KONCHN##(J) ;GET CHAN LOC
SKIPGE T1,CHNCFS##(P1);RESTORE CHNCFT IF IT COUNTED
MOVE T1,CHNIFS##(P1); BELOW 0
MOVEM T1,CHNCFS##(P1)
SWPPI6: POP P,U ;RESTORE U
PJRST JPOPJ## ;AND EXIT
IFN FTMP,<
SWPPI7: HRRZM J,.C0SWP##(T4) ;.CPSWP GREATER THAN 0
>
SWPPI8: DSKON
JRST SWPPI1
;SUBROUTINE TO SEE IF A SWAP REQUEST MAY BE STARTED
;CALLED AT INTERRUPT LEVEL BY FILIO ON A POSITION-DONE INTERRUPT AND BY SWPPIK
;NON-SKIP RETURN IF CAN'T START IT NOW (FRAGMENTED, ANOTHER FRAGMENT IN PROGRESS)
;SKIP RETURN IF IO CAN BE STARTED
;PRESERVES T1,T2
SWPCH:
SWPCHK::HLRZ T3,UNISWA##(U) ;FRAGMENTED?
JUMPE T3,CPOPJ1## ;NO, OK TO START
HRL T3,(T3)
MOVSS T3 ;YES, GET START OF CHAIN
SWPCH1: SKIPN T4,(T3) ;GET FRAGMENT POINTER
PJRST CPOPJ1## ;DONE - OK TO START
JUMPL T4,[HRR T3,T4
JRST SWPCH1]
TLNE T4,(SL.IOP) ;IN PROGRESS?
CAMN T3,UNISWA##(U) ;YES, IS IT THE ONE WE WANT TO START?
AOJA T3,SWPCH1 ;THIS ONE IS OK, CHECK NEXT
POPJ P, ;IO ALREADY HAPPENING - QUEUE THIS TILL LATER
IFN FTMP,<
;RETURNS CPOPJ IF ON OTHER CPU, CAUSES SWAP READ ERROR IF OTHER CPU IS DEAD
; RETURN CPOPJ1 IF ON THIS CPU
;PRESERVES T1,T2
SWPCD: PUSHJ P,SWPCP ;ON THIS CPU?
CAIA ;NO
JRST CPOPJ1## ;YES, ON THIS CPU RETURN
MOVSI T3,(CR.DET) ;CPU IS DETACHED BIT
TDNN T3,.C0RUN##(T4) ;CPU DETACHED?
POPJ P,
>
SWPCD1: PUSHJ P,SAVT## ;PRESERVE T1,T2 - SAVE T4
PUSHJ P,SW2LC ;INDEX INTO SW2LST
MOVE T4,SW2LST##(T1) ;ORIGINAL SWPLST ENTRY
TLO T4,(SL.ERR+SL.IOP) ;ERROR + I/O IN PROGRESS
PJRST DONE1 ;SET IT DONE
IFN FTMP,<
;RETURNS CPOPJ IF ON OTHER CPU, CPOPJ1 IF ON THIS
;PRESERVES T1,T2
SWPCP: MOVE T4,KONCAM##(J) ;CPU THAT THIS KONTROLLER IS ON
TDNE T4,.CPBIT## ;THIS CPU?
JRST CPOPJ1## ;YES, DO THE I/O NOW
IFN FTDUAL,<
SKIPN T3,UNI2ND##(U) ;SECOND PORT
JRST SWPCP1
HRRZ T3,UNIKON##(T3)
MOVE T3,KONCAM##(T3) ;2ND PORT ON THIS CPU?
TDNN T3,.CPBIT##
JRST SWPCP1 ;NO
HRRZ U,UNI2ND##(U) ;SWITCH TO OTHER PORT
HRR J,UNIKON##(U) ;KONTROLLER FOR SECOND PORT
JRST CPOPJ1## ;DO I/O NOW RETURN
SWPCP1:
>
PUSH P,T1 ;SAVE AC
PUSH P,T2
PUSHJ P,GETCAM## ;BUILD COMBINED CPU BIT MASK
PUSHJ P,CAMCPU## ;PICK BEST CPU
JRST TTPOPJ##
> ;END IFN FTMP
;SUBROUTINE TO GET THE NEXT ENTRY FROM SWPLST
;CALL WITH P1=0 ON FIRST ENTRY
;SUBSEQUENTLY CALL WITH P1,P2=NUMBERS RETURNED FROM THE LAST CALL
;RETURNS CPOPJ IF NO MORE ENTRIES
;RETURNS CPOPJ1 WITH P1 POINTING AT NEXT ENTRY,
; U=LOC OF UNIT DATA BLOCK, T1=PHYSICAL DSK BLOCK NUMBER
NEXT: JUMPN P1,NEXT2 ;FIRST CALL?
PUSHJ P,UUOLVL## ;IF AT UUO LEVEL
JRST NEXT1 ;AVOID CHANGING THE UBR
HRRZ P1,.USSLX ;BY FINDING ONLY THE ENTRY FOR THIS JOB
MOVE T1,SWPLST##(P1)
TLNE T1,(SL.IOP!SL.IOD) ;ALREADY STARTED?
POPJ P, ;YES, GO AWAY
MOVEI P2,1
MOVEI P1,SWPLST##-1(P1)
JUMPL T1,NEXT9 ;IF FRAGMENTED
JRST NEXT7
NEXT1: MOVEI P1,SWPLST##-1 ;YES, INITIALIZE P1
SKIPN P2,SPRCNT## ;ONLY LOOK AT SWAPS IF THERE ARE ANY
SKIPA P2,SLECNT## ;P2=NUMBER OF ENTRIES IN SWPLST
ADD P2,SWPCNT##
NEXT2: JUMPE P2,CPOPJ## ;NON-SKIP RETURN IF NO MORE ENTRIES
NEXT3: SKIPA T2,[TLNN T1,(SL.IOP)] ;ASSUME NOT A FRAGMENTED ENTRY
NEXT4: MOVE T2,[TLNE T1,(SL.IOP)] ;IF IT IS A FRAGMENTED ENTRY
NEXT5: SKIPN T1,1(P1) ;IS THERE ANOTHER ENTRY IN SWPLST?
JRST NEXT11 ;MAYBE (IF WE'RE IN A FRAGMENT CHAIN)
SKIPE SPRCNT## ;IF ANY SWAPS WAITING,
TLNE T1,(SL.SIO) ;IF THIS IS A SWAP REQUEST
SKIPA T4,SINCNT## ; TEST IT
JRST NEXT11 ;PAGE REQUEST - IGNORE FOR NOW
JUMPL T1,NEXT9 ;SWAP, IS IT A FRAGMENT POINTER?
JUMPE P2,NEXT6 ;IGNORE SINCNT IF FRAGMENT IN PROGRESS
TLNE T1,(SL.DIO) ;NO, IF AN OUTPUT REQUEST
JUMPG T4,NEXT11 ; IGNORE IT IF ANY INPUT REQUESTS WAITING
NEXT6: XCT T2 ;IS IT USABLE?(SL.IOP=0 IF NOT IN A FRAGMENT CHAIN
; , SL.IOP=1 IF IN A FRAGMENT CHAIN)
TLNE T1,(SL.IOD) ; AND SL.IOD=0
AOJA P1,NEXT13 ;NO, TRY NEXT
TLZN P1,400000 ;FIRST TIME FOR THIS ENTRY?
TLNN P1,-1 ;NO, IN A FRAGMENT?
JRST NEXT7 ;NO, USE THIS ENTRY
MOVSI T4,(SL.MAP) ;MAP INFO IN THIS ENTRY BIT
TLNN T1,(SL.DIO) ;YES, SWAPPING OUT?
JRST NEXT7 ;NO, ALL IS WELL
SKIPE 2(P1) ;YES, LAST ENTRY IN THE FRAGMENT?
TDNE T4,1(P1) ;MAP INFO THIS ENTRY AS BAD AS LAST
JRST NEXT11 ;YES, CANT USE IT (CANT WRITE UPMP TILL ALL
; DSK ADDRESSES ARE FILLED IN)
NEXT7:
IFN FTMP&FTKL10,<
TLNE T1,(SL.DIO) ;IF PAGING OUT
TLNE T1,(SL.SIO) ;(NOT SWAPPING)
JRST NEXT8
PUSHJ P,SW2LC
TLNE P1,-1
SUBI T1,1
HRR J,SW3LST##+1(T1) ;GET JOB NUMBER
PUSHJ P,CHKCSH## ;IS IT RIGHT WRT CACHE?
SKIPA T1,1(P1) ;YES, DO IT
JRST NEXT11 ;NO, TRY SOMEONE ELSE
>
NEXT8: PUSHJ P,SWPMEM ;YES, GET DSK ADR, UNIT
JRST NEXT11 ;SWPLST IS ZERO!
TLNN P1,-1 ;A MAIN ENTRY?
SUBI P2,1 ;YES, DECREMENT NO OF ENTRIES LEFT
AOJA P1,CPOPJ1## ;AND SKIP-RETURN
;HERE ON A POINTER TO A FRAGMENT
NEXT9: HLRZ T3,P1 ;T3 NON-0 IF NOT FIRST LINK (FATHER NOT SWPLST ENTRY)
JUMPN T3,NEXT10 ;GO IF NOT FIRST TIME IN THIS FRAGMENT
TLNE T1,(SL.IOD!SL.IOP) ;I/O ALREADY STARTED OR DONE?
JRST NEXT11 ;DONE, ERROR, OR ACTIVE, NEXT ENTRY
MOVE T4,T1 ;SAVE THIS PIECE
PUSHJ P,SW2LC ;WE THINK WE FOUND A USABLE ENTRY
MOVE T4,SW2LST##+1(T1) ;TO SEE WHAT WE MUST LOOK FOR
MOVE T1,1(P1) ;OK - RESTORE SWPLST ENTRY TO T1
MOVSI P1,400001(P1) ;SAVE POINT IN SWPLST WHERE WE TURNED DOWN
SOJL P2,CPOPJ## ;COUNT THE ENTRY
NEXT10: HRRI P1,-1(T1) ;SET RH(P1) FOR 1ST THING IN CHAIN
JUMPN T3,NEXT5 ;T2 SET UP RIGHT IF NOT 1ST LINK
JUMPE T4,NEXT3 ;IF ANOTHER FRAG THIS ENTRY NOT
;BEING DONE, ANY PART IS OK
SETZ P2, ;MAKE SURE THIS ENTRY IS PICKED
JRST NEXT4
;HERE WHEN AT END OF CHAIN
NEXT11: JUMPLE P2,CPOPJ## ;RETURN IF ALL ITEMS IN SWPLST SCANNED
TLNN P1,-1 ;NOT END, IN A FRAGMENT?
AOJA P1,NEXT12 ;NO, TRY NEXT SWPLST ENTRY
HLRZS P1 ;RESTORE MAIN LOC IN SWPLST IF FRAGMENT
TRZ P1,400000 ;BIT IS ON IF FOUND NOTHING
NEXT12: CAIL P1,SW2LST## ;REACHED END?
POPJ P, ;YES (DUAL CPU, OTHER CPU IN ZERSLE)
JRST NEXT3
NEXT13: TLNE P1,-1 ;FRAGMENT?
JRST NEXT5 ;YES, P2 ALREADY DECREMENTED
SOJG P2,NEXT5 ;NO, DECR P2 AND TRY NEXT
POPJ P, ;ALL DONE - RETURN
;SUBROUTINE TO GET THE BLOCK NUMBER FOR THIS SWPLST ENTRY
;CALL P1= LOC OF ENTRY
;RETURNS CPOPJ1 WITH U SET UP, T1= BLOCK NUMBER
;RETURNS CPOPJ IF THINGS ARE MESSED UP
THSBLK: SKIPN T1,(P1) ;GET SWPLST ENTRY
STOPCD CPOPJ##,DEBUG,NSE, ;++NO SWPLST ENTRY
; PJRST SWPMEM ;FALL INTO SWPMEM
;SUBROUTINE TO OBTAIN THE DISK ADDRESS FROM MEMTAB
;ENTER WITH T1=SWPLST ENTRY
;RETURN CPOPJ1 WITH U, T1 SET TO DISK ADDRESS
;RETURNS CPOPJ IF THINGS ARE MESSED UP
SWPMEM: SE1ENT ;MUST BE IN SECTION 1 TO REFERENCE MEMTAB
LDB T1,[POINT 13,T1,26] ;GET PHYSICAL PAGE NUMBER
SSX T1,MS.MEM ;MEMTAB SECTION
SKIPN T1,MEMTAB(T1) ;GET DSK ADDRESS
STOPCD CPOPJ##,DEBUG,MIZ, ;++MEMTAB IS ZERO
SWPADR::LDB U,SSUNT1## ;GET SWAP UNIT
MOVE U,SWPTAB##(U)
JUMPL U,CPOPJ1## ;UNIT GONE, BUT WE EXPECTED IT
SKIPE U
SKIPG UNISLB##(U)
STOPCD .,STOP,SBZ, ;++SWAP BLOCK ZERO
LDB T1,SLKNT1## ;1ST LOGICAL K
ROT T1,BLKSPP## ;CONVERT TO BLOCKS
ADD T1,UNISLB##(U) ;PLUS STARTING BLOCK NUMBER
JRST CPOPJ1## ;RETURN
;SUBROUTINE TO BE CALLED WHEN IO IS FINISHED. ENTERED AT INTERRUPT LEVEL FROM FILIO
;CALLED WITH P1=LOC OF SWPLST ENTRY, T1= NUMBER OF BLOCKS TRANSFERRED, P2=ERROR BITS
DONE:: MOVE T2,(P1) ;SWPLST ENTRY
MOVEI T3,UNIICT##(U) ;SET CORRECT UNIT WORD TO
TLNN T2,(SL.IPC) ;IPC AND PAGE QUEUES ARE PAGING I/O
TLNN T2,(SL.SIO) ; COUNT THE IO (SWAP OR PAGE, IN OR OUT)
MOVEI T3,UNIPCI##(U)
TLNE S,IO
ADDI T3,1
ADDM T1,(T3)
PUSHJ P,SW2LC ;GET INDEX INTO 2ND TABLE
MOVE T4,SW2LST##(T1) ;ORIGINAL SWPLST ENTRY
TRNE S,IODERR+IODTER+IOIMPM ;IO ERROR?
TLO T4,(SL.ERR) ;YES, SET BIT
TRNE P2,IOCHMP+IOCHNX ;CHAN-DETECTED ERROR?
TLO T4,(SL.CHN) ;YES
DONE1: HLRZ T3,P1 ;ORIGINAL SWPLST ENTRY IF A FRAGMENT
LDB T2,[POINT 9,(P1),35] ;NUMBER OF PAGES LEFT IN ENTRY
TLNN T4,(SL.ERR+SL.CHN) ;ABORT IF ERROR
JUMPN T2,DONE7
JUMPE T3,DONE2 ;NO, GO IF NOT IN A FRAGMENT
MOVSI T2,(SL.IOP) ;IN A FRAGMENT - CLEAR THE IOP BIT
ANDCAM T2,(T3) ; IN THE SWPLST ENTRY ITSELF
DONE2: TLZE T4,(SL.IOP) ;CLEAR IN-PROGRESS BIT
TLOE T4,(SL.IOD+SL.DFM) ;SET DONE BIT
STOPCD .+1,DEBUG,SBW, ;++SWPLST BITS WRONG
SETZM SW2LST##(T1)
MOVEM T4,(P1) ;SAVE UPDATED SWPLST ENTRY
TLNE T4,(SL.CHN+SL.ERR)
HRRZM U,SWPEUJ## ;SAVE ADR OF UNIT
JUMPE T3,DONE6 ;FINISHED IF NONE
TLNE T4,(SL.ERR+SL.CHN) ;IF AN ERROR,
JRST DONE5 ; DONT WASTE TIME BY CONTINUING
SKIPL T1,(T3) ;GET ADR OF START OF CHAIN
STOPCD DONE5,DEBUG,NRF, ;++SWPLST NOT REALLY FRAGMENTED
DONE3: SKIPN T2,(T1) ;LOOK AT NEXT ENTRY IN FRAGMENT CHAIN
JRST DONE5 ;WHOLE CHAIN DONE IF AT END
JUMPGE T2,DONE4 ;CHECK IT IF NOT ANOTHER POINTER
MOVE T1,T2 ;GO TO NEXT PART OF CHAIN
JRST DONE3
DONE4: TLNN T2,(SL.IOD) ;THIS FRAGMENT DONE?
POPJ P, ;NO, DONT WAKE UP SWAPPER
AOJA T1,DONE3 ;YES, TEST NEXT ENTRY OF FRAGMENT CHAIN
;HERE IF THE ENTIRE SWPLST FRAGMENT CHAIN IS FINISHED
DONE5: HLLZS T4 ;INDICATE DONE, ERROR BIT IF ON
IORB T4,(T3)
HLRZS P1 ;POINT TO SWPLST
DONE6: HRLOI T1,377777 ;SET UNISWD HUGE
IFN FTDUAL,<
SKIPE T2,UNI2ND##(U)
MOVEM T1,UNISWD##(T2)
>
MOVEM T1,UNISWD##(U)
TLNE T4,(SL.IPC) ;IF IPC PAGING
TLNN T4,(SL.DIO) ; OUT
JRST SWPINT##
TLNN T4,(SL.SIO) ;DON'T IF REALLY SWAPPING REPLACABLE QUEUE
AOS IPCCNT## ;BUMP A COUNT
PJRST SWPINT## ;KICK THE SWAPPER
;HERE IF THE SWPLST ENTRY WASN'T ENTIRELY PROCESSED
DONE7: SKIPN T3 ;IN A FRAGMENT?
MOVEI T3,(P1) ;NO, PICK UP ADDR OF ENTRY
MOVSI T1,(SL.IOP) ;CLEAR THE IO IN PROGRESS BIT
ANDCAM T1,(T3) ; SO NEXT WILL CONSIDER THIS ENTRY AGAIN
POPJ P, ;AND RETURN
;SUBROUTINE TO SET UP AN IOLIST FOR A SWAP/PAGE OPERATION
;ENTER P1=LOC OF SWPLST ENTRY, T3= MAX NUMBER OF BLOCKS TO DO
;EXIT P3=LOC OF 1ST IOWD, T1= NUMBER OF BLOCKS IN LIST
THIS:: PUSHJ P,GETSWJ ;GET JOB NUMBER
PUSHJ P,SVEUB## ;SAVE MAPPING IN EFFECT
PUSHJ P,SAVE4## ;SAVE P'S
LSH T3,-2 ;CONVERT BLOCKS TO PAGES
MOVE P4,(P1) ;GET SWPLST ENTRY
LDB P2,[POINT SL.SCT,P4,<^L<SL.CNT>+SL.SCT-1>] ;NUMBER OF PAGES REQUIRED
MOVE T2,P2
CAMLE P2,T3 ;NEED MORE THAN WE CAN DO?
MOVE P2,T3 ;YES, SETTLE FOR LESSER AMOUNT
SUB T2,P2 ;AMOUNT LEFT AFTER THIS OPERATION FINISHED
SKIPN P2 ;REALLY ANYTHING TO DO?
STOPCD .,STOP,ZPS, ;++ZERO PAGE SWAP
PUSH P,T2
TLO P4,(SL.IOP) ;INDICATE IO IN PROGRESS
PUSHJ P,SW2LC
SKIPN SW2LST##(T1) ;IF THE FIRST TIME,
MOVEM P4,SW2LST##(T1) ; SAVE THE SWPLST ENTRY IN DUPLICATE TABLE
DPB T2,[POINT SL.SCT,P4,<^L<SL.CNT>+SL.SCT-1>] ;UPDATE SWPLST ENTRY WITH NEW COUNT
MOVEM P4,(P1)
MOVE T2,P2 ;NUMBER OF PAGES WE'LL DO
LSH T2,2 ;CONVERT TO BLOCKS
EXCH T2,(P)
PUSH P,T2 ;SAVE (RETURN NUMBER TO FILIO)
DSKOFF ;PROTECT AGAINST S BEING CHANGED AT
; INTERRUPT LEVEL
TLNE P4,(SL.DIO) ;INPUT OR OUTPUT?
TLOA S,IO ;OUTPUT
TLZ S,IO ;INPUT
TRZ S,IODTER+IODERR+IOIMPM
MOVEM S,DEVIOS(F) ;SAVE UPDATED S
IFN FTKL10,<
SETZ P1, ;WE NEED AN IOWD
PUSHJ P,GCH4WD## ;GET A LOW-CORE BLOCK FOR THE IOLIST
JRST THIS21 ;CANT GET ONE!
MOVE P1,T1 ;ADR IN P1
HRLI P1,-3 ;CAN SAVE 3 IOWD'S WITH NO HASSLE
MOVEM T1,-5(P) ;RETURN INITIAL IOWD LOC IN P2
>
PUSH P,U ;SAVE U
IFN FTKS10,<
MOVE P1,CHNIMR##(P3) ;GET ADDRESS OF INITIAL MAPPING REGISTER
MOVEI T4,UBAEXP ;GET INITIAL MAPPING REGISTER ADDRESS
SUBM P1,T4 ;DISPLACEMENT OF THIS DEVICES FIRST
IMULI T4,UBAMUL ;MAKE INTO AN ELEVEN STYLE ADDRESS
MOVEM T4,CHNIEA##(P3) ;AND SAVE AS INITIAL ELEVEN ADDRESS
HLL P1,CHNUBA##(P3) ;GET UBA NUMBER
PUSH P,CHNMRC##(P3) ;SAVE FOR LATER
>
MOVEI U,0 ;U=0 FOR 18-BIT CHAN
IFN FTKL10,<
SKIPGE T2,CHB22B##(P3)
MOVEI U,1 ;22-BIT CHAN
TLNE T2,CP.RH2##!CP.KLP## ;RH20 OR KLIPA?
MOVEI U,2 ;YES
>
TLNN P4,(SL.SIO) ;SWAPPING?
TLO U,1 ;NO, PAGING, REMEMBER THAT (SEC # FROM MEMTAB)
IFN FTIPCF,<
TLNN P4,(SL.IPC) ;IPCF?
>
CAILE J,JOBMAX## ;HIGH SEG?
TLOA U,400000 ;INDICATE BY U NEGATIVE
PUSHJ P,[EXCH P1,-10(P)
PUSHJ P,GETVPN
EXCH P1,-10(P)
POPJ P, ]
LDB P4,[POINT 13,P4,26] ;PHYSICAL PAGE TO START IO AT
JUMPL U,THIS3 ;PROCEED IF HIGH SEG, IPCF, OR PAGING QUEUE
HRRZ T2,JBTUPM##(J) ;SWAPPING THE UPMP?
CAIE T2,(P4)
JRST THIS4 ;NO
TLO U,500000 ;YES, NO NEXT PAGE+"THIS IS UPT" BIT
TLNN S,IO ;INPUT?
TLO U,200000 ;YES, FLAG INPUT OF UPT
SKIPGE U
THIS3: SETO P3, ;BE SURE NON-ZERO AT THIS15 IF WE WANT IT TO BE
;HERE WITH P4=PAGE NUMBER OF THE BEGINNING PAGE OF THE IO
;AND P3=POINTER TO VIRTUAL SLOT IF SWAPOUT
THIS4:
IFN FTKL10,<
MOVE T2,[400000+T1,,1] ;SET TO COUNT CONTIGUOUS PAGES (IOWD FOR KL)
>
IFN FTKS10,<
POP P,T2 ;RESTORE SAVED UMR COUNT
>
THIS5:
IFN FTXMON,<
XJRST [MCSEC1+.+1] ;ENTER SECTION 1 FOR PAGTAB/MEMTAB REFERENCES
>
MOVE T1,P4 ;STARTING PAGE
THIS6: SSX P4,MS.MEM ;SET SECTION INDEX FOR PAGTAB/MEMTAB
SKIPGE MEMTAB(P4) ;IS THIS LAST PAGE IN FRAGMENT?
SOJN P2,@[0,,THIS27] ;YES, SOMEONE IS CONFUSED IF NOT LAST PAGE
JUMPL U,THIS10 ;GO IF HI-SEG
LDB T4,[POINT MT.SAD,MEMTAB(P4),<^L<MT.DAD>+MT.SAD-1>] ;DSK ADR OF THIS PAGE
TLNN S,IO ;IF SWAPPING OUT,
JRST THIS7 ;NO, DON'T CHANGE PAGE MAP
MOVE T3,(P3) ;GET CURRENT MAP CONTENTS
AND T3,[PM.BTS-PM.COR] ;SAVE THE BITS
IOR T4,T3
MOVEM T4,(P3) ;SAVE ADDR IN UPMP
THIS7: JUMPE P2,THIS11 ;GO IF LAST PAGE
LDB T4,NVPNP4 ;GET NEXT VIRTUAL PAGE #
CAIN T4,.UPMVP/PAGSIZ## ;UPMP?
TLO U,500000 ;YES, DONT WIPE OUT SLOT IN MAP
THIS9: TLNN S,IO ;INPUT?
TLZ U,400000 ;YES, STOP ON COUNT EXHAUSTED
PUSHJ P,GMPTR ;GET POINTER
MOVE P4,(T4) ;GET POINTER
TLZ P4,(PM.NAD) ;CLEAR BITS
SKIPA P3,T4 ;POINTER FOR NEXT DEPOSIT
THIS10: HRRZ P4,PAGTAB(P4) ;HI-SEG GETS NEXT PAGE FROM PAGTAB
IFN FTKL10,<
HRRZ T4,U ;LEFT HALF = 0 FOR INDEXING
CAIN P4,@T2 ;PAGES CONTIGUOUS?
CAML T2,MAXCNT(T4) ;YES, BELOW MAX SIZE OF AN IOWD?
SOJA P2,THIS11 ;NO, MAKE THE IOWD
CAMN T2,[400000+T1,,27] ;DON'T BUILD AN IOWD
SOJA P2,THIS11 ; THAT LOOKS LIKE AN RH20 GOTO WORD
SOJLE P2,THIS11 ;MAKE THE IOWD IF DONE
AOJA T2,THIS6 ;PAGE IN IOWD - COUNT AND TRY NEXT PAGE
>
;HERE TO FINISH THE IOWD/MAPPING REGISTER
THIS11:
IFN FTXMON,<
JRST @[0,,.+1] ;RETURN TO SECTION 0
>
IFN FTKL10,<
IMULI T2,-1000 ;COMPUTE WORDCOUNT
LSH T1,P2WLSH## ;CONVERT BEGINNING PAGE NUMBER TO ADDRESS
TRNN U,2 ;IF NOT AN RH20,
SOJA T1,THIS12 ; ADDR-1
MOVNS T2 ;RH20 - ADDR RATHER THAN ADR-1
TRO T2,RH2TRX## ; +WDCNT, TRA BIT
THIS12: DPB T2,PNTCNT(U)
MOVEM T1,(P1) ;SAVE IOWD IN LOCORE BLOCK
ADDI T1,1 ;ADDRESS OF 1ST WORD TO TRANSFER
AND T1,MSK22B##(U) ;GET ADDRESS
JUMPLE P2,THIS13 ;DONE IF P2=0
AOBJN P1,THIS4 ;MORE TO DO, GET NEXT CHUNK
TRNE U,2 ;IF AN RH20
TRO U,4 ; TELL KLSER
PUSHJ P,GETMOR## ;NEED ANOTHER 4-WORD BLOCK
JRST THIS20 ;NONE AVAILABLE
TRZ U,4 ;CLEAR KLSER'S RH20-BIT
JRST THIS4 ;GOT IT, DO NEXT CHUNK
>; END FTKL10
IFN FTKS10,<
TRO T1,UNB36B!UNBVBT ;SET 36 BIT MODE AND VALID BIT
WRIO T1,(P1) ;LOAD THE MAPPING REGISTER
ADDI P1,1 ;POINT TO NEXT MAPPING REGISTER
SOJLE P2,THIS13 ;DONE IF P2=0
SOJG T2,THIS5 ;IF UMR AVAILABLE, CONTINUE
MOVE T2,-7(P) ;OOPS, RAN OUT OF MAPPING REGISTERS
ADDM P2,(T2) ;INCREASE # PAGES LEFT TO DO
LSH P2,2
ADDM P2,-1(P) ;UPDATE # BLOCKS LEFT AFTER THIS IO
MOVNS P2
ADDM P2,-2(P) ;UPDATE # BLOCKS DONE THIS OPERATION
SOJA P1,THIS13 ;FINISH UP, START THE IO
>; END FTKS10
;HERE WHEN ALL REQUIRED IOWDS HAVE BEEN BUILT
THIS13:
IFN FTKL10,<
SETZM 1(P1) ;TERMINATE THE LIST
AOS T3,P1 ;POINT AT TERMINATION WORD
TRNN U,2 ;RH20?
JRST THIS14 ;NO
MOVSI T1,RH2LST## ;YES, INDICATE LAST IOWD
IORB T1,-1(P1)
LDB T2,[POINT 11,T1,13] ;WORDCOUNT
TLZ T1,077760 ;CLEAR WDCNT FIELD
ADD T1,T2 ;ADDR + N
JRST THIS15 ;STORE IN CHNTCW AND CONTINUE
THIS14: HLRO T1,-1(P1) ;WORD COUNT OF LAST IOWD
LDB T2,ADRPT2##(U) ;WHERE DATA ASSOCIATED WITH LAST IOWD
ASH T1,@ASH22B##(U) ; WILL START
SUBM T2,T1 ;WHERE LAST DATA ITEM WILL GO
DPB P1,ADRPT4##(U) ;WHERE TERMINATION WORD WILL BE FETCHED FROM
THIS15: MOVE T2,-5(P) ;ADDRESS OF THE CHANNEL DATA BLOCK
MOVEM T1,CHNTCW##(T2) ;STORE WHAT CHANNEL TERMINATION WORD SHOULD LOOK LIKE
>
IFN FTKS10,<
MOVE T2,-5(P) ;ADDRESS OF THE CHANNEL DATA BLOCK
HLL P1,CHNIMR##(T2) ;RESTORE LEFT HALF
SUB P1,CHNIMR##(T2) ;GET NUMBER OF MAPPING REGISTERS USED
LSH P1,P2WLSH##+2 ;MAKE INTO WORDS, 11 STYLE
MOVEM P1,CHNTCW##(T2) ;STORE ADDRESS OF LAST WORD TO BE TRANSFERRED
SUB P1,CHNIEA##(T2) ;COMPUTE TOTAL NUMBER OF BYTES IN TRANSFER
MOVEM P1,CHNBTC##(T2) ; AND PUT IT HERE
>
SKIPN -1(P) ;WILL THIS BE THE LAST IO?
SETZB P3,P4 ;YES
TLNE U,200000 ;UPMP SWAP IN?
JRST THIS16 ;YES
MOVE P1,-7(P) ;ORIGINAL SWPLST ENTRY ADDRESS
MOVSI T1,(SL.IPC) ;PAGING QUEUE BIT
TLNE S,IO ;INPUT?
TDNE T1,(P1) ;NO, PAGING QUEUE
JRST THIS16 ;NO
CAIG J,JOBMAX## ;JOB?
PUSHJ P,SETVPN ;YES, SET VPN IN .USLPS OR TABLE
THIS16: JUMPE P3,THIS18 ;GO IF NO MORE TO DO
DPB P4,[POINT SL.SPN,(P1),<^L<SL.PPN>+SL.SPN-1>]
JUMPL J,THIS17 ;IF SWAPPING "IP" QUEUE
TLNN U,200000 ;OR THIS IS UPMP SWAP IN
CAILE J,JOBMAX## ; OR A HIGH SEGMENT,
JRST THIS17 ;DON'T STORE SINCE A RANDOM JOB IS ADDRESSABLE
THIS17: HLRZS P1 ;SWPLST ENTRY FOR MAIN WORD
JUMPE P1,THIS18 ;GO IF NOT IN A FRAGMENT
MOVSI T1,(SL.IOP)
IORM T1,(P1) ;INDICATE IN A FRAGMENT FOR NEXT
; (SO WILL ONLY PICK THIS PIECE)
THIS18: TLNE S,IO ;IN OR OUT?
TLZN U,100000 ;;OUT, JUST SWAP THE UPT?
JRST THIS19 ;NO
SKIPE .USLPS ;DID WE STOP JUST BEFORE THE UPT?
JRST THIS19 ;YES, WE'LL GET IT NEXT TIME THEN
MOVE T1,NLUPMP##+.UMUPT ;YES,GET POINTER TO NULL UPMP
MOVEM T1,.UPMP+.UMUPT
THIS19: POP P,U ;RESTORE U
POP P,(P) ;FIX STACK
POP P,T1 ;NO OF BLOCKS TO TRANSFER
SKIPE DINITF##
POPJ P,
TLNN S,IO
ADDM T1,.CPSBI## ;COUNT TOTAL SWAPPING BLOCKS
TLNE S,IO
ADDM T1,.CPSBO##
POPJ P, ;AND RETURN
;HERE IF WE RAN OUT OF LOWER CORE BLOCKS
THIS20: HRRZ T1,-7(P)
ADDM P2,(T1) ;INCREASE # PAGES LEFT TO DO
LSH P2,2
ADDM P2,-1(P) ;UPDATE # BLOCKS LEFT AFTER THIS IO
MOVNS P2
ADDM P2,-2(P) ;UPDATE # BLOCKS DONE THIS OPERATION
SOJA P1,THIS13 ;FINISH UP, START THE IO
;HERE IF THERE WASNT A LOWER-CORE BLOCK TO START AT
THIS21: ADD P4,P2 ;MAKE P4 THE SWPLST ENTRY AGAIN
TLZ P4,(SL.IOP)
HRRZ P1,-6(P) ;RESET P1
MOVEM P4,(P1) ;SAVE BACK IN SWPLST
POP P,(P) ;CLEAR GARBAGE OFF LIST
SETZB T1,-4(P) ;INDICATE 0 BLOCKS TRANSFERRED
PJRST T2POPJ## ;RETURN TO FILIO
;HERE ON VARIOUS ERRORS
THIS27: STOPCD THIS13,DEBUG,IPM, ;++ILLEGAL POINTER IN MEMTAB
;SUBROUTINES TO MANIPULATE VIRTUAL PAGE NUMBERS FOR SWAPOUT
;GET/SETVPN:
; MOVE P1,SWPLST-POINTER ;SWPLST,,FRAG OR 0,,SWPLST
; PUSHJ P,{GET|SET}VPN ;CALL ROUTINE
; <ONLY RETURN, FOR GETVPN - P3 CONTAINS VIRTUAL POINTER>
GETVPN: MOVE P3,.USLPS ;NO, GET POINTER FROM CURRENT UPT
TLNN P1,-1 ;FRAGMENTED SWPLST ENTRY?
POPJ P, ;NO, ALL IS WELL
PUSHJ P,FRGIDX ;GET FRAGMENT INDEX
ADDI P3,(T1) ;POINTER INTO TABLE
MOVE P3,(P3) ;AND ENTRY
POPJ P,
SETVPN: MOVEI T2,.USLPS ;NO, STORE FOR CURRENT JOB
TLNN P1,-1 ;FRAGMENTED?
JRST SETVP5 ;NO
PUSHJ P,FRGIDX ;COMPUTE A FRAGMENT INDEX
MOVE T2,(T2) ;RELOCATE
ADD T2,T1 ;PLACE TO STORE
SETVP5: MOVEM P3,(T2) ;STORE
POPJ P,
;ROUTINE TO COMPUTE FRAGMENT TABLE OFFSET
;CALL WITH P1=SWPLST POINTER (SW2LC FORMAT)
;EXIT WITH T1=OFFSET INTO FRAGMENT VIRTUAL TABLE
FRGIDX: PUSH P,T2 ;GET AN AC
SETZ T1, ;COUNTER
HLRZ T2,P1 ;GET START OF CHAIN
HRRZ T2,(T2) ;FIRST FRAGMENT
FRGID2: CAIN T2,(P1) ;IS THIS THE RIGHT ENTRY?
JRST T2POPJ## ;YES, RETURN
AOS T1 ;NO, SET FOR NEXT
SKIPL 1(T2) ;POINTER TO NEXT
AOJA T2,FRGID2 ;NO
HRRZ T2,1(T2) ;GET NEXT BLOCK
JRST FRGID2 ;START LOOKING THERE
;SUBROUTINE TO GET SUFFICIENT FREE CORE TO BUILD THE VPN TABLE
;CALL:
; MOVE T1,FRAGMENT TABLE
; PUSHJ P,BLDVPN
; <NOT ENOUGH FREE CORE>
; <NORMAL RETURN, POINTER TO TABLE IN T2>
BLDVPN::
SETZ T2, ;T2 COUNTS WORDS
JUMPGE T1,CPOPJ1## ;NOT REALLY FRAG'D?
HRRZS T1
BLDVP1: SKIPN T3,(T1) ;DONE?
JRST BLDVP4 ;YES
JUMPL T3,[HRRZ T1,T3 ;POINTER TO ANOTHER ENTRY
JRST BLDVP1] ;LOOP BACK
AOS T2 ;ONE MORE WORD WE NEED
AOJA T1,BLDVP1 ;LOOP
BLDVP4: AOS T2 ;ONE MORE WORD FOR COUNT
PUSH P,T2 ;SAVE # OF WORDS
PUSHJ P,GETWDS## ;GET THE CORE
JRST T2POPJ## ;NOT THERE
POP P,(T1) ;REMEMBER THE COUNT
AOS T2,T1 ;AND RETURN +1 AS THE ADDRESS
MOVE T1,-1(T2) ;GET COUNT AGAIN
TRZE T1,3 ;ROUND TO NEAREST MULTIPLE OF 4
ADDI T1,4 ;TO ENSURE LINK WORD IS ZERO IN CASE
ADDI T1,-1(T2) ;THIS EVER GETS USED FOR SWPLST ENTRY
SETZM -1(T1) ;ZAP IT
JRST CPOPJ1## ;GOOD RETURN
;SUBROUTINE TO RETURN THE VPN TABLE POINTED TO BY C(T1)
RTNVPN::
MOVE T1,-1(T2) ;GET COUNT
SOS T2 ;ADDRESS
PJRST GIVWDS##
;SUBROUTINE TO SET UP J FROM SWPLST ENTRY
;ENTER P1 POINTING TO SWPLST
;EXIT CPOPJ1 IF A HIGH SEG, CPOPJ IF LOW
GETSWJ: PUSHJ P,SW2LC ;GET INDEX OF SWPLST ENTRY
HRRZ J,SW3LST##(T1) ;GET JOB NUMBER
MOVE T1,SWPLST##(T1) ;GET MAIN SWPLST ENTRY
TLC T1,(SL.SIO+SL.IPC) ;SWAPPING OUT THE REPLACABLE QUEUE?
TLNN T1,(SL.SIO+SL.IPC)
TLOA J,-1 ;YES, INDICATE THAT BY SETTING J NEGATIVE
CAILE J,JOBMAX## ;HIGH SEG?
AOS (P) ;HIGH SEG OR PAGING QUEUE RETURN
POPJ P, ;BACK
;SUBROUTINE TO COMPUTE INDEX INTO SW2LST TABLE
;ENTER P1=ADDRESS IN SWPLST (OR FRAGMENT, ADR IN LH)
;EXIT T1=INDEX
;PRESERVES T2-T4
SW2LC:: TLNN P1,-1 ;POINTER TO A FRAGMENT?
SKIPA T1,P1 ;NO, USE MAIN ADDRESS
HLRZ T1,P1 ;YES, GET SWPLST LOCATION
TRZ T1,400000 ;SIGN BIT OF P1 MIGHT BE ON
SUBI T1,SWPLST## ;MAKE INTO AN INDEX
POPJ P, ;AND RETURN
SUBTTL SWPSER INTERFACE WITH THE SWAPPER
;SUBROUTINE TO SETUP SWPLST FOR SWAP OUT
BOSLST::PUSHJ P,SAVE4## ;SAVE ACS
CAILE J,JOBMAX## ;HI SEG?
JRST BOSLS5 ;YES, DO IT DIFFERENTLY
PUSHJ P,SVEUB## ;LOW SEG, MAKE JOB ADDRESSABLE
MOVEM T2,.USLPS ;VPN POINTER
SKIPL .USBTS ;GET BITS
TDZA T2,T2 ;NOT EXTENDED
MOVEI T2,MXSECN ;MAX SECTION TO TRY
MOVEM T2,.USSPT ;SECTION TO DO
MOVE T1,JBTADR##(J) ;SAVE JBTADR
HLLM T1,.USREL ; FOR SWAP-IN
MOVE T2,JBTSTS##(J)
TLNE T2,JXPN
MOVEM T1,.JDAT+JOBDPG##
MOVE T1,.JDAT+.JBPFH## ;GET JOBPFH
MOVEM T1,.USPFH ;AND SAVE IN UPMP FOR BISLST (MIGRATING JOB)
SKIPGE U,JBTSWP##(J) ;FRAGMENTED?
JRST BOSLS1 ;YES
LDB T1,IMGOUT## ;NO, GET SIZE TO SWAP OUT
LDB T2,NFYPGS## ;ADD 1 PAGE FOR UPMP
ADD T1,T2
LDB J,NZSSCN## ;GET NUMBER OF NZS MAPS
ADDI J,(T1)
PUSHJ P,SETOMT ;SETOMT WILL SET UP MEMTAB
MOVE J,.USJOB ;RESTORE JOB #
MOVEI T1,(P3) ;FIRST PHYSICAL PAGE
LSH T1,SL.SCT ;POSITION IT
LDB T2,IMGOUT## ;NUMBER OF PAGES
LDB T3,NFYPGS## ;PLUS 1 FOR UPMP
ADD T2,T3
LDB T3,NZSSCN## ;# OF MAPS AGAIN
ADDI T2,(T3) ;ADD IN
DPB T2,[POINT SL.SCT,T1,<^L<SL.CNT>+SL.SCT-1>] ;IN T1
HLRZ T4,P3 ;VIRTUAL PAGE #
PUSHJ P,GMPTR ;GET POINTER
MOVEM T4,.USLPS ;NOT FRAGMENTED
JRST BOSLS4 ;SET LH BITS AND STORE T1 IN SWPLST
;HERE IF LOW SEG SWAP OUT AND DISK SPACE IS FRAGMENTED
BOSLS1: MOVE P1,JBTSWP##(J)
; TLZ P1,FRGSEG
PUSH P,.USLPS ;INITIALIZE POINTER TO VPN TABLE
MOVSI P2,(SL.DIO+SL.SIO) ;SWPLST DESCRIPTORS
PUSHJ P,NXTFRG ;SET UP U FOR THIS FRAGMENT
STOPCD .+1,DEBUG,O1F, ;++ONLY 1 FRAGMENT
PUSHJ P,SETOMT ;SET UP MEMTAB
BOSLS2: DPB P3,[POINT SL.SPN,P2,<^L<SL.PPN>+SL.SPN-1>] ;STORE 1ST PAGE NUMBER OF FRAG
HLRZ T4,P3 ;VPN OF FIRST VIRTUAL PAGE
PUSHJ P,GMPTR ;GENERATE A POINTER
MOVEM T4,@(P) ;STORE
AOS (P) ;INCREMENT
MOVEM P2,-1(P1) ;STORE THE SWPLST FRAGMENT IN TABLE
PUSHJ P,NXTFRG ;GET U FOR NEXT FRAG
JRST BOSLS3 ;LAST FRAGMENT
MOVEI P3,0 ;P3=0 0N CALL TO SETOMT
PUSHJ P,[SE1ENT ;DO THIS IN SECTION 1
JRST SETOM8] ;SET UP MEMTAB FOR THIS FRAG
JRST BOSLS2 ;AND TRY NEXT
BOSLS3: POP P,(P) ;FIX STACK
PUSHJ P,[SE1ENT ;DO THIS IN SECTION 1
SSX F,MS.MEM ;MAKE A REAL POINTER TO MEMTAB
LDB U,[POINT MT.SAD,MEMTAB(F),<^L<MT.DAD>+MT.SAD-1>]
POPJ P,]
MOVE J,.USJOB ;RESTORE J
MOVE T1,JBTSWP##(J) ;ADDRESS OF FRAGMENT/SWPLST TABLE
;HERE WHEN DONE, T1=SWPLST ENTRY, U=DSK ADR OF UPMP
BOSLS4: HRRZS M ;IS THE UPMP THE LAST PAGE?
CAIE M,.UPMVP/PAGSIZ##
STOPCD .,STOP,UNL ;++UPMP NOT LAST
MOVEM U,JBTSWP##(J) ;SAVE UPMP ADDR IN JBTSWP
TLO T1,(SL.DIO+SL.SIO) ;INDICATE SWAP OUT
MOVSI T2,(UP.PGB) ;INDICATE PAGES WILL BE GIVEN BACK
ANDCAM T2,.USBTS
PJRST MAKSLE ;STORE IN SWPLST AND RETURN
;HERE IF HIGH SEG SWAP OUT
BOSLS5: LDB P1,IMGOUT## ;SIZE OF OUTPUT IMAGE (NO PAGES TO SWAP)
HRLI P1,(SL.SIO+SL.DIO) ;SWPLST DESCRIPTORS
PJRST BHSLST ;GO DO IT
;SUBROUTINE TO SETUP SWPLST FOR SWAP IN OF UPMP
BUSLST::SE1ENT ;ENTER SECTION 1
CAILE J,JOBMAX## ;HI SEG?
JRST BISL11 ;YES, DO DIFFERENTLY
PUSHJ P,SVEUB## ;MAKE THE JOB ADDRESSABLE
MOVE U,JBTSWP##(J) ;NO, GET DSK ADDR OF UPMP
HRRZ T1,JBTUPM##(J) ;PAGE NUMBER OF UPMP
TLO U,(MT.LEF) ;INDICATE ONLY 1 FRAGMENT
SSX T1,MS.MEM ;MAKE MEMTAB ADDRESSABLE
MOVEM U,MEMTAB(T1) ;MEMTAB FOR UPMP
LDB T2,JBYMAP## ;ADDRESS OF THE MAP
EXCH U,T2 ;PUT IN U
TLZ T2,(PM.NAD) ;CLEAR BITS
SOS T2
CAME U,T2 ;CONTIGUOUS?
JRST BUSLS2 ;NO, ALAS
HRR T1,PAGTAB(T1)
MOVEI T2,.UPMVP/PAGSIZ##
DPB T2,NVPNT1 ;STORE POINTER TO NEXT WHICH IS UPT
MOVEM U,MEMTAB(T1)
HRRZS T1 ;CLEAR SECTION NUMBER FROM LEFT HALF
LSH T1,11
ADDI T1,2 ;NUMBER OF PAGES
TLO T1,(SL.SIO) ;SWAPPING UPMP IO (PREVENT FNDSLE FROM FINDING IT)
BUSLS1: LDB T2,JBYLSA## ;NUMBER OF 1ST PAGE FOR JOB
MOVEM T2,JBTSWP##(J) ;SAVE IN JBTSWP
AOS (P) ;GOOD RETURN
JRST MAKSLE ;SET UP SWPLST AND RETURN
BUSLS2: PUSH P,T1 ;SAVE PAGTAB/MEMTAB POINTER
HRLI T1,(<SL.SIO_-SL.SCT>) ;CLEAR SECTION #, SET BIT
LSH T1,SL.SCT ;POSITION
AOS T1 ;ONE PAGE
PUSH P,T1 ;SAVE IT
MOVEI T2,1 ;GET A CORE BLOCK
PUSHJ P,GET4WD## ;FOR THE SWPLST ENTRY
JRST TPOPJ## ;OOPS
POP P,1(T1) ;STORE THE ENTRY
TLO U,(MT.LEF) ;TURN ON
POP P,T2 ;PAGTAB POINTER
HRR T2,PAGTAB(T2) ;NEXT PAGE IN CHAIN
MOVEM U,MEMTAB(T2) ;STORE DISK ADDR IN MEMTAB
HRLI T2,(<SL.SIO_-SL.SCT>) ;CLEAR SECTION #, SET BIT
LSH T2,SL.SCT ;AND MAKE THE FRAGMENT ENTRY
AOS T2
MOVEM T2,(T1) ;MAP ENTRY
SETZM 2(T1) ;NO MORE
SETZM 3(T1)
HRLI T1,(SL.SIO!SL.FRG) ;SET FRAGMENTED ENTRY
JRST BUSLS1
;SUBROUTINE TO SET UP SWPLST FOR SWAP IN OF JOB
BISLST::PUSHJ P,SAVE4## ;SAVE SOME ACS
SETZB P3,.USLPS ;CLEAR SLOT IF LEFT FROM FRAGMENTED SWAPOUT
SKIPL JBTSWP##(J) ;IF NOT FRAGMENTED,
JRST BISLS1 ;GO DIRECTLY TO SETIMT
MOVSI T1,FRGSEG ;FRAG'D
ANDCAM T1,JBTSWP##(J) ;CLEAR BIT IN JBTSWP
DMOVE T1,.USHSE
LSH T1,W2PLSH##
LSH T2,W2PLSH##
EXCH T1,.USTMP
EXCH T2,.USTMP+1
DMOVE T3,.USTMP+2 ; TO SETIMT
MOVE M,.USTMP+4
MOVE F,.USTMP+5
MOVEI U,SETIMX ;WE'LL CALL SETIMX THIS TIME
JRST BISLS2
BISLS1: SKIPGE P1,.USBTS ;EXTENDED USER (UP.BIG=1B0)
TLNN P1,(UP.NZS) ;BIG USER, TIME TO DO NON-ZERO SECTIONS?
TDZA P1,P1 ;SECTION 0, DO IT
MOVEI P1,MXSECN ;START WITH SECTION 37 OTHERWISE
MOVEM P1,.USSPT ;SAVE AS SECTION TO START I/O AT
MOVEI U,SETIMT ;WHERE TO GO
BISLS2: SETZ P1, ;FIRST CALL
PUSHJ P,(U) ;SET UP UPMP FOR THIS FRAG, OR WHOLE JOB
BISLS3: SKIPA T1,P1 ;DONE - GET 1ST VIRT,,1ST PHYS
JRST BISLS4 ;ANOTHER FRAG TO DO
TLZ T1,-1 ;1ST PHYSICAL PAGE
LSH T1,SL.SCT ;POSITION IT
TLO T1,(SL.SIO) ;SWAPPING IO
DPB P3,[POINT SL.SCT,T1,<^L<SL.CNT>+SL.SCT-1>] ;NUMBER OF PAGES TO DO
JRST BISLS7 ;SET UP JBTADR AND CALL MAKSLE
;HERE WHEN FRAGMENTED
BISLS4: MOVEI P4,0 ;INDICATE 1ST CALL
PUSHJ P,GT4MR ;GET A 4-WORD BLOCK
JRST BISL12 ;CANT GET ONE
HRRZ P2,P4 ;SAVE 1ST ADR OF 4-WD BLOCKS
BISLS5: HRLI P3,(SL.SIO) ;SWAPPING IO
DPB P1,[POINT SL.SPN,P3,<^L<SL.PPN>+SL.SPN-1>] ;1ST PHY PAGE
MOVEM P3,(P4) ;SAVE SWPLST ENTRY IN 4-WD BLOCK
JUMPL P2,BISLS6 ;GO IF LAST FRAG
SETZB P1,P3 ;NOT LAST, SETIMX WANTS P1,P3=0
PUSHJ P,SETIMX ;SET UP UPMP FOR THIS FRAG
TLO P2,400000 ;LAST FRAGMENT - P2 NEGATIVE
AOBJN P4,BISLS5 ;GO DO NEXT IF 4-WD BLOCK NOT EXHAUSTED
PUSHJ P,GT4MR ;GET ANOTHER BLOCK
JRST BISL12 ;NONE AVAILABLE
JRST BISLS5 ;GET ONE - CONTINUE
;HERE WHEN LAST FRAGMENT DONE
BISLS6: SETZM 1(P4) ;TERMINATE LIST
HRRZ T1,P2 ;ADR OF START OF 4-WD BLOCKS
TLO T1,FRGSEG(SL.SIO) ;FRAGMENTED SWAP
;HERE AT END OF FRAG (OR WHOLE JOB)
BISLS7: HLRZ M,.USREL ;LH (JBTADR) ON SWAP-OUT
JUMPE M,BISLS8 ;ALREADY STORED
HRRZS .USREL ;CLEAR LH (.UPREL)
HRLM M,JBTADR##(J) ;RESTORE (NON-SHARABLE HS CASE)
BISLS8: MOVE R,JBTADR##(J) ;MAKE SURE R IS RIGHT
SKIPGE JBTSWP##(J) ;FRAGMENT END?
JRST BISLS9 ;YES, RAN OUT OF STUFF ON FRAGMENTED SWAP
MOVSI T2,(UP.NZS) ;BIT TO CHECK
XORB T2,.USBTS ;CHANGE STATE
JUMPGE T2,BISLS9 ;NORMAL USER
TLNE T2,(UP.NZS) ;BIT JUST GO ON?
HRRZM F,.USTMP+5 ;SAVE POINTER TO NEXT
MOVEM T2,.USBTS ;SAVE STATE OF BIT
BISLS9: SKIPLE T2,JBTSGN##(J) ;IS THERE A NON-SHARABLE HI-SEG?
TLNE T2,SHRSEG
JRST BISL10 ;NO, GO MAKE THE SWPLST ENTRY
IFN FTXMON,<
HRRZS T2 ;CLEAR JUNK
>
LDB T3,[POINT 9,JBTADR##(T2),8] ;YES
SKIPE JBTADR##(T2) ;HIGHEST ADR IN HIGH SEG
ADDI T3,1
DPB T3,JBYHSS## ;SAVE AS HI SEG SIZE
LDB T4,[POINT 9,JBTUPM##(T2),8] ;HI-SEG OFFSET
PUSHJ P,MAPHI
BISL10: JUMPG P3,MAKSLE ;MAKE SWPLST ENTRY (NORMAL)
;HERE IF REALLY DON'T NEED TO SWAP ANYTHING. NOTE THAT THIS CAN ONLY
;HAPPEN ON THE THIRD SWAP OPERATION OF AN NZS PROGRAM AS SECTION 0 ALWAYS
;HAS PAGE 0 TO SWAP IN.
MOVSI P2,(SL.IOD)
IORB P2,T1 ;MARK AS DONE
PUSHJ P,MAKSLE ;MAKE NEW SWPLST ENTRY
MOVEI P1,(T2) ;INDEX TO SWXLST
AOS (P) ;SKIP AOS OF SWAPPER COUNT
SOS SPRCNT## ;FIX COUNTS UP
SOS SINCNT##
MOVEI F,SWPDDB## ;RESTORE F
PJRST SWPINA## ;AND CONTINUE
;HERE FOR HI SEG
BISL11: PUSHJ P,SAVE2## ;SAVE ACS
LDB P1,IMGOUT## ;NO OF PAGES TO SWAP IN
HRLI P1,(SL.SIO) ;SWAPPING IO
MOVE T1,JBTSWP##(J) ;GET DISK ADDR
PUSHJ P,BLDVPN ;GET CORE FOR TABLE, IF NECESSARY
POPJ P, ;OOPS
AOS (P) ;GOOD RETURN
PJRST BHSLST ;SET UP SWPLST FOR HI SEG
;HERE WHEN NOT ENOUGH 4-WD BLOCKS ARE AVAILABLE
BISL12: DMOVEM T1,.USTMP ;SAVE WORKING ACS IN UPMP
DMOVEM T3,.USTMP+2
MOVEM M,.USTMP+4
HRRZM F,.USTMP+5
MOVSI T1,FRGSEG ;INDICATE HAVE DONE A PART OF WHAT WE NEED
IORM T1,JBTSWP##(J)
JUMPE P4,BISLS3 ;FINISH UP THIS PART AND CALL MAKSLE
SOJA P4,BISLS6 ;FINISH UP
;SUBROUTINE TO SETUP SWPLST FOR HIGH SEGMENT SWAP IN OR OUT
;CALLING SEQUENCE:
;
; MOVE P1,HIGH SEGMENT SIZE
; HRLI P1,SWPLST ATTRIBUTES (I.E. DIRECTION OF I/O)
; MOVEI T2,ADDR+1 OF CORE BLOCK FOR FRAGMENT TABLE COPY (IF FRAG'D)
; PUSHJ P,BHSLST
;ALWAYS RETURNS CPOPJ
BHSLST: MOVE T3,T2 ;SAVE CORE FOR FRAG COPY (IF ANY)
LDB T2,JBYHSA## ;1ST PAGE
SKIPGE T1,JBTSWP##(J) ;DSK ADR OF 1ST PAGE
JRST BHSLS1 ;FRAGMENTED
HRRZ T3,P1 ;SIZE
MOVEI T4,STOHDA ;ROUTINE TO STORE DISK ADDRESS IN MEMTAB
PUSHJ P,SETXMT ;SET UP FOR SWAP
LDB T1,JBYHSA## ;1ST PAGE
LSH T1,SL.SCT ;POSITION IT FOR SWPLST
IOR T1,P1 ;ADD ATTRIBUTES, SIZE
JRST MAKSLE ;SET UP SWPLST AND RETURN
BHSLS1: PUSHJ P,SAVE4## ;SAVE ACS
SOS P4,T3 ;GET CORE ADDRESS (WE DON'T NEED COUNT,
;BUT DO NEED EXTRA WORD FOR TERMINATING ZERO)
MOVE P2,T1 ;ADDRESS OF DISK ADDRESS FRAGMENT TABLE
MOVEI P3,STOHDA ;ROUTINE TO STORE DISK ADDRESS IN MEMTAB
PUSHJ P,BFSLST ;SETUP SWPLST FRAGMENT TABLE, MAKE SWPLST ENTRY, AND RETURN
HRRM P4,JBTSWP##(J) ;STORE NEW SWPLST TABLE
POPJ P,
;SUBROUTINE TO STORE DISK ADDRESS IN MEMTAB, CALL WITH T1=DISK ADDRESS,
; T2=MEMTAB INDEX, ALWAYS RETURNS CPOPJ
STOHDA: MOVEM T1,MEMTAB(T2) ;STORE DISK ADDRESS
POPJ P, ;AND RETURN
;SUBROUTINE TO SETUP SWPLST TO SWAP OUT PAGES ON "IN" QUEUE
;CALLING SEQUENCE:
; PUSHJ P,BPSLST
;ALWAYS RETURNS CPOPJ, I/O STARTED IF POSSIBLE
BMSLST::SKIPA T4,[STODAU] ;SPECIAL ENTRY FOR UUO LEVEL CALLS
BPSLST::MOVEI T4,STODA ;NORMAL ROUTINE TO CHANGE DSK ADDRS
SKIPE PAGIPQ## ;CAN'T DO ANYTHING IF I/O IS IN PROGRESS
POPJ P, ;RETURN DOING NOTHING IF I/O IS IN PROGRESS
PUSHJ P,SAVE1## ;SAVE AN AC
SKIPN U,PAGSNC## ;ANYTHING ON THE SLOW SWAPPING SPACE "IN" QUEUE?
JRST BPSLS1 ;NO, TRY "IN" QUEUE
MOVEI P1,PAGSNQ## ;YES, OUTPUT IT FIRST
TLO U,(PG.SLO) ;ALLOCATE FROM SLOW SWAPPING SPACE
JRST BPSLS2 ;GO START THE I/O
BPSLS1: SKIPN U,PAGINC## ;ANYTHING ON THE "IN" QUEUE?
POPJ P, ;NOTHING TO DO
MOVEI P1,PAGINQ## ;OUTPUT "IN" QUEUE
BPSLS2: PUSHJ P,SAVJW## ;SAVE J,W
MOVE W,T4 ;SAVE T4 (DON'T NEED W ANYWAY)
SETZ J, ;USE JOB 0
PUSHJ P,SWPSPC## ;GET SWAPPING SPACE
POPJ P, ;NONE AVAILABLE, TRY AGAIN LATER
MOVE J,-2(P) ;RESTORE J
DMOVE T2,(P1) ;"IN" QUEUE HEADER
DMOVEM T2,PAGIPQ## ;BECOMES "IP" QUEUE HEADER
CAIE P1,PAGIPQ## ;ARE WE RE-DOING THE IP QUEUE?
SETZB T3,(P1) ;"IN" QUEUE IS EMPTY
EXCH T3,1(P1) ;GET NUMBER OF PAGES ON "IP" QUEUE
MOVE T4,W ;RESTORE T4
JUMPL T1,BPSLS3 ;JUMP IF SWAPPING SPACE IS FRAGMENTED
.CREF FRGSEG
PUSHJ P,SETXMT ;SETUP MEMTAB AND COPY DISK ADDRESSES TO MAPS
MOVE T1,PAGIPQ## ;FIRST PAGE
LSH T1,SL.SCT ;POSITION FOR SWPLST ENTRY
IOR T1,PAGIPC## ;COUNT
TLO T1,(SL.SIO+SL.DIO+SL.IPC)
PUSHJ P,MAKSLE ;MAKE A SWPLST ENTRY
JRST BPSLS4 ;START I/O AND RETURN
;HERE WHEN SWAPPING SPACE IS FRAGMENTED
BPSLS3: PUSHJ P,SAVE4## ;SAVE ACS
MOVE P1,T3 ;COUNT TO P1
HRLI P1,(SL.SIO+SL.DIO+SL.IPC)
MOVE P2,T1 ;ADDRESS OF FRAGMENT TABLE
MOVEI P3,(T4) ;ADDRESS OF ROUTINE TO STORE IN MEMTAB
SETZ P4, ;NO FRAG TABLE COPY
PUSHJ P,BFSLST ;SETUP SWPLST
BPSLS4: PUSHJ P,INTLVL## ;AT INTERRUPT LEVEL?
HRRM T2,.USSLX ;NO, BE SURE WE FIND THIS SWPLST ENTRY
AOS SPRCNT## ;ONE MORE SWAP IN PROGRESS
PJRST SQOUT## ;START THE OUTPUT
;SUBROUTINE TO STORE DISK ADDRESS IN MEMTAB AND IN MAP THAT THE PAGE BELONGS TO
; CALL WITH T1=DISK ADDRESS, T2=MEMTAB INDEX, RETURNS CPOPJ, T1 AND T2 INTACT
STODA: PUSHJ P,SAVE4## ;SAVE ACS
MOVE P1,J ;SAVE J
DMOVE P2,T1 ;SAVE DISK ADDRESS AND MEMTAB INDEX
EXCH T1,MEMTAB(T2) ;STORE DISK ADDRESS, GET JOB NUMBER+VIRTUAL PAGE NUMBER
TLZE T1,(MT.IPC) ;AN IPCF PAGE?
JRST STODIP ;YES, HANDLE IT
MOVE P4,T1 ;SAVE THAT
LDB J,[POINT MT.SJB,P4,<^L<MT.JOB>+MT.SJB-1>] ;GET JOB NUMBER OF JOB PAGE BELONGS TO
PUSHJ P,SVEUB## ;MAKE MAPS ADDRESSABLE
LDB T1,[POINT <MT.SPN+MT.SSN>,P4,<^L<MT.VSN>+MT.SPN+MT.SSN-1>] ;GET PAGE NUMBER
PUSHJ P,GTPME ;GET MAP CONTENTS
AND T2,[PM.BTS] ;EXTRACT ACCESS BITS
IOR T2,MEMTAB(P3) ;ADD IN DISK ADDRESS
MOVEM T2,(T4) ;STORE IT IN THE MAP
DPB P4,[POINT P2.SPN,PT2TAB(P3),<^L<P2.VPN>+P2.SPN-1>] ;REMEMBER
;WHERE IT CAME FROM
DPB J,[POINT MT.SJB,MEMTAB(P3),<^L<MT.JOB>+MT.SJB-1>] ;AND SET JOB #
STODA1: MOVE J,P1 ;RESTORE J
STODA2: DMOVE T1,P2 ;AND T1, T2
POPJ P, ;AND RETURN
;HERE FOR IPCF PAGE
STODIP: DPB T1,[POINT P2.SPN,PT2TAB(T2),<^L<P2.VPN>+P2.SPN-1>] ;SET LOW
;ORDER BITS
ROT T1,-P2.SPN ;DEPOSIT
DPB T1,[POINT <^D18-P2.SPN>,MEMTAB(T2),<^L<MT.JOB>+MT.SJB-1>]
;HIGH ORDER BITS
ROT T1,P2.SPN ;PUT BACK
MOVSI P4,(MT.IPC) ;LEAVE MT.IPC ON TOO
IORM P4,MEMTAB(T2)
MOVSI T2,<1000_<^D36-^D18-IP.PLN##-1>> ;THIS IS A PAGE
IOR T2,P2 ;YES, GET DISK ADDRESS BACK
TLO T2,IP.DSK##_-^D18 ;MARK IT AS A DISK ADDRESS FOR IPCSER
MOVEM T2,(T1) ;STORE IT IN THE PACKET
.CREF MT.IPA ;IPCF PACKET ADDRESS
JRST STODA1 ;AND EXIT
;SUBROUTINE TO DO THE SAME THING AS STODA, BUT CAN BE CALLED AT
;UUO LEVEL. IS SLOWER, BUT DOESN'T CALL SVEUB. CANNOT BE CALLED
;AT NON-UUO LEVEL
STODAU::PUSHJ P,SAVE4## ;SAVE WORLD
DMOVE P2,T1 ;MOVE TO A BETTER PLACE
EXCH T1,MEMTAB(T2) ;SAVE DISK ADDR, GET WHERE TO PUT IT
TLZE T1,(MT.IPC) ;IPCF PAGE?
JRST STODIP ;YES, DO THAT
MOVE P4,T1 ;LOCATION WORD
LDB T1,[POINT MT.SJB,P4,<^L<MT.JOB>+MT.SJB-1>] ;JOB IT GOES IN
DPB T1,[POINT MT.SJB,MEMTAB(P3),<^L<MT.JOB>+MT.SJB-1>] ;PRESERVE
HRRZ T2,JBTUPM##(T1) ;UPMP FOR THAT JOB
HRLI T2,(<PM.DCD>B2+PM.WRT+PM.PUB) ;DON'T BOTHER CACHING IT
MOVEM T2,.UPMP+.UMTMP
PUSHJ P,CLPTZO ;SET UP THE MAPPING
EXP .TEMP
LDB T1,[POINT MT.SSN,P4,<^L<MT.VSN>+MT.SSN-1>] ;SECTION # PAGE IS IN
HRR T2,.TEMP+SECTAB(T1) ;SECTION MAP POINTER FOR THAT SECTION
TLZ T2,(PM.CSH) ;BE SURE IT'S OFF
MOVEM T2,.UPMP+.UMTMP ;MAP THAT
PUSHJ P,CLPTZO
EXP .TEMP ;CLEAR PAGING
LDB T1,[POINT MT.SPN,P4,<^L<MT.VPN>+MT.SPN-1>] ;PAGE TO CHANGE
MOVSI T2,(PM.BTS) ;GET BITS
ANDM T2,.TEMP(T1) ;SAVE ONLY THEM
MOVE T2,MEMTAB(P3) ;GET DISK ADDRESS
TLZ T2,(-1^!MT.DAD) ;KEEP ONLY ADDRESS
IORM T2,.TEMP(T1) ;AND PUT IT IN
DPB P4,[POINT P2.SPN,PT2TAB(P3),<^L<P2.VPN>+P2.SPN-1>]
DMOVE T1,P2
POPJ P,
;SUBROUTINE TO BUILD A FRAGMENTED SWPLST ENTRY
; CALL WITH P1=ATTRIBUTES,,SIZE, P2=ADDRESS OF DISK ADDRESS FRAGMENT TABLE,
; P3=ROUTINE TO CALL TO SETUP MEMTAB FOR A FRAGMENT, ALWAYS RETURNS CPOPJ
; P4=ADDRESS TO COPY ORIGINAL FRAGMENT TABLE TO (CONTIGUOUS BLOCK)
; OR ZERO IF NONE (COPY IS USED FOR HIGH SEG)
BFSLST: PUSHJ P,SAVE4## ;SAVE ACS
PUSH P,J ;NXTFRG CLOBBERS J
EXCH P2,P1 ;ATTRIBUTES,,SIZE
PUSH P,P1 ;SAVE LOC OF BLOCK
HLLM P2,(P) ;AND BITS
BFSLS1: DPB T2,[POINT SL.SPN,P2,<^L<SL.PPN>+SL.SPN-1>] ;SAVE PAGE NUMBER IN P2
PUSHJ P,NXTFRG ;SET U FOR THIS FRAGMENT
JRST BFSLS2 ;DONE
JUMPE P4,BFSLS4 ;NO COPYING TO DO
MOVE T1,-1(P1) ;GET ORIGINAL ENTRY
MOVEM T1,(P4) ;COPY IT
AOS P4
BFSLS4: MOVEM P2,-1(P1) ;SAVE SWPLST ENTRY
LDB T3,[POINT SL.SCT,P2,<^L<SL.CNT>+SL.SCT-1>] ;SIZE
MOVE T1,U ;1ST DSK ADR
MOVE T4,P3 ;ROUTINE TO CALL TO STORE IN MEMTAB
PUSHJ P,SETXMT ;SET UP FOR THIS FRAG
JRST BFSLS1 ;OK, DO NEXT FRAG
BFSLS2: POP P,T1 ;RESTORE 1ST ADR OF 4-WD BLOCKS
TLO T1,FRGSEG ;INDICATE FRAGMENTED
POP P,J ;RESTORE J
SKIPE P4 ;IF COPY OF FRAGMENT LIST
SETZM (P4) ;THEN TERMINATE COPY
JRST MAKSLE ;CALL MAKSLE AND RETURN
;SUBROUTINE TO SET UP MEMTAB FOR A SWAP
;CALL WITH T1=1ST DSK ADR, T2=1ST PAGE NUMBER, T3=NUMBER OF PAGES, T4=ROUTINE
; TO CALL TO STORE DISK ADDRESSES
;ALWAYS RETURNS CPOPJ
SETXMT: SE1ENT ;ENTER SECTION 1
PUSHJ P,SAVE2##
SETZ P1, ;NEED ZERO FOR SECTION #
MOVE P2,T4 ;ADDRESS OF ROUTINE TO CALL TO STORE DISK ADDRESS
SETXM1: SSX T2,MS.MEM ;SECTION NUMBER FOR PAGTAB/MEMTAB
PUSHJ P,(P2) ;SAVE DISK ADDRESS (CLEARING REST)
MOVE T4,T2 ;GET NEXT PAGE OF SEGMENT
TRNE T4,-1 ;LEGAL PREDESESSOR?
SKIPGE T2,PAGTAB(T2)
STOPCD .,STOP,PFC, ;++PAGE ON FREE CORE LIST
ADDI T1,1 ;INCR. DSK ADR BY 1
SOJG T3,SETXM1 ;GO DO NEXT PAGE
MOVSI T1,(MT.LEF)
IORM T1,MEMTAB(T4) ;INDICATE LAST PAGE IN MEMTAB
POPJ P, ;AND RETURN
;SUBROUTINE TO MOVE PAGES FROM "IP" QUEUE TO "OUT" QUEUE.
;CALL WITH P1=LOC OF SWPLST ENTRY, P2=SWPLST ENTRY
IP2OUT::SE1ENT ;MUST BE IN SECTION 1 TO LOOK AT PAGTAB/MEMTAB
PUSHJ P,SAVE2## ;SAVE ACS
IP2OU1: SKIPN P1,PAGIPQ## ;GET FIRST PAGE ON "IP" QUEUE
STOPCD IP2OU6,DEBUG,IPE, ;++IN PROGRESS QUEUE EMPTY
TLNE P2,(SL.ERR!SL.CHN!SL.CHK) ;ANY ERRORS?
JRST IP2ERR ;YES, PUT THE QUEUE BACK
IP2OU2: SSX P1,MS.MEM ;PAGTAB SECTION
MOVE P2,P1 ;SAVE PREDECESSOR
LDB T1,[POINT PT.SJB,PAGTAB(P1),<^L<PT.JOB>+PT.SJB-1>] ;GET POSSIBLE WAITING JOB NUMBER
JUMPE T1,IP2OU3 ;JUMP IF THERE IS NONE
S0PSHJ STPIOD## ;GET THE JOB STARTED AGAIN
HRRZS PAGTAB(P1) ;AND CLEAR JOB NUMBER
IP2OU3: MOVE T3,MEMTAB(P1) ;MEMTAB ENTRY
TLNN T3,(MT.GPB) ;DOES THE PAGE NEED TO BE GIVEN BACK?
JRST IP2OU4 ;NO, NEXT PAGE
LDB T2,[POINT MT.SAD,T3,<^L<MT.DAD>+MT.SAD-1>]
PUSHJ P,DLTDSP ;DELETE PAGE FROM DISK
HRRZ T2,P2 ;PHYSICAL PAGE NUMBER
MOVEI T3,PAGIPQ## ;"IP" QUEUE HEADER
PUSHJ P,RMVPFQ ;REMOVE THE PAGE FROM THE "IP" QUEUE
PUSHJ P,DLTPGC ;DELETE THE PAGE FROM CORE
SKIPE PAGIPQ## ;EMPTIED THE ENTIRE QUEUE?
JRST IP2OU1 ;NO, START OVER
JRST IP2OU5 ;YES, DELETE SWPLST ENTRY AND RETURN
IP2OU4: SKIPE P1,PAGTAB(P1) ;NEXT PAGE, EQUAL LAST PAGE?
JRST IP2OU2 ;YES, FINISH UP
DMOVE T1,PAGIPQ## ;GET FIRST PAGE, COUNT
EXCH T1,PAGOUQ## ;MAKE IT FIRST PAGE ON "OUT" QUEUE
MOVEM T1,PAGTAB(P2) ;LINK FORMER "OUT" QUEUE AT END OF FORMER "IP" QUEUE
SKIPE T1
HRRM P2,@[IW MS.MEM,PT2TAB(T1)]
ADDM T2,PAGOUC## ;UPDATE NUMBER OF PAGES ON "OUT" QUEUE
SETZM PAGIPQ## ;"IP" QUEUE IS NOW EMPTY
SETZM PAGIPC## ; ...
IP2OU5: MOVE P1,-2(P) ;GET SWPLST INDEX BACK
PUSHJ P,DLTSLX ;DELETE SWPLST ENTRY
IP2OU6:
IFN FTMP,<
PUSHJ P,SBSCD## ;MUST HAVE THE SCHEDULER INTERLOCK HERE
>
MOVEI P1,1 ;FLAG
HRRE J,JBTCQ##-PQIOQ## ;TAKE EVERYONE OUT OF PQIOW
JUMPLE J,IP2OU9 ;DONE HERE
IP2OU7: PUSHJ P,SSEC0##
IP2OU8: MOVEI T1,RNQ## ;REQUEUE HIM
SYSPIF
PUSHJ P,WAKOKE## ;PUT HIM IN THE RUN QUEUE
JFCL
HRRE J,JBTCQ##(J) ;NEXT JOB
JUMPG J,IP2OU8
IP2OU9: SOJL P1,CPOPJ## ;DONE IF LOOKED AT BOTH QUEUES
HRRE J,JBTCQ##-PQIOQ##-MXQUE##
JUMPG J,IP2OU7
POPJ P,
;HERE IF ERRORS IN THE SWPLST ENTRY
IP2ERR: SSX P1,MS.MEM ;SET RIGHT SECTION
LDB T1,[POINT P2.SPN,PT2TAB(P1),<^L<P2.VPN>+P2.SPN-1>] ;GET "VPN"
MOVSI T3,(MT.GPB) ;REALLY NEED THIS PAGE?
TDNE T3,MEMTAB(P1) ;?
JRST [MOVEI T3,PAGIPQ## ;NO, JUST FLUSH IT
HRRZ T2,P1 ;...
HRRZ P1,PAGTAB(P1) ;GET SUCCESSOR (IF ANY)
PUSHJ P,RMVPFQ ;REMOVE THE PAGE
JRST IP2ERX ] ;CONTINUE
MOVSI T3,(MT.IPC) ;IPCF PAGE?
TDNE T3,MEMTAB(P1) ;IS IT?
JRST IP2EIP ;YES, TREAT DIFFERENTLY
DPB T1,[POINT MT.SPN+MT.SSN,MEMTAB(P1),<^L<MT.VSN>+MT.SPN+MT.SSN-1>]
IP2ERE: HRRZ P1,PAGTAB(P1) ;NEXT PAGE ON IP QUEUE
IP2ERX: JUMPN P1,IP2ERR ;CONTINUE
MOVE P1,-2(P) ;DELETE THIS ENTRY
PUSHJ P,DLTSLX
MOVEI P1,PAGIPQ## ;HEADER TO "TRANSFER"
MOVE U,PAGIPC## ;AMOUNT OF SWPSPC TO GET
MOVEI T4,STODA ;ROUTINE
PJRST BPSLS2 ;TRY, TRY AGAIN
IP2EIP: LDB J,[POINT MT.SJB,MEMTAB(P1),<^L<MT.JOB>+MT.SJB-1>]
LSH J,P2.SPN ;SHIFT
IOR T1,J ;FULL 18-BIT ADDR
HRRM T1,MEMTAB(P1) ;SAVE IPCF ADDR
SETZ J,
DPB J,[POINT MT.SJB,MEMTAB(P1),<^L<MT.JOB>+MT.SJB-1>]
JRST IP2ERE ;CONTINUE WITH QUEUE
;SUBROUTINE TO MAKE AN ENTRY IN SWPLST
;CALLING SEQUENCE:
;
; MOVE T1,SWPLST ENTRY
; PUSHJ P,MAKSLE
;ALWAYS RETURNS CPOPJ
MAKSLE::MOVSI T2,MJBTMX## ;MAX NUMBER OF SWPLST ENTRIES
DSKOFF
IFN FTMP,<
SYSPIF
>
MAKSL1: SKIPE SWPLST##(T2) ;THIS SLOT AVAILABLE?
AOBJN T2,MAKSL1 ;NO
JUMPL T2,MAKSL2 ;FOUND A SLOT IF T2 NEG
STOPCD CPOPJ##,DEBUG,SLF, ;++SWPLST FULL
MAKSL2: MOVEM J,SW3LST##(T2) ;SAVE J
MOVEM T1,SWPLST##(T2) ;SAVE SWPLST ENTRY
MOVE T1,SWPOUT## ;SWPOUT (SCHED1) HAS TO BE SAVED
HRLM T1,SW3LST##(T2) ; IN CASE OF MULTIPLE SWAP-OUTS
AOS SLECNT## ;INCREMENT SWAP-LIST-ENTRY COUNT
MAKSL3:
IFN FTMP,<
SYSPIN
>
POPJ P, ;AND RETURN
;SUBROUTINE TO FIND A SWPLST ENTRY
;RETURNS CPOPJ IF NO ENTRIES (EVERYTHING IN SWPLST IS FOR PAGING)
;RETURNS CPOPJ1 IF FOUND, P1=INDEX , J=JOB NUMBER, T1=1ST PAGE, P2=ENTRY
FNDSLE::
IFN FTMP,<
SYSPIF ;MAKE SURE SOME OTHER CPU DOESN'T MAKE A SWPLST ENTRY
; AT INTERRUPT LEVEL
>
SKIPN P3,SLECNT## ;GET COUNT OF SWPLST ENTRIES
STOPCD MAKSL3,DEBUG,SLZ, ;++SLECNT IS ZERO
MOVEI P1,0 ;START AT 1ST THING IN SWPLST
FNDSL1: SKIPN P2,SWPLST##(P1);GET THE ENTRY
FNDSL2: AOJA P1,FNDSL1 ;NOT HERE - TRY NEXT
TLNE P2,(SL.DFM) ;DON'T FIND A UPMP ENTRY
JRST FNDSL3 ;IT WILL BE HANDLED AT INTERRUPT LEVEL
TLNE P2,(SL.SIO) ;SWAPPER ENTRY?
TLNN P2,(SL.IOD) ;YES, DONE?
FNDSL3: SOJG P3,FNDSL2 ;NO, TRY NEXT
JUMPE P3,ONPOPJ## ;DIDNT FIND ONE IF T1=0
MOVE T1,SW3LST##(P1) ;SWPOUT,,JOB NUMBER
TLNE P2,(SL.DIO) ;DON'T CHANGE SWPOUT IF INPUT
HLRZM T1,SWPOUT## ;RESTORE SWPOUT FOR SCHED1
HRRZ J,T1 ;SET UP J
LDB T1,[POINT 13,P2,26] ;1ST PHYSICAL PAGE
IFN FTMP,<
SYSPIN ;SLECNT AND SWPLST ARE CONSISTANT
>
PJRST CPOPJ1## ;TAKE SKIP-RETURN
;SUBROUTINE TO DELETE THE SWPLST ENTRY
;ENTER WITH P1=INDEX
;ALWAYS RETURNS CPOPJ
DLTSLX::
IFN FTMP,<
PUSH P,F ;PROBABLY NOT NECESSARY
MOVEI F,SWPDDB## ;FOR PIOFF
PIOFF ;GUARD AGAINST INTERPROCESSOR RACE
PUSHJ P,DLTSLE ;DELETE SWPLST ENTRY AND DECREMENT SLECNT
PION
JRST FPOPJ## ;RESTORE F AND RETURN
>
DLTSLE::SKIPN T1,SWPLST##(P1) ;GET ENTRY
STOPCD CPOPJ##,DEBUG,SIE, ;++SWPLST IS EMPTY
TLNE T1,(SL.IOD) ;IO DONE FOR THIS ENTRY?
TLNN T1,(SL.SIO) ;SWAPPER?
JRST DLTSL1 ;PAGER - LEAVE SWPCNT ALONE
SOSGE SWPCNT## ;DECREMENT SWPCNT
STOPCD DLTSL2,DEBUG,SIN, ;++SWPCNT IS NEGATIVE
DLTSL1: SOS SLECNT## ;DECREMENT NUMBER OF ITEMS IN SWPLST
SETZM SWPLST##(P1) ;CLEAR OUT THE OLD ENTRY
JUMPGE T1,CPOPJ## ;DONE IF NOT FRAGMENTED
;FALL INTO RTNBLK
;SUBROUTINE TO RETURN 4-WORD CORE BLOCKS USED IN SWPLST
;ENTER WITH T1=SWPLST ENTRY
RTNBLK: PUSHJ P,SAVE1## ;SAVE AC
MOVE P1,T1 ;ORIGINAL ENTRY
RTNBL1: HRRZ T2,P1 ;ADR OF 4-WD BLOCK
SKIPG T1,3(P1) ;NEXT BLOCK CONTIGUOUS WITH THIS?
SKIPA P1,T1 ;NO, SAVE ITS ADR
ADDI P1,4 ;YES
MOVEI T1,1 ;DELETE 1 BLOCK
PUSHJ P,GIV4WD##
JUMPE P1,CPOPJ## ;DONE IF LINK=0
JRST RTNBL1 ;NOT DONE, RETURN NEXT BLOCK
DLTSL2: SETZM SWPCNT## ;ZERO SWPCNT SO WONT KEEP GETTING HERE
POPJ P, ;AND RETURN
;SUBROUTINE TO GET 4 WORDS OF MONITOR FREE CORE
;ENTER P4=0 1ST TIME, P4=PREVIOUS P4 ON FOLLOWING CALLS
;RETURNS CPOPJ IF NO BLOCKS AVAILABLE
;RETURNS CPOPJ1 IF GOT ONE, P4=AOBJN WORD FOR BLOCK
GT4MR: PUSHJ P,SAVT## ;SAVE A BUNCH OF ACS
MOVEI T2,1 ;GET 1 BLOCK
PUSHJ P,GET4WD##
POPJ P,SETOMT ;CANT GET IT - POPJ
SETZM 3(T1) ;GOT IT, ZERO THE LINK
JUMPE P4,GT4M2 ;IF NOT 1ST CALL,
CAIE T1,1(P4) ;BLOCK CONTIGUOUS WITH PREVIOUS?
JRST GT4M1 ;NO
HRLI P4,-4 ;YES, CAN USE 4 WDS
JRST CPOPJ1## ; (LINK OF LAST, FIRST 3 OF THIS)
GT4M1: HRROM T1,(P4) ;POINT LAST WD OF PREVIOUS BLOCK AT THIS
GT4M2: MOVE P4,T1 ;ADR OF THIS BLOCK
HRLI P4,-3 ;CAN USE 3 WORDS
JRST CPOPJ1## ;TAKE GOOD RETURN
;SUBROUTINE TO SET UP BITS IN S FROM SWPLST
GETIOS::MOVEI S,0
TLNE P2,(SL.ERR) ;ERROR?
TRO S,IODERR ;YES
TLNE P2,(SL.CHN) ;CHAN ERROR?
TRO S,IOCHMP ;YES
TLNE P2,(SL.CHK) ;CHECKSUM ERRORS
TRO S,IOIMPM ;YES
TLNE P2,(SL.DIO) ;OUTPUT?
TLO S,IO ;YES
POPJ P, ;RETURN
;ROUTINE TO RETURN NEXT PAGE
;RETURNS RH(M)=VIRT PAGE, T4=POINTER TO MAP SLOT
;PRESERVE T1-T3,M ACCROSS CALLS (AFTER FIRST, CALL NXTSW2)
;BITS 3-17 OF M ARE PRESERVED FOR USE BY THE CALLER
;AND BITS 0-2 OF M (AS WELL AS RH(M) ARE FOR USE BY THIS ROUTINE
NXTWSB::SKIPGE .USBTS ;NOT A BIG USER?
SKIPG T2,.USSPT ;SECTION ZERO?
JRST [MOVEI T2,WSBTAB ;YES
JRST NXTWS1 ] ;DO THE OLD WAY
HRRZS T2 ;CLEAR LEFT HALF
IMULI T2,WSBTBL ;COMPUTE WHICH WSBTAB TO USE
MOVEI T2,.WSBNZ-WSBTBL(T2)
NXTWS1: AND M,[77777,,0] ;CLEAR ALL BITS WE USE
NXTWS2::MOVEI T1,^D36 ;36 BITS PER WORD
SKIPE T3,(T2) ;GET THE WSBTAB ENTRY
NXTWS3::JFFO T3,NXTWS4 ;FIND FIRST BIT
ADDI M,(T1) ;REST OF WORD 0 - COUNT VIRT PAGE IN M
HRRZ T3,M ;GET VPN
TLNN M,200000 ;TRANSLATED FUNNY SPACE #S YET?
CAIG T3,HLGPNO+1+<FYSSIZ/PAGSIZ##>+MXSECN
CAIL T3,.UPMVP/PAGSIZ##+MXSECN
SKIPA T3,[<.UPMVP/PAGSIZ##>+MXSECN+1] ;RETURN INVALID #
AOJA T2,NXTWS2 ;AND TRY NEXT WSBTAB WORD
HRRI M,(T3) ;M RETURNS PAGE #, NOT T3
POPJ P,
NXTWS4: LSH T3,1(T4) ;SHIFT OUT BITS THROUGH BIT JUST FOUND
SUBI T1,1(T4) ;ACCOUNT FOR NO OF BITS SCANNED
ADDI M,1(T4) ;INCR VIRTUAL PAGE
TLON M,400000 ;1ST TIME?
SUBI M,1 ;YES, WE'RE 1 TOO HIGH
HRRZ T4,M ;GET VIRTUAL PAGE IN T4
CAIG T4,HLGPNO ;STILL IN USER SPACE?
JRST [MOVE T4,.USSPT ;GET SECTION #
LSH T4,S2PLSH## ;MAKE FULL PAGE #
TRO T4,(M)
JRST GMPTR ]
TLOE M,200000 ;NO, TRANSLATE ALREADY?
JRST GMPTR ;ALREADY TRANSLATED, GO TO GMPTR
HRRI M,<.MCFV/PAGSIZ##>-<HLGPNO+1>(M) ;TRANSLATE #
HRRZ T4,M ;RESET T4
;FALL INTO GTMPTR
;SUBROUTINE TO SETUP A BYTE POINTER TO A HALF WORD IN THE MAP
;ENTER WITH T4=VIRTUAL PAGE NUMBER FOR WHICH THE BYTE PNTR IS TO BE COMPUTED
;PRESERVES T1-T3
GMPTR:: CAIGE T4,<.MCFV/PAGSIZ##>
JRST [ADD T4,[UMAPSN+UMAPS]
POPJ P,]
ADDI T4,.UPMP-<.MCFV/PAGSIZ##>+.UMORG
CAILE T4,.UPMP+.UMUPT ;SECTION MAP?
MOVEI T4,SECTAB-.UMORG-<<.UPMVP/PAGSIZ##>-<.MCFV/PAGSIZ##>>(T4)
POPJ P,
;SUBROUTINE TO SETUP MEMTAB FOR A SWAP OUT FROM THE WORKING SET TABLE
; AND THE UPMP
;CALLING SEQUENCE:
;
; MOVSI J,NUMBER OF PAGES ALLOCATED CONTIGUOUSLY ON THE DISK
; HRRI U,STARTING PAGE NUMBER ON THE DISK
; PUSHJ P,SETOMT ;FIRST CALL
; PUSHJ P,SETOM8 ;ALL SUBSEQUENT CALLS
;ALWAYS RETURNS CPOPJ, T1-T3,M,F,P4,R MUST BE PRESERVED FOR SUBSEQUENT CALLS
SETOMT: SE1ENT ;ENTER SECTION 1
SETZB P3,F ;FIRST TIME FOR ANYTHING
MOVSI P4,(UP.MAP) ;CLEAR BIT IN
ANDCAM P4,.USBTS ;.USBTS INDICATING MAP INFO
SKIPE R,.USSPT ;EXTENDED SECTION
JRST SETO18 ;YES
SETOM1: SETZB R,.USSPT ;BE SURE THAT'S WHAT WE'RE DOING
SETOM2: MOVEI P4,.UPMVP/PAGSIZ## ;MAX PAGE HERE IS THE UPMP
SETOM3: PUSHJ P,NXTWSB ;GET 1ST PAGE OF WORKING SET
SETOM4: CAIGE P4,(M) ;LEGAL PAGE #?
JRST SETO16 ;NO, GO TO NEXT SECTION
JUMPN F,SETO10 ;MUST BE JUST A SECTION CYCLE
MOVE F,(T4) ;GET MAP ENTRY
TLZE F,(<PM.DCD>B2) ;ACCESS ALLOWED ON?
TLZA F,(PM.NAD) ;YES, CLEAR BITS
TLZA F,(<PM.NAD^!<PM.COR!PM.AAB>>) ;ACCESS ALLOWED OFF, SEE IF EXPAND
JUMPN F,SETOM5 ;PROCEED WITH PARANOIA IF DCD IS ON
TLZN F,(PM.AAB) ;AAB ON?
TLZN F,(PM.COR) ;NO, COR MUST BE ON TOO IF NOT EXPANSION
CAIA ;AAB ON OR COR OF, EXPANSION
JUMPN F,SETOM5 ;FOUND A PAGE TO START AT
PUSHJ P,NXTWS3 ;MUST BE A NZS SECTION W/O P0
JRST SETOM4 ;AND COMPARE MORE
SETOM5: SKIPGE P3,.USSPT ;GET SECTION
TDZA P3,P3 ;MAPS
LSH P3,^D18+S2PLSH## ;LEFT HALF PAGE #
TLO P3,(M) ;VPN
HRR P3,F ;P3=1ST VIRT,,1ST PHYS
SETOM6: SSX F,MS.MEM ;SET SECTION NUMBER
MOVEM U,MEMTAB(F) ;SAVE DISK ADDRESS IN MEMTAB
MOVEI T4,(M)
CAIE T4,<.UPMVP-1>/PAGSIZ##
JRST SETOM7
MOVE T4,.USJOB
DPB U,JBYMT4## ;SET MAP
SETOM7: SOJLE J,SETO15 ;DONE
AOS U
SETOM8: JUMPE P4,SETO22 ;JUST DID A MAP
SETOM9: PUSHJ P,NXTWS3 ;NOT LAST, GET NEXT WS BIT
CAIGE P4,(M) ;LEGAL PAGE?
JRST SETO16 ;NO, NEXT SECTION
SETO10: MOVE T4,(T4) ;PHYSICAL PAGE
TDNN T4,[PM.ADR] ;ANY DISK ADDRESS?
JRST SETOM8 ;NO, IGNORE PAGE
TLZN T4,(<PM.DCD>B2)
JRST SETO14 ;NO
SETO11: JUMPN P3,SETO12 ;IF 1ST TIME,
SKIPGE P3,.USSPT
TDZA P3,P3
LSH P3,^D18+S2PLSH##
TLO P3,(M)
TRO P3,(T4) ; AND PHYS PAGE IN P3
JRST SETO13
SETO12: TRNE M,-1^!HLGPNO ;FUNNY PAGE?
SKIPA R,M ;YES
DPB M,[POINT 9,R,35] ;ELSE R HAS SECTION, MAKE VPN
DPB R,NVPNF ;AND SET NEXT VPN
SETO13: MOVE F,T4 ;F=PHYS PAGE
JRST SETOM6 ;AND CONTINUE
;HERE IF PM.ACC OFF - EITHER EXPANDING (INSDSK) OR IT REALLY SHOULD BE OFF
SETO14: TLNN T4,(PM.AAB) ;IS AAB OFF?
TLNN T4,(PM.COR) ;YES, IS COR ON?
JRST SETOM8 ;SOME FLAVOUR OF EXPANSION, IGNORE
JRST SETO11
;HERE AT FRAGMENT'S END
SETO15: PUSH P,T1 ;SAVE T1
HLRZ T1,P3 ;FIRST PAGE
DPB T1,NVPNF ;POINT LAST TO IT
MOVSI T1,(MT.LEF)
IORM T1,MEMTAB(F) ;SET LAST
MOVSI T1,(UP.MAP) ;MAP INFO THIS FRAGMENT?
TDNE T1,.USBTS ;?
TLO P2,(SL.MAP) ;YES, SET SWPLST BIT TOO
ANDCAM T1,.USBTS ;CLEAR BIT
JRST TPOPJ## ;RETURN
;HERE AT THE END OF A SECTION
SETO16: SKIPG .USSPT ;SECTION 0 OR MAPS?
JRST SETO19 ;YES, DO MAPS THEN OR RETURN
SETO17: SOSGE R,.USSPT ;COUNT DOWN TO DO NEXT SECTION
JRST SETO20 ;TIME TO START DOING MAPS
SETO18: SKIPN P4,.UPMP+SECTAB(R)
JRST SETO17
TRNN R,-1 ;SECTION 0?
SKIPA P4,[.UPMVP/PAGSIZ##-1-1] ;YES, STOP AT MAP THEN
MOVEI P4,HLGPNO ;MAX FOR NON-ZERO SECTIONS
LSH R,S2PLSH## ;MAKE IT A SECTION # WITH NO PAGE #
JRST SETOM3 ;START THE SECTION
;HERE WHEN DOING MAPS
SETO19: JUMPE P4,SETO21 ;DOING MAPS
CAIN P4,.UPMVP/PAGSIZ## ;JUST DO UPMP?
POPJ P, ;HUH? PROBABLY A UNL THEN
SETO20:
SETO21: MOVEM T4,.USTMP ;SAVE RELEVANT VARIABLES
MOVEM M,.USTMP+1 ;WHICH WILL BE DESTROYED
SETO22: MOVSI P4,(UP.MAP) ;SET WE'RE DOING MAPS
IORM P4,.USBTS ;SET IT FOR BOSLST
SKIPL P4,.USSPT ;FIRST TIME?
MOVSI P4,-<MXSECN+1> ;YES
AOBJP P4,SETO24 ;TIME TO DO SECTION 0
SETO23: SKIPE T4,.UPMP+SECTAB(P4);SAVE A LITTLE TIME IN THIS
TLNE T4,(<PM.ACD^!PM.DCD>B2) ;INDIRECT POINTER?
AOBJN P4,SETO23
JUMPGE P4,SETO24 ;DONE
MOVEM P4,.USSPT ;SAVE POINTER TO CURRENT MAP
MOVEI M,.UPMVP/PAGSIZ##(P4) ;PAGE # OF MAP
MOVEI T4,(M) ;POINTER
PUSHJ P,GMPTR ;GET MAP
SETZ P4, ;FLAG TO COME BACK HERE
HRRZS R ;AND THE SECTION #
JRST SETO10
;HERE TO DO MAP AND UPMP (FINISH SECTION 0)
SETO24: MOVE T4,.USTMP ;RESTORE RELEVANT VARIABLES
MOVE M,.USTMP+1
MOVEI P4,.UPMVP/PAGSIZ## ;NOW UPMP IS LAST
SETZM .USSPT ;REALLY SECTION 0 NOW
JRST SETO10
;SUBROUTINE TO SETUP THE UPMP WITH PHYSICAL CORE ADDRESSES FROM PAGTAB,
; THE UPMP, THE WORKING SET TABLE, AND THE ACCESS ALLOWED TABLE AND SETUP
; MEMTAB FOR A SWAP IN
;CALLING SEQUENCE:
;
; PUSHJ P,SETIMT ;FIRST CALL
; PUSHJ P,SETIMX ;ALL SUBSEQUENT CALLS
;RETURNS CPOPJ1 WHEN A NON-CONTIGUOUS DISK ADDRESS IS FOUND. RETURNS
; CPOPJ WHEN THE ENTIRE UPMP HAS BEEN PROCESSED.
;RETURNS P3=# OF PAGES, P1=1ST VIRT,,1ST PHYS
;PRESERVE T1-T4,M,F OVER CALLS TO SETIMX
;BITS IN THE LEFT HALF OF P3 IN BELOW (USED ONLY LOCALLY):
; 1B0 JUST CHANGED SECTION, STILL CONTIGUOUS)
; 1B14 SECTION CHANGE REQUIRED ON NEXT MEMTAB ENTRY
; 1B15 NO I/O TO DO YET
; 1B16 NEED TO ADVANCE PHYSICAL PAGE FOR STORE INTO P1
; 1B17 MAY BE NO PAGES IN REQUEST
SETIMT: SE1ENT ;ENTER SECTION 1
PUSH P,J ;SAVE J
SKIPE T1,.USSPT ;SECTION ZERO?
JRST SETI20 ;SET UP FOR FIRST CALL IN NZS
LDB F,JBYLSA## ;FIRST PHYSICAL ADDRESS
SETIM1: PUSHJ P,NXTWSB ;GET 1ST PAGE IN WORKING SET
HRRZ R,M
CAILE R,.UPMVP/PAGSIZ##+MXSECN
JRST SETI13
TLZ P3,4 ;ACTUALLY DOING SOMETHING I/OWISE
TLZE P3,400000 ;CYCLING THROUGH SECTIONS?
JRST SETIM5 ;YES, THIS WAS A LOGICAL CALL TO NXTNW3
MOVE U,(T4) ;GET MAP WORD
TLZ U,(PM.NAD) ;CLEAR EXTRANEOUS BITS
JUMPE U,SETI11 ;CONTINUE
JUMPN P1,SETIM3 ;IF JUST CYCLING THROUGH SECTIONS
SKIPGE P1,.USSPT
TDZA P1,P1
LSH P1,S2PLSH##+^D18
TLO P1,(M)
HRR P1,F ;1ST VIRTUAL,,1ST PHYSICAL
JRST SETIM3 ;PROCEED
SETIM2: MOVE U,(T4) ;GET DSK ADR
TLZ U,(PM.NAD) ;MAKE SURE EXTRANEOUS BITS ARE 0
JUMPE U,SETIM8 ;MAY NOT BE ANY PAGES IN THIS SECTION
SETIM3: MOVE J,(T4) ;GET OLD PAGE MAP ENTRY
AND J,[PM.BTS] ;KEEP ONLY ACCESSIBILITY BITS
TLNN J,(PM.AAB) ;IN AABTAB?
TRNE M,<-1^!HLGPGS> ;OR IS IT A MONITOR PAGE?
TLOA J,(<PM.DCD>B2)
TLZ J,(<PM.ACD>B2) ;NO ACCESS ALLOWED
TLO J,(PM.COR) ;NOW A CORE ADDRESS
ADDI J,(F)
MOVE R,F
SSX R,MS.MEM ;SET SECTION NUMBER FOR MEMTAB
TLNN F,-1 ;THIS PAGE HAVE A DISK ADDRESS?
MOVEM U,MEMTAB(R) ;YES, SAVE IN MEMTAB
MOVEM J,(T4) ;SAVE IN MAP
SETIM4: PUSHJ P,NXTWS3 ;GET NEXT PAGE, M=VIRT, T4=MAP POINTER
HRRZ R,M
CAILE R,.UPMVP/PAGSIZ##+MXSECN
JRST SETI12
CAIE R,.UPMVP/PAGSIZ##;UPT?
CAIN R,.UPMVP/PAGSIZ##-1 ;MAP?
JRST SETIM4 ;YES
SETIM5: MOVE J,(T4) ;DISK ADDR OF NEXT PAGE
TLZ J,(PM.NAD) ;CLEAR ACCESS BITS ETC.
JUMPE J,SETIM8 ;GO IF NO DISK ADDR
JUMPN P1,SETIM6 ;IF 1ST CALL,
SKIPGE P1,.USSPT ;SECTION #
TDZA P1,P1
LSH P1,S2PLSH##+^D18
TLNN P3,2 ;NEED TO ADVANCE PHYSICAL PAGE?
HRR P1,F ;NO, GET CURRENT 1ST PHYS
SETIM6: SKIPN U ;FIND FIRST PAGE YET?
SOSA U ;NO, BE SURE WE THINK IT'S CONTIGUOUS
SUB U,J
HLRZ J,F ;PAGE NUMBER OF LAST PAGE WITH A DSK ADR
TLZN F,-1 ;IF IT WAS LAST PAGE,
MOVE J,F ;GET IT FROM F
AOJN U,SETI15 ;GO IF NOT CONTIGUOUS
MOVEI R,(P3) ;CHECK ONLY RIGHT HALF
CAIL R,776 ;CAN ONLY STORE NINE BITS
SOJA U,SETI15 ;FRAGMENT; BE SURE THAT U'S NON-ZERO
SETIM7: SKIPGE U,.USSPT ;CURRENT SECTION
TDZA U,U
LSH U,S2PLSH## ;MAKE SECTION #
TRO U,(M) ;SET PART OTHER THAN SECTION
HRRZ R,J
SSX R,MS.MEM ;MAKE PAGTAB/MEMTAB ADDRESSBLE
DPB U,NVPNR ;STORE
HRR R,F ;FOR INDEXING INTO PAGTAB
HRR F,PAGTAB(R) ;NEXT PHYSICAL PAGE
TLZE P3,2 ;NEED TO STORE "ADVANCED" PHYSICAL IN P1?
HRRI P1,(F) ;YES, DO IT NOW
AOJA P3,SETIM2 ;COUNT THE PAGE, TEST NEXT
;HERE IF NEXT PAGE HAS NO DISK ADDRESS
SETIM8: PUSH P,T2 ;SAVE T2 FOR NXTWSB
MOVE T2,F ;FOR INDEXING INTO PAGTAB
SSX T2,MS.MEM ;SET SECTION NUMBER
HRRZ T2,PAGTAB(T2) ;THIS PHYSICAL PAGE
PUSHJ P,ZPAGE ;ZERO THE PAGE
POP P,T2 ;RESTORE T2
TLNN F,-1 ;FIRST SUCH PAGE?
HRLS F ;YES, SAVE IN LH(F)
SETIM9: MOVE R,F ;TO GET PAGTAB ENTRY
SSX R,MS.MEM ;SET SECTION
HRR F,PAGTAB(R) ;STEP TO NEXT PHYSICAL PAGE
SETI10: JUMPN P1,SETIM3 ;CONTINUE, U=DSK ADR IF NOT 1ST CALL TO SETIMX
JUMPE U,SETIM3 ;ALSO IF FIRST PAGE OF SECTION IS ABZ,
;THEN AVOID KAF
JRST SETIM2 ;1ST CALL TO SETIMX - GET U FROM BYTE PNTR
;HERE SAME AS SETIM8, BUT FOR FIRST TIME THROUGH MAIN SETIM LOOP
SETI11: TRNN P3,-1 ;ANY PAGES ALREADY IN REQUEST?
TLO P3,3 ;NO, THERE MAY BE NONE, FLAG PHYSICAL ADVANCE
PUSH P,T2 ;SAVE T2 FOR NXTWSB
HRRZI T2,(F) ;PAGE TO ZAP
PUSHJ P,ZPAGE ;ZERO THE PAGE
POP P,T2 ;RESTORE T2
JRST SETI10
;HERE FOR UPMP
SETI12: TLO P3,400010 ;FLAG A POSSIBLE SECTION CYCLE
SETI13: SKIPE .USSPT ;DOING SECTION 0?
JRST SETI16 ;NO, INCREMENT SECTION #
SETI14: SOS -1(P) ;RETURN CPOPJ
PUSHJ P,SETHSA ;UPDATE JBTHSA IF NECESSARY
TLNE F,-1 ;ENDING ON EXPANDING PAGES?
HLRZ J,F ;YES, LOAD J WITH LAST PAGE WE DID I/O TO
;HERE AT END OF THIS FRAGMENT
SETI15: HLRZ U,P1 ;NEXT VPN
MOVE R,J ;USE LAST PAGE I/O WAS DONE TO
SSX R,MS.MEM ;SET SECTION
DPB U,NVPNR ;SET NEXT VIRTUAL PAGE
MOVSI U,(MT.LEF)
IORM U,MEMTAB(R)
TLZ P3,400012 ;BE SURE THEY'RE CLEAR
TLZN P3,5 ;WENT THROUGH SETI11 (COUNT OFF BY ONE)?
;OR NOT DONE ANY I/O?
AOJA P3,JPOPJ1## ;NO, COUNT THE PAGE AND RETURN
JRST JPOPJ1## ;NO PAGES IN REQUEST
;HERE IF CONTIGUITY CROSSES A SECTION BOUNDARY
SETI16:
SETI17: SOSG T1,.USSPT ;DECREMENT SECTION WORKING ON
JRST SETI19 ;DONE IF THIS WAS LAST
SETI18: SKIPN .UPMP+SECTAB(T1) ;SECTION EXIST?
JRST SETI17 ;NO, TRY NEXT
JRST SETIM1 ;CONTINUE FRAGMENT
SETI19: SETZ T1, ;RESTORE SECTION 0
MOVEM T1,.USSPT
JRST SETI14
;HERE ON CALL TO SETIMT FOR NON-ZERO SECTIONS
SETI20: MOVE F,.USTMP+5 ;WHERE TO START
SSX F,MS.MEM ;PAGTAB SECTION
HRRZ F,PAGTAB(F) ;GET POINTER TO NEXT PHYSICAL PAGE
;(AND FLAG TO STORE U IN MEMTAB)
TLO P3,4 ;IN CASE WE DON'T DO ANY I/O
JRST SETI18 ;FIND FIRST REAL SECTION
;HERE FOR SUBSEQUENT CALLS
SETIMX: SE1ENT ;ENTER SECTION 1
PUSH P,J ;SAVE J
SSX F,MS.MEM ;SET SECTION
HRRZ F,PAGTAB(F) ;STEP TO NEXT PHYSICAL PAGE
;(AND STORE INTO MEMTAB AT SETIM2)
; JUMPN P1,SETIM3 ;CONTINUE, U=DSK ADR IF NOT 1ST CALL TO SETIMX
;(THE ABOVE JUMPN CAN'T EVER HAPPEN ANY MORE)
SKIPGE P1,.USSPT ;SECTION #
TDZA P1,P1
LSH P1,S2PLSH##+^D18
TLO P1,(M) ;..
HRR P1,F
JRST SETIM2
;SUBROUTINE TO SETUP AN AOBJN POINTER TO BE USED TO SETUP MEMTAB -
; I.E. XWD -NUMBER OF CONTIGUOUS PAGES ON THE DISK, STARTING
; PAGE ON THE DISK, FROM THE FRAGMENT TABLE POINTED TO BY JBTSWP.
; IT ALSO SETS UP THE JOB NUMBER AND NUMBER OF PAGES
; ENTRIES IN THE SWPLST ENTRY WHICH IS BEING BUILT.
;CALLING SEQUENCE:
;
; MOVE P1,POINTER TO THE FRAGMENT TABLE (1ST CALL)
; MOVEI P2,SWPLST DESCRIPTORS
; PUSHJ P,NXTFRG
;RETURNS CPOPJ IF THIS IS THE LAST ENTRY IN THE FRAGMENT TABLE, CPOPJ1
; IF NOT, P1 POINTS TO THE NEXT ENTRY
NXTFR1: HRRZ P1,(P1) ;GET NEXT FRAG TABLE ENTRY
NXTFRG: SKIPN J,(P1) ;GET NO OF DSK PAGES
POPJ P, ;DONE IF 0
JUMPL J,NXTFR1 ;POINTER TO ANOTHER ADR IF NEG
LDB J,FRGCP1## ;FRAGMENT COUNT
DPB J,[POINT SL.SCT,P2,<^L<SL.CNT>+SL.SCT-1>] ;SAVE NUMBER OF PAGES
LDB U,FRGAP1## ;FRAGMENT ADDRESS
AOJA P1,CPOPJ1## ;GOOD RETURN
;SUBROUTINE TO FIX THINGS UP AFTER A SWAP-WRITE ERROR
MAPBAK::TDZA T1,T1 ;NORMAL ENTRY (DON'T CALL XPANDH WHEN DONE)
MAPBAX::MOVEI T1,UP.JXP ;CALL XPANDH WHEN DONE
CAILE J,JOBMAX##
JRST DLTSLX
PUSHJ P,FNDPDS## ;GET PDB
HRRZ S,.PDSCX##(W) ;GET OLD SAVCTX POINTER (IF THERE IS)
HLLZS .PDSCX##(W) ;..
MOVE T3,.CPMAP##
HRRZ T2,JBTUPM##(J) ;POINT UPT BACK AT ITSELF
TLO T2,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.COR+IFE FTMP,<PM.CSH>)
CONO PI,PI.OFF ;DON'T LET INTERRUPT LEVEL CHANGE THIS
MOVEM T2,.ECKSM/PAGSIZ##(T3) ;SINCE IT POINTED AT NLUPMP
CLRPT .ECKSM
MOVEM T2,.ECKSM+.UMUPT ;POINT IT BACK AT ITSELF
CONO PI,PI.ON ;OK TO TURN THE PIS ON
PUSHJ P,SVEUB## ;MAKE SURE RIGHT STUFF GETS SAVED
IORM T1,.USBTS ;SET FLAG FOR WHEN DONE
PUSHJ P,SAVCTS## ;SAVE CONTEXT
STOPCD .,STOP,OOC ;++OUT OF CORE BLOCKS
JRST MAPB12
;HERE AT UUO LEVEL
PUSHJ P,MAPBK0 ;DO THE REAL WORK
PJRST USCHE1## ;CONTINUE NOW
MAPBK0: PUSHJ P,SAVE4## ;SAVE ACS
MOVE P3,.UPMP+SECTAB+0 ;MAKE SURE REAL SECTION 0 PTR (NOT DISK)
IFN FTMP,<
PUSHJ P,MLSCSH## ;CACHED?
TLZ P3,(PM.CSH) ;NO
>
MOVEM P3,.UPMP+.UMUPM
PUSHJ P,CLPTZO ;FIX PAGING MEMORY
EXP .UPMAP
SE1ENT ;MUST BE IN SECTION 1
MOVE J,.USJOB ;DON'T TRUST J
LDB P3,JBYLSA## ;YES, SET TO SCAN MEMTAB CHAIN
ADJSP P,1 ;ALLOCATE STACK SPACE TO REM LAST PAGE
MOVEI J,200 ;BEFORE CALLING SCDCHK
SETZM .USSPT
MAPBK1: PUSHJ P,NXTWSB ;GET 1ST PAGE IN WORKING SET
MAPBK2: HRRZ P4,M ;UPMP?
SKIPE .USSPT ;SECTION 0?
CAIG P4,HLGPNO ;NO, THIS IS MAX
CAILE P4,.UPMVP/PAGSIZ##+MXSECN
JRST MAPBK7 ;END THIS SECTION
MOVE P2,(T4) ;GET DSK ADR
TRNE P2,-1 ;EVEN IF PM.COR WILL BE OFF, COULD BE ABZ
TLNE P2,(PM.COR) ;IS IT A DISK ADDRESS?
JRST MAPBK4 ;NO, LOOK AT NEXT PAGE
HLRZ P1,P2 ;SAVE ACCESS AND SOFTWARE BITS
TLZ P2,(PM.NAD) ;KEEP ONLY ADDR IN P2
ANDI P1,(PM.BTS) ;AND ONLY BITS IN P1
HRRZM P3,(P) ;SAVE PAGE WE START AT
MAPBK3: SSX P3,MS.MEM ;MAKE GLOBAL INDEX
MOVE P4,MEMTAB(P3) ;MEMTAB FOR THIS PAGE
TLZ P4,(<-1^!MT.DAD>)
CAME P2,P4 ;DSK ADR THE SAME?
JRST MAPBK5 ;NO
HRLI P3,<(PM.COR)>(P1)
TLNN P3,(PM.AAB) ;IN AABTAB?
TRNE M,<-1^!HLGPGS> ;OR IS IT A MONITOR PAGE?
TLO P3,(<PM.DCD>B2)
MOVEM P3,(T4) ;SAVE MAP ENTRY IN UPMP
MAPBK4: PUSHJ P,NXTWS3 ;GET NEXT PAGE IN WORKING SET
JRST MAPBK2 ;DO SO NOW
MAPBK5: HRRZ P3,PAGTAB(P3) ;STEP TO NEXT PAGE OF JOB
CAMN P3,(P) ;BEEN HERE BEFORE?
JRST MAPBK4 ;YES, MUST BE EXPANDING INTO THIS PAGE
JUMPN P3,MAPB10 ;CONTINUE
MOVE P3,J ;SAVE COUNT
MOVE J,.USJOB ;RESTORE JOB #
LDB J,JBYLSA## ;FIRST PAGE
EXCH J,P3 ;CONTINUE
MAPB10: SOJG J,MAPBK3 ;CONTINUE
MOVE J,.USJOB ;WAIT
PUSHJ P,SCDCHK## ;CHECK
MOVEI J,200
JRST MAPBK3
;HERE FOR NEXT SECTION
MAPBK7: SKIPL .USBTS ;EXTENDED?
JRST MAPBK9 ;RESTORE INDEX AND FINISH UP
MAPBK8: AOS T1,.USSPT ;NEXT SECTION
CAILE T1,MXSECN ;MAX?
JRST MAPBK9 ;RESTORE INDEX AND FINISH UP
SKIPE P2,.UPMP+SECTAB(T1) ;SECTION EXIST?
TLNE P2,(<PM.ACD^!PM.DCD>B2) ;IMMEDIATE POINTER?
JRST MAPBK8 ;NO
JRST MAPBK1 ;DO THIS SECTION
MAPBK9: HRRZS .USREL
MOVE J,.USJOB ;RESTORE JOB #
PUSHJ P,FNDPDS## ;GET PDB
HRRZ P1,.PDSCX##(W) ;GET CONTEXT BLOCK POINTER
HRRZ P1,(P1) ;AND OLD POINTER (IF ANY)
PUSHJ P,RESCTS## ;GET RID OF THIS SAVCTX BLOCK
DMOVEM T1,.CPPC## ;SAVE PC
MOVSI T1,NSWP!NSHF ;RESTORE STATE OF NSWP,NSHF
AND T3,T1
ANDCAM T1,JBTSTS##(J)
IORM T3,JBTSTS##(J)
HRRM P1,.PDSCX##(W)
MOVEI P1,UP.JXP ;CALL XPANDH FOR SWAPPER?
TDNE P1,.USBTS ;?
PUSHJ P,XPANDH## ;YES, FORCE JOB OUT NOW
ANDCAM P1,.USBTS
JRST TPOPJ## ;FIX STACK AND RETURN
;HERE AFTER SETTING UP AT CLOCK LEVEL TO RUN MAPBAK AT UUO LEVEL
MAPB12: MOVSI T1,NSHF ;MAKE SURE SWAPPER DOESN'T FIDDLE WITH US
IORM T1,JBTSTS##(J) ;(SET NSHF BUT NOT NSWP)
MOVSI T1,SWP!SHF!JXPN!NSWP ;SO JOB WILL RUN
ANDCAM T1,JBTSTS##(J) ;CLEAR SO THE SCHEDULER KNOWS IT
PUSHJ P,REQUE## ;PUT INTO A QUEUE
S0JRST DLTSLX ;RETURN SWPLST ENTRY
;SUBROUTINE TO SET/CLEAR IO IN S FOR SWAPPER
;CALLED IN ERROR RECOVERY SINCE DEVIOS CAN CHANGE IN SWPDDB
;CALL WITH U SET UP
SWPINS::MOVE T1,UNISWA##(U) ;POINTER TO SWPLST
MOVE T1,(T1) ;GET SWPLST ENTRY
TLNN T1,(SL.DIO) ;INPUT?
TLZA S,IO ;YES
TLO S,IO ;NO
POPJ P,
;SUBROUTINE TO DETERMINE IF A JOB HAS A PAGE OR PAGES ON EITHER THE "IN" QUEUE
; OR THE "SN" QUEUE. CALL WITH J=JOB NUMBER, SKIPS IF JOB ISN'T ON EITHER QUEUE
;PRESERVES ALL ACS (SINCE CALLED FROM THE SWAPPER, THAT'S THE ONLY SAFE THING TO DO)
JOBNQ:: PUSHJ P,SVEUB## ;SEE IF JOB IS VIRTUAL
SKIPN .USVRT ;IS HE?
JRST CPOPJ1## ;NO, CAN'T HAVE PAGES ON ANY QUEUE
PUSHJ P,SAVT## ;SAVE ALL ACS
MOVEI T1,PAGINQ## ;LOOK AT "IN" QUEUE FIRST
PUSHJ P,JOBNPQ ;SEE IF JOB HAS PAGES ON THAT QUEUE
POPJ P, ;YES
MOVEI T1,PAGSNQ## ;NOW LOOK AT "SN" QUEUE
PUSHJ P,JOBNPQ
POPJ P, ;ON THE SN QUEUE
MOVEI T1,PAGIPQ## ;CHECK THE IP QUEUE AS WELL
;FALL INTO JOBNPQ
;SUBROUTINE TO SEE IF A JOB HAS ANY PAGES ON A PAGE QUEUE
;CALL WITH T1 = ADDRESS OF QUEUE, SKIPS IF JOB ISN'T ON THE QUEUE
JOBNPQ: SKIPN T1,(T1) ;NOT ON QUEUE IF QUEUE IS EMPTY
JRST CPOPJ1## ;NOT ON QUEUE RETURN
SE1ENT ;MUST BE IN SECTION 1 TO REFERENCE PAGTAB/MEMTAB
JOBNP1: SSX T1,MS.MEM
LDB T2,[POINT MT.SJB,MEMTAB(T1),<^L<MT.JOB>+MT.SJB-1>] ;GET JOB NUMBER FROM QUEUE
HLL T2,MEMTAB(T1) ;AND BITS
TLNN T2,(MT.IPC) ;IF THIS IS AN IPCF PAGE, DON'T WORRY
CAIE J,(T2)
SKIPA T1,PAGTAB(T1) ;GET NEXT PAGE
POPJ P, ;YES, INDICATE THAT TO CALLER
JUMPE T1,JOBNP1 ;CHECK IF IT EXISTS
JRST CPOPJ1## ;NOT ON THE QUEUE
;SUBROUTINE TO CLEAR A JOB'S PAGES IN ANY PAGING QUEUE (ANY IN QUEUE OR
;THE IP QUEUE). CALLED BY CORE 0 PROCESSING
JOBFNQ::
PUSHJ P,SVEUB## ;NEED TO MAP JOB
SE1ENT ;MUST BE IN SECTION 1
JOBFN2: SKIPN .USVRT ;IS JOB VIRTUAL?
POPJ P, ;NO, NOTHING TO DO
SKIPN PAGINC## ;ANYTHING ON THE FAST "IN" QUEUE?
JRST JOBFN3 ;NO
MOVEI T1,PAGINQ## ;POINT THERE
PUSHJ P,JOBNPQ ;SEE IF ANY PAGES ON THAT QUEUE FOR THIS JOB
SKIPA T1,MEMTAB(T1) ;YES, MUST PROCESS IT
JRST JOBFN3 ;NO PAGES ON IN QUEUE, PROCEED
ANDI T1,MT.VSN+MT.VPN ;SAVE JUST PAGE #
PUSHJ P,DLTPAG ;GET RID OF THE PAG
JRST JOBFN2 ;AND LOOK FOR MORE
JOBFN3: SKIPN PAGSNC## ;ANYTHING ON THE SLOW QUEUE?
JRST JOBFN6 ;NO
SKIPN .USVRT ;ONLY CONTINUE IF STILL VIRTUAL
POPJ P, ;DONE IF NOT
MOVEI T1,PAGSNQ## ;SLOW QUEUE
PUSHJ P,JOBNPQ ;FIND ANYTHING THERE
SKIPA T1,MEMTAB(T1) ;YES, MUST PROCESS IT
JRST JOBFN6 ;NO MORE HERE
ANDI T1,MT.VSN+MT.VPN
PUSHJ P,DLTPAG ;GET RID OF IT
JRST JOBFN3 ;CONTINUE LOOKING
JOBFN6: SKIPE PAGIPC## ;ANY PAGES ON IN PROGRESS QUEUE?
SKIPN .USVRT ;AND IS JOB STILL VIRTUAL?
POPJ P, ;NO TO ONE; ALL DONE
MOVEI T1,PAGIPQ## ;POINT TO IP QUEUE
PUSHJ P,JOBNPQ ;FIND PAGE THERE
CAIA ;FOUND ONE
POPJ P, ;DONE
MOVSI T2,(MT.GPB) ;GIVE PAGE BACK
IORM T2,MEMTAB(T1)
JRST JOBFN6
;SUBROUTINE TO REMOVE ALL DISK PAGES FOR JOB. CALLS SCDCHK, SO
;MUST BE RUN AT UUO LEVEL
DSKFLS::
SKIPN .USVRT ;VIRTUAL
POPJ P, ;NO, CAN'T HAVE ANY OF THESE THEN
SE1ENT
SETZM .USSPT ;START AT S0
DSKFL0: PUSHJ P,NXTNWS ;GET FIRST NON-WORKING SET PAGE
DSKFL1: TRNE M,-1^!HLGPNO ;DONE THIS SECTION?
JRST DSKFL6 ;YES
PUSHJ P,DSKFLX ;REMOVE PAGE
PUSHJ P,NXTNW3 ;CONTINUE LOOKING
JRST DSKFL1
DSKFL6: SKIPL .USBTS ;EXTENDED USER?
POPJ P, ;NO, DONE
PUSH P,.USSPT ;IN CASE SOMETHING HAPPENS
PUSHJ P,SCDCHK##
POP P,.USSPT
AOS T1,.USSPT ;NEXT SECTION
DSKFL7: CAILE T1,MXSECN ;AT TOP
POPJ P, ;YES, DONE
SKIPE T2,.UPMP+SECTAB(T1) ;YES, DOES SECTION EXIST?
TLNE T2,(<PM.ACD^!PM.DCD>B2) ;AND INDIRECT
AOJA T1,DSKFL7
MOVEM T1,.USSPT ;SAVE
JRST DSKFL0
;HERE TO DELETE PAGE WE FOUND
DSKFLX: PUSHJ P,SAVT## ;SAVE TS FOR NXTNWS
MOVE T1,.USSPT ;GET SECTION
LSH T1,S2PLSH##
IORI T1,(M)
JRST DLTPAG
;SUBROUTINE TO RETURN THE NEXT PAGE NOT IN THE WORKING SET
;RETURNS CPOPJ, WITH RH(M)=VIRT PAGE, T4=CONTENTS OF MAP SLOT
;ZERO PAGES AND PM.ZER PAGES ARE IGNORED
;NOTE THAT THIS ROUTINE ASSUMES ALL PER-PROCESS PAGES ARE IN THE WORKING SET
;PRESERVE T1-T3, M ACROSS CALLS (CALL NXTNW3 AFTER FIRST CALL)
;LIKE NXTWSB, BITS 3-17 OF M ARE PRESERVED FOR USE BY THE CALLER
;AND BITS 0-2 OF M (AS WELL AS RH(M) ARE FOR USE BY THIS ROUTINE
NXTNWS::
SKIPGE .USBTS ;NOT A BIG USER?
SKIPG T2,.USSPT ;SECTION POINTER
JRST [MOVEI T2,WSBTAB
JRST NXTNW1 ] ;SECTION ZERO; OLD WAY
HRRZS T2
IMULI T2,WSBTBL
MOVEI T2,.WSBNZ-WSBTBL(T2)
NXTNW1: AND M,[77777,,0] ;CLEAR ALL BITS WE USE
NXTNW2: MOVEI T1,^D36 ;36 BITS IN A WORD
SETCM T3,(T2) ;BITS FOR EVERY NON-WS PAGE
NXTNW3::
JFFO T3,NXTNW4 ;FIND A 1-BIT
ADDI M,(T1) ;REST OF WORD 0, STEP TO NEXT
MOVEI T4,(M) ;GET PAGE #
CAILE T4,HLGPNO ;IN USER SPACE?
TDZA T4,T4 ;NO, OFF THE END (SEE NOTE TOP OF THIS ROUTINE)
AOJA T2,NXTNW2
POPJ P,
NXTNW4: LSH T3,1(T4) ;CLEAR THE BIT
SUBI T1,1(T4) ;COUNT THE BIT
ADDI M,1(T4) ;...
TLON M,400000 ;FIRST TIME?
SUBI M,1 ;YES, WE'RE 1 TOO HIGH
MOVEI T4,(M) ;VIRTUAL PAGE #
CAILE T4,HLGPNO ;IN USER SPACE?
TDZA T4,T4 ;NO, RETURN ZERO
SKIPA T4,.USSPT
POPJ P,
LSH T4,S2PLSH##
TRO T4,(M)
NXTNW5: PUSHJ P,GTPM4 ;GET MAP CONTENTS
JUMPE T4,NXTNW3 ;UNALLOCATED PAGE
TDNE T4,[PM.ADR^!PM.ZER] ;ABZ PAGE?
PUSHJ P,NXTHS ;SEE IF 0 OR HIGH SEG PAGE
JRST NXTNW3 ;0 OR PM.ZER, TRY NEXT
TLNN T4,(PM.SSP!PM.OIQ) ;QUEUE PAGE?
IFN FTPEEKSPY,<
TLNE T4,(PM.SPY) ;SPY PAGE?
JRST NXTNW3 ;YES, DON'T FIND IT
>
POPJ P, ;"REAL" PAGE, RETURN IT
;SUBROUTINE TO SEE IF MAP CONTENTS IS 0 OR IN A HIGH SEG
;PRESERVES ALL ACS
NXTHS: JUMPE T4,CPOPJ## ;IF MAP IS NON-0
PUSHJ P,SAVT## ;SAVE ALL ACS
HRRZ T1,M ;PAGE TO TEST
PJRST TPNSHS ;GO SEE IF IT IS IN A HIGH SEG
;SUBROUTINE TO TEST IF A DISK ADDRESS IS ON A UNIT BEING REMOVED
;ENTER T4=C(MAP SLOT) - DSK ADR
;EXIT CPOPJ IF UNIT GOING DOWN, CPOPJ1 IF NOT
;PRESERVES T1-T3
TSTUN::
IFN FTPEEKSPY,<
TLNE T4,(PM.SPY) ;SPY PAGE?
JRST CPOPJ1## ;YES, IT'S NOT ON A BAD UNIT
>
LDB T4,SSUNT4## ;GET SWAP UNIT
SKIPLE T4,SWPTAB##(T4) ;UNIT DATA BLOCK LOC
SKIPGE UNIFKS##(T4) ;IF NEGATIVE, GOING DOWN TOO
JRST CPOPJ## ;UNIT ALREADY DOWN
MOVE T4,UNIUST##(T4) ;STATUS
TLNN T4,UNPNNA##+UNPRSS## ;UNIT GOING DOWN?
AOS (P) ;NO, SKIP RETURN
POPJ P, ;RETURN
;SUBROUTINE TO COMPLEMENT A BIT IN WSBTAB
;ENTER RH(M) = VIRTUAL PAGE NUMBER
;PRESERVES T1-T3
;NOTE THAT .USSPT MUST NOT BE AN INDIRECT SECTION
BTCOM::
PUSH P,T1 ;SAVE T1
PUSH P,T2 ;AND T2
SKIPG T1,.USSPT ;CURRENT SECTION
TDZA T1,T1 ;IS REALLY S0
LSH T1,S2PLSH## ;CONVERT TO PAGE #
ADDI T1,(M)
PUSHJ P,TSWST ;COMPUTE WSBTAB BIT, POSITION
JFCL
XORM T2,(T4) ;FLIP THE BIT IN WSBTAB
JRST TTPOPJ## ;NO
;SUBROUTINE TO ALLOCATE MONITOR PAGES
;CALLING SEQUENCE:
; MOVE T1,FIRST PAGE TO ALLOCATE
; MOVE T2,NUMBER OF PAGES TO ALLOCATE
; MOVE T3,SIGN BIT=FLAG 0=CACHED,NON-ZERO=UNCACHED (KL ONLY)
; PUSHJ P,CREMPG
; RETURNS HERE IF NO VIRTUAL CORE
; RETURNS HERE WHEN THE PAGES HAVE BEEN ALLOCATED
;STOPS IF THE PAGES ALREADY EXIST, CALLERS RESPONSIBILITY TO
; CHECK TO SEE THAT THE PROGRAM ISN'T GETTING TO BIG
CREMPG:
IFN FTMP,<
PUSHJ P,GGVMM## ;GET THE MM
>
GETMPG::
PUSHJ P,SAVE3## ;SAVE P1-P3
IFN FTKL10,<
MOVE P3,T3 ;SAVE CACHED/UNCACHED FLAG
>
CAMLE T2,VIRTAL## ;MAKE SURE THERE'S ENOUGH SPACE
POPJ P, ;FAIL
DMOVEM T1,P1 ;SAVE STARTING PAGE NUMBER, NUMBER OF PAGES
MOVN T3,T2 ;MINUS THE NUMBER OF PAGES OF INCREASE
ADDM T3,VIRTAL## ;DECREMENT TOTAL SYSTEM VIRTUAL MEMORY AVAILABLE
CREMP1: MOVE T3,P2 ;NUMBER OF PAGES TO ALLOCATE
PUSHJ P,FRDCRW## ;ENOUGH CORE IN CORE TO SATISFY REQUEST?
JRST CREMP5 ;NO, ALLOCATE CORE ON THE DISK
SE1ENT ;ENTER SECTION 1 TO ADDRESS PAGTAB
PUSH P,J ;SAVE J, COULD POINT AT A KDB
MOVE J,.CPJOB## ;CURRENT JOB
MOVE T3,[MCPCNT] ;ONE IN COUNT OF FUNNY PAGES BYTE
IMULI T3,(P2) ;TIMES THE NUMBER OF FUNNY PAGES TO ALLOCATE
ADDM T3,JBTPDB##(J) ;UPDATE NUMBER OF FUNNY PAGES OWNED BY THIS JOB
PUSHJ P,SCPAGS## ;FIND THE LAST PAGE ALLOCATED TO THIS JOB
MOVE T2,P2 ;NUMBER OF PAGES REQUESTED
PUSHJ P,ADPAGS## ;ALLOCATE THAT NUMBER
EXCH P1,T1 ;P1 = FIRST PHYSICAL PAGE ALLOCATED, T1 = VIRTUAL PAGE
IFN FTLOCK,<
LDB T2,JBYLSA## ;PAGE 0
SSX T2,MS.MEM ;PAGTAB SECTION NUMBER
HLR P3,PAGTAB(T2) ;LOCK BITS
>
SSX P1,MS.MEM ;PAGTAB SECTION
JRST CREMP3 ;GO ADD THE PAGES TO THE JOB'S MAP
CREMP2: SSX P1,MS.MEM ;SET PAGTAB SECTION NUMBER
HRRZ P1,PAGTAB(P1) ;NEXT PHYSICAL PAGE
CREMP3:
IFN FTLOCK,<
HRLM P3,PAGTAB(P1) ;LOCK BITS
>
IFN FTKL10,<
JUMPGE P3,CREMP4 ;JUMP IF CACHED PAGE
PUSHJ P,WSBIT ;SETUP FOR CALL TO INSMPU
MOVE T3,P1
HRLI T3,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.COR)
PUSHJ P,INSMPU ;PUST THE PAGE IN THE JOB'S MAP
CAIA ;SKIP
CREMP4:>
PUSHJ P,INSMPC ;INSERT THE PAGE IN THE JOB'S MAP CACHED
ADDI T1,1 ;NEXT VIRTUAL PAGE
SOJG P2,CREMP2 ;LOOP OVER ALL PAGES ALLOCATED
CLRPGT (0) ;CLEAR MEMORY OF PREVIOUS MAP
JRST JPOPJ1## ;RESTORE J AND RETURN
CREMP5: PUSH P,J ;SAVE J, COULD POINT AT A KDB
MOVE J,.CPJOB## ;CURRENT JOB
IFN FTLOCK,<
MOVSI T2,NSHF!NSWP ;JOB IS LOCKED BITS
TDNN T2,JBTSTS##(J) ;IS THE JOB LOCKED?
JRST CREMP6 ;NO
IFN FTMP,<
PUSHJ P,DWNMM## ;RETURN THE MEMORY MANAGEMENT RESOURCE
>
PUSH P,T1 ;YES, SAVE STARTING PAGE NUMBER
MOVEI T1,1 ;SLEEP 1 SECOND SINCE CANNOT SWAP OUT JOB TO ALLOCATE CORE
PUSHJ P,SLEEPF## ;ZZZZZZ
POP P,T1 ;RESTORE STARTING PAGE NUMBER
IFN FTMP,<
PUSHJ P,UPMM## ;RE-GET THE MM RESOURCE
>
POP P,J
JRST CREMP1 ;AND START OVER FROM SCRATCH
>
IFE FTLOCK,<
SETZ T2, ;FOR CALL TO IOWAT BELOW
>
CREMP6: PUSH P,S ;SAVE S (FILSER IS PARTICULAR ABOUT THAT)
PUSH P,F ;AND F
PUSHJ P,IOWAT ;WAIT FOR ALL I/O TO STOP SINCE JOB WILL BE SWAPPED
POP P,F ;RESTORE F
POP P,S ;AND S
LDB T2,NFYPGS## ;NUMBER OF FUNNY PAGES CURRENTLY ALLOCATED TO THE JOB
ADD T2,P2 ;PLUS NUMBER OF PAGES OF INCREASE
DPB T2,IFYPGS## ;NUMBER OF PAGES REQUIRED WHEN SWAPPED BACK IN
CREMP7:
IFN FTKL10,<
PUSHJ P,[JUMPG P3,INSDMC ;IF CACHED
JRST INSDMU ] ;IF NOT
>
IFN FTKS10,<
PUSHJ P,INSDMU ;INSERT PAGE (NEEDN'T WORRY ABOUT CACHE)
>
ADDI T1,1 ;NEXT VIRTUAL PAGE
SOJG P2,CREMP7 ;NEXT PAGE
PUSHJ P,XPANDH## ;MARK JOB AS EXPANDING
POP P,J ;RESTORE J
IFN FTMP,<
PUSHJ P,REMMM## ;GIVE UP MM NOW THAT XJOB AND JXPN AGREE
>
AOS (P) ;EVERYTHING IS OK
PJRST WSCHED## ;AND WAIT UNTIL THE JOB IS BACK IN CORE
;ROUTINE TO REQUEST ALLOCATION OF MONITOR PAGES AT CLOCK LEVEL.
;WHEN ALLOCATION IS COMPLETE (MAY TAKE A WHILE) THE CALLER WILL
;BE CALLED AT THE ADDRESS THEY SPECIFIED. THIS ROUTINE CAN BE
;CALLED ON ANY CPU BUT WILL ONLY RECALL ON THE BOOT CPU.
;CALL:
; T1/ SECTION #,,# PAGES REQUIRED
; T2/ ADDRESS OF ROUTINE TO CALL WHEN ALLOCATION COMPLETE
; T3-T4/ ARGUMENTS FOR CALLED ROUTINE (RETURNED IN T3-T4)
; PUSHJ P,GETCLP
;RETURN:
; CPOPJ ALWAYS
CLPLNK==0 ;LINK TO NEXT REQUEST IN CHAIN
CLPPGS==1 ;SECTION NUMBER,,NUMBER OF PAGES TO ALLOCATE
CLPRTN==2 ;ROUTINE TO CALL WHEN ALLOCATION COMPLETE
CLPARG==3 ;ARGUMENTS TO ROUTINE
CLPADR==5 ;VIRTUAL ADDRESS OF PAGES ALLOCATED
CLP4WD==2 ;NUMBER OF 4 WORD BLOCKS FOR REQUEST
GETCLP::PUSHJ P,SAVE4## ;SAVE P1-P4
DMOVE P1,T1 ;SAVE CALLER'S ARGUMENTS
DMOVE P3,T3 ;...
MOVEI T2,CLP4WD ;GET MEMORY FOR REQUEST BLOCK
S0PSHJ GET4WD## ;ASK
STOPCD .,STOP,CAC, ;++CAN'T ALLOCATE CLOCK LEVEL PAGES
SETZM CLPLNK(T1) ;CLEAR LINK WORD
DMOVEM P1,CLPPGS(T1) ;SAVE ARGUMENTS
DMOVEM P3,CLPARG(T1) ;...
SYSPIF ;PREVENT RACES
MOVEM T1,@CLPBOT## ;LINK NEW ENTRY ONTO END OF LIST
MOVEM T1,CLPBOT## ;MAKE THIS ENTRY THE NEW END
JRST ONPOPJ## ;RESTORE PI'S AND RETURN
;ROUTINE TO LOOP THROUGH THE CLP LIST AND ALLOCATE PAGES.
;CAN ONLY BE CALLED ON THE BOOT CPU.
CRECLP::SE1ENT ;MUST RUN IN NZS
PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,CLPTOP## ;GET FIRST ENTRY IN LIST
MOVE T1,CLPPGS(P1) ;GET NUMBER OF PAGES REQUESTED
IFN FTMP,<
JUMPL T1,CRECL1 ;JUMP IF WAITING FOR THE CACHE OR DATAO PAG,
PUSHJ P,GETMM## ;MUST HAVE THE MM
POPJ P, ;CAN'T GET IT, TRY AGAIN LATER
>; END IFN FTMP
HRRZ T3,T1 ;NUMBER OF PAGES TO ALLOCATE
PUSHJ P,FRDCR## ;SEE IF THE CORE IS AVAILABLE IN CORE
IFE FTMP,<
POPJ P, ;NOT NOW, WAIT A WHILE
>; END IFE FTMP
IFN FTMP,<
PJRST GIVMM## ;NOT NOW, WAIT A WHILE (GIVE UP MM)
>; END IFN FTMP
PUSHJ P,SAVR## ;SAVE R (JUST SUPERSTITION I HOPE)
HLRZ R,CLPPGS(P1) ;SECTION TO ALLOCATE FROM
IFE FTXMON,<
SKIPE R ;ANY SECTION NUMBER?
PUSHJ P,SVDCN## ;YES, ENTER DECNET CONTEXT
>; END IFE FTXMON
HRRZ T2,T1 ;NUMBER OF PAGES TO ALLOCATE
PUSHJ P,CREMNS ;ALLOCATE PAGES, SETUP MAPS
IFE FTMP,<
STOPCD CPOPJ##,DEBUG,FDL, ;++FRDCR LIED
>; END IFE FTMP
IFN FTMP,<
STOPCD GIVMM##,DEBUG,FDL, ;++FRDCR LIED
PUSHJ P,GIVMM## ;NOW OK TO RETURN THE MM
>; END IFN FTMP
MOVEM T1,CLPADR(P1) ;SAVE VIRTUAL ADDRESS OF PAGES JUST ALLOCATED
IFN FTMP,<
HRROS CLPPGS(P1) ;INDICATE WAITING ON CACHE AND PAGING MEMORY
; ON OTHER CPUS
HRROI T1,[MOVE T2,.CPCSN##-.CPCDB##(P1) ;BUMP CACHE SWEEP NUMBER
ADDI T2,2 ; ON ALL OTHER CPUS
MOVEM T2,.CPCSW##-.CPCDB##(P1) ;...
POPJ P,] ;RETURN FROM CPUAPP
PUSHJ P,CPUAPP## ;CAUSE ALL CPUS TO SWEEP CACHE AND DO A DATAO PAG,
CRECL1: PUSHJ P,MLSCSH## ;SEE IF MONITOR LOW SEGMENT CACHED (ONLY 1 CPU RUNNING)
CAIA ;NO
JRST CRECL2 ;YES, DON'T HAVE TO WORRY ABOUT OTHER CPUS
HRROI T1,[SKIPGE .CPOK##-.CPCDB##(P1) ; (ONLY CHECK IF CPU ALIVE AND WELL)
SKIPN .CPCSW##-.CPCDB##(P1) ;HAVE WE SWEPT YET?
CAIA ;HAVE SWEPT OR CAN'T BECAUSE CPU HAS DIED
SETO T3, ;FLAG SOMEONE STILL NEEDS TO SWEEP
POPJ P,] ;RETURN FROM CPUAPP
SETZ T3, ;ASSUME ALL CPUS ARE DONE
PUSHJ P,CPUAPP## ;HAVE ALL CPUS SWEPT AND CLEARED PAGING MEMORY?
JUMPN T3,CPOPJ## ;NO, STILL HAVE TO WAIT A WHILE
>; END IFN FTMP
CRECL2: MOVE T1,CLPADR(P1) ;GET VIRTUAL ADDRESS OF MEMORY ALLOCATED
HRRZ T2,CLPPGS(P1) ;GET NUMBER OF PAGES REQUESTED
DMOVE T3,CLPARG(P1) ;GET ARGUMENTS FOR ROUTINE
PUSHJ P,@CLPRTN(P1) ;CALL THE NOTIFICATION ROUTINE
SYSPIF ;PREVENT RACES
MOVE T1,CLPLNK(P1) ;GET LINK TO NEXT BLOCK
JUMPN T1,CRECL3 ;JUMP IF THERE IS ONE
MOVEI T2,CLPTOP## ;NOTHING, RESET EMPTY QUEUE
MOVEM T2,CLPBOT## ;...
CRECL3: MOVEM T1,CLPTOP## ;MAKE NEXT NEW FIRST
SYSPIN ;OK TO INTERRUPT AGAIN
MOVEI T1,CLP4WD ;NUMBER OF 4-WORD CHUNKS
MOVE T2,P1 ;ADDRESS OF THEM
S0JRST GIV4WD## ;RETURN THE CHUNK AND RETURN
;SUBROUTINE TO ALLOCATE AND MAKE ADDRESSABLE PAGES IN A NON-ZERO SECTION
;CALLING SEQUENCE:
; MOVEI R,SECTION NUMBER PAGES ARE TO BE ALLOCATED IN
; IF (R) = 0, ALLOCATE IN FUNNY SPACE
; MOVEI T2,NUMBER OF PAGES TO BE ALLOCATED
; PUSHJ P,CREMNS
; ... ;RETURNS HERE IF NOT POSSIBLE TO ALLOCATE PAGES
; ... ;RETURNS HERE WITH T1 = VIRTUAL ADDRESS OF PAGES ALLOCATED
;MUST BE CALLED IN SECTION 1 IF ALLOCATING NZS SPACE
CREMNS::
JUMPE R,CREFSP ;IF (R) = 0, ALLOCATE A PAGE OF FUNNY SPACE
PUSHJ P,SAVE4## ;SAVE WORKING ACS
MOVE P1,T2 ;SAVE NUMBER OF PAGES REQUESTED
;VERIFY THAT ALLOCATING A PHYSICAL PAGE WON'T PREVENT ANY JOB FROM BEING SWAPPED
; IN AND ADJUST CORMAX IF NEED BE TO KEEP ANY JOB FROM GETTING TO BIG AFTER A PAGE
; IS ALLOCATED. ACCOUNT FOR SECTION MAP IF IT MUST BE ALLOCATED.
; INSERT CODE HERE
IFN FTXMON,<
MOVE T1,R ;SECTION TO ALLOCATE FROM
ADD T1,.CPEPT## ;ADDRESS OF THE EPT
SKIPE T2,SECTAB(T1) ;SECTION ALREADY EXIST?
JRST CREMN1 ;YES, JUST FIND THE FREE PAGES
;HERE WHEN A PAGE MUST BE ALLOCATED FOR A SECTION MAP
MOVEI T3,1 ;ALLOCATE 1 PAGE
PUSHJ P,GETPHP ;GET A PAGE OF PHYSICAL MEMORY
MOVE T2,T1 ;PAGE NUMBER
MOVE T1,R ;SECTION NUMBER
MOVEM T2,SPTCOM##-<(MS.FMD)>(T1) ;STORE IN SPT SLOT
ADDI T1,SECTAB ;WHERE TO STORE
PUSHJ P,STMAPS ;STORE PAGE NUMBER IN THE SECTION MAP
>;END IFN FTXMON
IFE FTXMON,<
MOVE T2,.CPEPT## ;EPT FOR THIS CPU
MOVE T2,SECTAB+0(T2) ;CURRENT S0 MAP
>;END IFE FTXMON
CREMN1: HRLI T2,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.COR)
MOVEM T2,.UPMP+.UMTMP
CLRPGT (0)
PUSH P,T2 ;SAVE FOR LATER
MOVSI T1,-<HLGPNO+2> ;MAX # OF SLOTS+1 (FOR PRE-INCREMENT)
CREMN2: HRRZ P2,T1 ;FIRST FREE SLOT SEEN
MOVEI T3,0 ;NUMBER OF CONTIGUOUS FREE SLOTS SEEN SO FAR
CREMN3: CAIL T3,(P1) ;FOUND ENOUGH FREE SLOTS YET?
JRST CREMN4 ;YES
AOBJP T1,TPOPJ## ;SECTION FULL, CAN'T ALLOCATE HERE
SKIPE .TEMP-1(T1) ;NEXT SLOT FREE?
JRST CREMN2 ;NO, LOOK HIGHER UP
AOJA T3,CREMN3 ;YES, SEE IF ENOUGH SLOTS HAVE BEEN FOUND
CREMN4: MOVE T3,P1 ;NUMBER OF PAGES TO ALLOCATE
PUSHJ P,GETPHP ;GET THE PAGES
POP P,.UPMP+.UMTMP ;MAKE THE SECTION MAP ADDRESSABLE
CLRPGT (0) ;FLUSH PAGING MEMORY
MOVE P3,P2 ;STARTING MAP SLOT (NEEDED FOR VIRTUAL ADDRESS)
HRRZ P4,T1 ;FIRST PHYSICAL PAGE ALLOCATED
CREMN5: MOVE T2,P4 ;PAGE NUMBER TO T2
MOVEI T1,.TEMP(P2) ;WHERE TO STORE IN THE SECTION MAP
PUSHJ P,STMAPE ;MAKE THE MAP ENTRY
SSX P4,MS.MEM ;PAGTAB SECTION
HRRZ P4,PAGTAB(P4) ;NEXT PAGTAB ENTRY
TRNE P4,-1 ;LAST PAGE?
AOJA P2,CREMN5 ;NO, LOOP MAKING ENTRIES FOR EVERY PAGE ALLOCATED
CLRPGT (0) ;CLEAR PAGING MEMORY
MOVE T1,P3 ;FIRST SLOT ALLOCATED
LSH T1,P2WLSH## ;ADDRESS WITHIN THE SECTION
SSXE T1,(R) ;FULL VIRTUAL ADDRESS OF CORE ALLOCATED
JRST CPOPJ1## ;GIVE WON RETURN
;ROUTINE TO CREATE A PAGE IN FUNNY SPACE
; CALL WITH T1=BITS,,HEADER
;RETURNS CPOPJ IF NONE AVAILABLE, CPOPJ1 IF AVAILABLE, T1 = VIRTUAL ADDRESS OF PAGE
CREFSP::
PUSH P,T1 ;SAVE BITS,,HEADER
MOVEI T1,.MCFV/PAGSIZ## ;VIRTUAL PAGE NUMBER OF FIRST FUNNY PAGE
CREFS1: PUSHJ P,TSWST ;DOES IT EXIST
JRST [MOVE T2,-1(P) ;NO, CHECK IF RESTRICTED PAGE
CAIN T1,<<.MCFV+NWMCP>/PAGSIZ##>-1 ;THE NEXT TO THE LAST FUNNY PAGE
TLNE T2,200000 ;YES, ARE WE ALLOWED TO GIVE IT OUT
JRST CREFS2 ;OK TO CREATE THIS PAGE
AOJA T1,.+1] ;CANNOT GIVE IT OUT, STOP LOOP
CAIGE T1,<.MCFV+NWMCP>/PAGSIZ## ;OFF THE END OF FUNNY SPACE
AOJA T1,CREFS1 ;LOOK FOR A NON-EXISTANT PAGE
JRST TPOPJ## ;NONE AVAILABLE
CREFS2: MOVEI T2,1 ;NUMBER OF PAGES TO CREATE
PUSH P,T1 ;SAVE VIRTUAL PAGE NUMBER
IFN FTKL10,<
MOVE T3,-1(P) ;GET SIGN BIT FOR UNCACHED
>
PUSHJ P,CREMPG ;CREATE THE PAGE
JRST TTPOPJ## ;FAIL IF NO VIRTUAL SPACE
POP P,T1 ;RESTORE VIRTUAL PAGE NUMBER
SUBI T1,<.MCFV-.FPMC>/PAGSIZ## ;CONVERT TO PER-PROCESS ADDRESS
LSH T1,P2WLSH## ;...
JRST T2POJ1## ;POP OFF JUNK AND GIVE GOTIT RETURN
;SUBROUTINE TO GET PHYSICAL PAGES OF MEMORY
; CALL WITH T3 = NUMBER OF PAGES TO ALLOCATE
; CALLERS RESPONSABILITY TO CHECK TO SEE IF ALLOCATING PAGES REQUESTED WILL
; LEAVE ENOUGH ROOM FOR THE BIGGEST JOB TO SWAP IN
; RETURNS WITH T1 = FIRST PAGE ALLOCATED
; MUST OWN THE MM BEFORE CALL
GETPHP::PUSHJ P,FRDCR## ;MAKE ROOM IF POSSIBLE
CAIA ;DIDN'T MAKE IT, WAIT A WHILE
JRST GETPH1 ;PAGES ARE AVAILABLE, ALLOCATE THEM
PUSHJ P,UUOLVL## ;IF NOT AT UUO LEVEL, STOP (CALLER IS CONFUSED)
STOPCD CPOPJ##,DEBUG,NUL ;++NOT AT UUO LEVEL
IFN FTMP,<
PUSHJ P,DWNMM## ;RETURN MM BEFORE SLEEPING
>
PUSH P,T3 ;SAVE NUMBER OF PAGES REQUESTED
MOVEI T1,1 ;SLEEP A TIC
IFN FTXMON,<
PUSHJ P,SLEEPF## ;ZZZZZZ
>
IFE FTXMON,<
RGCALL SLEEPF##
>
IFN FTMP,<
PUSHJ P,UPMM## ;GET THE MM BACK
>
POP P,T3 ;RESTORE SIZE OF REQUEST
JRST GETPHP ;AND TRY AGAIN
GETPH1: SE1ENT ;ENTER SECTION 1
MOVE T2,T3 ;NUMBER OF PAGES TO GET
LSH T3,P2WLSH## ;NUMBER OF WORDS BEING ALLOCATED
MOVNS T3 ;MAKE NEGATIVE
ADDM T3,MAXMAX## ;DECREASE MAX CORMAX
ADDB T3,RMCMAX## ;ADJUST REAL CORMAX
CAMGE T3,CORMAX## ;LOWER THAN CORMAX?
MOVEM T3,CORMAX## ;YES, DECREASE CORMAX AS WELL
PUSHJ P,GTPAGS## ;GET THE NEEDED PAGES
MOVE T3,T1 ;RETURN FIRST PAGE ALLOCATED IN T1
SSX T3,MS.MEM ;PAGTAB SECTION
GETPH2: HRRZ T2,T3 ;PAGE NUMBER OF PAGE TO BE ZEROED
PUSHJ P,ZPAGE ;ZERO THE PAGE
MOVSI T2,MONTRB+TNCSHB;MARK THIS PAGE AS A MONITOR PAGE
IORB T2,PAGTAB(T3) ;LITE THE BIT AND GET NEXT PAGE NUMBER
TRNN T2,-1 ;LAST PAGE ALLOCATED?
JRST GETPH3 ;SET UP PT2TAB AND RETURN
HRR T3,T2 ;NO, NEXT PAGE NUMBER
JRST GETPH2 ;LOOP TO MARK AND ZERO ALL PAGES ALLOCATED
GETPH3: HRRZ T2,LMPAG## ;GET LAST ALLOCATED MONITOR PAGE
HRRZM T3,LMPAG## ;SET LAST PAGE ALLOCATED
SSX T2,MS.MEM ;PAGTAB SECTION
HRRM T1,PAGTAB(T2) ;SET FORWARD LINK
HRRZM T2,@[IW MS.MEM,PT2TAB(T1)] ;SET BACK LINK
POPJ P,
;SUBROUTINE TO STORE A PAGE NUMBER IN A MAP (CAUSES ALL CPUS TO SEE NEW MAPPING)
; ENTER AT STMAPS TO STORE IN SECTION TABLE, STMAPE TO STORE IN SECTION MAP
;CALL WITH T1= MAP OFFSET, T2 = NEW PHYSICAL PAGE # (OR ZERO IF
;CLEARING)
IFN FTXMON,<
STMAPS: TLOA T1,400000 ;REMEMBER ENTRY POINT
>
STMAPE: TLZ T1,400000 ;REMEMBER ENTRY POINT
PUSHJ P,SAVE4## ;SAVE ACS
IFN FTXMON,<
SKIPGE T1 ;STORING SECTION POINTER?
SKIPA P2,[<POINT 36,(P4),35>] ;YES, BYTE POINTER TO EPT INDEXED BY .CPEPT
>
MOVSI P2,(POINT 36,0,35) ;BYTE POINTER TO STORE IN SECTION MAP
SKIPN P3,T2 ;IF ZERO, STORE A ZERO
JRST STMAP1
HRLI P3,(<PM.DCD>B2+PM.WRT+PM.CSH) ;ACCESSIBLE, WRITABLE, CACHED
IOR P3,.CPKPM## ;ALSO LITE "KEEP ME" IF THERE IS AN MCA25
HRRI P2,(T1) ;OFFSET INTO SECTION TABLE OR MAP
IFN FTPEEKSPY,<
SKIPL T1 ;SECTION POINTER?
TLO P3,(PM.PUB) ;NO, PAGES MUST BE PUBLIC FOR SPYING
>
IFN FTMP,<
JUMPL T1,STMAP1 ;SECTION POINTERS ALWAYS HAVE CACHE BIT ON
PUSHJ P,MLSCSH## ;MONITOR LOW SEGMENT CACHED?
TLZ P3,(PM.CSH) ;NO, CACHE MUST BE OFF
>
STMAP1:
MOVEI T1,STMPEC## ;ROUTINE TO STORE ENTRY IN ALL CPU'S MAPS
PUSHJ P,UUOLVL## ;MM AND SLEEPING (WAITING) ARE THE CALLER'S
S0JRST CPUAPP## ; RESPONSIBILITY IF NOT AT UUO LEVEL
IFN FTMP,<
PUSHJ P,DIFMM## ;GIVE UP THE MM IF OWNED SINCE STMPEC MAY SLEEP
>
S0PSHJ CPUAPP## ; AND INSURE THAT ALL CPUS SEE THE NEW MAPPING
; DO IT
IFN FTMP,<
PJRST UIFMM## ;RESTORE THE MM IF OWNED UPON ENTRY
>
IFE FTMP,<
POPJ P, ;RETURN
>
;SUBROUTINE TO ALLOCATE FUNNY SPACE IN WORDS RATHER THAT CHUNKS
; T2/ NUMBER OF WORDS DESIRED
; PUSHJ P,GTFWDC ;GET FUNNY WORDS, CACHED
; -OR-
; PUSHJ P,GTFWDU ;GET FUNNY WORDS, UNCACHED
;RETURN CPOPJ IF SPACE IS NOT AVAILABLE
; CPOPJ1 IF IT IS, T1 = ADDRESS
GFWDCH::HRRZS .USFCU ;CLEAR LARGEST HOLE
PUSHJ P,GTFWDC ;GET THE SPACE
CAIA ;NOT AVAILABLE
JRST CPOPJ1## ;GOT IT
HLRZ T2,.USFCU ;GET SIZE OF BIGGEST HOLE
POPJ P, ; AND FAIL
IFN FTKL10,<
GFWDUD::SKIPA T1,[GTFWDU] ;TRY REGULAR ENTRY POINTS FIRST
GFWDCD::MOVEI T1,GTFWDC ;...
PUSHJ P,(T1) ;CALL CORRECT ROUTINE
>
IFE FTKL10,<
GFWDUD::
GFWDCD::PUSHJ P,GTFWDC ;ALL THE SAME ON KI/KS
>
CAIA ;NO FUNNY SPACE AVAILABLE
JRST CPOPJ1## ;GIVE GOOD RETURN
MOVE T1,[600000,,.USFCD] ;TRY RESTRICTED SPACE
JRST GTFWD1 ;AND HOPE THAT THERE IS SOME
GTFWDU::
IFN FTKL10,<
SKIPE [CPUN##-1] ;ALL SPACE IS CACHED IF ONLY 1
SKIPA T1,[400000,,.USFCU] ;ELSE GET UNCACHED HEADER
>
GTFWDC::MOVEI T1,.USFCC ;POINT TO CACHED LIST HEAD
GTFWD1: PUSHJ P,SAVR## ;SAVE R
MOVEI R,(MDSEC0) ;SECTION 0 SPACE (REALLY FUNNY SPACE)
JRST GTFWD2 ;JOIN COMMON CODE
IFE FTXMON,<
GFWNZD::SKIPA T1,[400000,,(MS.DCN)] ;"DECNET" CORE FOR THE KS
GFWNZO::SKIPA T1,[400000,,0] ;"ONCE-ONLY" CORE FOR THE KS
PUSHJ P,SVDCN## ;IF DECNET, POINT TO DECNET CORE
>
IFN FTXMON,<
GFWNZ2::SKIPA T1,[400000,,(MS.SAT)] ;SECTION 2 CORE
GFWNZD:: ;(NAME FOR DECNET TO CALL)
GFWNZS::MOVE T1,[400000,,(MS.MEM)] ;GENERAL NZS SPACE
SE1ENT ;MUST BE IN SECTION 1 TO ALLOCATE NZS SPACE
>
IFN FTMP,<
PUSHJ P,MMOWN## ;WE OWN MM ALREADY?
PUSHJ P,GGVMM## ;NO--MUST HAVE THE MM TO LINK THROUGH FREE CORE CHAINS
>
PUSHJ P,SAVR## ;SAVE R
MOVE R,T1 ;COPY SECTION # TO R
MOVE T1,NZSFCH##(R) ;HEADER FOR SPACE (ALWAYS UNCACHED)
GTFWD2: PUSH P,T1 ;SAVE HEAD (FLAG ACTUALLY)
GTFWD3:
IFE FTXMON,<
MOVEI T3,(T1) ;REMEMBER LINK
>
IFN FTXMON,<
MOVE T3,T1 ;REMEMBER LINK
SKIPE R ;SECTION ZERO ALWAYS STORES SECTION
CAME T3,NZSFCH##(R) ;IF NOT THE FIRST TIME IN NON-ZERO SECTION
SSXE T1,(R) ; SET SECTION INDEX TO FUNNY SPACE SECTION
>
HLL T3,T1 ;SET PREDECESSOR SECTION
JUMPE R,GTFWD4 ;NON-ZERO SECTION HAS END POINTER
CAMN T1,NZSFCE##(R) ;THIS LAST BLOCK?
JRST GTFWD7 ;YES
HRRZ T1,(T1) ;POINT TO NEXT BLOCK
JRST GTFWD5
GTFWD4: HRRZ T1,0(T1) ;T1 = CURRENT CHUNK ADDRESS
JUMPE T1,GTFWD7 ;IF 0, NO HOLE AVAILABLE, GET SOME MORE
GTFWD5: SSXE T1,(R) ;ADDRESS CORRECT SECTION
HLRZ T4,0(T1) ;SIZE OF THIS HOLE
CAIGE T4,(T2) ;LARGE ENOUGH FOR REQUEST
JRST [JUMPN R,GTFWD3 ;NO BIGGEST HOLE IN NZS SPACE
HRLZ T4,T4 ;NO, MOVE SIZE OF THIS HOLE
CAMLE T4,.USFCU ;BIGGEST YET
HLLM T4,.USFCU ;YES, REMEMBER FOR TMPCOR
JRST GTFWD3] ; AND LOOK AT THE NEXT
MOVEM T1,(P) ;SAVE CHUNK ADDRESS
CAIN T4,(T2) ;AN EXACT SIZE MATCH
JRST [HRR T4,0(T1) ;YES, GET POINTER TO NEXT
HRRM T4,0(T3) ;RE-LINK PREVIOUS
JUMPE R,TPOPJ1##
JRST GTFWD6] ;CHECK IF THIS WAS LAST
HRL T4,0(T1) ;GET LINK TO NEXT CHUNK
ADDI T1,(T2) ;ADDRESS OF REMAINDER THIS CHUNK
HRRM T1,0(T3) ;STORE LINK TO REMAINDER
SUBI T4,(T2) ;SIZE OF REMAINDER
MOVSM T4,0(T1) ;STORE NEW LENGTH,OLD LINK IN REMAINDER
JUMPE R,TPOPJ1## ;SECTION ZERO, WE ARE DONE
MOVE T3,T1 ;NEW LAST BLOCK
GTFWD6: POP P,T1 ;RESTORE ADDRESS
CAMN T1,NZSFCE##(R) ;JUST ALLOCATE LAST BLOCK?
MOVEM T3,NZSFCE##(R) ;STORE IT
JRST CPOPJ1## ;DONE
GTFWD7: PUSH P,T2 ;SAVE AMOUNT REQUESTED
MOVE T1,-1(P) ;BITS,,HEADER
MOVEI T2,1 ;ALWAYS CREATE ONLY 1 PAGE
PUSH P,R ;SAVE R
PUSHJ P,CREMNS ;CREATE A PAGE IN FUNNY SPACE OR NON-ZERO SECTION
JRST GTFWD8
POP P,R
JRST GTFWD9 ;A WINNER
GTFWD8: POP P,R
IFN FTKL10,<
POP P,T2 ;RESTORE AMOUNT REQUESTED
POP P,T1 ;RESTORE HEADER USED
SKIPE [CPUN##-1] ;ONLY ONE TRY IF ALL IS CACHED
JUMPGE T1,GTFWDU ;TRY FOR UNCACHED SPACE IF NO CACHED
POPJ P, ;ELSE OUT OF FUNNY SPACE
>
IFE FTKL10,<JRST TTPOPJ##> ;ONLY 1 TRY ON KI/KS
GTFWD9: POP P,T4 ;RESTORE AMOUNT REQUESTED
POP P,T3 ;RESTORE FREE SPACE HEADER AND FLAG
MOVEI T2,PAGSIZ## ;AMOUNT JUST ACQUIRED
CAILE T4,PAGSIZ## ;REQUESTING MORE THAN 1 PAGE
JRST GTFW10 ;YES, MERGE THIS PAGE AND TRY AGAIN
SUB T2,T4 ;AMOUNT LEFT OVER AFTER SATISFYING REQUEST
JUMPE T2,CPOPJ1## ;EXACT AMOUNT, RETURN NOW
PUSH P,T1 ;SAVE ADDRESS OF NEWLY ACQUIRED CHUNK
ADD T1,T4 ;ADDRESS OF RESIDUE
EXCH T1,T2 ;WANT ARGS IN OTHER ORDER
PUSHJ P,GVFWD3 ;GIVE IT BACK (T3 ALREADY SET UP)
JRST TPOPJ1## ;AND GIVE GOOD RETURN TO CALLER
GTFW10: PUSH P,T3 ;SAVE HEADER AND FLAGS
PUSH P,T4 ;SAVE ORIGINAL AMOUNT REQUESTED
TLO T3,100000 ;LIGHT BIT SAYING NOT TO RETURN FULL PAGES
EXCH T1,T2 ;WANT LENGTH AND ADDRESS IN THE OTHER ORDER
PUSHJ P,GVFWD3 ;RETURN FULL PAGE TO THE FREE LIST
POP P,T2 ;RESTORE ORIGINAL WORDS REQUESTED
POP P,T1 ;RESTORE FREE SPACE HEADER AND FLAGS
JRST GTFWD2 ;AND TRY TO SATISFY THE REQUEST NOW
;SUBROUTINE TO RETURN WORDS ACQUIRED BY GTFWDC, GTFWDU, OR GFWNZS
;CALL: T1/ WORDS TO RETURN
; T2/ ADDRESS
; PUSHJ P,GVFWDS
IFE FTXMON,<
GVFNZD::PUSHJ P,SAVR## ;SAVE R
MOVEI R,(MS.DCN) ;FLAG DECNET CONTEXT
SETZ T4, ;BUT STILL S0
PUSHJ P,SVDCN## ;MAP DECNET
JRST GVFWDC
GVFNZO::
> ;END IFE FTXMON
IFN FTXMON,<
GVFNZD::
>
GVFWDS::PUSHJ P,SAVR## ;SAVE TEMP USED FOR SECTION INDEX
GVFWD1:
IFN FTXMON,<
MOVEI R,(MDSEC0) ;ASSUME WE ARE TALKING ABOUT SECTION 0 SPACE
HLRZ T4,T2 ;SECTION NUMBER
>
IFE FTXMON,<
SETZB R,T4 ;ONCE ONLY OR FUNNY SPACE IS SECTION 0
>
CAML T2,LOCORE## ;ONCE-ONLY CORE?
IFN FTXMON,<
TLZE T2,-1 ;NZS SPACE?
TRNA ;ONCE ONLY OR NZS
>
JRST GVFWD2 ;NO, SECTION ZERO FUNNY SPACE
GVFWDC: CAIGE T4,NZSFCL## ;KNOW ABOUT THIS SECTION?
SKIPN T3,NZSFCH##(T4) ;?
STOPCD CPOPJ##,DEBUG,RWS, ;++RETURNING SPACE TO WRONG SECTION
IFN FTXMON,<
SKIPE R,T4 ;GET SECTION #
SE1ENT ;IF RETURNING NZS CORE
TLO R,400000 ;FLAG NOT FUNNY SPACE
>
IFE FTXMON,<
MOVSI R,400000 ;FLAG NOT FUNNY SPACE BUT STILL SECTION ZERO
>
IFN FTMP,<
PUSHJ P,MMOWN## ;WE OWN MM ALREADY?
PUSHJ P,GGVMM## ;NO--MUST INTERLOCK CHAIN CHASING
>
MOVE T3,NZSFCH##(R) ;GET PROPER HEADER
JRST GVFWD3 ;JOIN COMMON CODE
GVFWD2: MOVE T4,T2 ;COPY ADDRESS OF PIECE
LSH T4,W2PLSH## ;CONVERT TO PAGE NUMBER
CAIGE T4,.LPMC/PAGSIZ## ;RANGE CHECK IT
CAIGE T4,.FPMC/PAGSIZ## ;...
STOPCD CPOPJ##,DEBUG,PFR, ;++PIECE OUT OF FREE RANGE
CAIN T4,<.LPMC/PAGSIZ##>-1 ;IS THIS THE RESTRICTED PAGE
JRST [MOVE T3,[600000,,.USFCD] ;YES, USE THIS HEADER
JRST GVFWD3] ;ENTER COMMON CODE
ADDI T4,<.MCFV-.FPMC>/PAGSIZ## ;CONVERT TO VIRTUAL ADDRESS
PUSHJ P,GTPM4 ;GET PAGE MAP ENTRY
SKIPN T4
STOPCD CPOPJ##,DEBUG,FPE, ;++FUNNY PAGE MUST EXIST
IFN FTKL10,<
TLNN T4,(PM.CSH) ;A CACHED PAGE
SKIPA T3,[400000,,.USFCU] ;GET UNCACHED LIST HEADER
>
MOVEI T3,.USFCC ;GET CACHED LIST HEADER
GVFWD3: SPUSH T3 ;PUSH LEFT HALF
TLZ T3,100000 ;CLEAR POSSIBLE FLAG.
TLNE R,400000 ;FUNNY SPACE?
CAME T3,NZSFCH##(R) ;IF NOT THE FIRST TIME
IFN FTXMON,<
SSXE T3,(R) ; RELOCATE TO DATA SECTION
>
IFE FTXMON,<
HRRZS T3 ;ALL IS REALLY S0
>
JUMPE R,GVFWD4 ;ZERO TERMINATION FOR SECTION ZERO
CAMN T3,NZSFCE##(R) ;ELSE IS THIS LAST?
JRST [SPOP T3
JRST GVFWD5] ;YES
GVFWD4: HRRZ T4,0(T3) ;GET FIRST CHUNK IN FREE LIST
SPOP T3 ;RESTORE LEFT HALF
TLNN R,400000 ;FUNNY SPACE?
JUMPE T4,GVFWD5 ;SECTION ZERO IS ZERO TERMINATED
CAIN T4,(T2) ;ALREADY IN FREE LIST
STOPCD CPOPJ##,DEBUG,PFL ;++PIECE ON FREE LIST
CAIL T4,(T2) ;KEEP CHUNKS IN ADDRESS ORDER
JRST GVFWD5 ;IT GOES HERE
HRR T3,T4 ;REMEMBER LINK
JRST GVFWD3 ;AND LOOK AT THE NEXT
GVFWD5: PUSH P,T3 ;SAVE PREVIOUS (AND FLAGS)
MOVEI T4,(T3) ;ADDRESS OF PREVIOUS
JUMPL R,GVFWD6 ;ALWAYS COMBINE NZS
CAIE T4,.USFCD ;RESTRICTED SPACE HEADER
CAIN T4,.USFCC ;OR CACHED HEADER THE PREVIOUS?
JRST GVFWD8 ;YES, CANNOT COMBINE (LH OF HDR IS NOT A LENGTH)
JUMPE R,GVFWD7 ;SKIP SOME IF FUNNY SPACE
GVFWD6: HLL T4,NZSFCH##(R) ;COMPARE WITH NZS HEADER FOR RIGHT SECTION
IFN FTKL10,<
CAME T4,NZSFCH##(R)
TLZA T4,-1 ;CLEAR LEFT HALF, PRESERVE NON-SKIP
TLZA T4,-1 ;CLEAR LEFT HALF PRESERVE SKIP
GVFWD7: CAIN T4,.USFCU ;UNCACHED HEADER
>
IFE FTKL10,<
CAMN T4,NZSFCH##(R)
TLZA T4,-1 ;CLEAR LEFT HALF, PRESERVE NON-SKIP
TLZA T4,-1 ;CLEAR LEFT HALF PRESERVE SKIP
>
JRST GVFWD8 ;IF NZS HEADER, CANNOT COMBINE
IFE FTKL10,<
GVFWD7:
>
IFE FTXMON,<
TLZ T3,-1 ;CLEAR JUNK
>
IFN FTXMON,<
SSXE T3,(R) ;PROPER SECTION FOR REFERENCES BELOW
>
HLRZ T4,0(T3) ;LENGTH OF PREVIOUS PIECE
ADDI T4,(T3) ;FIRST WORD NOT IN PREVIOUS CHUNK
CAILE T4,(T2) ;BETTER BE
STOPCD TPOPJ##,DEBUG,FOP, ;++FUNNY ADDRESS OVERLAPS PREVIOUS
CAIE T4,(T2) ;PIECES CONTIGUOUS
JRST GVFWD8 ;NO, CANNOT COMBINE
MOVEI T2,(T3) ;YES, ADDRESS OF LARGER CHUNK
HLRZ T4,0(T3) ;SIZE OF PREVIOUS
ADD T1,T4 ;SIZE OF COMBINED PIECES
GVFWD8:
IFN FTXMON,<
SSXE T2,(R) ;SET FOR PROPER SECTION ADDRESSING
>
IFE FTXMON,<
HRRZS T2
>
HRLM T1,0(T2) ;SIZE OF THIS CHUNK
HRRZ T4,0(T3) ;PREVIOUS LINK TO NEXT
HRRM T4,0(T2) ;LINK THIS TO NEXT
CAME T2,T3 ;PREV=THIS (CONCATENATION)
HRRM T2,0(T3) ;NO, LINK PREV TO THIS
JUMPE R,GVFWD9
CAMN T3,NZSFCE##(R) ;LAST?
MOVEM T2,NZSFCE##(R) ;WE ARE NOW LAST
GVFWD9: HRRZ T3,T2 ;ADDRESS OF CURRENT
ADD T3,T1 ;+SIZE OF CURRENT
SKIPN T4 ;WAS LAST ADDRESS ZERO?
JUMPE R,GVFW10 ;YES, END OF LIST IF SECTION ZERO
CAMN T2,NZSFCE##(R) ;ARE WE NOW LAST?
JRST GVFW10 ;YES, THERE IS NO NEXT
CAILE T3,(T4) ;BETTER BE
STOPCD .,JOB,FON, ;++FUNNY ADDRESS OVERLAPS NEXT
CAIE T3,(T4) ;BUTT UP AGAINST NEXT ONE
JRST GVFW10 ;NO, CANNOT COMBINE THAT SIDE
HRLZS T1 ;SIZE OF CURRENT,,0
IFN FTXMON,<
SSXE T4,(R) ;PROPER SECTION (STILL CLEAR IF IFE FTXMON)
>
ADD T1,0(T4) ;COMBINED SIZE,,NEXT'S LINK
MOVEM T1,0(T2) ;STORE NEW INFO
HLRZS T1 ;ISOLATE SIZE OF NEW, LARGER PIECE
JUMPE R,GVFW10 ;NOTHING MORE IF SECTION 0
CAMN T4,NZSFCE##(R) ;WAS THIS LAST?
MOVEM T2,NZSFCE##(R) ;WE ARE LAST NOW
GVFW10: POP P,T3 ;RESTORE ORIGINAL PREVIOUS (AND FLAGS)
TLNE T3,100000 ;SUPRESS RECLAMATION OF FULL PAGES
POPJ P, ;YES, ALL DONE NOW
TLCE R,400000 ;FUNNY SPACE?
JUMPE R,CPOPJ ;NO, CAN'T RECLAIM ONCE-ONLY CORE
TLC R,400000 ;PUT BIT BACK RIGHT
PUSHJ P,INTLVL## ;ONLY RECLAIM AT UUO LEVEL
CAIGE T1,PAGSIZ## ;CAN WE RECLAIM A FULL CHUNK
POPJ P, ;NO, RETURN NOW
PUSHJ P,SAVE4## ;YES, SAVE SOME REGS
DMOVE P1,T1 ;SAVE LENGTH, ADDRESS OF PIECE
TRZ T1,PAGSIZ##-1 ;MAX WORDS THAT CAN BE RETURNED
ADDI T2,PAGSIZ##-1 ;AND ROUND ADDRESS TO CHUNK BOUNDRY
TRZ T2,PAGSIZ##-1 ;...
MOVE P4,P2 ;ORIGINAL ADDRESS
ADD P4,P1 ;P4 = FIRST WORD NOT IN PIECE
MOVE T4,T2 ;START OF CHUNK THAT CAN BE RETURNED
ADD T4,T1 ;T4 = FIRST WORD THAT WON'T BE RETURNED
GVFW11: CAMGE P4,T4 ;RETURNABLE SPACE COMPLETELY CONTAINED
JRST [SUBI T1,PAGSIZ## ;NO, LESS WORDS TO RETURN
JUMPE T1,CPOPJ## ;"AND THEN THERE WERE NONE"
SUBI T4,PAGSIZ## ;ADJUST ENDING ADDRESS ( +1 )
JRST GVFW11] ;AND LOOK AT THE SMALLER PIECE
MOVEI P3,(P2) ;GET RIGHT HALF
CAIE P3,(T3) ;CURRENT = PREVIOUS (CONCATENTATION)
JRST [JUMPE R,GVFW15 ;GO IF FUNNY SPACE
CAME T3,NZSFCH##(R) ;AT BEGINNING?
IFN FTMP,<
SSXE T3,(R) ;NO, RELOCATE
>
IFE FTMP,<
HRRZS T3
>
JRST GVFW15] ;AND UNLINK PIECE
JUMPE R,GVFW12 ;SECTION ZERO
HRR T3,NZSFCH##(R) ;ASSUME NZS CORE BEING RETURNED
JRST GVFW14 ;NON-ZERO SECTION
GVFW12: HRRI T3,.USFCC ;YES, MUST FIND NEW PREVIOUS
IFN FTKL10,<
SKIPGE T3 ;CACHED OR UNCACHED HEADER NEEDED
HRRI T3,.USFCU ;UNCACHED
>
TLNE T3,200000 ;RESTRICTED SPACE
HRRI T3,.USFCD ;YES
GVFW13:
IFN FTXMON,<
SSXE T3,(R) ;SET TO ADDRESS PROPER SECTION
>
IFE FTXMON,<
HRRZS T3
>
GVFW14: HRRZ P3,0(T3) ;GET LINK TO NEXT
CAIN P3,(P2) ;POINT TO THIS ONE
JRST GVFW15 ;YES, T3 = NEW PREVIOUS
HRR T3,P3 ;COPY PREVIOUS
JRST GVFW13 ;AND GO LOOK AGAIN
GVFW15: SPUSH P2 ;SAVE LEFT HALF
IFN FTXMON,<
SSXE P2,(R) ;SET PROPER SECTION
>
IFE FTXMON,<
HRRZS P2
>
HRRZ P3,0(P2) ;GET ADDRESS OF NEXT CHUNK
JUMPE R,GVFW16 ;SECTION ZERO
CAMN P2,NZSFCE##(R) ;WERE WE THE LAST?
MOVEM T3,NZSFCE##(R) ;PREDECESSOR NOW IS
GVFW16: SPOP P2 ;RESTORE LEFT HALF
HRRM P3,0(T3) ;DE-LINK THE LARGER PIECE
MOVE P1,T2 ;START OF REMOVED PIECE
SUB P1,P2 ;COMPUTE LENGTH OF L.H. EXCESS
MOVE P3,P4 ;1ST WORD NOT IN THE PIECE
SUB P3,T4 ;COMPUTE LENGTH OF R.H. EXCESS
MOVE P4,T4 ;AND WHERE IT STARTS
PUSH P,P1 ;SAVE REMAINDER INFORMATION
PUSH P,P2 ;...
DMOVE P1,T1 ;COPY AMOUNT TO RETURN
LSHC P1,W2PLSH## ;P1 = NUMBER TO RETURN, P2 = PAGE NUMBER OF FIRST
GVFW17: MOVE J,.USJOB ;GET JOB NUMBER WHO OWNS THESE PAGES
PUSHJ P,DLTMPG ;DELTETE THIS PAGE
AOS P2 ;STEP TO NEXT PAGE TO RETURN
SOJG P1,GVFW17 ;GET THEM ALL
CLRPGT (0) ;WE HAVE CHANGED THE MAP
POP P,T2 ;RESTORE LEFT HAND REMAINDER INFORMATION
POP P,T1 ;...
SKIPE T1 ;WAS THERE ANY
PUSHJ P,GVFWD1 ;YES, GIVE IT BACK
JUMPE P3,CPOPJ## ;DONE IF NO RIGHT HAND REMAINDER
DMOVE T1,P3 ;GET LENGTH AND ADDRESS OF IT
JRST GVFWD1 ;GIVE IT BACK AND RETURN
;SUBROUTINE TO RETURN A FUNNY PAGE, MUST BE A SUBROUTINE SO THAT
; IT CAN CALL THE COROUTINE GGVMM
; CALL WITH P2 = VIRTUAL PAGE NUMBER
DLTMPG: MOVE T1,P2 ;IN CASE A NZS PAGE
PJUMPN R,DNZSPG ;JUMP IF A NZS PAGE
IFN FTMP,<
PUSHJ P,GGVMM## ;GET MM RESOURCE SINCE DIDDLING CORE ALLOCATION TABLES
; WILL BE RETURNED UPON EXIT
>
DLTFSP::
MOVN T1,[MCPCNT] ;DECREMENT COUNT OF FUNNY PAGES OWNED
ADDM T1,JBTPDB##(J) ;...
MOVEI T1,<.MCFV-.FPMC>/PAGSIZ##(P2) ;CONVERT TO VIRTUAL PAGE NUMBER
PUSHJ P,TSWST ;GET BIT FOR WSBTAB
STOPCD .+1,DEBUG,PNW, ;++PAGE NOT IN WORKING SET
ANDCAM T2,(T4) ;NO LONGER IN WORKING SET
PUSHJ P,GTPME ;GET PAGE MAP ENTRY FOR IT
SETZM (T4) ;ZAP THE PAGE MAP ENTRY
TLZ T2,(PM.NAD) ;DOWN TO PHYSICAL PAGE NUMBER
PUSHJ P,LKPSF ;FIX UP PAGTAB
PJRST DLTPGC ;AND DELETE THE PAGE,
; RETURN MM RESOURCE AND RETURN TO CALLER
;SUBROUTINE TO RETURN A PAGE IN A NON-ZERO SECTION TO FREE CORE OR ONCE-ONLY CORE
; CALL WITH T1 = VIRTUAL PAGE NUMBER (MUST OWN THE MM RESOURCE)
;MUST BE IN SECTION 1
DNZSPG: LSHC T1,-^D9 ;ISOLATE SECTION NUMBER
LSH T2,-^D27 ;RIGHT JUSTIFY PAGE NUMBER
IFE FTXMON,<
MOVEI T1,0 ;MAKE SURE SECTION IS RIGHT
> ADD T1,.CPEPT## ;ADDRESS OF EPT + SECTION NUMBER
SKIPN T3,SECTAB(T1) ;GET ENTRY FROM SECTION MAP
STOPCD CPOPJ##,DEBUG,NXS, ;++NON-EXISTANT SECTION
MOVEM T3,.UPMP+.UMTMP ;MAKE THE SECTION MAP ADDRESSABLE
CLRPGT (0) ;MAKE NEW MAPPING VISABLE
MOVEI T1,.TEMP(T2) ;ADDRESS OF THE POINTER SLOT (FOR STMAPE)
SKIPN T2,.TEMP(T2) ;GET PAGE POINTER
STOPCD CPOPJ##,DEBUG,RNP, ;++RETURNING NON-EXISTANT PAGE
TLZ T2,(PM.NAD) ;ISOLATE PHYSICAL PAGE NUMBER
; SE1ENT ;(RIGHT NOW, DNZSPG IS ALWAYS CALLED HERE)
PUSH P,T1 ;SAVE MAP OFFSET
HRRZ T1,@[IW MS.MEM,PT2TAB(T2)]
CAMN T2,LMPAG## ;IS THIS THE LAST MONITOR PAGE?
HRRZM T1,LMPAG## ;YES, NEW LAST PAGE
PUSHJ P,LKPSF ;REMOVE PAGE FROM MONITOR'S CHAIN
PUSHJ P,DLTPGC ;RETURN THE PAGE TO FREE CORE
MOVEI T1,PAGSIZ## ;NUMBER OF WORDS BEING FREED
ADDM T1,MAXMAX## ;UPDATE MAXMAX TO REFLECT THAT
ADDM T1,RMCMAX## ;UPDATE REAL MAXIMUM FOR CORMAX
POP P,T1 ;RESTORE PAGE OFFSET
MOVEI T2,0 ;SET TO ZERO THE MAP SLOT
PJRST STMAPE ;ZERO THE MAP SLOT AND RETURN
SUBTTL COMCON INTERFACE WITH COMMAND DECODER
;PRIVILEGED COMMAND/UUO TO SET THE SYSTEM-WIDE VM LIMIT
SETVMX::PUSHJ P,CORLGL## ;GET CORE ARGUMENT
ADDI T2,1
LSH T2,W2PLSH## ;CONVERT TO PAGES
SETVM1::CAMLE T2,VIRTAL## ;BIGGER THAN VIRTAL?
MOVE T2,VIRTAL## ;YES, USE VIRTAL
CAMGE T2,VMTOTL## ;BIGGER THAN TOTAL VM NOW IN USE?
MOVE T2,VMTOTL## ;YES, USE CURRENT AMOUNT IN USE
MOVEM T2,VMCMAX## ;SAVE SYSTEM WIDE VM LIMIT
PJRST CPOPJ1## ;AND RETURN
;PRIVILEGED UUO TO SET THE ABSOLUTE PER-USER MAXIMA
SETUVL::HRR M,T2 ;LOC OF ARGUMENT
TLZ M,MXSECN ;(SETUUO IS LOCAL)
PUSHJ P,FLTSX ;MAKE SURE WONT FAULT
JRST ECOD0## ;PAGE-FAULT AT NON-UUO LEVEL????!!??
PUSHJ P,GETWDU## ;GET ARG
PUSHJ P,CHKLIM ;MAKE SURE VALUES ARE OK
JRST ECOD0## ;NOT - NON SKIP
SETVLM::
MOVEM T1,.PDMVL##(W) ;MVPL,,MPPL
SKIPN .PDCVL##(W) ;IF NOT ALREADY SET,
JRST SETUV2 ;SAVE AS CURRENT LIMITS TOO
PJRST CPOPJ1## ;AND GOOD RETURN
;NON-PRIVILEGED UUO TO SET INTERVAL FOR VIRTUAL-TIME INTERRUPT
SETVTM::PUSHJ P,FNDPDB## ;GET PDB FOR TARGET JOB
JRST ECOD0## ;CAN'T SET IF NO PDB
IMUL T2,TICSEC## ;CONVERT TO TICS-PER-INTERRUPT
IDIVI T2,^D1000
HRRZM T2,.PDTMC##(W) ;SAVE IN UPMP
HRRM T2,.PDTMI##(W)
PJRST CPOPJ1## ;AND RETURN
;SUBROUTINE TO CHECK CORE LIMITS
;ENTER T1=LIMITS
;EXIT CPOPJ IF TOO BIG, CPOPJ1 IF OK
;RETURNS T3=RH(T1) WITHOUT GUIDELINE BIT
CHKLIM: HLRZ T2,T1
HRRZ T3,T1
TRZ T3,400000 ;CLEAR LIMIT BIT
CAIG T2,<MXSECN+1>*<HLGPNO+1> ;OK?
CAILE T3,<MXSECN+1>*<HLGPNO+1>
POPJ P, ;NO, NON-SKIP
JUMPE T3,CPOPJ1## ;0 IS ALWAYS OK
CAIL T3,4 ;AT LEAST 4 PAGES?
PJRST CPOPJ1## ;YES, SKIP
TRZ T3,377777 ;CLEAR
TRO T3,4 ;MAKE IT FOUR PAGES
JRST CPOPJ1## ;SKIP RETURN
;NON-PRIVILEGED COMMAND TO SET CURRENT PER-USER LIMITS
SETUVC::SKIPA T1,[POINT 18,.PDMVL##(W),17]
SETUPC::MOVE T1,[POINT 18,.PDMVL##(W),35]
PUSHJ P,SAVE2## ;SAVE AN AC
MOVE P1,T1 ;SAVE POINTER TO MAX VALUE FOR THIS ARG
PUSHJ P,FNDPDB## ;GET PDB LOC
POPJ P, ;NONE-RETURN
MOVE T1,[-2,,[SIXBIT /GUIDEL/
SIXBIT /LIMIT/]]
PUSHJ P,TXTARG##
TDZA P2,P2
MOVE P2,T1
PUSHJ P,CORARG## ;GET THE CORE ARGUMENT
PJRST NOTENF##
ADDI T1,1 ;CONVERT TO PAGES
LSH T1,W2PLSH##
PUSHJ P,CHKLIM ;LEGAL?
PJRST COMERA##
LDB T2,P1 ;YES, GET MAX VALUE FOR THIS ARG
CAILE T1,(T2) ;TRYING TO SET IT TOO HIGH?
JRST COMERA## ;YES
HRRI P1,.PDCVL## ;NO, SET TO STORE NEW VALUE
DPB T1,P1 ;SAVE CURRENT LIMIT
TRNN T1,-1 ;SETTING LIMIT/GUIDELINE TO ZERO?
MOVEI P2,0 ;YES, CLEAR LIMIT BIT
TLNN P1,770000 ;PHYSICAL?
DPB P2,[POINT 1,.PDCVL##(W),18]
PJRST CPOPJ1## ;AND TAKE GOOD RETURN
;NON-PRIVILEGED UUO TO SET PER-USER CURRENT LIMITS
SETUV1::HRR M,T2 ;ADR OF ARGUMENT
TLZ M,MXSECN ;(SETUUO IS LOCAL)
PUSHJ P,FLTSX
POPJ P, ;PAGE-FAULT AT NON-UUO LEVEL???!!!
PUSHJ P,GETWDU## ;GET ARGUMENT
PUSHJ P,CHKLIM ;LEGAL?
POPJ P, ;NO, RETURN
MOVE T2,.PDMVL##(W) ;YES, GET MAX LIMIT
HRRZ T4,T2 ;MAKE SURE ARGUMENTS ARE BELOW MAX LIMITS
CAILE T2,<MXSECN+1>*<HLGPNO+1>
HRLI T2,<MXSECN+1>*<HLGPNO+1>
TRO T2,-1 ;PUT LARGE NUMBER IN IRRELEVANT RIGHT-HALF
CAMG T1,T2
CAMLE T3,T4
POPJ P, ;TRYING TO SET THEM TOO BIG
SETUV2: TLNE T1,-1 ;OK, SAVE WHAT HE ASKED FOR
.HLLM T1,.PDCVL##(W) ;CVPL
TRNE T1,-1
.HRRM T1,.PDCVL##(W) ;CPPL
SKIPN T1 ;IF WHOLE THING ZERO,
.MOVEM T1,.PDCVL##(W) ; DO IT ANYWAY
PJRST CPOPJ1##
;ROUTINE TO DETERMINE IF A PAGE EXISTS AND IF SO IF REFERENCING IT
; WILL CAUSE A PAGE FAULT. ENTER T2 = VIRTUAL ADDRESS
; EXIT CPOPJ IF PAGE DOESN'T EXIST
; CPOPJ1 IF PAGE EXISTS BUT IS PAGED OUT OR HAS ACCESS ALLOWED OFF,
; CPOPJ2 IF PAGE EXISTS AND IS IN CORE, OR IS ALLOCATED BUT ZERO
;RETURNS MAP CONTENTS FOR THE ADR IN T4
;PRESERVES T2.
FLTTC:: MOVE T4,T2 ;GET ADR
LSH T4,W2PLSH##+P2SLSH## ;GET SECTION
JUMPE T4,FLTTC1 ;CONTINUE IF S0
PUSH P,T2 ;SAVE T2
PUSHJ P,RSECT4 ;GET REAL SECTION #
JUMPN T4,T2POPJ## ;DOESN'T EXIST
POP P,T2 ;RESTORE T2
FLTTC1: MOVE T4,T2 ;GET WORD ADDRESS AGAIN
LSH T4,W2PLSH## ;PAGE #
SE1ENT
SKIPN T4,@[IW UMAPSN,UMAPS(T4)] ;GET ENTRY (SECTION EXISTS SO CAN'T FAULT)
POPJ P, ;TOO BAD PAGE DOESN'T
TLNE T4,(<PM.ACD>B2) ;IN CORE?
JRST CPOPJ2## ;YES
TLZ T4,(PM.NAD) ;KEEP ONLY ADDRESS
CAMN T4,[PM.ZER] ;ABZ PAGE?
AOS (P) ;YES, ACCESS ALLOWED IS ON
JRST CPOPJ1## ;DONE
;HERE TO DEPOSIT IN AN ALLOCATED BUT ZERO PAGE
; S = WHAT TO DEPOSIT, JOBEXM = WHERE
CREPAG::PUSHJ P,CLRASA## ;CLEAR JS.ASA IN CASE OF ERROR AND SO USER'S
; ACS WILL GET RESTORED WHEN MONITOR JOB IS STARTED
JUMPL P4,CREPA2 ;IF RUNNING, REQUIRE A CONTROL C
JSP T2,SAVCTX##
;RETURN HERE AT UUO LEVEL
MOVEM S,.JDAT+JOBFDV## ;SAVE WHAT TO DEPOSIT
MOVE T2,.JDAT+JOBEXM## ;WHERE TO DEPOSIT
TLZ T2,400000 ;CLEAR EXAMINE LAST FLAG
MOVEI T3,1 ;NUMBER OF PAGES TO CREATE FOR THE DEPOSIT
PUSHJ P,MAKPGS ;CREATE THE PAGE FOR THE DEPOSIT
JRST CREPA1 ;LOST, PHYSICAL LIMIT IS SET TOO LOW
MOVE T1,.JDAT+JOBFDV## ;WHAT
MOVE T2,.JDAT+JOBEXM## ;WHERE
TLZ T2,400000 ;CLEAR EXAMINE LAST FLAG
EXCTXU <MOVEM T1,(T2)> ;STORE IT AWAY FOR HIM
POPJ P,
CREPA1: PUSHJ P,TTYFUW## ;FIND HIS TTY AND RESTORE J
PUSHJ P,PRQM## ;"?"
MOVEI T1,OUTBMS## ;"OUT OF BOUNDS"
PJRST CONMES## ;PRINT THAT
CREPA2: SKIPGE .JDAT+JOBEXM## ;EXAMINE LAST FLAG ON?
TLO T2,400000 ;YES, SET IT AGAIN
MOVEM T2,.JDAT+JOBEXM## ;STORE WHAT USER TYPED SINCE CAN'T DO IT NOW
MOVEI T1,RUNERR## ;"PLEASE TYPE CONTROL C FIRST"
PJRST ERRMES## ;PRINT THAT AND RETURN TO COMCON
;SUBROUTINE TO RETURN # OF VIRTUAL PAGES ALLOCATED TO A USER'S JOB
;CALL WITH:
; UBR SETUP TO USER PAGE MAP PAGE
; MOVEI J,JOB #
; PUSHJ P,VMSIZE
; RETURNS HERE WITH LOWSEG SIZE IN T1 AND HISEG SIZE IN T2
;
; JOB'S UPMP IS IN CORE WHEN VMSIZE IS CALLED. LOWSEG SIZE
; INCLUDES THE JOB'S PAGE MAP PAGE.
;
VMSIZE::SETZB T1,T2 ;ASSUME USER DID CORE 0
SKIPN JBTADR##(J) ;ANY CORE ASSIGNED?
POPJ P, ;NO, RETURN ZEROS
PUSHJ P,LOSIZ ;GET THE LOW SEG SIZE
MOVEI T1,UPMPSZ##(T3) ; +1 FOR UPMP
ADD T1,.USMEM ; + NO OF NON-CONTIGUOUS PAGES
SKIPLE T3,JBTSGN##(J) ;HAVE A HI SEG?
TLOA T3,(1B0) ;MAKE A USABLE INDEX OUT OF COPY OF JBTSGN
TRNA ;NO HISEG
HLRZ T2,JBTADR##(T3) ;YES, GET ITS SIZE
ADDI T2,1
LSH T2,W2PLSH## ;CONVERT TO PAGES
POPJ P, ;AND RETURN
;SUBROUTINE TO COMPUTE THE LOW SEG SIZE
;ENTER J=JOB NUMBER
;EXIT T3= LOW SEG SIZE IN PAGES
;PRESERVES ALL ACS (EXCEPT T3)
;CALL HISIZ TO COMPUTE HI SEG SIZE, ALWAYS RETURNS CPOPJ1
HISIZ: HLRZ T3,JBTADR##(J) ;USE JBTADR
AOS T3 ;ROUND UP
LSH T3,W2PLSH## ;MAKE PAGES
JRST CPOPJ1## ;AND RETURN
LOSIZ: SKIPN T3,.USREL ;VIRTUAL?
HLRZ T3,JBTADR##(J) ;NO, USE JBTADR
ADDI T3,1
LSH T3,W2PLSH## ;CONVERT TO PAGES
ADD T3,.USNCR ;ADD # OF NZS PAGES
POPJ P, ;AND RETURN
SUBTTL ERRCON ERROR HANDLING MODULE
;SUBROUTINE TO COMPUTE A VIRTUAL PAGE NUMBER WITHIN A JOB'S
; ADDRESS SPACE BASED ON AN ABSOLUTE PAGE NUMBER KNOWN TO BE IN THE
; JOB'S MAP
;CALLING SEQUENCE:
; MOVE J,JOB NUMBER
; MOVE T3,PHYSICAL PAGE NUMBER TO BE USED IN VIRTUAL PAGE CALCULATION
; MAKE THE JOB'S MAP ADDRESSABLE
; PUSHJ P,PHYPVP ;CONVERT PHYSICAL PAGE NUMBER TO VIRTUAL PAGE NUMBER
;ALWAYS RETURNS POPJ,T1=VIRTUAL PAGE NUMBER WITHIN THE
; LOW SEGMENT OR RELATIVE PAGE NUMBER WITHIN HIGH SEGMENT
PHYPVP::SE1ENT ;TO TOUCH MAPS
SETZB T1,T4 ;START AT VIRTUAL PAGE 0
PUSHJ P,GMPTR ;GET A BYTE POINTER TO THE MAP
PHYPV1: MOVE T2,(T4) ;GET MAP CONTENTS
AOS T4 ;INCREMENT
TLZ T2,(PM.NAD) ;KEEP ONLY PAGE #
CAME T3,T2 ;IS THIS THE ABSOLUTE PAGE IN QUESTION?
AOJA T1,PHYPV1 ;NO, LOOK AT THE NEXT PAGE IN THE MAP
PUSHJ P,TSWST ;IN THE WORKING SET?
CAIA ;NO, SEE IF IN THE HIGH SEG
POPJ P, ;IT'S IN THE WORKING SET
PUSHJ P,TPNHS ;YES, IS THIS PAGE IN THE HIGH SEGMENT?
SKIPA J,JBTSGN##(J) ;YES, GET HIGH SEGMENT NUMBER
AOJA P1,PHYPV1 ;NO, NOT A REAL PAGE THEN (DISK ADDR?)
LDB T2,JBYHSO## ;GET ORIGIN PAGE OF THE HIGH SEGMENT
SUBI T1,(T2) ;COMPUTE RELATIVE PAGE WITHIN HIGH SEGMENT
POPJ P, ; AND RETURN
SUBTTL CORE1 INTERFACE WITH THE CORE ROUTINES
;SUBROUTINE TO TURN ON BITS IN WSBTAB WHEN A JOB IS EXPANDING
;ENTER T1=HIGHEST RELATIVE PAGE DESIRED
;PRESERVES T1
CLRWS:: PUSHJ P,SAVE2## ;SAVE P1 & P2
MOVSI P1,(ANDCAM T1,(T4)) ;SET ARGUMENT FOR ADJWS1
JRST ADJWS1 ;CLEAR BITS IN WSBTAB
ADJWS:: PUSHJ P,SAVE2## ;SAVE P1 & P2
MOVSI P1,(IORM T1,(T4)) ;SET ARG FOR ADJWS1
MOVEI T3,30 ;MAKE SURE UPMP BIT ON IN WSBTAB
IORM T3,WSBTAB+16
ADJWS1: PUSHJ P,SAVT##
MOVEI T3,(T1) ;GET ARG SET
ANDI T3,HLGPNO ;ONLY KEEP PAGE NUMBER
ADJWS2: MOVEI P2,MXSECN_S2PLSH## ;ISOLATE SECTION #
AND P2,T1
LSH P2,P2SLSH##
ADJWS3: SKIPGE .USBTS ;NOT A BIG USER
SKIPN T4,P2 ;SECTION BEING DONE
SKIPA T4,[WSBTAB-.WSBNZ+WSBTBL]
IMULI T4,WSBTBL
ADDI T4,.WSBNZ-WSBTBL
DOBIT: MOVEI T1,^D36 ;SET UP FIRST PART OF MASK
PUSHJ P,BITMSK##
DOBIT1: XCT P1 ;SET OR CLEAR BITS
JUMPLE T3,DOBIT2 ;GO IF THROUGH
PUSHJ P,BITMS2## ;SET MASK FOR NEXT PART
JRST DOBIT1 ;AND CONTINUE
DOBIT2: SOSGE T1,P2 ;ANOTHER SECTION TO DO?
POPJ P, ;NO, DONE
SKIPN .UPMP+SECTAB(T1);SECTION EXIST?
JRST DOBIT2 ;NO, KEEP LOOKING (SEC 0 MUST EXIST FOR NOW)
MOVEI T3,HLGPNO ;DO ALL PAGES IN PRECEDING SECTIONS
JRST ADJWS3
;SUBROUTINE TO COMPUTE THE TOTAL VIRTUAL SIZE OF A JOB
;ENTER WITH JOB ADDRESSABLE
;EXIT T2= JOB SIZE IN PAGES (EXCLUDES UPMP SIZE)
;PRESERVES ALL ACS BUT T2
VRTSZ: PUSH P,T1 ;SAVE T1
MOVE T1,.USJOB ;JOB NUMBER
SKIPN T2,.USREL ;NON-CONTIGUOUS?
HLRZ T2,JBTADR##(T1) ;NO, GET JBTADR
SKIPLE T1,JBTSGN##(T1) ;IS THERE A NON-SHARABLE HI-SEG?
TLNE T1,SHRSEG
JRST VRTSZ1 ;NO
HRRZS T1
HLRZ T1,JBTADR##(T1) ;YES, GET ITS SIZE
ADD T2,T1 ;LOW+HIGH SIZES
VRTSZ1: LSH T2,W2PLSH##
ADD T2,.USNCR ;AND NZS PAGES
ADD T2,.USMEM ;+NO OF NON-CONTIG PAGES
AOJA T2,TPOPJ## ;AND RETURN
;SUBROUTINE CALLED BY CORE1 ON A CORE UUO/COMMAND
;ALLOCATES SPACE (ALLOCATED BUT ZERO) IF A JOB IS ALREADY VIRTUAL
; OR IS GOING VIRTUAL BY THIS CORE OPERATION
;ENTER T3=AMOUNT OF INCREASE -1 ; T1=NEW HIGHEST ADDRESS
;EXIT CPOPJ IF ASKING FOR TOO MUCH
;EXIT CPOPJ1 IF ALLOCATED ON DSK
;EXIT CPOPJ2 OTHERWISE, T1=HIGHEST ADR, T3=AMOUNT OF INCREASE-1
VIRCHK::CAIG J,JOBMAX## ;LOW SEGS MUST CALL KISER TO
JUMPE R,CPOPJ2## ; GET INITIAL CORE (GETMIN)
TLNE J,SHRSEG ;A SHARABLE HIGH SEGMENT?
JRST CPOPJ2## ;YES, LET KISER HANDLE CORE ALLOCATION
PUSHJ P,UUOLVL## ;UUO LEVEL?
TDZA T3,T3 ;NO, MUST BE SECTION 0 THEN
XSFM T3 ;GET THE SECTION #
TRNE T3,MXSECN ;NON-ZERO SECTION?
JRST VIRCH6 ;YES, HANDLE DIFFERENTLY
CAIG J,JOBMAX## ;A HIGH SEGMENT?
SKIPN T2,.USREL ;NO, HIGHEST CONTIGUOUS ADDRESS IN THE LOW SEGMENT
HLRZ T2,R ;HIGHEST ADDRESS IN THE SEGMENT
MOVE T4,T1 ;HIGHEST ADDRESS REQUESTED
SUB T4,T2 ;MINUS CURRENT HIGHEST ADDRESS
JUMPLE T4,VIRCH9 ;DEALLOCATING
LSH T4,W2PLSH## ;CONVERT TO NUMBER OF PAGES OF INCREASE
DMOVEM T1,.USTMP ;SAVE REQUESTED SIZE, CURRENT SIZE
CAIG J,JOBMAX## ;A HIGH SEGMENT?
JRST VIRCH1 ;NO
EXCH J,.USJOB ;JOB NUMBER
PUSHJ P,HSVAD## ;COMPUTE THE EXTENT OF THE HIGH SEGMENT
EXCH J,.USJOB ;RESTORE HIGH SEGMENT NUMBER
MOVE T1,T2 ;UVA OF HIGH SEGMENT
ADD T1,.USTMP ;CURRENT HIGEST ADDRESS IN THE HIGH SEGMENT
ADD T2,.USTMP+1
VIRCH1: CAMG T4,VIRTAL## ;IS ENOUGH SWAPPING SPACE AVAILABLE?
PUSHJ P,CKNZ1 ; AND ARE ALL PAGES REQUESTED NOT IN-USE?
POPJ P, ;NO, ERROR RETURN
MOVE T1,.USTMP ;RESTORE THE HIGEST ADDRESS REQUESTED
MOVEM T4,.USTMP ;SAVE THE NUMBER OF PAGES OF INCREASE
CAIG J,JOBMAX## ;A HIGH SEGMENT?
PUSHJ P,FNDPDS## ;NO, FIND THE PDB FOR THIS JOB
PUSHJ P,GSIZT ;DOES IT FIT (PHSYCIALLY, VIRTUALY, NOT AT ALL)?
JRST VIRCH2 ;MAYBE VIRTUALLY
SKIPGE P1 ;VIRTUALLY IF NOT PHYSICAL ONLY
JRST VIRCH3 ;PHYSICALLY
;HERE IF JOB ALREADY VIRTUAL OR HAS TO GO VIRTUAL
VIRCH2: JUMPL P1,CPOPJ## ;PHYSICAL-ONLY IF P1 NEGATIVE
JRST VIRCH5 ;NO, LOW SEG VIRTUAL CORE
;HERE IF CAN GET PHYSICAL CORE
VIRCH3: CAIG J,JOBMAX## ;HIGH SEG?
JRST VIRCH4 ;NO
SKIPN T2,.USHSE ;CREATING?
MOVE T2,.USHSS ;YES, THEN START AT THE VERY BEGINNING
ADD T1,.USHSS ;HIGHEST PAGE DESIRED
TRO T1,PG.BDY ;WORD ADDRESS
VIRCH4: TDZA T3,T3 ;CLEAR
VIRCH5: MOVSI T3,(PG.SLO) ;ON DISK
SUBI T1,(T2) ;# OF PAGES TO EFFECT
SKIPN R ;IF CREATING FROM NOTHING,
AOSA T1 ;INCLUDE 0TH PAGE
AOS T2 ;ELSE START AT FIRST NON-EX PAGE
LSHC T1,W2PLSH## ;CONVERT TO PAGES
HLL T2,T3
MOVNM T1,.JDAT+JOBUAL##
MOVEM T2,.JDAT+JOBUAL##+1
SETZM .JDAT+JOBUAL##+6 ;NO SECOND UUO
CAIG J,JOBMAX## ;LOW SEG?
JRST VIRC14 ;DO THE UUOS
;HERE TO SET UP THE REMAP FOR A NON-SHARABLE HIGH SEG
HRRZM T2,.JDAT+JOBUAL##+4 ;SOURCE PAGE
HRRZM T2,.JDAT+JOBUAL##+5 ;NEW HS ORIGIN (APPEND)=IN PLACE
MOVE J,.USJOB ;POINT TO LOW SEG
MOVNM T1,.JDAT+JOBUAL##+3 ;(NEGATIVE INDICATES APPEND)
MOVEI T1,3 ;# OF ARGS
MOVEM T1,.JDAT+JOBUAL##+2 ;SET IN ARG BLOCK
MOVE T1,[.PAGRM,,JOBUAL##+2] ;SET ARG POINTER
MOVEM T1,.JDAT+JOBUAL##+6
JRST VIRC20
;HERE TO DO CORE UUO FOR A NON-ZERO SECTION
VIRCH6: CAILE J,JOBMAX## ;JOB OR HIGH SEG?
JRST VIRCH7 ;HIGH SEG
LSH T1,W2PLSH## ;CONVERT TO HIGHEST PAGE DESIRED
AOS T1 ;INCLUDE P0
MOVNM T1,.JDAT+JOBUAL## ;# OF PAGES TO "CREATE"
LSH T3,S2PLSH## ;CHANGE SECTION # TO PAGE 0 IN THAT SECTION
HRLI T3,(PG.IDC) ;DON'T CARE ABOUT PAGES THAT ALREADY EXIST
MOVEM T3,.JDAT+JOBUAL##+1 ;ARG
SETZM .JDAT+JOBUAL##+6 ;NO SECOND UUO
PJRST VIRC14 ;FINISH UP
;HERE FOR HIGH SEG
VIRCH7: MOVE T3,[.PAGRM,,JOBUAL##+2] ;A REMAP WILL BE DONE
MOVEM T3,.JDAT+JOBUAL##+6 ;POINTER TO BLOCK
MOVE J,.USJOB
LDB T3,JBYSG2##
XSFM T4
CAIN T3,(T4) ;IS HIGH SEG IN THIS SECTION?
SKIPN R ;YES, DOES IT ALREADY EXIST?
SKIPA T2,[377000] ;DOESN'T EXIST OR WRONG SECTION, CREATE
SKIPA T2,.USHSE ;APPENDING, CURRENT END OF HIGH SEG
SKIPA T3,[400000]
MOVE T3,.USHSS
ADDI T1,(T3)
LDB T3,JBYSG2## ;RESTORE SECTION #
HRLI T1,(T4) ;SECTION #
HRLI T2,(T4) ;HERE ALSO
LSHC T1,W2PLSH## ;PAGES
TLZN T2,-1 ;"CORE 0"
SOS T1 ;YES, ONE MORE PAGE TO DELETE
SUBM T2,T1 ;-# OF PAGES TO CREATE/REMAP
JUMPL T1,VIRCH8 ;NEGATIVE, ALL IS WELL
SETZM .JDAT+JOBUAL## ;NO FIRST UUO FOR DELETE
MOVEI T2,1 ;ONLY ONE ARG FOR DELETE REMAP
MOVEM T2,.JDAT+JOBUAL##+2 ;# OF ARGS
MOVEM T1,.JDAT+JOBUAL##+3 ;SET # OF PAGES (APPEND)
PJRST VIRC20
VIRCH8: MOVEM T1,.JDAT+JOBUAL##
CAIN T3,(T4) ;IS HIGH SEG IN THIS SECTION?
SKIPN R ;YES, DOES IT ALREADY EXIST?
MOVNS T1 ;CREATE
AOS T2
MOVEM T2,.JDAT+JOBUAL##+1 ;CREATE ARG TOO
HRRZS T2 ;INCASE DELETE
MOVEM T2,.JDAT+JOBUAL##+4 ;"FROM" REMAP PAGE
MOVEM T2,.JDAT+JOBUAL##+5 ;"TO" REMAP PAGE
MOVEI T2,3
MOVEM T2,.JDAT+JOBUAL##+2 ;# OF ARGS
MOVEM T1,.JDAT+JOBUAL##+3 ;SET # OF PAGES (APPEND)
JRST VIRC20
;HERE TO DEALLOCATE STORAGE
VIRCH9: CAIG J,JOBMAX## ;JOB?
JRST VIRC10 ;YES, DO AS LOW SEG STUFF
ASH T4,W2PLSH## ;CONVERT TO PAGES
JUMPE T4,VIRC18 ;NOTHING TO DO
MOVNM T4,.JDAT