diff options
| author | Eblo <7004497+Eblo@users.noreply.github.com> | 2025-09-12 22:19:05 -0400 |
|---|---|---|
| committer | Eblo <7004497+Eblo@users.noreply.github.com> | 2025-09-12 22:19:05 -0400 |
| commit | b95d50557327e35618988e2611472be78d7e4dae (patch) | |
| tree | 233856a91f50703e7c9c7bb6c9715e3ace635058 /mm/src/boot/O2 | |
| parent | f3c53811a4550adde5158b362dbf31ca1fbf9eac (diff) | |
Revert "Organize `libc64` files (#1492)"
This reverts commit e47a7050faf345ab2f220bfce58effd2590b9e5e.
Diffstat (limited to 'mm/src/boot/O2')
| -rw-r--r-- | mm/src/boot/O2/__osMalloc.c | 459 | ||||
| -rw-r--r-- | mm/src/boot/O2/gfxprint.c | 3 | ||||
| -rw-r--r-- | mm/src/boot/O2/loadfragment.c | 6 | ||||
| -rw-r--r-- | mm/src/boot/O2/loadfragment2.c | 4 | ||||
| -rw-r--r-- | mm/src/boot/O2/math64.c | 191 | ||||
| -rw-r--r-- | mm/src/boot/O2/printutils.c | 25 | ||||
| -rw-r--r-- | mm/src/boot/O2/rand.c | 90 | ||||
| -rw-r--r-- | mm/src/boot/O2/sleep.c | 27 | ||||
| -rw-r--r-- | mm/src/boot/O2/sprintf.c | 33 | ||||
| -rw-r--r-- | mm/src/boot/O2/system_heap.c | 10 | ||||
| -rw-r--r-- | mm/src/boot/O2/system_malloc.c | 52 |
11 files changed, 888 insertions, 12 deletions
diff --git a/mm/src/boot/O2/__osMalloc.c b/mm/src/boot/O2/__osMalloc.c new file mode 100644 index 000000000..afd626252 --- /dev/null +++ b/mm/src/boot/O2/__osMalloc.c @@ -0,0 +1,459 @@ +#include "os_malloc.h" +#include "libc/stdbool.h" +#include "libc/stdint.h" +#include "macros.h" +#include "functions.h" +#include <string.h> + +#define FILL_ALLOCBLOCK (1 << 0) +#define FILL_FREEBLOCK (1 << 1) +#define CHECK_FREE_BLOCK (1 << 2) + +#define NODE_MAGIC (0x7373) + +#define BLOCK_UNINIT_MAGIC (0xAB) +#define BLOCK_UNINIT_MAGIC_32 (0xABABABAB) +#define BLOCK_ALLOC_MAGIC (0xCD) +#define BLOCK_ALLOC_MAGIC_32 (0xCDCDCDCD) +#define BLOCK_FREE_MAGIC (0xEF) +#define BLOCK_FREE_MAGIC_32 (0xEFEFEFEF) + +OSMesg sArenaLockMsg[1]; + +void __osMallocAddHeap(Arena* arena, void* heap, size_t size); + +void ArenaImpl_LockInit(Arena* arena) { + osCreateMesgQueue(&arena->lock, sArenaLockMsg, ARRAY_COUNT(sArenaLockMsg)); +} + +void ArenaImpl_Lock(Arena* arena) { + // osSendMesg(&arena->lock, NULL, OS_MESG_BLOCK); +} + +void ArenaImpl_Unlock(Arena* arena) { + // osRecvMesg(&arena->lock, NULL, OS_MESG_BLOCK); +} + +ArenaNode* ArenaImpl_GetLastBlock(Arena* arena) { + ArenaNode* last; + ArenaNode* iter; + + last = arena->head; + + if (last != NULL) { + iter = last->next; + while (iter != NULL) { + last = iter; + iter = iter->next; + } + } + return last; +} + +/** + * Initializes \p arena to manage the memory region \p heap. + * + * @param arena The Arena to initialize. + * @param heap The memory region to use as heap space. + * @param size The size of the heap. + */ +void __osMallocInit(Arena* arena, void* heap, size_t size) { + memset(arena, 0, sizeof(Arena)); + + ArenaImpl_LockInit(arena); + + __osMallocAddHeap(arena, heap, size); + arena->isInit = true; +} + +// Original name: __osMallocAddBlock +void __osMallocAddHeap(Arena* arena, void* heap, size_t size) { + ptrdiff_t diff; + s32 alignedSize; + ArenaNode* firstNode; + ArenaNode* lastNode; + + if (heap == NULL) { + return; + } + + firstNode = (ArenaNode*)ALIGN16((uintptr_t)heap); + diff = (uintptr_t)firstNode - (uintptr_t)heap; + alignedSize = ((s32)size - diff) & ~0xF; + + // If the size of the heap is smaller than sizeof(ArenaNode), then the initialization will silently fail + if (alignedSize > (s32)sizeof(ArenaNode)) { + firstNode->next = NULL; + firstNode->prev = NULL; + firstNode->size = alignedSize - sizeof(ArenaNode); + firstNode->isFree = true; + firstNode->magic = NODE_MAGIC; + + ArenaImpl_Lock(arena); + + lastNode = ArenaImpl_GetLastBlock(arena); + + // Checks if there's already a block + if (lastNode == NULL) { + arena->head = firstNode; + arena->start = heap; + } else { + // Chain the existing block with the new one + firstNode->prev = lastNode; + lastNode->next = firstNode; + } + + ArenaImpl_Unlock(arena); + } +} + +/** + * Clears the whole \p arena, invalidating every allocated pointer to it. + * + * @param arena The Arena to clear. + */ +void __osMallocCleanup(Arena* arena) { + memset(arena, 0, sizeof(Arena)); +} + +/** + * Returns whether or not the \p arena has been initialized. + * + * @param arena The Arena to check. + * @return u8 `true` if the \p arena has been initialized. `false` otherwise. + */ +u8 __osMallocIsInitalized(Arena* arena) { + return arena->isInit; +} + +/** + * Allocates at least \p size bytes of memory using the given \p arena. + * The block of memory will be allocated at the start of the first sufficiently large free block. + * + * - If there's not enough space in the given \p arena, this function will fail, returning `NULL`. + * - If \p size is zero, then an empty region of memory is returned. + * + * To avoid memory leaks, the returned pointer should be eventually deallocated using either `__osFree` or + * `__osRealloc`. + * + * @param[in, out] arena The specific Arena to be used for the allocation. + * @param[in] size The size in bytes that will be allocated. + * @return void* On success, the allocated area of the \p arena memory. Otherwise, `NULL`. + */ +void* __osMalloc(Arena* arena, size_t size) { + ArenaNode* iter; + ArenaNode* newNode; + void* alloc = NULL; + + size = ALIGN16(size); + + ArenaImpl_Lock(arena); + + // Start iterating from the head of the arena. + iter = arena->head; + + // Iterate over the arena looking for a big enough space of memory. + while (iter != NULL) { + if (iter->isFree && iter->size >= size) { + size_t blockSize = ALIGN16(size) + sizeof(ArenaNode); + + // If the block is larger than the requested size, then split it and just use the required size of the + // current block. + if (blockSize < iter->size) { + ArenaNode* next; + + newNode = (ArenaNode*)((uintptr_t)iter + blockSize); + newNode->next = iter->next; + newNode->prev = iter; + newNode->size = iter->size - blockSize; + newNode->isFree = true; + newNode->magic = NODE_MAGIC; + + iter->next = newNode; + iter->size = size; + + next = newNode->next; + if (next != NULL) { + next->prev = newNode; + } + } + + iter->isFree = false; + alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); + break; + } + + iter = iter->next; + } + + ArenaImpl_Unlock(arena); + + return alloc; +} + +/** + * Allocates at least \p size bytes of memory using the given \p arena. + * Unlike __osMalloc, the block of memory will be allocated from the end of the \p arena. + * + * - If there's not enough space in the given \p arena, this function will fail, returning `NULL`. + * - If \p size is zero, then an empty region of memory is returned. + * + * To avoid memory leaks, the returned pointer should be eventually deallocated using `__osFree` or `__osRealloc`. + * + * @param[in, out] arena The specific Arena to be used for the allocation. + * @param[in] size The size in bytes that will be allocated. + * @return void* On success, the allocated area of the \p arena memory. Otherwise, `NULL`. + */ +void* __osMallocR(Arena* arena, size_t size) { + ArenaNode* iter; + ArenaNode* newNode; + size_t blockSize; + void* alloc = NULL; + + size = ALIGN16(size); + + ArenaImpl_Lock(arena); + + // Start iterating from the last block of the arena. + iter = ArenaImpl_GetLastBlock(arena); + + // Iterate in reverse the arena looking for a big enough space of memory. + while (iter != NULL) { + if (iter->isFree && iter->size >= size) { + blockSize = ALIGN16(size) + sizeof(ArenaNode); + + // If the block is larger than the requested size, then split it and just use the required size of the + // current block. + if (blockSize < iter->size) { + ArenaNode* next; + + newNode = (ArenaNode*)((uintptr_t)iter + (iter->size - size)); + newNode->next = iter->next; + newNode->prev = iter; + newNode->size = size; + newNode->magic = NODE_MAGIC; + + iter->next = newNode; + iter->size -= blockSize; + + next = newNode->next; + if (next != NULL) { + next->prev = newNode; + } + iter = newNode; + } + + iter->isFree = false; + alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); + break; + } + iter = iter->prev; + } + + ArenaImpl_Unlock(arena); + + return alloc; +} + +/** + * Deallocates the pointer \p ptr previously allocated by `__osMalloc`, `__osMallocR` or `__osRealloc`. + * If \p ptr is `NULL` or it has been already been freed, then this function does nothing. + * + * - The behaviour is undefined if \p ptr is not a memory region returned by one of the cited allocating + * functions. + * - The behaviour is undefined if \p ptr doesn't correspond to the given \p arena. + * - Any access to the freed pointer is undefined behaviour. + * + * @param[in, out] arena The specific Arena to be used for the allocation. + * @param[in, out] ptr The allocated memory block to deallocate. + */ +void __osFree(Arena* arena, void* ptr) { + ArenaNode* node; + ArenaNode* next; + ArenaNode* prev; + + ArenaImpl_Lock(arena); + + node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); + + if ((ptr != NULL) && (node->magic == NODE_MAGIC) && !node->isFree) { + next = node->next; + prev = node->prev; + node->isFree = true; + + // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the + // two nodes into one. + if ((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size && next->isFree) { + ArenaNode* newNext = next->next; + + if (newNext != NULL) { + newNext->prev = node; + } + + node->size += next->size + sizeof(ArenaNode); + + node->next = newNext; + next = newNext; + } + + // Checks if the previous node is contiguous to the current node and if it isn't currently allocated. Then merge + // the two nodes into one. + if ((prev != NULL) && prev->isFree && ((uintptr_t)node == (uintptr_t)prev + sizeof(ArenaNode) + prev->size)) { + if (next != NULL) { + next->prev = prev; + } + + prev->next = next; + prev->size += node->size + sizeof(ArenaNode); + } + } + + ArenaImpl_Unlock(arena); +} + +/** + * Reallocates the pointer \p ptr. + * \p ptr must be either a pointer previously allocated by `__osMalloc`, `__osMallocR` or `__osRealloc` and + * not freed yet, or a `NULL` pointer. + * + * - If \p ptr is `NULL` a new pointer is allocated. See `__osMalloc` for more details. + * - If \p newSize is 0, then the given pointer is freed and `NULL` is returned. See `__osFree` for more details. + * - If \p newSize is bigger than the currently allocated allocated pointer, then the area of memory is expanded to a + * size big enough to fit the requested size. + * + * - The behaviour is undefined if \p ptr is not a memory region returned by one of the cited allocating + * functions. + * - The behaviour is undefined if \p ptr doesn't correspond to the given \p arena. + * - If the pointer is freed, then any access to the original freed pointer is undefined behaviour. + * + * @param[in, out] arena The specific Arena to be used for the allocation. + * @param[in, out] ptr The allocated memory block to deallocate. + * @param[in] newSize The new requested size. + * @return void* On success, the pointer to the reallocated area of memory. On failure, `NULL` is returned, + * and the original parameter \p ptr remains valid. + */ +void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { + ArenaImpl_Lock(arena); + + (void)"__osRealloc(%08x, %d)\n"; + + if (ptr == NULL) { + // if the `ptr` is NULL, then allocate a new pointer with the specified size + // if newSize is 0, then __osMalloc would return a NULL pointer + ptr = __osMalloc(arena, newSize); + } else if (newSize == 0) { + // if the requested size is zero, then free the pointer + __osFree(arena, ptr); + ptr = NULL; + } else { + size_t diff; + void* newPtr; + // Gets the start of the ArenaNode pointer embedded + ArenaNode* node = (void*)((uintptr_t)ptr - sizeof(ArenaNode)); + + newSize = ALIGN16(newSize); + + // Only reallocate the memory if the new size isn't smaller than the actual node size + if ((newSize != node->size) && (node->size < newSize)) { + ArenaNode* next = node->next; + + diff = newSize - node->size; + // Checks if the next node is contiguous to the current allocated node and it has enough space to fit the + // new requested size + if (((uintptr_t)next == (uintptr_t)node + node->size + sizeof(ArenaNode)) && (next->isFree) && + (next->size >= diff)) { + ArenaNode* next2 = next->next; + + next->size = (next->size - diff); + if (next2 != NULL) { + // Update the previous element of the linked list + next2->prev = (void*)((uintptr_t)next + diff); + } + + next2 = (void*)((uintptr_t)next + diff); + node->next = next2; + node->size = newSize; + __osMemcpy(next2, next, sizeof(ArenaNode)); + } else { + // Create a new pointer and manually copy the data from the old pointer to the new one + newPtr = __osMalloc(arena, newSize); + if (newPtr != NULL) { + memcpy(ptr, newPtr, node->size); + __osFree(arena, ptr); + } + ptr = newPtr; + } + } + } + + ArenaImpl_Unlock(arena); + + return ptr; +} + +/** + * Gets the size of the largest free block, the total free space and the total allocated space. + * + * @param[in, out] arena The Arena which will be used to get the values from. + * @param[out] outMaxFree The size of the largest free block. + * @param[out] outFree The total free space. + * @param[out] outAlloc The total allocated space. + */ +void __osGetSizes(Arena* arena, size_t* outMaxFree, size_t* outFree, size_t* outAlloc) { + ArenaNode* iter; + + ArenaImpl_Lock(arena); + + *outMaxFree = 0; + *outFree = 0; + *outAlloc = 0; + + iter = arena->head; + while (iter != NULL) { + if (iter->isFree) { + *outFree += iter->size; + if (*outMaxFree < iter->size) { + *outMaxFree = iter->size; + } + } else { + *outAlloc += iter->size; + } + + iter = iter->next; + } + + ArenaImpl_Unlock(arena); +} + +/** + * Checks the validity of every node of the \p arena. + * + * @param arena The Arena to check. + * @return s32 0 if every pointer is valid. 1 otherwise. + */ +s32 __osCheckArena(Arena* arena) { + ArenaNode* iter; + s32 err = 0; + + ArenaImpl_Lock(arena); + + // "Checking the contents of the arena..." + (void)"アリーナの内容をチェックしています... (%08x)\n"; + + for (iter = arena->head; iter != NULL; iter = iter->next) { + if (iter->magic != NODE_MAGIC) { + // "Oops!!" + (void)"おおっと!! (%08x %08x)\n"; + + err = 1; + break; + } + } + + // "The arena still looks good" + (void)"アリーナはまだ、いけそうです\n"; + + ArenaImpl_Unlock(arena); + + return err; +} diff --git a/mm/src/boot/O2/gfxprint.c b/mm/src/boot/O2/gfxprint.c index 50360bb6b..5b0ea20d0 100644 --- a/mm/src/boot/O2/gfxprint.c +++ b/mm/src/boot/O2/gfxprint.c @@ -1,5 +1,4 @@ #include "global.h" -#include "libc64/aprintf.h" #include "2s2h/BenPort.h" #include "align_asset_macro.h" @@ -390,7 +389,7 @@ Gfx* GfxPrint_Close(GfxPrint* this) { } s32 GfxPrint_VPrintf(GfxPrint* this, const char* fmt, va_list args) { - return vaprintf(&this->callback, fmt, args); + return PrintUtils_VPrintf(&this->callback, fmt, args); } s32 GfxPrint_Printf(GfxPrint* this, const char* fmt, ...) { diff --git a/mm/src/boot/O2/loadfragment.c b/mm/src/boot/O2/loadfragment.c index 83ea54539..b1ba39d65 100644 --- a/mm/src/boot/O2/loadfragment.c +++ b/mm/src/boot/O2/loadfragment.c @@ -11,7 +11,7 @@ */ #include "global.h" -#include "libc64/malloc.h" +#include "system_malloc.h" #include "loadfragment.h" #include <string.h> @@ -187,7 +187,7 @@ void* Fragment_AllocateAndLoad(uintptr_t vromStart, uintptr_t vromEnd, void* vra if (gLoadLogSeverity >= 3) {} - allocatedRamAddr = malloc_r(size); + allocatedRamAddr = SystemArena_MallocR(size); end = (uintptr_t)allocatedRamAddr + size; if (gLoadLogSeverity >= 3) {} @@ -203,7 +203,7 @@ void* Fragment_AllocateAndLoad(uintptr_t vromStart, uintptr_t vromEnd, void* vra allocatedBytes = ovlRelocs->bssSize + size; - allocatedRamAddr = realloc(allocatedRamAddr, allocatedBytes); + allocatedRamAddr = SystemArena_Realloc(allocatedRamAddr, allocatedBytes); if (gLoadLogSeverity >= 3) {} diff --git a/mm/src/boot/O2/loadfragment2.c b/mm/src/boot/O2/loadfragment2.c index 32febf4a8..cd7da84f2 100644 --- a/mm/src/boot/O2/loadfragment2.c +++ b/mm/src/boot/O2/loadfragment2.c @@ -7,7 +7,7 @@ * These are for specific fragment overlays with the .ovl file extension */ #include "global.h" -#include "libc64/malloc.h" +#include "system_malloc.h" #include "loadfragment.h" s32 gOverlayLogSeverity = 2; @@ -170,7 +170,7 @@ size_t Overlay_Load(uintptr_t vromStart, uintptr_t vromEnd, void* ramStart, void } void* Overlay_AllocateAndLoad(uintptr_t vromStart, uintptr_t vromEnd, void* vramStart, void* vramEnd) { - void* allocatedRamAddr = malloc_r((uintptr_t)vramEnd - (uintptr_t)vramStart); + void* allocatedRamAddr = SystemArena_MallocR((uintptr_t)vramEnd - (uintptr_t)vramStart); if (allocatedRamAddr != NULL) { Overlay_Load(vromStart, vromEnd, vramStart, vramEnd, allocatedRamAddr); diff --git a/mm/src/boot/O2/math64.c b/mm/src/boot/O2/math64.c new file mode 100644 index 000000000..746be8e01 --- /dev/null +++ b/mm/src/boot/O2/math64.c @@ -0,0 +1,191 @@ +/** + * MathF library + * Contains tangent function, wrappers for a number of the handwritten functions in fp, and a suite of arctangents + */ +#include "global.h" +#include "fixed_point.h" + +s32 gUseAtanContFrac; + +/** + * Tangent function computed using libultra sinf and cosf + */ +f32 Math_FTanF(f32 x) { + return sinf(x) / cosf(x); +} + +// Unused +f32 Math_FFloorF(f32 x) { + return floorf(x); +} + +// Unused +f32 Math_FCeilF(f32 x) { + return ceilf(x); +} + +// Unused +f32 Math_FRoundF(f32 x) { + return roundf(x); +} + +// Unused +f32 Math_FTruncF(f32 x) { + return truncf(x); +} + +f32 Math_FNearbyIntF(f32 x) { + return nearbyintf(x); +} + +/** + * Arctangent approximation using a Maclaurin series [https://mathworld.wolfram.com/MaclaurinSeries.html] + * (one quadrant, i.e. |x| < 1) + */ +f32 Math_FAtanTaylorQF(f32 x) { + // Coefficients of Maclaurin series of arctangent + static const f32 coeffs[] = { + -1.0f / 3, +1.0f / 5, -1.0f / 7, +1.0f / 9, -1.0f / 11, +1.0f / 13, -1.0f / 15, +1.0f / 17, 0.0f, + }; + + f32 poly = x; + f32 sq = SQ(x); + f32 exp = x * sq; + const f32* c = coeffs; + f32 term; + + // Calculate the series until adding more terms does not change the float + while (true) { + term = *c++ * exp; + if (poly + term == poly) { + break; + } + poly += term; + exp *= sq; + } + + return poly; +} + +/** + * Extends previous arctangent function to the rest of the real numbers. + * Uses the formulae arctan(x) = pi/2 - arctan(1/x) + * and arctan(x) = pi/4 - arctan( (1-x)/(1+x) ) + * to extend the range in which the series computed by Math_FAtanTaylorQF is a good approximation + */ +f32 Math_FAtanTaylorF(f32 x) { + f32 t; + f32 q; + + if (x > 0.0f) { + t = x; + } else if (x < 0.0f) { + t = -x; + } else if (x == 0.0f) { + return 0.0f; + } else { + return qNaN0x10000; + } + + if (t <= M_SQRT2f - 1.0f) { + return Math_FAtanTaylorQF(x); + } + + if (t >= M_SQRT2f + 1.0f) { + q = M_PIf / 2 - Math_FAtanTaylorQF(1.0f / t); + } else { // in the interval (\sqrt{2} - 1, \sqrt{2} + 1) + q = M_PIf / 4 - Math_FAtanTaylorQF((1.0f - t) / (1.0f + t)); + } + + if (x > 0.0f) { + return q; + } else { + return -q; + } +} + +/** + * Arctangent approximation using a continued fraction + * Cf. https://en.wikipedia.org/wiki/Gauss%27s_continued_fraction#The_series_2F1_2 , + * https://dlmf.nist.gov/4.25#E4 + */ +f32 Math_FAtanContFracF(f32 x) { + s32 sector; + f32 z; + f32 conv; + f32 sq; + s32 i; + + if (x >= -1.0f && x <= 1.0f) { + sector = 0; + } else if (x > 1.0f) { + sector = 1; + x = 1.0f / x; + } else if (x < -1.0f) { + sector = -1; + x = 1.0f / x; + } else { + return qNaN0x10000; + } + + // Builds the continued fraction from the innermost fraction out + sq = SQ(x); + conv = 0.0f; + z = 8.0f; + for (i = 8; i != 0; i--) { + conv = SQ(z) * sq / (2.0f * z + 1.0f + conv); + z -= 1.0f; + } + conv = x / (1.0f + conv); + + if (sector == 0) { + return conv; + } else if (sector > 0) { + return M_PIf / 2 - conv; + } else { + return -M_PIf / 2 - conv; + } +} + +/** + * Single-argument arctangent, only used by the two-argument function. + * Nothing else sets the bss variable gUseAtanContFrac, so the Maclaurin series is always used + */ +f32 Math_FAtanF(f32 x) { + if (!gUseAtanContFrac) { + return Math_FAtanTaylorF(x); + } else { + return Math_FAtanContFracF(x); + } +} + +/** + * Main two-argument arctangent function + */ +f32 Math_FAtan2F(f32 y, f32 x) { + if (x == 0.0f) { + if (y == 0.0f) { + return 0.0f; + } else if (y > 0.0f) { + return M_PIf / 2; + } else if (y < 0.0f) { + return -M_PIf / 2; + } else { + return qNaN0x10000; + } + } else if (x >= 0.0f) { + return Math_FAtanF(y / x); + } else if (y < 0.0f) { + return Math_FAtanF(y / x) - M_PIf; + } else { + return M_PIf - Math_FAtanF(-(y / x)); + } +} + +f32 Math_FAsinF(f32 x) { + return Math_FAtan2F(x, sqrtf(1.0f - SQ(x))); +} + +f32 Math_FAcosF(f32 x) { + return M_PIf / 2 - Math_FAsinF(x); +} diff --git a/mm/src/boot/O2/printutils.c b/mm/src/boot/O2/printutils.c new file mode 100644 index 000000000..82e16f4dd --- /dev/null +++ b/mm/src/boot/O2/printutils.c @@ -0,0 +1,25 @@ +#include "global.h" +#include "stdio.h" + +s32 _Printf(PrintCallback a, void* arg, const char* fmt, va_list ap) { + unsigned char buffer[4096]; + + vsnprintf(buffer, sizeof(buffer), fmt, ap); + a(arg, buffer, strlen(buffer)); +} + +s32 PrintUtils_VPrintf(PrintCallback* pfn, const char* fmt, va_list args) { + return _Printf(*pfn, pfn, fmt, args); +} + +s32 PrintUtils_Printf(PrintCallback* pfn, const char* fmt, ...) { + s32 ret; + va_list args; + va_start(args, fmt); + + ret = PrintUtils_VPrintf(pfn, fmt, args); + + va_end(args); + + return ret; +}
\ No newline at end of file diff --git a/mm/src/boot/O2/rand.c b/mm/src/boot/O2/rand.c new file mode 100644 index 000000000..152c8a0e7 --- /dev/null +++ b/mm/src/boot/O2/rand.c @@ -0,0 +1,90 @@ +#include "rand.h" + +//! The latest generated random number, used to generate the next number in the sequence. +static u32 sRandInt = 1; + +//! Space to store a value to be re-interpreted as a float. +//! This can't be static because it is used in z_kankyo. +u32 gRandFloat; + +/** + * Generates the next pseudo-random integer. + */ +u32 Rand_Next(void) { + return sRandInt = (sRandInt * RAND_MULTIPLIER) + RAND_INCREMENT; +} + +/** + * Seeds the internal pseudo-random number generator with a provided starting value. + */ +void Rand_Seed(u32 seed) { + sRandInt = seed; +} + +/** + * Returns a pseudo-random float between 0.0f and 1.0f from the internal PRNG. + * + * @note Works by generating the next integer, masking it to an IEEE-754 compliant float between 1.0f and 2.0f, and + * subtracting 1.0f. + * + * @remark This is also recommended by Numerical Recipes, pp. 284-5. + */ +f32 Rand_ZeroOne(void) { + sRandInt = (sRandInt * RAND_MULTIPLIER) + RAND_INCREMENT; + gRandFloat = ((sRandInt >> 9) | 0x3F800000); + return *((f32*)&gRandFloat) - 1.0f; +} + +/** + * Returns a pseudo-random float between -0.5f and 0.5f in the same way as Rand_ZeroOne(). + */ +f32 Rand_Centered(void) { + sRandInt = (sRandInt * RAND_MULTIPLIER) + RAND_INCREMENT; + gRandFloat = ((sRandInt >> 9) | 0x3F800000); + return *((f32*)&gRandFloat) - 1.5f; +} + +//! All functions below are unused variants of the above four, that use a provided random number variable instead of the +//! internal `sRandInt` + +/** + * Seeds a provided pseudo-random number with a provided starting value. + * + * @see Rand_Seed + */ +void Rand_Seed_Variable(u32* rndNum, u32 seed) { + *rndNum = seed; +} + +/** + * Generates the next pseudo-random number from the provided rndNum. + * + * @see Rand_Next + */ +u32 Rand_Next_Variable(u32* rndNum) { + return *rndNum = (*rndNum * RAND_MULTIPLIER) + RAND_INCREMENT; +} + +/** + * Generates the next pseudo-random float between 0.0f and 1.0f from the provided rndNum. + * + * @see Rand_ZeroOne + */ +f32 Rand_ZeroOne_Variable(u32* rndNum) { + u32 next = (*rndNum * RAND_MULTIPLIER) + RAND_INCREMENT; + + gRandFloat = ((*rndNum = next) >> 9) | 0x3F800000; + return *((f32*)&gRandFloat) - 1.0f; +} + +/** + * Generates the next pseudo-random float between -0.5f and 0.5f from the provided rndNum. + * + * @see Rand_ZeroOne, Rand_Centered + */ +f32 Rand_Centered_Variable(u32* rndNum) { + u32 next = (*rndNum * RAND_MULTIPLIER) + RAND_INCREMENT; + + gRandFloat = ((*rndNum = next) >> 9) | 0x3F800000; + return *((f32*)&gRandFloat) - 1.5f; +} diff --git a/mm/src/boot/O2/sleep.c b/mm/src/boot/O2/sleep.c new file mode 100644 index 000000000..a45d7e7dd --- /dev/null +++ b/mm/src/boot/O2/sleep.c @@ -0,0 +1,27 @@ +#include "global.h" + +void Sleep_Cycles(u64 time) { + // OSMesgQueue mq; + // OSMesg msg[1]; + // OSTimer timer; + + // osCreateMesgQueue(&mq, msg, ARRAY_COUNT(msg)); + // osSetTimer(&timer, time, 0, &mq, NULL); + // osRecvMesg(&mq, NULL, OS_MESG_BLOCK); +} + +void Sleep_Nsec(u32 nsec) { + // Sleep_Cycles(OS_NSEC_TO_CYCLES(nsec)); +} + +void Sleep_Usec(u32 usec) { + // Sleep_Cycles(OS_USEC_TO_CYCLES(usec)); +} + +void Sleep_Msec(u32 ms) { + // Sleep_Cycles((ms * OS_CPU_COUNTER) / 1000ULL); +} + +void Sleep_Sec(u32 sec) { + // Sleep_Cycles(sec * OS_CPU_COUNTER); +} diff --git a/mm/src/boot/O2/sprintf.c b/mm/src/boot/O2/sprintf.c new file mode 100644 index 000000000..bcb2a4384 --- /dev/null +++ b/mm/src/boot/O2/sprintf.c @@ -0,0 +1,33 @@ +#include "ultra64.h" +#include "libc/stdlib.h" +#include "libc/string.h" +#include <stdio.h> + +#if 0 +void* proutSprintf(void* dst, const char* fmt, size_t size) { + return (void*)((uintptr_t)memcpy(dst, fmt, size) + size); +} + +int vsprintf(char* dst, char* fmt, va_list args) { + int ans = _Printf(proutSprintf, dst, fmt, args); + if (ans > -1) { + dst[ans] = 0; + } + return ans; +} + +int sprintf(char* dst, const char* fmt, ...) { + int ans; + va_list args; + va_start(args, fmt); + + ans = _Printf(&proutSprintf, dst, fmt, args); + if (ans > -1) { + dst[ans] = 0; + } + + va_end(args); + + return ans; +} +#endif diff --git a/mm/src/boot/O2/system_heap.c b/mm/src/boot/O2/system_heap.c index 7ad21b6ae..c34129f12 100644 --- a/mm/src/boot/O2/system_heap.c +++ b/mm/src/boot/O2/system_heap.c @@ -2,11 +2,11 @@ * @file system_heap.c * * @note: - * Only SystemHeap_Init() is used, and is essentially just a wrapper for MallocInit(). + * Only SystemHeap_Init() is used, and is essentially just a wrapper for SystemArena_Init(). * */ #include "global.h" -#include "libc64/malloc.h" +#include "system_malloc.h" typedef void (*BlockFunc)(uintptr_t); typedef void (*BlockFunc1)(uintptr_t, u32); @@ -31,12 +31,12 @@ void* SystemHeap_Malloc(size_t size) { size = 1; } - return __osMalloc(&malloc_arena, size); + return __osMalloc(&gSystemArena, size); } void SystemHeap_Free(void* ptr) { if (ptr != NULL) { - __osFree(&malloc_arena, ptr); + __osFree(&gSystemArena, ptr); } } @@ -118,6 +118,6 @@ void SystemHeap_RunInits(void) { } void SystemHeap_Init(void* start, size_t size) { - MallocInit(start, size); + SystemArena_Init(start, size); SystemHeap_RunInits(); } diff --git a/mm/src/boot/O2/system_malloc.c b/mm/src/boot/O2/system_malloc.c new file mode 100644 index 000000000..e41c11df9 --- /dev/null +++ b/mm/src/boot/O2/system_malloc.c @@ -0,0 +1,52 @@ +#include "global.h" +#include "os_malloc.h" +#include <string.h> + +Arena gSystemArena; + +void* SystemArena_Malloc(size_t size) { + return __osMalloc(&gSystemArena, size); +} + +void* SystemArena_MallocR(size_t size) { + return __osMallocR(&gSystemArena, size); +} + +void* SystemArena_Realloc(void* oldPtr, size_t newSize) { + return __osRealloc(&gSystemArena, oldPtr, newSize); +} + +void SystemArena_Free(void* ptr) { + __osFree(&gSystemArena, ptr); +} + +void* SystemArena_Calloc(size_t num, size_t size) { + void* ptr; + size_t totalSize = num * size; + + ptr = __osMalloc(&gSystemArena, totalSize); + if (ptr != NULL) { + memset(ptr, 0, totalSize); + } + return ptr; +} + +void SystemArena_GetSizes(size_t* maxFreeBlock, size_t* bytesFree, size_t* bytesAllocated) { + __osGetSizes(&gSystemArena, maxFreeBlock, bytesFree, bytesAllocated); +} + +u32 SystemArena_CheckArena(void) { + return __osCheckArena(&gSystemArena); +} + +void SystemArena_Init(void* start, size_t size) { + __osMallocInit(&gSystemArena, start, size); +} + +void SystemArena_Cleanup(void) { + __osMallocCleanup(&gSystemArena); +} + +u8 SystemArena_IsInitialized(void) { + return __osMallocIsInitalized(&gSystemArena); +} |
