Don't trash a list the GE interrupt handler needs.

Even after it's marked COMPLETED, the CPU needs it to start and finish the
interrupt.  Fixes #2956, where an existing completed list was not having
its interrupt run correctly.
This commit is contained in:
Unknown W. Brackets 2013-09-01 10:16:29 -07:00
parent cfbf83eeab
commit 8998a1b303
3 changed files with 23 additions and 5 deletions

View File

@ -55,6 +55,11 @@ public:
{
GeInterruptData intrdata = ge_pending_cb.front();
DisplayList* dl = gpu->getList(intrdata.listid);
if (!dl->interruptsEnabled)
{
ERROR_LOG_REPORT(HLE, "Unable to run GE interrupt: list has interrupts disabled, should not happen");
return false;
}
if (dl == NULL)
{
@ -120,6 +125,11 @@ public:
ge_pending_cb.pop_front();
DisplayList* dl = gpu->getList(intrdata.listid);
if (!dl->interruptsEnabled)
{
ERROR_LOG_REPORT(HLE, "Unable to finish GE interrupt: list has interrupts disabled, should not happen");
return;
}
switch (dl->signal)
{

View File

@ -187,13 +187,13 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, bool head) {
// return 0x80000021;
//}
}
if (dls[i].state == PSP_GE_DL_STATE_NONE)
if (dls[i].state == PSP_GE_DL_STATE_NONE && !dls[i].pendingInterrupt)
{
// Prefer a list that isn't used
id = i;
break;
}
if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED && dls[i].waitTicks < currentTicks)
if (id < 0 && dls[i].state == PSP_GE_DL_STATE_COMPLETED && !dls[i].pendingInterrupt && dls[i].waitTicks < currentTicks)
{
id = i;
}
@ -806,8 +806,10 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
}
// 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))
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
currentList->pendingInterrupt = true;
UpdateState(GPUSTATE_INTERRUPT);
}
}
}
break;
@ -815,8 +817,10 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
switch (currentList->signal) {
case PSP_GE_SIGNAL_HANDLER_PAUSE:
if (currentList->interruptsEnabled) {
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted))
if (__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
currentList->pendingInterrupt = true;
UpdateState(GPUSTATE_INTERRUPT);
}
}
break;
@ -829,7 +833,9 @@ void GPUCommon::ExecuteOp(u32 op, u32 diff) {
currentList->subIntrToken = prev & 0xFFFF;
currentList->state = PSP_GE_DL_STATE_COMPLETED;
UpdateState(GPUSTATE_DONE);
if (!currentList->interruptsEnabled || !__GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
if (currentList->interruptsEnabled && __GeTriggerInterrupt(currentList->id, currentList->pc, startingTicks + cyclesExecuted)) {
currentList->pendingInterrupt = true;
} else {
currentList->waitTicks = startingTicks + cyclesExecuted;
busyTicks = std::max(busyTicks, currentList->waitTicks);
__GeTriggerSync(WAITTYPE_GELISTSYNC, currentList->id, currentList->waitTicks);
@ -883,6 +889,7 @@ void GPUCommon::InterruptEnd(int listid) {
isbreak = false;
DisplayList &dl = dls[listid];
dl.pendingInterrupt = false;
// TODO: Unless the signal handler could change it?
if (dl.state == PSP_GE_DL_STATE_COMPLETED || dl.state == PSP_GE_DL_STATE_NONE) {
dl.waitTicks = 0;

View File

@ -129,6 +129,7 @@ struct DisplayList
bool interrupted;
u64 waitTicks;
bool interruptsEnabled;
bool pendingInterrupt;
};
enum GPUInvalidationType {