Google
 

Trailing-Edge - PDP-10 Archives - BB-Z759A-SM - cobol-source/mmangr.mac
There are 6 other files named mmangr.mac in the archive. Click here to see a list.
; UPD ID= 3369 on 1/30/81 at 9:02 AM by WRIGHT                          
TITLE	MMANGR - Memory manager
SUBTTL	D. WRIGHT

	SEARCH COPYRT
	SALL

COPYRIGHT (C) 1981, 1983, 1984 BY DIGITAL EQUIPMENT CORPORATION


;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
;ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH LICENSE AND WITH THE
;INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY  OTHER
;COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
;OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF THE  SOFTWARE  IS  HEREBY
;TRANSFERRED.


;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
;AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
;CORPORATION.

;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
;SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.

SEARCH	MMANGU		;Search memory manager universal file
			;Picks up TOPS20 definition

IFN TOPS20,<SEARCH	MONSYM,MACSYM>
IFE TOPS20,<SEARCH	UUOSYM,MACTEN>


IFE TOPS20,<
	TWOSEG	400K	;Two-segment program, relocate to 400K
>;End IFE TOPS20
	.COPYRIGHT		;Put standard copyright statement in REL file
SALL
;AC definitions

T1=1		;Usual temps
T2=2
T3=3
T4=4
T5=5
P1=6		;Perm.
P2=7
P3=10
P=17		;Pushdown ptr.

;Entry points to MMANGR:

ENTRY	INITM	;Initialize memory manager
ENTRY	MMGPMP	;Entry to pass page map of section 0
ENTRY	INITMU	;Initialize one user
ENTRY	FINFRE	;Find free pages
ENTRY	RETRN	;Return pages to free pool
SUBTTL	MACROS


IFN TOPS20,<
DEFINE TYPE (ADDR),<
	HRROI	1,ADDR
	PSOUT%
>;END DEFINE TYPE

>;END IFN TOPS20

IFE TOPS20,<
DEFINE TYPE (ADDR),<
	OUTSTR	ADDR
>;END DEFINE TYPE

>;END IFE TOPS20

DEFINE $TEXT(STRING),<
XLIST
ASCIZ |STRING|
LIST
>;END DEFINE $TEXT
SUBTTL	INITM - Initialize memory manager

;Called only once by a program when it first starts up.
;If the main program runs in section 0 but you want the memory
;manager to use memory in other sections, the program must first
;map itself to section 1, then call INITM in section 1.
;
;Call:
;	1/ flags (MM%UXS)
;Return:
;	1/ Status 0=ok, 1=problem

INITM:	PUSH	P,T1		;SAVE AC1 FOR A SECOND.
	SETZM	MMDST		;CLEAR DATA AREA
	MOVE	T1,[MMDST,,MMDST+1]
	BLT	T1,MMDEN
	POP	P,T1		;RESTORE AC1

IFN TOPS20,<
	SETZM	MMEXSC		;CLEAR "USE EXTENDED SECTIONS" FLAG
	TXNN	T1,MM%UXS	;DOES HE WANT TO ALLOW THEM?
	 JRST	INITM2		;NO
	XMOVEI	T1,INITM	;WHERE ARE WE?
	TLNN	T1,-1		;IN SECTION 0?
	 JRST	INITM0		;YES, GIVE WARNING AND GO ON
	SETOM	MMEXSC		;SET "ALLOW EXTENDED ADDRESSES" FLAG
	JRST	INITM2		;GO ON

INITM0:	TYPE	[ASCIZ/%MMANGR: (INITM) Memory will only be managed in section 0
/]
>;END IFN TOPS20

INITM2:
IFN TOPS20,	XMOVEI	T1,MYPGS	;GET START OF MY 2 PAGES
IFE TOPS20,	MOVEI	T1,MYPGS	;Get start of my page
	TRZE	T1,777		; ROUND UP TO NEAREST PAGE
	ADDI	T1,1000
	MOVEM	T1,PTRLSU	;POINTER TO USER DATA
IFN TOPS20,<
	ADDI	T1,1000		;NEXT PAGE
	MOVEM	T1,PTRLSS	;POINTER TO SECTION DATA
>;END IFN TOPS20
IFE TOPS20,<
	JRST	RETST0		;RETURN STATUS 0
>;END IFE TOPS20

IFN TOPS20,<
;FIND A FREE SECTION TO USE FOR MEMORY ALLOCATION
	SKIPN	MMEXSC		;USE EXTENDED SECTIONS?
	 JRST	RETST0		;NO, JUST RETURN STATUS 0
	PUSHJ	P,FINPRS	;FIND A PRIVATE SECTION I CAN TAKE OVER.
	 JRST	INITE3		;?CAN'T, GIVE UP
	MOVE	T2,PTRLSS	;GET PTR TO SECTION DATA
	AOS	.MSNSH(T2)	;Count another section defined
	ADDI	T2,.MSSSB	;POINT TO START OF 1ST SECTION BLOCK
	MOVEM	T1,.MSSCN(T2)	;STORE SECTION NUMBER
				; EVERYTHING ELSE IN ENTRY IS ZERO
	JRST	RETST0		;RETURN STATUS 0

