; ***** DON'T KNOW WHETHER THIS WORKS. WAS NEVER USED!! *****
; ----------------------------------------------------------------------
;                   Copyright (C) 1991 by Natrlich!
;                      This file is copyrighted!
;                Refer to the documentation for details.
; ----------------------------------------------------------------------
;                 Nothing beats a selfwritten malloc....
; HEAD -> [used.w][size.w][next.l] -> ....
; This mallocer doesn't really free anything back to the OS. Why should
; we ? For all programs that are expected to run in a matter of seconds
; not hours, the overhead isn't justified.
; Leaves in the worst case MANY bytes of fragmented OS space unused
;    This is only a crutch for GEMDOSes fucked up memory manager
; ----------------------------------------------------------------------
         .export  malloc
         .export  free

BLOCKSIZE   equ   $6008                ;; must be within 15 bits
GBLOCK      equ   $03


         .code
failed:
         sub.l    a0,a0
         bra      done

malloc:
         move.w   d0,1
         move.l   a3,-(a7)             ;; save two regs
         move.l   d3,-(a7)

         move.l   d0,d3                ;; try to alloc 0 ??
         beq.b    failed               ;; that's stupid
         bmi.b    failed               ;; negative is wrong also
         
         cmpi.l   #BLOCKSIZE-$100,d0   ;; more than we can handle
         ble.b    goodenough           ;; then give it to GEMDOS

         addq.l   #8,d0                ;; so this is too big for us
         move.l   d0,-(a7)             ;; use MALLOC from GEMDOS
         move.w   #$48,-(a7)
         trap     #1
         addq.l   #6,a7
         tst.l    d0                   ;; Enough memory ??
         beq.b    failed               ;; njet ->
         move.l   d0,a0                ;; else mark it as
         move.w   #GBLOCK,(a0)         ;; being a GEMDOS block
         addq.l   #8,a0                ;; skip header
         bra.b    done                 ;; and return

goodenough:
         lea      head,a1              ;; get head pointer
         bra.b    next

loop:
         tst.w    (a1)                 ;; block in USE ?
         bne.b    next                 ;; yes ->next
         cmp.l    (a1),d0              ;; size OK ?  (First fit)
         ble.b    ok
next:
         lea      4(a1),a3             ;; save address of NEXT pointer
         move.l   (a3),a1              ;; get NEXT pointer
         move.l   a1,d1                ;; end of list
         bne.b    loop                 ;; da nada ---^

alloc:
         pea      BLOCKSIZE
         move.w   #$48,-(a7)
         trap     #1
         addq.l   #6,a7
         tst.l    d0
         beq.b    failed               ;; not enough room ---V

         move.l   d0,(a3)              ;; initialize header
         move.l   d0,a1                ;; of memory block
         move.l   #BLOCKSIZE-8,(a1)    ;; actual block - header
         clr.l    4(a1)                ;; clear next pointer

ok:
         lea      8(a1),a0             ;; get memory area anyway
         move.l   (a1),d1              ;; get block size
         sub.l    d3,d1                ;; subtract #bytes
         subq.l   #8,d1                ;; less the header
         cmpi.w   #4,d1                ;; no split for less than 4
         blt.b    success              ;; then we are thru!!

         move.l   d3,(a1)+             ;; mosey on up to NEXT field
         lea      4(d3,a1),a3          ;;       DO THE SPLIT
         move.l   (a1),4(a3)           ;; save old NEXT in new
         move.l   a3,(a1)              ;; save new as NEXT in old
         move.l   d1,(a3)              ;; save SIZE and clear USED

success:
         st       -8(a0)               ;; mark as used
done:
         move.l   (a7)+,d3
fdone:
         move.l   (a7)+,a3
         rts


free:
         move.l   a3,-(a7)             ;; save a reg

         move.l   a0,d0                ;; 0 pointer (MAYBE WE SHOULD CRASH)
         beq.b    fdone                ;; but we don't
         
         lea      -8(a0),a3            ;; get header
         move.w   (a3),d0
         beq.b    fdone                ;; LUSER tried to free twice
         subq.w   #GBLOCK,d0           ;; Was it a bona fide GEMDOS block ?
         beq.b    yup                  ;; then we DO free ---V

         clr.w    (a3)                 ;; mark as unused
         move.l   (a3),d1              ;; get size in D1
         add.l    a3,d1                ;; add with current pointer
         addq.l   #8,d1                ;; add header len
         move.l   4(a3),a1             ;; get NEXT pointer
         cmpa.l   d1,a1                ;; curr + #header + size == NEXT ??
         bne.b    nojoin               ;; NO join impossible
         tst.w    (a1)                 ;; next block free  ?
         bne.b    nojoin               ;; no --V
         bsr.b    join_adjacent

nojoin:
         lea      head,a1              ;; get head (CHK LFT NEIGHBOR)

loop2a:
         move.l   4(a1),a1             ;; get next pointer address
         move.l   a1,d1                ;; end of list
         beq.b    fdone

         move.l   (a1),d1              ;; get size in A2
         add.l    a1,d1                ;; add with current pointer
         addq.l   #8,d1                ;; add header len
         cmpa.l   d1,a3                ;; points to us ??
         bne.b    loop2a               ;; yes -> done

         bsr.b    join_adjacent        ;; USED must have been CLEAR 
         bra.b    fdone                ;; for this to work

yup:
         move.l   a0,-(a7)             ;; free that sucker
         move.w   #$49,-(a7)
         trap     #1
         addq.l   #6,a7
         bra.b    fdone



join_adjacent:
         move.l   (a3),d0              ;; get SIZE of LEFT guy
         add.l    (a1),d0              ;; add sizes of RITE to it
         addq.l   #8,d0                ;; don't forget the header
         move.l   d0,(a3)              ;; write in LEFT
         move.l   4(a1),4(a3)          ;; copy RITE NEXT pointer to LEFT
         rts


         .data
head:
         .dc.w    $FFFF                ;; used internally flag
         .dc.w    $0000                ;; no size
headnext:
         .dc.l    0                    ;; points nowhere

