/
/
/	here to allocate a new block
/
/	mov	...,r0
/	jsr	pc,allocate
/	mov	r1,...
/
/	requested size in bytes in r0
/	pointer to header of allocated block returned in r1
/	r0 is preserved
/
/	convert to words, adjust for header, round up
/	to a power of two
/
/	each block has a four-word header
/		W - write ptr (also used as link ptr in frlist)
/		R - read ptr
/		A - pointer to head of data
/		L - ptr to (end+1) of data
w=0
r=2
a=4
l=6
/
allocate:
	clr	garbage
	mov	r0,-(sp)
	mov	r2,-(sp)
	tst	stats
	bne	1f
	jsr	pc,init
1:
	inc	stats
	bne 9f; inc stats; 9:
	cmp	r0,$strend-strbuf
	blos 9f; 4; 9:
1:
	cmp	$8.,r0
	blo	2f
	mov	$3.,r0
	br	1f
2:
	sub	$1,r0
	bmi	1f
	jsr	pc,log2
	add	$1,r0
1:	asl	r0		/bite to word
	mov	r0,-(sp)
	add	$2,r0
	cmp	r0,$frend-frlist+2
	blo	zzz
	jmp	err
/
/	look on free list for block of required size
/
zzz:
	mov	(sp),r0
	tst	frlist(r0)
	beq	xxx
/
/	found it, allocate and return
/
	mov	frlist(r0),r1
	mov	(r1),frlist(r0)
	mov	a(r1),r0
	mov	r0,w(r1)		/W
	mov	r0,r(r1)		/R
	tst	(sp)+
	mov	(sp)+,r2
	mov	(sp)+,r0
	rts	pc
/
/	no block of required size
/	look for larger block
/
xxx:
	tst	hdrptr
	bne	1f
	mov	r0,-(sp)
	jsr	pc,morehd
	tst	r0
	bne	out
	mov	(sp)+,r0
1:
	tst	(r0)+
	cmp	r0,$frend-frlist
	bhis	www
	tst	frlist(r0)
	bne	yyy
	br	xxx
/
/	there are no larger blocks;  must garbage collect
/
www:
	jsr	pc,collect
	tst	r0
	bne	zzz
	jsr	pc,moresp
	tst	r0
	beq	zzz
/
/	out of space
/
out:
	mov	$1,r0
	sys	write; 1f; 2f-1f
	jmp	reset
1:	<Out of space.\n>
2:	.even
/
/	split larger block into two smaller pieces and
/	link together as smaller blocks in the free list.
/
yyy:
	mov	frlist(r0),r1
	mov	(r1),frlist(r0)
	mov	hdrptr,r2
	bne	1f
	mov	r0,-(sp)
	jsr	pc,morehd
	tst	r0
	bne	out
	mov	(sp)+,r0
	mov	hdrptr,r2
1:
	mov	(r2),hdrptr
	clr	(r2)
	mov	r2,(r1)
	mov	r1,hdrptr(r0)
	mov	l(r1),l(r2)
	mov	l(r1),r0
	sub	a(r1),r0
	asr	r0
	add	a(r1),r0
	mov	r0,l(r1)
	mov	r0,a(r2)
	br	zzz
/
/
/	here to release a block
/
/	mov	...,r1
/	jsr	pc,release
/
/	pointer to block in r1
/
release:
/
/	discover that this is a plausible pointer
/
	mov	r0,-(sp)
	jsr	pc,preposterous
/
/	find free list index and link block to that entry
/
	inc	stats+2
	mov	frlist(r0),(r1)
	clr	r(r1)
	mov	r1,frlist(r0)
	clr	r1		/self-defense
	mov	(sp)+,r0
	rts	pc
/
/
/	jsr	pc,collect
/
/	coalesce free storage by rejoining paired blocks
/	on the free list.
/	zero is returned in r0 if no paired blocks were found.
/
collect:
	mov	r1,-(sp)
	mov	r2,-(sp)
	mov	r3,-(sp)
	mov	r4,-(sp)
	clr	useful
	inc	stats+4.
	clr	r0		/start with smallest blocks
				/r0 contains frlist index
loop1:	mov	$frlist,r1
	add	r0,r1
/
/	try next list member at this level
/
loop2:	mov	(r1),r3
	beq	advance		/list is empty
	tst	*(r1)		/W
	beq	advance		/only one list element