INITE3:	TYPE	TPRINI
	TYPE	[ASCIZ/ Can't find a private section
/]
	JRST	RETST1		;RETURN STATUS 1
>;END IFN TOPS20

;Print this first on INITM errors
TPRINI:	$TEXT	<?MMANGR: Routine "INITM" encountered a problem:
>
IFN TOPS20,<
;ROUTINE TO FIND A PRIVATE SECTION AND CREATE IT.
; RETURNS .+1 IF CAN'T
; RETURNS .+2 IF GOT ONE, SEC # IN T1
;USES T1 AND T2 ONLY
FINPRS:	DMOVEM	T3,MMAC34	;SAVE USER ACS 3 AND 4
	MOVEI	T3,2000		;START LOOKING WITH SECTION 2
	MOVEI	T4,^D20		; STOP AFTER THIS MANY TRIES
RPSLP:	MOVE	T1,T3		;GET PAGE NUMBER TO CHECK
	HRLI	T1,.FHSLF	;MY FORK
	RPACS%			;DOES SECTION EXIST?
	 ERJMP	RPSL11		;FOUND AN UNUSED ONE!
	ADDI	T3,1000		;BUMP PAGE NUMBER TO NEXT SECTION
	SOJG	T4,RPSLP	; TRY A BUNCH OF TIMES
	JRST	CCRETP		;? TOO BAD

RPSL11:	LSH	T3,-^D9		;T3= SECTION NUMBER
	SETZ	T1,		;WANT PRIVATE SECTIONS
	HRLI	T2,.FHSLF	;SECTION IN THIS FORK
	HRR	T2,T3		;GET SECTION NUMBER
	MOVE	T4,T3		;SAVE SECT #
	MOVX	T3,PM%RD!PM%WR+1	;READ WRITE AND ONE SECTION
SMAPLP:	SMAP%			;TELL MONITOR WE WANT TO USE OTHER SECTIONS
	 ERJMP	CCRETP		;FAILED
	MOVE	T1,T4		;RETURN SECTION NUMBER IN T1
	DMOVE	T3,MMAC34	;RESTORE ACS 3 AND 4
	AOS	(P)		;SKIP RETURN
	POPJ	P,		;RETURN

CCRETP:	DMOVE	T3,MMAC34	;RESTORE ACS 3 AND 4
	POPJ	P,		;RETURN .+1
>;END IFN TOPS20
SUBTTL	MMGPMP - Copy section 0 map

;CALL:
;	1/ ptr to section 0 map
;Return:
;	1/ Status 0

MMGPMP:	PUSH	P,T3		;SAVE AC 3
	PUSH	P,T2		;AND T2
	MOVE	T3,[-SCMPSZ,,SC0MAP] ;AOBJN PTR TO SC0MAP
MMGPM1:	MOVE	T2,(T1)		;GET A WORD
	MOVEM	T2,(T3)		; COPY IT TO MY MAP
	ADDI	T1,1		;BUMP #1 POINTER
	AOBJN	T3,MMGPM1	;LOOP
	POP	P,T2		;Restore ac2
	POP	P,T3		;RESTORE AC 3
	SETOM	HAVSC0		;SET "HAVE A SECTION 0 MAP" FLAG
	JRST	RETST0
SUBTTL	INITMU - Initialize memory manager for a user

;Called once for every module that uses the memory manager.
;Call:
;	1/ flags (MM%CRM, MM%UXS)
;	2/ SIXBIT NAME
;	3/ (If MM%CRM set) Address of routine to return memory usage
;	4/ (If MM%CRM set) Address of routine to cut back memory usage
;Return:
;	1/ Status 0=ok, 1=problem

INITMU:	DMOVEM	T5,MMAC56	;SAVE A COUPLE ACS
	AOS	T5,NMMODS	;GET # OF MODULES
	CAILE	T5,MNPPAG	;Exceeded one page of info?
	 JRST	INMUE0		;YES, COMPLAIN
	SKIPN	T5,PTRLSU	;GET PTR TO LIST OF USERS
	 JRST	INMUE1		;ERROR- PTR NOT SETUP
INIU1:	SKIPN	.MNNXT(T5)	;IS THERE A NEXT BLOCK?
	 JRST	INIU2		;NO, LINK TO END
	MOVE	T5,.MNNXT(T5)	;GET PTR TO NEXT BLOCK
	JRST	INIU1		;SEARCH FOR END OF CHAIN
INIU2:	SKIPN	.MNNAM(T5)	;IS NAME OF THIS ONE NULL?
	 JRST	INIU3		;YES, FIRST ONE
	MOVE	P1,T5		;GET START OF NEXT BLOCK
	ADDI	P1,.MNSIZ
	MOVEM	P1,.MNNXT(T5)	;STORE IN CURRENT ENTRY
	MOVE	T5,P1		;SET T5= START OF THIS BLOCK
