;
; dynAnchor.s
;
; Useful handle RMA allocation for dynamite
;
;  1994-1998 Straylight
;
;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Dynamite
;
; Dynamite is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; Dynamite is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with Dynamite.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


;----- Standard header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

;----- External dependencies ------------------------------------------------

		GET	sh.wSpace

;----- Constants ------------------------------------------------------------

danc__chunk	EQU	16			;Number of handles to get

;----- Main code ------------------------------------------------------------

		AREA	|Dynamite$$Code|,CODE,READONLY

; --- danc_alloc ---
;
; On entry:	--
;
; On exit:	R0 == pointer to block allocated, or V set and pointer to
;		      error
;
; Use:		Allocates an anchor to use with dynamite from the RMA,
;		in a very quick way indeed.

		EXPORT	danc_alloc
danc_alloc	ROUT

		STMFD	R13!,{R1-R3,R14}

		; --- Are there any free blocks? ---

		LDR	R2,dyn_ancTable		;Get the free list offset
		CMP	R2,#0			;Are there any free blocks?
		BEQ	%01danc_alloc		;No -- better allocate some

		; --- Mess about with the free list and return ---

00danc_alloc	LDR	R3,[R2]			;Get next pointer from block
		STR	R3,dyn_ancTable		;This is now first free block
		MOV	R0,R2			;Point to the block
		LDMFD	R13!,{R1-R3,PC}^	;Restore registers and return

		; --- Create a big block ---

01danc_alloc	MOV	R0,#6			;Allocate memory please
		MOV	R3,#danc__chunk*4+4	;Get the chunk size
		SWI	XOS_Module		;Allocate the big block then
		LDMVSFD	R13!,{R1-R3,PC}		;If it failed, return error

		LDR	R14,dyn_ancList		;Load current list head
		STR	R2,dyn_ancList		;Save this as new list head
		STR	R14,[R2],#4		;And save old list head

		; --- Now set up the links for the free list ---

		MOV	R0,#0			;Next free pointer start at 0
		SUB	R3,R3,#8		;Offset to next field of sub
02danc_alloc	STR	R0,[R2,R3]		;Store in next field
		ADD	R0,R2,R3		;Point to that block
		SUBS	R3,R3,#4		;Point to previous block
		BGE	%02danc_alloc		;If more to do, continue...

		; --- The links are set up -- now take off a block ---

		B	%00danc_alloc		;Then allocate as normal

		LTORG

; --- danc_free ---
;
; On entry:	R0 == pointer to block
;
; On exit:	Registers preserved
;
; Use:		Frees an anchor allocated using danc_alloc.

		EXPORT	danc_free
danc_free	ROUT

		STMFD	R13!,{R0,R1,R14}	;Preserve registers

		; --- Mess about with the list ---

		LDR	R1,dyn_ancTable		;Get current first block
		STR	R1,[R0]			;Store in newly freed block
		STR	R0,dyn_ancTable		;And insert new block in list
		LDMFD	R13!,{R0,R1,PC}^	;Oh, and return to caller

		LTORG

; --- danc_quit ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Frees everyone's anchors nicely when the module quits.

		EXPORT	danc_quit
danc_quit	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		LDR	R2,dyn_ancList		;Load the list head
		CMP	R2,#0			;Is there anything to do?
		LDMEQFD	R13!,{R0-R2,PC}^	;No -- return then
		MOV	R0,#7			;Free RMA block
00danc_quit	LDR	R1,[R2,#0]		;Load the next pointer
		SWI	XOS_Module		;Free the block
		MOVS	R2,R1			;Point to next one
		BNE	%00danc_quit		;And loop round for more
		LDMFD	R13!,{R0-R2,PC}^	;Return when all done

		LTORG

;----- That's all, folks ----------------------------------------------------

		END
