Introduce new APU timing hack

Timings.APUAllowTimeOverflow allows the SPC to cross the time limit
set by CPU.Cycles. Currently fixes Earthworm Jim 2, Ms. Pacman and
NBA Hang Time.
This commit is contained in:
dborth 2010-10-19 02:24:07 +00:00
parent 9816922af5
commit 221bab8a9a
8 changed files with 29 additions and 4 deletions

View File

@ -511,7 +511,7 @@ int SNES_SPC::cpu_read( int addr, rel_time_t time )
BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\ BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\
{\ {\
rel_time_t rel_time = m.spc_time - end_time;\ rel_time_t rel_time = m.spc_time - end_time;\
assert( rel_time <= 0 );\ /*assert( rel_time <= 0 );*/\
m.spc_time = end_time;\ m.spc_time = end_time;\
m.dsp_time += rel_time;\ m.dsp_time += rel_time;\
m.timers [0].next_time += rel_time;\ m.timers [0].next_time += rel_time;\
@ -524,7 +524,7 @@ BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\
m.timers [0].next_time -= rel_time;\ m.timers [0].next_time -= rel_time;\
m.timers [1].next_time -= rel_time;\ m.timers [1].next_time -= rel_time;\
m.timers [2].next_time -= rel_time;\ m.timers [2].next_time -= rel_time;\
assert( m.spc_time <= end_time );\ /*assert( m.spc_time >= end_time );*/\
return &REGS [r_cpuio0];\ return &REGS [r_cpuio0];\
} }
@ -543,7 +543,7 @@ void SNES_SPC::end_frame( time_t end_time )
// Greatest number of clocks early that emulation can stop early due to // Greatest number of clocks early that emulation can stop early due to
// not being able to execute current instruction without going over // not being able to execute current instruction without going over
// allowed time. // allowed time.
assert( -cpu_lag_max <= m.spc_time && m.spc_time <= 0 ); assert( -cpu_lag_max <= m.spc_time && m.spc_time <= cpu_lag_max );
// Catch timers up to CPU // Catch timers up to CPU
for ( int i = 0; i < timer_count; i++ ) for ( int i = 0; i < timer_count; i++ )

View File

@ -106,6 +106,8 @@ public:
//// Snes9x Accessor //// Snes9x Accessor
void spc_allow_time_overflow( bool );
void dsp_set_spc_snapshot_callback( void (*callback) (void) ); void dsp_set_spc_snapshot_callback( void (*callback) (void) );
void dsp_dump_spc_snapshot( void ); void dsp_dump_spc_snapshot( void );
void dsp_set_stereo_switch( int ); void dsp_set_stereo_switch( int );
@ -258,6 +260,9 @@ private:
static char const signature [signature_size + 1]; static char const signature [signature_size + 1];
void save_regs( uint8_t out [reg_count] ); void save_regs( uint8_t out [reg_count] );
// Snes9x timing hack
bool allow_time_overflow;
}; };
#include <assert.h> #include <assert.h>
@ -285,4 +290,6 @@ inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( d
inline bool SNES_SPC::check_kon() { return dsp.check_kon(); } inline bool SNES_SPC::check_kon() { return dsp.check_kon(); }
#endif #endif
inline void SNES_SPC::spc_allow_time_overflow( bool allow ) { allow_time_overflow = allow; }
#endif #endif

View File

@ -68,6 +68,8 @@ blargg_err_t SNES_SPC::init()
m.cycle_table [i * 2 + 0] = n >> 4; m.cycle_table [i * 2 + 0] = n >> 4;
m.cycle_table [i * 2 + 1] = n & 0x0F; m.cycle_table [i * 2 + 1] = n & 0x0F;
} }
allow_time_overflow = false;
#if SPC_LESS_ACCURATE #if SPC_LESS_ACCURATE
memcpy( reg_times, reg_times_, sizeof reg_times ); memcpy( reg_times, reg_times_, sizeof reg_times );

View File

@ -196,7 +196,9 @@ loop:
check( (unsigned) y < 0x100 ); check( (unsigned) y < 0x100 );
opcode = *pc; opcode = *pc;
if ( (rel_time += m.cycle_table [opcode]) > 0 ) if (allow_time_overflow && rel_time >= 0 )
goto stop;
if ( (rel_time += m.cycle_table [opcode]) > 0 && !allow_time_overflow)
goto out_of_time; goto out_of_time;
#ifdef SPC_CPU_OPCODE_HOOK #ifdef SPC_CPU_OPCODE_HOOK

View File

@ -598,6 +598,11 @@ void S9xAPUTimingSetSpeedup (int ticks)
UpdatePlaybackRate(); UpdatePlaybackRate();
} }
void S9xAPUAllowTimeOverflow (bool allow)
{
spc_core->spc_allow_time_overflow(allow);
}
void S9xResetAPU (void) void S9xResetAPU (void)
{ {
spc::reference_time = 0; spc::reference_time = 0;

View File

@ -195,6 +195,7 @@ void S9xAPUExecute (void);
void S9xAPUEndScanline (void); void S9xAPUEndScanline (void);
void S9xAPUSetReferenceTime (int32); void S9xAPUSetReferenceTime (int32);
void S9xAPUTimingSetSpeedup (int); void S9xAPUTimingSetSpeedup (int);
void S9xAPUAllowTimeOverflow (bool);
void S9xAPULoadState (uint8 *); void S9xAPULoadState (uint8 *);
void S9xAPUSaveState (uint8 *); void S9xAPUSaveState (uint8 *);
void S9xDumpSPCSnapshot (void); void S9xDumpSPCSnapshot (void);

View File

@ -3530,6 +3530,7 @@ void CMemory::ApplyROMFixes (void)
//// APU timing hacks :( //// APU timing hacks :(
Timings.APUSpeedup = 0; Timings.APUSpeedup = 0;
Timings.APUAllowTimeOverflow = FALSE;
if (!Settings.DisableGameSpecificHacks) if (!Settings.DisableGameSpecificHacks)
{ {
@ -3571,9 +3572,15 @@ void CMemory::ApplyROMFixes (void)
match_na("HEIWA Parlor!Mini8") || // Parlor mini 8 match_na("HEIWA Parlor!Mini8") || // Parlor mini 8
match_nn("SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!")) // SANKYO Fever! Fever! match_nn("SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!")) // SANKYO Fever! Fever!
Timings.APUSpeedup = 1; Timings.APUSpeedup = 1;
if (match_na ("EARTHWORM JIM 2") || // Earthworm Jim 2
match_na ("NBA Hangtime") || // NBA Hang Time
match_na ("MSPACMAN")) // Ms Pacman
Timings.APUAllowTimeOverflow = TRUE;
} }
S9xAPUTimingSetSpeedup(Timings.APUSpeedup); S9xAPUTimingSetSpeedup(Timings.APUSpeedup);
S9xAPUAllowTimeOverflow(Timings.APUAllowTimeOverflow);
//// Other timing hacks :( //// Other timing hacks :(

View File

@ -334,6 +334,7 @@ struct STimings
int32 NMIDMADelay; // The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly. int32 NMIDMADelay; // The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly.
int32 IRQPendCount; // This value is just a hack, because Snes9x cannot emulate any events in an opcode. int32 IRQPendCount; // This value is just a hack, because Snes9x cannot emulate any events in an opcode.
int32 APUSpeedup; int32 APUSpeedup;
bool8 APUAllowTimeOverflow;
}; };
struct SSettings struct SSettings