INIU3:	MOVEM	T1,.MNNFL(T5)	;STORE FLAGS
	MOVEM	T2,.MNNAM(T5)	;STORE NAME
	TXNN	T1,MM%CRM	;ADDRS GIVEN?
	 JRST	INIU4		;NO
	MOVEM	T3,.MNARU(T5)	; YES, STORE ADDRESSES OF ROUTINES
	MOVEM	T4,.MNACB(T5)
INIU4:	DMOVE	T5,MMAC56	;RESTORE SAVED ACS
	JRST	RETST0		;RETURN STATUS 0
;ERRORS IN INITMU
INMUE0:	TYPE	IMUEH		;TYPE HEADER
	TYPE	[ASCIZ/ Too many modules called the initialize routine
/]
	DMOVE	T5,MMAC56	;RESTORE ACS
	JRST	RETST1		;RETURN STATUS 1

INMUE1:	TYPE	IMUEH		;TYPE HEADER
	TYPE	[ASCIZ/ "INITM" routine not called by main program
/]
	DMOVE	T5,MMAC56	;RESTORE ACS
	JRST	RETST1		;RETURN STATUS 1

IMUEH:	$TEXT	<?MMANGR: "INITMU" routine encountered a problem:
>
SUBTTL	FINFRE - Find free pages

;Call:
;	1/ flags (MM%GSS, MM%NCL)
;	2/ number of pages
;Returns:
;	1/ Status 0=ok, 1=can't get (system error), 2=can't get (user error)
;	2/ Address of start of block
;If status returned = 2, then message has been typed out

FINFRE:	SKIPN	MMEXSC		;Extended sections available?
	 TXO	T1,MM%GSS	;No, whether he cares or not we are
				; going to get memory in his current section
	DMOVEM	T1,MMAC12	;SAVE ACS 1 & 2
	DMOVEM	T3,MMAC34	;SAVE ACS 3 & 4

IFN TOPS20,<
	SETOM	SECRST		;Assume no section restriction
	TXNN	T1,MM%GSS	;Get core in current section?
	 JRST	FINFR1		;No, use extended sections
>;END IFN TOPS20
IFE TOPS20,<
	SETZM	SECRST		;Restricted to section 0
	JRST	FINRS0		;Get memory from section 0
>

;GET CALLER'S SECTION
IFN TOPS20,<
	MOVE	T2,(P)		;Get top of pushdown stack
	TLZ	T2,770000	;CLEAR PC FLAGS
	HLRZ	T2,T2		;SECTION # IN T2
	MOVEM	T2,SECRST	;Remember we are restricted to this section
	JUMPE	T2,FINRS0	;Restricted to section 0

;Use extended sections.. fall into "FINFR1"
;  continued on next page..
;Here if we will use extended sections
;SECRST/ section number to restrict us to, or -1
FINFR1:	MOVE	T1,MMAC12+1	;Try to find this many pages
	MOVE	T2,MMAC12	;Flags in t2
	PUSHJ	P,FINSOM	;. .
	JUMPE	T1,FINFRG	;Return if got 'em

;Didn't get them. We have to create another section.
	MOVE	T4,T2		;Save address of last section page
	MOVE	T3,.MSNSH(T4)	;Get # of sections defined on this page
	CAIE	T3,MSPPAG	;Is it at the maximum already?
	 JRST	FINFR2		;No

;Try to get another section page from a section we have already
	PUSH	P,SECRST	;Don't restrict us to a section now
	SETOM	SECRST		;. .
	MOVEI	T1,1		;Try to find this many pages
	MOVX	T2,0		;No flags
	PUSHJ	P,FINSOM
	POP	P,SECRST	;Restore section restriction, if any
	JUMPN	T1,FINFR2	;Jump if can't find a free page
	MOVEM	T2,.MSPNX(T4)	;Link last page to this new one
	MOVE	T4,T2		;T4= address of new page

;Here to create a new section and try again
FINFR2:	PUSHJ	P,FINPRS	;Go get a private section
	 JRST	FINFR9		;Can't

;Got it. Create a section block for it (tacked on end of list).
	MOVE	T3,.MSNSH(T4)	;Get # of sections defined on this page
	CAIE	T3,MSPPAG	;Is it at the maximum?
	 JRST	FINFR3		;No
	HRLZ	T3,T1		;T3= address of new section-page
	MOVEM	T3,.MSPNX(T4)	;Store address of next section-page
	MOVE	T4,T3		;T4= address of new section-page
	MOVEI	T2,1		;1 section defined on this page
	MOVEM	T2,.MSNSH(T4)
	MOVE	T3,T4
	ADDI	T3,.MSSSB	;T3= address of section block to define
	JRST	FINFR4

;Same section-page can be used
FINFR3:	IMULI	T3,.MSSIZ	;Get offset of next section block
	ADD	T3,T4		; Get absolute address
	MOVE	T2,T3		;store "next" address in previous section entry
	SUBI	T2,.MSSIZ
	MOVEM	T3,.MSNXT(T2)	;. .

