        TITLE   'mem - Memory Management Functions'
        PAGE 59, 132
        .LALL

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  MEM - Memory Management Functions                            ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Real Time Dos                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  This material  was created as a published version  of a DOS  ;
        ;  equivalent product.   This program  logically  functions in  ;
        ;  the same way as  MSDOS functions and it  is  internal  data  ;
        ;  structure compliant with MSDOS 6.0                           ;
        ;                                                               ;
        ;  This product is distributed  AS IS and contains no warranty  ;
        ;  whatsoever,   including  warranty  of   merchantability  or  ;
        ;  fitness for a particular purpose.                            ;
        ;                                                               ;
        ;                                                               ;
        ;  (c) Copyright 1990, 1997. Api Software and Mike Podanoffsky  ;
        ;      All Rights Reserved Worldwide.                           ;
        ;                                                               ;
        ;  This product is protected under copyright laws and  may not  ;
        ;  be reproduced  in whole  or in part, in any form  or media,  ;
        ;  included but not limited to source listing, facsimile, data  ;
        ;  transmission, cd-rom, or  floppy disk without the expressed  ;
        ;  written consent of the author.                               ;
        ;                                                               ;
        ;  License  for  distribution  for commercial  use  or  resale  ;
        ;  required from:                                               ;
        ;                                                               ;
        ;  Api Software                                                 ;
        ;  12 South Walker Street                                       ;
        ;  Lowell,  MA   01851                                          ;
        ;                                                               ;
        ;  internet: mikep@world.std.com                                ;
        ;                                                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;  Compile with MASM 5.1                                        ;
        ;...............................................................;

        include rxdosmac.asm
        include rxdosdef.asm

RxDOS   SEGMENT PUBLIC 'CODE'
        assume cs:RxDOS, ds:RxDOS, es:RxDOS, ss:RxDOS

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  MEM - Memory Management Functions                            ;
        ;...............................................................;

        public allocateMemBlock
        public _freeMemBlock
        public _modifyMemBlock

        public _initializeMemoryBlock
        public _collectMemoryBlocks
        public _releaseOwnerMemoryBlocks
        public _allocateUpperMB
        public _allocateConvMB
        public _allocateMinMaxMemBlock

        extrn _RxDOS_CurrentPSP                 : word
        extrn _RxDOS_pStartMemBlock             : word
        extrn _RxDOS_DOSProgramName             : byte
        extrn _RxDOS_AllocStrategy              : word
        extrn _RetCallersStackFrame             : near

        extrn pexterrInvalidFunction            : near
        extrn pexterrFileNotFound               : near
        extrn pexterrPathNotFound               : near
        extrn pexterrIllegalName                : near
        extrn pexterrNoHandlesAvailable         : near
        extrn pexterrAccessDenied               : near
        extrn pexterrInvalidHandle              : near
        extrn pexterrArenaTrashed               : near
        extrn pexterrNotEnoughMemory            : near
        extrn pexterrInvalidBlock               : near
        extrn pexterrInvalidAccess              : near
        extrn pexterrInvalidDrive               : near
        extrn pexterrCurrentDirectory           : near
        extrn pexterrNoMoreFiles                : near
        extrn pexterrFileExists                 : near

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Allocate Min Max Memory Block                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Input:                                                       ;
        ;  ax   minimum block                                           ;
        ;  dx   maximum block                                           ;
        ;                                                               ;
        ;  Returns:                                                     ;
        ;  es   segment address of allocated memory block               ;
        ;  ax   segment address of allocated memory block header        ;
        ;  cx   size of memory available                                ;
        ;...............................................................;

_allocateMinMaxMemBlock:

        Entry
        def  _minParag, ax
        def  _maxParag, dx

        mov cx, dx                                      ; try for max
        call allocateMemBlock                           ; will probably fail
        jnc _allocateMinMaxMemBlock_20                  ; if ok -->

        cmp cx, word ptr [ _minParag ][ bp ]            ; largest available will fit ?
        jnc _allocateMinMaxMemBlock_12                  ; yes, go for max -->
        SetError pexterrNotEnoughMemory, _allocateMinMaxMemBlock_20

_allocateMinMaxMemBlock_12:
        call allocateMemBlock                           ; allocate largest available
        mov es, ax                                      ; segment address
        sub ax, (sizeMEMBLOCK/ PARAGRAPH)
        or ax, ax

