Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"name": "ctr-u.bin",
"symbols":
[
"gcc-syms-rewrite.txt"
"gcc-syms-rewrite.txt", "gcc-extern-rewrite.txt"
],
"build_id": 9999
}
Expand Down
7 changes: 7 additions & 0 deletions include/ctr/nd.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <ctr/macros.h>
#include <ctr/math.h>
#include <ctr/rng.h>

void ND_LOAD_XnfFile(char* filename, u32 address, char* dummy);
s32 ND_SquareRoot0_stub(s32 n);
Expand All @@ -19,4 +20,10 @@ void ND_MATH_VectorNormalize(SVec3* vector);
void ND_MATH_CombineMatrixTransformation(Matrix* out, const Matrix* m, const Matrix* n);
void ND_MATH_MatrixMultiplication(Matrix* out, const Matrix* m, const Matrix* n);

/* RNG */
u32 ND_RNG_Rand();
s32 ND_RNG_RandInt(u32 n);
u16 ND_RNG_PseudoRand(u16 n);
u32 ND_RNG_Random(RNGSeed* seed);

#endif
20 changes: 20 additions & 0 deletions include/ctr/rng.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef RAND_H
#define RAND_H
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weren't you using pragma once in other files?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could switch to pragma once for every header


#include <ctr/macros.h>

typedef struct RNGSeed
{
u32 a;
u32 b;
} RNGSeed;

u32 RNG_Rand();
s32 RNG_RandInt(u32 n);
u16 RNG_PseudoRand(u16 n);
u32 RNG_Random(RNGSeed* seed);

extern u32 e_seed; // 0x8008d424
extern RNGSeed e_gameTrackerSeed; // 0x8009904c

#endif
54 changes: 37 additions & 17 deletions include/ctr/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,51 @@
#define TEST_H

#include <ctr/macros.h>
#include <ctr/math.h>
#include <ctr/redux.h>
#include <ctr/math.h>
#include <ctr/rng.h>

void LoadTestPatches();

#define BACKUP_ADDR 0x80400000

#define TEST_MATH_IMPL
#define TEST_RNG_IMPL

#ifdef TEST_MATH_IMPL
void TEST_MATH_Sin(u32 angle, s32 res);
void TEST_MATH_Cos(u32 angle, s32 res);
void TEST_MATH_Sqrt(u32 n, u32 shift, u32 res);
void TEST_MATH_GetInverseMatrixTransformation(const Matrix* matrix, const Matrix* res);
void TEST_MATH_VectorLength(const SVec3* vector, s32 res);
void TEST_MATH_VectorNormalize(SVec3* vector, const SVec3* res);
void TEST_MATH_CombineMatrixTransformation(const Matrix* m, const Matrix* n, const Matrix* res);
void TEST_MATH_MatrixMultiplication(const Matrix* m, const Matrix* n, const Matrix* res);
void TEST_MATH_Sin(u32 angle, s32 ret);
void TEST_MATH_Cos(u32 angle, s32 ret);
void TEST_MATH_Sqrt(u32 n, u32 shift, u32 ret);
void TEST_MATH_GetInverseMatrixTransformation(const Matrix* matrix, const Matrix* ret);
void TEST_MATH_VectorLength(const SVec3* vector, s32 ret);
void TEST_MATH_VectorNormalize(SVec3* vector, const SVec3* ret);
void TEST_MATH_CombineMatrixTransformation(const Matrix* m, const Matrix* n, const Matrix* ret);
void TEST_MATH_MatrixMultiplication(const Matrix* m, const Matrix* n, const Matrix* ret);
#else
#define TEST_MATH_Sin(angle, ret)
#define TEST_MATH_Cos(angle, ret)
#define TEST_MATH_Sqrt(n, shift, ret)
#define TEST_MATH_GetInverseMatrixTransformation(matrix, ret)
#define TEST_MATH_VectorLength(vector, ret)
#define TEST_MATH_VectorNormalize(vector, ret)
#define TEST_MATH_CombineMatrixTransformation(m, n, ret)
#define TEST_MATH_MatrixMultiplication(m, n, ret)
#endif

