; **************** Our RISCOS 3.1 DA default settings *****************
#set RO31_First_DynamicAreaNo  = 6			;start DA number
#set RO31_Last_DynamicAreaNo   = 8			;allow 3 DA's

;RO31_DA_table structure:
STRUCT RO31_DA
{
  .address	DCD 0	;logical address
  .end_address	DCD 0	;current end address
  .max_size	DCD 0	;maximum size
  .reserved	DCD 0	;minimum size
  .size
}

; *********************************************************************



;RO31_OS_DynamicArea
;-------------------
;Implements OS_DynamicArea on RO3.1 (PRM5a-53)
;
;NOTE This code has to be 26bit / RO3.1 compatible only
;
;Entry:
; R0 = reason (0 - create, 1 - remove)
; R11 = pointer to VARS
;
;When 0 (create):
;  R2 = initial size
;  R2 = max size
;
;When 1 (remove):
;  R1 = area number

.RO31_OS_DynamicArea
 ADD     R12, R11, #RO31_DA_table - VARS	;pointer to DA table

 TEQ     R0, #0				;create area?
 BEQ     _create_new_DA			;YES, skip checks

 SUB     R14, R1, #RO31_First_DynamicAreaNo
 ADD     R12, R12, R14, LSL #4		;R12 now points at DA table entry

 CMP     R1, #RO31_First_DynamicAreaNo	;below our first DA?
 BLO     vector_handler_forward		;YES, pass to OS

 LDR     R14, [R11, #RO31_Next_DynamicAreaNo - VARS]
 CMP     R1, R14			;above our next DA?
 BHS     vector_handler_forward		;YES, pass to OS

 CMP     R0, #2
 BLO     _remove_DA			;remove area?
 BHI     vector_handler_trap		;area info? NO, exit

					;area info PRM5a-59
 LDR     R2, [R12, #RO31_DA.end_address]	;load the return values
 LDR     R3, [R12, #RO31_DA.address]	;logical address
 SUB     R2, R2, R3			;size
 MOV     R4, #0				;flags
 LDR     R5, [R12, #RO31_DA.max_size]	;max  size
 MOV     R6, #0				;handler
 MOV     R7, #0				;workspace
 ADR     R8, ADFFS_Title		;pointer to "ADFFS"
B       vector_handler_trap


._remove_DA				;remove area PRM5a-58
 STR     R0, [R13, #-4]!

 MOV     R0, #0
 STR     R0, [R12, #RO31_DA.max_size]	;mark DA as pending deletion

 LDR     R0, [R11, #RO31_Next_DynamicAreaNo - VARS]	;next DA number
 SUB     R0, R0, #1
 TEQ     R1, R0				;is this the last DA?
 STREQ   R0, [R11, #RO31_Next_DynamicAreaNo - VARS]	;YES, decrease DA counter
 BEQ     _okay_to_remove

 STMFD   R13!, {R1-R3, R12}		;not the last DA, so need to check
 MOV     R3, R1				;R3 = DA we were called for
 SUB     R2, R0, R1			;before allowing removal
 ADD     R12, R12, R2, LSL #4		;go to the last DA

 MOV     R2, #0
 ._L1
   LDR     R14, [R12, #RO31_DA.max_size]	;load max size, will be 0 if deleted
   ADDS    R2, R2, R14			;is it pending deletion?
   MOVEQ   R1, #-&6000000		;YES
   SWIEQ   XOS_ChangeDynamicArea	; |+ reduce DA to 0
   SUB     R0, R0, #1
   TEQ     R0, R3			;have we hit the DA we were called for?
 BNE     _L1
 LDMFD   R13!, {R1-R3, R12}

 TEQ     R2, #0				;can remove this DA?
 LDRNE   R0, [R13], #4			;NO,
 BNE     vector_handler_trap		; |+ can't remove DA yet

 ._okay_to_remove
 MOV     R14, R1
 LDR     R0, [R12, #RO31_DA.end_address]	;hand everything back
 LDR     R1, [R12, #RO31_DA.address]
 SUBS    R1, R1, R0			;R1 = size negated
 MOV     R0, R14			;R0 = DA number
B       _P1


;_create_new_DA
;--------------
;Creates a new DA
;
;Entry:
; R1 = -1 (or new area number)
; R2 = initial size
; R3 = -1 (or logical address of area)
; R4 = area flags
; R5 = max size (-1 unlimited)
; R6 = pointer to dynamic area handler routine
; R7 = pointer to workspace (passed in R12 to handler)
; R8 = pointer to dynamic area name
; R11 = pointer to VARS
; R12 = ptr to RO31_DA_table

._create_new_DA				;create area PRM5a-55
 STR     R0, [R13, #-4]!

 CMN     R1, #1				;is the area number unset?
 CMNNE   R3, #1				;is the base logical address unset?
 BNE     _error				;NO, error
 CMP     R5, #RO31_DynamicAreaLimit	;is max size too big?
 BHI     _error				;NO, error
 CMP     R5, #0				;is max size set?
 BEQ     _error				;NO, error

 LDR     R0, [R11, #RO31_Next_DynamicAreaNo - VARS]	;next DA number
 TEQ     R0, #RO31_Last_DynamicAreaNo+1	;have we hit our limit
 BEQ     _error				;YES, error
 ADD     R1, R0, #1			;increase
 STR     R1, [R11, #RO31_Next_DynamicAreaNo - VARS]	;store back

 STMFD   R13!, {R0, R4}
 SUB     R1, R0, #RO31_First_DynamicAreaNo
 ADD     R12, R12, R1, LSL #4		;R12 now points at DA table entry

 SWI     XOS_ReadMemMapInfo		;check if we need to reserve the full
					;DA to prevent memory conflicts
 MUL     R4, R0, R1			;R4 = memory size in bytes

 ADD     R0, R11, #RO31_DynamicAreaAddress - VARS
 LDR     R3, [R0, #0]			;next DA address end
 SUB     R3, R3, R5			;R3 = start of new DA
 STR     R3, [R0, #0]			;update next DA address end
 STR     R3, [R12, #RO31_DA.address]	;store DA start address
 STR     R3, [R12, #RO31_DA.end_address]	;store DA end address
 STR     R5, [R12, #RO31_DA.max_size]	;store DA max size
 CMP     R4, R3				;is there a possible memory conflict?
 MOVHI   R2, R5				;YES, allocate max amount
 LDMFD   R13!, {R0, R4}

 MOVS    R1, R2				;R1=size of DA

;Entry:
; R0 - DA number
; R1 - size change
 ._P1
 STR     R0, [R13, #-4]!		;preserve DA number
 SWINE   XOS_ChangeDynamicArea		;create area if >0  PRM1-384
 LDR     R1, [R13], #4			;preserve DA number
 BVS     _error_exit

 LDR     R0, [R13], #4
 B       vector_handler_trap


._error
 ADR     R0, error_DA_failed
._error_exit
 ADD     R13, R13, #4			;drop R0 from stack
B       vector_handler_trap_VS