_allocateMinMaxMemBlock_20:
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Initialize Memory Block                                      ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  es    segment points to memory block to initialize           ;
        ;  ax    is size to initialize (paragraphs )                    ;
        ;  bx    parent                                                 ;
        ;         0000 block is free                                    ;
        ;         0008 (_RxDOS_PARENT_SIGNATURE) block belongs to RxDOS ;
        ;...............................................................;

_initializeMemoryBlock:
        push ax                                         ; init length (paragraphs )

        xor ax, ax
        xor di, di
        mov cx, (sizeMEMBLOCK)/2                        ; size of memory header (words )
        rep stosw

        pop ax
        xor di, di
        mov byte ptr es:[ _memSignature ], _RxDOS_ENDSIGNATURE
        mov word ptr es:[ _memAlloc ], ax
        mov word ptr es:[ _memParent ], bx

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if valid PSP, copy program name to memory block
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        cmp bx, _RxDOS_PARENT_SIGNATURE                 ; RxDOS Block ?
        jnz _initMemory_20                              ; if not RxDOS -->

        push ds
        push si
        push di

        currSegment ds                                  ; point to data segment
        mov si, offset [ _RxDOS_DOSProgramName ]
        lea di, offset _memPgmName [ di ]
        mov cx, 4                                       ; (size _RxDOS_DOSProgramName)/2
        rep movsw                                       ; copy RxDOS name to memory block

        pop di
        pop si
        pop ds

_initMemory_20:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Allocate Memory Block                                        ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Input:                                                       ;
        ;  cx   # paragraphs of memory requested                        ;
        ;                                                               ;
        ;  Returns:                                                     ;
        ;  es   segment address of allocated memory block               ;
        ;  cx   size of largest block of memory available in            ;
        ;         paragraphs, if allocation fails.                      ;
        ;  cy   if error                                                ;
        ;...............................................................;

allocateMemBlock:

        Entry
        def  _allocation, cx

        mov bx, cx
        call _allocateUpperMB                           ; allocate upper mem blocks
        jnc allocateMemBlock_12                         ; if allocation made -->

        getarg bx, _allocation
        call _allocateConvMB                            ; allocate lower mem blocks

allocateMemBlock_12:
        mov es, ax                                      ; segment allocation
        mov cx, dx                                      ; largest block
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Collect Memory Blocks                                        ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  This routine will scan all memory blocks and merge all free  ;
        ;  memory blocks together.                                      ;
        ;...............................................................;

_collectMemoryBlocks:

        push ds
        push es
        push ax
        mov ax, word ptr ss:[ _RxDOS_pStartMemBlock ]

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  is block free ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_collectMemoryBlocks_08:
        mov ds, ax                                      ; next in ax

_collectMemoryBlocks_12:
        cmp byte ptr ds:[ _memSignature ], _RxDOS_MEMSIGNATURE
        jnz _collectMemoryBlocks_36                     ; done -->

        cmp word ptr ds:[ _memParent ], 0000            ; is block free ?
        jnz _collectMemoryBlocks_26                     ; no, go to next -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  is next also free ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        mov ax, ds                                      ; get current segment
        add ax, word ptr ds:[ _memAlloc ]               ; increment to next block
        inc ax
        mov es, ax
        cmp word ptr es:[ _memParent ], 0000            ; is next block free ?
        jnz _collectMemoryBlocks_08                     ; no, go to next -->

        mov ax, word ptr es:[ _memAlloc ]               ; get next allocation
        inc ax                                          ; kill interim Mem block as well
        add word ptr ds:[ _memAlloc ], ax               ; add to current block

        mov al, byte ptr es:[ _memSignature ]           ; last signature is passed to current block
        mov byte ptr ds:[ _memSignature ], al           ;
        jmp _collectMemoryBlocks_12

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  go to next
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_collectMemoryBlocks_26:
        mov ax, ds                                      ; get current segment
        add ax, word ptr ds:[ _memAlloc ]               ; increment to next block
        inc ax
        jmp _collectMemoryBlocks_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  done
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_collectMemoryBlocks_36:
        pop ax
        pop es
        pop ds
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  release all Mem blocks for owner                             ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   bx     PSP address of owner                                 ;
        ;...............................................................;

_releaseOwnerMemoryBlocks:

        push es
        mov ax, word ptr ss:[ _RxDOS_pStartMemBlock ]

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  does block belong to owner ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_releaseOwnerMemoryBlocks_08:
        mov es, ax                                      ; next block in ax
        cmp bx, word ptr es:[ _memParent ]              ; owner block ?
        jnz _releaseOwnerMemoryBlocks_12                ; no -->
        mov word ptr es:[ _memParent ], 0000            ; free up block

