	; --------------------------
	; Data Directory area (DDIR)
	; --------------------------

; Flags for ddir_flags
QDATA_AUTO	equ	01h
QDATA_DYNA	equ	02h
QDATA_MARKDEL	equ	04h
	
ddirentry	struc					; Record size is: 0x10 (16) bytes
	ddir_NextFreed	dd	?		; If not -1, this field points to next record freed
	ddir_wordnb	dw	?		; Reference to the word (word nb) to multiply with size wordentry
	ddir_blksize	dd	?		; Block size
	ddir_blkaddr	dd	?		; Block address (relative to the start of Data Dict)
	ddir_threadnb	db	?		; Thread nb (which thread owns this data ?)
	ddir_flags	db	?		; Flags: QDATA_AUTO QDATA_DYNA QDATA_MARKDEL
ddirentry	ends

DDIR_WSIZE	equ	6000h			; Window size of DDIR: room for 1536s allocations


; ===============================================================
; = Malloc						=
; =                                     	            	=
; = Usage:	Allocate memory into the Data Dictionnary,	=
; =		via DDIR indirection (Data Directory Area).	=
; =                       		                       	=
; = I)		EAX	memory amount asked (in bytes)	=
; =		EBX	0: static memory			=
; =			1: local memory			=
; =			2: dynamic memory			=
; =                                 	                		=
; = O)		EAX	the data block reference		=
; =		EBX	the real data address		=
; =                                         	        		=
; = M)		ECX EDX					=
; ===============================================================

		align	4
Malloc		proc

		; Is there enought memory ?
		; -------------------------

		mov	edx, [CDA_START]
		add	edx, [CDA_SIZE]
		mov	ecx, [DDA_START]
		sub	ecx, [DDA_SIZE]
		sub	ecx, eax
		cmp	ecx, edx
		jge	@@MemOk

		; Out of memory !
		mov	ah, ERR_NOMEMORY		; Out of memory.
		clr	edx			; No additionnal msg
		clr	ecx			; No line #
		jmp	doError
		
@@MemOk:

		; Add a new record into DDIR
		; --------------------------

		push	ebx
		mov	ebx, [DDIR_FFREED]
		cmp	ebx, -1
		je	@@Rec2

		; A record is freed, take it
		add	ebx, [DDIR_START]
		mov	ecx, [ebx.ddir_NextFreed]
		mov	[DDIR_FFREED], ecx
		jmp	@@RecDone
		
		; No record freed, add one (if possible...)
@@Rec2:		mov	ebx, [DDIR_SIZE]
		cmp	ebx, DDIR_WSIZE
		jl	@@RecNbOk

		; DDIR table full !
		pop	ebx			; Clean stack
		mov	ah, ERR_DDIRFULL		; "Data allocation table full."
		clr	edx			; No additionnal msg
		clr	ecx			; No line #
		jmp	doError
		
@@RecNbOk:	add	ebx, [DDIR_START]		; EBX points to the new record
		
		; Update DDIR size
		add	[DDIR_SIZE], size ddirentry

@@RecDone:

		
		; Get asked memory
		; ----------------

		mov	edx, [CDA_START]
		add	edx, [CDA_SIZE]
		mov	ecx, [DDA_START]
		sub	ecx, [DDA_SIZE]
		sub	ecx, eax

		; Update memory pointers
		add	[DDA_SIZE], eax

		; Update memory allocated bounds
		mov	edx, [DDA_START]
		sub	edx, [DDA_SIZE]
		mov	[DDA_BOUND], edx


		; Fill the DDIR entry
		; -------------------
		
		; The record is not free
		mov	[ebx.ddir_NextFreed], -1
		
		; Block size
		mov	[ebx.ddir_blksize], eax
		
		; Memory address
		mov	[ebx.ddir_blkaddr], ecx

		; Reference to the word which owns this data
		mov	eax, [VOC_CURRENT]
		add	eax, [VOC_START]
		mov	eax, [eax.voc_lastword]
		push	ecx
		mov	ecx, size wordentry
		clr	edx
		idiv	ecx					; eax /= size wordentry
		pop	ecx
		mov	[ebx.ddir_wordnb], ax

		; Thread nb
		mov	eax, [CurrActThread]
		mov	[ebx.ddir_threadnb], al
		
		; Thread nb, local? dynamic?
		clr	al					; Initialize flags
		pop	edx
		cmp	dl, 1
		jne	@@Not1
		or	al, QDATA_AUTO				; Automatic variable
		jmp	@@12
@@Not1:		cmp	dl, 2
		jne	@@12
		or	al, QDATA_DYNA				; Dynamic variable
@@12:		mov	[ebx.ddir_flags], al			; Set flags
		

		; Return to caller
		; ----------------

		; EAX = data block reference
		sub	ebx, [DDIR_START]
		mov	eax, ebx
		
		; EBX = real data address
		mov	ebx, ecx

		; Done				
		ret

Malloc		endp


