GPU: Allow relative jumps and calls.

These are tested in gpu/signals/jumps, so they ought to work.
Doesn't seem like games generally use them, though.
This commit is contained in:
Unknown W. Brackets 2022-01-23 23:03:30 -08:00
parent 5a6bf8b435
commit 511c822312

View file

@ -1397,31 +1397,53 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
DEBUG_LOG(G3D, "Signal with Sync. signal/end: %04x %04x", signal, enddata);
break;
case PSP_GE_SIGNAL_JUMP:
case PSP_GE_SIGNAL_RJUMP:
case PSP_GE_SIGNAL_OJUMP:
{
trigger = false;
currentList->signal = behaviour;
// pc will be increased after we return, counteract that.
u32 target = (((signal << 16) | enddata) & 0xFFFFFFFC) - 4;
const char *targetType = "absolute";
if (behaviour == PSP_GE_SIGNAL_RJUMP) {
target += currentList->pc - 4;
targetType = "relative";
} else if (behaviour == PSP_GE_SIGNAL_OJUMP) {
target = gstate_c.getRelativeAddress(target);
targetType = "origin";
}
if (!Memory::IsValidAddress(target)) {
ERROR_LOG_REPORT(G3D, "Signal with Jump: bad address. signal/end: %04x %04x", signal, enddata);
ERROR_LOG_REPORT(G3D, "Signal with Jump (%s): bad address. signal/end: %04x %04x", targetType, signal, enddata);
UpdateState(GPUSTATE_ERROR);
} else {
UpdatePC(currentList->pc, target);
currentList->pc = target;
DEBUG_LOG(G3D, "Signal with Jump. signal/end: %04x %04x", signal, enddata);
DEBUG_LOG(G3D, "Signal with Jump (%s). signal/end: %04x %04x", targetType, signal, enddata);
}
}
break;
case PSP_GE_SIGNAL_CALL:
case PSP_GE_SIGNAL_RCALL:
case PSP_GE_SIGNAL_OCALL:
{
trigger = false;
currentList->signal = behaviour;
// pc will be increased after we return, counteract that.
u32 target = (((signal << 16) | enddata) & 0xFFFFFFFC) - 4;
const char *targetType = "absolute";
if (behaviour == PSP_GE_SIGNAL_RCALL) {
target += currentList->pc - 4;
targetType = "relative";
} else if (behaviour == PSP_GE_SIGNAL_OCALL) {
target = gstate_c.getRelativeAddress(target);
targetType = "origin";
}
if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) {
ERROR_LOG_REPORT(G3D, "Signal with Call: stack full. signal/end: %04x %04x", signal, enddata);
ERROR_LOG_REPORT(G3D, "Signal with Call (%s): stack full. signal/end: %04x %04x", targetType, signal, enddata);
} else if (!Memory::IsValidAddress(target)) {
ERROR_LOG_REPORT(G3D, "Signal with Call: bad address. signal/end: %04x %04x", signal, enddata);
ERROR_LOG_REPORT(G3D, "Signal with Call (%s): bad address. signal/end: %04x %04x", targetType, signal, enddata);
UpdateState(GPUSTATE_ERROR);
} else {
// TODO: This might save/restore other state...
@ -1431,7 +1453,7 @@ void GPUCommon::Execute_End(u32 op, u32 diff) {
stackEntry.baseAddr = gstate.base;
UpdatePC(currentList->pc, target);
currentList->pc = target;
DEBUG_LOG(G3D, "Signal with Call. signal/end: %04x %04x", signal, enddata);
DEBUG_LOG(G3D, "Signal with Call (%s). signal/end: %04x %04x", targetType, signal, enddata);
}
}
break;