_releaseOwnerMemoryBlocks_12:
        cmp byte ptr es:[ _memSignature ], _RxDOS_MEMSIGNATURE
        jnz _releaseOwnerMemoryBlocks_24                ; if at end -->

        mov ax, es                                      ; get current segment
        add ax, word ptr es:[ _memAlloc ]               ; increment to next block
        inc ax
        jmp _releaseOwnerMemoryBlocks_08
        
_releaseOwnerMemoryBlocks_24:
        pop es
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Free Memory Block                                            ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   es     memory block                                         ;
        ;...............................................................;

_freeMemBlock:

        push es
        mov ax, es
        sub ax, ( sizeMEMBLOCK / PARAGRAPH )
        mov es, ax
        cmp byte ptr es:[ _memSignature ], _RxDOS_MEMSIGNATURE
        jz _freeMemBlock_12
        cmp byte ptr es:[ _memSignature ], _RxDOS_ENDSIGNATURE
        jnz _freeMemBlock_16

_freeMemBlock_12:
        mov word ptr es:[ _memParent ], 0000            ; free up block

_freeMemBlock_16:
        pop es
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Modify Block Size                                            ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  On Call:                                                     ;
        ;   es     paragraph to modify                                  ;
        ;   bx     new paragraph size                                   ;
        ;                                                               ;
        ;  On Return:                                                   ;
        ;   es     paragraph to modify                                  ;
        ;   bx     max block available                                  ;
        ;   ax     error code, if error                                 ;
        ;   cy     set if error                                         ;
        ;                                                               ;
        ;  Contraction involves splitting a block into two smaller      ;
        ;  portions. Expansion requires that the block which follows    ;
        ;  be empty. If it is, it is combined with the modify block     ;
        ;  to create a huge block, which can then be split.             ;
        ;...............................................................;

_modifyMemBlock:

        Entry
        def _modifyBlock, es
        def _modifySize, bx

        call _collectMemoryBlocks                       ; collect free blocks

        mov ax, es
        sub ax, ( sizeMEMBLOCK / PARAGRAPH )
        mov es, ax
        storarg _modifyBlock, es

        cmp byte ptr es:[ _memSignature ], _RxDOS_MEMSIGNATURE
        jz _modifyMemBlock_12
        cmp byte ptr es:[ _memSignature ], _RxDOS_ENDSIGNATURE
        jz _modifyMemBlock_12

        SetError pexterrInvalidBlock, _modifyMemBlock_66

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  are we expanding allocation ?
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_modifyMemBlock_12:
        cmp bx, word ptr es:[ _memAlloc ]
        jc _modifyMemBlock_32                           ; if contracting allocation -->
        ifz _modifyMemBlock_42                          ; same size as now, ignore request -->

        mov dx, word ptr es:[ _memAlloc ]               ; get current allocation size
        cmp byte ptr es:[ _memSignature ], _RxDOS_MEMSIGNATURE
        jnz _modifyMemBlock_14                          ; if at end block, can't expand ->

        inc dx
        mov ax, es
        add ax, dx
        mov es, ax                                      ; address of next block
        cmp word ptr es:[ _memParent ], 0000            ; is next block free ?
        jnz _modifyMemBlock_14                          ; no, error -->

        add dx, word ptr es:[ _memAlloc ]               ; total expansion space
        cmp bx, dx                                      ; is extra block enough to expand ?
        jc _modifyMemBlock_18                           ; yes, ok to try to expand -->
        jz _modifyMemBlock_18                           ; yes, ok to try to expand -->
        
_modifyMemBlock_14:
        mov bx, dx                                      ; available size
        jmp _modifyMemBlock_46                          ; not enough memory -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  merge blocks together
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_modifyMemBlock_18:
        mov al, byte ptr es:[ _memSignature ]           ; sig of next block

        getarg es, _modifyBlock
        mov word ptr es:[ _memAlloc ], dx               ; new expanded size
        mov byte ptr es:[ _memSignature ], al           ; sig of next block

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  collapse allocated space
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_modifyMemBlock_32:
        mov cx, es                                      ; current segment
        add cx, bx
        inc cx                                          ; where to create next mem seg

        mov dl, byte ptr es:[ _memSignature ]           ; sig of next block
        mov ax, word ptr es:[ _memAlloc ]               ; existing allocated space
        sub ax, bx                                      ; size of remaining block
        jz _modifyMemBlock_42                           ; same as now -- done
        dec ax                                          ; make room for mem header
        mov byte ptr es:[ _memSignature ], _RxDOS_MEMSIGNATURE
        mov word ptr es:[ _memAlloc ], bx               ; re-allocate space

        push dx
        mov es, cx
        xor bx, bx                                      ; free block
        call _initializeMemoryBlock                     ; initialize memory block.

        pop dx
        mov byte ptr es:[ _memSignature ], dl

