]> git.sur5r.net Git - cc65/commitdiff
Replace malloc() by an assembler version
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Fri, 21 Jul 2000 16:57:58 +0000 (16:57 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Fri, 21 Jul 2000 16:57:58 +0000 (16:57 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@181 b7a2c559-68d2-44c3-8de9-860c34a00d81

include/stdlib.h
libsrc/common/.cvsignore
libsrc/common/Makefile
libsrc/common/malloc.c [deleted file]
libsrc/common/malloc.s [new file with mode: 0644]

index dab0246c09a90867b5df1470c0f1984d0c318157..990a88a4427a7eba0d731e190c95c40e68d48245 100644 (file)
@@ -23,7 +23,7 @@
 
 
 /* Memory management */
-void* malloc (size_t size);
+void* __fastcall__ malloc (size_t size);
 void* calloc (size_t count, size_t size);
 void* realloc (void* block, size_t size);
 void __fastcall__ free (void* block);
index 1f88d3044c767f1358c0c073e22890f3da0bcd8c..7f2a43786d562f93cf9bfa1da0b4f2a1bacd1796 100644 (file)
@@ -12,8 +12,6 @@ realloc.s
 bsearch.s
 printf.s
 _hextab.s
-malloc.s
-free.s
 vfprintf.s
 fdopen.s
 _afailed.s
index 4726d5a5f355ecaf4c3e4ed77675516c99d3ef4d..2521e28a2cd9bec377d30e90adfb629b81fcd2f2 100644 (file)
        @$(AS) -g -o $@ $(AFLAGS) $(*).s
 
 %.o:   %.s
-       @echo $<
+       @echo $<                 
        @$(AS) -g -o $@ $(AFLAGS) $<
 
 C_OBJS = fclose.o fgets.o fprintf.o strdup.o calloc.o _fopen.o\
         fputs.o fread.o fwrite.o gets.o realloc.o bsearch.o strxfrm.o\
-        printf.o _hextab.o malloc.o vfprintf.o fdopen.o strtok.o\
+        printf.o _hextab.o vfprintf.o fdopen.o strtok.o\
         _afailed.o fopen.o fgetc.o fputc.o puts.o gets.o perror.o getchar.o\
         _printf.o vprintf.o vsprintf.o sprintf.o abort.o qsort.o putchar.o\
         errormsg.o _hadd.o cprintf.o vcprintf.o freopen.o locale.o
@@ -51,16 +51,17 @@ S_OBJS =    _fdesc.o        \
                jmpvec.o        \
                labs.o          \
                longjmp.o       \
-               ltoa.o          \
-               maperrno.o      \
-               memchr.o        \
-               memcmp.o        \
-               memcpy.o        \
-               memset.o        \
-               rand.o          \
-               setjmp.o        \
-               stkcheck.o      \
-               strcat.o        \
+               ltoa.o          \
+               malloc.o        \
+               maperrno.o      \
+               memchr.o        \
+               memcmp.o        \
+               memcpy.o        \
+               memset.o        \
+               rand.o          \
+               setjmp.o        \
+               stkcheck.o      \
+               strcat.o        \
                strchr.o        \
                strcmp.o        \
                strcoll.o       \
diff --git a/libsrc/common/malloc.c b/libsrc/common/malloc.c
deleted file mode 100644 (file)
index ca4044c..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * malloc.c
- *
- * Ullrich von Bassewitz, 03.06.1998
- */
-
-
-
-#include <stddef.h>
-#include "_heap.h"
-
-
-
-void* malloc (size_t size)
-/* Allocate memory from the given heap. The function returns a pointer to the
- * allocated memory block or a NULL pointer if not enough memory is available.
- * Allocating a zero size block is not allowed.
- */
-{
-    struct freeblock* f;
-    unsigned* p;
-
-
-    /* Check for a size of zero, then add the administration space and round
-     * up the size if needed.
-     */
-    if (size == 0) {
-       return 0;
-    }
-    size += HEAP_ADMIN_SPACE;
-    if (size < sizeof (struct freeblock)) {
-        size = sizeof (struct freeblock);
-    }
-
-    /* Search the freelist for a block that is big enough */
-    f = _hfirst;
-    while (f && f->size < size) {
-        f = f->next;
-    }
-
-    /* Did we find one? */
-    if (f) {
-
-        /* We found a block big enough. If the block can hold just the
-         * requested size, use the block in full. Beware: When slicing blocks,
-         * there must be space enough to create a new one! If this is not the
-         * case, then use the complete block.
-         */
-        if (f->size - size < sizeof (struct freeblock)) {
-
-            /* Use the actual size */
-            size = f->size;
-
-            /* Remove the block from the free list */
-            if (f->prev) {
-                /* We have a previous block */
-                f->prev->next = f->next;
-            } else {
-                /* This is the first block, correct the freelist pointer */
-                _hfirst = f->next;
-            }
-            if (f->next) {
-                /* We have a next block */
-                f->next->prev = f->prev;
-            } else {
-                /* This is the last block, correct the freelist pointer */
-                _hlast = f->prev;
-            }
-
-        } else {
-
-            /* We must slice the block found. Cut off space from the upper
-            * end, so we can leave the actual free block chain intact.
-            */
-
-           /* Decrement the size of the block */
-           f->size -= size;
-
-           /* Set f to the now unused space above the current block */
-           f = (struct freeblock*) (((unsigned) f) + f->size);
-
-        }
-
-        /* Setup the pointer for the block */
-        p = (unsigned*) f;
-
-    } else {
-
-        /* We did not find a block big enough. Try to use new space from the
-         * heap top.
-         */
-       if (((unsigned) _hend) - ((unsigned) _hptr) < size) {
-            /* Out of heap space */
-            return 0;
-       }
-
-
-       /* There is enough space left, take it from the heap top */
-       p = _hptr;
-               _hptr = (unsigned*) (((unsigned) _hptr) + size);
-
-    }
-
-    /* New block is now in p. Fill in the size and return the user pointer */
-    *p++ = size;
-    return p;
-}
-
-
-
diff --git a/libsrc/common/malloc.s b/libsrc/common/malloc.s
new file mode 100644 (file)
index 0000000..548c96e
--- /dev/null
@@ -0,0 +1,336 @@
+;
+; Ullrich von Bassewitz, 17.7.2000
+;
+; Allocate a block from the heap.
+;
+; void* __fastcall__ malloc (size_t size);
+;
+;
+; C implementation was:
+;
+; void* malloc (size_t size)
+; /* Allocate memory from the given heap. The function returns a pointer to the
+;  * allocated memory block or a NULL pointer if not enough memory is available.
+;  * Allocating a zero size block is not allowed.
+;  */
+; {
+;     struct freeblock* f;
+;     unsigned* p;
+;
+;
+;     /* Check for a size of zero, then add the administration space and round
+;      * up the size if needed.
+;      */
+;     if (size == 0) {
+;      return 0;
+;     }
+;     size += HEAP_ADMIN_SPACE;
+;     if (size < sizeof (struct freeblock)) {
+;         size = sizeof (struct freeblock);
+;     }
+;
+;     /* Search the freelist for a block that is big enough */
+;     f = _hfirst;
+;     while (f && f->size < size) {
+;         f = f->next;
+;     }
+;
+;     /* Did we find one? */
+;     if (f) {
+;
+;         /* We found a block big enough. If the block can hold just the
+;          * requested size, use the block in full. Beware: When slicing blocks,
+;          * there must be space enough to create a new one! If this is not the
+;          * case, then use the complete block.
+;          */
+;         if (f->size - size < sizeof (struct freeblock)) {
+;
+;             /* Use the actual size */
+;             size = f->size;
+;
+;             /* Remove the block from the free list */
+;             if (f->prev) {
+;                 /* We have a previous block */
+;                 f->prev->next = f->next;
+;             } else {
+;                 /* This is the first block, correct the freelist pointer */
+;                 _hfirst = f->next;
+;             }
+;             if (f->next) {
+;                 /* We have a next block */
+;                 f->next->prev = f->prev;
+;             } else {
+;                 /* This is the last block, correct the freelist pointer */
+;                 _hlast = f->prev;
+;             }
+;
+;         } else {
+;
+;             /* We must slice the block found. Cut off space from the upper
+;           * end, so we can leave the actual free block chain intact.
+;           */
+;
+;          /* Decrement the size of the block */
+;          f->size -= size;
+;
+;          /* Set f to the now unused space above the current block */
+;          f = (struct freeblock*) (((unsigned) f) + f->size);
+;
+;         }
+;
+;         /* Setup the pointer for the block */
+;         p = (unsigned*) f;
+;
+;     } else {
+;
+;         /* We did not find a block big enough. Try to use new space from the
+;          * heap top.
+;          */
+;      if (((unsigned) _hend) - ((unsigned) _hptr) < size) {
+;             /* Out of heap space */
+;             return 0;
+;      }
+;
+;
+;      /* There is enough space left, take it from the heap top */
+;      p = _hptr;
+;              _hptr = (unsigned*) (((unsigned) _hptr) + size);
+;
+;     }
+;
+;     /* New block is now in p. Fill in the size and return the user pointer */
+;     *p++ = size;
+;     return p;
+; }
+;
+
+
+       .importzp       ptr1, ptr2, ptr3
+       .import         __hptr, __hfirst, __hlast, __hend
+       .export         _malloc
+
+       .macpack        generic
+
+; Offsets into struct freeblock and other constant stuff
+
+size           = 0
+next           = 2
+prev           = 4
+admin_space    = 2
+min_size       = 6
+
+
+; Code
+
+_malloc:
+       sta     ptr1            ; Store size in ptr1
+       stx     ptr1+1
+
+; Check for a size of zero, if so, return NULL
+
+       ora     ptr1+1
+       beq     Done            ; a/x already contains zero
+
+; Add the administration space and round up the size if needed
+
+       lda     ptr1
+               add     #admin_space
+       sta     ptr1
+       bcc     @L1
+       inc     ptr1+1
+@L1:   ldx     ptr1+1
+       bne     @L2
+       cmp     #min_size+1
+       bcs     @L2
+       lda     #min_size
+       sta     ptr1            ; High byte is already zero
+
+; Load a pointer to the freelist into ptr2
+
+@L2:   lda     __hfirst
+       sta     ptr2
+               lda     __hfirst+1
+       sta     ptr2+1
+
+; Search the freelist for a block that is big enough. We will calculate
+; (f->size - size) here and keep it, since we need the value later.
+
+       jmp     @L4
+
+@L3:   ldy     #size
+               lda     (ptr2),y
+               sub     ptr1
+       tax                     ; Remember low byte for later
+       iny                     ; Y points to size+1
+               lda     (ptr2),y
+       sbc     ptr1+1
+       bcs     BlockFound      ; Beware: Contents of a/x/y are known!
+
+; Next block in list
+
+       iny                     ; Points to next
+       lda     (ptr2),y
+       tax
+       iny                     ; Points to next+1
+       lda     (ptr2),y
+       stx     ptr2
+       sta     ptr2+1
+@L4:   ora     ptr2
+               bne     @L3
+
+; We did not find a block big enough. Try to use new space from the heap top.
+
+       lda     __hptr
+       add     ptr1            ; _hptr + size
+               tay
+               lda     __hptr+1
+       adc     ptr1+1
+       bcs     OutOfHeapSpace  ; On overflow, we're surely out of space
+
+               cmp     __hend+1
+       bne     @L5
+       cpy     __hend
+@L5:   bcc     TakeFromTop
+       beq     TakeFromTop
+
+; Out of heap space
+
+OutOfHeapSpace:
+       lda     #0
+       tax
+Done:  rts
+       
+; There is enough space left, take it from the heap top
+
+TakeFromTop:
+       ldx     __hptr          ; p = hptr;
+       stx     ptr2
+       ldx     __hptr+1
+       stx     ptr2+1
+
+       sty     __hptr          ; hptr += size;
+               sta     __hptr+1
+       jmp     FillSizeAndRet  ; Done
+
+; We found a block big enough. If the block can hold just the
+; requested size, use the block in full. Beware: When slicing blocks,
+; there must be space enough to create a new one! If this is not the
+; case, then use the complete block.
+; On input, x/a do contain the remaining size of the block. The zero
+; flag is set if the high byte of this remaining size is zero.
+
+BlockFound:
+               bne     SliceBlock      ; Block is large enough to slice
+       cpx     #min_size+1     ; Check low byte
+               bcs     SliceBlock      ; Jump if block is large enough to slice
+
+; The block is too small to slice it. Use the block in full. The block
+; does already contain the correct size word, all we have to do is to
+; remove it from the free list.
+
+               ldy     #prev+1         ; Load f->prev
+       lda     (ptr2),y
+       sta     ptr3+1
+       dey
+       lda     (ptr2),y
+       sta     ptr3
+       dey                     ; Points to next+1
+       ora     ptr3+1
+       beq     @L1             ; Jump if f->prev zero
+
+; We have a previous block, ptr3 contains its address.
+; Do f->prev->next = f->next
+
+       lda     (ptr2),y        ; Load high byte of f->next
+       sta     (ptr3),y        ; Store high byte of f->prev->next
+       dey                     ; Points to next
+       lda     (ptr2),y        ; Load low byte of f->next
+       sta     (ptr3),y        ; Store low byte of f->prev->next
+       jmp     @L2
+
+; This is the first block, correct the freelist pointer
+; Do _hfirst = f->next
+
+@L1:           lda     (ptr2),y        ; Load high byte of f->next
+       sta     __hfirst+1
+       dey                     ; Points to next
+       lda     (ptr2),y        ; Load low byte of f->next
+       sta     __hfirst
+
+; Check f->next. Y points always to next if we come here
+
+@L2:   lda     (ptr2),y        ; Load low byte of f->next
+       sta     ptr3
+       iny                     ; Points to next+1
+       lda     (ptr2),y        ; Load high byte of f->next
+       sta     ptr3+1
+       iny                     ; Points to prev
+       ora     ptr3
+       beq     @L3             ; Jump if f->next zero
+
+; We have a next block, ptr3 contains its address.
+; Do f->next->prev = f->prev
+
+       lda     (ptr2),y        ; Load low byte of f->prev
+       sta     (ptr3),y        ; Store low byte of f->next->prev
+       iny                     ; Points to prev+1
+       lda     (ptr2),y        ; Load high byte of f->prev
+       sta     (ptr3),y        ; Store high byte of f->prev->next
+               jmp     RetUserPtr      ; Done
+
+; This is the last block, correct the freelist pointer.
+; Do _hlast = f->prev
+
+@L3:           lda     (ptr2),y        ; Load low byte of f->prev
+       sta     __hlast
+       iny                     ; Points to prev+1
+       lda     (ptr2),y        ; Load high byte of f->prev
+       sta     __hlast+1
+       jmp     RetUserPtr      ; Done
+
+; We must slice the block found. Cut off space from the upper end, so we
+; can leave the actual free block chain intact.
+
+SliceBlock:
+
+; Decrement the size of the block. Y points to size+1.
+
+       dey                     ; Points to size
+       lda     (ptr2),y        ; Low byte of f->size
+       sub     ptr1
+       sta     (ptr2),y
+       tax                     ; Save low byte of f->size in X
+       iny                     ; Points to size+1
+       lda     (ptr2),y        ; High byte of f->size
+       sbc     ptr1+1
+       sta     (ptr2),y
+
+; Set f to the space above the current block, which is the new block returned
+; to the caller.
+
+       txa                     ; Get low byte of f->size
+               add     ptr2
+       tax
+       lda     (ptr2),y        ; Get high byte of f->size
+       adc     ptr2+1
+       stx     ptr2
+       sta     ptr2+1
+
+; Fill the size into the admin space of the block and return the user pointer
+
+FillSizeAndRet:
+       ldy     #size           ; *p = size;
+       lda     ptr1            ; Low byte of block size
+       sta     (ptr2),y
+       iny                     ; Points to size+1
+       lda     ptr1+1
+       sta     (ptr2),y
+
+RetUserPtr:
+       lda     ptr2            ; return ++p;
+       ldx     ptr2+1
+       add     #admin_space
+       bcc     @L9
+       inx
+@L9:   rts
+