STRUCT codelet_struct
{
  .next		DCD 0			;16 words if codelets reused,
  .previous	DCD 0			;8 word if not
  .size		DCD 0
#if JIT_codelet_reuse == 1 OR Unaligned_Support == 1
  .instruction	DCD 0			;JIT modified original instruction
  .use_count	DCD 0
  .validation	DCD 0
  .original	DCD 0			;original instruction
		DBD 4			;pad so code is cache aligned
#endif
  .source	DCD 0			;PC at original instruction
					;if source=0 the codelet is immortal
  .trace	DCD 0			;instruction trace pointer
  .tmp3		DCD 0			;3 temp vars for codelet use
  .tmp2		DCD 0			;must preceded codelet
  .tmp1		DCD 0
  .codelet				;needs to cache align if possible
}


#set codelet_alignment	= codelet_struct.codelet	;hopefully cache align codelets
#set codelet_PC		= codelet_struct.codelet - codelet_struct.source
#set min_codelet_size	= codelet_struct.codelet + codelet_alignment
#set B_blank = &EA000000		;blank B instruction for codelet returns
#set CODELET_validation = &0CDE1E70





;allocate_codelet
;----------------
;find and allocate space for a codelet
;
;Entry:
; R0 - original instruction
; R1 - use counter
;	1 - can be reused
;	0 - cant be reused
; R6 - size
; R7 - original instruction address + 8
;
;Exit:
; R1 - 0 if an existing codelet has been used
; R6 - pointer to codelet code start

 ALIGN   32, 4