_modifyMemBlock_42:
        xor bx, bx                                      ; clear carry
        Return

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_modifyMemBlock_46:
        RetCallersStackFrame es, si
        mov word ptr es:[ _BX  ][ si ], bx              ; max amount allowed
        mov ax, offset pexterrNotEnoughMemory

_modifyMemBlock_66:
        stc
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Allocate Upper Memory Blocks                                 ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  bx   # paragraphs of memory requested                        ;
        ;                                                               ;
        ;  Returns:                                                     ;
        ;  ax   segment address of allocated memory block               ;
        ;  dx   size of largest block of memory available in            ;
        ;         paragraphs, if allocation fails.                      ;
        ;...............................................................;

_allocateUpperMB:
        stc
        ret

        test word ptr [ _RxDOS_AllocStrategy ], (_MEM_FIRSTFIT_HIGH + _MEM_FIRSTFIT_HIGHONLY )
        jnz _allocateUpperMB_14                         ; if search upper memory blocks -->

_allocateUpperMB_12:
        xor dx, dx
        SetError pexterrNotEnoughMemory
        ret

_allocateUpperMB_14:
        mov ax, _RxDOS_HIGHMEMBLOCK
        call _localAreaAllocateMemory
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Allocate Conventional Memory Blocks                          ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  bx   # paragraphs of memory requested                        ;
        ;                                                               ;
        ;  Returns:                                                     ;
        ;  ax   segment address of allocated memory block               ;
        ;  dx   size of largest block of memory available in            ;
        ;         paragraphs, if allocation fails.                      ;
        ;...............................................................;

_allocateConvMB:
        test word ptr [ _RxDOS_AllocStrategy ], (_MEM_FIRSTFIT_HIGHONLY )
        jz _allocateConvMB_14                           ; if search conv memory blocks -->

_allocateConvMB_12:
    ;   xor dx, dx
    ;   SetError pexterrNotEnoughMemory
    ;   ret

_allocateConvMB_14:
        call _collectMemoryBlocks                       ; collect free blocks
        mov ax, word ptr ss:[ _RxDOS_pStartMemBlock ]
        call _localAreaAllocateMemory
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Local Zone Memory Allocation                                 ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  ax   paragraph to begin search                               ;
        ;  bx   # paragraphs of memory requested                        ;
        ;                                                               ;
        ;  Returns:                                                     ;
        ;  ax   segment address of allocated memory block               ;
        ;  bx   size of largest block of memory available in            ;
        ;         paragraphs, if allocation fails.                      ;
        ;...............................................................;

_localAreaAllocateMemory:

        Entry
        def _bestFit, 0000                              ; segment pointer to best fit
        def _lastFit, 0000                              ; segment pointer to last fit
        def _sizeFirstBlock                             ; size of first block
        def _sizeSecondBlock                            ; size of second block
        def _returnSegmentAddress                       ; return segment address
        def _firstSegmentAddress                        ; first seg
        def _secondSegmentAddress                       ; second seg

        push ds
        push es                                         ; save segment registers
        or ax, ax                                       ; zero if no mem allocated 
        jnz _allocMem_10                                ; mem list available -->
        xor dx, dx                                      ; no memory available
        SetError pexterrNotEnoughMemory, _allocMem_44   ; error -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  scan memory blocks
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_allocMem_10:
        cli                                             ; prevent interrupts
        xor dx, dx                                      ; largest available
        mov cx, 0ffffh                                  ; best fit

_allocMem_12:
        mov es, ax                                      ; point to memory seg
        cmp byte ptr es:[ _memSignature ], _RxDOS_MEMSIGNATURE
        jz _allocMem_14                                 ; if valid arena -->
        cmp byte ptr es:[ _memSignature ], _RxDOS_ENDSIGNATURE
        jz _allocMem_14                                 ; if valid arena -->
        SetError pexterrInvalidBlock, _allocMem_44      ; else, if error -->