;Increment # sections defined on this page
	MOVEI	T2,1
	ADDM	T2,.MSNSH(T4)

;Here with T3 = address of section-block
;	t4 = address of current section-block page
;	T1 = section number of new section
;At this point, .MSNSH(T4) has been updated
;All that needs to be done is to create the section block info itself
FINFR4:	MOVEM	T1,.MSSCN(T3)	;Store section number in entry
	HRLZ	T1,T1		;Get address of first page in section
	CAMN	T1,T4		; Is this first page used?
	 SKIPA	T1,[1B0]	;Yes, mark it as not free
	SETZ	T1,		;No, mark it as free
	MOVEM	T1,.MSPGD(T3)	;Store 1st word of page data
	SETZM	.MSNXT(T3)	;Clear "next" pointer

;Set pages-in-use bits to all zeroes
	MOVEI	T1,<^D512/^D36> ; Number of words minus 1
	SETZM	.MSPGD+1(T3)	;Clear a word
	SOJG	T1,.-1		; Do them all

;Try original request again
	MOVE	T1,MMAC12+1	;Number of pages he wants
	MOVE	T2,MMAC12	;Flags
	PUSHJ	P,FINSOM
	JUMPE	T1,FINFRG	;Got 'em, return status 0
	TYPE	[ASCIZ/?MMANGR: Internal error
/]
	MOVEI	T1,1		;Return status 1
	JRST	FINFRG

;Couldn't create another private section
FINFR9:	MOVEI	T1,1		;Return status 1
	JRST	FINFRG

;Here to return to user, restoring acs 3 and 4
;Come here with status in T1
FINFRG:	DMOVE	T3,MMAC34	;Restore acs
	POPJ	P,		;Return
;Big subroutine to try to find N pages.
;Call: SECRST/ section to restrict ourselves to
;	T1/ Number of pages desired
;	T2/ Flags (MM%NCL)
;Returns:
;	T1/ status 0=ok, 1=can't get
;	T2/ address of first location gotten (if status 0)
;	 or address of last section-page  (if status 1)
;only t1, t2 smashed
FINSOM:	PUSH	P,T4		;SAVE SOME ACS
	PUSH	P,T3
	PUSH	P,T2		;Top of stack -1 is flags
	PUSH	P,T1		;Top of stack is # of pages

	MOVE	T1,PTRLSS	;GET PTR TO FIRST SECTION-BLOCK PAGE
	MOVE	T2,T1		;GET PTR TO FIRST SECTION DEFINED IN THAT PAGE
	SKIPG	T3,SECRST	;Restricted to a particular section?
	 JRST	FINSM1		;No
	TYPE	[ASCIZ/%MMANGR: FINFRE will not restrict memory
 to a particular section except section 0
/]

;Here with T2 pointing to start of a page of section blocks.
FINSM1:	ADDI	T2,.MSSSB
FINSM2:	MOVEM	T2,CURSCB	;SAVE CURRENT SECTION BLOCK ADDRESS
	MOVE	T1,(P)		;# pages desired..
	PUSHJ	P,CHKFPS	;Check for enough free pages in current section
	 JRST	FINSM3		;Not enough in this section, try next one

;Met our goal in this section, t1= starting address
	MOVE	T3,-1(P)	;Check to see if we should clear memory
	TXNE	T3,MM%NCL
	 JRST	FNSM2A		;Don't bother
	MOVE	T3,T1		;Start of block
	SETZM	(T3)		;Clear 1st word
	MOVE	T4,T1		;Start of block
	ADDI	T4,1		;+1
	MOVE	T2,(P)		;Get # pages
	LSH	T2,^D9		;# WORDS
	SUBI	T2,1		;# TO BLT
	EXTEND	T2,[XBLT]	;Clear memory

FNSM2A:
IFN TOPS20, ADJSP P,-1		;Throw away old T1
IFE TOPS20,	POP	P,(P)
	POP	P,T2		;RESTORE OTHER ACS
	POP	P,T3
	POP	P,T4
	MOVE	T2,T1		;Return start of block in T2
	JRST	RETST0		;RETURN STATUS 0

; Continued on following page..
;"FINSOM" routine, continued.

;Come here if not enough free pages found in current section,
; look at next section
FINSM3:	MOVE	T1,CURSCB	;GET PTR TO CURRENT SECTION
	SKIPN	T2,.MSNXT(T1)	;Skip if there is another one
	 JRST	FINSM4		;NO, check for sections on another page
	MOVEM	T2,CURSCB	;Make this the current section block
	JRST	FINSM2		;Loop back to see if enough free pages here

;Look for another page of section blocks
FINSM4:	TRZ	T1,777		;POINT TO START OF PAGE
	SKIPE	T2,.MSPNX(T1)	;Skip if there's not another section-block page
	 JRST	FINSM1		;Go look at the section blocks on this page

