From 70941d8a9099316b574225a1b92eb2f2e3ac7670 Mon Sep 17 00:00:00 2001 From: TheUbMunster Date: Tue, 30 Sep 2025 00:08:17 -0600 Subject: [PATCH 1/5] LIST namespace, need to do tests still. --- include/ctr/list.h | 24 ++++++ include/ctr/test.h | 1 + rewrite/src/exe/list.c | 168 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 include/ctr/list.h create mode 100644 rewrite/src/exe/list.c diff --git a/include/ctr/list.h b/include/ctr/list.h new file mode 100644 index 000000000..60bd4cd34 --- /dev/null +++ b/include/ctr/list.h @@ -0,0 +1,24 @@ +#pragma once + +typedef struct Item +{ + struct Item* next; + struct Item* prev; +} Item; + +typedef struct LinkedList +{ + Item* first; + Item* last; + int count; +} LinkedList; + +void LIST_Clear(LinkedList* list); +void LIST_AddFront(LinkedList* list, Item* item); +void LIST_AddBack(LinkedList* list, Item* item); +void* LIST_GetNextItem(Item* item); +void* LIST_GetFirstItem(LinkedList* list); +Item* LIST_RemoveMember(LinkedList* L, Item* I); +Item* LIST_RemoveFront(LinkedList* L); +Item* LIST_RemoveBack(LinkedList* L); +void LIST_Init(LinkedList* L, Item* item, int itemSize, int numItems); \ No newline at end of file diff --git a/include/ctr/test.h b/include/ctr/test.h index 2cf6a28c0..0ad2e5901 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -29,6 +29,7 @@ force_inline void FlushCache() #define TEST_MATH_IMPL #define TEST_RNG_IMPL #define TEST_COLL_IMPL +#define TEST_LIST_IMPL #ifdef TEST_MATH_IMPL void TEST_MATH_Sin(u32 angle, s32 ret); diff --git a/rewrite/src/exe/list.c b/rewrite/src/exe/list.c new file mode 100644 index 000000000..f2f316591 --- /dev/null +++ b/rewrite/src/exe/list.c @@ -0,0 +1,168 @@ +#include + +void LIST_Clear(LinkedList* list) +{ + list->first = NULL; + list->last = NULL; + list->count = 0; +} + +void LIST_AddFront(LinkedList* list, Item* item) +{ + if (item == NULL) + { + return; + } + + item->prev = NULL; + Item* oldFirst = list->first; + item->next = oldFirst; + if (oldFirst == NULL) + { + list->last = item; + } + else + { + list->first->prev = item; + } + list->first = item; + list->count++; +} + +void LIST_AddBack(LinkedList* list, Item* item) +{ + if (item == NULL) + { + return; + } + + item->next = NULL; + Item* oldLast = list->last; + item->prev = oldLast; + if (oldLast == NULL) + { + list->first = item; + } + else + { + list->last->next = item; + } + list->last = item; + list->count++; +} + +void* LIST_GetNextItem(Item* item) +{ + return item->next; +} + +void* LIST_GetFirstItem(LinkedList* list) +{ + return list->first; +} + +Item* LIST_RemoveMember(LinkedList* list, Item* item) +{ + if (item == NULL || list->first == NULL) + { + return item; + } + + if (item->prev == NULL) + { + list->first = item->next; + } + else + { + item->prev->next = item->next; + } + if (item->next == NULL) + { + list->last = item->prev; + } + else + { + item->next->prev = item->prev; + } + list->count--; + item->next = NULL; + item->prev = NULL; + return item; +} + +Item* LIST_RemoveFront(LinkedList* list) +{ + Item* removedItem = list->first; + if (removedItem == NULL) + { + return removedItem; + } + + if (removedItem->prev == NULL) + { + list->first = removedItem->next; + } + else + { + removedItem->prev->next = removedItem->next; + } + if (removedItem->next == NULL) + { + list->last = removedItem->prev; + } + else + { + removedItem->next->prev = removedItem->prev; + } + list->count--; + removedItem->next = NULL; + removedItem->prev = NULL; + return removedItem; +} + +Item* LIST_RemoveBack(LinkedList* list) +{ + //for some reason, LIST_RemoveBack and LIST_RemoveFront aren't mirrors of each other. + struct Item* removedItem; + + Item* removedItem = list->last; + if (removedItem == NULL) + { + return removedItem; + } + if (list->first != NULL) + { + if (removedItem->prev == NULL) + { + list->first = removedItem->next; + } + else + { + removedItem->prev->next = removedItem->next; + } + if (removedItem->next == NULL) + { + list->last = removedItem->prev; + } + else + { + removedItem->next->prev = removedItem->prev; + } + list->count--; + } + removedItem->next = NULL; + removedItem->prev = NULL; + return removedItem; +} + +void LIST_Init(LinkedList* list, Item* item, int itemSize, int numItems) +{ + while (numItems > 0) + { + LIST_AddBack(list, item); + + numItems--; + + item = (Item*)((int)item + itemSize); + } +} \ No newline at end of file From 7f8763f89f95332bf59fe7e962e4fa07d24b50b6 Mon Sep 17 00:00:00 2001 From: TheUbMunster Date: Sat, 4 Oct 2025 19:44:56 -0600 Subject: [PATCH 2/5] Jitpool + feedback --- include/ctr/jitpool.h | 19 ++++++ include/ctr/list.h | 12 ++-- include/ctr/nd.h | 8 ++- rewrite/src/exe/jitpool.c | 43 +++++++++++++ rewrite/src/exe/list.c | 124 +++++++++++--------------------------- 5 files changed, 111 insertions(+), 95 deletions(-) create mode 100644 include/ctr/jitpool.h create mode 100644 rewrite/src/exe/jitpool.c diff --git a/include/ctr/jitpool.h b/include/ctr/jitpool.h new file mode 100644 index 000000000..d3f28791c --- /dev/null +++ b/include/ctr/jitpool.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +typedef struct JitPool +{ + LinkedList free; + LinkedList taken; + + s32 maxItems; + u32 itemSize; + s32 poolSize; + void* ptrPoolData; +} JitPool; + +void JitPool_Clear(JitPool* AP); +void JitPool_Init(JitPool* AP, s32 maxItems, s32 itemSize); +Item* JitPool_Add(JitPool* AP); +void JitPool_Remove(JitPool* AP, Item* item); \ No newline at end of file diff --git a/include/ctr/list.h b/include/ctr/list.h index 60bd4cd34..864ec117e 100644 --- a/include/ctr/list.h +++ b/include/ctr/list.h @@ -1,5 +1,7 @@ #pragma once +#include + typedef struct Item { struct Item* next; @@ -10,7 +12,7 @@ typedef struct LinkedList { Item* first; Item* last; - int count; + s32 count; } LinkedList; void LIST_Clear(LinkedList* list); @@ -18,7 +20,7 @@ void LIST_AddFront(LinkedList* list, Item* item); void LIST_AddBack(LinkedList* list, Item* item); void* LIST_GetNextItem(Item* item); void* LIST_GetFirstItem(LinkedList* list); -Item* LIST_RemoveMember(LinkedList* L, Item* I); -Item* LIST_RemoveFront(LinkedList* L); -Item* LIST_RemoveBack(LinkedList* L); -void LIST_Init(LinkedList* L, Item* item, int itemSize, int numItems); \ No newline at end of file +Item* LIST_RemoveMember(LinkedList* list, Item* item); +Item* LIST_RemoveFront(LinkedList* list); +Item* LIST_RemoveBack(LinkedList* list); +void LIST_Init(LinkedList* list, Item* item, s32 itemSize, s32 numItems); \ No newline at end of file diff --git a/include/ctr/nd.h b/include/ctr/nd.h index 45b9b5b92..ca540f019 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -36,4 +36,10 @@ void ND_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, con void ND_COLL_LoadVerticeData(CollDCache* cache); s32 ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); void ND_COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); -void ND_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache); \ No newline at end of file +void ND_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache); + +/* MEMPACK */ +void* ND_MEMPACK_AllocMem(s32 size); + +/* MISC */ +void* memset(void* dest, u8 val, s32 len); \ No newline at end of file diff --git a/rewrite/src/exe/jitpool.c b/rewrite/src/exe/jitpool.c new file mode 100644 index 000000000..efff502c7 --- /dev/null +++ b/rewrite/src/exe/jitpool.c @@ -0,0 +1,43 @@ +#include +#include + +void JitPool_Clear(JitPool* AP) +{ + Item* item = (Item*)AP->ptrPoolData; + LIST_Clear(&AP->free); + LIST_Clear(&AP->taken); + for (u32 i = 0; i < AP->maxItems; i++) + { + LIST_AddFront(AP->free, item); + //oddly, if AP->itemSize is not aligned to 4 bytes, this will align it DOWN to the nearest 4 byte boundary. + //will this cause clobbering? + item = (struct Item*)((u32)&item->next + (AP->itemSize & 0xfffffffc)); + } +} + +void JitPool_Init(JitPool* AP, s32 maxItems, s32 itemSize) +{ + memset((void*)AP, '\0', sizeof(JitPool)); + AP->maxItems = maxItems; + AP->itemSize = itemSize; + AP->poolSize = maxItems * itemSize; + void* poolData = ND_MEMPACK_AllocMem(maxItems * itemSize); + AP->ptrPoolData = poolData; + JitPool_Clear(AP); +} + +Item* JitPool_Add(JitPool* AP) +{ + Item* item = AP->free.first; + if (item != NULL) { + LIST_RemoveMember(&AP->free, item); + LIST_AddFront(&AP->taken, item); + } + return item; +} + +void JitPool_Remove(JitPool* AP, Item* item) +{ + LIST_RemoveMember(&AP->taken, item); + LIST_AddFront(AP->free, item); +} \ No newline at end of file diff --git a/rewrite/src/exe/list.c b/rewrite/src/exe/list.c index f2f316591..f101520c9 100644 --- a/rewrite/src/exe/list.c +++ b/rewrite/src/exe/list.c @@ -9,44 +9,30 @@ void LIST_Clear(LinkedList* list) void LIST_AddFront(LinkedList* list, Item* item) { - if (item == NULL) - { - return; - } + if (item == NULL) { return; } item->prev = NULL; Item* oldFirst = list->first; item->next = oldFirst; - if (oldFirst == NULL) - { - list->last = item; - } - else - { - list->first->prev = item; - } + + if (oldFirst == NULL) { list->last = item; } + else { list->first->prev = item; } + list->first = item; list->count++; } void LIST_AddBack(LinkedList* list, Item* item) { - if (item == NULL) - { - return; - } + if (item == NULL) { return; } item->next = NULL; Item* oldLast = list->last; item->prev = oldLast; - if (oldLast == NULL) - { - list->first = item; - } - else - { - list->last->next = item; - } + + if (oldLast == NULL) { list->first = item; } + else { list->last->next = item; } + list->last = item; list->count++; } @@ -63,27 +49,14 @@ void* LIST_GetFirstItem(LinkedList* list) Item* LIST_RemoveMember(LinkedList* list, Item* item) { - if (item == NULL || list->first == NULL) - { - return item; - } + if (item == NULL || list->first == NULL) { return item; } + + if (item->prev == NULL) { list->first = item->next; } + else { item->prev->next = item->next; } + + if (item->next == NULL) { list->last = item->prev; } + else { item->next->prev = item->prev; } - if (item->prev == NULL) - { - list->first = item->next; - } - else - { - item->prev->next = item->next; - } - if (item->next == NULL) - { - list->last = item->prev; - } - else - { - item->next->prev = item->prev; - } list->count--; item->next = NULL; item->prev = NULL; @@ -93,27 +66,14 @@ Item* LIST_RemoveMember(LinkedList* list, Item* item) Item* LIST_RemoveFront(LinkedList* list) { Item* removedItem = list->first; - if (removedItem == NULL) - { - return removedItem; - } + if (removedItem == NULL) { return removedItem; } + + if (removedItem->prev == NULL) { list->first = removedItem->next; } + else { removedItem->prev->next = removedItem->next; } + + if (removedItem->next == NULL) { list->last = removedItem->prev; } + else { removedItem->next->prev = removedItem->prev; } - if (removedItem->prev == NULL) - { - list->first = removedItem->next; - } - else - { - removedItem->prev->next = removedItem->next; - } - if (removedItem->next == NULL) - { - list->last = removedItem->prev; - } - else - { - removedItem->next->prev = removedItem->prev; - } list->count--; removedItem->next = NULL; removedItem->prev = NULL; @@ -126,43 +86,29 @@ Item* LIST_RemoveBack(LinkedList* list) struct Item* removedItem; Item* removedItem = list->last; - if (removedItem == NULL) - { - return removedItem; - } + if (removedItem == NULL) { return removedItem; } + if (list->first != NULL) { - if (removedItem->prev == NULL) - { - list->first = removedItem->next; - } - else - { - removedItem->prev->next = removedItem->next; - } - if (removedItem->next == NULL) - { - list->last = removedItem->prev; - } - else - { - removedItem->next->prev = removedItem->prev; - } + if (removedItem->prev == NULL) { list->first = removedItem->next; } + else { removedItem->prev->next = removedItem->next; } + + if (removedItem->next == NULL) { list->last = removedItem->prev; } + else { removedItem->next->prev = removedItem->prev; } list->count--; } + removedItem->next = NULL; removedItem->prev = NULL; return removedItem; } -void LIST_Init(LinkedList* list, Item* item, int itemSize, int numItems) +void LIST_Init(LinkedList* list, Item* item, s32 itemSize, s32 numItems) { - while (numItems > 0) + for(; numItems > 0; numItems--) { LIST_AddBack(list, item); - numItems--; - - item = (Item*)((int)item + itemSize); + item = (Item*)((s32)item + itemSize); } } \ No newline at end of file From 695f44bb9c09655cff96d7ccdd50bf8c8f3d118b Mon Sep 17 00:00:00 2001 From: TheUbMunster Date: Mon, 6 Oct 2025 00:13:03 -0600 Subject: [PATCH 3/5] testing changes, COLL still todo --- include/ctr/list.h | 5 +- include/ctr/nd.h | 4 +- include/ctr/test.h | 32 ++++++++++- include/ctr/test_backup.h | 15 +++++ rewrite/src/exe/coll.c | 3 + rewrite/src/exe/jitpool.c | 6 +- rewrite/src/exe/list.c | 2 - rewrite/src/exe/rng.c | 10 +++- rewrite/src/hooks/dll/load_decomp.c | 2 +- rewrite/src/tests/test.c | 22 ++++++++ rewrite/src/tests/test_backup.c | 86 +++++++++++++++++++++++++++++ rewrite/src/tests/test_rng.c | 51 ++++++++++++++--- 12 files changed, 219 insertions(+), 19 deletions(-) create mode 100644 include/ctr/test_backup.h create mode 100644 rewrite/src/tests/test_backup.c diff --git a/include/ctr/list.h b/include/ctr/list.h index 864ec117e..29635920f 100644 --- a/include/ctr/list.h +++ b/include/ctr/list.h @@ -23,4 +23,7 @@ void* LIST_GetFirstItem(LinkedList* list); Item* LIST_RemoveMember(LinkedList* list, Item* item); Item* LIST_RemoveFront(LinkedList* list); Item* LIST_RemoveBack(LinkedList* list); -void LIST_Init(LinkedList* list, Item* item, s32 itemSize, s32 numItems); \ No newline at end of file +void LIST_Init(LinkedList* list, Item* item, s32 itemSize, s32 numItems); + +//not a real ND function, just a helper macro. The value of an "Item" is the memory right after the Item struct. +#define LIST_GetItem(itemPtr) ((void*)(((Item*)itemPtr) + 1)) \ No newline at end of file diff --git a/include/ctr/nd.h b/include/ctr/nd.h index ca540f019..eb973f8f6 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -42,4 +42,6 @@ void ND_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache); void* ND_MEMPACK_AllocMem(s32 size); /* MISC */ -void* memset(void* dest, u8 val, s32 len); \ No newline at end of file +//TODO: ensure that the signedness of s32 for both of these are correct +void* memset(void* dest, u8 val, s32 len); +void* memcpy(void* dest, const void* src, s32 count); \ No newline at end of file diff --git a/include/ctr/test.h b/include/ctr/test.h index 0ad2e5901..a95f107dc 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -7,11 +7,14 @@ #include #include #include +#include extern const char* s_nameTestedFunc; void TEST_WRAPPER(); void LoadTestPatches(); +void TEST_Init(); +s32 TEST_Memcmp(const void* s1, const void* s2, u32 n); u32 PatchFunction_Beg(u32* index, const char* funcName); void PatchFunction_End(u32 index); u32 PrintSVectorDiff(const SVec3* expected, const SVec3* ret); @@ -25,11 +28,26 @@ force_inline void FlushCache() } #define BACKUP_ADDR 0x80400000 +#define TEST +#if defined(TEST) +#define DYNAMIC_ASSERT(expected, actual, msg) //TODO +#else +#define DYNAMIC_ASSERT(expected, actual, msg) +#endif + +#if defined(TEST) +#define STATIC_ASSERT //TODO +#else +#define STATIC_ASSERT +#endif + +#if defined(TEST) #define TEST_MATH_IMPL #define TEST_RNG_IMPL -#define TEST_COLL_IMPL +//#define TEST_COLL_IMPL #define TEST_LIST_IMPL +#endif #ifdef TEST_MATH_IMPL void TEST_MATH_Sin(u32 angle, s32 ret); @@ -52,10 +70,22 @@ force_inline void FlushCache() #endif #ifdef TEST_RNG_IMPL + typedef struct BDATA_RNG_Rand + { + u32 e_seed; //backup of 0x8008d424 + } BDATA_RNG_Rand; void BACKUP_RNG_Rand(); + void RESTORE_RNG_Rand(BDATA_RNG_Rand* restore); void TEST_RNG_Rand(); + + typedef struct BDATA_RNG_RandInt + { + RNGSeed e_gameTracker_seed; //backup of e_gameTracker->seed + } BDATA_RNG_RandInt; void BACKUP_RNG_RandInt(); + void RESTORE_RNG_RandInt(BDATA_RNG_RandInt* restore); void TEST_RNG_RandInt(u32 n, s32 ret); + void TEST_RNG_PseudoRand(u16 n, u16 ret); void TEST_RNG_Random(RNGSeed* seed, const RNGSeed* ret); #else diff --git a/include/ctr/test_backup.h b/include/ctr/test_backup.h new file mode 100644 index 000000000..d1494f5a3 --- /dev/null +++ b/include/ctr/test_backup.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#define BACKUP_STACK_BASE_ADDR ((u32)0x80400000u) +#define BACKUP_STACK_HEAD_PTR ((volatile u32*)(BACKUP_STACK_BASE_ADDR + 0x0)) +#define BACKUP_STACK_DATA_BEGIN ((u8*)(BACKUP_STACK_BASE_ADDR + 0x8)) +#define BACKUP_STACK_DATA_END ((u8*)(0x80500000u)) +#define BACKUP_ALIGN ((u32)4) + +void BACKUP_INIT(void); +void* BACKUP_PUSH(const void* src, u32 size); +void* BACKUP_PEEK(u32 depth, u32* out_size); +s32 BACKUP_POP(void); //add variable for "how many times to pop" +s32 BACKUP_POP_MULTIPLE(u32 count); \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index 1b374af07..fec09aaf3 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -294,6 +294,9 @@ static void _COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const Co } if ((distTriNextPos >= cache->inputHitRadius) || ((!triggerScript) && (distTriNextPos > distTriCurrPos))) { return; } + + + u32 crossedPlane = false; const SVec3 deltaPos = { .x = cache->inputNextPos.x - cache->collInput.quadblock.driverPos.x, diff --git a/rewrite/src/exe/jitpool.c b/rewrite/src/exe/jitpool.c index efff502c7..e74f68f20 100644 --- a/rewrite/src/exe/jitpool.c +++ b/rewrite/src/exe/jitpool.c @@ -6,9 +6,9 @@ void JitPool_Clear(JitPool* AP) Item* item = (Item*)AP->ptrPoolData; LIST_Clear(&AP->free); LIST_Clear(&AP->taken); - for (u32 i = 0; i < AP->maxItems; i++) + for (s32 i = 0; i < AP->maxItems; i++) { - LIST_AddFront(AP->free, item); + LIST_AddFront(&AP->free, item); //oddly, if AP->itemSize is not aligned to 4 bytes, this will align it DOWN to the nearest 4 byte boundary. //will this cause clobbering? item = (struct Item*)((u32)&item->next + (AP->itemSize & 0xfffffffc)); @@ -39,5 +39,5 @@ Item* JitPool_Add(JitPool* AP) void JitPool_Remove(JitPool* AP, Item* item) { LIST_RemoveMember(&AP->taken, item); - LIST_AddFront(AP->free, item); + LIST_AddFront(&AP->free, item); } \ No newline at end of file diff --git a/rewrite/src/exe/list.c b/rewrite/src/exe/list.c index f101520c9..f34c373d0 100644 --- a/rewrite/src/exe/list.c +++ b/rewrite/src/exe/list.c @@ -83,8 +83,6 @@ Item* LIST_RemoveFront(LinkedList* list) Item* LIST_RemoveBack(LinkedList* list) { //for some reason, LIST_RemoveBack and LIST_RemoveFront aren't mirrors of each other. - struct Item* removedItem; - Item* removedItem = list->last; if (removedItem == NULL) { return removedItem; } diff --git a/rewrite/src/exe/rng.c b/rewrite/src/exe/rng.c index d105f8bba..e45156fcd 100644 --- a/rewrite/src/exe/rng.c +++ b/rewrite/src/exe/rng.c @@ -9,8 +9,11 @@ /* Address: 0x8003ea28 */ u32 RNG_Rand() { - BACKUP_RNG_Rand(); + BACKUP_RNG_Rand(); //global state before + e_seed = (e_seed * RNG_MULT_FACTOR + RNG_INC_FACTOR) & 0xFFFF; + + BACKUP_RNG_Rand(); //global state after (result from decomp) TEST_RNG_Rand(); return e_seed; } @@ -18,9 +21,12 @@ u32 RNG_Rand() /* Address: 0x8003ea6c */ s32 RNG_RandInt(u32 n) { - BACKUP_RNG_RandInt(); + BACKUP_RNG_RandInt(); //global state before + const u32 rand = RNG_Random(&e_gameTracker->seed); const s32 ret = ((s32) ((rand & 0xFFFF) * n)) >> 16; + + BACKUP_RNG_RandInt(); //global state after (result from decomp) TEST_RNG_RandInt(n, ret); return ret; } diff --git a/rewrite/src/hooks/dll/load_decomp.c b/rewrite/src/hooks/dll/load_decomp.c index d5bdcfb46..8a7559c2d 100644 --- a/rewrite/src/hooks/dll/load_decomp.c +++ b/rewrite/src/hooks/dll/load_decomp.c @@ -14,7 +14,7 @@ void LoadDecomp() #ifndef REWRITE_PROFILER ND_LOAD_XnfFile("\\TESTS.BIN;1", testAddr, &dummy); - LoadTestPatches(); + TEST_Init(); #endif ND_LOAD_XnfFile("\\DECOMP.BIN;1", decompAddr, &dummy); diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index 071af047f..56f639831 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -1,4 +1,5 @@ #include +#include #define JMP(dest) ((((u32)dest) & 0x3FFFFFF) >> 2 | 0x8000000) #define NOP 0x0 @@ -34,6 +35,27 @@ FunctionPatch s_functions[] = const char* s_nameTestedFunc = nullptr; +void TEST_Init() +{ + BACKUP_INIT(); + LoadTestPatches(); +} + +s32 TEST_Memcmp(const void* s1, const void* s2, u32 n) +{ + const u8* p1 = (const u8*)s1; + const u8* p2 = (const u8*)s2; + for (u32 i = 0; i < n; i++) + { + if (p1[i] != p2[i]) + { + ND_printf("[%s] Test Failed (memcmp mismatch at byte %d):\nExpected: %02x\nResult: %02x\n", s_nameTestedFunc, i, p1[i], p2[i]); + return p1[i] - p2[i]; + } + } + return 0; +} + void LoadTestPatches() { const u32 funcCount = ARR_LEN(s_functions); diff --git a/rewrite/src/tests/test_backup.c b/rewrite/src/tests/test_backup.c new file mode 100644 index 000000000..a1872a0cc --- /dev/null +++ b/rewrite/src/tests/test_backup.c @@ -0,0 +1,86 @@ +#include +#include + +//this type isn't part of the public API +typedef struct FrameHeader { + u32 prev; + u32 size; +} FrameHeader; + +force_inline u32 align_up(u32 n, u32 a) +{ + u32 r = n % a; + return r ? (n + (a - r)) : n; +} + +force_inline u8* top_next_free_ptr(void) +{ + u32 head = *BACKUP_STACK_HEAD_PTR; + if (!head) { return BACKUP_STACK_DATA_BEGIN; } + + FrameHeader* h = (FrameHeader*)((u8*)0 + head); + u8* after = (u8*)(h + 1) + h->size; + u32 aligned = align_up((u32)(after - (u8*)0), BACKUP_ALIGN); + return (u8*)((u8*)0 + aligned); +} + +void BACKUP_INIT(void) +{ + *BACKUP_STACK_HEAD_PTR = 0; +} + +/* PUSH: + - If src == NULL: reserves 'size' bytes; returns writable payload pointer. + - If src != NULL: copies 'size' bytes from src into payload; returns payload pointer. + Returns NULL on OOM. */ +void* BACKUP_PUSH(const void* src, u32 size) +{ + u8* where = top_next_free_ptr(); + u32 need = align_up((u32)sizeof(FrameHeader) + size, BACKUP_ALIGN); + + if (where + need > BACKUP_STACK_DATA_END) { return 0; } + + FrameHeader* h = (FrameHeader*)where; + h->prev = *BACKUP_STACK_HEAD_PTR; + h->size = size; + + void* payload = (void*)(h + 1); + if (src && size) { memcpy(payload, src, (s32)size); } + + *BACKUP_STACK_HEAD_PTR = (u32)(where - (u8*)0); + return payload; +} + +/* PEEK depth n (0 = top). Returns payload pointer or NULL if out-of-range. + Optionally writes size to *out_size. */ +void* BACKUP_PEEK(u32 depth, u32* out_size) +{ + u32 addr = *BACKUP_STACK_HEAD_PTR; + FrameHeader* h = (FrameHeader*)((u8*)0 + addr); + + while (h && depth--) { + h = (FrameHeader*)((u8*)0 + h->prev); + } + if (!h) { return 0; } + + if (out_size) { *out_size = h->size; } + return (void*)(h + 1); +} + +/* POP top frame. Returns 0 on success, nonzero if empty. */ +s32 BACKUP_POP(void) +{ + u32 head = *BACKUP_STACK_HEAD_PTR; + if (!head) { return -1; } + + FrameHeader* h = (FrameHeader*)((u8*)0 + head); + *BACKUP_STACK_HEAD_PTR = h->prev; + return 0; +} + +s32 BACKUP_POP_MULTIPLE(u32 count) +{ + for (u32 i = 0; i < count; i++) { + if (BACKUP_POP() != 0) { return -1; } + } +} \ No newline at end of file diff --git a/rewrite/src/tests/test_rng.c b/rewrite/src/tests/test_rng.c index 6f7d5434a..de15ecad3 100644 --- a/rewrite/src/tests/test_rng.c +++ b/rewrite/src/tests/test_rng.c @@ -4,31 +4,66 @@ void BACKUP_RNG_Rand() { - u32* seedAddr = (u32*) BACKUP_ADDR; - *seedAddr = e_seed; + BDATA_RNG_Rand backup = { + .e_seed = e_seed + }; + BACKUP_PUSH(&backup, sizeof(backup)); +} + +void RESTORE_RNG_Rand(BDATA_RNG_Rand* restore) +{ + e_seed = restore->e_seed; } void TEST_RNG_Rand() { const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_Rand), "RNG_Rand"); - const u32 ret = e_seed; - e_seed = *(u32*) BACKUP_ADDR; + + BDATA_RNG_Rand* before = (BDATA_RNG_Rand*)BACKUP_PEEK(1, NULL); + BDATA_RNG_Rand* resultFromDecomp = (BDATA_RNG_Rand*)BACKUP_PEEK(0, NULL); + RESTORE_RNG_Rand(before); ND_RNG_Rand(); - if (e_seed != ret) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, e_seed, ret); } + BACKUP_RNG_Rand(); + BDATA_RNG_Rand* resultFromND = (BDATA_RNG_Rand*)BACKUP_PEEK(0, NULL); + + bool failedGlobalState = TEST_Memcmp(resultFromDecomp, resultFromND, sizeof(BDATA_RNG_Rand)); + + BACKUP_POP_MULTIPLE(3); + + if (failedGlobalState) { ND_printf("[%s] Test Failed (global state mismatch)\n", s_nameTestedFunc); } + if (resultFromND->e_seed != resultFromDecomp->e_seed) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, resultFromND->e_seed, resultFromDecomp->e_seed); } PatchFunction_End(index); } void BACKUP_RNG_RandInt() { - RNGSeed* seedAddr = (RNGSeed*) BACKUP_ADDR; - *seedAddr = e_gameTracker->seed; + BDATA_RNG_RandInt backup = { + .e_gameTracker_seed = e_gameTracker->seed + }; + BACKUP_PUSH(&backup, sizeof(backup)); +} + +void RESTORE_RNG_RandInt(BDATA_RNG_RandInt* restore) +{ + e_gameTracker->seed = restore->e_gameTracker_seed; } void TEST_RNG_RandInt(u32 n, s32 ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_RandInt), "RNG_RandInt"); - e_gameTracker->seed = *(RNGSeed*) BACKUP_ADDR; + + BDATA_RNG_RandInt* before = (BDATA_RNG_RandInt*)BACKUP_PEEK(1, NULL); + BDATA_RNG_RandInt* resultFromDecomp = (BDATA_RNG_RandInt*)BACKUP_PEEK(0, NULL); + RESTORE_RNG_RandInt(before); const s32 expected = ND_RNG_RandInt(n); + BACKUP_RNG_RandInt(); + BDATA_RNG_RandInt* resultFromND = (BDATA_RNG_RandInt*)BACKUP_PEEK(0, NULL); + + bool failedGlobalState = TEST_Memcmp(resultFromDecomp, resultFromND, sizeof(BDATA_RNG_RandInt)); + + BACKUP_POP_MULTIPLE(3); + + if (failedGlobalState) { ND_printf("[%s] Test Failed (global state mismatch)\n", s_nameTestedFunc); } if (expected != ret) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, expected, ret); } PatchFunction_End(index); } From 977c32394a7cc02eaaaaa1bb5ce8954ed7dedfb5 Mon Sep 17 00:00:00 2001 From: TheUbMunster Date: Tue, 7 Oct 2025 01:42:00 -0600 Subject: [PATCH 4/5] Finished swapping tests to the stack system. --- include/ctr/test.h | 42 ++++++++++++-- rewrite/src/exe/coll.c | 50 ++++++++--------- rewrite/src/tests/test_coll.c | 100 +++++++++++++++++++++++++++++++--- 3 files changed, 151 insertions(+), 41 deletions(-) diff --git a/include/ctr/test.h b/include/ctr/test.h index a95f107dc..6177b27d6 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -27,7 +27,6 @@ force_inline void FlushCache() ((void (*)())0xa0)(); } -#define BACKUP_ADDR 0x80400000 #define TEST #if defined(TEST) @@ -45,7 +44,7 @@ force_inline void FlushCache() #if defined(TEST) #define TEST_MATH_IMPL #define TEST_RNG_IMPL -//#define TEST_COLL_IMPL +#define TEST_COLL_IMPL #define TEST_LIST_IMPL #endif @@ -90,8 +89,10 @@ force_inline void FlushCache() void TEST_RNG_Random(RNGSeed* seed, const RNGSeed* ret); #else #define BACKUP_RNG_Rand() + #define RESTORE_RNG_Rand(restore) #define TEST_RNG_Rand() #define BACKUP_RNG_RandInt() + #define RESTORE_RNG_RandInt(restore) #define TEST_RNG_RandInt(n, ret) #define TEST_RNG_PseudoRand(n, ret) #define TEST_RNG_Random(seed, ret) @@ -101,11 +102,40 @@ force_inline void FlushCache() void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* point, const SVec3* ret); void TEST_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollVertex* ret); void TEST_COLL_LoadVerticeData(CollDCache* cache); - void TEST_COLL_LoadQuadblockData_LowLOD(CollDCache* cache, const Quadblock* quadblock, const CollDCache* ret); - void TEST_COLL_LoadQuadblockData_HighLOD(CollDCache* cache, const Quadblock* quadblock, const CollDCache* ret); + + typedef struct BDATA_COLL_LoadQuadblockData_LowLOD + { + CollDCache cache; //backup of *cache + } BDATA_COLL_LoadQuadblockData_LowLOD; + void BACKUP_COLL_LoadQuadblockData_LowLOD(CollDCache* cache); + void RESTORE_COLL_LoadQuadblockData_LowLOD(BDATA_COLL_LoadQuadblockData_LowLOD* restore, CollDCache* cache); + void TEST_COLL_LoadQuadblockData_LowLOD(const Quadblock* quadblock, CollDCache* cache); + + typedef struct BDATA_COLL_LoadQuadblockData_HighLOD + { + CollDCache cache; //backup of *cache + } BDATA_COLL_LoadQuadblockData_HighLOD; + void BACKUP_COLL_LoadQuadblockData_HighLOD(CollDCache* cache); + void RESTORE_COLL_LoadQuadblockData_HighLOD(BDATA_COLL_LoadQuadblockData_HighLOD* restore, CollDCache* cache); + void TEST_COLL_LoadQuadblockData_HighLOD(const Quadblock* quadblock, CollDCache* cache); + void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret); - void TEST_COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollDCache* ret); - void TEST_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache, const CollDCache* ret); + + typedef struct BDATA_COLL_TestTriangle + { + CollDCache cache; //backup of *cache + } BDATA_COLL_TestTriangle; + void BACKUP_COLL_TestTriangle(CollDCache* cache); + void RESTORE_COLL_TestTriangle(BDATA_COLL_TestTriangle* restore, CollDCache* cache); + void TEST_COLL_TestTriangle(const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, CollDCache* cache); + + typedef struct BDATA_COLL_TestLeaf_Quadblock + { + CollDCache cache; //backup of *cache + } BDATA_COLL_TestLeaf_Quadblock; + void BACKUP_COLL_TestLeaf_Quadblock(CollDCache* cache); + void RESTORE_COLL_TestLeaf_Quadblock(BDATA_COLL_TestLeaf_Quadblock* restore, CollDCache* cache); + void TEST_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache); #else #define TEST_COLL_ProjectPointToEdge(out, v1, v2, point) #define TEST_COLL_CalculateTrianglePlane(cache, v1, v2, v3, ret) diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index fec09aaf3..311e0c8ed 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -101,11 +101,12 @@ static void _COLL_LoadQuadblockData_LowLOD(CollDCache* cache, const Quadblock* q static void COLL_LoadQuadblockData_LowLOD(CollDCache* cache, const Quadblock* quadblock) { -#ifdef TEST_COLL_IMPL - *(CollDCache*)(BACKUP_ADDR) = *cache; -#endif + BACKUP_COLL_LoadQuadblockData_LowLOD(cache); //global state before + _COLL_LoadQuadblockData_LowLOD(cache, quadblock); - TEST_COLL_LoadQuadblockData_LowLOD((CollDCache*)(BACKUP_ADDR), quadblock, cache); + + BACKUP_COLL_LoadQuadblockData_LowLOD(cache); //global state after (result from decomp) + TEST_COLL_LoadQuadblockData_LowLOD(quadblock, cache); } /* Address: 0x8001f6f0 */ @@ -137,11 +138,12 @@ static void _COLL_LoadQuadblockData_HighLOD(CollDCache* cache, const Quadblock* static void COLL_LoadQuadblockData_HighLOD(CollDCache* cache, const Quadblock* quadblock) { -#ifdef TEST_COLL_IMPL - *(CollDCache*)(BACKUP_ADDR) = *cache; -#endif + BACKUP_COLL_LoadQuadblockData_HighLOD(cache); //global state before + _COLL_LoadQuadblockData_HighLOD(cache, quadblock); - TEST_COLL_LoadQuadblockData_HighLOD((CollDCache*)(BACKUP_ADDR), quadblock, cache); + + BACKUP_COLL_LoadQuadblockData_HighLOD(cache); //global state after (result from decomp) + TEST_COLL_LoadQuadblockData_HighLOD(quadblock, cache); } /* Address: 0x8001f928 */ @@ -385,12 +387,12 @@ static void _COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const Co static void COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3) { -#ifdef TEST_COLL_IMPL - const u32 backupAddr = BACKUP_ADDR + sizeof(CollDCache); - *(CollDCache*)(backupAddr) = *cache; -#endif - _COLL_TestTriangle(cache, v1, v2, v3); - TEST_COLL_TestTriangle((CollDCache*)(backupAddr), v1, v2, v3, cache); + BACKUP_COLL_TestTriangle(cache); //global state before + + _COLL_TestTriangle(cache, v1, v2, v3); + + BACKUP_COLL_TestTriangle(cache); //global state after (result from decomp) + TEST_COLL_TestTriangle(v1, v2, v3, cache); } /* Address: 0x80020064 */ @@ -453,19 +455,13 @@ static void _COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cac void COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache) { -#ifdef TEST_COLL_IMPL - *(CollDCache*)(BACKUP_ADDR) = *cache; -#endif - _COLL_TestLeaf_Quadblock(quadblock, cache); -#ifdef TEST_COLL_IMPL - const u32 retAddr = BACKUP_ADDR + sizeof(CollDCache); - *(CollDCache*)(retAddr) = *cache; - *cache = *(CollDCache*)(BACKUP_ADDR); -#endif - TEST_COLL_TestLeaf_Quadblock(quadblock, cache, (CollDCache*)(retAddr)); -#ifdef TEST_COLL_IMPL - *cache = *(CollDCache*)(retAddr); -#endif + BACKUP_COLL_TestLeaf_Quadblock(cache); //global state before + + _COLL_TestLeaf_Quadblock(quadblock, cache); + + BACKUP_COLL_TestLeaf_Quadblock(cache); //global state after (result from decomp) + TEST_COLL_TestLeaf_Quadblock(quadblock, cache); + /* This is a hand written assembly function that breaks the ABI, and some callers expect the argument registers to be untouched */ __asm__ volatile("move $t9, %0" : : "r"((u32)quadblock)); diff --git a/rewrite/src/tests/test_coll.c b/rewrite/src/tests/test_coll.c index 5172951b8..5a2358f3c 100644 --- a/rewrite/src/tests/test_coll.c +++ b/rewrite/src/tests/test_coll.c @@ -70,23 +70,65 @@ void TEST_COLL_LoadVerticeData(CollDCache* cache) PatchFunction_End(index); } -void TEST_COLL_LoadQuadblockData_LowLOD(CollDCache* cache, const Quadblock* quadblock, const CollDCache* ret) +void BACKUP_COLL_LoadQuadblockData_LowLOD(CollDCache* cache) +{ + BDATA_COLL_LoadQuadblockData_LowLOD backup = {}; + backup.cache = *cache; + BACKUP_PUSH(&backup, sizeof(backup)); +} + +void RESTORE_COLL_LoadQuadblockData_LowLOD(BDATA_COLL_LoadQuadblockData_LowLOD* restore, CollDCache* cache) +{ + *cache = restore->cache; +} + +void TEST_COLL_LoadQuadblockData_LowLOD(const Quadblock* quadblock, CollDCache* cache) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_LoadQuadblockData_LowLOD), "COLL_LoadQuadblockData_LowLOD"); + + BDATA_COLL_LoadQuadblockData_LowLOD* before = (BDATA_COLL_LoadQuadblockData_LowLOD*)BACKUP_PEEK(1, NULL); + BDATA_COLL_LoadQuadblockData_LowLOD* resultFromDecomp = (BDATA_COLL_LoadQuadblockData_LowLOD*)BACKUP_PEEK(0, NULL); + RESTORE_COLL_LoadQuadblockData_LowLOD(before, cache); typedef void (*Func)(CollDCache* cache, const Quadblock* quadblock); Func func = (Func) TEST_WRAPPER; func(cache, quadblock); - PrintDCacheDiff(cache, ret); + BACKUP_COLL_LoadQuadblockData_LowLOD(cache); + BDATA_COLL_LoadQuadblockData_LowLOD* resultFromND = (BDATA_COLL_LoadQuadblockData_LowLOD*)BACKUP_PEEK(0, NULL); + + BACKUP_POP_MULTIPLE(3); + + PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); PatchFunction_End(index); } -void TEST_COLL_LoadQuadblockData_HighLOD(CollDCache* cache, const Quadblock* quadblock, const CollDCache* ret) +void BACKUP_COLL_LoadQuadblockData_HighLOD(CollDCache* cache) +{ + BDATA_COLL_LoadQuadblockData_HighLOD backup = {}; + backup.cache = *cache; + BACKUP_PUSH(&backup, sizeof(backup)); +} + +void RESTORE_COLL_LoadQuadblockData_HighLOD(BDATA_COLL_LoadQuadblockData_HighLOD* restore, CollDCache* cache) +{ + *cache = restore->cache; +} + +void TEST_COLL_LoadQuadblockData_HighLOD(const Quadblock* quadblock, CollDCache* cache) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_LoadQuadblockData_HighLOD), "COLL_LoadQuadblockData_HighLOD"); + + BDATA_COLL_LoadQuadblockData_HighLOD* before = (BDATA_COLL_LoadQuadblockData_HighLOD*)BACKUP_PEEK(1, NULL); + BDATA_COLL_LoadQuadblockData_HighLOD* resultFromDecomp = (BDATA_COLL_LoadQuadblockData_HighLOD*)BACKUP_PEEK(0, NULL); + RESTORE_COLL_LoadQuadblockData_HighLOD(before, cache); typedef void (*Func)(CollDCache* cache, const Quadblock* quadblock); Func func = (Func) TEST_WRAPPER; func(cache, quadblock); - PrintDCacheDiff(cache, ret); + BACKUP_COLL_LoadQuadblockData_HighLOD(cache); + BDATA_COLL_LoadQuadblockData_HighLOD* resultFromND = (BDATA_COLL_LoadQuadblockData_HighLOD*)BACKUP_PEEK(0, NULL); + + BACKUP_POP_MULTIPLE(3); + + PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); PatchFunction_End(index); } @@ -101,23 +143,65 @@ void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVe PatchFunction_End(index); } -void TEST_COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollDCache* ret) +void BACKUP_COLL_TestTriangle(CollDCache* cache) +{ + BDATA_COLL_TestTriangle backup = {}; + backup.cache = *cache; + BACKUP_PUSH(&backup, sizeof(backup)); +} + +void RESTORE_COLL_TestTriangle(BDATA_COLL_TestTriangle* restore, CollDCache* cache) +{ + *cache = restore->cache; +} + +void TEST_COLL_TestTriangle(const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, CollDCache* cache) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_TestTriangle), "COLL_TestTriangle"); + + BDATA_COLL_TestTriangle* before = (BDATA_COLL_TestTriangle*)BACKUP_PEEK(1, NULL); + BDATA_COLL_TestTriangle* resultFromDecomp = (BDATA_COLL_TestTriangle*)BACKUP_PEEK(0, NULL); + RESTORE_COLL_TestTriangle(before, cache); typedef void (*Func)(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); Func func = (Func) TEST_WRAPPER; func(cache, v1, v2, v3); - PrintDCacheDiff(cache, ret); + BACKUP_COLL_TestTriangle(cache); + BDATA_COLL_TestTriangle* resultFromND = (BDATA_COLL_TestTriangle*)BACKUP_PEEK(0, NULL); + + BACKUP_POP_MULTIPLE(3); + + PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); PatchFunction_End(index); } -void TEST_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache, const CollDCache* ret) +void BACKUP_COLL_TestLeaf_Quadblock(CollDCache* cache) +{ + BDATA_COLL_TestLeaf_Quadblock backup = {}; + backup.cache = *cache; + BACKUP_PUSH(&backup, sizeof(backup)); +} + +void RESTORE_COLL_TestLeaf_Quadblock(BDATA_COLL_TestLeaf_Quadblock* restore, CollDCache* cache) +{ + *cache = restore->cache; +} + +void TEST_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_TestLeaf_Quadblock), "COLL_TestLeaf_Quadblock"); + + BDATA_COLL_TestLeaf_Quadblock* before = (BDATA_COLL_TestLeaf_Quadblock*)BACKUP_PEEK(1, NULL); + BDATA_COLL_TestLeaf_Quadblock* resultFromDecomp = (BDATA_COLL_TestLeaf_Quadblock*)BACKUP_PEEK(0, NULL); + RESTORE_COLL_TestLeaf_Quadblock(before, cache); typedef void (*Func)(const Quadblock* quadblock, CollDCache* cache); Func func = (Func) TEST_WRAPPER; func(quadblock, cache); - PrintDCacheDiff(cache, ret); + BACKUP_COLL_TestLeaf_Quadblock(cache); + BDATA_COLL_TestLeaf_Quadblock* resultFromND = (BDATA_COLL_TestLeaf_Quadblock*)BACKUP_PEEK(0, NULL); + + BACKUP_POP_MULTIPLE(3); + + PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); PatchFunction_End(index); } From 6c56cca8ebbad0e7dd67ad8c54421936ac8628e2 Mon Sep 17 00:00:00 2001 From: TheUbMunster Date: Wed, 22 Oct 2025 17:23:00 -0600 Subject: [PATCH 5/5] Final adjustments for tests? --- include/ctr/nd.h | 3 ++ include/ctr/test.h | 21 ++++++++++--- rewrite/src/tests/test.c | 23 +++++++-------- rewrite/src/tests/test_coll.c | 45 +++++++++++++++------------- rewrite/src/tests/test_list.c | 55 +++++++++++++++++++++++++++++++++++ rewrite/src/tests/test_math.c | 24 ++++++++++++--- rewrite/src/tests/test_rng.c | 8 +++++ 7 files changed, 137 insertions(+), 42 deletions(-) create mode 100644 rewrite/src/tests/test_list.c diff --git a/include/ctr/nd.h b/include/ctr/nd.h index eb973f8f6..e07944904 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -38,6 +38,9 @@ s32 ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVerte void ND_COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); void ND_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache); +/* LIST */ +void ND_LIST_Init(LinkedList* list, Item* item, s32 itemSize, s32 numItems); + /* MEMPACK */ void* ND_MEMPACK_AllocMem(s32 size); diff --git a/include/ctr/test.h b/include/ctr/test.h index 6177b27d6..ba630b8df 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -7,18 +7,19 @@ #include #include #include +#include #include extern const char* s_nameTestedFunc; void TEST_WRAPPER(); -void LoadTestPatches(); +void TEST_LoadPatches(); void TEST_Init(); -s32 TEST_Memcmp(const void* s1, const void* s2, u32 n); +bool TEST_Memcmp(const void* expected, const void* actual, u32 n); u32 PatchFunction_Beg(u32* index, const char* funcName); void PatchFunction_End(u32 index); -u32 PrintSVectorDiff(const SVec3* expected, const SVec3* ret); -u32 PrintMatrixDiff(const Matrix* expected, const Matrix* ret, u32 cmpTrans); +u32 TEST_PrintSVectorDiff(const SVec3* expected, const SVec3* ret); +u32 TEST_PrintMatrixDiff(const Matrix* expected, const Matrix* ret, u32 cmpTrans); force_inline void FlushCache() { @@ -145,4 +146,16 @@ force_inline void FlushCache() #define TEST_COLL_BarycentricTest(t, v1, v2, v3, pos, ret) #define TEST_COLL_TestTriangle(cache, v1, v2, v3, ret) #define TEST_COLL_TestLeaf_Quadblock(quadblock, cache, ret) +#endif + +#ifdef TEST_LIST_IMPL + typedef struct BDATA_LIST_Init + { + void asdf; + } BDATA_LIST_Init; + void BACKUP_LIST_Init(const void* source); + void RESTORE_LIST_Init(BDATA_LIST_Init* restore, void* destination); + void TEST_LIST_Init(LinkedList* list, Item* item, s32 itemSize, s32 numItems); +#else + #define TEST_LIST_Init(list, item, itemSize, numItems) #endif \ No newline at end of file diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index 56f639831..f5cc79eaa 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -38,25 +38,22 @@ const char* s_nameTestedFunc = nullptr; void TEST_Init() { BACKUP_INIT(); - LoadTestPatches(); + TEST_LoadPatches(); } -s32 TEST_Memcmp(const void* s1, const void* s2, u32 n) +bool TEST_Memcmp(const void* expected, const void* actual, u32 n) { - const u8* p1 = (const u8*)s1; - const u8* p2 = (const u8*)s2; + bool failed = false; + const u8* pExpected = (const u8*)expected; + const u8* pActual = (const u8*)actual; for (u32 i = 0; i < n; i++) { - if (p1[i] != p2[i]) - { - ND_printf("[%s] Test Failed (memcmp mismatch at byte %d):\nExpected: %02x\nResult: %02x\n", s_nameTestedFunc, i, p1[i], p2[i]); - return p1[i] - p2[i]; - } + if (pExpected[i] != pActual[i]) { ND_printf("[%s] Test Failed:\nOffset %x: %d, got: %d\n", s_nameTestedFunc, i, (u32)pExpected[i], (u32)pActual[i]); failed = true; } } - return 0; + return failed; } -void LoadTestPatches() +void TEST_LoadPatches() { const u32 funcCount = ARR_LEN(s_functions); for (u32 i = 0; i < funcCount; i++) @@ -101,7 +98,7 @@ void PatchFunction_End(u32 index) FlushCache(); } -u32 PrintSVectorDiff(const SVec3* expected, const SVec3* ret) +u32 TEST_PrintSVectorDiff(const SVec3* expected, const SVec3* ret) { u32 failed = 0; for (u32 i = 0; i < 3; i++) @@ -115,7 +112,7 @@ u32 PrintSVectorDiff(const SVec3* expected, const SVec3* ret) return failed; } -u32 PrintMatrixDiff(const Matrix* expected, const Matrix* ret, u32 cmpTrans) +u32 TEST_PrintMatrixDiff(const Matrix* expected, const Matrix* ret, u32 cmpTrans) { u32 failed = 0; for (u32 i = 0; i < 3; i++) diff --git a/rewrite/src/tests/test_coll.c b/rewrite/src/tests/test_coll.c index 5a2358f3c..936d1fca6 100644 --- a/rewrite/src/tests/test_coll.c +++ b/rewrite/src/tests/test_coll.c @@ -2,19 +2,7 @@ #ifdef TEST_COLL_IMPL -static u32 PrintDCacheDiff(const CollDCache* expected, const CollDCache* ret) -{ - u32 failed = false; - const u8* pExpected = (const u8*) expected; - const u8* pRet = (const u8*) ret; - const u32 len = sizeof(CollDCache); - for (u32 i = 0; i < len; i++) - { - if (pExpected[i] != pRet[i]) { ND_printf("[%s] Test Failed:\nOffset %x: %d, got: %d\n", s_nameTestedFunc, i, (u32) pExpected[i], (u32) pRet[i]); failed = true; } - } - return failed; -} - +#pragma region COLL_ProjectPointToEdge void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* point, const SVec3* ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_ProjectPointToEdge), "COLL_ProjectPointToEdge"); @@ -22,22 +10,26 @@ void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* typedef void (*Func)(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); Func func = (Func) TEST_WRAPPER; func(&expected, v1, v2, point); - PrintSVectorDiff(&expected, ret); + TEST_PrintSVectorDiff(&expected, ret); PatchFunction_End(index); } +#pragma endregion +#pragma region COLL_CalculateTrianglePlane void TEST_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollVertex* ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_CalculateTrianglePlane), "COLL_CalculateTrianglePlane"); typedef void (*Func)(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3); Func func = (Func) TEST_WRAPPER; func(cache, v1, v2, v3); - PrintSVectorDiff(&v1->triNormal, &ret->triNormal); + TEST_PrintSVectorDiff(&v1->triNormal, &ret->triNormal); if (v1->planeDist != ret->planeDist) { ND_printf("[%s] Test Failed:\nDist: %d\nResult: %d\n", s_nameTestedFunc, v1->planeDist, ret->planeDist); } if (v1->normalDominantAxis != ret->normalDominantAxis) { ND_printf("[%s] Test Failed:\nAxis: %d\nResult: %d\n", s_nameTestedFunc, v1->normalDominantAxis, ret->normalDominantAxis); } PatchFunction_End(index); } +#pragma endregion +#pragma region COLL_LoadVerticeData void TEST_COLL_LoadVerticeData(CollDCache* cache) { CollVertex vertices[NUM_VERTICES_QUADBLOCK]; @@ -59,7 +51,7 @@ void TEST_COLL_LoadVerticeData(CollDCache* cache) func(cache); for (u32 i = 0; i < NUM_VERTICES_QUADBLOCK; i++) { - PrintSVectorDiff(&cache->quadblockCollVertices[i].pos, &vertices[i].pos); + TEST_PrintSVectorDiff(&cache->quadblockCollVertices[i].pos, &vertices[i].pos); if (cache->quadblockCollVertices[i].levVertex != vertices[i].levVertex) { ND_printf("[%s] Test Failed: levVertex at index %d\n", s_nameTestedFunc, i); @@ -69,7 +61,9 @@ void TEST_COLL_LoadVerticeData(CollDCache* cache) if (cache->quadblockFourthIndex != fourthIndex) { ND_printf("[%s] Test Failed:\nfourthIndex: %d\nResult:%d\n", s_nameTestedFunc, cache->quadblockFourthIndex, fourthIndex);} PatchFunction_End(index); } +#pragma endregion +#pragma region COLL_LoadQuadblockData_LowLOD void BACKUP_COLL_LoadQuadblockData_LowLOD(CollDCache* cache) { BDATA_COLL_LoadQuadblockData_LowLOD backup = {}; @@ -97,10 +91,12 @@ void TEST_COLL_LoadQuadblockData_LowLOD(const Quadblock* quadblock, CollDCache* BACKUP_POP_MULTIPLE(3); - PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); + TEST_Memcmp(&resultFromND->cache, &resultFromDecomp->cache, sizeof(resultFromND->cache)); PatchFunction_End(index); } +#pragma endregion +#pragma region COLL_LoadQuadblockData_HighLOD void BACKUP_COLL_LoadQuadblockData_HighLOD(CollDCache* cache) { BDATA_COLL_LoadQuadblockData_HighLOD backup = {}; @@ -128,21 +124,25 @@ void TEST_COLL_LoadQuadblockData_HighLOD(const Quadblock* quadblock, CollDCache* BACKUP_POP_MULTIPLE(3); - PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); + TEST_Memcmp(&resultFromND->cache, &resultFromDecomp->cache, sizeof(resultFromND->cache)); PatchFunction_End(index); } +#pragma endregion +#pragma region COLL_BarycentricTest void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_BarycentricTest), "COLL_BarycentricTest"); typedef s32 (*Func)(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); Func func = (Func) TEST_WRAPPER; const s32 expected = func(t, v1, v2, v3); - PrintSVectorDiff(&t->pos, pos); + TEST_PrintSVectorDiff(&t->pos, pos); if (expected != ret) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, expected, ret); } PatchFunction_End(index); } +#pragma endregion +#pragma region COLL_TestTriangle void BACKUP_COLL_TestTriangle(CollDCache* cache) { BDATA_COLL_TestTriangle backup = {}; @@ -170,10 +170,12 @@ void TEST_COLL_TestTriangle(const CollVertex* v1, const CollVertex* v2, const Co BACKUP_POP_MULTIPLE(3); - PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); + TEST_Memcmp(&resultFromND->cache, &resultFromDecomp->cache, sizeof(resultFromND->cache)); PatchFunction_End(index); } +#pragma endregion +#pragma region COLL_TestLeaf_Quadblock void BACKUP_COLL_TestLeaf_Quadblock(CollDCache* cache) { BDATA_COLL_TestLeaf_Quadblock backup = {}; @@ -201,8 +203,9 @@ void TEST_COLL_TestLeaf_Quadblock(const Quadblock* quadblock, CollDCache* cache) BACKUP_POP_MULTIPLE(3); - PrintDCacheDiff(&resultFromND->cache, &resultFromDecomp->cache); + TEST_Memcmp(&resultFromND->cache, &resultFromDecomp->cache, sizeof(resultFromND->cache)); PatchFunction_End(index); } +#pragma endregion #endif // TEST_COLL_IMPL \ No newline at end of file diff --git a/rewrite/src/tests/test_list.c b/rewrite/src/tests/test_list.c new file mode 100644 index 000000000..320c6d4cd --- /dev/null +++ b/rewrite/src/tests/test_list.c @@ -0,0 +1,55 @@ +#include + +#ifdef TEST_LIST_IMPL + +#pragma region LIST_Init +void BACKUP_RNG_Rand() +{ + BDATA_RNG_Rand backup = { + .e_seed = e_seed + }; + BACKUP_PUSH(&backup, sizeof(backup)); +} + +void RESTORE_RNG_Rand(BDATA_RNG_Rand* restore) +{ + e_seed = restore->e_seed; +} + +void TEST_RNG_Rand() +{ + const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_Rand), "RNG_Rand"); + + BDATA_RNG_Rand* before = (BDATA_RNG_Rand*)BACKUP_PEEK(1, NULL); + BDATA_RNG_Rand* resultFromDecomp = (BDATA_RNG_Rand*)BACKUP_PEEK(0, NULL); + RESTORE_RNG_Rand(before); + ND_RNG_Rand(); + BACKUP_RNG_Rand(); + BDATA_RNG_Rand* resultFromND = (BDATA_RNG_Rand*)BACKUP_PEEK(0, NULL); + + bool failedGlobalState = TEST_Memcmp(resultFromDecomp, resultFromND, sizeof(BDATA_RNG_Rand)); + + BACKUP_POP_MULTIPLE(3); + + if (failedGlobalState) { ND_printf("[%s] Test Failed (global state mismatch)\n", s_nameTestedFunc); } + if (resultFromND->e_seed != resultFromDecomp->e_seed) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, resultFromND->e_seed, resultFromDecomp->e_seed); } + PatchFunction_End(index); +} + +void BACKUP_LIST_Init(const void* source) +{ + +} + +void RESTORE_LIST_Init(BDATA_LIST_Init* restore, void* destination) +{ + +} + +void TEST_LIST_Init(LinkedList* list, Item* item, s32 itemSize, s32 numItems) +{ + const u32 index = PatchFunction_Beg((u32*)(&ND_LIST_Init), "LIST_Init"); +} +#pragma endregion + +#endif //TEST_LIST_IMPL \ No newline at end of file diff --git a/rewrite/src/tests/test_math.c b/rewrite/src/tests/test_math.c index 312c339a7..eddc74d81 100644 --- a/rewrite/src/tests/test_math.c +++ b/rewrite/src/tests/test_math.c @@ -2,6 +2,7 @@ #ifdef TEST_MATH_IMPL +#pragma region MATH_Sin void TEST_MATH_Sin(u32 angle, s32 ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_Sin), "MATH_Sin"); @@ -9,7 +10,9 @@ void TEST_MATH_Sin(u32 angle, s32 ret) if (expected != ret) { ND_printf("[%s] Test Failed:\nInput: %d\nExpected: %d\nResult: %d\n", s_nameTestedFunc, angle, expected, ret); } PatchFunction_End(index); } +#pragma endregion +#pragma region MATH_Cos void TEST_MATH_Cos(u32 angle, s32 ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_Cos), "MATH_Cos"); @@ -17,7 +20,9 @@ void TEST_MATH_Cos(u32 angle, s32 ret) if (expected != ret) { ND_printf("[%s] Test Failed:\nInput: %d\nExpected: %d\nResult: %d\n", s_nameTestedFunc, angle, expected, ret); } PatchFunction_End(index); } +#pragma endregion +#pragma region MATH_Sqrt void TEST_MATH_Sqrt(u32 n, u32 shift, u32 ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_Sqrt), "MATH_Sqrt"); @@ -25,16 +30,20 @@ void TEST_MATH_Sqrt(u32 n, u32 shift, u32 ret) if (expected != ret) { ND_printf("[%s] Test Failed:\nInput: %d %d\nExpected: %d\nResult: %d\n", s_nameTestedFunc, n, shift, expected, ret); } PatchFunction_End(index); } +#pragma endregion +#pragma region MATH_GetInverseMatrixTransformation void TEST_MATH_GetInverseMatrixTransformation(const Matrix* matrix, const Matrix* ret) { Matrix out; const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_GetInverseMatrixTransformation), "MATH_GetInverseMatrixTransformation"); ND_MATH_GetInverseMatrixTransformation(&out, matrix); - PrintMatrixDiff(&out, ret, true); + TEST_PrintMatrixDiff(&out, ret, true); PatchFunction_End(index); } +#pragma endregion +#pragma region MATH_VectorLength void TEST_MATH_VectorLength(const SVec3* vector, s32 ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_VectorLength), "MATH_VectorLength"); @@ -42,31 +51,38 @@ void TEST_MATH_VectorLength(const SVec3* vector, s32 ret) if (expected != ret) { ND_printf("[%s] Test Failed:\nInput: %d %d %d\nExpected: %d\nResult: %d\n", s_nameTestedFunc, vector->x, vector->y, vector->z, expected, ret); } PatchFunction_End(index); } +#pragma endregion +#pragma region MATH_VectorNormalize void TEST_MATH_VectorNormalize(SVec3* vector, const SVec3* ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_VectorNormalize), "MATH_VectorNormalize"); ND_MATH_VectorNormalize(vector); - PrintSVectorDiff(vector, ret); + TEST_PrintSVectorDiff(vector, ret); PatchFunction_End(index); } +#pragma endregion +#pragma region MATH_CombineMatrixTransformation void TEST_MATH_CombineMatrixTransformation(const Matrix* m, const Matrix* n, const Matrix* ret) { Matrix expected; const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_CombineMatrixTransformation), "MATH_CombineMatrixTransformation"); ND_MATH_CombineMatrixTransformation(&expected, m, n); - PrintMatrixDiff(&expected, ret, true); + TEST_PrintMatrixDiff(&expected, ret, true); PatchFunction_End(index); } +#pragma endregion +#pragma region MATH_MatrixMultiplication void TEST_MATH_MatrixMultiplication(const Matrix* m, const Matrix* n, const Matrix* ret) { Matrix expected; const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_MatrixMultiplication), "MATH_MatrixMultiplication"); ND_MATH_MatrixMultiplication(&expected, m, n); - PrintMatrixDiff(&expected, ret, false); + TEST_PrintMatrixDiff(&expected, ret, false); PatchFunction_End(index); } +#pragma endregion #endif // TEST_MATH_IMPL \ No newline at end of file diff --git a/rewrite/src/tests/test_rng.c b/rewrite/src/tests/test_rng.c index de15ecad3..02a1885fe 100644 --- a/rewrite/src/tests/test_rng.c +++ b/rewrite/src/tests/test_rng.c @@ -2,6 +2,7 @@ #ifdef TEST_RNG_IMPL +#pragma region RNG_Rand void BACKUP_RNG_Rand() { BDATA_RNG_Rand backup = { @@ -34,7 +35,9 @@ void TEST_RNG_Rand() if (resultFromND->e_seed != resultFromDecomp->e_seed) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, resultFromND->e_seed, resultFromDecomp->e_seed); } PatchFunction_End(index); } +#pragma endregion +#pragma region RNG_RandInt void BACKUP_RNG_RandInt() { BDATA_RNG_RandInt backup = { @@ -67,7 +70,9 @@ void TEST_RNG_RandInt(u32 n, s32 ret) if (expected != ret) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, expected, ret); } PatchFunction_End(index); } +#pragma endregion +#pragma region RNG_PseudoRand void TEST_RNG_PseudoRand(u16 n, u16 ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_PseudoRand), "RNG_PseudoRand"); @@ -75,7 +80,9 @@ void TEST_RNG_PseudoRand(u16 n, u16 ret) if (expected != ret) { ND_printf("[%s] Test Failed:\nExpected: %d\nResult: %d\n", s_nameTestedFunc, expected, ret); } PatchFunction_End(index); } +#pragma endregion +#pragma region RNG_Random void TEST_RNG_Random(RNGSeed* seed, const RNGSeed* ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_Random), "RNG_Random"); @@ -85,5 +92,6 @@ void TEST_RNG_Random(RNGSeed* seed, const RNGSeed* ret) if (expected != ret->b) { ND_printf("[%s] Test Failed:\nExpected: %d\nret: %d\n", s_nameTestedFunc, expected, ret->b); } PatchFunction_End(index); } +#pragma endregion #endif // TEST_RNG_IMPL \ No newline at end of file