Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93e-bb - 7,6/ap017/core1.x17
There is 1 other file named core1.x17 in the archive. Click here to see a list.
TITLE CORE1 - LOGICAL AND PHYSICAL CORE ALLOCATION ROUTINES - V664
SUBTTL T. HASTINGS/TH/RCC/CHW/JMF/DAL 15 JULY 86
	SEARCH	F,S
	$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 VCORE1,664
			;THIS MACRO PUTS VERSION NO. IN STORAGE MAP AND GLOB

	ENTRY	CORE1		;ALWAYS LOAD CORE1(FOR LIB SEARCH)


;CORE ALLOCATION IS DONE ON A 1K BLOCK BASIS
;USING A USE BIT TABLE(CORTAB).  EACH 1K BLOCK IS REPRESENTED BY A 1 OR 2
;BIT ENTRY IN CORTAB (2 BITS IF THE LOCK UUO IS INCLUDED IN THE SYSTEM)
;A ZERO ENTRY MEANS BLOCK NOT IN USE
;A NON-ZERO ENTRY INDICATES MEMORY IN USE AS FOLLOWS:
;(NUMBERS IN BRACKETS INDICATE CONTENTS OF ENTRIES IN CORTAB IN THE FOLLOWING FORMAT
;[CONTENTS OF CORTAB IN SYSTEM NOT INCLUDING LOCK UUO, CONTENTS OF CORTAB
;IN SYSTEM INCLUDING LOCK UUO]

; 1. IN USE BY MONITOR [1,2]
; 2. IN USE BY A LOCKED JOB [-,2]
; 3. IN USE BY A JOB NOT LOCKED [1,1]
; 4. NON-EXISTANT [1,2]

;WHEN THE SYSTEM IS STARTED, SYSINI SETS THE CORTAB TABLE
;IT ALSO SETS A BYTE POINTER(CORLST) WHICH POINTS TO THE
;LOWEST NON-EXISTANT BLOCK IMMEDIATELY ABOVE THE HIGHEST
;EXISTANT BLOCK. IT ALSO SETS CORTAL TO THE NO. OF
;FREE BLOCKS AVAILABLE.
;THE CORE1 ROUTINE ASSIGNS CORE IF POSSIBLE, SETS THE USE BITS,
;AND MOVES THE JOB IF NEW ASSIGNMENT IS A DIFFERENT PLACE THAN OLD
;THE JBTADR TABLE IS ALSO UPDATED BY THE CORE ROUTINES
;LH=PROTECTION,RH=RELOCATION
;JOBADR IS MODIFIED IF CORE FOR CURRENT JOB
;HARDWARE RELOC. AND PROTEC. ARE RESET IF CURRENT JOB
;FINALLY JOBREL(PROTECTION) IN JOB DATA AREA IS ALWAYS UPDATED

;LIST OF GLOBALS AFFECTED:
;JBTADR,CORTAL,CORTAB,HOLEF,SHFWAT,JOBADR,HOLES

;CORE UUO
;CALL:	MOVEI	AC,HIGHEST REL. ADR. DESIRED IN LOW SEG
;	HRLI	AC,HIGHEST REL. ADR. DESIRED IN HIGH SEG
;	CALL	AC,[SIXBIT /CORE/]
;	ERROR	RETURN
;	OK	RETURN TO USER, JOB MOVED IF NECESSARY
;RETURN NO. OF FREE 1K BLOCKS IN AC(OR MAX. NO. BLOCKS ALLOWED IF SWAPPING SYS)
;BOTH HALVES 0 MEANS ERROR RETURN NO. OF FREE 1K BLOCKS(OR MAX. NO. OF BLOCKS
; ALLOWED IF SWAPPING SYSTEM) IMMEDIATELY WITHOUT AFFECTING CORE
; OR WAITING FOR IO DEVICES
;LH=0 MEANS DO NOT CHANGE HIGH SEG ASSIGNMENT
;RH=0 MEANS DO NOT CHANGE LOW SEG ASSIGNMENT


CORUUO::SKIPE	T1		;IF ZERO CORE REQUESTED JUST RETURN
				; THE AMOUNT AVAILABLE
	PUSHJ	P,CHGCOR	;CHANGE THE CORE ASSIGNMENT
	  SKIPA			;NOT ENOUGH
	AOS	(P)		;OK RETURN TO USER
	PUSHJ	P,CORBND	;T1 = UPPER BOUND ON WORDS FOR JOB
	LSH	T1,W2KLSH##	;CONVERT TO K

	JRST	STOTAC##	;STORE IN USER AC AND RETURN TO USER
;SUBROUTINE TO CHANGE CORE - JUST LIKE CORE UUO
; EXCEPT VALUE NOT STORED IN USER'S UUO ACS
; USED BY MONITOR JOBS INSTEAD OF CORE UUOS
;CALL:	MOVE	T1,XWD NEW HIGH, NEW LOW SEG HIGHEST ADR
;	PUSHJ	P,CHGCOR
;	  ERROR RETURN
;	OK RETURN

CHGCOR::PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSH	P,T1		;NO, SAVE HIGHEST DESIRED ADDRESS IN BOTH SEGS
	MOVSI	T2,JACCT
	TDNE	T2,JBTSTS##(J)	;PRIVILEGED PROGRAM?
	TLO	P1,PHONLY	;YES, PHYSICAL ONLY THEN

	PUSHJ	P,IOWAIT##	;WAIT FOR ALL DEVICE INACTIVE
IFN FTMP,<
	PUSHJ	P,UPMM##	;GET THE MEMORY MANAGEMENT RESOURCE
>
	HRRZ	T1,(P)		;HIGHEST REL. LOC. DESIRED FOR LOW SEG(RH)
	JUMPE	T1,CORU1	;IS RH 0(IF YES DO NOT CHANGE LOW SEG)?
	IORI	T1,PG.BDY##	;NO, MAKE IT AN EVEN MULTIPLE OF 1K-1
IFN FTLOCK,<
	MOVSI	T2,NSHF!NSWP	;LOCKED JOBS CANNOT CHANGE THEIR SIZE
	TDNN	T2,JBTSTS##(J)	;IS HE LOCKED?
>
	PUSHJ	P,CORE1		;TRY TO ASSIGN CORE
	  JRST	CORERR		;NOT AVAILABLE, ERROR RETURN
				; SUM OF NEW LOW AND OLD HIGH SEG TOO BIG
CORU1:	HLRZ	T1,(P)		;CHECK TO SEE IF USER IS REQUESTING HIGH CORE
	PUSHJ	P,UCORHI##	;TRY TO ASSIGN CORE FOR HIGH SEG,
				; UCORHI EXPECTS ARG ON PD LIST
	  JRST	CORERR		;ERROR-ACTIVE IO(SAVE IN PROGRESS FOR SOME USER)
				; OR PROTECTION FAILURE (CAN'T UPDATE)
	AOS	-1(P)		;SET FOR OK(SKIP) RETURN
CORERR:	POP	P,T1		;REMOVE ARG FROM LIST
IFN FTMP,<
	PUSHJ	P,TGVMM##	;GIVE UP THE MM IF OWNED
>
	MOVE	T1,JBTSTS##(J)	;JOB STATUS WORD
	TLNE	T1,JXPN!SWP	;MUST LOW SEGMENT BE SWAPPED OUT TO EXPAND OR
				; HIGH SEGMENT LOGICAL CORE ASSIGNED ON DISK?
	PUSHJ	P,WSCHED##	;YES, CALL SCHEDULER TO STOP JOB
				; LOW SEG MUST BE SWAPPED OUT TO EXPAND
	POPJ	P,
;SUBROUTINE TO RETURN UPPER BOUND CORE LIMIT FOR JOB IN WORDS
;CALL:	MOVE	J,JOB NO
;	PUSHJ	P,CORBND
;	ALWAYS RETURN - T1 = UPPER BOUND

CORBND::PUSH	P,T2
IFN FTLOCK,<
	PUSH	P,J		;SAVE JOB NUMBER
	MOVSI	T1,NSWP!NSHF
	MOVEI	T2,0
	TDNE	T1,JBTSTS##(J)	;SEGMENT LOCKED?
	PUSHJ	P,SEGSIZ##	;YES, GET ITS CORE SIZE
	PUSH	P,T2		;SAVE CORE SIZE
	MOVE	J,JBTSGN##(J)	;GET HIGH SEG NUMBER
	MOVEI	T2,0
	JUMPLE	J,CRBND1	;USING A HIGH SEG?
	HRRZS	J		;CLEAR JUNK IN LEFT HALF
	TDNE	T1,JBTSTS##(J)	; THAT IS LOCKED?
	PUSHJ	P,SEGSIZ##	;YES, GET HIGH SEG SIZE
CRBND1:	POP	P,T1		;GET BACK LOW SEG SIZE
	ADD	T1,T2		;GET TOTAL SIZE THIS JOBS LOCKED CORE
	LSH	T1,P2WLSH##
	ADD	T1,CORMAX##	;ADD TO CORMAX TO GET APPARENT CORMAX
	POP	P,J		;RESTORE JOB NUMBER
>
IFE FTLOCK,<
	MOVE	T1,CORMAX##	;GET CORMAX
>
	LDB	T2,JBYLCR##	;GET THIS JOBS CORE LIMIT
	JUMPE	T2,CRBND2
	LSH	T2,^D9
	CAMLE	T1,T2		;WE WANT
	MOVE	T1,T2		; THE SMALLER OF THE TWO
CRBND2:	PUSHJ	P,FNDPDB##	;FIND THE PDB
	  JRST	CRBND4		;NO LIMIT OR GUIDELINE IF NO PDB
	HRRZ	T2,.PDCVL##(W)	;CURRENT PHYSICAL LIMIT OR GUIDELINE
	JUMPE	T2,CRBND3	;IGNORE IF NONE
	TRZN	T2,400000	;LIMIT?
	JUMPL	P1,CRBND3	;NO, IGNORE GUIDELINE IF PHONLY
	LSH	T2,P2WLSH##	;NUMBER OF WORDS
	CAMLE	T1,T2		;SMALLEST YET?
	MOVE	T1,T2		;NO, USE SMALLER
CRBND3:	HRRZ	T2,.PDMVL##(W)	;FINALLY, MAX PHYSICAL LIMIT
	JUMPE	T2,CRBND4
	LSH	T2,P2WLSH##
	CAMLE	T1,T2
	MOVE	T1,T2
CRBND4:IFN FTLOCK,<
	LSH	T1,W2PLSH##
	CAILE	T1,@CORLIM##	;CORLIM MIGHT BE EVEN SMALLER
	HRRZ	T1,CORLIM##	; IF SO, IT IS THE LIMIT
	LSH	T1,P2WLSH##
>
	SUBI	T1,UPMSZW##	;ACCOUNT FOR THE FACT THAT THE UPMP IS ALLOCATED
				; FROM USER CORE. THUS, MAXIMUM SIZE A JOB
				; A JOB CAN OBTAIN IS MIN (CORMAX, JOB LIMIT)-
				; THE SIZE OF THE USER PAGE MAP PAGE
	JUMPL	P1,T2POPJ##	;RETURN IF PHYSICAL ONLY
	PUSHJ	P,FNDPDB##
	  PJRST	T2POPJ##	;NO LIMITS IF NO PDB
	HLRZ	T2,.PDCVL##(W)	;CURRENT VIRTUAL LIMIT
	LSH	T2,P2WLSH##	;CONVERT TO PAGES
	CAMGE	T1,T2
	MOVE	T1,T2
	PJRST	T2POPJ##	;YES, USE SMALLER JOB LIMIT
;CORLM.	UUO -- SET JOB'S CORE LIMIT
;CALL:	HRLZI	AC,12
;	HRRI	AC,LIMIT IN NO. OF WORDS
;	SETUUO	AC,
;	ERROR
;	OK

CORELM::JUMPE	T2,CORLM1
	CAIG	T2,MINMAX##	;GREATER THAN MIN
	MOVEI	T2,MINMAX##	;YES--USE MINMAX
CORLM1:	ADDI	T2,PG.BDY##	;ROUND UP TO LAST LOWSEG ADDRESS
				;  + HIGH SEG SIZE
				;THIS IS TO BE SIMILAR TO CORE UUO
	TLNE	T2,-1		;SEE IF OVERFLOW
	SETOM	T2		;YES--SET TO INFINITY
	LSH	T2,-^D9		;CONVERT TO 512 UNITS
	DPB	T2,JBYLCR##	;STORE
	JRST	CPOPJ1##	;RETURN


;ROUTINE TO TEST FOR ANY ACTIVE DEVICES

;CALL:	MOVE	J,JOB NUMBER OR HIGH SEG NUMBER
;	MOVE	R,ADDRESS OF JOB DATA AREA
;	PUSHJ	P,ANYACT
;	DEVICES	ACTIVE
;	DEVICES	NOT ACTIVE EXCEPT POSSIBLY TTY
;IN REENTRANT SYSTEMS ANYACT IS BROKEN INTO 2 CALLS, ANYSAV AND ANYDEV
;ANYSAV TESTS WHTETHER THIS IS A HI SEG THAT HAS A SAVE IN PROGRESS
ANYACT::PUSHJ	P,ANYSAV##	;IS A SAVE IN PROGRESS FOR HI SEG?
	  POPJ	P,		;YES - RETURN


ANYDEV::PUSHJ	P,SAVE2##	;PRESERVE ACCUMULATORS P1, P2, P3

IFN FTMP,<
	PUSHJ	P,ANYRUN##	;IS THIS JOB RUNNING ON THE SLAVE
	  POPJ	P,		;YES, RETURN IMMEDIATELY
>
	CAILE	J,JOBMAX##	;YES, IT THIS A HIGH SEG?
	JRST	CPOPJ1##	;YES, OK TO SHUFFLE OR SWAP SINCE NSHF,NSWP NOT SET
				; AND NO SAVE IN PROGRESS
	LDB	P1,PJBSTS##	;JOB'S QUEUE CODE
	CAIE	P1,PIOWQ##	;IN PAGING I/O WAIT?
	CAIN	P1,DIOWQ##	;OR DSK I/O WAIT?
	POPJ	P,		;YES, CAN'T SWAP IT OUT NOW
				; ONLY HAPPENS IF LOCK IS TRYING
				; TO FORCE THIS JOB OUT
	MOVEI	P1,0		;ASSUME JOB IS CURRENT JOB (DEVICE TABLE IS THE MONITOR)
	CAME	J,.CPJOB##	;IS IT?
	PUSHJ	P,SVEUB##	;NO, MAKE THE JOB DATA AREA ADDRESSABLE
	PUSH	P,T1
ANY:	PUSHJ	P,NXTCH##
	  JRST	ANY3
IFN FTMSGSER,<
	HRRZ	F,T1
	LDB	P2,PDVTYP##	;GET THE DEVICE TYPE
	CAIE	P2,<.TYMPX/.TYEST>	;MPX?
	JRST	ANY1		;NO--JUST LOOK AT IOACT
	PUSHJ	P,MPXACT##	;SEE IF IT IS ACTIVE
	  JRST	TPOPJ##		;RETURN IF ACTIVE
	JRST	ANY		;LOOK AT NEXT DEVICE
> ;END FTMSGSER
ANY1:	TRNN	S,IOACT		;IS DEVICE ACTIVE?
	JRST	ANY
	MOVSI	P2,DVTTY	;DEVICE IS A TTY BIT
	TDNN	P2,DEVMOD(T1)	;NOT FINISHED, IS DEVICE TTY?
	JRST	TPOPJ##		;NO, ERROR RETURN, CANNOT ASSIGN CORE
	JRST	ANY		;YES, KEEP LOOKING FOR AN ACTIVE DEVICE
ANY3:
	SKIPN	F,DIADSK##	;DSK CHAN STOPPED?
	JRST	TPOPJ1##	;NO, OK RETURN
	LDB	P1,PJOBN##	;YES, IS THIS THE JOB THAT STOPPED IT!
	CAMN	P1,J
	JRST	TPOPJ##		;YES, SOMETHING IS ACTIVE

	PJRST	TPOPJ1##	;OK RETURN
;ROUTINE TO FLUSH PHYSICAL CORE ASSIGNED IN MEMORY
;NOTE: THIS ROUTINE DIFFERS SIGNIFICANTLY FROM CORE0 AND CORE1 IN THAT
;IT IS ONLY A PHYSICAL  REMOVAL OF CORE(VIRTAL IS NOT AFFECTED)
;SEE COMMENTS FOR CORE1
;CALL:	MOVE	J,HIGH OR LOW SEGMENT NUMBER
;	PUSHJ	P,KCORE1
;	ALWAYS	RETURN HERE
;SCORE1 IS CALLED FROM SHUFFLER WITH T1 SET TO SEG SIZE


KCORE1::MOVEI	T1,0		;SETUP DESIRED HIGHEST ADR
SCORE1::SOS	(P)		;CORE1 WILL ALWAYS SKIP RETURN
	MOVE	R,JBTADR##(J)
	PJRST	CORE1A		;BYPASS LOGICAL CORE ASSIGNMENT PART
				; AND FLUSH PHYSICAL CORE(LOGICAL CORE UNEFFECTED)
;CALL:	MOVE	T1,HIGHEST LEGAL ASSRESSABLE LOC. DESIRED
;	MOVE	J,JOB NUMBER
;	MOVE	R,[XWD PROT.,RELOC.]=JBTADR(J)
;	PUSHJ	P,CORE0
;	ERROR	;EITHER JOB HAS ACTIVE IO
		; OR NOT ENOUGH CORE
;	OK	RETURN
;JOB IS MOVED IF NECESSARY TO SATISFY REQUEST
;R IS SET TO NEW CORE ASSIGNMENT ON EITHER RETURN
;0 MEANS NONE ASSIGNED IN MEMORY, ASSIGNED ON DISK
;ENTER HERE FROM CORE CONSOLE COMMAND OR INITIAL CORE
;ASSIGNMENT OF JUST A JOB DATA AREA FOR RUN COMMAND
;IE ENTER WHEN DEVICES MAY BE ACTIVE OR JOB MAY HAVE NO PREVIOUS CORE
;JOB CAN HAVE CORE IN MEMORY, CORE ON DISK, OR NONE EITHER PLACE
;JOB CANNOT BE IN PROCESS OF SWAP OUT OR SWAP IN(CALLER'S RESPONSIBILITY)
;CORE0 NO LONGER REASSIGN CORE ON DISK IF OLD CORE ON DISK
;BECAUSE OF FRAGMENTED SWAPPING(TOO HARD) UNLESS 0 BEING ASKED FOR
;THEREFORE THE CORE COMMAND CAUSES JOB TO BE SWAPPED INTO CORE FIRST(INCORE=1)
;HOWEVER, THE R,RUN,GET,KJOB COMMANDS DO NOT REQUIRE THE PREVIOUS CORE IMAGE TO
;BE SWAPPED IN(AS THIS IS SLOW). THEY ASK FOR 140 WORDS, AND LARGER DISK SPACE IS RELINQUISHED
;UPON SWAPIN BY THE SWAPPER, VIRTAL IS INCREASED THEN RATHER THAN
;ON THE CALL TO CORE0.
;IT WILL TRY TO REASSIGN CORE IN MEMORY IF OLD CORE IN MEMORY
;IF THIS FAILS, IT WILL REASSIGN NEW CORE ON DISK AND ASK SWAPPER TO EXPAND
;IF JOB DID NOT HAVE OLD CORE, AN ATTEMPT WILL BE MADE TO ASSIGN CORE IN MEMORY
;IF THIS FAILS, TI WILL BE ASSIGNED ON THE DISK AND ASK SWAPPER TO EXPAND
;THE OTHER PLACES IN THE MONITOR WHERE THE IN-CORE COUNT IS TOUCHED IS
;IN GET WHERE IT INCREMENTS TO SHARE COPY ALREADY IN CORE.
;AND END OF SWAPIN OF LOW SEG AND HIGH SEG IS ALREADY IN CORE FOR OTHER USER
;THE CORE ROUTINES DO NOT ALTER THE HIGH SEG IN CORE COUNT.  IT IS UP TO THE  CALLER
;(IN SEGCON) TO CALL THE CORE ROUTINES ONLY IF IN CORE COUNT IS 0.
;AND END OF SWAPIN OF LOW SEG AND HIGH SEG IS ALREADY IN CORE FOR OTHER USER
CORE0::	MOVE	R,JBTADR##(J)
	JUMPN	R,CORE0A	;DOES JOB HAVE CORE IN MEMORY?
				; (ALWAYS TRUE BOTH SEGS IF CORE UUO)
	PUSHJ	P,SUMSEG##	;NO, WILL SUM OF BOTH SEGMENTS FIT IN PHYSICAL CORE?
				; LARGEST PERMITTED CORE. COMPARE SUM WITH CORMAX

	  POPJ	P,		;NO, GIVE ERROR RETURN
	MOVSI	T2,SWP		;IS JOB SWAPPED OUT?
	TDNN	T2,JBTSTS##(J)	;(MAY HAVE 0 DISK SPACE ALTHOUGH SWAPPED OUT)
	JRST	CORE1		;NO, TRY TO ASSIGN CORE IN MEMORY
	PUSHJ	P,CHGSWP##	;YES, CHANGE ASSIGNMENT OF SWAPPING SPACE ON DISK
				; INCREASE VIRTAL(COUNT OF FREE 1K BLOCKS OF SWAPPING
				; (SHOULD NEVER NEED TO DECREASE VIRTAL SINCE
				; CORE COMMAND ALWAYS SWAPS JOB IN FIRST).
				; (FRAGMENTATION POSTPONES RETURNING SPACE AND
				; INCREASING VIRTAL UNTIL SWAP IN IF NOT ASKING
				; FOR 0 VIRTUAL CORE)
	JRST	CPOPJ1##	;GIVE OK RETURN TO CALLER

CORE0A:

IFN FTTRPSET,<
	SKIPN	.CPSTS##	;NO,IS TIME SHARING STOPPED BY
				; TRPSET UUO DONE FOR JOB 1?
>

	PUSHJ	P,ANYACT	;NO,ANY ACTIVE DEVICE?
	  POPJ	P,		;YES, CANNOT ASSIGN CORE
				; NO, FALL INTO CORE1
;ROUTINE TO TRY TO ASSIGN CORE IN CORE
;LOW OR HIGH SEG MUST NOT BE SWAPPED OUT(CALLER'S RESPONSIBILITY)
;AND MUST NOT HAVE ANY ACTIVE DEVICES(IT MAY HAVE 0 CORE IN CORE THOUGH)
;IN OTHER WORDS HIGH OR LOW SEG MAY OR MAY NOT HAVE VIRTUAL CORE
;BUT IF IT HAS VIRTUAL CORE IT MUST BE IN PHYSICAL CORE
;THIS IS BOTH A LOGICAL AND A PHYSICAL CORE ASSIGNMENT
;FIRST OLD CORE IS RETURNED TO SYSTEM
;THEN NEW REQUEST IS ATTEMPTED TO BE SATISFIED IN LOWEST
;POSITION POSSIBLE.  THUS CORE TENDS TO BE PACKED
;IF NEW REQUEST CANNOT BE GRANTED, OLD AMOUNT IS RETAINED, IF NON-SWAPPING SYS
;OTHERWISE SWAPPER IS CALLED(XPAND) TO EXPAND CORE BY SWAPPING OUT



CORE1::	MOVE	R,JBTADR##(J)
	JUMPL	T1,CPOPJ##	;DON'T ALLOW NEGATIVE ARGUMENTS
IFN FTLOCK,<
	MOVSI	T2,NSHF!NSWP	;LOCKED SEGMENTS CANNOT CHANGE THEIR CORE SIZE
	TDNE	T2,JBTSTS##(J)	;IS THIS SEGMENT LOCKED?
	POPJ	P,		;YES, ERROR RETURN
	;END IFN FTLOCK
>
	CAILE	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	JRST	CORE12		;YES, PROCEED
	MOVE	T3,T1		;LOW SEGMENT, SAVE AMOUNT OF CORE REQUESTED
	PUSHJ	P,HSVAD##	;COMPUTE HIGH SEGMENT BOUNDS
	CAIL	T3,(T2)		;TRYING TO EXPAND INTO THE HIGH SEGMENT?
	JUMPN	T1,CPOPJ##	;YES IF THERE IS ONE - JUMP IF SO
	MOVE	T1,T3		;OK, RESTORE ARGUMENT
CORE12:	NOSCHEDULE		;PREVENT SCHEDULING

	PUSHJ	P,SEGSIZ##	;T2=OLD SEG SIZE
	JUMPE	T2,CORE10
	CAIG	J,JOBMAX##	;IF THIS IS A LOW SEGMENT,
	SUBI	T2,UPMPSZ##	;SUBTRACT OUT THE SIZE OF THE UPMP WHICH WAS
				; ADDED IN FOR ACCOUNTING PURPOSES

CORE10:	SKIPN	T3,T1		;IS O BEING REQUESTED?
	MOVNI	T3,1		;YES, PRETEND -1(DEPEND ON ASH BUG WHICH KEEPS -1
				; ON RT. SHIFT)
	ASH	T3,W2PLSH##	;CONVERT TO NO. OF K-1(01,0,1,2,...)
	SUB	T3,T2		;NO. OF K-1 INCREASE=NEW-OLD-1
	PUSHJ	P,VIRCHK##	;ALLOCATE CORE ON DSK? (USER JUST GOING
				; VIRTUAL OR ALREADY VIRTUAL)
	  POPJ	P,		;ALREADY VIRTUAL BUT TRYING TO EXCEED LIMITS
	  PJRST	CPOPJ1##	;YES, TAKE GOOD RETURN
	PUSHJ	P,SAVE1##
	TLO	P1,PHONLY	;PHYSICAL ONLY FOR CORBND

	CAMGE	T3,VIRTAL##	;IS THERE ENOUGH FREE VIRTUAL CORE IN SYSTEM?

	PUSHJ	P,SUMSEG##	;YES, IS SUM OF SEGS LESS THAN MAX. ALLOWED CORE+1?

	  POPJ	P,		;NO, ERROR RETURN
	AOJE	T3,CPOPJ1##	;YES, GET NO. K OF INCREASE AND
				;RETURN WITHOUT MOVING CORE IF NO CHANGE IN SIZE
	CAILE	J,JOBMAX##	;IF A LOW SEG...
	JRST	CORE11
	SKIPN	R		;IF GOING FROM 0 TO N,
	ADDI	T3,UPMPSZ##+1	;U DECREASE VIRTAL
	SKIPN	T1		;IF GOING FROM N TO 0,
	SUBI	T3,UPMPSZ##+1	;U DECREASE VIRTAL
CORE11:	MOVNS	T3		;MAKE MINUS FOR UPDATE
	ADDM	T3,VIRTAL##	;AND UPDATE TOTAL VIRTUAL CORE IN SYSTEM
				; SINCE THIS REQUEST CAN BE SATISFIIED

;HERE TO ALLOCATE PHYSICAL CORE IN CORE OR ON THE DISK
;ALWAYS SKIP RETURN - R = NEW PROTECTION,,RELOCATION
; R = 0 IF CORE IS ASSIGNED ON THE SWAPPING SPACE

CORE1A::JUMPE	R,CORGT0	;JUMP IF SEGMENT HAS NO CORE IN CORE
	HLRZ	T3,R		;T3 = CURRENT HIGHEST RELATIVE ADDRESS IN THE SEGMENT
	SKIPN	T1		;IS ZERO CORE BEING REQUESTED?
	MOVNI	T1,1		;YES, PRETEND -1 AND DEPEND ON BUG IN ASH
				; WHICH MAKES -1 = -1 WHEN SHIFTED
	SUB	T3,T1		;T3 = NUMBER OF WORDS OF INCREASE OR DECREASE IN
				; SEGMENT SIZE
	ASH	T3,W2PLSH##	;CONVERT TO NUMBER OF PAGES OF INCREASE OR DECREASE
	JUMPG	T3,CORE1B	;JUMP IF SEGMENT IS GETTING SMALLER
	MOVMS	T3		;T3 = NUMBER OF PAGES OF INCREASE
	PUSHJ	P,FRDCR##	;ARE THERE THAT MANY FREE PAGES AVAILABLE IN CORE?
	  JRST	CORGT7		;NO, MARK THE SEGMENT AS EXPANDING AND ALLOCATE
				; THE REQUIRED NUMBER OF PAGES ON SWAP-IN
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF INCREASE
	LDB	T1,JBYLSA##	;FIRST PAGE OF SEGMENT
	CAILE	J,JOBMAX##	;UNLESS HIGH SEG
	LDB	T1,JBYHSA##
	MOVE	T2,(P)		;T2 = NUMBER OF PAGES TO ADD TO THE SEGMENT
	ADDM	T2,JBTIMI##(J)	;INCREASE JBTIMI BY THAT NUMBER OF PAGES

	CAILE	J,JOBMAX##	;IF A HISEG,
	PUSHJ	P,SCPAGS	;KEEP THEM IN ORDER
	MOVE	T2,(P)		;SCPAGS CLOBBERS THIS
	PUSHJ	P,ADPAGS	;ALLOCATE ENOUGH PAGES TO SATISFY THE REQUEST
	POP	P,T2		;RESTORE THE NUMBER OF PAGES OF INCREASE
	LSH	T2,^D18+P2WLSH##;CONVERT TO NUMBER OF WORDS OF INCREASE IN
				; POSITION TO UPDATE CURRENT RELOCATION
	ADD	R,T2		;R = NEW PROTECTION,,RELOCATION
	JRST	CORGT2		;STORE NEW PROTECTION,,RELOCATION AND CLEAR
				; PAGES JUST ADDED TO INSURE SECURITY
CORE1B:	JUMPG	T1,CORE1C	;REQUESTING 0K CORE IN CORE?
IFN FTMP&FTKL10,<
	PUSHJ	P,CLCSN##	;YES, DON'T HAVE TO SWEEP BEFORE WE
				; RUN HIM AGAIN
>;END IFN FTMP&FTKL10
	CAMN	J,.CPJOB##	;CORE 0 ON THE CURRENT JOB?
	JRST	[MOVEI T2,NUPMPP## ;NULL JOB'S UPMP PAGE NUMBER
		 CONO PI,PI.OFF	;MAKE CHANGING THE SPT AND THE UBR ATOMIC
		 MOVEM T2,@.CPSPT## ;POINT SPT AT THE NULL JOB'S MAP
		 DATAO PAG,NULDOP## ;AND THE UBR AT THE NULL JOB'S MAP
		 CONO PI,PI.ON	;BOTH AGREE, ALLOW INTERRUPTS AGAIN
		 JRST .+1]	;AND CONTINUE

	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF DECREASE
	PUSH	P,J		;IN CASE LEFT HALF CRUFT,
	HRRZS	J		;CLEAR CRUFT
	LDB	T1,JBYLSA##	;FIRST PAGE OF THE SEGMENT
	CAILE	J,JOBMAX##	;UNLESS HIGH SEG
	LDB	T1,JBYHSA##
	POP	P,J
	JRST	CORE1D		;GO RETURN PAGES
CORE1C:	LDB	T2,[POINT 9,R,8];T2 = THE CURRENT SIZE OF THE SEGMENT IN
				; PAGES - 1
	SUBI	T2,(T3)		;COMPUTE THE RELATIVE PAGE NUMBER OF THE FIRST
				; PAGE TO RETURN TO THE FREE CORE LIST
	PUSH	P,T3		;SAVE THE NUMBER OF PAGES OF DECREASE
	PUSHJ	P,SNPAGS	;FIND THE ABSOLUTE PAGE NUMBER OF THE FIRST PAGE
				; TO RETURN TO THE FREE CORE LIST
IFN FTXMON,<
	XJRST	[MCSEC1+.+1]
>
	SSX	T1,MS.MEM	;SET SECTION NUMBER
	HRRZ	T2,PAGTAB(T1)	;T2 = THE LINK TO THE FIRST PAGE TO FREE
	HLLZS	PAGTAB(T1)	;INDICATE THAT THIS IS NOW THE LAST PAGE
				; OF THE SEGMENT
	MOVE	T1,T2		;T1 = THE ABSOLUTE PAGE NUMBER OF FIRST PAGE TO FREE
IFN FTXMON,<
	JRST	@[0,,.+1]	;RETURN TO SECTION 0
>
CORE1D:	PUSHJ	P,GVPAGS	;RETURN FREED PAGES TO THE FREE CORE LIST
	LDB	T2,IMGOUT##	;SWAPPER DEALLOCATION?
	JUMPN	T2,CORE1E	;JUMP IF YES
	LDB	T2,IMGIN##	;UPDATE IMGIN TO REFLECT # OF PAGES ALLOCD
	SUB	T2,(P)
	DPB	T2,IMGIN##
CORE1E:	POP	P,T2		;RESTORE THE NUMBER OF PAGES OF DECREASE
	LSH	T2,^D18+P2WLSH##;CONVERT TO NUMBER OF WORDS OF DECREASE AND
				; POSITION TO UPDATE CURRENT RELOCATION
	SUB	R,T2		;R = NEW PROTECTION,,RELOCATION
	SKIPG	R		;WERE ALL OF THE PAGES BELONGING TO THE SEGMENT
				; RETURNED TO FREE CORE
	SETZB	T1,R		;YES, INDICATE SEGMENT HAS NO CORE IN CORE
	CAILE	J,JOBMAX##	;IS THIS SEGMENT A HIGH SEGMENT?
	JUMPE	R,CORGT1	;YES, AND DOES IT STILL HAVE CORE IN CORE?
	JUMPN	R,CORGT2	;NO, DOES LOW SEGMENT HAVE CORE IN CORE?
	LDB	T1,IMGOUT##	;SWAPPER DEALLOCATION?
	SKIPN	T1
	PUSHJ	P,JOBFNQ##	;NO, CHECK VIRTUAL PAGES
	HRRZ	T1,JBTUPM##(J)	;NO, RETURN UPMP TO THE FREE CORE LIST
	SETZ	R,
	HLLZS	JBTUPM##(J)	;INDICATE NO UPMP OR CORE IN CORE
	PUSHJ	P,GVPAGS	;GIVE UP THE PAGE ALLOCATED TO THE UPMP
	JRST	CORGT6		;STORE R AND RETURN
;HERE WHEN THE SEGMENT IS EXPANDING FROM ZERO (CALLED BY THE SWAPPER AND ABOVE)
CORGET::PUSHJ	P,SVEUB		;SAVE UBR ON CALL FROM THE SWAPPER
CORGT0:	JUMPE	T1,CPOPJ1##	;RETURN IF MULTIPLE CALLS TO RETURN CORE
	AOS	T2,T1		;T2 = NUMBER OF WORDS OF CORE REQUIRED TO
				; SATISFY REQUEST
	LSH	T2,W2PLSH##	;T2 = NUMBER OF PAGES REQUIRED
	MOVE	T3,T2
	CAILE	J,JOBMAX##
	JRST	CORG0A		;NO
	LDB	T3,IMGOUT##
	JUMPE	T3,CORG0B
	LDB	T3,NZSICN##	;# OF NZS MAPS WANTED FOR SWAPIN
	SKIPE	T3		;ANY WANTED?
	DPB	T3,NZSXCN##	;YES, WE "HAVE THEM NOW"
	LDB	T3,IFYPGS##
	JUMPE	T3,[LDB T3,NFYPGS##
		JRST CORG0C]
	MOVEI	T4,0
	DPB	T4,IFYPGS##
	CAIA
CORG0B:	MOVEI	T3,UPMPSZ##+1
	DPB	T3,NFYPGS##
CORG0C:	ADDM	T2,T3		;ADD THAT IN
	LDB	T4,NZSSCN##
	ADD	T3,T4		;# OF NZS MAPS
CORG0A:	CAMLE	T3,BIGHOL##	;NO, IS THERE ENOUGH FREE CORE IN CORE TO
				; ACCOMODATE THE REQUEST?
	SOJA	T1,CORGT7	;NO, MARK THE SEGMENT AS EXPANDING AND ALLOCATE
				; THE REQUIRED NUMBER OF PAGES ON SWAP-IN
	DPB	T2,IMGIN##	;STORE THE NUMBER OF PAGES ALLOCATED IN CORE
	HRLI	R,-1(T1)	;R = NEW PROTECTION,,?
	CAILE	J,JOBMAX##
	SKIPA	T2,T3
	MOVEI	T2,-UPMPSZ##-1(T3)
	PUSHJ	P,GTPAGS	;ALLOCATE THE PAGES TO SATISFY THE REQUEST
	HRLI	T1,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.CSH+PM.AAB+PM.COR)

	CAILE	J,JOBMAX##	;IS THIS A LOW SEGMENT
	JRST	CORGT1		;NO, UPMP HAS ALREADY BEEN ALLOCATED
	PUSH	P,T1		;SAVE THE PAGE NUMBER OF FIRST PAGE OF THE LOW SEGMENT
	MOVEI	T2,UPMPSZ##+1	;ALLOCATE ONE PAGE FOR THE UPMP
	PUSHJ	P,GTPAGS	;GET ONE PAGE OFF THE FREE CORE LIST
	HRRM	T1,JBTUPM##(J)	;STORE IT AS THE ADDRESS OF THE UPMP
	MOVE	T3,.CPMAP##
	HRLI	T1,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.AAB)
	MOVEM	T1,.EUPMP/PAGSIZ##(T3)

	CLRPGT	(0,.EUPMP)	;THE UPMP IS NOW MAPPED THROUGH THE EXEC
	     	      		; MAP. CLEAR THE AM SO THE NEW MAPPING
				; WILL BE IN AFFECT
	SETZM	.EUPMP
	MOVE	T2,[.EUPMP,,.EUPMP+1]
	BLT	T2,.EUPMP+PG.BDY## ;ZERO THE ENTIRE UPMP
	MOVSI	T2,NUPPMT##	;NOW SETUP THE REST OF THE MAP FROM THE
	HRRI	T2,.EUPMP+.UPTVC ; PROTOTYPE MAP (NULL JOB'S UPMP)
	BLT	T2,.EUPMP+NUPMPL##-1
	MOVE	T2,T1
IFN FTXMON,<
	XJRST	[MCSEC1+.+1]	;REFERENCES TO PAGTAB REQUIRE WE MUST BE IN SECTION 1
	SSX	T2,MS.MEM
	HRR	T1,PAGTAB(T2)
	JRST	@[0,,.+1]	;RETURN TO SECTION 0
>
IFE FTXMON,<
	HRR	T1,PAGTAB(T2)
>
	EXCH	T1,.EUPMP/PAGSIZ##(T3)
	CLRPGT	(0,.EUPMP)
	SETZM	.EUPMP
	MOVE	T2,[.EUPMP,,.EUPMP+1]
	BLT	T2,.EUPMP+PG.BDY##
	EXCH	T1,.EUPMP/PAGSIZ##(T3)
	CLRPGT	(0,.EUPMP)
	TLO	T1,(PM.PUB+PM.CSH+PM.COR) ;ALWAYS PUBLIC HERE, USER MAP SPECIFIES
	MOVEM	T1,.EUPMP+SECTAB	;SECTION 0 MAP POINTER
IFN FTMP,<
	SKIPE	[M.CPU##-1]	;IF NOT CONFIGURED FOR SMP
>
	TLZ	T1,(PM.CSH)	;TURN ON CACHE BIT
	MOVEM	T1,.EUPMP+.UMUPM ;PAGE MAP - UNCACHED IF SMP
	HRR	T1,JBTUPM##(J)	;PROCESS TABLE
	MOVEM	T1,.EUPMP+.UMUPT ;PROCESS TABLE MAPPING - UNCACHED IF SMP
	TLO	T1,(PM.CSH)
	MOVEM	T1,.EUPMP+.UMUUP ;PROCESS TABLE MAPPING - CACHED REFERENCES

	POP	P,T1		;RESTORE THE MAPPING FOR THE FIRST PAGE OF THE
				; LOW SEGMENT
	PUSHJ	P,STEUB##	;MAKE THE UPMP ADDRESSABLE (SET THE UBR TO
				; POINT TO THIS PAGE)
	MOVEM	T1,.UPMAP
IFN FTMP,<
	TLZ	T1,(PM.CSH)	;TURN OFF CACHE BIT
>
	MOVEM	T1,.UPMP+.UMJDT
	CLRPGT	(0,.JDAT)	;CLEAR OUT OLD ENTRY FOR .JDAT
	DPB	T1,JBYLSA##	;STORE FIRST PAGE OF LOW SEG IN JBTAD2
	JRST	CORGT2		;CLEAR THE PAGES JUST ALLOCATED
CORGT1:	DPB	T1,JBYHSA##	;STORE THE STARTING PAGE NUMBER OF THE HIGH SEGMENT
CORGT2:	JUMPE	R,CORGT6	;ALL DONE IF THE SEGMENT HAS NO CORE AT THIS POINT
	HLRZ	T1,R		;T1 = HIGHEST RELATIVE ADDRESS SEGMENT CURRENTLY HAS
	HLRZ	T2,JBTADR##(J)	;T2 = HIGHEST RELATIVE ADDRESS SEGMENT PREVIOUSLY HAD
	JUMPN	T2,CORGT3	;JUMP IF SEGMENT HAD CORE IN CORE
	LDB	T2,IMGOUT##	;T2=AMT OF CORE SEG HAD WHEN LAST IN CORE
	LSH	T2,P2WLSH##	;CONVERT TO NUMBER OF WORDS
	SOS	T2		;HIGHEST RELATIVE ADDRESS
CORGT3:	CAMG	T1,T2		;CURRENT SEGMENT SIZE GREATER THAN PREVIOUS SIZE?
	JRST	CORGT5		;NO, NOTHING TO CLEAR
IFN FTXMON,<
	XJRST	 [MCSEC1+.+1]	;REFERENCES TO PAGTAB REQUIRE WE MUST BE IN SECTION 1
>
	SUB	T1,T2		;T1 = NUMBER OF WORDS OF INCREASE
	ADDI	T2,1		;T2 = NUMBER OF WORDS PREVIOUSLY ALLOCATED THE SEGMENT
	LSH	T2,W2PLSH##	;CONVERT TO PAGE NUMBER OF LAST PAGE
				; PREVIOUSLY ALLOCATED TO THE SEGMENT
	PUSHJ	P,ZERHGH##	;IF JOB HAS A NON-SHARABLE HI-SEG
	  JRST	@[0,,CORGT5]	; ZERO THE CORE DIFFERENTLY
	ADDM	T1,CLRWRD##	;INCREASE COUNT OF NUMBER OF WORDS CLEARED
	PUSHJ	P,SNPAGS	;GET THE ABSOLUTE PAGE NUMBER OF THE FIRST
				; NEW PAGE (PAGE TO BE CLEARED)
CORGT4:
	HRLI	T1,(<PM.DCD>B2+PM.WRT+PM.CSH+PM.AAB)

IFN FTMP&FTKL10,<
	PUSHJ	P,MLSCSH##	;IS FRECOR CACHED
	 TDZ	T1,[PM.CSH]	;NO, MUST BE UNCACHED
>
	MOVE	T2,.CPMAP##
	MOVEM	T1,.EUPMP/PAGSIZ##(T2)

	CLRPGT	(0,.EUPMP)
	MOVEI	T2,.EUPMP+1	;MAKE A BLT POINTER
	HRLI	T2,.EUPMP	;SET TO ZERO THE PAGE
	SETZM	.EUPMP		;ZERO THE FIRST WORD OF THE PAGE
	BLT	T2,.EUPMP+PAGSIZ##-1
				;ZERO THE PAGE
	ANDI	T1,17777	;CLEAR THE ACCESS BITS
	SSX	T1,MS.MEM	;SET SECTION NUMBER
	HRRZ	T1,PAGTAB(T1)	;GET THE ABSOLUTE PAGE NUMBER OF THE
				; NEXT PAGE OF THE SEGMENT
	JUMPN	T1,CORGT4	;IF NOT THE LAST PAGE ZERO IT
IFN FTXMON,<
	JRST	@[0,,.+1]	;RETURN TO SECTION 0
>
CORGT5:	HRRI	R,.VJDT		;ASSUME A HIGH SEGMENT,.I.E., RH(R) = EVA
				; OF THE VESTIGUAL JOB DATA AREA
	CAILE	J,JOBMAX##	;IS IT A HIGH SEGMENT?
	JRST	CORGT6		;NO
	HRRI	R,.JDAT		;LOW SEGMENT, RH(R) = EVA OF JOB DATA AREA
	HLRZM	R,.JDAT+JOBREL## ;STORE THE NEW SIZE OF THE LOW SEGMENT FOR THE
				; USER SO HE WON'T GET CONFUSED ON EXAMINE COMMAND
CORGT6:	SKIPE	R		;GETTING CORE?
	PUSHJ	P,IICLNK##	;YES, ADD TO IN-CORE LIST
	MOVEM	R,JBTADR##(J)	;STORE NEW PROTECTION,,RELOCATION
	LDB	T1,IMGOUT##	;CORE ALLOCATION FOR THE SWAPPER?
 	JUMPN	T1,CPOPJ1##	;YES, ALL DONE
	CAMN	J,.CPJOB##	;IS THIS THE CURRENT JOB (CORE UUO)?
	PUSHJ	P,SETREL##	;YES, SETUP THE MAP AND SOFTWARE RELOCTATION INFO.
	AOS	(P)		;GIVE SKIP (OK) RETURN
	CAILE	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	PJRST	CURHGH##	;YES SEE IF CORE WAS ALLOCATED FOR THE HIGH
				; SEGMENT WHICH THE CURRENT JOB MIGHT BE SHARING
	SKIPE	R		;DON'T STORE JOB IF CORE 0
				; NULL JOB MIGHT BE ADDRESSABLE
	MOVEM	J,.USJOB	;SAVE THE JOB NUMBER FOR DEBUGGING AND
				; VIRCHK (FOR GIVING BACK HIGH SEG CORE)
	CAMN	J,.CPJOB##	;CURRENT JOB?
	TLNN	R,MPGSIZ##	; OR ONLY ONE PAGE ALLOCATED TO THE CURRENT JOB?
				; IF ONLY 1 PAGE SETREL MIGHT NOT CALL MAPLOW
	JUMPN	R,MAPLOW	;NO, SETUP THE MAP FOR E AND D COMMANDS
	POPJ	P,		;YES, MAP IS ALREADY SETUP
;HERE IF NOT ENOUGH FREE PAGES AVAILABLE IN CORE TO SATISFY REQUEST
; INDICATE JOB IS EXPANDING AND THE REQUIRED NUMBER OF PAGES WILL BE
; ALLOCATED WHEN THE SEGMENT IS NEXT SWAPPED IN
CORGT7:	AOS	(P)		;SET FOR SKIP RETURN
	PJRST	XPAND##		;AND MARK THE JOB AS EXPANDING
;ROUTINE TO SETUP THE PORTION OF THE MAP WHICH MAPS THE
; LOW SEGMENT
;CALLING SEQUENCE:
;	PUSHJ	P,MAPLOW
;	...	ALWAYS RETURN HERE

MAPLOW::LDB	T1,PCORSZ##	;HIGHEST PAGE IN THE LOW SEGMENT
	ADDI	T1,1		;LOW SEGMENT SIZE
	PUSHJ	P,CLRWS##	;CLEAR WORKING SET BITS
	LDB	T1,[POINT 9,JBTADR##(J),8];NEW HIGHEST PAGE IN THE LOW SEGMENT
	ADDI	T1,1		;NEW LOW SEGMENT SIZE
	PUSHJ	P,ADJWS##	;SET WORKING SET BITS FOR NEW SIZE
	MOVEI	T1,.UPMAP-1
	MOVSI	T2,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.CSH+PM.AAB+PM.COR)

IFN FTLOCK,<
	MOVSI	T3,(JS.NCS)	;DON'T CACHE BIT
	TDNE	T3,JBTST2##(J)	;SHOULD CACHE BIT BE OFF IN THE MAP?
	PUSHJ	P,[TDZ T2,[PM.CSH] ;YES, CLEAR IT
		   JRST CSDMP##];AND FLUSH THE CACHE
>
	LDB	T3,JBYLSA##	;FIRST PHYSICAL PAGE IN THE LOW SEGMENT
	HLRZ	T4,JBTADR##(J)	;LOW SEGMENT SIZE
	PUSHJ	P,REMAP		;SETUP THE MAP FOR THE LOW SEGMENT
	PJRST	STEUB##		;CLEAR PAGE TABLE AND RETURN
;ROUTINE TO SETUP THE PORTION OF THE MAP WHICH MAPS THE HIGH SEGMENT
;CALLING SEQUENCE:
;	PUSHJ	P,MAPHGH
;	...	ALWAYS RETURN HERE

SETMAP::SKIPA	J,.CPJOB##	;CURRENT JOB NUMBER
REMHGH::TDZA	T3,T3		;NO HIGH SEGMENT NUMBER
MAPHGH::MOVE	T3,JBTSGN##(J)	;HIGH SEGMENT NUMBER
	PUSHJ	P,SAVE1##	;SAVE P1
	PUSHJ	P,SVEUB		;MAKE SURE THE JOB IS ADDRESSABLE
	PUSHJ	P,HSVAD##	;COMPUTE HIGH SEGMENT STARTING AND ENDING ADDRESSES
	HRRZ	T4,T3		;CLEAR JUNK FOR INDEXING (MAY BE IN SECTION 1)
	SKIPL	P1,T3		;SPY SEGMENT?
	HLRZ	P1,JBTADR##(T4)	;NO, SIZE OF THE REAL HIGH SEGMENT
	HRLZS	P1		;HIGH SEGMENT SIZE,,0
	SKIPL	USRHCU##	;SAVE IN PROGRESS?
	HRRM	T1,JOBHRL##+.JDAT ;YES, DON'T CLOBBER IOWD IN COMPRESSED LOW SEGMENT
	TLNN	T3,SHRSEG+SPYSEG  ;HIGH SEGMENT SHARABLE?
	JUMPN	T3,SCWEXO	;NO, THE MAP IS RIGHT EXCEPT FOR W.E. AND PUBLIC BITS
	SE1ENT
	LDB	T1,JBYSG2##	;SECTION OF HIGH SEG
	LSH	T1,S2PLSH##	;PAGE #
	LSH	T2,W2PLSH##
	ADD	T1,T2		;1ST PAGE
	ADD	T1,[UMAPSN+UMAPS-1] ;SET UP FOR PRE-INCREMENT
	MOVSI	T2,(<PM.DCD>B2+PM.WRT+PM.CSH+PM.NIA+PM.AAB+PM.COR)
IFN FTLOCK!FTMP,<
	TLNE	T3,NCSH+NOCSH	;CACHE?
	PUSHJ	P,[TDZ T2,[PM.CSH];NO, CLEAR THE BIT
		   JRST CSDMP##];AND FLUSH THE CACHE
>
	PUSH	P,T1		;CHKPUB CLOBBERS T1
	PUSHJ	P,CHKPUB	;SEE IF THE SEGMENT SHOULD BE CONCEALED
	  TDO	T2,[PM.PUB]	;JACCT OR NOT EXECUTE ONLY, SO MAKE PAGES PUBLIC
	POP	P,T1		;RESTORE T1
	TLNN	T3,UWPOFF	;USER WRITE PROTECT OFF?
	TDZ	T2,[PM.WRT]	;NO, DON'T ALLOW WRITE
	JUMPL	T3,SETMP1	;JUMP IF A SPY SEGMENT
	HRRZS	T3		;CLEAR LEFT HALF CRUFT
	LDB	T3,[POINT 13,JBTHSA##(T3),35] ;FIRST PHYSICAL PAGE OF THE HIGH SEGMENT
	MOVE	T4,T3
	HRLI	T4,(<PM.DCD>B2+PM.WRT+PM.PUB+PM.AAB)
	MOVEM	T4,.UPMP+.UMVJD
	HLRZ	T4,P1		;HIGH SEGMENT SIZE
	PUSHJ	P,REMAP		;MAP THE HIGH SEGMENT INTO THE USER'S ADDRESS SPACE
	JRST	SETMP3		;CONTINUE
SETMP1:	TDZ	T2,[PM.CSH]	;DON'T ALLOW USER'S TO GET THINGS
				; INTO THE CACHE THAT SHOULDN'T BE THERE
	LDB	T3,[POINT 9,P1,8];SIZE OF THE SPY SEGMENT
	TDO	T2,[PM.PUB]	;EXECUTE ONLY SPY SEG DOESN'T WORK
SETMP2:	AOS	T1		;INCREMENT
	MOVEM	T2,(T1)		;AND DEPOSIT, MAP MONITOR ADDRESSES
	AOS	T2		;STEP TO NEXT MONITOR PAGE
	SOJGE	T3,SETMP2	;MAP AS MANY PAGES AS THE USER REQUESTED
SETMP3:	LDB	T3,JBYHSS##	;PREVIOUS HIGH SEGMENT SIZE
	TLNE	P1,-1		;IF THE HIGH SEGMENT SIZE ISN'T 0,
	SUBI	T3,1		;HIGHEST PAGE IN THE HIGH SEGMENT
	LDB	T2,[POINT 9,P1,8]  ;CURRENT SIZE -1 OF THE SEGMENT IN PAGES
	PUSHJ	P,ZERMAP	;ZERO MAP SLOTS NO LONGER A PART OF THE HIGH SEGMENT
	TLNE	P1,-1		;IF THERE STILL IS A HIGH SEGMENT
	ADDI	T2,1		;COMPUTE NEW NUMBER OF PAGES IN THE HIGH SEGMENT
	DPB	T2,JBYHSS##	;STORE NEW NUMBER OF PAGES IN THE HIGH SEGMENT
	CONO	PAG,@.CPEBR##	;CLEAR THE PAGING MEMORY SO NEW MAPPING WILL BE SEEN
	POPJ	P,		;AND RETURN TO THE CALLER
;SUBROUTINE TO MAKE WRITE-ENABLE AND PUBLIC BITS RIGHT FOR A HI SEG
SCWEXO::MOVE	R,JBTADR##(J)	;MAKE SURE R IS SETUP TO POINT AT
				; THE LOW SEGMENT
	SKIPG	JBTSGN##(J)	;DOES THE JOB HAVE A REAL HIGH SEGMENT?
	POPJ	P,		;NO
	DMOVE	T1,.USHSE	;ORIGIN, HIGHEST ADDRESS IN THE HIGH SEGMENT
	JUMPE	T1,CPOPJ##	;DO NOTHING IF HIGH SEGMENT SIZE=0
	DMOVE	T3,T1		;COPY NUMBERS
	LSHC	T3,W2PLSH##	;ORIGIN PAGE, HIGHEST PAGE
	PUSHJ	P,CHKPUB	;SEE IF THE HIGH SEGMENT SHOULD BE CONCEALED
	  TLO	T3,400000	;NO, MAKE THE HIGH SEGMENT PUBLIC
	LDB	T1,JBYSG2##	;SECTION # OF HIGH SEG
	LSH	T1,S2PLSH##	;PART OF PAGE #
	IORI	T1,(T4)		;AND PUT IN REST
	SE1ENT			;FOR PAGE MAP REFERENCES
SCWEX1:	PUSHJ	P,TSWST##	;IS THIS PAGE IN THE WORKING SET?
	  JRST	SCWEX2		;NO, SKIP IT
	PUSHJ	P,GTPME##	;GET CONTESTS OF MAP
	TLO	T2,(PM.NIA)	;NO I/O ALLOWED
	TDZ	T2,[PM.WRT+PM.PUB] ;ASSUME WRITE-LOCKED AND EXECUTE ONLY
	SKIPGE	T3		;PUBLIC?
	TDO	T2,[PM.PUB]	;YES, TURN ON THE PUBLIC BIT
	MOVEM	T2,(T4)		;STORE BACK IN THE MAP WITH NEW ATTRIBUTES
SCWEX2:	MOVEI	T2,HLGPNO	;IGNORE SECTION # HERE
	ANDI	T2,(T1)
	CAIE	T2,(T3)		;LAST PAGE?
	AOJA	T1,SCWEX1	;NO, LOOP OVER ALL HIGH SEGMENT PAGES
	CONO	PAG,@.CPEBR##	;CLEAR THE PAGING MEMORY SO NEW MAPPING WILL BE SEEN
	POPJ	P,		;RETURN

;SUBROUTINE TO SEE IF A HIGH SEGMENT SHOULD BE CONCEALED, CALL WITH J =
; JOB NUMBER, RETURNS CPOPJ1 IF SO

CHKPUB::MOVE	T1,JBTSGN##(J)	;THIS USER'S HIGH SEGMENT BITS
	TLNN	T1,GTSSEG	;SEGMENT GETSEGED?
	POPJ	P,		;NO, ALWAYS PUBLIC
IFN FTFDAE,<
	MOVSI	T1,(JS.FXO)	;XO BY THE FILE DAEMON BIT
	TDNE	T1,JBTST2##(J)	;IS IT EXECUTE ONLY ?
	JRST	CPOPJ1##	;YES, MAKE IT CONCEALED
>
	MOVE	T1,JBTSTS##(J)	;CURRENT JOB STATUS
	TLNN	T1,JACCT	;A PRIVLEDGED PROGRAM (TOO STUPID TO BE XO)?
	TRNN	T1,JS.XO	;AN EXECUTE ONLY PROGRAM?
	POPJ	P,		;NO, MAKE THE HIGH SEGMENT PUBLIC
	JRST	CPOPJ1##	;YES, MAKE IT CONCEALED
;SUBROUTINE TO SETUP THE USER PAGE MAP PAGE TO REFLECT THE LOCATION
; OF THE PAGES OF A SEGMENT IN PHYSICAL MEMORY
;CALLING SEQUENCE:
;	MOVE	T1,BYTE POINTER TO THE MAP
;	MOVE	T2,PAGE ATTRIBUTES
;	MOVE	T3,ABSOLUTE PAGE NUMBER OF FIRST PAGE OF THE SEGMENT
;	MOVE	T4,HIGHEST ADDRESS IN THE SEGMENT
;	PUSHJ	P,REMAP
;	...	ALWAYS RETURN HERE

REMAP:	JUMPE	T4,CPOPJ##	;IF THE SEGMENT IS ZERO LENGTH RETURN
	SE1ENT			;MUST BE IN SECTION 1
	LSH	T4,W2PLSH##	;CONVERT TO NUMBER OF PAGES - 1
REMAP1:	TDO	T3,T2		;ABSOLUTE PAGE NUMBER PLUS ACCESS BITS
	AOS	T1
	MOVEM	T3,(T1)		;STORE PHYSICAL LOCATION OF THE PAGE AND
				; THE ACCESS BITS IN THE MAP
	TDZ	T3,T2		;CLEAR ACCESS BITS
	SSX	T3,MS.MEM	;SET SECTION NUMBER
	HRRZ	T3,PAGTAB(T3)	;GET THE ABSOLUTE PAGE NUMBER OF THE NEXT
				; PAGE IN THE SEGMENT
	SOJL	T4,CPOPJ##	;RETURN IF ALL THE PAGES IN THE SEGMENT
				; HAVE BEEN MAPPED
	JUMPG	T3,REMAP1	;MAP ALL THE PAGES IN THE SEGMENT
	STOPCD	.,STOP,PMU,	;++PAGTAB MESSED UP

;ROUTINE TO DETERMINE IF THE SIZE OF A SEGMENT HAS CHANGED SINCE THE LAST
; TIME THE JOB WHOSE ADDRESSING SPACE CONTAINS THIS SEGMENT WAS RUN.  IF THE
; SEGMENT IS SMALLER THAN THE IT PREVIOUSLY WAS, THE ROUTINE
; ZEROES THE LOCATIONS IN THE MAP WHICH CORRESPOND TO THE PAGES REMOVED FROM
; THE SEGMENT (OR ALL THE LOCATIONS IF THE SEGMENT WAS REMOVED) SO THE JOB
; WILL PAGE FAIL ON AN ILLEGAL MEMORY REFERENCE
;CALLING SEQUENCE:
;	MOVE	T3,PREVIOUS SEGMENT SIZE IN PAGES - 1
;	PUSHJ	P,ZERMAP
;	...	ALWAYS RETURN HERE - T2 = CURRENT SEGMENT SIZE IN PAGES - 1

ZERMAP:	SUBI	T3,(T2)		;NEW SIZE MINUS OLD SIZE
	JUMPLE	T3,CPOPJ##	;RETURN IF THE SEGMENT IS THE SAME
				; SIZE OR BIGGER THAN IT WAS THE LAST TIME
				; THE JOB WAS RUN
ZRMAP1:	AOS	T1		;INCREMENT
	SETZM	(T1)		;ZERO
	SOJG	T3,ZRMAP1	; ILLEGAL MEMORY REFERENCE
	POPJ	P,		;RETURN
;SUBROUTINE TO RETURN PAGES TO THE LINKED LIST OF FREE PAGES AND UPDATE
; BIGHOL (THE TOTAL NUMBER OF FREE PAGES) AND CORTAL (THE TOTAL NUMBER
; OF FREE PAGES PLUS THE NUMBER OF PAGES OCCUPIED BY
; DORMANT OR IDLE SEGMENTS)
;CALLING SEQUENCE:
;	MOVE	T1,FIRST PAGE TO RETURN TO THE FREE CORE LIST
;	PUSHJ	P,GVPAGS
;	ALWAYS RETURN HERE

GVPAGS::
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN THE MM RESOURCE?
	  PUSHJ	P,MMDIE		;NO, MUST DIE
>
	SE1ENT			;MUST BE IN SECTION 1 TO REFERENCE PAGTAB
	HRRZS	T2,T1		;T2 = FIRST PAGE TO RETURN (CLEAR ANY JUNK IN LH)
	EXCH	T1,PAGPTR##	;STORE FIRST PAGE TO FREE AS FIRST PAGE ON THE
				; FREE CORE LIST AND GET FIRST PAGE ON CURRENT LIST
	PUSH	P,T1		;SAVE
	SSX	T2,MS.MEM
	HRRZ	T1,PT2TAB(T2)	;GET BACK LINK (IF ANY)
	SKIPE	T1		;IGNORE IF NONE
	HLLZS	@[IW MS.MEM,PAGTAB(T1)] ;CLEAR BACK LINK
	HLLZS	PT2TAB(T2)	;NO BACK LINK
	MOVSI	T1,(P2.LIP)	;LOKCON CHECK
	MOVEI	T3,1		;AT LEAST ONE PAGE IS BEING RETURNED
GVPAG1:	MOVSI	T4,FREPAG	;THIS PAGE IS ON THE FREE CORE LIST BIT
	SSX	T2,MS.MEM	;SET SECTION NUMBER
	TDNE	T4,PAGTAB(T2)	;PAGE MUST NOT BE FREE ALREADY
	STOPCD	.,STOP,ARF,	;++ATTEMPT TO RETURN FREE PAGE
	IORB	T4,PAGTAB(T2)	;MARK THIS PAGE AS BEING ON THE FREE CORE LIST
				; AND GET THE NEXT PAGE TO BE RETURNED
	TDNN	T1,PT2TAB(T2)	;LOKCON WAITING FOR THIS PAGE?
	JRST	GVPAG5		;NO, PROCEED
	HRRZ	T1,PT2TAB(T2)	;YES, PREVIOUS PAGE TO THIS ONE
	SSX	T4,MS.MEM	;SET SECTION IN SUCCESSOR
	SSX	T1,MS.MEM	;AND PREDECESSOR
	TRNE	T4,-1		;IS THE A SUCCESSOR?
	HRRM	T1,PT2TAB(T4)	;YES, SET OUR PREDECESSOR AS HIS
	PUSH	P,T1		;FOR IF WE EXIT
	TRNN	T1,-1		;IS THIS FIRST PAGE ON FREE LIST?
	MOVEI	T1,PAGPTR-PAGTAB ;YES, SET TO STORE IN PAGPTR
	HRRM	T4,PAGTAB(T1)	;STORE SUCCESSOR
	SOS	T3		;UNDO THE FOLLOWING AOJA
	AOS	LOKHOL##	;ONE MORE PAGE IN LOKCON'S QUEUE
	AOS	LOKTAL##	;AND LOKCON'S VERSION OF CORTAL
	HRRZ	T1,LOKPTR##	;FIRST PAGE IN LOKCON'S QUEUE
	SSX	T1,MS.MEM	;IN CASE POINTED @PAGPTR
	HRRM	T1,PAGTAB(T2)	;IS NOW OUR SUCCESSOR
	HRRZM	T2,LOKPTR##	;WE ARE NOW FIRST
	HLLZS	PT2TAB(T2)	;WE HAVE NO PREDECESSOR
	TRNE	T1,-1		;DO WE HAVE A SUCCESSOR?
	HRRM	T2,PT2TAB(T1)	;YES, SET US AS PREDECESSOR
	MOVSI	T1,(P2.LIP)	;RESTORE T1
	POP	P,T2		;REAL LAST PAGE ON FREE LIST
GVPAG5:	TRNN	T4,-1		;LAST PAGE TO BE RETURNED?
	JRST	GVPAG2		;YES, UPDATE BIGHOL AND CORTAL AND RETURN
	HRRZ	T2,T4		;INDEX TO NEXT PAGE TO FREE
	AOJA	T3,GVPAG1	;COUNT NUMBER OF PAGES FREED AND RETURN NEXT PAGE
GVPAG2:	POP	P,T1		;RESTORE T1 (OLD PAGPTR)
	TRNN	T2,-1
	MOVEI	T2,PAGPTR-PAGTAB ;THEN POINT AT PAGPTR
	HRRM	T1,PAGTAB(T2)	;LINK THE REST OF THE FREE CORE LIST TO THE PAGES
	SSX	T1,MS.MEM
				; FREED
	ADDM	T3,BIGHOL##	;UPDATE THE AMOUNT OF FREE CORE BY THE NUMBER
				; OF PAGES FREED
	ADDM	T3,CORTAL##	;ALSO, UPDATE THE AMOUNT OF POTENTIALLY FREE CORE
IFN FTMP&FTKL10,<
	SETOM	SAVCTL##	;MAKE SURE A SWEEP HAPPENS
>
	CAIE	T2,PAGPTR-PAGTAB ;ALREADY SET IF NO PAGES ADDED
	TRNN	T1,-1		;OR IF THERE WERE NO PAGES
	POPJ	P,		;THEN RETURN NOW
	HRRM	T2,PT2TAB(T1)
	POPJ	P,		;AND RETURN
;SUBROUTINE TO FIND THE NTH PAGE FOR N.LT.THE NUMBER OF PAGES
; ASSIGNED TO THE JOB OR THE JOBS LAST PAGE
;CALLING SEQUENCE:
;	PUSHJ	P,SCPAGS	;TO FIND THE LAST PAGE OF THE JOB
;OR
;	PUSHJ	P,SNPAGS	;TO FIND THE NTH PAGE OF A JOB
;	RETURN HERE - T1 = PAGE NUMBER OF THE NTH PAGE

SCPAGS::MOVEI	T2,-1		;STOP AFTER SCANNING ALL PAGES
SNPAGS::
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN THE MM RESOURCE?
	  PUSHJ	P,MMDIE		;NO, MUST DIE
>
	SE1ENT			;MUST BE IN SECTION 1 TO REFERENCE PAGTAB
	PUSH	P,J		;SAVE J
IFN FTXMON,<
	HRRZS	J		;COULD BE IN SECTION 1 AND LH OF J CONTAINS CRUFT
>
	LDB	T3,JBYHSA##	;PHYSICAL PAGE NUMBER OF PAGE 0 IN THE LOW SEGMENT
	CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	LDB	T3,JBYLSA##	;YES, PHYSICAL PAGE NUMBER OF FIRST PAGE OF
				; THE HIGH SEGMENT
	POP	P,J		;RESTORE SEGMENT NUMBER
SNPAG1::HRRZ	T1,T3		;CURRENT PAGE WITHIN THE SEGMENT
	SSX	T1,MS.MEM	;SET SECTION NUMBER
	SKIPGE	T3,PAGTAB(T1)	;GET NEXT PAGE IN THE SEGMENT
	STOPCD	.,STOP,PSF,	;++PAGE IN SEGMENT FREE
	TRNE	T3,-1		;IS THIS THE LAST PAGE IN THE SEGMENT?
	SOJGE	T2,SNPAG1	;NO, IS THIS THE NTH PAGE WITHIN THE SEGMENT?
	HRRZS	T1		;RETURN ONLY THE PHYSICAL PAGE NUMBER
	POPJ	P,		;YES, RETURN WITH T1 = NTH OR LAST PAGE
;SUBROUTINE TO GET PAGES FROM THE LINKED LIST OF FREE PAGES AND
; UPDATE CORTAL AND BIGHOL
;CALLING SEQUENCE:
;	MOVE	T1,WHERE TO BEGIN ALLOCATION IF ADDING PAGES
;	MOVE	T2,NUMBER OF PAGES TO ALLOCATE
;	PUSHJ	P,ADPAGS	;OR
;	PUSHJ	P,GTPAGS	;IF NO PAGES ARE CURRENTLY ALLOCATED
;	ALWAYS RETURN HERE - T1 = PAGE NUMBER OF FIRST PAGE ALLOCATED

ADPAGS::MOVE	T4,PAGPTR##	;FIRST FREE PAGE
	SE1ENT			;GET TO SECTION 1
	SSX	T1,MS.MEM	;SET SECTION INDEX
	PUSH	P,PAGTAB(T1)	;SAVE PREVIOUS LINK
	HRRM	T4,PAGTAB(T1)	;LINK IT TO THE PAGES CONTAINED IN THIS SEGMENT
	MOVE	T4,T1		;PRE-LOAD PAGE
	JRST	GTPAG0
GTPAGS::
	SETZ	T4,
	SE1ENT			;GET TO SECTION 1
	PUSH	P,T4		;VALUE TO PUT ON END OF PAGTAB CHAIN
GTPAG0:
IFN FTMP,<
	PUSHJ	P,MMOWN##	;OWN THE MM RESOURCE?
	  PUSHJ	P,MMDIE		;NO, MUST DIE
>
	SKIPN	T1,PAGPTR##	;GET FIRST FREE PAGE
	STOPCD	.,STOP,PEZ,	;++PAGPTR=0
	MOVNS	T2		;MINUS NUMBER OF PAGES BEING ALLOCATED
	ADDM	T2,BIGHOL##	;DECREASE THE NUMBER OF FREE PAGES BY THAT AMOUNT
	ADDM	T2,CORTAL##	;AND THE NUMBER OF POTENTIALLY FREE PAGES
	MOVE	T3,T1		;FIRST PAGE TO ALLOCATE
GTPAG1:	SSX	T3,MS.MEM
	HRRM	T4,PT2TAB(T3)	;SET PREVIOUS POINTER (CLEARING REST)
	HRRZ	T4,T3		;ALLOCATE THIS PAGE
	MOVSI	T3,FREPAG	;PREPARE TO MARK THIS PAGE AS IN-USE
	SKIPN	T4		;END OF THE FREE CORE LIST?
	STOPCD	.,STOP,FPI,	;++FREE PAGE INUSE
	SSX	T4,MS.MEM	;SET SECTION INDEX
	ANDCAB	T3,PAGTAB(T4)	;CLEAR THE BIT INDICATING A FREE PAGE AND GET
				; THE NEXT PAGE ON THE FREE CORE LIST
	AOJL	T2,GTPAG1	;LOOP UNTIL ALL PAGES REQUESTED ARE ALLOCATED
	HRRZM	T3,PAGPTR##	;STORE THE NEW FIRST PAGE IN THE FREE CORE LIST
	SSX	T3,MS.MEM
	HLLZS	PT2TAB(T3)	;IT HAS NO BACK LINK NOW
	POP	P,T3		;THE BEGINNING OF THE REST OF THE CHAIN
	HRRZM	T3,PAGTAB(T4)	;POINT NEW PART TO OLD PART
	JUMPE	T3,CPOPJ##	;RETURN IF NO BACK LINK TO UPDATE
	SSX	T3,MS.MEM	;POINT TO PAGTAB SECTION
	HRRM	T4,PT2TAB(T3)	;UPDATE BACK LINK
	POPJ	P,		;AND RETURN TO THE CALLER

;HERE IF TRYING TO DO CORE ALLOCATION WITHOUT THE MM RESOURCE
IFN FTMP,<
MMDIE::	STOPCD	.,STOP,DOM,	;DON'T OWN MM RESOURCE
>
;*** THIS PROBABLY CAN BE MADE TO DO SOME REASONABLE RECOVERY
SUBTTL	SWAP - USER PROGRAM SWAPPING ROUTINES

;SUBROUTINE TO SETUP THE MAP FOR A JOB WHICH WAS JUST SWAPPED IN
; THIS INCLUDES THE TRAP LOCATIONS AS WELL AS THE MAP ITSELF
;CALLING SEQUENCE:
;	MOVE	J,JOB NUMBER OF JOB JUST SWAPPED IN
;	MOVE	R,XWD LOW SEGMENT SIZE, EVA OF THE JOB DATA AREA
;	SETUP THE USER BASE REGISTER TO POINT TO THIS JOB'S UPMP
;	PUSHJ	P,MAPUSR
;	ALWAYS RETURN HERE

MAPUSR::PUSHJ	P,SVEUB		;MAKE THE MAP ADDRESSABLE
	MOVE	R,JBTADR##(J)	;R=WXD LOW SEGMENT SIZE, ADDRESS OF JOB DATA AREA
	PJRST	MAPHGH		;MAP THE HIGH SEGMENT
SUBTTL	SWPSER - SWAPPING SERVICE ROUTINE

;SUBROUTINE TO MAKE THE FIRST WORD OF A SEGMENT ADDRESSABLE FOR JBTCHK
; CALLING SEQUENCE:
;	MOVE	T1,IOWD USED FOR SWAPPING
;	MOVE	J,SEGMENT NUMBER OF SEGMENT SWAPPED IN OR OUT
;	PUSHJ	P,GETCHK
;	ALWAYS RETURN HERE
;T1 = EXEC VIRTUAL ADDRESS OF WORD 0 OF THE SEGMENT.  IF THIS IS A LOW
; SEGMENT, JUST SETUP THE UBR SINCE T1 CONTAINS THE ADDRESS OF WORD 0
; OF THE SEGMENT MAPPED THROUGH THE PER PROCESS MAP.  IF THIS IS A HIGH
; SEGMENT, MAP WORD 0 THROUGH THE EXEC MAP SINCE THE SEGMENT MAY BE
; DORMANT OR IDLE AND THUS NOT APPEAR IN ANY USERS MAP.

GETCHK::CAIG	J,JOBMAX##	;IS THIS A HIGH SEGMENT?
	SKIPA	T1,JBYLSA##	;LOW SEG
	MOVE	T1,JBYHSA##	;HIGH SEG
	LDB	T1,T1		;ABSOLUTE PAGE #

;SUBROUTINE TO MAKE A PHYSICAL PAGE ADDRESSABLE FOR SWAPPER
;CALLING SEQUENCE:
;	MOVEI	T1,PAGE NUMBER
;	PUSHJ	P,SWPAD
;	ALWAYS RETURNS HERE
;T1=EVA OF FIRST WORD IN PAGE
;PRESERVES T2-T4
SWPAD::	PUSHJ	P,SAVE1##
	MOVE	P1,.CPMAP##
	HRLI	T1,(<PM.DCD>B2+PM.WRT+PM.PUB)
	MOVEM	T1,.ECKSM/PAGSIZ##(P1)
	CLRPGT	(0,.ECKSM)	;FLUSH THE ASSOCIATIVE MEMORY SO THE NEW MAPPING
	     	      		; WILL BE IN EFFECT
	MOVEI	T1,.ECKSM	;T1 = EXEC VIRTUAL ADDRESS OF WORD 0 OF THE
				; HIGH SEGMENT
	POPJ	P,		;RETURN
;ROUTINE TO CLEAR PART OF JOB DATA AREA(PART PROTECTED FROM USER IO)
;CALLED WHEN SWAP READ ERROR AND AT SYSTEM RESTART(140)
;	MOVE	J,JOB NO.
;CALL:	MOVE	R,ADDRESS OF JOB DATA AREA
;	PUSHJ	P,CLRJOB

CLRJOB::PUSHJ	P,SVEUB##	;MAKE SURE JOB DATA AREA IS ADDRESSABLE
	SETZM	USRPRT##	;FIRST LOC. PROTECTED FROM USER
	MOVSI	T1,USRPRT##
	HRRI	T1,USRPR1##
	MOVE	T2,.JDAT+JOBDDT##	;SAVE DDT STARTING ADDRESS
	BLT	T1,USRJDA##+17
	MOVEM	T2,.JDAT+JOBDDT##
	SETZM	.JDAT+JOBENB##	;ALSO CLEAR APR ENABLE WORD
	SETZM	.JDAT+JOBPD1##	;AND UUO PC FLAGS(USED WHEN JOB STARTS)
	PJRST	ESTOP1##	;GO SET JOB STATUS NOT BE ALLOWED
				;NOTE JACCT IS CLEARED

	SUBTTL	CORE ALLOCATION  --  EXTENSIBLE BITMAP MEMORY ROUTINES


;ROUTINES CALLED TO ALLOCATE EXTENSIBLE BITMAP MEMORY
;LINKAGE:
;	T2/ NUMBER OF WORDS
;	T3/ ADDRESS OF ALLOCATION CONTROL BLOCK
;	PUSHJ	P,GTXWDS
;RETURNS:
;	CPOPJ ON ALLOCATION ERROR
;	CPOPJ1 ON SUCCESS WITH:
;	T1/ ADDRESS OF MEMORY ALLOCATED

GTXWDS::TDZA	T1,T1		;CLEAR ZERO FLAG AND SKIP
GTXWDZ::SETO	T1,		;SET ZERO FLAG
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSH	P,T1		;SAVE ZERO FLAG
	MOVE	P4,T3		;SAVE ADDRESS OF ALLOCATION CONTROL BLOCK
	SKIPN	P3,ACBAHB(P4)	;GET ADDRESS OF ALLOCATION HEADER BLOCK
	STOPCD	CPOPJ##,DEBUG,CORNAH ;++NO ALLOCATION HEADER BLOCK
	IDIV	T2,AHBCSZ(P3)	;COMPUTE NUMBER OF CHUNKS TO ALLOCATE
	SKIPE	T3		;ANY REMAINDER?
	ADDI	T2,1		;YES, ROUND UP
	IMUL	T2,AHBCSZ(P3)	;CONVERT BACK INTO WORDS
	MOVE	P1,T2		;SAVE IN P1

GTXWD0:	MOVE	T1,P1		;GET WORD COUNT
	ADDB	T1,ACBUSD(P4)	;UPDATE ALLOCATOR'S COUNT OF USED MEMORY
	CAMLE	T1,ACBMAX(P4)	;WITHIN MAXIMUM ALLOWABLE AMOUNT?
	JRST	GTXWX1		;NO, GO FIX COUNT AND RETURN
	CAMLE	T1,ACBHWM(P4)	;GREATER THAN PREVIOUS HIGH WATER MARK?
	MOVEM	T1,ACBHWM(P4)	;YES, STORE NEW HIGH WATER MARK

	MOVN	T1,P1		;GET NEGATIVE WORD COUNT
	ADDB	T1,AHBFRE(P3)	;UPDATE HEADER BLOCK'S COUNT OF FREE WORDS
	JUMPL	T1,GTXWX2	;IF NOT ENOUGH, GO TRY AND EXTEND POOL
	CAMGE	T1,AHBLWM(P3)	;LESS THAN PREVIOUS LOW WATER MARK?
	MOVEM	T1,AHBLWM(P3)	;YES, STORE NEW LOW WATER MARK

	SKIPA	P2,AHBAEB(P3)	;GET ADDRESS OF FIRST ALLOCATION EXTENT BLOCK
GTXWD1:	MOVE	P2,AEBNXT(P2)	;GET ADDRESS OF NEXT ALLOCATION EXTENT BLOCK
	JUMPE	P2,GTXWX2	;AT END OF LIST, GO ATTEMPT TO EXTEND POOL
	MOVE	T1,P1		;GET NUMBER OF WORDS TO ALLOCATE
	IDIV	T1,AHBCSZ(P3)	;CONVERT INTO CHUNKS
	MOVEI	T2,AEBBMP(P2)	;GET ADDRESS OF BIT MAP AOBJN POINTER
	CAMG	P1,AEBFRE(P2)	;DOES THIS EXTENT HAVE ENOUGH FREE WORDS?
	PUSHJ	P,GETBIT	;YES, TRY TO ALLOCATE CORE
	  JRST	GTXWD1		;FAILED, LOOP BACK FOR NEXT ALLOCATION EXTENT
	IMUL	T1,AHBCSZ(P3)	;COMPUTE WORD OFFSET OF ALLOCATION
	ADD	T1,AEBADR(P2)	;COMPUTE ADDRESS OF ALLOCATION
	EXCH	T1,(P)		;SAVE ADDRESS, GET BACK ZERO FLAG

				;CONTINUED ON NEXT PAGE
				;CONTINUED FROM PREVIOUS PAGE

	MOVN	T2,P1		;GET NEGATIVE WORD COUNT
	ADDB	T2,AEBFRE(P2)	;UPDATE EXTENT BLOCK'S COUNT OF FREE WORDS
	CAMGE	T2,AEBLWM(P2)	;LESS THAN PREVIOUS LOW WATER MARK?
	MOVEM	T2,AEBLWM(P2)	;YES, STORE NEW LOW WATER MARK

	JUMPE	T1,GTXWD2	;JUMP IF NOT ZEROING ALLOCATED CORE

IFE FTXMON,<
	MOVS	T1,(P)		;GET STARTING ADDRESS OF ALLOCATION
	HLRI	T1,1(T1)	;GET ADDRESS OF SECOND WORD OF ALLOCATION
	MOVE	T2,P1		;GET NUMBER OF WORDS ALLOCATED
	ADD	T2,(P)		;COMPUTE LAST ADDRESS+1 TO ZERO WITH BLT
	SETZM	-1(T1)		;ZERO FIRST WORD OF ALLOCATION
	CAIE	T2,(T1)		;IS ALLOCATION ONE WORD LONG?
	BLT	T1,-1(T2)	;NO, ZERO REMAINDER OF ALLOCATION
>; END IFE FTXMON
IFN FTXMON,<
	MOVE	T1,P1		;GET NUMBER OF WORDS ALLOCATED
	SUBI	T1,1		;COMPUTE WORDS TO ZERO WITH XBLT
	MOVE	T2,(P)		;GET STARTING ADDRESS OF ALLOCATION
	MOVE	T3,T2		;GET ADDRESS OF SECOND WORD OF ALLOCATION
	ADDI	T3,1		;...
	SETZM	(T2)		;ZERO FIRST WORD OF ALLOCATION
	EXTEND	T1,[XBLT]	;ZERO REMAINDER OF ALLOCATION
>; END IFN FTXMON

GTXWD2:	MOVE	T1,AHBFRE(P3)	;GET HEADER BLOCKS'S COUNT OF FREE WORDS
	ADD	T1,AHBPND(P3)	;PLUS CURRENT PENDING ALLOCATION AMOUNT
	CAMGE	T1,AHBTHR(P3)	;BELOW ALLOCATION THRESHOLD?
	PUSHJ	P,GTXXTD	;YES, GO TRY TO EXTEND POOL
	  JFCL			;DON'T CARE IF EXTENSION FAILED OR PENDING
	PJRST	TPOPJ1##	;RESTORE ADDRESS OF ALLOCATION AND RETURN


;HERE IF REQUESTED AMOUNT WOULD PUT ALLOCATOR OVER MAXIMUM

GTXWX1:	MOVN	T1,P1		;GET NEGATIVE WORD COUNT
	ADDM	T1,ACBUSD(P4)	;FIX ALLOCATOR'S COUNT OF USED MEMORY
	PJRST	TPOPJ##		;CLEAN STACK AND RETURN

;HERE TO EXTEND A BITMAP MEMORY POOL

GTXWX2:	ADDM	P1,AHBFRE(P3)	;FIX HEADER BLOCK'S COUNT OF FREE WORDS
	MOVN	T1,P1		;GET NEGATIVE WORD COUNT
	ADDM	T1,ACBUSD(P4)	;FIX ALLOCATOR'S COUNT OF USED MEMORY
	PUSHJ	P,GTXXTD	;EXTEND ALLOCATOR'S POOL IF POSSIBLE
	  PJRST	TPOPJ##		;FAILED OR PENDING, CLEAN STACK AND RETURN
	JRST	GTXWD0		;LOOP BACK TO TRY WITH LARGER POOL
;ROUTINE CALLED TO EXTEND A BITMAP MEMORY POOL
;LINKAGE:
;	P3/ ADDRESS OF ALLOCATION HEADER BLOCK
;	PUSHJ	P,GTXXTD
;RETURNS:
;	CPOPJ IF EXTENSION FAILED OR PENDING
;	CPOPJ1 IF EXTENSION COMPLETED

GTXXTD:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	MOVE	P1,AHBMIN(P3)	;GET MINIMUM FREE ALLOCATION AMOUNT
	SUB	P1,AHBFRE(P3)	;COMPUTE TARGET INCREMENTAL ALLOCATION
	SUB	P1,AHBPND(P3)	;...
	TRZE	P1,PG.BDY##	;ROUND UP TO PAGE BOUNDARY
	ADDI	P1,PAGSIZ##	;...
	PJMPLE	P1,CPOPJ##	;RETURN IF DON'T NEED INCREMENTAL ALLOCATION
	CAMGE	P1,AHBINC(P3)	;LESS THAN INCREMENTAL ALLOCATION AMOUNT?
	MOVE	P1,AHBINC(P3)	;YES, GET INCREMENTAL ALLOCATION AMOUNT
	MOVE	T1,AHBMAX(P3)	;GET MAXIMUM ALLOCATION AMOUNT
	SUB	T1,AHBCUR(P3)	;COMPUTE MAXIMUM AMOUNT TO ADD TO ALLOCATION
	SUB	T1,AHBPND(P3)	;...
	CAMLE	P1,T1		;LESS THAN TARGET INCREMENTAL ALLOCATION
	MOVE	P1,T1		;YES, USE MAXIMUM INCREMENTAL ALLOCATION
	PJMPLE	P1,CPOPJ##	;RETURN NOW IF AT MAXIMUM ALLOCATION

	MOVE	T2,P1		;GET INCREMENTAL ALLOCATION AMOUNT
	IDIV	T2,AHBCSZ(P3)	;COMPUTE INCREMENTAL NUMBER OF CHUNKS
	ADDI	T2,^D35		;CALCULATE NUMBER OF WORDS FOR BITMAP
	IDIVI	T2,^D36		;...
	ADDI	T2,AEBLEN	;ADD IN SIZE OF ALLOCATION EXTENT BLOCK
	PUSHJ	P,GETWDS	;ALLOCATE SECTION 0 CORE
	  POPJ	P,		;FAILED, RETURN NOW
	MOVE	P2,T1		;SAVE ADDRESS OF ALLOCATION EXTENT BLOCK

	MOVEM	P1,AEBSIZ(P2)	;INITIALIZE EXTENT BLOCK'S EXTENT SIZE
	MOVEM	P1,AEBFRE(P2)	;AND COUNT OF FREE WORDS
	MOVEM	P1,AEBLWM(P2)	;AND LOW WATER MARK
	MOVE	T2,P1		;GET INCREMENTAL ALLOCATION AMOUNT
	IDIV	T2,AHBCSZ(P3)	;CONVERT TO CHUNKS
	ADDI	T2,^D35		;CALCULATE NUMBER OF WORDS FOR BITMAP
	IDIVI	T2,^D36		; (REMAINDER IN T3)
	MOVN	T1,T2		;BUILD AOBJN POINTER TO BIT MAP
	HRLZS	T1		;...
	HRRI	T1,AEBBMP+1(P2)	;...
	MOVEM	T1,AEBBMP(P2)	;AND SAVE IN EXTENT BLOCK
	SETZM	AEBBMP+1(P2)	;ZERO FIRST WORD OF BITMAP
	MOVSI	T1,AEBBMP+1(P2)	;CONSTRUCT BLT POINTER TO CLEAR BITMAP
	HRRI	T1,AEBBMP+2(P2)	;...
	ADDI	T2,AEBBMP+1(P2)	;CALCULATE ADDRESS OF WORD FOLLOWING BITMAP
	CAIE	T2,AEBBMP+2(P2)	;IS BITMAP ONE WORD LONG?
	BLT	T1,-1(T2)	;NO, ZERO REMAINDER OF BITMAP

				;CONTINUED ON NEXT PAGE
				;CONTINUED FROM PREVIOUS PAGE

	SUBI	T3,^D35		;CALCULATE NUMBER OF BITS TO MARK OFF
	MOVNS	T3		; IN LAST WORD OF BITMAP
	SETO	T1,		;START WITH A COMPLETE MASK
	LSH	T1,(T3)		;COMPUTE MASK OF BITS TO KEEP
	SETCAM	T1,-1(T2)	;MARK OFF APPROPRIATE BITS IN LAST WORD

	ADDM	P1,AHBPND(P3)	;UPDATE HEADER BLOCK'S PENDING ALLOCATION
	MOVE	T1,P1		;GET INCREMENTAL ALLOCATION AMOUNT
	LSH	T1,W2PLSH##	;CONVERT TO PAGES
	HRL	T1,AHBSEC(P3)	;GET SECTION NUMBER FOR ALLOCATION
	XMOVEI	T2,GTXXT1	;GET ADDRESS OF CALLBACK ROUTINE
	MOVE	T3,P2		;GET ADDRESS OF ALLOCATION EXTENT BLOCK
	MOVE	T4,P3		;AND ADDRESS OF ALLOCATION HEADER BLOCK
	PJRST	GETCLP##	;QUEUE ALLOCATION REQUEST AND RETURN

;HERE ON ALLOCATION COMPLETION CALLBACK

GTXXT1:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVE	P2,T3		;GET BACK ADDRESS OF ALLOCATION EXTENT BLOCK
	MOVE	P3,T4		;AND ADDRESS OF ALLOCATION HEADER BLOCK
	MOVEM	T1,AEBADR(P2)	;STORE ALLOCATED ADDRESS OF NEW EXTENT
	MOVE	P1,AEBSIZ(P2)	;GET SIZE OF ALLOCATION EXTENT

	SKIPA	T1,AHBAEB(P3)	;GET ADDRESS OF FIRST ALLOCATION EXTENT BLOCK
GTXXT2:	MOVE	T1,AEBNXT(T1)	;GET ADDRESS OF NEXT ALLOCATION EXTENT BLOCK
	SKIPE	AEBNXT(T1)	;FOUND END OF EXTENT BLOCK CHAIN?
	JRST	GTXXT2		;NO, LOOP BACK
	SETZM	AEBNXT(P2)	;LINK NEW EXTENT BLOCK AT END OF CHAIN
	MOVEM	P2,AEBNXT(T1)	;...

	MOVN	T1,P1		;GET NEGATIVE INCREMENTAL ALLOCATION AMOUNT
	ADDM	T1,AHBPND(P3)	;UPDATE HEADER BLOCK'S PENDING AMOUNT
	ADDM	P1,AHBCUR(P3)	;AND CURRENT ALLOCATION AMOUNT
	ADDM	P1,AHBFRE(P3)	;AND CURRENT FREE WORD AMOUNT
	POPJ	P,		;RETURN
;ROUTINE CALLED TO DEALLOCATE EXTENSIBLE BITMAP MEMORY
;LINKAGE:
;	T1/ NUMBER OF WORDS
;	T2/ ADDRESS OF MEMORY
;	T3/ ADDRESS OF ALLOCATION CONTROL BLOCK
;	PUSHJ	P,GVXWDS
;RETURNS:
;	CPOPJ ALWAYS

GVXWDS::PUSHJ	P,SAVE4##	;SAVE P1-P4
	MOVE	P4,T3		;SAVE ADDRESS OF ALLOCATION CONTROL BLOCK
	MOVE	P3,ACBAHB(P4)	;GET ADDRESS OF ALLOCATION HEADER BLOCK
	MOVE	P1,T1		;GET SIZE OF MEMORY TO DEALLOCATE
	IDIV	P1,AHBCSZ(P3)	;CALCULATE NUMBER OF CHUNKS
	SKIPE	P2		;ANY REMAINDER?
	ADDI	P1,1		;YES, ROUND UP
	IMUL	P1,AHBCSZ(P3)	;CONVERT BACK INTO WORDS

	SKIPA	P2,AHBAEB(P3)	;GET ADDRESS OF FIRST ALLOCATION EXTENT BLOCK
GVXWD1:	MOVE	P2,AEBNXT(P2)	;GET ADDRESS OF NEXT ALLOCATION EXTENT BLOCK
	SKIPN	P2		;AT END OF ALLOCATION EXTENT LIST?
	STOPCD	CPOPJ##,DEBUG,CORCNA ;++YES, CHUNK NOT ALLOCATED
	MOVE	T1,AEBSIZ(P2)	;GET SIZE OF EXTENT
	ADD	T1,AEBADR(P2)	;COMPUTE LAST ADDRESS WITHIN EXTENT
	SUBI	T1,1		;...
	CAML	T2,AEBADR(P2)	;DOES CHUNK FALL WITHIN THIS EXTENT?
	CAMLE	T2,T1		;...
	JRST	GVXWD1		;NO, LOOP BACK AND TRY NEXT EXTENT

	PUSH	P,T2		;SAVE ADDRESS OF CHUNK
	MOVE	T1,P1		;GET NUMBER OF WORDS TO DEALLOCATE
	IDIV	T1,AHBCSZ(P3)	;CONVERT TO CHUNKS
	POP	P,T2		;GET BACK CHUNK ADDRESS
	SUB	T2,AEBADR(P2)	;COMPUTE CHUNK OFFSET WITHIN EXTENT
	IDIV	T2,AHBCSZ(P3)	;...
	SKIPE	T3		;ANY REMAINDER?
	STOPCD	CPOPJ##,DEBUG,CORNCB ;++NOT ON A CHUNK BOUNDARY
	IDIVI	T2,^D36		;COMPUTE BIT TABLE AND BIT NUMBER OFFSETS
	HRLS	T2		;MAKE AN AOBJN POINTER TO REST OF BITMAP
	ADD	T2,AEBBMP(P2)	;...
	PUSHJ	P,SETZRS	;CLEAR THE BITS

	ADDM	P1,AEBFRE(P2)	;UPDATE FREE WORD COUNTS
	ADDM	P1,AHBFRE(P3)	;...
	MOVN	T1,P1		;GET NEGATIVE WORD COUNT
	ADDM	T1,ACBUSD(P4)	;UPDATE USED WORD COUNT
	POPJ	P,		;AND RETURN
	SUBTTL	CORE ALLOCATION  --  NZS BITMAP MEMORY ROUTINES


;SUBROUTINES TO GET "FREE" CORE FROM NON-ZERO SECTIONS.  USED
;BY DECNET, SCA, AND ETHERNET CODE (TO GIVE THEM A SEPARATE POOL,
;AND TO ALLOW CORE TO BE IN EXTENDED SECTIONS).
;CALL:
;	T2/ NUMBER OF WORDS DESIRED
;	PUSHJ	P,GET?WS
;RETURN:
;	CPOPJ IF AMOUNT DESIRED NOT AVAILABLE
;	CPOPJ1 IF SUCCESS WITH:
;	T1/ START OF CHUNK

IFN FTSCA,<
GETSWS::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVEI	P1,SCAPTR##	;ADDRESS OF AOBJN TABLE DESCRIBING POOL
	MOVE	P2,SCALOC##	;ADDRESS OF BASE OF POOL
	PJRST	GETXWS		;TRY TO FIND THE SPACE
>; END IFN FTSCA

IFN FTENET,<
GETEWZ::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVEI	P1,ETHPTR##	;ADDRESS OF AOBJN TABLE DESCRIBING POOL
	MOVE	P2,ETHLOC##	;ADDRESS OF BASE OF POOL
	PJRST	GETXWZ		;TRY TO FIND THE SPACE
GETEWS::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVEI	P1,ETHPTR##	;ADDRESS OF AOBJN TABLE DESCRIBING POOL
	MOVE	P2,ETHLOC##	;ADDRESS OF BASE OF POOL
	PJRST	GETXWS		;TRY TO FIND THE SPACE
IFN FTKL10,<
GETNWZ::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVEI	P1,KNIPTR##	;ADDRESS OF AOBJN TABLE DESCRIBING POOL
	MOVE	P2,KNILOC##	;ADDRESS OF BASE OF POOL
	PJRST	GETXWZ		;TRY TO FIND THE SPACE
GETNWS::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVEI	P1,KNIPTR##	;ADDRESS OF AOBJN TABLE DESCRIBING POOL
	MOVE	P2,KNILOC##	;ADDRESS OF BASE OF POOL
	PJRST	GETXWS		;TRY TO FIND THE SPACE
>; END IFN FTKL10
>; END IFN FTENET

;HERE TO DO THE WORK FOR GET?WS

IFN FTDECNET!FTSCA!FTENET,<
GETXWZ:	MOVEI	T1,3(T2)	;MAKE IT 4-WORD INCREMENTS
	ASH	T1,-2
	EXCH	T2,P1		;SAVE SIZE, GET AOBJN POINTER TO BIT TABLE
	PUSHJ	P,GETBIT	;FIND THAT MANY BITS
	  POPJ	P,		;NO GO, RETURN FAILURE.
	ASH	T1,2		;CONVERT TO NUMBER OF WORDS
	ADD	T1,P2		;ADD IN START ADDRESS OF POOL.
	SETZM	(T1)		;ZERO FIRST WORD OF CHUNK
	SOS	T2,P1		;GET SIZE OF REMAINDER OF CHUNK
	PJUMPE	T2,CPOPJ1##	;RETURN IF NO OTHER WORDS TO ZERO
	MOVE	T3,T1		;GET START ADDRESS OF CHUNK
	XMOVEI	T4,1(T3)	;AND START ADDRESS +1 OF CHUNK
	EXTEND	T2,[XBLT]	;ZERO REMAINDER OF CHUNK
	JRST	CPOPJ1##	;RETURN SUCCESS
GETXWS:	MOVEI	T1,3(T2)	;MAKE IT 4-WORD INCREMENTS
	ASH	T1,-2
	MOVE	T2,P1		;AOBJN WORD TO BIT TABLE DESCRIBING THIS POOL
	PUSHJ	P,GETBIT	;FIND THAT MANY BITS
	  POPJ	P,		;NO GO, RETURN FAILURE.
	ASH	T1,2		;CONVERT TO NUMBER OF WORDS
	ADD	T1,P2		;ADD IN START ADDRESS OF POOL.
	JRST	CPOPJ1##	;RETURN SUCCESS
>; END IFN FTDECNET!FTSCA!FTENET
;SUBROUTINES TO RETURN "FREE" CORE OBTAINED BY A CALL TO GET?WS.
;CALL:
;	T1/ NUMBER OF WORDS TO RETURN
;	T2/ ADDRESS OF CHUNK
;	PUSHJ	P,GIV?WS
;RETURN:
;	CPOPJ ALWAYS

IFN FTSCA,<
GIVSWS::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVE	P1,SCAPTR##	;AOBJN TABLE DESCRIBING POOL
	MOVE	P2,SCALOC##	;ADDRESS OF BASE OF POOL
	PJRST	GIVXWS		;RETURN THE SPACE
>; END IFN FTSCA

IFN FTENET,<
GIVEWS::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVE	P1,ETHPTR##	;AOBJN TABLE DESCRIBING POOL
	MOVE	P2,ETHLOC##	;ADDRESS OF BASE OF POOL
	PJRST	GIVXWS		;RETURN THE SPACE
IFN FTKL10,<
GIVNWS::PUSHJ	P,SAVE2##	;SAVE P1 AND P2
	MOVE	P1,KNIPTR##	;AOBJN TABLE DESCRIBING POOL
	MOVE	P2,KNILOC##	;ADDRESS OF BASE OF POOL
	PJRST	GIVXWS		;RETURN THE SPACE
>; END IFN FTKL10
>; END IFN FTENET

IFN FTDECNET!FTSCA!FTENET,<
GIVXWS:	ADDI	T1,3		;ROUND UP
	ASH	T1,-2		;CONVERT WORD COUNT TO 4-WORD COUNT
	SUB	T2,P2		;CONVERT FROM ABSOLUTE TO RELATIVE ADDRESS
	ASH	T2,-2		;CONVERT TO NUMBER OF 4 WORD BLOCKS
	IDIVI	T2,^D36		;CONVERT TO OFFSET INTO TABLE OF BITS
	HRLS	T2		;LEFT HALF....
	ADD	T2,P1		;MAKE AN AOBJN POINTER TO REST OF TABLE
	PJRST	SETZRS		;AND ZERO BITS IN THE TABLE
>;END IFN FTDECNET!FTSCA!FTENET
	SUBTTL	CORE ALLOCATION  --  SECTION 0 BITMAP MEMORY ROUTINES


;SUBROUTINE TO GET "FREE" CORE
;ENTER GET4WD: T2=# 4 WORD BLOCKS TO GET
;ENTER GETWDS: T2=# WORDS TO GET
;RETURN CPOPJ IF NOT AVAILABLE, WITH T2=LARGEST HOLE AVAILABLE
;RETURN CPOPJ1 IF GOTTEN, WITH T1=LOC OF CORE
GETWDS::ADDI	T2,3		;CONVERT TO 4 WORD BLOCKS
	ASH	T2,-2
GET4WD::MOVE	T1,T2		;NUMBER OF BLOCKSTO GET
	MOVEI	T2,FREPTR##	;L(AOBJN WORD)
	PUSH	P,T1		;SAVE NUMBER BEING REQUESTED
	PUSHJ	P,GETBIT	;GET, SET THE BITS
	  JRST	GET4W2		;NOT ENOUGH AVAILABLE
	POP	P,T2		;RESTORE AMOUNT GOTTEN
IFN FTRSP,<
	ADDM	T2,FRUSED##	;BUMP FREE-CORE-USED WORD
>
	LSH	T1,2		;*4 TO CONVERT TO AN ADDRESS
	ADD	T1,LOCORE##	;+START OF TABLE = ACTUAL ADDRESS
	PJRST	CPOPJ1##	;TAKE GOOD RETURN

;HERE IF REQUESTED AMOUNT ISNT AVAILABLE
GET4W2:	MOVE	T2,T1		;LARGEST HOLE WE FOUND
	JRST	TPOPJ##		;TAKE LOST RETURN

;SUBROUTINE TO ZERO BITS IN A BIT TABLE
;CALLING SEQUENCE:
;	MOVE	T1,NUMBER OF BITS TO CLEAR
;	MOVE	T2,AOBJN POINTER TO TABLE
;	MOVE	T3,BIT POSITION WITHIN TABLE
;	PUSHJ	P,ZERBTS
;ALWAYS RETURNS CPOPJ

ZERBTS::IDIVI	T3,^D36		;36 BITS/WORD
	HRLS	T3		;WORD NUMBER TO BOTH HALVES
	ADD	T2,T3		;POINT AOBJN POINTER TO WORD IN TABLE
	MOVE	T3,T4		;BIT POSITION WITHIN WORD
	PJRST	SETZRS		;ZERO TIME BITS

;SUBROUTINE TO RETURN "FREE" CORE
;ENTER GIVWDS: T1=# WDS. TO RETURN, T2=START ADR. OF CORE
;ENTER GIV4WD: T1=# 4 WRD. BLOCKS TO RETURN, T2=START ADR. OF CORE
GIVWDS::ADDI	T1,3		;CONVERT TO # 4WD. BLOCKS
	ASH	T1,-2
GIV4WD::SUB	T2,LOCORE##	;GET ADR. RELATIVE TO START OF TABLE
IFN FTRSP,<
	MOVN	T3,T1
	ADDM	T3,FRUSED##	;DECREMENT FREE-CORE USED
>
	LSH	T2,-2		;/4 TO CONVERT TO BITS
	IDIVI	T2,^D36		;COMPUTE WORD LOC, STARTING BIT
	HRLS	T2		;WORD POSITION IN BOTH HALVES
	ADD	T2,FREPTR##	;SET AOBJN WORD FOR TABLE
				;FALL INTO SETZRS

;SUBROUTINE TO SET ZEROS IN A TABLE
;ARG	T1=HOW MANY BITS TO CLEAR
;	T2=AOBJN POINTER FOR TABLE
;	T3=POSITION IN WORD OF FIRST BIT TO CLEAR
;	(0=BIT 0, 1=BIT 1, ETC.)

SETZRS::PUSH	P,P3
	SETZ	P3,		;NOT TABLE RELATIVE
	PUSHJ	P,SETZRP	;ZERO THE BITS
	JRST	P3POPJ##	;RESTORE P3 AND RETURN
SETZRP::EXCH	T1,T3		;SET ACS FOR CLRBTS
	MOVEI	T4,^D36		;ADJUST FOR 1ST WORD
	SUBM	T4,T1
	HRRZ	T4,T2		;SET T4 FOR CLRBTS
	PUSH	P,T2		;SAVE AOBJN WORD
	PUSHJ	P,CLRBTS	;CLEAR SOME BITS
	  STOPCD	T2POPJ##,DEBUG,BAC, ;++BIT ALREADY CLEAR
	POP	P,T2		;RESTORE AOBJN WORD
	HLRE	T3,T2		;LENGTH OF POINTER
	SUB	T2,T3		;COMPUTE TOP OF TABLE
	CAILE	T4,(T2)		;FINAL ADR PAST TOP?
	STOPCD	CPOPJ##,DEBUG,PTT,	;++PAST TOP OF TABLE
	POPJ	P,		;NO, GOOD RETURN
	STRTAD==200000
	RELABP==40000
;SUBROUTINE TO FIND N CONSECUTIVE 0'S IN A TABLE
;ENTER WITH P1 = AOBJN WORD TO THE TABLE
;P2 = PREVIOUS BEST SO FAR
;RH(P3)= HOW MANY,  BIT STRTAD =1 IF START LOC SPECIFIED
;LH(P3) HAS BITS 0,1,2 USED BY FILSER
;EXIT CPOPJ1 IF FOUND, WITH P4 = WHERE THE HOLE IS, P1=UPDATED POINTER
;EXIT CPOPJ IF UNSUCCESSFUL, P2 = LARGEST HOLE FOUND
;P2,P4 CHANGED
;NOTE--SHOULD NOT CONTAIN A METER POINT SINCE IS CALLED
;      BY ENDSTS ON 407 START BEFORE METINI IS CALLED
GETZ::	PUSHJ	P,SETR		;ZERO R IF OLD STYLE CALL
GETZ0:	TLNE	P3,STRTAD	;START LOC SPECIFIED?  (NOTE THAT ENTRY TO ROUTINE
				; IS AT GETZR IF START LOC SPECIFIED)
	POPJ	P,		;YES, ERROR RETURN
	HRRM	P1,-2(P)	;STORE ABOJN POINTER IN INDIRECT WORD
	SETCM	T1,@-2(P)	;WORD TO INVESTIGATE
	JRST	GETZA		;SKIP CALL TO SETR
GETZX::	PUSHJ	P,SETR		;SETUP INDIRECT POINTER
GETZA:	MOVEI	T4,^D36		;NO. SET UP COUNT
	JUMPE	T1,GETZ4	;FULL IF 0
	JUMPG	T1,GETZ3	;1ST BIT UNAVAILABLE IF POSITIVE
GETZ1:	SETCA	T1,		;SET TO REAL CONTENTS
	JFFO	T1,.+2		;COUNT THE NUMBER OF 0'S
	MOVEI	T2,^D36		;36 OF THEM
	JRST	GETZB		;SKIP CALL TO SETR
GETZR::	PUSHJ	P,SETR		;SETUP INDIRECT POINTER TO THE BIT TABLE
GETZB:	MOVE	T3,T2		;SHIFT COUNT (T3 CAN BE .GT. 36 AT GETZ2)
	MOVEM	P1,P4		;SAVE POSITION IN P4
	HRLM	T4,P4		;LOC OF HOLE
GETZ2:	CAIL	T3,(P3)		;FOUND ENOUGH?
	JRST	CPOPJ1##	;YES. GOOD RETURN
	CAILE	T3,(P2)		;NO. BEST SO FAR?
	HRRI	P2,(T3)		;YES. SAVE IT
	SUBI	T4,(T2)		;DECREASE POSITION COUNTER
	JUMPLE	T4,GETZ5	;0'S ON END
	TLNE	P3,STRTAD	;THIS HOLE NOT GOOD ENOUGH
	POPJ	P,		;ERROR RETURN IF START ADDRESS GIVEN
	SETCA	T1,		;NOW WE WANT TO COUNT 1'S
	LSH	T1,1(T2)	;REMOVE BITS WE ALREADY LOOKED AT
	JUMPE	T1,GETZ4	;GO IF THE REST OF THE WORD IS ALL ONES
GETZ3:	JFFO	T1,.+1		;NUMBER OF (REAL) 1'S
	LSH	T1,(T2)		;GET RID OF THEM
	CAIN	T4,^D36		;1ST POSITION IN WORD?
	ADDI	T4,1		;YES, SUBTRACT REAL JFFO COUNT
	SUBI	T4,1(T2)	;DECREASE POSITION COUNT
	JUMPG	T4,GETZ1	;TRY NEXT 0 - HOLE
GETZ4:	AOBJN	P1,GETZ0	;1'S ON END - START FRESH AT NEXT WORD

;HERE IF THE DESIRED SIZE NOT YET FOUND, BUT THE WORD HAD 0'S ON THE END
GETZ5:	AOBJP	P1,CPOPJ##	;THROUGH IF END OF SAT
	HRRM	P1,-2(P)	;STORE UPDATED AOBJN POINTER
	SKIPGE	T1,@-2(P)	;NEXT WORD POSITIVE?
	JRST	GETZ0		;NO. THIS HOLE NOT GOOD ENOUGH
	JFFO	T1,.+2		;YES. COUNT THE 0'S
	MOVEI	T2,^D36		;36 0'S
	ADDI	T3,(T2)		;ADD TO PREVIOUS ZERO-COUNT
	MOVEI	T4,^D36		;RESET T4
	JRST	GETZ2		;AND TEST THIS HOLE

;SUBROUTINE TO SET UP A BIT MASK FOR IORM OR ANDCAM INTO A TABLE
;ENTER WITH T1=POSITION (36=BIT0, 1=BIT35)
; AND T3=HOW MANY
;AFTER THE FIRST CALL USE BITMS2, T3=COUNT RETURNS T1=MASK,
;T3=REMAINING COUNT ROUTINE HAS RETURNED FINAL MASK IF
;T3 .LE. 0 ASSUMES T4=ADR IN TABLE, BITMS2 INCREMENTS T4

BITMSK::PUSH	P,T1		;SAVE POSITION
	MOVN	T1,T3		;- COUNT
	CAILE	T3,^D36		;MORE THAN 1 WORD?
	MOVNI	T1,^D36		;YES, SETTLE FOR A WORD (OR LESS)
	MOVSI	T2,400000	;SET TO PROPOGATE A MASK
	ASH	T2,1(T1)	;GET THE RIGHT NUMBER OF BITS
	SETZ	T1,
	LSHC	T1,@0(P)	;POSITION THE BITS IN T1 (=MASK)
	SUB	T3,0(P)		;REDUCE THE COUNT TO THE NEW VALUE
	PJRST	T2POPJ##	;AND RETURN
;HERE AFTER FIRST CALL, MASK STARTS AT BIT 0
BITMS2::SETO	T1,		;MASK STARTS AT BIT 0
	MOVNI	T2,-^D36(T3)	;SET UP SHIFT
	CAIGE	T3,^D36		;DONT SHIFT IS .GE. 36
	LSH	T1,(T2)		;POSTION THE MASK
	SUBI	T3,^D36		;REDUCE THE COUNT
	AOJA	T4,CPOPJ##	;UPDATE THE POSITION AND RETURN

;SUBROUTINE TO MARK BITS AS TAKEN IN A TABLE
;USES ACS AS RETURNED BY GETZ - P3=HOW MANY
;  LH(P4)=POSITION, RH(P4)=WHERE (POSITION=36 IF BIT0, 1 IF BIT35)
;RETURNS CPOPJ IF BIT IS ALREADY SET, CPOPJ1 NORMALLY, RESPECTS T1
SETOS::	PUSHJ	P,SETR		;SETUP INDIRECT POINTER TO THE BIT TABLE
	PUSH	P,T1		;SAVE T1
	MOVE	T4,P4		;WHERE
	HRRZ	T3,P3		;COUNT
	HLRZ	T1,P4		;POSITION IN WORD
	PUSHJ	P,BITMSK	;SET UP A MASK
SETOS1:	HRRM	T4,-3(P)	;FOR INDIRECT
	BTSOFF			;BETTER NOT INTERRUPT HERE
	TDNE	T1,@-3(P)	;BIT ALREADY ON?
	JRST	SETOS2		;YES
	IORM	T1,@-3(P)	;NO, NOW IT IS
	BTSON			;RESTOR PI
	JUMPLE	T3,TPOPJ1##	;DONE IF COUNT .LE. 0
	PUSHJ	P,BITMS2	;NOT DONE, GET MASK FOR NEXT WORD
	JRST	SETOS1		;AND GO SET THE BITS IN THAT WORD
;HERE IF BIT ALREADY ON
SETOS2:	BTSON			;PI CAN BE ON
	PUSH	P,T3		;SAVE CURRENT COUNT
	HLRZ	T1,P4		;RESTORE ORIGINAL VALUES
	HRRZ	T3,P3
	MOVE	T4,P4
	PUSHJ	P,BITMSK	;AND GENERATE A MASK
SETOS3:	HRRM	T4,-4(P)	;SET FOR INDIRECT
	CAMN	T3,(P)		;IS THE COUNT FOR MASK=COUNT WHEN SET?
	JRST	SETOS4		;YES, DONE
	ANDCAM	T1,@-4(P)	;NO, CLEAR THOSE BITS
	PUSHJ	P,BITMS2	;GENERATE NEXT MASK
	JRST	SETOS3		;AND CONTINUE
SETOS4:	POP	P,(P)		;CLEARED ALL THE RIGHT BITS - FIX PD LIST
	JRST	TPOPJ##		;AND NON-SKIP RETURN


;SUBROUTINE TO OBTAIN FREE BITS, MARK THEM AS TAKEN IN THE TABLE
;ENTER WITH T1=HOW MANY,
;T2=XWD ADR OF 1ST WORD OF TABLE, ADR OF TABLE AOBJN WORD (OR 0, LOC OF AOBJN)
;RETURNS CPOPJ IF NOT ENOUGH AVAILABLE, T1=SIZE OF LARGEST HOLE
;RETURNS CPOPJ1 IF GOTTEN, T1= RELATIVE ADDRESS OF BLOCK OBTAINED
;T3 IS UPDATED AOBJN POINTER
GETBIT::PUSHJ	P,SAVE4##	;SAVE P1-P4
	TLNN	T2,-1		;STARTING AT AN OFFSET?
	HRL	T2,(T2)		;NO, START AT FIRST WORD
	PUSH	P,T2		;SAVE ADR OF AOBJN WORD FOR TABLE
GETBI1:	HRRZ	P1,0(P)		;GET AOBJN WORD
	MOVE	P1,(P1)
	SETZ	P2,		;NO BEST SO FAR
	MOVE	P3,T1		;NUMBER OF BITS TO GET
	PUSHJ	P,GETZ		;GET THE BITS
	  JRST	GETBI2		;NOT ENOUGH AVAILABLE
	HRRZ	T1,P4		;GOT THEM - FIRST WORD WITH ZEROES
	HLRZ	T2,(P)		;LOC OF FIRST WORD OF TABLE
	SUBI	T1,(T2)		;COMPUTE RELATIVE ADDRESS OF START
	IMULI	T1,^D36		;36 BITS PER WORD
	HLRZ	T2,P4		;BIT POSITION OF 1ST 0 IN THE WORD
	MOVNS	T2
	ADDI	T1,^D36(T2)	;T1= RELATIVE LOC WITHIN THE TABLE
	PUSHJ	P,SETOS		;MARK THE BITS AS TAKEN
	  SKIPA	T1,P3		;SOME FINK SNUCK IN ON US!
	AOSA	-1(P)		;GOT THEM - WIN RETURN
	JRST	GETBI1		;TRY AGAIN TO GET SOME BITS

	MOVE	T3,P1		;UPDATED POINTER
	JRST	T2POPJ##	;RETURN
;HERE IF NOT ENOUGH ARE AVAILABLE
GETBI2:	MOVE	T1,P2		;T1=LARGEST HOLE FOUND
	PJRST	T2POPJ##	;NON-SKIP RETURN
;ROUTINE TO CLEAR BITS FROM A TABLE
;ENTER T1=POSITION, T3=COUNT, T4=TABLE ADR
; POSITION=36 IF BIT0, 1 IF BIT35
;RETURNS POPJ IF BIT ALREADY 0, POPJ1 OTHERWISE
CLRBTS::PUSHJ	P,BITMSK	;GENERATE A MASK
	PUSHJ	P,SETR		;SETUP TABLE ADDRESS
CLRBT1:	HRRM	T4,-2(P)	;SET INDIRECT WORD
	BTSOFF			;CANT INTERRUPT
	MOVE	T2,@-2(P)	;WORD TO CLEAR BITS FROM
	TDC	T2,T1		;ARE THE BITS ALREADY OFF?
	TDNE	T2,T1
	PJRST	ONPOPB##	;YES, RESTORE PI AND NON-SKIP
	MOVEM	T2,@-2(P)	;NO, NOW THEY ARE
	BTSON			;RESTORE THE PI
	JUMPLE	T3,CPOPJ1##	;DONE IF COUNT .LE. 0
	PUSHJ	P,BITMS2	;GENERATE MASK FOR NEXT WORD
	JRST	CLRBT1		;AND GO CLEAR THOSE BITS

;SUBROUTINE TO FIND N CONSECUTIVE ZEROS IN A TABLE
;ARGS	T1=AOBJN POINTER TO TABLE
;	T2=PREVIOUS BEST
;	T3=HOW MANY, BIT STRTAD=1 IF START ADDR SPECIFIED
;VALUES	IF UNSUCCESSFUL, T2=LARGEST HOLE FOUND, NON-SKIP RETURN
;	IF SUCCESSFUL, T4=POSITION OF BEGINNING OF HOLE, SKIP RETURN
;THIS ROUTINE CALLS GETZ BUT SATISFIES STANDARD AC CONVENTIONS


CLGETZ::PUSHJ	P,SAVE4##		;SAVE GLOBAL ACS
	MOVE	P1,T1		;SET ACS FOR GETZ
	MOVE	P2,T2
	MOVE	P3,T3
	PUSHJ	P,GETZ		;GET THE BITS
	  CAIA		;NOT ENOUGH AVAILABLE
	AOS	(P)		;OK, SET FOR SKIP RETURN
	MOVE	T1,P1		;RESTORE T-ACS WITH ANSWERS
	MOVE	T2,P2
	MOVE	T3,P3
	MOVE	T4,P4
	POPJ	P,		;TAKE WIN OR LOSE RETURN
;SUBROUTINE TO SET BITS IN A TABLE
;ARGS	T3=HOW MANY
;	T4=POSITION OF FIRST, RH=ADDR, LH=POSITION, 36=BIT 0,1=BIT 35
;THIS ROUTINE CALLS SETOS BUT SATISFIES STANDARD AC CONVENTIONS
CSETOS::PUSHJ	P,SAVE4##		;SAVE P1-P4
	MOVE	P3,T3		;SET ACS FOR SETOS
	MOVE	P4,T4
	PUSHJ	P,SETOS		;SET THE BITS
	STOPCD	CPOPJ##,DEBUG,BNZ,	;++BIT NOT ZERO

	POPJ	P,		;OK, RETURN
;INTERFACE ROUTINE TO GETZ/SETOS WHICH ALLOWS THEM TO BE CALLED WITH AN
; EXTENDED ADDRESS AND A AOBJN POINTER RELATIVE TO A BIT TABLE
;CALLING SEQUENCE:
;	MOVE	R,ADDRESS OF THE BIT TABLE
;	MOVE	P1,AOBJN POINTER RELATIVE TO THE TABLE
;	TLO	P3,RELABP	;INDICATE THIS FORM OF CALL
;	PUSHJ	P,SETR		;MUST BE IN A NON-ZERO SECTION IF RELABP IS ON
;ALWAYS RETURN CPOPJ, -2(P) IS AN INSTRUCTION FORMAT INDIRECT WORD TO BIT TABLE

SETR:	PUSH	P,R		;SAVE R, SOME CALLERS MAY WANT IT RETURNED
	MOVSI	R,400000+R	;LOCAL INSTRUCTION FORMAT INDIRECT WORD
	EXCH	R,-1(P)		;SAVE IT ON THE STACK, GET RETURN ADDRESS
	MOVEM	R,1(P)		;TO CALL THE CALLER
IFN FTXMON,<
	TLNN	P3,RELABP	;RELATIVE AOBJN POINTER SPECIFIED?
	JRST	SETR1		;NO, OLD CALL
	TLNN	R,(SECMSK)	;MUST BE IN A NON-ZERO SECTION IF RELABP IS ON
	STOPCD	SETR2,DEBUG,NNS,;++NOT IN A NON-ZERO SECTION
>
	TLNN	P3,RELABP	;NEW CALL?
SETR1:	TDZA	R,R		;NO, NO RELOCATION
	MOVE	R,(P)		;YES, GET RELOCATION
	PUSHJ	P,@1(P)		;CALL CALLER AS A COROUTINE
	  CAIA			;NON-SKIP RETURN
	AOS	-2(P)		;PROPAGATE SKIP
SETR2:	POP	P,R		;RESTORE R
	POP	P,(P)		;POP OFF JUNK
	POPJ	P,		;AND RETURN
COREND:	END