/
/	calculate address of buddy
/
	mov	a(r3),r4
	mov	$block,r2
1:
	cmp	r4,(r2)
	blo	1f
	cmp	(r2),lblock
	beq	2f
	add	$2,r2
	br	1b
1:
	sub	$2,r2
2:
	mov	(r2),beg
	sub	beg,r4
	bit	exp2(r0),r4
	beq	2f
	bic	exp2(r0),r4
	br	1f
2:	bis	exp2(r0),r4
1:	add	beg,r4
/
/	and search for him
/
loop3:	tst	0(r3)
	beq	nocoal
	mov	(r3),r2
	cmp	a(r2),r4
	beq	coal
	mov	(r3),r3
	br	loop3
/
/	have found a pair; remove both blocks from list,
/	coalesce them, and put them on next higher list
/
coal:	inc	useful
	mov	(r3),r4
	mov	(r4),(r3)	/remove him from list
	mov	(r1),r2
	mov	(r2),(r1)	/remove the other one
	cmp	a(r2),a(r4)
	bhi	1f
	mov	r2,-(sp)
	mov	r4,r2
	mov	(sp)+,r4
1:	add	exp2(r0),l(r4)
	clr	r(r4)
	mov	frlist+2(r0),(r4)
	mov	r4,frlist+2(r0)
	mov	hdrptr,(r2)
	mov	r2,hdrptr
	clr	r(r2)
	mov	beg,a(r2)
	mov	beg,l(r2)
	br	loop2
/
/	no buddy found, try next block on this list
/
nocoal:
	mov	(r1),r1
	br	loop2
/
/	advance to next free list
/
advance:
	tst	(r0)+
	cmp	r0,$frend-frlist
	blo	loop1
	mov	useful,r0
/
/	do we have enough headers to continue?
/
	cmp	garbage,$2
	blo	1f
	mov	$1,r0
	sys	write; 4f; 5f-4f
	jmp	reset
/
4:	<Out of space - too big a block.\n>
5:	.even
/
/
/	restore registers and return
/
1:
	inc	garbage
	mov	(sp)+,r4
	mov	(sp)+,r3
	mov	(sp)+,r2
	mov	(sp)+,r1
	rts	pc
/
.bss
garbage: .=.+2
.text
/
/	routine to get more space for strings
/
moresp:
	mov	r2,-(sp)
	mov	r1,-(sp)
	mov	brk,r1
	mov	$block,r2
	add	nblock,r2
	cmp	r2,$blkend
	bhis	rout
	mov	r1,(r2)
	mov	r1,lblock
	add	$2,nblock
	add	$10000,r1
	mov	r1,9f
	sys	break;9:..
	bes	2f
	mov	hdrptr,r2
	bne	1f
	jsr	pc,morehd
	tst	r0
	beq	2f
	mov	hdrptr,r2
1:
	mov	(r2),hdrptr
	mov	brk,a(r2)
	mov	r1,brk
	mov	r1,l(r2)
	clr	r(r2)
	mov	$10000,r0
	jsr	pc,log2
	asl	r0
	mov	frlist(r0),w(r2)
	mov	r2,frlist(r0)
	clr	r0
	mov	(sp)+,r1
	mov	(sp)+,r2
	rts	pc
2:
	mov	$1,r0
	mov	(sp)+,r1
	mov	(sp)+,r2
	rts	pc
/
/	routine to get move space for headers
/
morehd:
	mov	r2,-(sp)
	mov	brk,r0
	mov	$hblock,r2
	add	nhdr,r2
	cmp	r2,$hblkend
	bhis	rout
	mov	r0,(r2)
	mov	r0,lhblock
	add	$2,nhdr
	add	$1024.,r0
	mov	r0,9f
	sys	break;9:..
	bes	2f
	mov	brk,r2
	mov	r2,hdrptr
	mov	r0,brk
	sub	$8,r0
1:
	add	$8,r2
	mov	r2,-8(r2)
	cmp	r2,r0
	blos	1b
	clr	-8(r2)
	clr	r0
	mov	(sp)+,r2
	rts	pc
2:
	mov	$1,r0
	mov	(sp)+,r2
	rts	pc
rout:
	mov	$1,r0
	sys	write; 4f; 5f-4f
	jmp	reset
