DSB2 IRQ 2 now fires at 1KHz rather than once per frame, improving

music timing in Daytona USA 2 and Sega Rally 2. DSB1 CPU timing 
increased from 1MHz to 4MHz, improving music fade timing in Scud Race. 
Thanks to gm_matthew for these discoveries.
This commit is contained in:
SpinDizzy 2021-03-03 15:30:19 +00:00
parent e3374256ff
commit 46b1de2238
2 changed files with 212 additions and 180 deletions
Src/Model3

View file

@ -1,7 +1,8 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
** Copyright 2011-2021 Bart Trzynadlowski, Nik Henson, Ian Curtis,
** Harry Tuttle, and Spindizzi
**
** This file is part of Supermodel.
**
@ -438,7 +439,7 @@ void CDSB1::RunFrame(INT16 *audioL, INT16 *audioR)
}
// While FIFO not empty, fire interrupts, run for up to one frame
for (cycles = (4000000/60)/4; (cycles > 0) && (fifoIdxR != fifoIdxW); )
for (cycles = (4000000/60); (cycles > 0) && (fifoIdxR != fifoIdxW); )
{
Z80.SetINT(true); // fire an IRQ to indicate pending command
//printf("Z80 INT fired\n");
@ -1015,12 +1016,27 @@ void CDSB2::RunFrame(INT16 *audioL, INT16 *audioR)
M68KSetIRQ(1); // indicate pending command
//printf("68K INT fired\n");
M68KRun(500);
m_totalCyclesElapsed += M68KRun(500);
}
// Per-frame interrupt
// gm_matthew made the interesting discovery that IRQ2 may in fact be a timer interrupt
// rather than a per-frame interrupt.For Daytona 2 and Sega Rally 2, assuming a value
// of 1KHz fixes music fade outs and some timing issues. It is very likely this is a
// configurable timer and we should be on the look-out for games which appear to use
// different values. It is equally likely that all games share a similar code base and
// use 1KHz as the timer rate.
while (m_totalCyclesElapsed < m_nextFrameEndCycles)
{
if (m_totalCyclesElapsed >= m_nextTimerInterruptCycles)
{
// Fire timer interrupt and schedule next one
M68KSetIRQ(2);
M68KRun(4000000/60);
m_nextTimerInterruptCycles = (m_totalCyclesElapsed + k_timerPeriod) - (m_totalCyclesElapsed + k_timerPeriod) % k_timerPeriod;
}
int cyclesToRun = (std::min)(m_nextTimerInterruptCycles, m_nextFrameEndCycles) - m_totalCyclesElapsed;
m_totalCyclesElapsed += M68KRun(cyclesToRun);
}
m_nextFrameEndCycles = (m_totalCyclesElapsed + k_framePeriod) - (m_totalCyclesElapsed + k_framePeriod) % k_framePeriod;
M68KGetContext(&M68K);
@ -1080,6 +1096,10 @@ void CDSB2::Reset(void)
//printf("DSB2 PC=%06X\n", M68KGetPC());
M68KGetContext(&M68K);
m_totalCyclesElapsed = 0;
m_nextFrameEndCycles = k_framePeriod;
m_nextTimerInterruptCycles = k_timerPeriod;
DebugLog("DSB2 Reset\n");
}
@ -1162,6 +1182,12 @@ void CDSB2::LoadState(CBlockFile *StateFile)
M68KLoadState(StateFile, "DSB2 68K");
M68KGetContext(&M68K);
// Technically these should be saved/restored rather than being reset but that would mean
// the save state format has to be modified and the difference would be imperceptible anyway
m_totalCyclesElapsed = 0;
m_nextFrameEndCycles = k_framePeriod;
m_nextTimerInterruptCycles = k_timerPeriod;
// Restart MPEG audio at the appropriate position
if (isPlaying)
{

View file

@ -1,7 +1,8 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
** Copyright 2011-2021 Bart Trzynadlowski, Nik Henson, Ian Curtis,
** Harry Tuttle, and Spindizzi
**
** This file is part of Supermodel.
**
@ -317,6 +318,11 @@ private:
// M68K CPU
M68KCtx M68K;
static const int k_framePeriod = 4000000/60;
static const int k_timerPeriod = 4000000/1000; // 1KHz timer
int m_totalCyclesElapsed;
int m_nextFrameEndCycles;
int m_nextTimerInterruptCycles;
};