;Have to return "No success"
IFN TOPS20,<
	ADJSP	P,-2		;Throw away old T1, T2
>
IFE TOPS20,<
	POP	P,(P)
	POP	P,(P)
>
	POP	P,T3		;Restore user's T3
	POP	P,T4		;Restore user's T4

;Set T2= Address of last section block page looked at
	MOVE	T2,T1
	JRST	RETST1		;And return status 1
>;END IFN TOPS20
;Find pages, restricted to section 0
;MMAC12+1/ number of pages desired
FINRS0:	PUSH	P,P1		;SAVE AC
	MOVE	P1,[POINT 1,SC0MAP] ;POINT TO PAGE MAP
	SETZ	T4,		;START AT PAGE 0
FINR01:	ILDB	T2,P1		;Look for a free one
	JUMPE	T2,.+2
	AOJA	T4,FINR01
	CAILE	T4,777		;Did we find any?
	 JRST	FINR0N		;No, no room

	HRRZ	T1,T4		;Assume this is it
	HRRZ	T3,MMAC12+1	;Countdown
	MOVEM	P1,SAVEPB	;Save page table byte ptr
	ADDI	T4,1		;Account for pages we found

FINR02:	SOJLE	T3,FINR0G	;Got 'em.. mark as taken
	ILDB	T2,P1		;Look some more
	ADDI	T4,1		;On next page now
	CAILE	T4,777
	 JRST	FINR0N		;No room
	JUMPE	T2,FINR02	;Still OK.. keep going

;This clump won't do.. try again
	JRST	FINR01

FINR0G:	MOVE	P1,SAVEPB	;Get byte ptr at start of clump
	SETO	T2,		;Set flag to -1
	DPB	T2,P1		;Mark that page
	MOVE	T3,MMAC12+1	;# of pages
	SOJLE	T3,FINR0R	;Return when marked them all
	IDPB	T2,P1
	JRST	.-2

FINR0N:	POP	P,P1		;RESTORE AC
	DMOVE	T3,MMAC34	;Restore AC's
	JRST	RETST1		;Return status 1 (system error)

FINR0R:	MOVE	T2,T1		;Return t2= address
	LSH	T2,^D9
IFE TOPS20,<
	PUSHJ	P,CRPGS		;Go create the pages
	 JRST	FINR0N		;?Problem, return status 1
>;END IFE TOPS20
	MOVE	P1,MMAC12	;Get user's ac 1
	TXNE	P1,MM%NCL	;Don't bother to clear memory?
	 JRST	FINRRN		;Just return

;Clear memory we gave him
;t2= Starting address of the block
;MMAC12+1 = number of pages to clear
	SETZM	(T2)		;Clear first address
IFN TOPS20,<
	XMOVEI	T3,.		;What section are we in?
	TLNN	T3,-1		;Non-zero section?
	 JRST	FINRR2		;No

;Clear memory with XBLT
	PUSH	P,P2		;Save acs for XBLT
	PUSH	P,P3
	MOVE	P1,MMAC12+1	;# pages
	LSH	P1,^D9		;# words to copy
	SUBI	P1,1		;. .
	MOVE	P2,T2		;Location of source block
	MOVEI	P3,1(T2)	;Location of destination block
	EXTEND	P1,[XBLT]	;** Clear memory **
	POP	P,P3
	POP	P,P2
	JRST	FINRRN		;Done clearing memory
>;END IFN TOPS20

;Here if we are not running in an extended section
FINRR2:	HRL	T3,T2
	HRRI	T3,1(T2)	;Starting BLT word
	MOVE	T4,MMAC12+1	;# PAGES
	LSH	T4,^D9		;# WORDS GOTTEN
	ADDI	T4,-1(T2)	;Ending address
	BLT	T3,(T4)		;** Clear the memory **

FINRRN:	POP	P,P1		;Restore AC
	DMOVE	T3,MMAC34	;restore AC's
	JRST	RETST0		;And set status = 0
IFE TOPS20,<

;CRPGS - Routine to create the pages we will give user.
;Skip return if OK, else POPJ after typing the message
;Inputs:
;	MMAC12+1/ number of pages
;	T1 = starting page number
;Uses T1-T3

;The pages must not exist.

CRPGS:	MOVEM	T1,PGUADR+1	;Save first page number
	MOVEI	T1,1		;Create one page at a time
	MOVEM	T1,PGUADR	; Save argument count
	MOVE	T3,MMAC12+1	;Get # of pages
CRPGS0:	MOVE	T1,[.PAGCD,,PGUADR] ;Ready to create page
	PAGE.	T1,		;Create the page..
	 JRST	CRPGSE		;Error
	SOJLE	T3,CPOPJ1	;Jump if all done
	AOS	PGUADR+1	;Increment page number
	JRST	CRPGS0		;Loop

