Ski Champ hanging on FBI screen - a possible fix

When running Ski Champ with the region set to USA, the game hangs on the "winners don't use drugs" splash screen. This has been a known bug since 2014:
The game gets stuck in this loop:
Basically if the low byte of the word stored in $1E0064 is 0x20 or higher, the code spins in a loop. I think what is happening is that this function builds a queue of soundboard commands, and if the queue gets full it is supposed to wait until the IRQ 0x40 (SCSP) handler removes a command from the queue and decrements the low byte of $1E0064, breaking the loop. But there's a problem: this loop runs during the IRQ2 handler, when external interrupts are disabled! This means the IRQ 0x40 interrupt cannot fire and the game hangs.
A later part of this function sets the midiCtrlPort value to 0x27 if the low byte of $1E0064 equals 1, triggering an IRQ 0x40 sequence. However, I found out that just before the game hangs the midiCtrlPort value is already 0x27 before IRQ2 fires - interesting. On real hardware I believe the soundboard would fire an IRQ 0x40 immediately, but Supermodel currently waits until after IRQ2. I decided to try making it so that Supermodel also fires any pending IRQ 0x40s at the start of the frame after ping-pong flip and before IRQ2, and the game no longer hangs!
I'll upload a pull request to GitHub when I have a more elegant fix
Conversus W. Vans wrote:When I change the region to USA in Ski Champ on Supermodel, it freezes at the "WINNERS DON'T USE DRUGS" screen. Wtf?
Meanwhile, I have it set to 'EXPORT'.
The game gets stuck in this loop:
- Code: Select all
>>*Jmp000A63B0 addi r4,r13,-$7F9C ; set r4 to $1E0064
$000A63B4 lwarx r5,0,r4
$000A63B8 and r6,r5,$000000FF
$000A63BC rlwinm r7,r5,16,$000000FF
$000A63C0 addi r6,r6,$01
$000A63C4 cmpi cr0,0,r6,$20
$000A63C8 bt cr0[gt],Jmp000A63B0
Basically if the low byte of the word stored in $1E0064 is 0x20 or higher, the code spins in a loop. I think what is happening is that this function builds a queue of soundboard commands, and if the queue gets full it is supposed to wait until the IRQ 0x40 (SCSP) handler removes a command from the queue and decrements the low byte of $1E0064, breaking the loop. But there's a problem: this loop runs during the IRQ2 handler, when external interrupts are disabled! This means the IRQ 0x40 interrupt cannot fire and the game hangs.
A later part of this function sets the midiCtrlPort value to 0x27 if the low byte of $1E0064 equals 1, triggering an IRQ 0x40 sequence. However, I found out that just before the game hangs the midiCtrlPort value is already 0x27 before IRQ2 fires - interesting. On real hardware I believe the soundboard would fire an IRQ 0x40 immediately, but Supermodel currently waits until after IRQ2. I decided to try making it so that Supermodel also fires any pending IRQ 0x40s at the start of the frame after ping-pong flip and before IRQ2, and the game no longer hangs!
I'll upload a pull request to GitHub when I have a more elegant fix
