Files
ox/src/nostalgia/core/gba/mem.cpp
T
2017-10-15 02:48:37 -05:00

136 lines
2.8 KiB
C++

/*
* Copyright 2016-2017 gtalent2@gmail.com
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "addresses.hpp"
#include "panic.hpp"
namespace nostalgia {
namespace core {
struct HeapSegment {
size_t size;
uint8_t inUse;
HeapSegment *next;
uint8_t *end() {
return ((uint8_t*) this) + this->size;
}
};
static HeapSegment *_heapIdx = nullptr;
void initHeap() {
_heapIdx = (HeapSegment*) MEM_WRAM_END;
_heapIdx--;
// set size to half of WRAM
_heapIdx->size = (MEM_WRAM_END - MEM_WRAM_BEGIN) / 2;
_heapIdx->next = nullptr;
_heapIdx->inUse = false;
}
}
}
using namespace nostalgia::core;
void *malloc(size_t allocSize) {
// add space for heap segment header data
const auto fullSize = allocSize + sizeof(HeapSegment);
auto seg = _heapIdx;
HeapSegment *prev = nullptr;
while (seg && seg->size < fullSize) {
prev = seg;
seg = seg->next;
}
// panic if the allocation failed
if (seg == nullptr) {
panic("Heap allocation failed");
}
seg = (HeapSegment*) (((uint8_t*) seg) - allocSize);
if (prev) {
prev->next = seg;
}
// update size for the heap segment now that it is to be considered
// allocated
seg->size = fullSize;
seg->next = (HeapSegment*) (((uint8_t*) seg) + fullSize);
seg->inUse = true;
auto out = seg + 1;
auto hs = *_heapIdx;
hs.size -= fullSize;
if (hs.size == 0) {
_heapIdx = hs.next;
} else {
_heapIdx = (HeapSegment*) (((uint8_t*) _heapIdx) - fullSize);
*_heapIdx = hs;
}
return out;
}
void free(void *ptrIn) {
// get ptr back down to the meta data
auto *ptr = ((HeapSegment*) ptrIn) - 1;
HeapSegment *prev = nullptr;
HeapSegment *current = _heapIdx;
while (current && current != ptr) {
prev = current;
current = current->next;
}
// ptr was found as a valid memory allocation, deallocate it
if (current) {
// move header back to end of segment
auto newCurrent = (HeapSegment*) current->end() - sizeof(HeapSegment);
*newCurrent = *current;
current = newCurrent;
prev->next = current;
// mark as not in use
current->inUse = false;
// join with next if next is also unused
if (current->next && !current->next->inUse) {
current->size += current->next->size;
current->next = current->next->next;
}
// join with prev if prev is also unused
if (prev && !prev->inUse) {
prev->size += current->size;
prev->next = current->next;
current = prev;
}
// if current is closer heap start than _heapIdx, _heapIdx becomes
// current
if (current > _heapIdx) {
_heapIdx = current;
}
}
}
void *operator new(size_t allocSize) {
return malloc(allocSize);
}
void *operator new[](size_t allocSize) {
return malloc(allocSize);
}
void operator delete(void *ptr) {
free(ptr);
}
void operator delete[](void *ptr) {
free(ptr);
}