summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/Src/CommandProcessor.cpp
diff options
context:
space:
mode:
authorskidau <skidau@gmail.com>2012-03-20 19:37:25 +1100
committerskidau <skidau@gmail.com>2012-03-20 19:37:25 +1100
commita60a0825a334e898832337ad4a66266a645241e9 (patch)
tree7f8d991c6265a0f65484613e8e016adc03df52f4 /Source/Core/VideoCommon/Src/CommandProcessor.cpp
parent14ea442382681567277e0cd0538d4537f434effe (diff)
parent20eca1bf7e2e02dd18229dc2b6b83935ce0d4047 (diff)
Merged 'FifoBusy' branch. Thanks
to marcosvitali. Added an external exception check when the CPU writes to the FIFO. This allows the CPU time to service FIFO overflows. Fixes random hangs caused by FIFO overflows and desyncs like in "The Last Story" and "Battalion Wars 2". Thanks to marcosvitali for the research. Added some code to unlink invalidated blocks so that the recompiled block can be linked (speed-up). This release still fixed the hangs produced by fifo overflow without sacrifice performance. For example you can test Tutorial moves at the beginning of The last history now is fluid 30/60. Fixed possibles random hangs in DC mode. Fixed hangs in DC mode in (Simpsons, Monkey Island, Pokemon XD, etc) Implemented accurate management of Pixel Engine Interrupts. Now the GPU loop is stopped when a PE Interrupt needs to be managed and resumed when Pixel Engine finish. Fixed Metroid Prime 3 and 2 desync. And other games with desync because of FIFO Reset. That happens because FIFO_RW_DISTANCE_HI must be written first, for checking fifo.CPReadWriteDistance == 0, so some fifo resets was not managed in the right way. Fixed Super Monkey Ball in some cases when the game write the WriteReadDistance need to be safe like the SafeCPRead. Improved the CheckException for the GatherPipe writes in JIT, now only the External Exceptions are processed. Fixed definitely Pokemon XD in dual core mode. This game is doing something not allowed. It attach to CPU the same fifo attached to the GPU in multibuffer mode. I added a check to prevent overwrite the GPU FIFO with the CPU FIFO. If the game do that on breakpoint the solution can fail. Fixed ReadWriteDistance calc when CPRead > CPWrite. Added Token and Finish cause to GP Jit checking. Additional cleanup in CommandProcessor. Fixes issue 5209 Fixes issue 5055 Fixes issue 4889 Fixes issue 4061 Fixes issue 4010 Fixes issue 3902
Diffstat (limited to 'Source/Core/VideoCommon/Src/CommandProcessor.cpp')
-rw-r--r--Source/Core/VideoCommon/Src/CommandProcessor.cpp116
1 files changed, 60 insertions, 56 deletions
diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp
index fc85b8e39d..a4dddf537f 100644
--- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp
+++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp
@@ -56,11 +56,12 @@ static bool bProcessFifoToLoWatermark = false;
static bool bProcessFifoAllDistance = false;
volatile bool isPossibleWaitingSetDrawDone = false;
+volatile bool isHiWatermarkActive = false;
volatile bool interruptSet= false;
volatile bool interruptWaiting= false;
volatile bool interruptTokenWaiting = false;
volatile bool interruptFinishWaiting = false;
-volatile bool OnOverflow = false;
+volatile bool waitingForPEInterruptDisable = false;
bool IsOnThread()
{
@@ -86,13 +87,12 @@ void DoState(PointerWrap &p)
p.Do(bProcessFifoToLoWatermark);
p.Do(bProcessFifoAllDistance);
-
+ p.Do(isHiWatermarkActive);
p.Do(isPossibleWaitingSetDrawDone);
p.Do(interruptSet);
p.Do(interruptWaiting);
p.Do(interruptTokenWaiting);
p.Do(interruptFinishWaiting);
- p.Do(OnOverflow);
}
inline void WriteLow (volatile u32& _reg, u16 lowbits) {Common::AtomicStore(_reg,(_reg & 0xFFFF0000) | lowbits);}
@@ -135,16 +135,14 @@ void Init()
bProcessFifoToLoWatermark = false;
bProcessFifoAllDistance = false;
isPossibleWaitingSetDrawDone = false;
- OnOverflow = false;
+ isHiWatermarkActive = false;
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
}
void Read16(u16& _rReturnValue, const u32 _Address)
{
-
INFO_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
- ProcessFifoEvents();
switch (_Address & 0xFFF)
{
case STATUS_REGISTER:
@@ -173,11 +171,23 @@ void Read16(u16& _rReturnValue, const u32 _Address)
case FIFO_LO_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPLoWatermark); return;
case FIFO_RW_DISTANCE_LO:
- _rReturnValue = ReadLow (fifo.CPReadWriteDistance);
+ if (IsOnThread())
+ if(fifo.CPWritePointer >= fifo.SafeCPReadPointer)
+ _rReturnValue = ReadLow (fifo.CPWritePointer - fifo.SafeCPReadPointer);
+ else
+ _rReturnValue = ReadLow (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32);
+ else
+ _rReturnValue = ReadLow (fifo.CPReadWriteDistance);
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_LO : %04x", _rReturnValue);
return;
case FIFO_RW_DISTANCE_HI:
- _rReturnValue = ReadHigh(fifo.CPReadWriteDistance);
+ if (IsOnThread())
+ if(fifo.CPWritePointer >= fifo.SafeCPReadPointer)
+ _rReturnValue = ReadHigh (fifo.CPWritePointer - fifo.SafeCPReadPointer);
+ else
+ _rReturnValue = ReadHigh (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32);
+ else
+ _rReturnValue = ReadHigh(fifo.CPReadWriteDistance);
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_HI : %04x", _rReturnValue);
return;
case FIFO_WRITE_POINTER_LO:
@@ -358,6 +368,7 @@ void Write16(const u16 _Value, const u32 _Address)
break;
case FIFO_READ_POINTER_HI:
WriteHigh((u32 &)fifo.CPReadPointer, _Value);
+ fifo.SafeCPReadPointer = fifo.CPReadPointer;
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI : %04x", _Value);
break;
@@ -390,10 +401,6 @@ void Write16(const u16 _Value, const u32 _Address)
case FIFO_RW_DISTANCE_HI:
WriteHigh((u32 &)fifo.CPReadWriteDistance, _Value);
- DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value);
- break;
- case FIFO_RW_DISTANCE_LO:
- WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0);
if (fifo.CPReadWriteDistance == 0)
{
GPFifo::ResetGatherPipe();
@@ -403,6 +410,10 @@ void Write16(const u16 _Value, const u32 _Address)
ResetVideoBuffer();
}
IncrementCheckContextId();
+ DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value);
+ break;
+ case FIFO_RW_DISTANCE_LO:
+ WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0);
DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_LO : %04x", _Value);
break;
@@ -412,7 +423,6 @@ void Write16(const u16 _Value, const u32 _Address)
if (!IsOnThread())
RunGpu();
- ProcessFifoEvents();
}
void Read32(u32& _rReturnValue, const u32 _Address)
@@ -434,6 +444,19 @@ void STACKALIGN GatherPipeBursted()
{
if (!IsOnThread())
RunGpu();
+ else
+ {
+ // In multibuffer mode is not allowed write in the same fifo attached to the GPU.
+ // Fix Pokemon XD in DC mode.
+ if((ProcessorInterface::Fifo_CPUEnd == fifo.CPEnd) && (ProcessorInterface::Fifo_CPUBase == fifo.CPBase)
+ && fifo.CPReadWriteDistance > 0)
+ {
+ waitingForPEInterruptDisable = true;
+ ProcessFifoAllDistance();
+ waitingForPEInterruptDisable = false;
+ }
+
+ }
return;
}
@@ -449,26 +472,7 @@ void STACKALIGN GatherPipeBursted()
Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE);
if (!IsOnThread())
- {
RunGpu();
- }
- else
- {
- if(fifo.CPReadWriteDistance == fifo.CPEnd - fifo.CPBase - 32)
- {
- if(!OnOverflow)
- NOTICE_LOG(COMMANDPROCESSOR,"FIFO is almost in overflown, BreakPoint: %i", fifo.bFF_Breakpoint);
- OnOverflow = true;
- while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
- fifo.CPReadWriteDistance > fifo.CPEnd - fifo.CPBase - 64)
- Common::YieldCPU();
- }
- else
- {
- OnOverflow = false;
- }
- }
-
_assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase,
"FIFO is overflown by GatherPipe !\nCPU thread is too fast!");
@@ -509,17 +513,15 @@ void AbortFrame()
void SetOverflowStatusFromGatherPipe()
{
- if (!fifo.bFF_HiWatermarkInt) return;
-
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
- fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
-
- bool interrupt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt &&
- m_CPCtrlReg.GPLinkEnable && m_CPCtrlReg.GPReadEnable;
+ isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable;
- if (interrupt != interruptSet && interrupt)
- CommandProcessor::UpdateInterrupts(true);
-
+ if (isHiWatermarkActive)
+ {
+ interruptSet = true;
+ INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
+ ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
+ }
}
void SetCpStatus()
@@ -527,14 +529,12 @@ void SetCpStatus()
// overflow & underflow check
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
-
- // breakpoint
+ // breakpoint
if (fifo.bFF_BPEnable)
{
if (fifo.CPBreakpoint == fifo.CPReadPointer)
- {
-
+ {
if (!fifo.bFF_Breakpoint)
{
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer);
@@ -562,13 +562,18 @@ void SetCpStatus()
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable;
+ isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable;
+
if (interrupt != interruptSet && !interruptWaiting)
{
u64 userdata = interrupt?1:0;
if (IsOnThread())
{
- interruptWaiting = true;
- CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
+ if(!interrupt || bpInt || undfInt)
+ {
+ interruptWaiting = true;
+ CommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
+ }
}
else
CommandProcessor::UpdateInterrupts(userdata);
@@ -591,7 +596,7 @@ void ProcessFifoAllDistance()
if (IsOnThread())
{
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
- fifo.CPReadWriteDistance && !AtBreakpoint())
+ fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt())
Common::YieldCPU();
}
bProcessFifoAllDistance = false;
@@ -611,13 +616,16 @@ void Shutdown()
void SetCpStatusRegister()
{
// Here always there is one fifo attached to the GPU
-
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
- m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint);
+ m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ;
m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance;
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark;
+ // HACK to compensate for slow response to PE interrupts in Time Splitters: Future Perfect
+ if (IsOnThread())
+ PixelEngine::ResumeWaitingForPEInterrupt();
+
INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex);
DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s"
, m_CPStatusReg.Breakpoint ? "ON" : "OFF"
@@ -630,14 +638,14 @@ void SetCpStatusRegister()
void SetCpControlRegister()
{
-
// If the new fifo is being attached We make sure there wont be SetFinish event pending.
// This protection fix eternal darkness booting, because the second SetFinish event when it is booting
// seems invalid or has a bug and hang the game.
if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable)
{
- PixelEngine::ResetSetFinish();
+ ProcessFifoEvents();
+ PixelEngine::ResetSetFinish();
}
fifo.bFF_BPInt = m_CPCtrlReg.BPInt;
@@ -652,9 +660,6 @@ void SetCpControlRegister()
ProcessorInterface::Fifo_CPUBase = fifo.CPBase;
ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd;
}
- // If overflown happens process the fifo to LoWatemark
- if (bProcessFifoToLoWatermark)
- ProcessFifoToLoWatermark();
if(fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable)
{
@@ -666,7 +671,6 @@ void SetCpControlRegister()
fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable;
}
-
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s"
, fifo.bFF_GPReadEnable ? "ON" : "OFF"
, fifo.bFF_BPEnable ? "ON" : "OFF"