; ===============================================================
; = BWD_ALLOT						=
; =                                                 		=
; = Code for the forth word:	RT_(BW)ALLOT		=
; =							=
; = Stack:	( n --- addr )				=
; =							=
; = Usage:	Allocate (n * [1,2,4]) bytes in the Data	=
; =		Dictionnary.				=
; = O) EAX : memory block nb (DDIR table).			=
; ================================================================

BWD_ALLOT	MACRO	sz

		align	4

		if	sz eq 'B'
RT_BALLOT	proc
		elseif	sz eq 'W'
RT_WALLOT	proc
		else
RT_ALLOT		proc
		endif

		; ----------------------
		; CTRL-BREAK not allowed
		; ----------------------

		inc	[NoCtrlBreak]


		; ------------------
		; Verify stack frame
		; ------------------
		
		VSTACK	1


		; ---------------------------------
		; Dynamic allocation ? (with ALLOC)
		; ---------------------------------
		
		cmp	[AllocFlag], TRUE
		je	@@StaticAll


		; ----------------------------------------------------------------
		; Automatic allocation ? No if Compile Actions called by INTERPRET
		; ----------------------------------------------------------------

		lea	eax, InterpretAddr
		add	eax, [OfsDictReloc]
		cmp	dword ptr [esp + 4], eax
		je	@@StaticAll

		; Amount of memory asked
		mov	eax, PARAM0
		if	sz eq 'W'
		shl	eax, 1					; * 2
		elseif	sz eq 'D'
		shl	eax, 2					; * 4
		endif

		; Is memory already allocated for this auto variable ? If yes, release this memory before
		mov	edx, [esp + 4]
		mov	edx, [edx]
		cmp	edx, -1
		je	@@FirstAlloc


		; Re-allocation of memory
		; -----------------------

		call	ReAlloc
		jmp	@@MemDone
		

		; Get memory asked (first allocation)
		; -----------------------------------
		
@@FirstAlloc:	mov	bl, 1					; 1 mean Local variable
		call	Malloc					; Get memory


		; Store the data block address
@@MemDone:	mov	PARAM0, ebx 				; Push block address on stack
		mov	ecx, [esp + 4]				; Addr of cell where we have to store DataBlockAddr
		mov	[ecx], eax

		; Done for dynamic allocation
		jmp	@@Exit					; ret

		
		; -------------------------------------------
		; Static allocation (not inside a definition)
		; -------------------------------------------
		
@@StaticAll:

		; Compile: CALL $
		CALL_rel32
		clr	eax
		call	CodeComma               		; Code,

		; Compile: ADD DWORD PTR [ESP], 4+6+3+2+1
		ADD_xESPi8_i8	0, 4+6+3+2+1

		; Get memory asked (returned: <n>, block memory nb)
		; then compile: MOV EAX, [EDI.ddir_blkaddr + <n>]
		MOV_EAX_xEDIi32
		mov	eax, [esi]
		if	sz eq 'W'
		shl	eax, 1					; * 2
		elseif	sz eq 'D'
		shl	eax, 2					; * 4
		endif
		cmp	[AllocFlag], TRUE
		je	@@DynaVar
		clr	bl					; 0 means static  variable
		jmp	@@malloc
@@DynaVar:	mov	bl, 2					; 2 means dynamic variable
@@malloc:		call	Malloc					; Get memory
		mov	[esi], ebx 				; Push block address on stack
		add	eax, ddir_blkaddr
		call	CodeComma				; Code,
		
		; Compile: SUB ESI, 4
		SUB_ESI_i8	@WordSize
		
		; Compile: MOV [ESI], eax
		MOV_xESIi8_EAX
		
		; Compile: RET
		_RET_

		; Record the addr of the block, which can be used by ALLOTMORE (if static allocation)
		cmp	[AllocFlag], TRUE
		mov	[REF_BLK_ALLCTED], eax

		; On output, EAX is block nb
		sub	eax, ddir_blkaddr
		

		; ------------------------------------------------------
		; Return to caller, with real block address on top stack
		; ------------------------------------------------------
		
@@Exit:		
		; CTRL-BREAK allowed
		SUMMON	CTRLBREAK_REST

		ret

		if	sz eq 'B'
E_RT_BALLOT:
		elseif	sz eq 'W'
E_RT_WALLOT:
		else
E_RT_ALLOT:
		endif
		endp


; ===============================================================
; = ReAlloc						=
; =                                     	            	=
; = Usage:	Re-Allocate memory into the Data Dictionnary	=
; =		via DDIR indirection (Data Directory Area).	=
; =                       		                       	=
; = I)		EAX	memory amount asked (in bytes)	=
; =		EDX	data block nb			=
; =                                 	                		=
; = O)		EAX	the data block reference		=
; =		EBX	the real data address		=
; =                                         	        		=
; = M)		ECX EDX					=
; ===============================================================

		align	4
