A call to GXCopyDisp(), made once before the title screen for no
apparent purpose, is causing heap corruption, but it isn't observed on
real hardware thanks to the data cache. Skipping the call works too,
preventing a crash on the main menu.
This is necessary to retain precision above 32 bits, but more importantly to prevent an expression like (0x80000000 | 1) from flipping the sign of the result.
This game follows the anti-pattern of calling memset on a buffer in the
midst of being DMA copied to ARAM, then calling a DVD read function that
effectively cancels the memset with dcbi instructions. Dolphin does not
emulate dcache for performance reasons, so this patch removes the
offending memset call.
Patches are included for two regions and are enabled by default.
https://bugs.dolphin-emu.org/issues/12759
PR #2663 added a Jit64 implementation of dcbX and a fast path to skip JIT cache invalidation. Unfortunately, there is a mismatch between address spaces in this optimization. It tests the effective address (with the top 3 bits cleared) against the valid block bitset which is intended to be indexed by physical address. While this works in the common case, it fails (for example) when the effective address is in the 7E... region (a.k.a. "fake VMEM"). This may also fall apart under more complex memory mapping scenarios requiring full MMU emulation.
The good news is that even without this fast path, the underlying call to JitInterface::InvalidateICache() still does very little work in the common case. It correctly translates the effective address to a physical address which it tests against the valid block bitset, skipping invalidation if it is not necessary. As such, the cost of removing the fast path should not be too high.
The Jit64 implementation is retained, though all it does now is emit a call. This is marginally more efficient than simple interpreter fallback, which involves an extra call. The JitArm64 implementation has also been fixed.
The game Happy Feet is fixed by this change, as it loads code in the 7E... address region and depends upon JIT cache invalidation in reponse to dcbf.
https://bugs.dolphin-emu.org/issues/12133
https://bugs.dolphin-emu.org/issues/6749
This change fixes the scratchy audio in Teenage Mutant Ninja Turtles (SX7E52/SX7P52). The game starts an audio interface DMA with an unaligned address, and because Dolphin was not masking off the low 5 bits of AUDIO_DMA_START_LO, all future AI DMAs were misaligned. To understand why, it is instructive to refer to AUDIO_InitDMA() in libogc, which behaves the same as the official SDK:
_dspReg[25] = (_dspReg[25]&~0xffe0)|(startaddr&0xffff);
The implementation does not mask off the low bits of the passed in value before it ORs them with low bits of the current register value. Therefore, if they are not masked off by the hardware itself, they become permanently stuck once set.
Adding a write mask for AUDIO_DMA_START_LO is enough to fix the bug in TMNT, but I decided to run some tests on GC and Wii to find the correct write masks for the surrounding registers, as only a couple were already being masked. Dolphin has gotten away with not masking the rest because many are already A) masked on read (or never read) by the SDK and/or B) masked on use (or never used) in Dolphin.
This leaves just three registers where the difference may be observable: AR_DMA_CNT_H and AUDIO_DMA_START_HI/LO.
This code was storing references to patch entries which could move around in memory if a patch was erased from the middle of a vector or if the vector itself was reallocated. Instead, NewPatchDialog maintains a separate copy of the patch entries which are committed back to the patch if the user accepts the changes.
These games are erroneously zeroing buffers before they can be fully copied to ARAM by DMA. The responsible memset() calls are followed by a call to DVDRead() which issues dcbi instructions that effectively cancel the memset() on real hardware. Because Dolphin lacks dcache emulation, the effects of the memset() calls are observed, which causes missing audio.
In a comment on the original bug, phire noted that the issue can be corrected by simply nop'ing out the offending memset() calls. Because the games dynamically load different .rel executables based on the character and/or language, the addresses of these calls can vary.
To deal generally with the problem of code being dynamically loaded to fixed, known addresses, the patch engine is extended to support conditional patches which require a match against a known value. This sort of thing is already achievable with Action Replay/Gecko codes, but their use depends on enabling cheats globally in Dolphin, which is not a prerequisite shared by patches.
Patches are included for every region, character, and language combination. They are enabled by default.
The end result is an approximation of the games' behavior on real hardware without the associated complexity of proper dcache emulation.
https://bugs.dolphin-emu.org/issues/9840
This game can deadlock the CPU and GPU by setting FIFO breakpoints too infrequently, provided the CPU gets too far ahead, as can happen under Dolphin due to timing inaccuracies. The game never clears breakpoints, and it will skip setting them if the previous one has not been hit by the GPU. If the CPU gets far enough ahead it will reach the FIFO high water mark and trigger an overflow interrupt, causing the render thread to be suspended. The GPU will make forward progress until it hits the last set breakpoint. However, if the distance between that breakpoint and the FIFO write pointer is greater than the low water mark, then the GPU will never generate an underflow interrupt and the render thread will never be resumed. This patch forces the game to update the breakpoint unconditionally and has been tested on real hardware with no apparent ill effect.
This patch covers the US release (GLSE64), but there are three more (GLSD64, GLSF64, GLSP64) that will likely require similar patches.
This fixes the crash at Goblin Wall: https://bugs.dolphin-emu.org/issues/9915
A patch (for the US release only) that fixes the game's buffer overrun bug is included as an alternative with lower performance cost. It is disabled by default.
The first call to GXCopyDisp() corrupts game data, but on real hardware it isn't observed thanks to the data cache. Skipping the call works too, preventing a crash on boot.
This patch is enabled by default.