#include <string.h>
#include "heap.h"
#include <gfx_utils.h>
#define HEAP_USED_MAGIC 0x50414548
heap_t _heap;
static void _heap_create(void *start)
{
_heap.start = start;
_heap.first = NULL;
_heap.last = NULL;
}
static void *_heap_alloc(u32 size)
{
hnode_t *node, *new_node;
size = ALIGN(size, sizeof(hnode_t));
if (!_heap.first)
{
node = (hnode_t *)_heap.start;
node->used = HEAP_USED_MAGIC;
node->size = size;
node->prev = NULL;
node->next = NULL;
_heap.first = node;
_heap.last = node;
return (void *)node + sizeof(hnode_t);
}
#ifdef BDK_MALLOC_NO_DEFRAG
node = _heap.last;
#else
node = _heap.first;
while (true)
{
if (!node->used && (size <= node->size))
{
u32 new_size = node->size - size;
new_node = (hnode_t *)((void *)node + sizeof(hnode_t) + size);
if (new_size >= (sizeof(hnode_t) << 2))
{
new_node->used = 0;
new_node->size = new_size - sizeof(hnode_t);
new_node->next = node->next;
if (new_node->next)
new_node->next->prev = new_node;
new_node->prev = node;
node->next = new_node;
}
else
size += new_size;
node->size = size;
node->used = HEAP_USED_MAGIC;
return (void *)node + sizeof(hnode_t);
}
if (node->next)
node = node->next;
else
break;
}
#endif
new_node = (hnode_t *)((void *)node + sizeof(hnode_t) + node->size);
new_node->used = HEAP_USED_MAGIC;
new_node->size = size;
new_node->prev = node;
new_node->next = NULL;
node->next = new_node;
_heap.last = new_node;
return (void *)new_node + sizeof(hnode_t);
}
static void _heap_free(void *addr)
{
hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t));
if (addr < _heap.start || node->used != HEAP_USED_MAGIC)
{
return;
}
node->used = 0;
#ifndef BDK_MALLOC_NO_DEFRAG
hnode_t *prev = node->prev;
if (prev && !prev->used)
{
prev->size += node->size + sizeof(hnode_t);
prev->next = node->next;
if (node->next)
node->next->prev = prev;
node = prev;
}
hnode_t *next = node->next;
if (next && !next->used)
{
node->size += next->size + sizeof(hnode_t);
node->next = next->next;
if (next->next)
next->next->prev = node;
}
#endif
}
void heap_init(void *base)
{
_heap_create(base);
}
void heap_set(heap_t *heap)
{
memcpy(&_heap, heap, sizeof(heap_t));
}
void *malloc(u32 size)
{
return _heap_alloc(size);
}
void *zalloc(u32 size)
{
void *buf = (void *)_heap_alloc(size);
memset(buf, 0, ALIGN(size, sizeof(hnode_t)));
return buf;
}
void *calloc(u32 num, u32 size)
{
return zalloc(num * size);
}
void free(void *buf)
{
_heap_free(buf);
}
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
{
u32 count = 0;
memset(mon, 0, sizeof(heap_monitor_t));
hnode_t *node = _heap.first;
while (true)
{
if (node->used)
{
mon->nodes_used++;
mon->used += node->size + sizeof(hnode_t);
}
else
mon->total += node->size + sizeof(hnode_t);
if (print_node_stats)
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
count, node->used, (u32)node + sizeof(hnode_t), node->size);
count++;
if (node->next)
node = node->next;
else
break;
}
mon->total += mon->used;
mon->nodes_total = count;
}