#ifdef TEST_RNG_IMPL
void BACKUP_RNG_Rand();
void TEST_RNG_Rand();
void BACKUP_RNG_RandInt();
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
#define TEST_MATH_Sin(angle, res)
#define TEST_MATH_Cos(angle, res)
#define TEST_MATH_Sqrt(n, shift, res)
#define TEST_MATH_GetInverseMatrixTransformation(matrix, res)
#define TEST_MATH_VectorLength(vector, res)
#define TEST_MATH_VectorNormalize(vector, res)
#define TEST_MATH_CombineMatrixTransformation(m, n, res)
#define TEST_MATH_MatrixMultiplication(m, n, res)
#define BACKUP_RNG_Rand()
#define TEST_RNG_Rand()
#define BACKUP_RNG_RandInt()
#define TEST_RNG_RandInt(n, ret)
#define TEST_RNG_PseudoRand(n, ret)
#define TEST_RNG_Random(seed, ret)
#endif

#endif
2 changes: 1 addition & 1 deletion rewrite/buildList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ common, exe, 0x8003c63c, 0x0, src/hooks/dll/hook.s
common, header, 0x8000B0B8, 0x0, src/hooks/dll/load_decomp.c

// decomp files
common, DLL, 0x80200000, 0x0, src/math.c src/prim.c, DECOMP.BIN
common, DLL, 0x80200000, 0x0, src/math.c src/rng.c src/prim.c, DECOMP.BIN
common, DLL, 0x80600000, 0x0, src/tests/test.c, TESTS.BIN
47 changes: 47 additions & 0 deletions rewrite/src/rng.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <ctr/rng.h>
#include <ctr/math.h>
#include <ctr/test.h>

#define RNG_MULT_FACTOR 0x6255
#define RNG_INC_FACTOR 0x3619

/* Address: 0x8003ea28 */
u32 RNG_Rand()
{
BACKUP_RNG_Rand();
e_seed = (e_seed * RNG_MULT_FACTOR + RNG_INC_FACTOR) & 0xFFFF;
TEST_RNG_Rand();
return e_seed;
}

/* Address: 0x8003ea6c */
s32 RNG_RandInt(u32 n)
{
BACKUP_RNG_RandInt();
const u32 rand = RNG_Random(&e_gameTrackerSeed);
const s32 ret = ((s32) ((rand & 0xFFFF) * n)) >> 16;
TEST_RNG_RandInt(n, ret);
return ret;
}

/* Address: 0x8003eaac */
u16 RNG_PseudoRand(u16 n)
{
const u16 ret = n * RNG_MULT_FACTOR + RNG_INC_FACTOR;
TEST_RNG_PseudoRand(n, ret);
return ret;
}

/* Address: 0x8006c684 */
u32 RNG_Random(RNGSeed* seed)
{
#ifdef TEST_RNG_IMPL
RNGSeed inputSeed = *seed;
#endif
const u32 x = seed->b >> 8;
const u32 nextA = (seed->a >> 8) | (seed->b << 24);
seed->b = (x | ((seed->a + x + (nextA >> 8)) << 24)) ^ 0xDEADC0ED;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iirc there was a deadcoed struct in sdata or something? Do we still use that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We aren't using anything from the previous decomp

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm more interested in knowing where the functionality that that struct represented went.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just parameters initialized with a seed, and bit shifted to give a pseudorandom number at the end.

seed->a = nextA;
TEST_RNG_Random(&inputSeed, seed);
return seed->b;
}
108 changes: 83 additions & 25 deletions rewrite/src/tests/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ FunctionPatch s_functions[] =
TEST_FUNC(MATH_VectorNormalize),
TEST_FUNC(MATH_CombineMatrixTransformation),
TEST_FUNC(MATH_MatrixMultiplication),
TEST_FUNC(RNG_Rand),
TEST_FUNC(RNG_RandInt),
TEST_FUNC(RNG_PseudoRand),
TEST_FUNC(RNG_Random),
};

void LoadTestPatches()
Expand Down Expand Up @@ -65,108 +69,162 @@ static u32 PatchFunction_End(u32 index)
*(s_functions[index].address + 1) = s_functions[index].secondNewInst;
}

static u32 PrintSVectorDiff(const char* name, const SVec3* expected, const SVec3* res)
static u32 PrintSVectorDiff(const char* name, const SVec3* expected, const SVec3* ret)
{
u32 failed = 0;
for (u32 i = 0; i < 3; i++)
{
if (expected->v[i] != res->v[i])
if (expected->v[i] != ret->v[i])
{
failed = 1;
ND_printf("[%s] Test Failed:\nv[%d] = %d, got %d\n", name, i, expected->v[i], res->v[i]);
ND_printf("[%s] Test Failed:\nv[%d] = %d, got %d\n", name, i, expected->v[i], ret->v[i]);
}
}
return failed;
}

