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:
Marcos Vitali 2010-12-11 12:42:55 +00:00
parent 24569aca3d
commit a9ca9cfd9b
5 changed files with 275 additions and 150 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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;