BIG FIFO Commit PART 1! Sometimes you need to write everything from 0, so 10 days later Ive rewrited some parts of the FIFO in Dual Core mode. Is pending use the same code for SC mode.
- Improved the GP Register Status: now this is all the time from the fifo loop. - Improved the Interrupts manage: 1) Removed All UpdateInturrupts from CommandProcessor Writes and Read. 2) now the CP interrupts are schedule from the video thread and the fifo loop waiting until this happens 3) considering Inmediate mode for the CP interrupts 3) Implemented Interrupt CP Cache State 4) Implemented only Overflow interrupt in GatherPipeCheck because this need to be detected quickly. - Implemented Overflow handling like a real HW, when Hiwatermark interrupt happens this write ClearRegister with True en HI and False in LO (FifoIntReset) after that a Control Register is writed and the FIFO is processed to LO Watermark. - Removed all ugly code from LO and HI watermark manage - Removed all ugly code from BP manage - Change >= by == in the BP clauses - Removed speed hack (1024 chunk) for better GP Status Control. - Commented GXSetGPFifo very soon hack - Commented FackWatchDog hack - Commented FIFO_RW_DISTANCE = WritePointer hack This is the beginning and the base for the future., If this broke your favorite game my apologize, only report this and will try solve it. If you have a Overflown don't worry, I've implemented the real solution code using the Overflow Interruption only need continue working for a perfect protection. Why I did it? Because is preferable a accurate and clean fifo instead hack y fifo for improve that. Thanks to DONKO for you awesome Video Plug in and skid for the chatting. PD: I have 7-10 fps more in the star fox video. bye :P git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6554 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
24569aca3d
commit
a9ca9cfd9b
|
@ -73,7 +73,7 @@
|
|||
#include "MathUtil.h"
|
||||
#include "Thread.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
#include "OpcodeDecoding.h"
|
||||
#include "Fifo.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "CommandProcessor.h"
|
||||
|
@ -84,9 +84,10 @@ namespace CommandProcessor
|
|||
|
||||
int et_UpdateInterrupts;
|
||||
|
||||
|
||||
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
|
||||
{
|
||||
UpdateInterrupts();
|
||||
UpdateInterrupts(userdata);
|
||||
}
|
||||
|
||||
// look for 1002 verts, breakpoint there, see why next draw is flushed
|
||||
|
@ -109,8 +110,12 @@ u16 m_tokenReg;
|
|||
static u32 fake_GPWatchdogLastToken = 0;
|
||||
static Common::EventEx s_fifoIdleEvent;
|
||||
static Common::CriticalSection sFifoCritical;
|
||||
static bool bProcessFifoToLoWatemark = false;
|
||||
|
||||
volatile bool isFifoBusy = false; //This state is changed when the FIFO is processing data.
|
||||
volatile bool interruptSet= false;
|
||||
volatile bool interruptWaiting= false;
|
||||
|
||||
|
||||
void FifoCriticalEnter()
|
||||
{
|
||||
|
@ -163,8 +168,15 @@ void Init()
|
|||
|
||||
memset(&fifo,0,sizeof(fifo));
|
||||
fifo.CPCmdIdle = 1 ;
|
||||
fifo.CPReadIdle = 1; // We use it as UnderFlow flag now, otherwise we need a new volatile variable
|
||||
fifo.CPReadIdle = 1;
|
||||
fifo.bFF_Breakpoint = 0;
|
||||
fifo.bFF_HiWatermark = 0;
|
||||
fifo.bFF_HiWatermarkInt = 0;
|
||||
fifo.bFF_LoWatermark = 0;
|
||||
fifo.bFF_LoWatermarkInt = 0;
|
||||
|
||||
interruptSet = false;
|
||||
interruptWaiting = false;
|
||||
|
||||
s_fifoIdleEvent.Init();
|
||||
|
||||
|
@ -178,19 +190,30 @@ void Shutdown()
|
|||
|
||||
void Read16(u16& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
|
||||
switch (_Address & 0xFFF)
|
||||
{
|
||||
case STATUS_REGISTER:
|
||||
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
|
||||
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || !fifo.bFF_GPReadEnable;
|
||||
m_CPStatusReg.CommandIdle = fifo.CPCmdIdle;
|
||||
m_CPStatusReg.UnderflowLoWatermark = fifo.CPReadIdle;
|
||||
|
||||
// hack: CPU will always believe fifo is empty and on idle
|
||||
//m_CPStatusReg.ReadIdle = 1;
|
||||
//m_CPStatusReg.CommandIdle = 1;
|
||||
|
||||
// Here always there is one fifo attached to the GPU
|
||||
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
|
||||
m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint);
|
||||
m_CPStatusReg.CommandIdle = fifo.CPCmdIdle;
|
||||
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
|
||||
m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single Core MODE
|
||||
m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint;
|
||||
m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || !fifo.bFF_GPReadEnable;
|
||||
m_CPStatusReg.CommandIdle = fifo.CPCmdIdle;
|
||||
m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark;
|
||||
}
|
||||
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"
|
||||
|
@ -249,15 +272,15 @@ void Read16(u16& _rReturnValue, const u32 _Address)
|
|||
return;
|
||||
|
||||
case FIFO_READ_POINTER_LO:
|
||||
//_rReturnValue = ReadLow (fifo.CPReadPointer);
|
||||
_rReturnValue = ReadLow (fifo.CPReadPointer);
|
||||
// hack: CPU will always believe fifo is empty and on idle
|
||||
_rReturnValue = ReadLow (fifo.CPWritePointer);
|
||||
//_rReturnValue = ReadLow (fifo.CPWritePointer);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_READ_POINTER_LO : %04x", _rReturnValue);
|
||||
return;
|
||||
case FIFO_READ_POINTER_HI:
|
||||
//_rReturnValue = ReadHigh(fifo.CPReadPointer);
|
||||
_rReturnValue = ReadHigh(fifo.CPReadPointer);
|
||||
// hack: CPU will always believe fifo is empty and on idle
|
||||
_rReturnValue = ReadHigh(fifo.CPWritePointer);
|
||||
//_rReturnValue = ReadHigh(fifo.CPWritePointer);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_READ_POINTER_HI : %04x", _rReturnValue);
|
||||
return;
|
||||
|
||||
|
@ -344,6 +367,7 @@ void Read16(u16& _rReturnValue, const u32 _Address)
|
|||
|
||||
void Write16(const u16 _Value, const u32 _Address)
|
||||
{
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR, "(write16): 0x%04x @ 0x%08x",_Value,_Address);
|
||||
|
||||
// Force complete fifo flush if we attempt to set/reset the fifo (API GXSetGPFifo or equivalent)
|
||||
|
@ -378,8 +402,8 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
while (fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance)
|
||||
s_fifoIdleEvent.Wait();
|
||||
|
||||
//ProcessFifoAllDistance();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -401,22 +425,25 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
{
|
||||
UCPCtrlReg tmpCtrl(_Value);
|
||||
m_CPCtrlReg.Hex = tmpCtrl.Hex;
|
||||
u32 tmpFifoGPReadEnable = fifo.bFF_GPReadEnable;
|
||||
|
||||
if((fifo.bFF_GPReadEnable && !tmpCtrl.GPReadEnable) || (fifo.bFF_BPInt && !tmpCtrl.BPInt))
|
||||
Common::AtomicStore(fifo.bFF_Breakpoint, false);
|
||||
|
||||
if (tmpCtrl.FifoUnderflowIntEnable)
|
||||
Common::AtomicStore(fifo.CPReadIdle, false);
|
||||
|
||||
if (tmpCtrl.FifoOverflowIntEnable)
|
||||
m_CPStatusReg.OverflowHiWatermark = false;
|
||||
|
||||
UpdateInterrupts();
|
||||
|
||||
// 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.
|
||||
|
||||
// Single Core MODE
|
||||
if (!g_VideoInitialize.bOnThread)
|
||||
{
|
||||
|
||||
Common::AtomicStore(fifo.bFF_Breakpoint, false);
|
||||
if (tmpCtrl.FifoUnderflowIntEnable)
|
||||
Common::AtomicStore(fifo.bFF_LoWatermark, false);
|
||||
|
||||
if (tmpCtrl.FifoOverflowIntEnable)
|
||||
m_CPStatusReg.OverflowHiWatermark = false;
|
||||
|
||||
UpdateInterruptsScMode();
|
||||
}
|
||||
|
||||
if (!fifo.bFF_GPReadEnable && tmpCtrl.GPReadEnable && !tmpCtrl.BPEnable)
|
||||
{
|
||||
PixelEngine::ResetSetFinish();
|
||||
|
@ -424,22 +451,13 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
|
||||
fifo.bFF_BPInt = tmpCtrl.BPInt;
|
||||
fifo.bFF_BPEnable = tmpCtrl.BPEnable;
|
||||
if(tmpFifoGPReadEnable == fifo.bFF_GPReadEnable)
|
||||
{
|
||||
fifo.bFF_GPReadEnable = tmpCtrl.GPReadEnable;
|
||||
|
||||
if (fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance >= fifo.CPHiWatermark))
|
||||
{
|
||||
// A little trick to prevent FIFO from overflown in dual core mode
|
||||
while (fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance >= fifo.CPHiWatermark))
|
||||
Common::YieldCPU();
|
||||
|
||||
if (!m_CPStatusReg.OverflowHiWatermark)
|
||||
m_CPStatusReg.OverflowHiWatermark = true;
|
||||
}
|
||||
fifo.bFF_GPReadEnable = tmpCtrl.GPReadEnable;
|
||||
fifo.bFF_HiWatermarkInt = tmpCtrl.FifoOverflowIntEnable;
|
||||
fifo.bFF_LoWatermarkInt = tmpCtrl.FifoUnderflowIntEnable;
|
||||
|
||||
|
||||
}
|
||||
// If overflown happens process the fifo to LoWatemark
|
||||
if (bProcessFifoToLoWatemark)
|
||||
ProcessFifoToLoWatemark();
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR,"\t Write to CTRL_REGISTER : %04x", _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s"
|
||||
|
@ -456,11 +474,24 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
case CLEAR_REGISTER:
|
||||
{
|
||||
UCPClearReg tmpCtrl(_Value);
|
||||
if (tmpCtrl.ClearFifoOverflow)
|
||||
m_CPStatusReg.OverflowHiWatermark = false;
|
||||
if (tmpCtrl.ClearFifoUnderflow)
|
||||
Common::AtomicStore(fifo.CPReadIdle, false);
|
||||
UpdateInterrupts();
|
||||
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
if (!tmpCtrl.ClearFifoUnderflow && tmpCtrl.ClearFifoOverflow)
|
||||
bProcessFifoToLoWatemark = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single Core MODE
|
||||
if (tmpCtrl.ClearFifoOverflow)
|
||||
m_CPStatusReg.OverflowHiWatermark = false;
|
||||
if (tmpCtrl.ClearFifoUnderflow)
|
||||
Common::AtomicStore(fifo.bFF_LoWatermark, false);
|
||||
UpdateInterruptsScMode();
|
||||
}
|
||||
|
||||
|
||||
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x", _Value);
|
||||
}
|
||||
break;
|
||||
|
@ -519,8 +550,6 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
break;
|
||||
case FIFO_HI_WATERMARK_HI:
|
||||
WriteHigh((u32 &)fifo.CPHiWatermark, _Value);
|
||||
// Tune this when you see lots of FIFO overflown by GatherPipe
|
||||
//HiWatermark_Tighter = fifo.CPHiWatermark - 32 * g_ActiveConfig.iFIFOWatermarkTightness;
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_HI_WATERMARK_HI : %04x", _Value);
|
||||
break;
|
||||
|
||||
|
@ -561,6 +590,8 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||
|
||||
if (!g_VideoInitialize.bOnThread)
|
||||
CatchUpGPU();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
|
@ -580,34 +611,34 @@ void IncrementGPWDToken()
|
|||
Common::AtomicIncrement(fifo.Fake_GPWDToken);
|
||||
}
|
||||
|
||||
bool AllowIdleSkipping()
|
||||
{
|
||||
return !g_VideoInitialize.bOnThread || !m_CPCtrlReg.BPEnable;
|
||||
}
|
||||
|
||||
// Check every FAKE_GP_WATCHDOG_PERIOD if a PE-frame-finish occurred
|
||||
// if not then lock CPUThread until GP finish a frame.
|
||||
void WaitForFrameFinish()
|
||||
{
|
||||
while ((fake_GPWatchdogLastToken == fifo.Fake_GPWDToken) && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance)
|
||||
{
|
||||
s_fifoIdleEvent.Wait();
|
||||
}
|
||||
|
||||
fake_GPWatchdogLastToken = fifo.Fake_GPWDToken;
|
||||
//while ((fake_GPWatchdogLastToken == fifo.Fake_GPWDToken) && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance)
|
||||
//{
|
||||
// s_fifoIdleEvent.Wait();
|
||||
//}
|
||||
|
||||
//fake_GPWatchdogLastToken = fifo.Fake_GPWDToken;
|
||||
}
|
||||
|
||||
void STACKALIGN GatherPipeBursted()
|
||||
{
|
||||
|
||||
// if we aren't linked, we don't care about gather pipe data
|
||||
if (!m_CPCtrlReg.GPLinkEnable)
|
||||
{
|
||||
if (!g_VideoInitialize.bOnThread)
|
||||
CatchUpGPU();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
SetOverflowStatusFromGatherPipe();
|
||||
|
||||
|
||||
// update the fifo-pointer
|
||||
if (fifo.CPWritePointer >= fifo.CPEnd)
|
||||
fifo.CPWritePointer = fifo.CPBase;
|
||||
|
@ -616,38 +647,22 @@ void STACKALIGN GatherPipeBursted()
|
|||
|
||||
Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE);
|
||||
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
|
||||
if (fifo.CPReadWriteDistance >= fifo.CPHiWatermark)
|
||||
{
|
||||
// A little trick to prevent FIFO from overflown in dual core mode
|
||||
while (fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance >= fifo.CPHiWatermark))
|
||||
Common::YieldCPU();
|
||||
|
||||
if (!m_CPStatusReg.OverflowHiWatermark)
|
||||
{
|
||||
m_CPStatusReg.OverflowHiWatermark = true;
|
||||
if (m_CPCtrlReg.FifoOverflowIntEnable)
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
|
||||
if (!g_VideoInitialize.bOnThread)
|
||||
{
|
||||
CatchUpGPU();
|
||||
if (!m_CPStatusReg.OverflowHiWatermark && fifo.CPReadWriteDistance >= fifo.CPHiWatermark)
|
||||
{
|
||||
m_CPStatusReg.OverflowHiWatermark = true;
|
||||
if (m_CPCtrlReg.FifoOverflowIntEnable)
|
||||
UpdateInterrupts();
|
||||
}
|
||||
UpdateInterruptsScMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase,
|
||||
"FIFO is overflown by GatherPipe !\nCPU thread is too fast, try changing the watermark tightness in the game properties.");
|
||||
"FIFO is overflown by GatherPipe !\nCPU thread is too fast, try changing the watermark tightness in the game properties.");
|
||||
|
||||
// check if we are in sync
|
||||
_assert_msg_(COMMANDPROCESSOR, fifo.CPWritePointer == *(g_VideoInitialize.Fifo_CPUWritePointer), "FIFOs linked but out of sync");
|
||||
|
@ -655,6 +670,7 @@ void STACKALIGN GatherPipeBursted()
|
|||
_assert_msg_(COMMANDPROCESSOR, fifo.CPEnd == *(g_VideoInitialize.Fifo_CPUEnd), "FIFOs linked but out of sync");
|
||||
}
|
||||
|
||||
|
||||
// This is only used in single core mode
|
||||
void CatchUpGPU()
|
||||
{
|
||||
|
@ -672,7 +688,7 @@ void CatchUpGPU()
|
|||
Common::AtomicStore(fifo.bFF_GPReadEnable, false);
|
||||
Common::AtomicStore(fifo.bFF_Breakpoint, true);
|
||||
if (fifo.bFF_BPInt)
|
||||
UpdateInterrupts();
|
||||
UpdateInterruptsScMode();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -681,6 +697,7 @@ void CatchUpGPU()
|
|||
SaveSSEState();
|
||||
LoadDefaultSSEState();
|
||||
Fifo_SendFifoData(ptr,32);
|
||||
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||
LoadSSEState();
|
||||
|
||||
// increase the ReadPtr
|
||||
|
@ -698,26 +715,48 @@ void CatchUpGPU()
|
|||
fifo.CPReadWriteDistance -= 32;
|
||||
}
|
||||
|
||||
if (!fifo.CPReadIdle && fifo.CPReadWriteDistance < fifo.CPLoWatermark)
|
||||
if (!fifo.bFF_LoWatermark && fifo.CPReadWriteDistance < fifo.CPLoWatermark)
|
||||
{
|
||||
Common::AtomicStore(fifo.CPReadIdle, true);
|
||||
Common::AtomicStore(fifo.bFF_LoWatermark, true);
|
||||
if (m_CPCtrlReg.FifoUnderflowIntEnable)
|
||||
UpdateInterrupts();
|
||||
UpdateInterruptsScMode();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
void UpdateInterruptsScMode()
|
||||
{
|
||||
bool active = (fifo.bFF_BPInt && fifo.bFF_Breakpoint)
|
||||
|| (m_CPCtrlReg.FifoUnderflowIntEnable && fifo.CPReadIdle)
|
||||
|| (m_CPCtrlReg.FifoUnderflowIntEnable && fifo.bFF_LoWatermark)
|
||||
|| (m_CPCtrlReg.FifoOverflowIntEnable && m_CPStatusReg.OverflowHiWatermark);
|
||||
INFO_LOG(COMMANDPROCESSOR, "Fifo Interrupt: %s", (active)? "Asserted" : "Deasserted");
|
||||
g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, active);
|
||||
}
|
||||
|
||||
void UpdateInterruptsFromVideoPlugin()
|
||||
|
||||
|
||||
void UpdateInterrupts(u64 userdata)
|
||||
{
|
||||
g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, 0);
|
||||
if (userdata)
|
||||
{
|
||||
interruptSet = true;
|
||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||
g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!fifo.bFF_Breakpoint)
|
||||
{
|
||||
interruptSet = false;
|
||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared %i %i %i %i", fifo.CPReadPointer, fifo.CPBreakpoint, fifo.CPWritePointer, fifo.CPReadWriteDistance);
|
||||
g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, false);
|
||||
}
|
||||
}
|
||||
interruptWaiting = false;
|
||||
}
|
||||
|
||||
void UpdateInterruptsFromVideoPlugin(u64 userdata)
|
||||
{
|
||||
g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata);
|
||||
}
|
||||
|
||||
void SetFifoIdleFromVideoPlugin()
|
||||
|
@ -731,12 +770,102 @@ void SetFifoIdleFromVideoPlugin()
|
|||
// to 0 when PI_FIFO_RESET occurs.
|
||||
void AbortFrame()
|
||||
{
|
||||
|
||||
Fifo_SetRendering(false);
|
||||
while(!fifo.CPCmdIdle)
|
||||
Common::YieldCPU();
|
||||
ProcessFifoAllDistance();
|
||||
Fifo_SetRendering(true);
|
||||
PixelEngine::ResetSetToken();
|
||||
PixelEngine::ResetSetFinish();
|
||||
}
|
||||
|
||||
void SetOverflowStatusFromGatherPipe()
|
||||
{
|
||||
if (!fifo.bFF_HiWatermarkInt) return;
|
||||
|
||||
// overflow check
|
||||
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;
|
||||
|
||||
if (interrupt != interruptSet && interrupt)
|
||||
CommandProcessor::UpdateInterrupts(true);
|
||||
|
||||
}
|
||||
|
||||
void SetStatus()
|
||||
{
|
||||
// overflow check
|
||||
fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark);
|
||||
fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark);
|
||||
|
||||
// breakpoint
|
||||
|
||||
if (fifo.bFF_BPEnable)
|
||||
{
|
||||
if (fifo.CPBreakpoint == fifo.CPReadPointer)
|
||||
{
|
||||
|
||||
if (!fifo.bFF_Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fifo.bFF_Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fifo.bFF_Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i %i", fifo.CPReadPointer);
|
||||
fifo.bFF_Breakpoint = false;
|
||||
}
|
||||
|
||||
bool bpInt = fifo.bFF_Breakpoint && fifo.bFF_BPInt;
|
||||
bool ovfInt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt;
|
||||
bool undfInt = fifo.bFF_LoWatermark && fifo.bFF_LoWatermarkInt;
|
||||
|
||||
bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPLinkEnable && m_CPCtrlReg.GPReadEnable;
|
||||
|
||||
if (interrupt != interruptSet && !interruptWaiting)
|
||||
{
|
||||
u64 userdata = interrupt?1:0;
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
interruptWaiting = true;
|
||||
CommandProcessor::UpdateInterruptsFromVideoPlugin(userdata);
|
||||
}
|
||||
else
|
||||
CommandProcessor::UpdateInterrupts(userdata);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessFifoToLoWatemark()
|
||||
{
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
||||
fifo.CPReadWriteDistance > fifo.CPLoWatermark && !AtBreakpoint())
|
||||
Common::YieldCPU();
|
||||
}
|
||||
bProcessFifoToLoWatemark = false;
|
||||
}
|
||||
|
||||
void ProcessFifoAllDistance()
|
||||
{
|
||||
if (g_VideoInitialize.bOnThread)
|
||||
{
|
||||
while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable &&
|
||||
fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||
Common::YieldCPU();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace CommandProcessor
|
||||
|
|
|
@ -31,6 +31,9 @@ namespace CommandProcessor
|
|||
|
||||
extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread.
|
||||
extern volatile bool isFifoBusy; //This one is used for sync gfx thread and emulator thread.
|
||||
extern volatile bool interruptSet;
|
||||
extern volatile bool interruptWaiting;
|
||||
|
||||
// internal hardware addresses
|
||||
enum
|
||||
{
|
||||
|
@ -147,10 +150,12 @@ void Write32(const u32 _Data, const u32 _Address);
|
|||
|
||||
// for CGPFIFO
|
||||
void CatchUpGPU();
|
||||
void SetStatus();
|
||||
void GatherPipeBursted();
|
||||
void UpdateFifoRegister();
|
||||
void UpdateInterrupts();
|
||||
void UpdateInterruptsFromVideoPlugin();
|
||||
void UpdateInterrupts(u64 userdata);
|
||||
void UpdateInterruptsFromVideoPlugin(u64 userdata);
|
||||
void UpdateInterruptsScMode();
|
||||
void SetFifoIdleFromVideoPlugin();
|
||||
|
||||
bool AllowIdleSkipping();
|
||||
|
@ -162,6 +167,9 @@ void WaitForFrameFinish();
|
|||
void FifoCriticalEnter();
|
||||
void FifoCriticalLeave();
|
||||
|
||||
void SetOverflowStatusFromGatherPipe();
|
||||
void ProcessFifoToLoWatemark();
|
||||
void ProcessFifoAllDistance();
|
||||
void AbortFrame();
|
||||
} // namespace CommandProcessor
|
||||
|
||||
|
|
|
@ -127,13 +127,14 @@ void Fifo_SendFifoData(u8* _uData, u32 len)
|
|||
// Copy new video instructions to videoBuffer for future use in rendering the new picture
|
||||
memcpy(videoBuffer + size, _uData, len);
|
||||
size += len;
|
||||
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||
}
|
||||
|
||||
|
||||
// Description: Main FIFO update loop
|
||||
// Purpose: Keep the Core HW updated about the CPU-GPU distance
|
||||
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
||||
{
|
||||
|
||||
fifoStateRun = true;
|
||||
SCPFifoStruct &_fifo = CommandProcessor::fifo;
|
||||
s32 distToSend;
|
||||
|
@ -146,67 +147,48 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||
|
||||
// check if we are able to run this buffer
|
||||
|
||||
while (_fifo.bFF_GPReadEnable && (_fifo.CPReadWriteDistance || (_fifo.bFF_BPEnable && ((_fifo.CPReadPointer <= _fifo.CPBreakpoint) && (_fifo.CPReadPointer + 32 > _fifo.CPBreakpoint)))))
|
||||
CommandProcessor::SetStatus();
|
||||
|
||||
while (!CommandProcessor::interruptWaiting && _fifo.bFF_GPReadEnable &&
|
||||
_fifo.CPReadWriteDistance && !AtBreakpoint())
|
||||
{
|
||||
// while the FIFO is processing data we activate this for sync with emulator thread.
|
||||
CommandProcessor::isFifoBusy = true;
|
||||
|
||||
|
||||
if (!fifoStateRun)
|
||||
break;
|
||||
if (!fifoStateRun) break;
|
||||
|
||||
_fifo.CPCmdIdle = false;
|
||||
|
||||
CommandProcessor::FifoCriticalEnter();
|
||||
// Create pointer to video data and send it to the VideoPlugin
|
||||
u32 readPtr = _fifo.CPReadPointer;
|
||||
u8 *uData = video_initialize.pGetMemoryPointer(readPtr);
|
||||
// DEBUG_LOG(BOOT, "readPtr: %08x uData %08x", readPtr, uData);
|
||||
|
||||
// If we are in BP mode we only send 32B chunks to Video plugin for BP checking
|
||||
if (_fifo.bFF_BPEnable)
|
||||
{
|
||||
if ((readPtr <= _fifo.CPBreakpoint) && (readPtr + 32 > _fifo.CPBreakpoint))
|
||||
{
|
||||
Common::AtomicStore(_fifo.bFF_GPReadEnable, false);
|
||||
Common::AtomicStore(_fifo.bFF_Breakpoint, true);
|
||||
if (_fifo.bFF_BPInt)
|
||||
CommandProcessor::UpdateInterruptsFromVideoPlugin();
|
||||
CommandProcessor::FifoCriticalLeave();
|
||||
CommandProcessor::isFifoBusy = false;
|
||||
break;
|
||||
}
|
||||
distToSend = 32;
|
||||
|
||||
distToSend = 32;
|
||||
if (readPtr >= _fifo.CPEnd)
|
||||
readPtr = _fifo.CPBase;
|
||||
else
|
||||
readPtr += 32;
|
||||
}
|
||||
// If we are not in BP mode we send all the chunk we have to speed up
|
||||
if (readPtr == _fifo.CPEnd)
|
||||
readPtr = _fifo.CPBase;
|
||||
else
|
||||
{
|
||||
distToSend = _fifo.CPReadWriteDistance;
|
||||
// send 1024B chunk max length to have better control over PeekMessages' period
|
||||
distToSend = distToSend > 1024 ? 1024 : distToSend;
|
||||
if (readPtr + distToSend >= _fifo.CPEnd + 32)
|
||||
{
|
||||
distToSend = _fifo.CPEnd + 32 - readPtr;
|
||||
readPtr = _fifo.CPBase;
|
||||
}
|
||||
else
|
||||
readPtr += distToSend;
|
||||
}
|
||||
|
||||
readPtr += 32;
|
||||
|
||||
_assert_msg_(COMMANDPROCESSOR, (s32)_fifo.CPReadWriteDistance - distToSend >= 0 ,
|
||||
"Negative fifo.CPReadWriteDistance = %i in FIFO Loop !\nThat can produce inestabilty in the game. Please report it.", _fifo.CPReadWriteDistance - distToSend);
|
||||
|
||||
Common::AtomicStore(_fifo.CPReadPointer, readPtr);
|
||||
Common::AtomicAdd(_fifo.CPReadWriteDistance, -distToSend);
|
||||
|
||||
// Execute new instructions found in uData
|
||||
Fifo_SendFifoData(uData, distToSend);
|
||||
|
||||
|
||||
Fifo_SendFifoData(uData, distToSend);
|
||||
Common::AtomicStore(_fifo.CPReadPointer, readPtr);
|
||||
Common::AtomicAdd(_fifo.CPReadWriteDistance, -distToSend);
|
||||
|
||||
CommandProcessor::isFifoBusy = true;
|
||||
CommandProcessor::SetStatus();
|
||||
|
||||
_fifo.CPCmdIdle = false;
|
||||
|
||||
OpcodeDecoder_Run(g_bSkipCurrentFrame);
|
||||
|
||||
_fifo.CPCmdIdle = true;
|
||||
|
||||
CommandProcessor::isFifoBusy = false;
|
||||
CommandProcessor::FifoCriticalLeave();
|
||||
|
||||
// Those two are pretty important and must be called in the FIFO Loop.
|
||||
|
@ -214,17 +196,10 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||
// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down.
|
||||
|
||||
VideoFifo_CheckAsyncRequest();
|
||||
CommandProcessor::isFifoBusy = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!_fifo.CPReadIdle && _fifo.CPReadWriteDistance < _fifo.CPLoWatermark)
|
||||
{
|
||||
Common::AtomicStore(_fifo.CPReadIdle, true);
|
||||
CommandProcessor::UpdateInterruptsFromVideoPlugin();
|
||||
}
|
||||
|
||||
_fifo.CPCmdIdle = true;
|
||||
CommandProcessor::SetFifoIdleFromVideoPlugin();
|
||||
if (EmuRunning)
|
||||
Common::YieldCPU();
|
||||
|
@ -233,3 +208,9 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool AtBreakpoint()
|
||||
{
|
||||
SCPFifoStruct &_fifo = CommandProcessor::fifo;
|
||||
return _fifo.bFF_BPEnable && (_fifo.CPReadPointer == _fifo.CPBreakpoint);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ class PointerWrap;
|
|||
|
||||
extern volatile bool g_bSkipCurrentFrame;
|
||||
|
||||
|
||||
void Fifo_Init();
|
||||
void Fifo_Shutdown();
|
||||
|
||||
|
@ -37,7 +38,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize);
|
|||
void Fifo_ExitLoop();
|
||||
void Fifo_ExitLoopNonBlocking();
|
||||
void Fifo_RunLoop(bool run);
|
||||
|
||||
bool AtBreakpoint();
|
||||
void Fifo_DoState(PointerWrap &f);
|
||||
|
||||
void Fifo_SetRendering(bool bEnabled);
|
||||
|
|
|
@ -64,6 +64,12 @@ typedef struct
|
|||
volatile u32 CPCmdIdle;
|
||||
volatile u32 CPReadIdle;
|
||||
|
||||
volatile u32 bFF_LoWatermarkInt;
|
||||
volatile u32 bFF_HiWatermarkInt;
|
||||
|
||||
volatile u32 bFF_LoWatermark;
|
||||
volatile u32 bFF_HiWatermark;
|
||||
|
||||
// for GP watchdog hack
|
||||
volatile u32 Fake_GPWDToken; // cicular incrementer
|
||||
} SCPFifoStruct;
|
||||
|
|
Loading…
Reference in New Issue