mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-21 17:30:46 +00:00
Add the common funcs to the direct exec calls.
This commit is contained in:
parent
9851400681
commit
256e98b841
@ -303,16 +303,16 @@ static const CommandTableEntry commandTable[] = {
|
||||
{GE_CMD_TRANSFERSIZE, 0},
|
||||
|
||||
// From Common. No flushing but definitely need execute.
|
||||
{GE_CMD_OFFSETADDR, FLAG_EXECUTE},
|
||||
{GE_CMD_ORIGIN, FLAG_EXECUTE | FLAG_READS_PC}, // Really?
|
||||
{GE_CMD_OFFSETADDR, FLAG_EXECUTE, &GPUCommon::Execute_OffsetAddr},
|
||||
{GE_CMD_ORIGIN, FLAG_EXECUTE | FLAG_READS_PC, &GPUCommon::Execute_Origin}, // Really?
|
||||
{GE_CMD_PRIM, FLAG_EXECUTE, &GLES_GPU::Execute_Prim},
|
||||
{GE_CMD_JUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC},
|
||||
{GE_CMD_CALL, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC},
|
||||
{GE_CMD_RET, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC},
|
||||
{GE_CMD_END, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC}, // Flush?
|
||||
{GE_CMD_JUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, &GPUCommon::Execute_Jump},
|
||||
{GE_CMD_CALL, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, &GPUCommon::Execute_Call},
|
||||
{GE_CMD_RET, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, &GPUCommon::Execute_Ret},
|
||||
{GE_CMD_END, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, &GPUCommon::Execute_End}, // Flush?
|
||||
{GE_CMD_VADDR, FLAG_EXECUTE, &GLES_GPU::Execute_Vaddr},
|
||||
{GE_CMD_IADDR, FLAG_EXECUTE, &GLES_GPU::Execute_Iaddr},
|
||||
{GE_CMD_BJUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC}, // EXECUTE
|
||||
{GE_CMD_BJUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, &GPUCommon::Execute_BJump}, // EXECUTE
|
||||
{GE_CMD_BOUNDINGBOX, FLAG_EXECUTE}, // + FLUSHBEFORE when we implement... or not, do we need to?
|
||||
|
||||
// Changing the vertex type requires us to flush.
|
||||
|
@ -683,9 +683,249 @@ void GPUCommon::PreExecuteOp(u32 op, u32 diff) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_OffsetAddr(u32 op, u32 diff) {
|
||||
gstate_c.offsetAddr = op << 8;
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Origin(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
gstate_c.offsetAddr = currentList->pc;
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Jump(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
const u32 data = op & 0x00FFFFFF;
|
||||
const u32 target = gstate_c.getRelativeAddress(data);
|
||||
if (Memory::IsValidAddress(target)) {
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
} else {
|
||||
ERROR_LOG_REPORT(G3D, "JUMP to illegal address %08x - ignoring! data=%06x", target, data);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_BJump(u32 op, u32 diff) {
|
||||
if (!currentList->bboxResult) {
|
||||
// bounding box jump.
|
||||
easy_guard guard(listLock);
|
||||
const u32 data = op & 0x00FFFFFF;
|
||||
const u32 target = gstate_c.getRelativeAddress(data);
|
||||
if (Memory::IsValidAddress(target)) {
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
} else {
|
||||
ERROR_LOG_REPORT(G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Call(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
|
||||
// Saint Seiya needs correct support for relative calls.
|
||||
const u32 retval = currentList->pc + 4;
|
||||
const u32 data = op & 0x00FFFFFF;
|
||||
const u32 target = gstate_c.getRelativeAddress(data);
|
||||
|
||||
// Bone matrix optimization - many games will CALL a bone matrix (!).
|
||||
if ((Memory::ReadUnchecked_U32(target) >> 24) == GE_CMD_BONEMATRIXDATA) {
|
||||
// Check for the end
|
||||
if ((Memory::ReadUnchecked_U32(target + 11 * 4) >> 24) == GE_CMD_BONEMATRIXDATA &&
|
||||
(Memory::ReadUnchecked_U32(target + 12 * 4) >> 24) == GE_CMD_RET) {
|
||||
// Yep, pretty sure this is a bone matrix call.
|
||||
FastLoadBoneMatrix(target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) {
|
||||
ERROR_LOG_REPORT(G3D, "CALL: Stack full!");
|
||||
} else if (!Memory::IsValidAddress(target)) {
|
||||
ERROR_LOG_REPORT(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, data);
|
||||
} else {
|
||||
auto &stackEntry = currentList->stack[currentList->stackptr++];
|
||||
stackEntry.pc = retval;
|
||||
stackEntry.offsetAddr = gstate_c.offsetAddr;
|
||||
// The base address is NOT saved/restored for a regular call.
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_Ret(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
if (currentList->stackptr == 0) {
|
||||
DEBUG_LOG_REPORT(G3D, "RET: Stack empty!");
|
||||
} else {
|
||||
auto &stackEntry = currentList->stack[--currentList->stackptr];
|
||||
gstate_c.offsetAddr = stackEntry.offsetAddr;
|
||||
u32 target = (currentList->pc & 0xF0000000) | (stackEntry.pc & 0x0FFFFFFF);
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4;
|
||||
if (!Memory::IsValidAddress(currentList->pc)) {
|
||||
ERROR_LOG_REPORT(G3D, "Invalid DL PC %08x on return", currentList->pc);
|
||||
UpdateState(GPUSTATE_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::Execute_End(u32 op, u32 diff) {
|
||||
easy_guard guard(listLock);
|
||||
const u32 data = op & 0x00FFFFFF;
|
||||
const u32 prev = Memory::ReadUnchecked_U32(currentList->pc - 4);
|
||||
UpdatePC(currentList->pc);
|
||||
switch (prev >> 24) {
|
||||
case GE_CMD_SIGNAL:
|
||||
{
|
||||
// TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935#
|
||||
SignalBehavior behaviour = static_cast<SignalBehavior>((prev >> 16) & 0xFF);
|
||||
int signal = prev & 0xFFFF;
|
||||
int enddata = data & 0xFFFF;
|
||||
bool trigger = true;
|
||||
currentList->subIntrToken = signal;
|
||||
|
||||
switch (behaviour) {
|
||||
case PSP_GE_SIGNAL_HANDLER_SUSPEND:
|
||||
// Suspend the list, and call the signal handler. When it's done, resume.
|
||||
// Before sdkver 0x02000010, listsync should return paused.
|
||||
if (sceKernelGetCompiledSdkVersion() <= 0x02000010)
|
||||
currentList->state = PSP_GE_DL_STATE_PAUSED;
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal with wait. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_HANDLER_CONTINUE:
|
||||
// Resume the list right away, then call the handler.
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal without wait. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_HANDLER_PAUSE:
|
||||
// Pause the list instead of ending at the next FINISH.
|
||||
// Call the handler with the PAUSE signal value at that FINISH.
|
||||
// Technically, this ought to trigger an interrupt, but it won't do anything.
|
||||
// But right now, signal is always reset by interrupts, so that causes pause to not work.
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal with Pause. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_SYNC:
|
||||
// Acts as a memory barrier, never calls any user code.
|
||||
// Technically, this ought to trigger an interrupt, but it won't do anything.
|
||||
// Triggering here can cause incorrect rescheduling, which breaks 3rd Birthday.
|
||||
// However, this is likely a bug in how GE signal interrupts are handled.
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal with Sync. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_JUMP:
|
||||
{
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
// pc will be increased after we return, counteract that.
|
||||
u32 target = ((signal << 16) | enddata) - 4;
|
||||
if (!Memory::IsValidAddress(target)) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Jump: bad address. signal/end: %04x %04x", signal, enddata);
|
||||
} else {
|
||||
UpdatePC(currentList->pc, target);
|
||||
currentList->pc = target;
|
||||
DEBUG_LOG(G3D, "Signal with Jump. signal/end: %04x %04x", signal, enddata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PSP_GE_SIGNAL_CALL:
|
||||
{
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
// pc will be increased after we return, counteract that.
|
||||
u32 target = ((signal << 16) | enddata) - 4;
|
||||
if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Call: stack full. signal/end: %04x %04x", signal, enddata);
|
||||
} else if (!Memory::IsValidAddress(target)) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Call: bad address. signal/end: %04x %04x", signal, enddata);
|
||||
} else {
|
||||
// TODO: This might save/restore other state...
|
||||
auto &stackEntry = currentList->stack[currentList->stackptr++];
|
||||
stackEntry.pc = currentList->pc;
|
||||
stackEntry.offsetAddr = gstate_c.offsetAddr;
|
||||
stackEntry.baseAddr = gstate.base;
|
||||
UpdatePC(currentList->pc, target);
|
||||
currentList->pc = target;
|
||||
DEBUG_LOG(G3D, "Signal with Call. signal/end: %04x %04x", signal, enddata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PSP_GE_SIGNAL_RET:
|
||||
{
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
if (currentList->stackptr == 0) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Return: stack empty. signal/end: %04x %04x", signal, enddata);
|
||||
} else {
|
||||
// TODO: This might save/restore other state...
|
||||
auto &stackEntry = currentList->stack[--currentList->stackptr];
|
||||
gstate_c.offsetAddr = stackEntry.offsetAddr;
|
||||
gstate.base = stackEntry.baseAddr;
|
||||
UpdatePC(currentList->pc, stackEntry.pc);
|
||||
currentList->pc = stackEntry.pc;
|
||||
DEBUG_LOG(G3D, "Signal with Return. signal/end: %04x %04x", signal, enddata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG_REPORT(G3D, "UNKNOWN Signal UNIMPLEMENTED %i ! signal/end: %04x %04x", behaviour, signal, enddata);
|
||||
break;
|
||||
}
|
||||
// TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe?
|
||||
if (currentList->interruptsEnabled && trigger) {
|
||||
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
currentList->pendingInterrupt = true;
|
||||
UpdateState(GPUSTATE_INTERRUPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GE_CMD_FINISH:
|
||||
switch (currentList->signal) {
|
||||
case PSP_GE_SIGNAL_HANDLER_PAUSE:
|
||||
currentList->state = PSP_GE_DL_STATE_PAUSED;
|
||||
if (currentList->interruptsEnabled) {
|
||||
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
currentList->pendingInterrupt = true;
|
||||
UpdateState(GPUSTATE_INTERRUPT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PSP_GE_SIGNAL_SYNC:
|
||||
currentList->signal = PSP_GE_SIGNAL_NONE;
|
||||
// TODO: Technically this should still cause an interrupt. Probably for memory sync.
|
||||
break;
|
||||
|
||||
default:
|
||||
currentList->subIntrToken = prev & 0xFFFF;
|
||||
UpdateState(GPUSTATE_DONE);
|
||||
if (currentList->interruptsEnabled && __GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
currentList->pendingInterrupt = true;
|
||||
} else {
|
||||
currentList->state = PSP_GE_DL_STATE_COMPLETED;
|
||||
currentList->waitTicks = startingTicks + cyclesExecuted;
|
||||
busyTicks = std::max(busyTicks, currentList->waitTicks);
|
||||
__GeTriggerSync(GPU_SYNC_LIST, currentList->id, currentList->waitTicks);
|
||||
if (currentList->started && currentList->context.IsValid()) {
|
||||
gstate.Restore(currentList->context);
|
||||
ReapplyGfxStateInternal();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG(G3D,"Ah, not finished: %06x", prev & 0xFFFFFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GPUCommon::ExecuteOp(u32 op, u32 diff) {
|
||||
u32 cmd = op >> 24;
|
||||
u32 data = op & 0xFFFFFF;
|
||||
const u32 cmd = op >> 24;
|
||||
|
||||
// Handle control and drawing commands here directly. The others we delegate.
|
||||
switch (cmd) {
|
||||
@ -693,94 +933,27 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
|
||||
break;
|
||||
|
||||
case GE_CMD_OFFSETADDR:
|
||||
gstate_c.offsetAddr = data << 8;
|
||||
Execute_OffsetAddr(op, diff);
|
||||
break;
|
||||
|
||||
case GE_CMD_ORIGIN:
|
||||
{
|
||||
easy_guard guard(listLock);
|
||||
gstate_c.offsetAddr = currentList->pc;
|
||||
}
|
||||
Execute_Origin(op, diff);
|
||||
break;
|
||||
|
||||
case GE_CMD_JUMP:
|
||||
{
|
||||
easy_guard guard(listLock);
|
||||
u32 target = gstate_c.getRelativeAddress(data);
|
||||
if (Memory::IsValidAddress(target)) {
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
} else {
|
||||
ERROR_LOG_REPORT(G3D, "JUMP to illegal address %08x - ignoring! data=%06x", target, data);
|
||||
}
|
||||
}
|
||||
Execute_Jump(op, diff);
|
||||
break;
|
||||
|
||||
case GE_CMD_BJUMP:
|
||||
if (!currentList->bboxResult) {
|
||||
// bounding box jump.
|
||||
easy_guard guard(listLock);
|
||||
u32 target = gstate_c.getRelativeAddress(data);
|
||||
if (Memory::IsValidAddress(target)) {
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
} else {
|
||||
ERROR_LOG_REPORT(G3D, "BJUMP to illegal address %08x - ignoring! data=%06x", target, data);
|
||||
}
|
||||
}
|
||||
Execute_BJump(op, diff);
|
||||
break;
|
||||
|
||||
case GE_CMD_CALL:
|
||||
{
|
||||
easy_guard guard(listLock);
|
||||
|
||||
// Saint Seiya needs correct support for relative calls.
|
||||
u32 retval = currentList->pc + 4;
|
||||
u32 target = gstate_c.getRelativeAddress(data);
|
||||
|
||||
// Bone matrix optimization - many games will CALL a bone matrix (!).
|
||||
if ((Memory::ReadUnchecked_U32(target) >> 24) == GE_CMD_BONEMATRIXDATA) {
|
||||
// Check for the end
|
||||
if ((Memory::ReadUnchecked_U32(target + 11 * 4) >> 24) == GE_CMD_BONEMATRIXDATA &&
|
||||
(Memory::ReadUnchecked_U32(target + 12 * 4) >> 24) == GE_CMD_RET) {
|
||||
// Yep, pretty sure this is a bone matrix call.
|
||||
FastLoadBoneMatrix(target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) {
|
||||
ERROR_LOG_REPORT(G3D, "CALL: Stack full!");
|
||||
} else if (!Memory::IsValidAddress(target)) {
|
||||
ERROR_LOG_REPORT(G3D, "CALL to illegal address %08x - ignoring! data=%06x", target, data);
|
||||
} else {
|
||||
auto &stackEntry = currentList->stack[currentList->stackptr++];
|
||||
stackEntry.pc = retval;
|
||||
stackEntry.offsetAddr = gstate_c.offsetAddr;
|
||||
// The base address is NOT saved/restored for a regular call.
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4; // pc will be increased after we return, counteract that
|
||||
}
|
||||
}
|
||||
Execute_Call(op, diff);
|
||||
break;
|
||||
|
||||
case GE_CMD_RET:
|
||||
{
|
||||
easy_guard guard(listLock);
|
||||
if (currentList->stackptr == 0) {
|
||||
DEBUG_LOG_REPORT(G3D, "RET: Stack empty!");
|
||||
} else {
|
||||
auto &stackEntry = currentList->stack[--currentList->stackptr];
|
||||
gstate_c.offsetAddr = stackEntry.offsetAddr;
|
||||
u32 target = (currentList->pc & 0xF0000000) | (stackEntry.pc & 0x0FFFFFFF);
|
||||
UpdatePC(currentList->pc, target - 4);
|
||||
currentList->pc = target - 4;
|
||||
if (!Memory::IsValidAddress(currentList->pc)) {
|
||||
ERROR_LOG_REPORT(G3D, "Invalid DL PC %08x on return", currentList->pc);
|
||||
UpdateState(GPUSTATE_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
Execute_Ret(op, diff);
|
||||
break;
|
||||
|
||||
case GE_CMD_SIGNAL:
|
||||
@ -788,160 +961,9 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
|
||||
// Processed in GE_END.
|
||||
break;
|
||||
|
||||
case GE_CMD_END: {
|
||||
easy_guard guard(listLock);
|
||||
u32 prev = Memory::ReadUnchecked_U32(currentList->pc - 4);
|
||||
UpdatePC(currentList->pc);
|
||||
switch (prev >> 24) {
|
||||
case GE_CMD_SIGNAL:
|
||||
{
|
||||
// TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935#
|
||||
SignalBehavior behaviour = static_cast<SignalBehavior>((prev >> 16) & 0xFF);
|
||||
int signal = prev & 0xFFFF;
|
||||
int enddata = data & 0xFFFF;
|
||||
bool trigger = true;
|
||||
currentList->subIntrToken = signal;
|
||||
|
||||
switch (behaviour) {
|
||||
case PSP_GE_SIGNAL_HANDLER_SUSPEND:
|
||||
// Suspend the list, and call the signal handler. When it's done, resume.
|
||||
// Before sdkver 0x02000010, listsync should return paused.
|
||||
if (sceKernelGetCompiledSdkVersion() <= 0x02000010)
|
||||
currentList->state = PSP_GE_DL_STATE_PAUSED;
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal with wait. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_HANDLER_CONTINUE:
|
||||
// Resume the list right away, then call the handler.
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal without wait. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_HANDLER_PAUSE:
|
||||
// Pause the list instead of ending at the next FINISH.
|
||||
// Call the handler with the PAUSE signal value at that FINISH.
|
||||
// Technically, this ought to trigger an interrupt, but it won't do anything.
|
||||
// But right now, signal is always reset by interrupts, so that causes pause to not work.
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal with Pause. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_SYNC:
|
||||
// Acts as a memory barrier, never calls any user code.
|
||||
// Technically, this ought to trigger an interrupt, but it won't do anything.
|
||||
// Triggering here can cause incorrect rescheduling, which breaks 3rd Birthday.
|
||||
// However, this is likely a bug in how GE signal interrupts are handled.
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
DEBUG_LOG(G3D, "Signal with Sync. signal/end: %04x %04x", signal, enddata);
|
||||
break;
|
||||
case PSP_GE_SIGNAL_JUMP:
|
||||
{
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
// pc will be increased after we return, counteract that.
|
||||
u32 target = ((signal << 16) | enddata) - 4;
|
||||
if (!Memory::IsValidAddress(target)) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Jump: bad address. signal/end: %04x %04x", signal, enddata);
|
||||
} else {
|
||||
UpdatePC(currentList->pc, target);
|
||||
currentList->pc = target;
|
||||
DEBUG_LOG(G3D, "Signal with Jump. signal/end: %04x %04x", signal, enddata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PSP_GE_SIGNAL_CALL:
|
||||
{
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
// pc will be increased after we return, counteract that.
|
||||
u32 target = ((signal << 16) | enddata) - 4;
|
||||
if (currentList->stackptr == ARRAY_SIZE(currentList->stack)) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Call: stack full. signal/end: %04x %04x", signal, enddata);
|
||||
} else if (!Memory::IsValidAddress(target)) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Call: bad address. signal/end: %04x %04x", signal, enddata);
|
||||
} else {
|
||||
// TODO: This might save/restore other state...
|
||||
auto &stackEntry = currentList->stack[currentList->stackptr++];
|
||||
stackEntry.pc = currentList->pc;
|
||||
stackEntry.offsetAddr = gstate_c.offsetAddr;
|
||||
stackEntry.baseAddr = gstate.base;
|
||||
UpdatePC(currentList->pc, target);
|
||||
currentList->pc = target;
|
||||
DEBUG_LOG(G3D, "Signal with Call. signal/end: %04x %04x", signal, enddata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PSP_GE_SIGNAL_RET:
|
||||
{
|
||||
trigger = false;
|
||||
currentList->signal = behaviour;
|
||||
if (currentList->stackptr == 0) {
|
||||
ERROR_LOG_REPORT(G3D, "Signal with Return: stack empty. signal/end: %04x %04x", signal, enddata);
|
||||
} else {
|
||||
// TODO: This might save/restore other state...
|
||||
auto &stackEntry = currentList->stack[--currentList->stackptr];
|
||||
gstate_c.offsetAddr = stackEntry.offsetAddr;
|
||||
gstate.base = stackEntry.baseAddr;
|
||||
UpdatePC(currentList->pc, stackEntry.pc);
|
||||
currentList->pc = stackEntry.pc;
|
||||
DEBUG_LOG(G3D, "Signal with Return. signal/end: %04x %04x", signal, enddata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG_REPORT(G3D, "UNKNOWN Signal UNIMPLEMENTED %i ! signal/end: %04x %04x", behaviour, signal, enddata);
|
||||
break;
|
||||
}
|
||||
// TODO: Technically, jump/call/ret should generate an interrupt, but before the pc change maybe?
|
||||
if (currentList->interruptsEnabled && trigger) {
|
||||
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
currentList->pendingInterrupt = true;
|
||||
UpdateState(GPUSTATE_INTERRUPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GE_CMD_FINISH:
|
||||
switch (currentList->signal) {
|
||||
case PSP_GE_SIGNAL_HANDLER_PAUSE:
|
||||
currentList->state = PSP_GE_DL_STATE_PAUSED;
|
||||
if (currentList->interruptsEnabled) {
|
||||
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
currentList->pendingInterrupt = true;
|
||||
UpdateState(GPUSTATE_INTERRUPT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PSP_GE_SIGNAL_SYNC:
|
||||
currentList->signal = PSP_GE_SIGNAL_NONE;
|
||||
// TODO: Technically this should still cause an interrupt. Probably for memory sync.
|
||||
break;
|
||||
|
||||
default:
|
||||
currentList->subIntrToken = prev & 0xFFFF;
|
||||
UpdateState(GPUSTATE_DONE);
|
||||
if (currentList->interruptsEnabled && __GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
|
||||
currentList->pendingInterrupt = true;
|
||||
} else {
|
||||
currentList->state = PSP_GE_DL_STATE_COMPLETED;
|
||||
currentList->waitTicks = startingTicks + cyclesExecuted;
|
||||
busyTicks = std::max(busyTicks, currentList->waitTicks);
|
||||
__GeTriggerSync(GPU_SYNC_LIST, currentList->id, currentList->waitTicks);
|
||||
if (currentList->started && currentList->context.IsValid()) {
|
||||
gstate.Restore(currentList->context);
|
||||
ReapplyGfxStateInternal();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG(G3D,"Ah, not finished: %06x", prev & 0xFFFFFF);
|
||||
break;
|
||||
}
|
||||
case GE_CMD_END:
|
||||
Execute_End(op, diff);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
DEBUG_LOG(G3D,"DL Unknown: %08x @ %08x", op, currentList == NULL ? 0 : currentList->pc);
|
||||
|
@ -52,6 +52,14 @@ public:
|
||||
virtual u32 Break(int mode);
|
||||
virtual void ReapplyGfxState();
|
||||
|
||||
void Execute_OffsetAddr(u32 op, u32 diff);
|
||||
void Execute_Origin(u32 op, u32 diff);
|
||||
void Execute_Jump(u32 op, u32 diff);
|
||||
void Execute_BJump(u32 op, u32 diff);
|
||||
void Execute_Call(u32 op, u32 diff);
|
||||
void Execute_Ret(u32 op, u32 diff);
|
||||
void Execute_End(u32 op, u32 diff);
|
||||
|
||||
virtual u64 GetTickEstimate() {
|
||||
#if defined(_M_X64) || defined(ANDROID)
|
||||
return curTickEst_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user