mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 13:55:38 +00:00
CDROM: Further adjust IRQ delay
Fixes audio dropouts in Crime Crackers, Ogre Battle seems fine now as well.
This commit is contained in:
parent
9392c19a70
commit
f1ca914512
|
@ -30711,6 +30711,9 @@ SCPS-10003:
|
||||||
name: "Crime Crackers (Japan)"
|
name: "Crime Crackers (Japan)"
|
||||||
controllers:
|
controllers:
|
||||||
- DigitalController
|
- DigitalController
|
||||||
|
settings:
|
||||||
|
dmaMaxSliceTicks: 100 # Stops DMA from blazing past the deferred CDROM async interrupt.
|
||||||
|
displayActiveEndOffset: -1 # Fixes garbage on edge of screen in cutscenes.
|
||||||
codes:
|
codes:
|
||||||
- HASH-111C340E270B10A8
|
- HASH-111C340E270B10A8
|
||||||
metadata:
|
metadata:
|
||||||
|
|
|
@ -60,8 +60,8 @@ enum : u32
|
||||||
MAX_FAST_FORWARD_RATE = 12,
|
MAX_FAST_FORWARD_RATE = 12,
|
||||||
FAST_FORWARD_RATE_STEP = 4,
|
FAST_FORWARD_RATE_STEP = 4,
|
||||||
|
|
||||||
MINIMUM_INTERRUPT_DELAY = 6000,
|
MINIMUM_INTERRUPT_DELAY = 1000,
|
||||||
INTERRUPT_DELAY_CYCLES = 2000,
|
INTERRUPT_DELAY_CYCLES = 500,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
||||||
|
@ -1033,9 +1033,16 @@ void CDROM::WriteRegister(u32 offset, u8 value)
|
||||||
case 5:
|
case 5:
|
||||||
{
|
{
|
||||||
DEBUG_LOG("Interrupt flag register <- 0x{:02X}", value);
|
DEBUG_LOG("Interrupt flag register <- 0x{:02X}", value);
|
||||||
|
|
||||||
|
const u8 prev_interrupt_flag_register = s_interrupt_flag_register;
|
||||||
s_interrupt_flag_register &= ~(value & INTERRUPT_REGISTER_MASK);
|
s_interrupt_flag_register &= ~(value & INTERRUPT_REGISTER_MASK);
|
||||||
if (s_interrupt_flag_register == 0)
|
if (s_interrupt_flag_register == 0)
|
||||||
{
|
{
|
||||||
|
// Start the countdown from when the interrupt was cleared, not it being triggered.
|
||||||
|
// Otherwise Ogre Battle, Crime Crackers, Lego Racers, etc have issues.
|
||||||
|
if (prev_interrupt_flag_register != 0)
|
||||||
|
s_last_interrupt_time = System::GetGlobalTickCounter();
|
||||||
|
|
||||||
InterruptController::SetLineState(InterruptController::IRQ::CDROM, false);
|
InterruptController::SetLineState(InterruptController::IRQ::CDROM, false);
|
||||||
if (HasPendingAsyncInterrupt() && !HasPendingCommand())
|
if (HasPendingAsyncInterrupt() && !HasPendingCommand())
|
||||||
QueueDeliverAsyncInterrupt();
|
QueueDeliverAsyncInterrupt();
|
||||||
|
@ -1159,7 +1166,6 @@ bool CDROM::HasPendingAsyncInterrupt()
|
||||||
void CDROM::SetInterrupt(Interrupt interrupt)
|
void CDROM::SetInterrupt(Interrupt interrupt)
|
||||||
{
|
{
|
||||||
s_interrupt_flag_register = static_cast<u8>(interrupt);
|
s_interrupt_flag_register = static_cast<u8>(interrupt);
|
||||||
s_last_interrupt_time = System::GetGlobalTickCounter();
|
|
||||||
UpdateInterruptRequest();
|
UpdateInterruptRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1205,14 +1211,12 @@ void CDROM::QueueDeliverAsyncInterrupt()
|
||||||
// interrupt, then read the FIFO. If an INT1 comes in during that time, it'll read the INT1 response
|
// interrupt, then read the FIFO. If an INT1 comes in during that time, it'll read the INT1 response
|
||||||
// instead of the INT3 response, and the game gets confused. So, we just delay INT1s a bit, if there
|
// instead of the INT3 response, and the game gets confused. So, we just delay INT1s a bit, if there
|
||||||
// has been any recent INT3s - give it enough time to read the response out. The real console does
|
// has been any recent INT3s - give it enough time to read the response out. The real console does
|
||||||
// something similar anyway, the INT1 task won't run immediately after the INT3 is cleared. We use
|
// something similar anyway, the INT1 task won't run immediately after the INT3 is cleared.
|
||||||
// the response FIFO being empty as a second heuristic, to avoid very late INT1s that cause early
|
|
||||||
// buffer loads and sector retries in other games, like Lego Racers PAL.
|
|
||||||
DebugAssert(HasPendingAsyncInterrupt());
|
DebugAssert(HasPendingAsyncInterrupt());
|
||||||
|
|
||||||
// underflows here are okay
|
// underflows here are okay
|
||||||
const u32 diff = System::GetGlobalTickCounter() - s_last_interrupt_time;
|
const u32 diff = System::GetGlobalTickCounter() - s_last_interrupt_time;
|
||||||
if (diff >= MINIMUM_INTERRUPT_DELAY || s_response_fifo.IsEmpty())
|
if (diff >= MINIMUM_INTERRUPT_DELAY)
|
||||||
{
|
{
|
||||||
DeliverAsyncInterrupt(nullptr, 0, 0);
|
DeliverAsyncInterrupt(nullptr, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,7 +555,10 @@ void System::UpdateOverclock()
|
||||||
|
|
||||||
u32 System::GetGlobalTickCounter()
|
u32 System::GetGlobalTickCounter()
|
||||||
{
|
{
|
||||||
return TimingEvents::GetGlobalTickCounter() + CPU::GetPendingTicks();
|
// When running events, the counter actually goes backwards, because the pending ticks are added in chunks.
|
||||||
|
// So, we need to return the counter with all pending ticks added in such cases.
|
||||||
|
return TimingEvents::IsRunningEvents() ? TimingEvents::GetEventRunTickCounter() :
|
||||||
|
(TimingEvents::GetGlobalTickCounter() + CPU::GetPendingTicks());
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 System::GetFrameNumber()
|
u32 System::GetFrameNumber()
|
||||||
|
|
Loading…
Reference in a new issue