	.TITLE	AALLOCX
	.ident	/X01.03/

	.enabl	lc, gbl
	.nlist	bex
;	.list	meb

;
; Utility Routines
; Dynamic Space Management
;
; Version x01
;
; David G. Conroy	12-Dec-77
;
;
; Edit history
; 01 01-Aug-79 MM	Added RT11 support
; 02 16-Feb-81 MM	Removed EIS
; 03 27-Feb-82 RBD	Use unsigned compare for addresses. Bit me on TSX+
;			Globalize HILOCN for AS
;
; Note:
;	This routine is used only in the compiler/assembler library.
;	Work areas are forced into the root segment by allocating the
;	aldata .psect in CC0RT.
;
	.globl	$alloc
	.globl	$free
	.globl	hilocn						;03

	.mcall	call
	.mcall	callr
	.mcall	return
	.MCALL	GTSK$S
	.mcall	extk$s

;
; Equivalences
; LINK must be 0.
;

LINK	=	0		;Link to next block in free list
SIZE	=	2		;Size of the block

SLOP	=	8.		;Fuzz factor for space allocation

;
; Local Data (The RT11 linker requires this to be in the root).
;


limits:	.limit			;Load sizes (set by TKB)
GTSBUF:	.BLKW	16.		;WORK BUFFER FOR GTSK$S
avail:	.word	0
	.word	0
hilocn::							;03
	.word	0		;Highest loc+1 in partition (zero if not set)

	.even

;+
; ** $alloc -- allocate space
;
; This routine allocates a block of memory from the global free
; list.  This list is automatically  set up by '$alloc'  on the
; first call.
;
; If there is insufficient space to allocate the block and task
; extension has failed, $alloc calls the routine $deny and then
; returns whatever $deny leaves in r0.
;
; Inputs:
;	r0=size of block desired (bytes)
;
; Outputs:
;	r0=pointer to block
;-

$alloc:	mov	r3,-(sp)	;Save registers
	mov	r2,-(sp)
	mov	r1,-(sp)

	tst	hilocn		;Is this the first call
	bne	20$		;Br if not
	mov	r0,-(sp)	;Save size requested
	mov	limits+2,r0	;Get top address of task
	add	#3,r0		;Round up mod 4
	bic	#3,r0
	GTSK$S	#GTSBUF		;GET TASK PARAMETERS
	bcs	110$		;Something is nasty in the nursery
	MOV	GTSBUF+G.TSTS,R1	;R1=HIGHEST ADDR+1
	mov	r1,hilocn	;save new top of core
	sub	r0,r1		;Get size of core hole
	cmp	r1,#4		;If very small core hole
	blo	10$		;It cannot be freed		;01/03
	mov	r1,(r0)+	;Otherwise free it
	call	$free
10$:	mov	(sp)+,r0	;Get requested size back

20$:	add	#2+1,r0		;1 control word + rounding
	bic	#1,r0
	cmp	r0,#4		;Check for bad call
	blo	110$		;Abort if allocating zero words
	mov	r0,r1		;Save rounded size

30$:	mov	#avail,r3	;Points to free list header
40$:	mov	(r3),r2		;mov LINK(r3),r2
	beq	80$		;No space on the free list
	cmp	SIZE(r2),r0	;Is it usable
	bhis	50$
	mov	r2,r3		;No, continue the search
	br	40$

50$:	neg	r0		;Compute what is left over
	add	SIZE(r2),r0
	cmp	r0,#SLOP	;Do we want to leave what is left over
	bhis	60$		;Yes
	mov	(r2),(r3)	;No, unlink the block
	mov	r2,r0		;Setup for return
	mov	SIZE(r2),(r0)+
	br	100$

60$:	mov	r0,SIZE(r2)	;Adjust size in the block
	add	r2,r0		;Get pointer to the space to return
	mov	r1,(r0)+	;Put size in it
	br	100$		;Return

;
; Out of space
; Try to extend the task.
;

80$:
	add	#77,r0		;Get grow increment
	bic	#77,r0
	mov	r0,r2		;Save it, then
;	ash	#-6,r0		;Convert to 32 word blocks
	asr	r0						;02+
	asr	r0
	asr	r0
	asr	r0
	asr	r0
	asr	r0						;02-
	extk$s	r0		;Try to grow
	bcs	90$		;No
	mov	hilocn,r0	;Return new block to free list
	add	r2,hilocn
	mov	r2,(r0)+
	call	$free
	mov	r1,r0		;Setup size again, and
	br	30$		;Try again (must work)

90$:
	call	$deny		;No space

100$:	mov	(sp)+,r1	;Return
	mov	(sp)+,r2
	mov	(sp)+,r3
	return

110$:	CRASH			;Nasty

;+
; ** $free -- free space (obtained from '$alloc')
;
; This routine returns a block of memory, previously obtained
; from '$alloc', to the free pool.
; Needless to say,  grave disorder will result if some random
; integer  is passed to '$free',  or you try to '$free'  some
; space twice.
;
; Inputs:
;	r0=pointer to the space
;-

$free:	mov	r4,-(sp)	;Save some registers
	mov	r3,-(sp)
	mov	r2,-(sp)
	mov	r1,-(sp)
	mov	r0,-(sp)

	mov	-(r0),r1	;Fix pointer, get size

	mov	#avail,r3	;Free list pointer
10$:	mov	(r3),r2		;Walk down the list until
	beq	30$		;The end
	cmp	r2,r0		;Or the correct place is found
	bhi	20$
	mov	r2,r3
	br	10$

20$:	mov	r0,r4		;Test for collapse top end
	add	r1,r4
	cmp	r4,r2		;If they hit
	bne	30$
	add	SIZE(r2),r1	;Join them together
	mov	(r2),(r0)
	br	40$

30$:	mov	r2,(r0)		;Otherwise just link it in

40$:	mov	r3,r4		;Test for collapse bottom end
	add	SIZE(r3),r4
	cmp	r4,r0
	bne	50$
	add	r1,SIZE(r3)	;Merge them
	mov	(r0),(r3)
	br	60$

50$:	mov	r0,(r3)		;Otherwise finish linking it in
	mov	r1,SIZE(r0)

60$:	mov	(sp)+,r0	;Return
	mov	(sp)+,r1
	mov	(sp)+,r2
	mov	(sp)+,r3
	mov	(sp)+,r4
	return

	.END