_allocMem_14:
        cmp word ptr es:[ _memParent ], 0000            ; 0000 for parent means its free
        jnz _allocMem_20                                ; not a free block -->

        mov si, word ptr es:[ _memAlloc ]               ; get available space
        sub si, bx                                      ; is block within allocation size ?
        jc _allocMem_16                                 ; no -->

        storarg _lastFit, ax                            ; seg address of last fit
        test word ptr [ _RxDOS_AllocStrategy ], _MEM_FIRSTFIT_STRATEGY
        jz _allocMem_30                                 ; ok to allocate this block ->

        cmp cx, si                                      ; is this block a better fit ?
        jc _allocMem_16                                 ; not a better strategy -->
        mov cx, si                                      ; else save fit
        storarg _bestFit, ax                            ; seg address of best fit

_allocMem_16:
        cmp dx, word ptr es:[ _memAlloc ]               ; larger block ?
        jnc _allocMem_20                                ; no -->
        mov dx, word ptr es:[ _memAlloc ]               ; get size

_allocMem_20:
        inc ax
        add ax, word ptr es:[ _memAlloc ]      
        cmp byte ptr es:[ _memSignature ], _RxDOS_ENDSIGNATURE
        jnz _allocMem_12                                ; not at end yet -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  available block not found or allocation deferred to here
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        getarg ax, _bestFit
        test word ptr [ _RxDOS_AllocStrategy ], _MEM_BESTFIT_STRATEGY
        jnz _allocMem_24                                ; if best fit -->

        getarg ax, _lastFit
        test word ptr [ _RxDOS_AllocStrategy ], _MEM_LASTFIT_STRATEGY
        jz _allocMem_26                                 ; if not last fit -->

_allocMem_24:
        or ax, ax                                       ; determine if no allocation
        jnz _allocMem_30                                ; if block available -->

_allocMem_26:
        SetError pexterrNotEnoughMemory, _allocMem_44   ; error exit -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  Allocate block.
;
;  es   points to free block from where to allocate
;  bx   allocation size
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_allocMem_30:
        mov es, ax                                      ; 
        storarg _returnSegmentAddress, es               ; save this address
        mov dl, byte ptr es:[ _memSignature ]           ; current block signature
        mov ax, word ptr es:[ _memAlloc ]               ; get allocation

        sub ax, bx                                      ; this is remaining alloc balance
        jz _allocMem_38                                 ; if exact fit -->
        dec ax                                          ; make room for second mem control block
        mov cx, es
        add cx, ax                                      ; where next block will be if high
        inc cx                                          ; adjust for next block header
        storarg _sizeFirstBlock, ax                     ; first block size, assume last fit
        storarg _sizeSecondBlock, bx                    ; second block size, assume last fit
        storarg _returnSegmentAddress, cx

        test word ptr [ _RxDOS_AllocStrategy ], _MEM_LASTFIT_STRATEGY
        jnz _allocMem_32                                ; if allocate last fit -->

        mov cx, es
        add cx, bx                                      ; space we'll need
        inc cx                                          ; where next block will be
        storarg _sizeFirstBlock, bx                     ; first block size, assume other fit
        storarg _sizeSecondBlock, ax                    ; second block size, assume other fit
        storarg _returnSegmentAddress, es

_allocMem_32:
        storarg _firstSegmentAddress, es
        storarg _secondSegmentAddress, cx

        push dx                                         ; current block signature
        mov es, cx                                      ; create a block here 
        xor bx, bx                                      ; this block is free
        getarg ax, _sizeSecondBlock                     ; second block size
        call _initializeMemoryBlock                     ; initialize memory block.
        pop dx
        mov byte ptr es:[ _memSignature ], dl           ; save real signature

        getarg es, _firstSegmentAddress
        getarg bx, _sizeFirstBlock                      ; first block size
        mov word ptr es:[ _memAlloc ], bx               ; allocate what we need
        mov byte ptr es:[ _memSignature ], _RxDOS_MEMSIGNATURE

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; update old mem control block
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_allocMem_38:
        getarg es, _returnSegmentAddress                ; get return seg address
        mov cx, word ptr ss:[ _RxDOS_CurrentPSP ]
        or cx, cx
        jnz _allocMem_40
        mov cx, _RxDOS_PARENT_SIGNATURE                 ; system block

_allocMem_40:
        mov word ptr es:[ _memParent ], cx              ; current owner

        mov dx, word ptr es:[ _memAlloc ]               ; allocated size
        mov ax, es
        inc ax                                          ; seg address of data
        clc                                             ; no carry.

_allocMem_44:
        pop es                                          ; restore segment registers
        pop ds

        sti
        Return

RxDOS   ENDS
        END