static u32 PrintMatrixDiff(const char* name, const Matrix* expected, const Matrix* res, u32 cmpTrans)
static u32 PrintMatrixDiff(const char* name, const Matrix* expected, const Matrix* ret, u32 cmpTrans)
{
u32 failed = 0;
for (u32 i = 0; i < 3; i++)
{
for (u32 j = 0; j < 3; j++)
{
if (expected->m[i][j] != res->m[i][j])
if (expected->m[i][j] != ret->m[i][j])
{
failed = 1;
ND_printf("[%s] Test Failed:\nm[%d][%d] = %d, got %d\n", name, i, j, expected->m[i][j], res->m[i][j]);
ND_printf("[%s] Test Failed:\nm[%d][%d] = %d, got %d\n", name, i, j, expected->m[i][j], ret->m[i][j]);
}
}
if ((cmpTrans) && (expected->t.v[i] != res->t.v[i]))
if ((cmpTrans) && (expected->t.v[i] != ret->t.v[i]))
{
failed = 1;
ND_printf("[%s] Test Failed:\nt[%d] = %d, got %d\n", name, i, expected->t.v[i], res->t.v[i]);
ND_printf("[%s] Test Failed:\nt[%d] = %d, got %d\n", name, i, expected->t.v[i], ret->t.v[i]);
}
}
return failed;
}

#ifdef TEST_MATH_IMPL
void TEST_MATH_Sin(u32 angle, s32 res)

void TEST_MATH_Sin(u32 angle, s32 ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_Sin));
const s32 expected = ND_MATH_Sin(angle);
if (expected != res) { ND_printf("[MATH_Sin] Test Failed:\nInput: %d\nExpected: %d\nResult :%d\n", angle, expected, res); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expected:[space][number] vs Result:[number]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like result has two spaces on it now lol, probably doesn't matter though.

if (expected != ret) { ND_printf("[MATH_Sin] Test Failed:\nInput: %d\nExpected: %d\nResult:%d\n", angle, expected, ret); }
PatchFunction_End(index);
}

void TEST_MATH_Cos(u32 angle, s32 res)
void TEST_MATH_Cos(u32 angle, s32 ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_Cos));
const s32 expected = ND_MATH_Cos(angle);
if (expected != res) { ND_printf("[MATH_Cos] Test Failed:\nInput: %d\nExpected: %d\nResult :%d\n", angle, expected, res); }
if (expected != ret) { ND_printf("[MATH_Cos] Test Failed:\nInput: %d\nExpected: %d\nResult:%d\n", angle, expected, ret); }
PatchFunction_End(index);
}

void TEST_MATH_Sqrt(u32 n, u32 shift, u32 res)
void TEST_MATH_Sqrt(u32 n, u32 shift, u32 ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_Sqrt));
const u32 expected = ND_MATH_Sqrt(n, shift);
if (expected != res) { ND_printf("[MATH_Sqrt] Test Failed:\nInput: %d %d\nExpected: %d\nResult :%d\n", n, shift, expected, res); }
if (expected != ret) { ND_printf("[MATH_Sqrt] Test Failed:\nInput: %d %d\nExpected: %d\nResult:%d\n", n, shift, expected, ret); }
PatchFunction_End(index);
}

void TEST_MATH_GetInverseMatrixTransformation(const Matrix* matrix, const Matrix* res)
void TEST_MATH_GetInverseMatrixTransformation(const Matrix* matrix, const Matrix* ret)
{
Matrix out;
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_GetInverseMatrixTransformation));
ND_MATH_GetInverseMatrixTransformation(&out, matrix);
PrintMatrixDiff("MATH_GetInverseMatrixTransformation", &out, res, true);
PrintMatrixDiff("MATH_GetInverseMatrixTransformation", &out, ret, true);
PatchFunction_End(index);
}

void TEST_MATH_VectorLength(const SVec3* vector, s32 res)
void TEST_MATH_VectorLength(const SVec3* vector, s32 ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_VectorLength));
const s32 expected = ND_MATH_VectorLength(vector);
if (expected != res) { ND_printf("[MATH_VectorLength] Test Failed:\nInput: %d %d %d\nExpected: %d\nResult :%d\n", vector->x, vector->y, vector->z, expected, res); }
if (expected != ret) { ND_printf("[MATH_VectorLength] Test Failed:\nInput: %d %d %d\nExpected: %d\nResult:%d\n", vector->x, vector->y, vector->z, expected, ret); }
PatchFunction_End(index);
}

