mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-12-17 13:32:24 +00:00
Addressing multiple TODO's since no one else did
1. test_recompiler.cpp:216 - Implement CR register checking - Added proper CR register validation that checks all 4 fields (lt, gt, eq, so) - Each field is extracted from the 4-bit CR value using bit shifts 2. recompiler.h:55 - Create RecompileArgs struct - Introduced RecompileArgs struct to encapsulate the 7 function parameters - Improves code maintainability and reduces function signature complexity - Updated function signature and call site accordingly 3. recompiler.cpp:366 - Add bounds checking for mmioStore - Added validation to ensure the next instruction (data + 1) is within function bounds - Prevents potential out-of-bounds memory access 4. recompiler.cpp:1258 - Fix MFOCRF hardcoded CR field - Implemented proper FXM field mask decoding to determine which CR field to read - Removed hardcoded cr6 and now dynamically selects the correct CR field (cr0-cr7) - FXM is decoded as an 8-bit mask where bit 0 (0x80) = cr0, bit 1 (0x40) = cr1, etc.
This commit is contained in:
parent
ddd128bcca
commit
e82a89397a
3 changed files with 49 additions and 22 deletions
|
|
@ -254,15 +254,16 @@ void Recompiler::Analyse()
|
||||||
std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs) { return lhs.base < rhs.base; });
|
std::sort(functions.begin(), functions.end(), [](auto& lhs, auto& rhs) { return lhs.base < rhs.base; });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Recompiler::Recompile(
|
bool Recompiler::Recompile(const RecompileArgs& args)
|
||||||
const Function& fn,
|
|
||||||
uint32_t base,
|
|
||||||
const ppc_insn& insn,
|
|
||||||
const uint32_t* data,
|
|
||||||
std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
|
|
||||||
RecompilerLocalVariables& localVariables,
|
|
||||||
CSRState& csrState)
|
|
||||||
{
|
{
|
||||||
|
const Function& fn = args.fn;
|
||||||
|
uint32_t base = args.base;
|
||||||
|
const ppc_insn& insn = args.insn;
|
||||||
|
const uint32_t* data = args.data;
|
||||||
|
auto& switchTable = args.switchTable;
|
||||||
|
RecompilerLocalVariables& localVariables = args.localVariables;
|
||||||
|
CSRState& csrState = args.csrState;
|
||||||
|
|
||||||
println("\t// {} {}", insn.opcode->name, insn.op_str);
|
println("\t// {} {}", insn.opcode->name, insn.op_str);
|
||||||
|
|
||||||
// TODO: we could cache these formats in an array
|
// TODO: we could cache these formats in an array
|
||||||
|
|
@ -363,9 +364,11 @@ bool Recompiler::Recompile(
|
||||||
return "ea";
|
return "ea";
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO (Sajid): Check for out of bounds access
|
|
||||||
auto mmioStore = [&]() -> bool
|
auto mmioStore = [&]() -> bool
|
||||||
{
|
{
|
||||||
|
// Check if the next instruction is within bounds
|
||||||
|
if (base + 4 >= fn.base + fn.size)
|
||||||
|
return false;
|
||||||
return *(data + 1) == c_eieio;
|
return *(data + 1) == c_eieio;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1255,8 +1258,21 @@ bool Recompiler::Recompile(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PPC_INST_MFOCRF:
|
case PPC_INST_MFOCRF:
|
||||||
// TODO: don't hardcode to cr6
|
{
|
||||||
println("\t{}.u64 = ({}.lt << 7) | ({}.gt << 6) | ({}.eq << 5) | ({}.so << 4);", r(insn.operands[0]), cr(6), cr(6), cr(6), cr(6));
|
// Decode FXM field mask to determine which CR field to read
|
||||||
|
// FXM is an 8-bit mask where bit 0 (0x80) = cr0, bit 1 (0x40) = cr1, etc.
|
||||||
|
uint32_t fxm = insn.operands[1];
|
||||||
|
size_t crField = 0;
|
||||||
|
for (size_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if (fxm & (0x80 >> i))
|
||||||
|
{
|
||||||
|
crField = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("\t{}.u64 = ({}.lt << 7) | ({}.gt << 6) | ({}.eq << 5) | ({}.so << 4);", r(insn.operands[0]), cr(crField), cr(crField), cr(crField), cr(crField));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PPC_INST_MFTB:
|
case PPC_INST_MFTB:
|
||||||
|
|
@ -2427,7 +2443,7 @@ bool Recompiler::Recompile(const Function& fn)
|
||||||
if (insn.opcode->id == PPC_INST_BCTR && (*(data - 1) == 0x07008038 || *(data - 1) == 0x00000060) && switchTable == config.switchTables.end())
|
if (insn.opcode->id == PPC_INST_BCTR && (*(data - 1) == 0x07008038 || *(data - 1) == 0x00000060) && switchTable == config.switchTables.end())
|
||||||
fmt::println("Found a switch jump table at {:X} with no switch table entry present", base);
|
fmt::println("Found a switch jump table at {:X} with no switch table entry present", base);
|
||||||
|
|
||||||
if (!Recompile(fn, base, insn, data, switchTable, localVariables, csrState))
|
if (!Recompile(RecompileArgs{fn, base, insn, data, switchTable, localVariables, csrState}))
|
||||||
{
|
{
|
||||||
fmt::println("Unrecognized instruction at 0x{:X}: {}", base, insn.opcode->name);
|
fmt::println("Unrecognized instruction at 0x{:X}: {}", base, insn.opcode->name);
|
||||||
allRecompiled = false;
|
allRecompiled = false;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,17 @@ enum class CSRState
|
||||||
VMX
|
VMX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RecompileArgs
|
||||||
|
{
|
||||||
|
const Function& fn;
|
||||||
|
uint32_t base;
|
||||||
|
const ppc_insn& insn;
|
||||||
|
const uint32_t* data;
|
||||||
|
std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable;
|
||||||
|
RecompilerLocalVariables& localVariables;
|
||||||
|
CSRState& csrState;
|
||||||
|
};
|
||||||
|
|
||||||
struct Recompiler
|
struct Recompiler
|
||||||
{
|
{
|
||||||
// Enforce In-order Execution of I/O constant for quick comparison
|
// Enforce In-order Execution of I/O constant for quick comparison
|
||||||
|
|
@ -52,15 +63,7 @@ struct Recompiler
|
||||||
|
|
||||||
void Analyse();
|
void Analyse();
|
||||||
|
|
||||||
// TODO: make a RecompileArgs struct instead this is getting messy
|
bool Recompile(const RecompileArgs& args);
|
||||||
bool Recompile(
|
|
||||||
const Function& fn,
|
|
||||||
uint32_t base,
|
|
||||||
const ppc_insn& insn,
|
|
||||||
const uint32_t* data,
|
|
||||||
std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
|
|
||||||
RecompilerLocalVariables& localVariables,
|
|
||||||
CSRState& csrState);
|
|
||||||
|
|
||||||
bool Recompile(const Function& fn);
|
bool Recompile(const Function& fn);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,15 @@ void TestRecompiler::RecompileTests(const char* srcDirectoryPath, const char* ds
|
||||||
int secondSpaceIndex = str.find(' ', spaceIndex + 1);
|
int secondSpaceIndex = str.find(' ', spaceIndex + 1);
|
||||||
auto reg = str.substr(spaceIndex + 1, secondSpaceIndex - spaceIndex - 1);
|
auto reg = str.substr(spaceIndex + 1, secondSpaceIndex - spaceIndex - 1);
|
||||||
if (reg[0] == 'c')
|
if (reg[0] == 'c')
|
||||||
continue; // TODO
|
{
|
||||||
|
// CR register: parse 4-bit value (lt, gt, eq, so)
|
||||||
|
auto value = str.substr(secondSpaceIndex + 1);
|
||||||
|
fmt::println(file, "\tPPC_CHECK_VALUE_U({}, ctx.{}.lt, ({}) >> 3 & 1);", name, reg, value);
|
||||||
|
fmt::println(file, "\tPPC_CHECK_VALUE_U({}, ctx.{}.gt, ({}) >> 2 & 1);", name, reg, value);
|
||||||
|
fmt::println(file, "\tPPC_CHECK_VALUE_U({}, ctx.{}.eq, ({}) >> 1 & 1);", name, reg, value);
|
||||||
|
fmt::println(file, "\tPPC_CHECK_VALUE_U({}, ctx.{}.so, ({}) & 1);", name, reg, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (reg[0] == 'v')
|
if (reg[0] == 'v')
|
||||||
{
|
{
|
||||||
int openingBracketIndex = str.find('[', secondSpaceIndex + 1);
|
int openingBracketIndex = str.find('[', secondSpaceIndex + 1);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue