;
; lit.s
;
; Literal pool management
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's BASIC Assembler Supplement.
;
; BAS 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.
;
; BAS 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 BAS.  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

		GET	libs:stream

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

		GET	sh.aofGen
		GET	sh.bas
		GET	sh.fastMove
		GET	sh.flex
		GET	sh.insert
		GET	sh.workspace

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

		AREA	|BAS$$Code|,CODE,READONLY

; --- lit_add ---
;
; On entry:	R0 == address of literal data
;		R1 == size of literal data
;		R2 == word align flag
;
; On exit:	R0 set up as described below.
;
; Use:		Adds the given data to the current literal pool.  On the
;		first pass, it returns the value of P% in R0.  On the
;		second pass, it returns the address of the literal item.

		EXPORT	lit_add
lit_add		ROUT

		STMFD	R13!,{R1-R5,R12,R14}	;Save some registers
		STR	R12,[R7,#:INDEX:be__line] ;Store line value
		MOV	R12,R7			;Find my workspace
		MOV	R3,R0			;Keep the start address
		MOV	R4,R1			;And the size of the block

		BL	aof_firstPass		;Is this the first pass?
		BCS	%50lit_add		;Yes -- behave totally oddly

		; --- Handle word aligning ---

		CMP	R2,#0			;Is the word align flag on?
		BEQ	%10lit_add		;No -- don't bother then
		LDR	R1,lit__contents+4	;Load the current size
		ANDS	R1,R1,#3		;Get the nonwordalignedness
		BEQ	%10lit_add		;No excess -- skip on then
		RSB	R1,R1,#4		;Find how much we have to add
		ADR	R0,lit__contents	;Point to the contents block
		BL	aof_ensure		;Get the memory area
		MOV	R14,#0			;A nice zero byte
05lit_add	STRB	R14,[R0],#1		;Store it in the block
		SUBS	R1,R1,#1		;Decrement the counter
		BGT	%05lit_add		;And carry on round

		; --- Now add the contents ---

10lit_add	LDR	R5,lit__contents+4	;Load offset of literal item
		ADR	R0,lit__contents	;Point to the contents block
		MOV	R1,R4			;Get the block size
		BL	aof_ensure		;Make sure it's big enough
		MOV	R1,R3			;Point to caller's block
		MOV	R2,R4			;Get the size
		BL	fastMove		;Copy it over PDQ

		; --- Now return the correct address ---

		LDR	R14,lit__next		;Find next literal index
		LDR	R0,lit__table		;Find the literal table
		LDR	R0,[R0,R14]		;Load the pool base address
		ADD	R0,R0,R5		;And add the item offset
		LDMFD	R13!,{R1-R5,R12,PC}^	;And return to caller

		; --- Handle a literal pool request on first pass ---

50lit_add	LDR	R3,lit__contents+4	;Load the current size
		CMP	R2,#0			;Are we word aligning?
		ADDNE	R3,R3,#3		;If so, word align this
		BICNE	R3,R3,#3		;In time-honoured fashion
		ADD	R3,R3,R1		;Add on size of item
		STR	R3,lit__contents+4	;Save the new size back
		LDR	R0,be__percents		;Find the % variables
		LDR	R0,[R0,#('P'-'A')*4]	;Load current P% value
		LDMFD	R13!,{R1-R5,R12,PC}^	;And return to caller

		LTORG

; --- lit_ltorg ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Inserts a literal pool at the current position.

		EXPORT	lit_ltorg
lit_ltorg	ROUT

		STMFD	R13!,{R0-R4,R12,R14}	;Save some registers
		STR	R12,[R7,#:INDEX:be__line] ;Store line value
		MOV	R12,R7			;Find my workspace
		BL	insert_align		;Word align current pos

		LDR	R14,lit__contents+4	;Any data in literal pool?
		CMP	R14,#0			;If so, this won't be 0
		BEQ	%90lit_ltorg		;No -- just align then

		LDR	R4,be__percents		;Find the % variables

		BL	aof_firstPass		;Is this the first pass?
		BCC	%20lit_ltorg		;No -- do the copying then

		; --- Add an entry into the literal table ---

		LDR	R2,[R4,#('P'-'A')*4]	;Load current P% value
		ADR	R0,lit__table		;Find the literal table
		MOV	R1,#4			;Entries are 1 word long
		BL	aof_ensure		;Make the space for it
		STR	R2,[R0],#4		;Store address in the block
		B	%50lit_ltorg		;Do the rest of the LTORG op

		; --- Copy the data in the pool over ---

20lit_ltorg	LDR	R0,[R4,#('O'-'A')*4]	;Load current O% value
		ADR	R1,lit__contents	;Find the pool contents
		LDMIA	R1,{R1,R2}		;Load address and size
		BL	fastMove		;Copy the data over

		ADR	R0,lit__contents	;Point to the anchor
		MOV	R1,#256			;Reduce it in size again
		BL	flex_extend		;Put the block back again
		STR	R1,lit__contents+8	;Save this as the block size

		LDR	R14,lit__next		;Load next literal pool index
		ADD	R14,R14,#4		;Bump it along one word
		STR	R14,lit__next		;Save it back again

		; --- Now move on P% and O% ---

50lit_ltorg	LDR	R0,lit__contents+4	;Load the pool size
		ADD	R1,R4,#('O'-'A')*4	;Point to current O% value
		LDMIA	R1,{R2,R3}		;Load O% and P% out
		ADD	R2,R2,R0		;Bump O% along
		ADD	R3,R3,R0		;Bump P% along
		STMIA	R1,{R2,R3}		;Save adjusted values back

		MOV	R0,#0			;Next literal pool is clear
		STR	R0,lit__contents+4	;So reset its size to 0

90lit_ltorg	BL	insert_align		;Word align location

		LDMFD	R13!,{R0-R4,R12,PC}^	;And return to caller

		LTORG

; --- lit_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises things for the Literal Manager.

		EXPORT	lit_init
lit_init	ROUT

		STMFD	R13!,{R0-R3,R14}	;Save some registers
		MOV	R2,#0			;Blocks currently empty
		MOV	R3,#256			;Initial size is 256
		MOV	R1,#256			;Allocate to 256 bytes

		ADR	R0,lit__table		;Point to lit table anchor
		BL	flex_alloc		;Try to allocate memory
		STMCCIB	R0,{R2,R3}		;Save size information
		ADRCC	R0,lit__contents	;Point to lit contents anchor
		BLCC	flex_alloc		;Try to allocate memory
		STMCCIB	R0,{R2,R3}		;Save size information
		BCS	bas_noMem		;If no memory, die horridly

		MOV	R14,#0			;No current lit pool index
		STR	R14,lit__next		;So save 0 as index
		LDMFD	R13!,{R0-R3,PC}^	;And return to caller

		LTORG

; --- lit_end ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Tidies up the Literal Manager after saving an AOF file.

		EXPORT	lit_end
lit_end		ROUT

		STMFD	R13!,{R0,R7,R14}	;Save some registers
		MOV	R7,R12			;For technical reasons
		LDR	R12,be__line		;Keep the line number right
		BL	lit_ltorg		;Insert final literal pool
		MOV	R12,R7			;Restore the workspace ptr
		ADR	R0,lit__table		;Point to table anchor
		BL	flex_free		;Free the memory
		ADR	R0,lit__contents	;Point to contents block
		BL	flex_free		;Free the memory
		LDMFD	R13!,{R0,R7,PC}^	;And return to caller

		LTORG

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

		END