void TEST_MATH_VectorNormalize(SVec3* vector, const SVec3* res)
void TEST_MATH_VectorNormalize(SVec3* vector, const SVec3* ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_VectorNormalize));
ND_MATH_VectorNormalize(vector);
PrintSVectorDiff("MATH_VectorNormalize", vector, res);
PrintSVectorDiff("MATH_VectorNormalize", vector, ret);
PatchFunction_End(index);
}

void TEST_MATH_CombineMatrixTransformation(const Matrix* m, const Matrix* n, const Matrix* res)
void TEST_MATH_CombineMatrixTransformation(const Matrix* m, const Matrix* n, const Matrix* ret)
{
Matrix expected;
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_CombineMatrixTransformation));
ND_MATH_CombineMatrixTransformation(&expected, m, n);
PrintMatrixDiff("MATH_CombineMatrixTransformation", &expected, res, true);
PrintMatrixDiff("MATH_CombineMatrixTransformation", &expected, ret, true);
PatchFunction_End(index);
}

void TEST_MATH_MatrixMultiplication(const Matrix* m, const Matrix* n, const Matrix* res)
void TEST_MATH_MatrixMultiplication(const Matrix* m, const Matrix* n, const Matrix* ret)
{
Matrix expected;
const u32 index = PatchFunction_Beg((u32*)(&ND_MATH_MatrixMultiplication));
ND_MATH_MatrixMultiplication(&expected, m, n);
PrintMatrixDiff("MATH_MatrixMultiplication", &expected, res, false);
PrintMatrixDiff("MATH_MatrixMultiplication", &expected, ret, false);
PatchFunction_End(index);
}

#endif // TEST_MATH_IMPL

#ifdef TEST_RNG_IMPL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should split up the test files per-namespace

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good idea


void BACKUP_RNG_Rand()
{
u32* seedAddr = (u32*) BACKUP_ADDR;
*seedAddr = e_seed;
}

void TEST_RNG_Rand()
{
const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_Rand));
const u32 ret = e_seed;
e_seed = *(u32*) BACKUP_ADDR;
ND_RNG_Rand();
if (e_seed != ret) { ND_printf("[RNG_Rand] Test Failed:\nExpected: %d\nResult: %d\n", e_seed, ret); }
PatchFunction_End(index);
}

void BACKUP_RNG_RandInt()
{
RNGSeed* seedAddr = (RNGSeed*) BACKUP_ADDR;
*seedAddr = e_gameTrackerSeed;
}

void TEST_RNG_RandInt(u32 n, s32 ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_RandInt));
e_gameTrackerSeed = *(RNGSeed*) BACKUP_ADDR;
const s32 expected = ND_RNG_RandInt(n);
if (expected != ret) { ND_printf("[RNG_RandInt] Test Failed:\nExpected: %d\nResult: %d\n", expected, ret); }
PatchFunction_End(index);
}

void TEST_RNG_PseudoRand(u16 n, u16 ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_PseudoRand));
const u16 expected = ND_RNG_PseudoRand(n);
if (expected != ret) { ND_printf("[RNG_PseudoRand] Test Failed:\nExpected: %d\nResult: %d\n", expected, ret); }
PatchFunction_End(index);
}

void TEST_RNG_Random(RNGSeed* seed, const RNGSeed* ret)
{
const u32 index = PatchFunction_Beg((u32*)(&ND_RNG_Random));
const u32 expected = ND_RNG_Random(seed);
if (seed->a != ret->a) { ND_printf("[RNG_Random] Test Failed:\nseed->a: %d\nret->a: %d\n", seed->a, ret->a); }
if (seed->b != ret->b) { ND_printf("[RNG_Random] Test Failed:\nseed->b: %d\nret->b: %d\n", seed->b, ret->b); }
if (expected != ret->b) { ND_printf("[RNG_Random] Test Failed:\nExpected: %d\nret: %d\n", expected, ret->b); }
PatchFunction_End(index);
}

#endif // TEST_MATH_IMPL
#endif // TEST_RNG_IMPL
2 changes: 2 additions & 0 deletions symbols/gcc-extern-rewrite.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
e_seed = 0x8008d424;
e_gameTrackerSeed = 0x8009904c;
Loading