/
4:	<out of space - no more block storage\n>
5:	.even
/
/	routine to find integer part of log2(x)
/
/	jsr	pc,log2
/
/	r0 = log2(r0)
/
log2:
	mov	r0,-(sp)
	bge 9f; 4; 9:
	mov	$15.,r0
1:
	rol	(sp)
	bmi	1f
	sob	r0,1b
1:
	dec	r0
	tst	(sp)+
	rts	pc
/
	0		/Don't move me, I'm exp(-1)
exp2:
	1;2;4;10;20;40;100;200;400;1000;2000;4000;
	10000;20000;40000;100000
/
/	routine to discover whether r1 points to
/	a plausible header - to avoid ruination.
/
/	r1 is preserved and r0 gets a suitable index for frlist
/
/	jsr	pc,preposterous
/
preposterous:
	mov	r2,-(sp)
	mov	$hblock,r2
1:
	cmp	r1,(r2)
	blo	1f
	cmp	(r2),lhblock
	beq	2f
	add	$2,r2
	br	1b
1:
	sub	$2,r2
2:
	mov	(r2),r2
	add	$1024.,r2
	cmp	r1,r2
	blo	9f;4;9:
	mov	$block,r2
1:
	cmp	a(r1),(r2)
	blo	1f
	cmp	(r2),lblock
	beq	2f
	add	$2,r2
	br	1b
1:
	sub	$2,r2
2:
	cmp	l(r1),(r2)
	bhis	9f;4;9:
	mov	(r2),r2
	add	$10000,r2
	cmp	a(r1),r2
	blo	9f;4;9:
	cmp	l(r1),r2
	blos	9f;4;9:
	mov	(sp)+,r2
	mov	l(r1),r0		/L
	sub	a(r1),r0		/A
	mov	r0,-(sp)
	jsr	pc,log2
	asl	r0
	cmp	exp2(r0),(sp)
	beq 9f; 4; 9:
	add	$2,r0
	cmp	r0,$frend-frlist+2
	blo 9f; 4; 9:
	sub	$2,r0
	mov	r0,(sp)
	mov	frlist(r0),r0
1:	beq	1f
	cmp	r0,r1
	bne 9f; 4; 9:
	mov	(r0),r0
	br	1b
1:	mov	(sp)+,r0
	rts	pc
/
/
/	routine to initialize storage area, headers and
/	free list upon first call to allocate a block.
/	The entire storage area is formed into a single block.
/
init:
	mov	r0,-(sp)
	mov	r1,-(sp)
/
/	form all the headers into a single list.
/
	mov	$headers,r0
	mov	r0,hdrptr
1:	add	$8,r0
	mov	r0,-8(r0)
	cmp	r0,$headend-8
	blos	1b
	clr	-8(r0)
	mov	$frlist,r0
1:	clr	(r0)+
	cmp	r0,$frend
	blo	1b
/
	mov	hdrptr,r1
	mov	(r1),hdrptr
	clr	w(r1)
	mov	$strbuf,r0
	mov	r0,a(r1)
	mov	$strend-strbuf,r0
	jsr	pc,log2
	asl	r0
	cmp	r0,$frend-frlist
	blo 9f; 4; 9:
	mov	r1,frlist(r0)
	mov	exp2(r0),r0
	add	$strbuf,r0
	mov	r0,l(r1)
	mov	$hdrptr,r1
1:	mov	(r1),r1
	tst	r1
	beq	1f
	mov	$strbuf,a(r1)
	mov	$strbuf,l(r1)
	br	1b
1:
	mov	$end,brk
	add	$2,nblock
	mov	$strbuf,block
	mov	$strbuf,lblock
	mov	$headers,hblock
	add	$2,nhdr
	mov	$headers,lhblock
	mov	(sp)+,r1
	mov	(sp)+,r0
	rts	pc


.bss
nhdr:	.=.+2
lhblock:	.=.+2
hblock:	.=.+20.
hblkend:
stats:	.=.+16.
useful:	.=.+2
beg:	.=.+2
lblock:	.=.+2
nblock:	.=.+2
block:	.=.+40.
blkend:
brk:	.=.+2
hdrptr:	.=.+2	/do not move me
frlist:	.=hdrptr+32.
frend:
headers:.=hdrptr+1024.
headend:
strbuf:	.=.+10000
strend:
end:
signal = 48.
