diff --git a/Source/Core/Core/HW/GPFifo.cpp b/Source/Core/Core/HW/GPFifo.cpp index ef05946c2b..4de989b05b 100644 --- a/Source/Core/Core/HW/GPFifo.cpp +++ b/Source/Core/Core/HW/GPFifo.cpp @@ -56,9 +56,23 @@ void Init() memset(s_gather_pipe, 0, sizeof(s_gather_pipe)); } -bool IsEmpty() +bool IsBNE() { - return GetGatherPipeCount() == 0; + // TODO: It's not clear exactly when the BNE (buffer not empty) bit is set. + // The PPC 750cl manual says in section 2.1.2.12 "Write Pipe Address Register (WPAR)" (page 78): + // "A mfspr WPAR is used to read the BNE bit to check for any outstanding data transfers." + // In section 9.4.2 "Write Gather Pipe Operation" (page 327) it says: + // "Software can check WPAR[BNE] to determine if the buffer is empty or not." + // On page 327, it also says "The only way for software to flush out a partially full 32 byte + // block is to fill up the block with dummy data,." + // On page 328, it says: "Before disabling the write gather pipe, the WPAR[BNE] bit should be + // tested to insure that all outstanding transfers from the buffer to the bus have completed." + // + // GXRedirectWriteGatherPipe and GXRestoreWriteGatherPipe (used for display lists) wait for + // the bit to be 0 before continuing, so it can't be a case of any data existing in the FIFO; + // it might be a case of over 32 bytes being stored pending transfer to memory? For now, always + // return false since that prevents hangs in games that use display lists. + return false; } void ResetGatherPipe() diff --git a/Source/Core/Core/HW/GPFifo.h b/Source/Core/Core/HW/GPFifo.h index b29b1b9fde..4ba023117f 100644 --- a/Source/Core/Core/HW/GPFifo.h +++ b/Source/Core/Core/HW/GPFifo.h @@ -26,7 +26,7 @@ void UpdateGatherPipe(); void CheckGatherPipe(); void FastCheckGatherPipe(); -bool IsEmpty(); +bool IsBNE(); // Write void Write8(u8 value); diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index b7da980db3..8699f05b75 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -238,11 +238,14 @@ void Interpreter::mfspr(UGeckoInstruction inst) case SPR_WPAR: { - // TODO: If wpar_empty ever is false, Paper Mario hangs. Strange. - // Maybe WPAR is automatically flushed after a certain amount of time? - bool wpar_empty = true; // GPFifo::IsEmpty(); - if (!wpar_empty) - rSPR(index) |= 1; // BNE = buffer not empty + // The bottom, read-only bit checks if the buffer is not empty. + // GXRedirectWriteGatherPipe and GXRestoreWriteGatherPipe (used for display lists) wait for + // this bit to be cleared before writing to SPR_WPAR again (with a value of 0x0c00800 (aka + // GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS)). + // Currently, we always treat the buffer as not empty, as the exact behavior is unclear + // (and games that use display lists will hang if the bit doesn't eventually become zero). + if (GPFifo::IsBNE()) + rSPR(index) |= 1; else rSPR(index) &= ~1; } diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 3cd9bde984..301ff55a6b 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -282,16 +282,16 @@ static void WriteToHardware(u32 em_address, const u32 data, const u32 size) wi = translated_addr.wi; } - // Check for a gather pipe write. + // Check for a gather pipe write (which are not implemented through the MMIO system). // // Note that we must mask the address to correctly emulate certain games; Pac-Man World 3 // in particular is affected by this. (See https://bugs.dolphin-emu.org/issues/8386) // - // Note that the PowerPC 750CL manual says (in section 9.4.2 Write Gather Pipe Operation on page - // 327): "A noncacheable store to an address with bits 0-26 matching WPAR[GB_ADDR] but with bits - // 27-31 not all zero will result in incorrect data in the buffer." So, it's possible that in some - // cases writes which do not exactly match the masking behave differently, but Pac-Man World 3's - // writes happen to behave correctly. + // The PowerPC 750CL manual says (in section 9.4.2 Write Gather Pipe Operation on page 327): + // "A noncacheable store to an address with bits 0-26 matching WPAR[GB_ADDR] but with bits 27-31 + // not all zero will result in incorrect data in the buffer." So, it's possible that in some cases + // writes which do not exactly match the masking behave differently, but Pac-Man World 3's writes + // happen to behave correctly. if (flag == XCheckTLBFlag::Write && (em_address & 0xFFFFF000) == GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS) {