code	segment word public
assume	cs:code
include errno.inc
; Memory allocation routines.
; ---------------------------
;
; Memory is allocated by pointer rather than segment: these routines use
; DI as a pointer into a constant segment, thus there is a communal
; maximum limit of slightly less than 64k.
;
; Note: DS should always point to the same constant segment and is assumed to
;       be valid in these routines
;
; Memory control block structure:
;
; offs  type  description
; ----  ----  ----------------------
;  0    byte  signature "R"
;  1    byte  status - "F" free  "A" allocated
;  2    word  size of block in bytes
;  4    word  pointer: previous MCB (0=first block)
;  6    word  pointer: forward MCB (0=last block)
;  8

extrn errno:word

public _free
_free:
; DS:BX points to memory block
        push  bp
        mov   bp,sp
        push  bx si di
        mov   word ptr ds:[errno],0
        mov   bx,[bp+4]
        or    bx,bx                 ; null?
        jz    L2                    ; skip the rest

        sub   bx,8                  ; point to MCB

        cmp   word ptr [bx],'AR'    ; allocated?
        jnz   L5                    ; error! not allocated!
        mov   word ptr [bx],'FR'    ; mark free

        mov   si,[bx+4]             ; previous MCB
        mov   di,[bx+6]             ; forward MCB

        or    si,si                 ; first MCB?
        jz    L1                    ; nup, skip to forward free check
        cmp   word ptr [si],'FR'    ; is previous MCB free?
        jnz   L1                    ; nup, skip to forward free check

        mov   ax,[bx+2]             ; this block size
        add   ax,8                  ; plus MCB
        add   [si+2],ax             ; save new size of previous MCB
        mov   [si+6],di             ; link previous to forward
        mov   [di+4],si
        mov   word ptr [bx],'fr'    ; invalidate block header
        mov   bx,si

L1:
        or    di,di                 ; last MCB?
        jz    L2                    ; nup
        cmp   word ptr [di],'FR'    ; is forward MCB free?
        jnz   L2                    ; nup
        mov   ax,[di+2]             ; forward block size
        add   ax,8                  ; plus MCB
        add   [bx+2],ax             ; save new size
        mov   ax,[di+6]
        mov   [bx+6],ax
        mov   word ptr [di],'fr'    ; invalidate block header
        xor   ax,ax                 ; return value
L2:
        pop   di si bx
        pop   bp
        ret   2
L5:
        mov   word ptr ds:[errno],ERR_MEM_INVALIDPTR ; Invalid pointer to free
        mov   ax,-1
        jmp   L2
code ends
end