ReAlloc		proc

		; Free the data used
		; ------------------

		push	edx					; Save data block nb (for future use)
		call	UnAllot
		

		; Is there enought memory ?
		; -------------------------

		mov	edx, [CDA_START]
		add	edx, [CDA_SIZE]
		mov	ecx, [DDA_START]
		sub	ecx, [DDA_SIZE]
		sub	ecx, eax
		cmp	ecx, edx
		jge	@@MemOk

		; Out of memory !
		add	esp, 1 * @WordSize			; Clean stack
		mov	ah, ERR_NOMEMORY			; Out of memory.
		clr	edx				; No additionnal msg
		clr	ecx				; No line #
		jmp	doError
		
@@MemOk:


		; Add a new record into DDIR
		; --------------------------

		mov	ebx, [DDIR_FFREED]
		cmp	ebx, -1
		je	@@Rec2

		; A record is freed, take it
		add	ebx, [DDIR_START]
		mov	ecx, [ebx.ddir_NextFreed]
		mov	[DDIR_FFREED], ecx
		jmp	@@RecDone
		
		; No record freed, add one (if possible...)
@@Rec2:		mov	ebx, [DDIR_SIZE]
		cmp	ebx, DDIR_WSIZE
		jl	@@RecNbOk

		; DDIR table full !
		add	esp, 1 * @WordSize		; Clean stack
		mov	ah, ERR_DDIRFULL		; "Data allocation table full."
		clr	edx			; No additionnal msg
		clr	ecx			; No line #
		jmp	doError
		
@@RecNbOk:	add	ebx, [DDIR_START]		; EBX points to the new record
		
		; Update DDIR size
		add	[DDIR_SIZE], size ddirentry

@@RecDone:
		
		
		; Get asked memory
		; ----------------

		mov	edx, [CDA_START]
		add	edx, [CDA_SIZE]
		mov	ecx, [DDA_START]
		sub	ecx, [DDA_SIZE]
		sub	ecx, eax

		; Update memory pointers
		add	[DDA_SIZE], eax

		; Update memory allocated bounds
		mov	edx, [DDA_START]
		sub	edx, [DDA_SIZE]
		mov	[DDA_BOUND], edx


		; Fill the DDIR entry
		; -------------------
		
		; The record is not free
		mov	[ebx.ddir_NextFreed], -1
		
		; Block size
		mov	[ebx.ddir_blksize], eax
		
		; Memory address
		mov	[ebx.ddir_blkaddr], ecx

		; Reference to the word which owns this data
		pop	edx					; Get saved previous record used
		mov	ax, [edi + edx.ddir_wordnb]
		mov	[ebx.ddir_wordnb], ax
		
		; Thread nb
		mov	eax, [CurrActThread]
		mov	[ebx.ddir_threadnb], al
		
		; Thread nb, local? dynamic?
		movzx	eax, [edi + edx.ddir_flags]		; Get previous flags
		and	al, (not QDATA_MARKDEL)		; Record not marked as deleted
		mov	[ebx.ddir_flags], al
		

		; Return to caller
		; ----------------

		; EAX = data block reference
		sub	ebx, [DDIR_START]
		mov	eax, ebx
		
		; EBX = real data address
		mov	ebx, ecx

		; Done				
		ret

ReAlloc		endp


; ================================================================
; = UnAllot						=
; =                                                 		=
; = Usage							=
; =	Free memory allocated for a word with ALLOT.		=
; =							=
; = I) EDX : memory block nb				=
; =							=
; = M) none						=
; ================================================================

		align	4
UnAllot		proc

		; -------------------
		; Save used registers
		; -------------------
		
		push	eax


		; ----------------------------------------
		; Is-it the last block ? If yes, delete it
		; ----------------------------------------

		mov	eax, [DDIR_SIZE]
		sub	eax, size ddirentry
		cmp	eax, edx
		jne	@@NotLast
		
		; Update the memory used
		mov	eax, [edi + edx.ddir_blksize]
		sub	[DDA_SIZE], eax
		
		; Update the size of the table
		sub	[DDIR_SIZE], size ddirentry
		
		; Update memory allocated bounds
		mov	eax, [DDA_START]
		sub	eax, [DDA_SIZE]
		mov	[DDA_BOUND], eax

		; Done
		jmp	@@Exit
		
@@NotLast:


		; ----------------------------------------------------------------------
		; Update the amount of memory which can be salvaged by GARBAGE collector
		; ----------------------------------------------------------------------
		
		test	[edi + edx.ddir_flags], QDATA_MARKDEL
		jnz	@@UpdtSalvag
		mov	eax, [edi + edx.ddir_blksize]
		add	[DDIR_MEMSALV], eax
@@UpdtSalvag:	
		

		; ---------------------------------------------------------------------
		; Mark this block as free, but not deleted (it will be deleted by DUST)
		; ---------------------------------------------------------------------

		; Mark the block as to be deleted
		or	[edi + edx.ddir_flags], QDATA_MARKDEL

		
		; ----------------
		; Return to caller
		; ----------------

@@Exit:		pop	eax
		ret

E_UnAllot:
UnAllot		endp
