Emulator Issues #8175
closedDatel Discs Immediately hang on Single Core, intermittently hang on Dualcore
0%
Description
Game Name?
Advance Game Port - GNHE5d
Action Replay by Datel - DTLX01 (Modified to DTLE01 for Dolphin to run it)
Maxplay - GNHE5d
Max Drive Pro v1.0 - GNHE5d
Yes I know several of the discs are the same ID; that's just how they are.
What's the problem? Describe what went wrong in few words.
Single core will immediately (within 2 seconds) luck up in all of them except the advance game port, which will freeze up 2 seconds after launching a GBA game. Dualcore will randomly hang. Can last 5 - 10 minutes, can last 2 seconds. It will hang, just a matter of when.
What did you expect to happen instead?
I didn't expect these discs to work at all honestly. It was a pleasant surprise.
What steps will reproduce the problem?
1.Make sure you have a bios enabled.
2.Make sure you have LLE audio enabled
3.Boot a disc in single core, it will crash.
4.Boot it in Dualcore, it will crash /eventually/
Dolphin 3.5 and 3.5-367 are old versions of Dolphin that have
known issues and bugs, so don't report issues about them and test the
latest Dolphin version first.
Which versions of Dolphin did you test on?
4.0, 4.0-5378
Does using an older version of Dolphin solve your issue? If yes, which
versions of Dolphin used to work?
Nopers
What are your PC specifications? (including, but not limited to: Operating
System, CPU and GPU)
Core i5 3570K, GTX 760, Windows 7 x64
Is there any other relevant information? (e.g. logs, screenshots,
configuration files)
Fiora (Queen Fiora? Jit Princess Fiora? JMC's savior Fiora?) actually found a workaround for this bug already. in void SetFinish, modify line 310 from
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0);
to
CoreTiming::ScheduleEvent_Threadsafe(250000, et_SetFinishOnMainThread, 0);
That completely eliminates hangs. It can still rarely hang with 200000. We don't think this is the correct solution, but it is at least a start toward understanding it.
Updated by kolano almost 7 years ago
Just did some retesting with Maxplay in 5.0-6004, which is likely of interest.
With Dual Core just a single "FIFO is overflowed by GatherPipe ! CPU thread is too fast!" error occurs. With Single Core the error now happens numerous times, until a separate Unknown Opcode error occurs. The top part of the first screen then starts to show and when Dolphin hangs without further error, only showing the top 20% or so of the screen.
Updated by pokechu22 almost 3 years ago
This was impacted by 5.0-15579 (https://github.com/dolphin-emu/dolphin/pull/1024); in single-core, the large number of error popups still appear (tested via MaxPlay, Max Drive Pro, and Action Replay Max), but the titles boot after them instead of hanging on a black screen. I haven't done extensive testing with regards to stability ingame though.
Updated by ZephyrSurfer over 2 years ago
I assume the pull request linked to should be https://github.com/dolphin-emu/dolphin/pull/10244
There doesn't appear to be a build for 5.0-15579 though
Updated by pokechu22 over 2 years ago
- Status changed from Accepted to Fixed
- Fixed in set to 5.0-15579
Yep, the linked PR is supposed to be https://github.com/dolphin-emu/dolphin/pull/10244. I'm not sure why no corresponding build exists (the progress report links to the corresponding PR instead of the build like it normally does, too). 5.0-15581 removes the dual-core forcing for that, though: https://dolphin-emu.org/download/dev/e92e90d1474d028ba63a3e11b5528e30ebc72c85/
Basically everything I've done with Datel discs lately has been in single core, and I haven't ran into any issues other that don't also exist in dual core (e.g. #11724), so this is fixed.
Updated by pokechu22 2 months ago
SD Media Launcher (JP) hangs, and I looked into this a bit. It seems like Datel just messed up.
The hang is due to GXDrawDone
not being implemented correctly. Here's Datel's implementation (800104a0 in SD Media Launcher):
void GX_DrawDone(void)
{
int iVar1;
undefined4 uVar2;
uVar2 = _CPU_ISR_Disable();
write_volatile_1(wgPipe,0x61);
write_volatile_4(wgPipe,0x45000002);
GX_Flush();
_CPU_ISR_Disable(uVar2);
write_volatile_4(_gxfinished,0);
do {
iVar1 = read_volatile_4(_gxfinished);
} while (iVar1 == 0);
return;
}
Compare the implementation from Super Mario Sunshine:
void gx::GXDrawDone(void)
{
undefined4 uVar1;
uVar1 = os::OSDisableInterrupts();
write_volatile_1(wgPipe._0_1_,0x61);
write_volatile_4(wgPipe,0x45000002);
GXFlush();
DrawDone = '\0';
os::OSRestoreInterrupts(uVar1);
uVar1 = os::OSDisableInterrupts();
while (DrawDone == '\0') {
os::OSSleepThread(&FinishQueue);
}
os::OSRestoreInterrupts(uVar1);
return;
}
_gxfinished
is supposed to be set to 0, and then set to 1 by an interrupt. However, Datel enables interrupts before setting _gxfinished
to 0, so it's possible for the interrupt trigger, setting _gxfinished
to 1, and then _gxfinished
gets set to 0 by GX_DrawDone
and the loop never terminates. This is what the timing hack attempted to fix - if it takes longer for the interrupt to trigger, then it's likely that it'll never hang. (The value we currently use, 500, is still too fast.) The following memory patch works:
$SD Media Launcher (JP) GXDrawDone patch
0x800104E4:dword:0x3D20800C:0x480094B9
0x800104E8:dword:0x38000000:0x3D20800C
0x800104EC:dword:0x3D60800C:0x38000000
0x800104F0:dword:0x9009BC94:0x3D60800C
0x800104F4:dword:0x480094A9:0x9009BC94
There's a second bug that causes the "FIFO is overflowed by GatherPipe" messages: GXInitFifoPtrs
(called by GXInit
) is also wrong. Here's Datel's version:
void GX_InitFifoPtrs(gxfifo *fifo,undefined *rd_ptr,undefined *wt_ptr)
{
_CPU_ISR_Disable();
fifo->rd_ptr = (uint)rd_ptr;
fifo->wt_ptr = (uint)wt_ptr;
fifo->rdwt_dst = (int)wt_ptr - (int)rd_ptr;
if ((int)wt_ptr - (int)rd_ptr == 0) { // should be < 0
fifo->rdwt_dst = fifo->size; // should be += size
}
_CPU_ISR_Disable();
return;
}
while Super Mario Sunshine uses:
void gx::GXInitFifoPtrs(gxfifo *fifo,undefined *rd_ptr,undefined *wt_ptr)
{
os::OSDisableInterrupts();
fifo->rd_ptr = (uint)rd_ptr;
fifo->wt_ptr = (uint)wt_ptr;
fifo->rdwt_dst = (int)wt_ptr - (int)rd_ptr;
if ((int)fifo->rdwt_dst < 0) {
fifo->rdwt_dst = fifo->rdwt_dst + fifo->size;
}
os::OSRestoreInterrupts();
return;
}
GXInitFifoPtrs
is called with rd_ptr
== wt_ptr
, so this ends up making rdwt_dst
be size
(0x40000), which generally messes things up (I still don't fully understand how it's supposed to work, though). This seems to result in 0x40000 bytes of additional graphics data that needs to be decoded, all of which is just whatever junk is already in memory. (For SD Media Launcher, this is all 0xA8 bytes, which completely hangs things as this corresponds to an impossibly large GX_DRAW_LINES
.)
If the fifo->rdwt_dst
assignment instruction at 80014ef4
is nopped out, then no "FIFO is overflowed by GatherPipe" or unknown opcode messages are logged. Note that a per-frame patch doesn't work for this, as the code is called before any frame gets rendered.
Both of these probably apply to all Datel titles, but the code is located at different places in each title, so it'd require writing the same patch a bunch of times.
(Libogc's GX_InitFifoPtrs
also seems to incorrectly set rd_ptr
to rdwt_dst + size
, but that won't happen with rd_ptr == wt_ptr
, so it probably isn't relevant here.)