.allocate_codelet
 STMFD   R13!, {R0, R2-R3, R14}

 #if JIT_codelet_reuse == 1
   BIC     R0, R0, #OP_condition		;drop condition

   TEQ     R1, #0				;can we use an existing codelet?
   BEQ     _need_new_codelet			;NO

   ;codelet can be reused, check for existing match
   LDR     R1, first_codelet			;get first codelet address
   ._codelet_reuse_L1
     LDR     R2, [R1, #codelet_struct.instruction]
     TEQ     R2, R0				;same instruction?
     BEQ     _codelet_found			;YES

     MOV     R3, R1
     LDR     R1, [R1, #codelet_struct.next]	;get next block address
     CMP     R1, R3				;is it the last codelet
   BLO     _codelet_reuse_L1			;NO
   B       _need_new_codelet			;YES, needs a new codelet

   ._codelet_found
   LDR     R14, [R1, #codelet_struct.use_count]
   ADD     R14, R14, #1				;increase use counter
   STR     R14, [R1, #codelet_struct.use_count]
;@@@ now need to add this source address to the list of addresses this
;    codelet serves
   MOV     R14, #0				;no need for new codelet
   TEMP    R2
   STR     R14, codelet_cache_flush		;so no requirement to clean the cache
   LOCK    R2
   B       _exit

   ._need_new_codelet
 #endif
						;find free codelet
 ADR     R2, codelet_cache_flush
 #if JIT_instruction_trace == 1
   ADD     R6, R6, #JIT_IT_codelet_size
 #endif
 MOV     R1, #lastfree_codelet
 STR     R6, [R2, #4]
 ADD     R6, R6, #codelet_struct.codelet + codelet_alignment - 1
 BIC     R6, R6, #codelet_alignment - 1
 ._L1
   LDR     R1, [R1, #codelet_struct.next]	;get next block address
   LDR     R3, [R1, #codelet_struct.size]	;R3=codelet.size
   CMP     R3, R6				;is it big enough?
   BHS     _found_space				;YES
   TEQ     R1, #lastfree_codelet		;have we looped?
 BNE     _L1					;NO

 MOV     R1, #&1D				;ADFF501D
 B       JIT_report_unimplemented_debug		;ran out of codelet memory

 ._found_space
 SUB     R3, R3, R6				;R3 = freesize

 CMP     R3, #min_codelet_size			;is there room for another codelet?
 STRHS   R3, [R1, #codelet_struct.size]		;YES, codelet.size = freesize
 ADDHS   R1, R1, R3				; |   codelet = codelet + freesize
 STRHS   R6, [R1, #codelet_struct.size]		; |   codelet.size = required
 ADD     R14, R1, #codelet_struct.codelet
 STR     R14, [R2, #0]				;store address for cache clean
 BHS     _P1					; |+  allocate space as free

 ;update previous/next free
 LDR     R2, [R1, #codelet_struct.previous]	;R2 = codelet.previous
 LDR     R14, [R1, #codelet_struct.next]	;R14 = codelet.next
 STR     R14, [R2, #codelet_struct.next]	;(codelet.previous).next = codelet.next
 STR     R2, [R14, #codelet_struct.previous]	;(codelet.next).previous = codelet.previous
 ._P1

 ;update previous/next allocated
 LDR     R2, [R1, #codelet_struct.size]		;R2 = codelet.size
 ADD     R3, R1, R2				;R3 = codelet.previous = codelet + codelet.size
 LDR     R14, [R3, #codelet_struct.next]	;R14 = (codelet.previous).next
 STR     R3, [R1, #codelet_struct.previous]	;codelet.previous = R3
 STR     R14, [R1, #codelet_struct.next]	;codelet.next = (codelet.previous).next
 STR     R1, [R3, #codelet_struct.next]		;(codelet.previous).next = codelet
 STR     R1, [R14, #codelet_struct.previous]	;(codelet.next).previous = codelet

 STR     R7, [R1, #codelet_struct.source]	;codelet.source = instr addr

 #if JIT_codelet_reuse == 1 AND JIT_cache_consistency == 1
   LDR     R2, [R7, #-8]
   AND     R14, R2, #%1111 << 24
   TEQ     R14, #%10011 << 24			;BL?
   STRNE   R2, [R1, #codelet_struct.original]	;NO
   STREQ   R0, [R1, #codelet_struct.original]	;YES, store modified
 #endif
 #if JIT_codelet_reuse == 1 OR Unaligned_Support == 1
   MOV     R14, #1
   STR     R0, [R1, #codelet_struct.instruction]
   STR     R14, [R1, #codelet_struct.use_count]	;reset use counter
   MOV     R14, #CODELET_validation
   STR     R14, [R1, #codelet_struct.validation]
 #endif

 #if compile_RO > 311 AND JIT_debug == 1
   ADR     R2, jit_codelet_count
   LDR     R0, [R2]
   ADD     R0, R0, #1 << 8
   STR     R0, [R2]
 #endif

 ._exit
 ADD     R6, R1, #codelet_struct.codelet	;return codelet
LDMFD   R13!, {R0, R2-R3, PC}




;free_codelet
;------------
;Marks a codelet as released and defrags the heap up and down if possible
;SWI codelets are not released, as they're immortal (no longer required)
;
;Entry:
; R2 = codelet_struct.codelet - 8
;
;Exit:
; registers preserved : (R2 is actually okay to corrupt)

 ALIGN   32, 4
.free_codelet
 STMFD   R13!, {R0-R3, R14}

 SUB     R2, R2, #codelet_struct.codelet - 8	;R2=codelet header
 MOV     R0, #0

 #if JIT_codelet_reuse == 1 OR Unaligned_Support == 1
   LDR     R1, [R2, #codelet_struct.use_count]
   SUBS    R1, R1, #1				;last codelet use?
   STRNE   R1, [R2, #codelet_struct.use_count]	;NO
;@@@ next two lines need to remove this source address from the codelet
;    reuse list
   MVNNE   R0, #0				;mark source as cleared
   STRNE   R0, [R2, #codelet_struct.source]	;codelet.source = -1
   LDMNEFD R13!, {R0-R3, PC}			; |+ leave codelet and exit

   STR     R0, [R2, #codelet_struct.instruction] ;YES, clean the instruction
   STR     R0, [R2, #codelet_struct.validation]
 #endif

 STR     R0, [R2, #codelet_struct.source]	;codelet.source = 0

 #if JIT_debug == 1
   ADR     R1, jit_codelet_count
   LDR     R14, [R1]
   SUB     R14, R14, #1 << 8			;decrease codelet count
   ADD     R14, R14, #1				;and increase recycle indicator
   BIC     R14, R14, #%100000
   STR     R14, [R1]
 #endif

 ;update previous/next allocated
 LDR     R0, [R2, #codelet_struct.next]		;R0 = codelet.next
 LDR     R1, [R2, #codelet_struct.previous]	;R1 = codelet.previous
 STR     R0, [R1, #codelet_struct.next]		;(codelet.previous).next = codelet.next
 STR     R1, [R0, #codelet_struct.previous]	;(codelet.next).previous = codelet.previous

 ;find next free
 MOV     R1, #lastfree_codelet			;R1 = next
 ._L1						;repeat
   LDR     R1, [R1, #codelet_struct.next]	;next = next.next
   CMP     R1, R2				;until next < codelet
 BHI     _L1

 LDR     R14, [R2, #codelet_struct.size]	;R14 = codelet.size

 ;defrag down
 LDR     R0, [R1, #codelet_struct.size]	;R0 = next.size
 ADD     R3, R1, R0				;R3 = next + next.size
 TEQ     R3, R2					;if next + next.size = codelet
 ADDEQ   R14, R14, R0				;then size += next.size
 MOVEQ   R2, R1					;codelet = next
 LDREQ   R0, [R1, #codelet_struct.next]		;R0 = next.next
 MOVNE   R0, R1					;R0 = next

 ;defrag up
 LDR     R1, [R1, #codelet_struct.previous]	;R1 = previous
 ADD     R3, R2, R14				;R3 = codelet + codelet.size
 TEQ     R3, R1					;if codelet + codelet.size = previous
 LDREQ   R3, [R1, #codelet_struct.size]		;R3 = previous.size
 LDREQ   R1, [R1, #codelet_struct.previous]	;previous = previous.previous
 ADDEQ   R14, R14, R3				;size += previous.size
						;R1 = previous codelet

 STR     R14, [R2, #codelet_struct.size]	;codelet.size = size

 ;update previous/next free
 STR     R0, [R2, #codelet_struct.next]		;codelet.next = next
 STR     R1, [R2, #codelet_struct.previous]	;codelet.previous = previous
 STR     R2, [R0, #codelet_struct.previous]	;next.previous = codelet
 STR     R2, [R1, #codelet_struct.next]		;previous.next = codelet

LDMFD   R13!, {R0-R3, PC}
