Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
40 changes: 14 additions & 26 deletions ps2xRecomp/src/lib/control_flow_emitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,25 +404,26 @@ namespace ps2recomp
case OPCODE_BNE:
case OPCODE_BNEL:
return fmt::format("GPR_U64(ctx, {}) != GPR_U64(ctx, {})", rsReg, rtReg);
// Sign tests look at the full 64-bit register, like every other R5900 compare.
case OPCODE_BLEZ:
case OPCODE_BLEZL:
return fmt::format("GPR_S32(ctx, {}) <= 0", rsReg);
return fmt::format("GPR_S64(ctx, {}) <= 0", rsReg);
case OPCODE_BGTZ:
case OPCODE_BGTZL:
return fmt::format("GPR_S32(ctx, {}) > 0", rsReg);
return fmt::format("GPR_S64(ctx, {}) > 0", rsReg);
case OPCODE_REGIMM:
switch (m_branchInst.rt)
{
case REGIMM_BLTZ:
case REGIMM_BLTZL:
case REGIMM_BLTZAL:
case REGIMM_BLTZALL:
return fmt::format("GPR_S32(ctx, {}) < 0", rsReg);
return fmt::format("GPR_S64(ctx, {}) < 0", rsReg);
case REGIMM_BGEZ:
case REGIMM_BGEZL:
case REGIMM_BGEZAL:
case REGIMM_BGEZALL:
return fmt::format("GPR_S32(ctx, {}) >= 0", rsReg);
return fmt::format("GPR_S64(ctx, {}) >= 0", rsReg);
default:
return "false";
}
Expand Down Expand Up @@ -463,36 +464,28 @@ namespace ps2recomp
const uint32_t target = conditionalBranchTarget();
const bool likely = isLikelyBranch();
const std::string branchTakenVar = fmt::format("branch_taken_0x{:x}", m_branchInst.address);
std::string unconditionalLinkCode;
std::string conditionalLinkCode;
std::string linkCode;

if (m_branchInst.opcode == OPCODE_REGIMM)
if (m_branchInst.opcode == OPCODE_REGIMM &&
(m_branchInst.rt == REGIMM_BLTZAL || m_branchInst.rt == REGIMM_BGEZAL ||
m_branchInst.rt == REGIMM_BLTZALL || m_branchInst.rt == REGIMM_BGEZALL))
{
if (m_branchInst.rt == REGIMM_BLTZAL || m_branchInst.rt == REGIMM_BGEZAL)
{
unconditionalLinkCode = fmt::format("SET_GPR_U32(ctx, 31, 0x{:X}u);", fallthroughPc());
}
else if (m_branchInst.rt == REGIMM_BLTZALL || m_branchInst.rt == REGIMM_BGEZALL)
{
conditionalLinkCode = fmt::format("SET_GPR_U32(ctx, 31, 0x{:X}u);", fallthroughPc());
}
// Every "and link" branch, likely or not, writes $ra whether or not it is taken.
// The condition is captured first so a link into rs sees the pre-link value.
linkCode = fmt::format("SET_GPR_U32(ctx, 31, 0x{:X}u);", fallthroughPc());
}

m_ss << " {\n";
m_ss << " const bool " << branchTakenVar << " = (" << conditionalBranchExpression() << ");\n";

if (!unconditionalLinkCode.empty())
if (!linkCode.empty())
{
m_ss << " " << unconditionalLinkCode << "\n";
m_ss << " " << linkCode << "\n";
}

