From b2c02e216ceaeb51ee4f6c644050e26d4adab566 Mon Sep 17 00:00:00 2001 From: skidau Date: Fri, 14 Nov 2014 11:46:02 +1100 Subject: [PATCH 1/3] Separated out the CPU and GPU thread path to avoid clobbering. Removed the Eternal Darkness check as it is no longer required. Fixes issue 7835. --- Source/Core/VideoCommon/CommandProcessor.cpp | 52 ++++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/Source/Core/VideoCommon/CommandProcessor.cpp b/Source/Core/VideoCommon/CommandProcessor.cpp index 8af2af9ccc..155e4b18ec 100644 --- a/Source/Core/VideoCommon/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/CommandProcessor.cpp @@ -404,7 +404,33 @@ void SetCPStatusFromGPU() INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); fifo.bFF_Breakpoint = false; } - SetCPStatusFromCPU(); + // overflow & underflow check + fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); + fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); + + 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.GPReadEnable; + + if (interrupt != interruptSet && !interruptWaiting) + { + u64 userdata = interrupt ? 1 : 0; + if (IsOnThread()) + { + if (!interrupt || bpInt || undfInt || ovfInt) + { + // Schedule the interrupt asynchronously + interruptWaiting = true; + CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + } + } + else + { + CommandProcessor::UpdateInterrupts(userdata); + } + } } void SetCPStatusFromCPU() @@ -426,18 +452,9 @@ void SetCPStatusFromCPU() { if (!interrupt || bpInt || undfInt || ovfInt) { - if (Core::IsGPUThread()) - { - // Schedule the interrupt asynchronously - interruptWaiting = true; - CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); - } - else - { - interruptSet = interrupt; - INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); - ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt); - } + interruptSet = interrupt; + INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, interrupt); } } else @@ -451,7 +468,7 @@ void ProcessFifoAllDistance() { if (IsOnThread()) { - while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && + while (!interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) Common::YieldCPU(); } @@ -489,13 +506,6 @@ void SetCpStatusRegister() void SetCpControlRegister() { - // If the new fifo is being attached, force an exception check - // This fixes the hang while booting Eternal Darkness - if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable) - { - CoreTiming::ForceExceptionCheck(0); - } - fifo.bFF_BPInt = m_CPCtrlReg.BPInt; fifo.bFF_BPEnable = m_CPCtrlReg.BPEnable; fifo.bFF_HiWatermarkInt = m_CPCtrlReg.FifoOverflowIntEnable; From 3d448e49c6b2cb51121e85046ee4b96c18b12e01 Mon Sep 17 00:00:00 2001 From: skidau Date: Fri, 14 Nov 2014 17:07:11 +1100 Subject: [PATCH 2/3] Update CPStatus before processing the FIFO events and force an exception check on interrupts. Added more information into the FIFO unknown opcode error message. --- Source/Core/VideoCommon/CommandProcessor.cpp | 10 ++++++---- Source/Core/VideoCommon/OpcodeDecoding.cpp | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Source/Core/VideoCommon/CommandProcessor.cpp b/Source/Core/VideoCommon/CommandProcessor.cpp index 155e4b18ec..899438b9e4 100644 --- a/Source/Core/VideoCommon/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/CommandProcessor.cpp @@ -304,6 +304,9 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) void GatherPipeBursted() { + if (IsOnThread()) + SetCPStatusFromCPU(); + ProcessFifoEvents(); // if we aren't linked, we don't care about gather pipe data if (!m_CPCtrlReg.GPLinkEnable) @@ -326,9 +329,6 @@ void GatherPipeBursted() return; } - if (IsOnThread()) - SetCPStatusFromCPU(); - // update the fifo pointer if (fifo.CPWritePointer >= fifo.CPEnd) fifo.CPWritePointer = fifo.CPBase; @@ -369,6 +369,7 @@ void UpdateInterrupts(u64 userdata) INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared"); ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false); } + CoreTiming::ForceExceptionCheck(0); interruptWaiting = false; } @@ -404,6 +405,7 @@ void SetCPStatusFromGPU() INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %i", fifo.CPReadPointer); fifo.bFF_Breakpoint = false; } + // overflow & underflow check fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); @@ -447,7 +449,7 @@ void SetCPStatusFromCPU() if (interrupt != interruptSet && !interruptWaiting) { - u64 userdata = interrupt?1:0; + u64 userdata = interrupt ? 1 : 0; if (IsOnThread()) { if (!interrupt || bpInt || undfInt || ovfInt) diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 5c3544aecb..a7dd5b6a85 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -118,10 +118,19 @@ static void UnknownOpcode(u8 cmd_byte, void *buffer, bool preprocess) "bFF_BPEnable: %s\n" "bFF_BPInt: %s\n" "bFF_Breakpoint: %s\n" + "bFF_GPLinkEnable: %s\n" + "bFF_HiWatermarkInt: %s\n" + "bFF_LoWatermarkInt: %s\n" ,cmd_byte, fifo.CPBase, fifo.CPEnd, fifo.CPHiWatermark, fifo.CPLoWatermark, fifo.CPReadWriteDistance - ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint, fifo.bFF_GPReadEnable ? "true" : "false" - ,fifo.bFF_BPEnable ? "true" : "false" ,fifo.bFF_BPInt ? "true" : "false" - ,fifo.bFF_Breakpoint ? "true" : "false"); + ,fifo.CPWritePointer, fifo.CPReadPointer, fifo.CPBreakpoint + ,fifo.bFF_GPReadEnable ? "true" : "false" + ,fifo.bFF_BPEnable ? "true" : "false" + ,fifo.bFF_BPInt ? "true" : "false" + ,fifo.bFF_Breakpoint ? "true" : "false" + ,fifo.bFF_GPLinkEnable ? "true" : "false" + ,fifo.bFF_HiWatermarkInt ? "true" : "false" + ,fifo.bFF_LoWatermarkInt ? "true" : "false" + ); } } From ca3e5ce5e131c6f820d8fa069bf1b1566c60c844 Mon Sep 17 00:00:00 2001 From: skidau Date: Mon, 17 Nov 2014 16:05:16 +1100 Subject: [PATCH 3/3] Added an exception check when the game is close to overflowing. Fixes the fifo overflow that occurs in Battalion Wars 2. Changed the CPEnd loop check to an exact match. --- Source/Core/VideoCommon/CommandProcessor.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/CommandProcessor.cpp b/Source/Core/VideoCommon/CommandProcessor.cpp index 899438b9e4..a47cfa18b1 100644 --- a/Source/Core/VideoCommon/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/CommandProcessor.cpp @@ -330,7 +330,7 @@ void GatherPipeBursted() } // update the fifo pointer - if (fifo.CPWritePointer >= fifo.CPEnd) + if (fifo.CPWritePointer == fifo.CPEnd) fifo.CPWritePointer = fifo.CPBase; else fifo.CPWritePointer += GATHER_PIPE_SIZE; @@ -342,6 +342,10 @@ void GatherPipeBursted() ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd; } + // If the game is running close to overflowing, make the exception checking more frequent. + if (fifo.bFF_HiWatermark) + CoreTiming::ForceExceptionCheck(0); + Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE); RunGpu(); @@ -470,8 +474,7 @@ void ProcessFifoAllDistance() { if (IsOnThread()) { - while (!interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance && !AtBreakpoint()) + while (!interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) Common::YieldCPU(); } }