CRPGSE:	TYPE	[ASCIZ/?MMANGR: Can't create a page: /]
	CAIN	T1,PAGCE%	;Page should not exist, but does
	 JRST	CRPCE		;That's the error
	TYPE	[ASCIZ/ PAGE. error code = /]
	PUSHJ	P,TYPOCT	;Type octal number
	TYPE	CRLF
	POPJ	P,		;Error return

CRPCE:	TYPE	[ASCIZ/ Page number /]
	MOVE	T1,PGUADR+1	;Get page number
	PUSHJ	P,TYPOCT	;Type it
	TYPE	[ASCIZ/ already exists
/]
	POPJ	P,		;Error return

;Routine to type octal number from T1
TYPOCT:	IDIVI	T1,8		;Divide by base
	PUSH	P,T2		;Save remainder
	SKIPE	T1		;Done?
	PUSHJ	P,TYPOCT	;No, stack it
	POP	P,T1		;Restore digit
	ADDI	T1,"0"		;Make ASCII
	OUTCHR	T1		;Type it
	POPJ	P,		;Recurse

CRLF:	ASCIZ /
/				;Address of a CRLF
>;END IFE TOPS20
IFN TOPS20,<

;Routine to find a clump of free pages in the current section
; If found, it marks them "INUSE" and modifies the section block.
;
;Call:
;	CURSCB/ address of current section block
;	T1/ number of pages desired
;Returns:
;	.+1 if can't
;	.+2 if did, T1/ global address of start of block
;May use AC's T1-T4
;
;Note: This routine may be called several times during one call to "FINFRE",
;       so it must be fast!

CHKFPS:	PUSH	P,P1		;Save P1
	PUSH	P,P2		;and P2
	MOVE	P2,CURSCB	;get address of current section block
	MOVE	P1,[POINT 1,.MSPGD(P2)] ;P1 = ptr to pages in the section
	SETZ	T4,		;T4= page offset being considered
CHKFP1:	ILDB	T2,P1		;Look for a free one
	JUMPE	T2,.+2
	AOJA	T4,CHKFP1
	CAILE	T4,777		;Did we find any?
	 JRST	CHKFNR		;No, no room

	MOVEM	T4,PSBLPG	;Remember page number incase this is it
	HRRZ	T3,T1		;Countdown
	MOVEM	P1,SAVEPB	;Save page table byte ptr
	ADDI	T4,1		;Account for page we found

CHKFP2:	SOJLE	T3,CHKFPG	;Got 'em.. mark as taken
	ILDB	T2,P1		;Look some more
	ADDI	T4,1		;On next page now
	CAILE	T4,777
	 JRST	CHKFNR		;No room
	JUMPE	T2,CHKFP2	;Still OK.. keep going
	JRST	CHKFP1		;This clump won't do.. try again

;Continued on next page..
;CHKFPS routine (continued)

;Here when we found a clump of pages that will do.
;T1/ number of pages
;PSBLPG/ starting page offset in section
;SAVEPB/ saved BP to page table where the clump starts
;P1 and P2 have been pushed on the stack

CHKFPG:	AOS	-2(P)		;Success, give skip return
	MOVE	T3,T1		;# of pages in T3
	MOVE	T1,PSBLPG	;Get starting page offset
	LSH	T1,^D9		;Make address offset
	MOVE	T2,CURSCB	;Current section block
	HRL	T1,.MSSCN(T2)	;Put section number in address, to get
				; Global address of start of block in T1
	MOVE	P1,SAVEPB	;Get byte ptr at start of clump
	SETO	T2,		;Set flag to -1
	DPB	T2,P1		;Mark that page
	SOJLE	T3,CHKFNR	;Return when marked them all
	IDPB	T2,P1
	JRST	.-2

CHKFNR:	POP	P,P2		;Restore P1, P2
	POP	P,P1
	POPJ	P,		;RETURN
>;END IFN TOPS20
SUBTTL	RETRN - Return pages to memory manager

;Call:
;	1/ flags
;	2/ Number of pages
;	3/ Address of start of block to return
;Returns:
;	1/ Status 0=ok, 1=Not returnable (message typed)

RETRN:	CAILE	T2,1000		;Can't return more than 1000 pages at a time
	 JRST	RETE01
	JUMPE	T2,RETST0	;Return 0 pages--done
	TRNE	T3,777		;Must be on an even page boundary
	 JRST	RETE02		;No, error
IFN TOPS20,<
	TLNE	T3,-1		;Returning pages in non-zero sections?
	 JRST	RETNR1		;Yes
>

;Return pages in section 0
	SKIPN	HAVSC0		;Do we have a section 0 map?
	 JRST	RETE04		;No
	LSH	T3,-^D9		;Get T3= starting page number
	DMOVEM	T3,MMAC34	;SAVE ACS 3, 4
	ADD	T3,T2		;Start + # returned
	CAILE	T3,1000		;Must be less than 1000
	 JRST	RETE03		;?no, give error
	MOVE	T3,MMAC34	;Restore ac 3
	MOVE	T4,[POINT 1,SC0MAP] ;Point to section 0 map
	SOJL	T3,RETNR0	;Jump when positioned to page #
	IBP	T4		;Bump byte ptr
	JRST	.-2		;Loop
RETNR0:	MOVEM	T4,SAVRBP	;Save byte ptr of starting page

;Make sure bits are set now
	MOVE	T1,T2		;# PAGES, 1 TO 1000
	ILDB	T3,T4		;Get bit
	JUMPE	T3,RETE05	;? Not set, return "not returnable"
	SOJG	T1,.-2		;Loop for all

;All set.. clear them now
IFE TOPS20,<
	MOVEM	T2,SAVRNP	;Save # pages returned
>;END IFE TOPS20
	MOVE	T4,SAVRBP	;Get back byte ptr
	SETZ	T3,		;Clear bits
	IDPB	T3,T4		;Clear bit for a page
	SOJG	T2,.-1		;Loop for all
IFE TOPS20,<
	PUSHJ	P,DLPGS		;Delete pages
	 JRST	RET341		;Error, restore 3,4 return status 1
>;END IFE TOPS20
	JRST	RET340		;Restore 3, 4, return status 0
; RETRN routine (Cont'd)

IFE TOPS20,<

;DLPGS - TOPS10 routine to delete pages when they are returned to mem. manager.
;  The pages are deleted via the PAGE. UUO. If the UUO gets an error because
;the page is already gone, there is no problem. Any other kind of UUO error
;causes a message to be typed out and the POPJ return taken.

;Inputs:
;	MMAC34/ Starting page number
;	SAVRNP/ Number of pages
;Uses T1-T3
DLPGS:	MOVE	T1,MMAC34	;Get starting page number
	MOVEM	T1,PGUADR+1	;Save for PAGE. UUO
	MOVEI	T1,1		;One argument
	MOVEM	T1,PGUADR	;. .
	MOVX	T1,PA.GAF	;Get flag that says destroy page
	IORM	T1,PGUADR+1	;Put in arg block
	MOVE	T3,SAVRNP	;Get number of pages
DLPGS0:	MOVE	T1,[.PAGCD,,PGUADR] ;Prepare for PAGE. UUO
	PAGE.	T1,		;Destroy one page
	 JRST	DLPGSE		;Error, go see why
DLPGS1:	SOJLE	T3,CPOPJ1	;Skip return if done
	HRRZ	T1,PGUADR+1	;Increment page #
	ADDI	T1,1
	HRRM	T1,PGUADR+1	; . .
	JRST	DLPGS0		;Loop

;PAGE. UUO failed
DLPGSE:	CAIN	T1,PAGME%	;Page should exist, but does not
	 JRST	DLPGS1		;Yes, it doesn't matter.
	TYPE	[ASCIZ/?MMANGR: RETRN routine can't destroy a page,
 PAGE. UUO error code = /]
	PUSHJ	P,TYPOCT	;Type octal error code
	TYPE	CRLF
	POPJ	P,		;Give error return
>;END IFE TOPS20
; RETRN routine (Cont'd)

IFN TOPS20,<
;Here to return pages in a non-zero section
RETNR1:	DMOVEM	T3,MMAC34	;Save acs 3,4
	HLRZ	T4,T3		;Get t4= section number
	TLZ	T3,-1		;Clear section number
	LSH	T3,-^D9		;Get t3= starting page number offset in section
	ADD	T3,T2		;Start + # returned
	CAILE	T3,1000		;Must be less than 1000
	 JRST	RETE03		;?No, give error
	SUB	T3,T2		;Restore page offset

;Search thru the list of section blocks for that section
;Section # to look for is in T4
	MOVE	T1,PTRLSS	;Get pointer to section blocks
RETNR2:	MOVE	T2,T1		;Get t2= starting section block
	ADDI	T2,.MSSSB
RETNR3:	CAMN	T4,.MSSCN(T2)	;Does this section block match
	 JRST	RETNR4		;Yes, go return pages here
	SKIPE	T2,.MSNXT(T2)	;No, is there a "next" block?
	 JRST	RETNR3		;Yes, go check it
	SKIPE	T1,.MSPNX(T1)	;No, is there another section-block page?
	 JRST	RETNR2		;Yes, go check it
	JRST	RETE06		;?Can't find that section block

;Come here when the section-block pointer is in T2
RETNR4:	MOVE	T1,T2		;GET T1= ptr to page data
	ADDI	T1,.MSPGD	;. .
	MOVEM	T1,RBPT+1	;Save return byte ptr address
	MOVX	T1,1B12+<POINT 1,0> ;Extended byte ptr
	MOVEM	T1,RBPT		;First word of byte ptr
	SOJL	T3,RETNR5	;Jump when positioned to page #
	IBP	RBPT		;. .
	JRST	.-2
RETNR5:	DMOVE	T1,RBPT		;Save this place
	DMOVEM	T1,SAVRBP	;. .

;Make sure bits are on
	MOVE	T1,MMAC12+1	;Number of pages, 1 to 1000
	ILDB	T3,RBPT		;Get bit
	JUMPE	T3,RETE05	;?Not set, return "not returnable"
	SOJG	T1,.-2		;Look for all

;All set.. clear them now
	MOVE	T2,MMAC12+1	;Number of pages
	SETZ	T3,		;Clear bits
	IDPB	T3,SAVRBP	;Clear bit for a page
	SOJG	T2,.-1		;Loop for all
	JRST	RET340		;Restore 3,4 return status 0


	DMOVE	T3,MMAC34	;Restore acs 3,4
	JRST	RETST0		;Return status 0
>;END IFN TOPS20
SUBTTL	RETRN errors

RETE01:	TYPE	RETEH		;Type header
	TYPE	[ASCIZ/ Attempt to return more than 1000 pages at a time
/]
	JRST	RETST1		;Return status 1

RETE02:	TYPE	RETEH		;Type header
	TYPE	[ASCIZ/ Input starting address of block not on a page boundary
/]
	JRST	RETST1		;Return status 1

RETE03:	TYPE	RETEH		;Type header
	TYPE	[ASCIZ/ Input starting address of block + # pages returned
 goes over a section boundary
/]
	JRST	RET341		;Return status 1, restore acs

IFN TOPS20,<
RETE04:	TYPE	RETEH		;Type header
	TYPE	[ASCIZ/ Attempt to return pages to section 0, but no
 section 0 page map was supplied when "INITM" was called
/]
	JRST	RETST1
>
IFE TOPS20,<
RETE04:	TYPE	RETEH		;Type header
	TYPE	[ASCIZ/ Attempt to return pages before page map was supplied
/]
	JRST	RETST1
>;END IFE TOPS20

RETE05:	TYPE	RETEH		;Type header
	TYPE	[ASCIZ/ Attempt to return pages that were not reserved
/]
	JRST	RET341		;Return status 1, restore acs

IFN TOPS20,<
RETE06:	TYPE	RETEH		;Type header
	TYPE	[ASCIZ/ Attempt to return pages to a section with no reserved pages
/]
	JRST	RET341		;Return status 1, restore acs
>;END IFN TOPS20

RETEH:	$TEXT	<?MMANGR: RETRN routine can't return memory, reason:
>
SUBTTL	Return status routines

RET341:	DMOVE	T3,MMAC34	;Restore acs 3 and 4
	JRST	RETST1		;Return status 1

RET340:	DMOVE	T3,MMAC34	;Restore acs 3 and 4
RETST0:	TDZA	T1,T1		;SET STATUS TO 0 and skip
RETST1:	MOVEI	T1,1		;SET STATUS TO 1
	POPJ	P,		;RETURN

CPOPJ1:	AOS	(P)		;Skip returns
CPOPJ:	POPJ	P,		;Single returns
SUBTTL	DATA SECTION

;Data used by the memory manager
IFE TOPS20,<
RELOC	0		;Relocate to low-segment
>;END IFE TOPS20

MMDST==.		;START OF DATA
MMAC12:	BLOCK	2	;USER'S ACS 1 AND 2
MMAC34:	BLOCK	2	;USER'S ACS 3 AND 4
MMAC56:	BLOCK	2
MMAC78:	BLOCK	2
MMEXSC:	BLOCK	1	;ALLOWED TO USE EXTENDED SECTIONS
NMMODS:	BLOCK	1	;NUMBER OF MODULES CONNECTED
NMSECS:	BLOCK	1	;NUMBER OF EXTENDED SECTIONS IN USE
HAVSC0:	BLOCK	1	;FLAG FOR "HAVE SECTION 0"
SC0MAP:	BLOCK	<^D512/^D36>+1	;A PAGE MAP FOR SECTION 0
SCMPSZ==.-SC0MAP	;NUMBER OF WORDS NEEDED
SAVEPB:	BLOCK	1	;SAVED BP TO SC0MAP
PTRLSU:	BLOCK	1	;POINTER TO LIST OF USERS
SECRST:	BLOCK	1	;SECTION WE ARE RESTRICTED TO USING (FINFRE)
CURSCB:	BLOCK	1	;CURRENT SECTION BLOCK POINTER
PSBLPG:	BLOCK	1	;Saved page number in "CHKFPS" routine
SAVRBP:	BLOCK	2	;Saved BP used by RETRN
RBPT:	BLOCK	2	;Byte ptr to extended section

;TOPS20- only locations
IFN TOPS20,<
MYPGS:	BLOCK	^D512*3	;Two pages for my lists
PTRLSS:	BLOCK	1	;Pointer to list of section maps
>;END IFN TOPS20

;TOPS10- only locations
IFE TOPS20,<
MYPGS:	BLOCK	^D512*2	;One page for my lists
PGUADR:	BLOCK	2	;PAGE. UUO argument block
SAVRNP:	BLOCK	1	;(RETRN) Number of pages to return
>;END IFE TOPS20

MMDEN==.-1		;END OF DATA

END