if (likely)
{
m_ss << " if (" << branchTakenVar << ") {\n";
if (!conditionalLinkCode.empty())
{
m_ss << " " << conditionalLinkCode << "\n";
}
emitDelaySlot(" ");

if (isInternalTarget(target))
Expand All @@ -508,11 +501,6 @@ namespace ps2recomp
}
else
{
if (!conditionalLinkCode.empty())
{
m_ss << " if (" << branchTakenVar << ") { " << conditionalLinkCode << " }\n";
}

emitDelaySlot(" ");

m_ss << " if (" << branchTakenVar << ") {\n";
Expand Down
9 changes: 5 additions & 4 deletions ps2xRecomp/src/lib/instruction_translator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,11 @@ namespace ps2recomp
return genWrite(16, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate), fmt::format("(uint16_t)GPR_U32(ctx, {})", inst.rt)) + ";";
case OPCODE_SW:
return genWrite(32, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate), fmt::format("GPR_U32(ctx, {})", inst.rt)) + ";";
// LQ/SQ silently ignore the low four address bits instead of raising an address error.
case OPCODE_LQ:
return fmt::format("SET_GPR_VEC(ctx, {}, {});", inst.rt, genRead(128, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
return fmt::format("SET_GPR_VEC(ctx, {}, {});", inst.rt, genRead(128, fmt::format("ADD32(GPR_U32(ctx, {}), {}) & ~0xFu", inst.rs, inst.simmediate)));
case OPCODE_SQ:
return genWrite(128, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate), fmt::format("GPR_VEC(ctx, {})", inst.rt)) + ";";
return genWrite(128, fmt::format("ADD32(GPR_U32(ctx, {}), {}) & ~0xFu", inst.rs, inst.simmediate), fmt::format("GPR_VEC(ctx, {})", inst.rt)) + ";";
case OPCODE_LD:
return fmt::format("SET_GPR_U64(ctx, {}, {});", inst.rt, genRead(64, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
case OPCODE_SD:
Expand All @@ -218,14 +219,14 @@ namespace ps2recomp
return fmt::format(
"{{ int64_t src = (int64_t)GPR_S64(ctx, {}); "
"int64_t imm = (int64_t)(int32_t){}; "
"int64_t res = src + imm; "
"int64_t res = (int64_t)((uint64_t)src + (uint64_t)imm); "
"if (((src ^ imm) >= 0) && ((src ^ res) < 0)) "
" runtime->SignalException(ctx, EXCEPTION_INTEGER_OVERFLOW); "
"else SET_GPR_S64(ctx, {}, res); }}",
inst.rs, inst.simmediate, inst.rt);
case OPCODE_DADDIU:
return fmt::format(
"SET_GPR_S64(ctx, {}, (int64_t)GPR_S64(ctx, {}) + (int64_t)(int32_t){});",
"SET_GPR_U64(ctx, {}, GPR_U64(ctx, {}) + (uint64_t)(int64_t)(int32_t){});",
inst.rt, inst.rs, inst.simmediate);
case OPCODE_J:
return fmt::format("// J 0x{:X} - Handled by branch logic", buildAbsoluteJumpTarget(inst.address, inst.target));
Expand Down
9 changes: 5 additions & 4 deletions ps2xRecomp/src/lib/special_translator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,11 @@ namespace ps2recomp
return fmt::format("SET_GPR_U64(ctx, {}, ((int64_t)GPR_S64(ctx, {}) < (int64_t)GPR_S64(ctx, {})) ? 1 : 0);", inst.rd, inst.rs, inst.rt);
case SPECIAL_SLTU:
return fmt::format("SET_GPR_U64(ctx, {}, ((uint64_t)GPR_U64(ctx, {}) < (uint64_t)GPR_U64(ctx, {})) ? 1 : 0);", inst.rd, inst.rs, inst.rt);
// MOVZ/MOVN are 64-bit moves: the upper half of the 128-bit destination is preserved.
case SPECIAL_MOVZ:
return fmt::format("if (GPR_U64(ctx, {}) == 0) SET_GPR_VEC(ctx, {}, GPR_VEC(ctx, {}));", inst.rt, inst.rd, inst.rs);
return fmt::format("if (GPR_U64(ctx, {}) == 0) SET_GPR_U64(ctx, {}, GPR_U64(ctx, {}));", inst.rt, inst.rd, inst.rs);
case SPECIAL_MOVN:
return fmt::format("if (GPR_U64(ctx, {}) != 0) SET_GPR_VEC(ctx, {}, GPR_VEC(ctx, {}));", inst.rt, inst.rd, inst.rs);
return fmt::format("if (GPR_U64(ctx, {}) != 0) SET_GPR_U64(ctx, {}, GPR_U64(ctx, {}));", inst.rt, inst.rd, inst.rs);
case SPECIAL_MFSA:
return fmt::format("SET_GPR_U32(ctx, {}, ctx->sa);", inst.rd);
case SPECIAL_MTSA:
Expand All @@ -132,7 +133,7 @@ namespace ps2recomp
return fmt::format(
"{{ int64_t a = (int64_t)GPR_S64(ctx, {}); "
"int64_t b = (int64_t)GPR_S64(ctx, {}); "
"int64_t r = a + b; "
"int64_t r = (int64_t)((uint64_t)a + (uint64_t)b); "
"if (((a ^ b) >= 0) && ((a ^ r) < 0)) runtime->SignalException(ctx, EXCEPTION_INTEGER_OVERFLOW); "
"else SET_GPR_S64(ctx, {}, r); }}",
inst.rs, inst.rt, inst.rd);
Expand All @@ -144,7 +145,7 @@ namespace ps2recomp
return fmt::format(
"{{ int64_t a = (int64_t)GPR_S64(ctx, {}); "
"int64_t b = (int64_t)GPR_S64(ctx, {}); "
"int64_t r = a - b; "
"int64_t r = (int64_t)((uint64_t)a - (uint64_t)b); "
"if (((a ^ b) < 0) && ((a ^ r) < 0)) runtime->SignalException(ctx, EXCEPTION_INTEGER_OVERFLOW); "
"else SET_GPR_S64(ctx, {}, r); }}",
inst.rs, inst.rt, inst.rd);
Expand Down
4 changes: 2 additions & 2 deletions ps2xRuntime/include/ps2_runtime_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static inline uint32_t ps2_plzcw32(uint32_t x)
{ \
int32_t _a = (int32_t)(rs); \
int32_t _b = (int32_t)(rt); \
int32_t _r = _a + _b; \
int32_t _r = (int32_t)((uint32_t)_a + (uint32_t)_b); \
overflow = (((_a ^ _b) >= 0) && ((_a ^ _r) < 0)); \
result32 = (uint32_t)_r; \
} while (0);
Expand All @@ -102,7 +102,7 @@ static inline uint32_t ps2_plzcw32(uint32_t x)
{ \
int32_t _a = (int32_t)(rs); \
int32_t _b = (int32_t)(rt); \
int32_t _r = _a - _b; \
int32_t _r = (int32_t)((uint32_t)_a - (uint32_t)_b); \
overflow = (((_a ^ _b) < 0) && ((_a ^ _r) < 0)); \
result32 = (uint32_t)_r; \
} while (0);
Expand Down
1 change: 1 addition & 0 deletions ps2xTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ target_include_directories(ps2_test_function_table PRIVATE
add_library(ps2_test_lib STATIC
src/code_generator_tests.cpp
src/r5900_decoder_tests.cpp
src/r5900_general_instruction_tests.cpp
src/elf_analyzer_tests.cpp
src/pad_input_tests.cpp
src/ps2_runtime_io_tests.cpp
Expand Down
2 changes: 2 additions & 0 deletions ps2xTest/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

void register_code_generator_tests();
void register_r5900_decoder_tests();
void register_r5900_general_instruction_tests();
void register_elf_analyzer_tests();
void register_pad_input_tests();
void register_ps2_runtime_io_tests();
Expand All @@ -26,6 +27,7 @@ int main()

register_code_generator_tests();
register_r5900_decoder_tests();
register_r5900_general_instruction_tests();
register_elf_analyzer_tests();
register_pad_input_tests();
register_ps2_runtime_io_tests();
Expand Down
Loading