?ifndef _ALLOC_
?define _ALLOC_ TRUE
?warning FALSE

:byte HEAP[SIZE_HEAP];
:word BLOCK_MEM[NUMBLOCK+1]=0;

/* Процедура выделения и освобождения динамической памяти
word MALLOC (size) - выделить память размером size. Возвращает смещение блока
                     или 0 если нет места.
void FREE (offs) - освобождает ранее выделеный блок памяти.
В программе должны быть определены define - SIZE_HEAP - размер динамической
памяти (не более 0x7FFF) и NUMBLOCK - число блоков памяти которые могут быть
запрошены одновременно.
--------------------------------
Procedure of allocation and releases dynamic memory
word MALLOC (size) - allocate the memory by size. Returns offset of block
                     or 0 if no space.
void FREE (offs) - releases earlier allocate block a memory.
In program must be defined SIZE_HEAP - a size dynamic
memory (not more 0x7FFF) and NUMBLOCK - a number of blocks a memory which can be
requested simultaneously.

*/

:word MALLOC(AX)
{
	$PUSH SI
	$PUSH DI
	DX><AX;
	SI=0;
	BX=#BLOCK_MEM;
	DI=0;
	do{
		AX=DSWORD[BX];
		IF(AX==0){
			CX=SIZE_HEAP-SI;
			IF(CX>=DX){
				DH|=0X80;
				DSWORD[BX]=DX;
				DSWORD[BX+2]=AX;
				AX=SI+#HEAP;
			}
			GOTO EN;
		}
		IF(AX<0X8000){
			IF(AX>=DX){
				CX=AX-DX;
				DH|=0X80;
				DSWORD[BX]=DX;
				IF(CX){
					BX+=2;
					do{
						AX=DSWORD[BX];
						DSWORD[BX]=CX;
						CX=AX;
						BX+=2;
					} while (AX);
					DSWORD[BX]=AX;
				}
				AX=SI+#HEAP;
				GOTO EN;
			}
		}
		AH&=0X7F;
		SI+=AX;
		BX+=2;
		DI++;
		IF(DI==NUMBLOCK)BREAK;
		CX=SI+DX;
	}while(CX<=SIZE_HEAP);
ER:
	AX=0;
EN:
	$POP DI
	$POP SI
}

:void FREE(AX)
{
	DX=AX-#HEAP;
	$CLD
	$PUSH SI
	$PUSH DI
	$PUSH DS
	$POP ES
	SI=#BLOCK_MEM;
	DX=AX-#HEAP;
	IF(ZEROFLAG){
		DI=SI;
		SI+=2;
		DX=DSWORD[DI];
		DH&=0X7F;
		$TEST DSWORD[SI],0X8000
		$JZ CC1
	}
	ELSE{
		BX=0;
		do
		{
			$LODSW
			AH&=0X7F;
			BX+=AX;
			IF(AX==0)GOTO EN;
TW:
		}while( BX!=DX );
		DI=SI;
		SI+=2;
		DX=DSWORD[DI];
		DH&=0X7F;
		AX=DSWORD[SI-4];
		$TEST AH,0X80
		IF(ZEROFLAG){
			DX+=AX;
			DI-=2;
		}
		IF(DSWORD[SI]<0X8000){
			AX=0;
			IF(DSWORD[SI]==AX){
				DSWORD[DI]=AX;
				GOTO EN;
			}
CC1:
			DX+=DSWORD[SI];
			SI+=2;
		}
	}
	AX><DX;
	$STOSW
	AX=SI-DI;
	IF(NOTZEROFLAG){
		do
		{
			$LODSW
			$STOSW
		} while (AX);
	}
EN:
	$POP DI
	$POP SI
}

?endif
