summaryrefslogtreecommitdiffstats
path: root/gbdk/gbdk-lib/libc/malloc.c
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2022-06-02 15:28:40 +0200
committerLouis Burda <quent.burda@gmail.com>2022-06-02 15:28:40 +0200
commit5bc16063c29aa4d3d287ebd163ccdbcbf54c4f9f (patch)
treec131f947a37b3af2d14d41e9eda098bdec2d061c /gbdk/gbdk-lib/libc/malloc.c
parent78a5f810b22f0d8cafa05f638b0cb2e889824859 (diff)
downloadcscg2022-gearboy-master.tar.gz
cscg2022-gearboy-master.zip
Added submodule filesHEADmaster
Diffstat (limited to 'gbdk/gbdk-lib/libc/malloc.c')
-rw-r--r--gbdk/gbdk-lib/libc/malloc.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/gbdk/gbdk-lib/libc/malloc.c b/gbdk/gbdk-lib/libc/malloc.c
new file mode 100644
index 00000000..965e47dd
--- /dev/null
+++ b/gbdk/gbdk-lib/libc/malloc.c
@@ -0,0 +1,114 @@
+/*-------------------------------------------------------------------------
+ malloc.c - allocate memory.
+
+ Copyright (C) 2015, Philipp Klaus Krause, pkk@spth.de
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#if defined(__SDCC_mcs51) || defined(__SDCC_ds390) || defined(__SDCC_ds400)
+#define HEAPSPACE __xdata
+#elif defined(__SDCC_pdk13) || defined(__SDCC_pdk14) || defined(__SDCC_pdk15)
+#define HEAPSPACE __near
+#else
+#define HEAPSPACE
+#endif
+
+typedef struct header HEAPSPACE header_t;
+
+struct header
+{
+ header_t *next; // Next block. Linked list of all blocks, terminated by pointer to end of heap (or to the byte beyond the end of the heap).
+ header_t *next_free; // Next free block. Used in free blocks only. Overlaps with user data in non-free blocks. Linked list of free blocks, 0-terminated.
+};
+
+header_t *HEAPSPACE __sdcc_heap_free; // First free block, 0 if no free blocks.
+
+extern header_t __sdcc_heap;
+#define HEAP_START &__sdcc_heap
+
+#if defined(__SDCC_mcs51) || defined(__SDCC_ds390) || defined(__SDCC_ds400) || defined(__SDCC_hc08) || defined(__SDCC_s08)
+
+extern const unsigned int __sdcc_heap_size;
+#define HEAP_END (struct header HEAPSPACE *)((char HEAPSPACE *)&__sdcc_heap + (__sdcc_heap_size - 1)) // -1 To be sure that HEAP_END is bigger than HEAP_START.
+
+#else
+
+extern header_t __sdcc_heap_end; // Just beyond the end of the heap. Must be higher in memory than _sdcc_heap_start.
+#define HEAP_END &__sdcc_heap_end
+
+#endif
+
+void __sdcc_heap_init(void)
+{
+ __sdcc_heap_free = HEAP_START;
+ __sdcc_heap_free->next = HEAP_END;
+ __sdcc_heap_free->next_free = 0;
+}
+
+#if defined(__SDCC_mcs51) || defined(__SDCC_ds390) || defined(__SDCC_ds400)
+void HEAPSPACE *malloc(size_t size)
+#else
+void *malloc(size_t size)
+#endif
+{
+ header_t *h;
+ header_t *HEAPSPACE *f;
+
+#if defined(__SDCC_mcs51) || defined(__SDCC_ds390) || defined(__SDCC_ds400) || defined(__SDCC_hc08) || defined(__SDCC_s08)
+ if(!__sdcc_heap_free)
+ __sdcc_heap_init();
+#endif
+
+ if(!size || size + offsetof(struct header, next_free) < size)
+ return(0);
+ size += offsetof(struct header, next_free);
+ if(size < sizeof(struct header)) // Requiring a minimum size makes it easier to implement free(), and avoid memory leaks.
+ size = sizeof(struct header);
+
+ for(h = __sdcc_heap_free, f = &__sdcc_heap_free; h; f = &(h->next_free), h = h->next_free)
+ {
+ size_t blocksize = (char HEAPSPACE *)(h->next) - (char HEAPSPACE *)h;
+ if(blocksize >= size) // Found free block of sufficient size.
+ {
+ if(blocksize >= size + sizeof(struct header)) // It is worth creating a new free block
+ {
+ header_t *const newheader = (header_t *const)((char HEAPSPACE *)h + size);
+ newheader->next = h->next;
+ newheader->next_free = h->next_free;
+ *f = newheader;
+ h->next = newheader;
+ }
+ else
+ *f = h->next_free;
+
+ return(&(h->next_free));
+ }
+ }
+
+ return(0);
+}
+