diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index 8f9b621284..df0fc6fc02 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -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 diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index 45291223b6..68e0f32080 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -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 diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index fb4275929c..1259b5c51a 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -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); +} diff --git a/Source/Core/VideoCommon/Src/Fifo.h b/Source/Core/VideoCommon/Src/Fifo.h index 95c7630a5d..2a3a5e4221 100644 --- a/Source/Core/VideoCommon/Src/Fifo.h +++ b/Source/Core/VideoCommon/Src/Fifo.h @@ -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); diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index d6e71a5de9..eab8a68100 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -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;