mirror of
https://github.com/dborth/snes9xgx.git
synced 2024-11-27 13:04:21 +01:00
fix SPC crash that happens on some games, eg: chrono trigger
(http://www.snes9x.com/phpbb3/viewtopic.php?f=6&t=6881) the snes9x team gave up and replaced the core, but others have fixed it https://bitbucket.org/mpyne/game-music-emu/issues/18/spc_cpucpp-492-always-assert-s
This commit is contained in:
parent
05a607a8f7
commit
4f2234cbc2
@ -282,7 +282,7 @@ static unsigned char const glitch_probs [3] [256] =
|
|||||||
// If write isn't preceded by read, data has this added to it
|
// If write isn't preceded by read, data has this added to it
|
||||||
int const no_read_before_write = 0x2000;
|
int const no_read_before_write = 0x2000;
|
||||||
|
|
||||||
void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
|
void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, uint16_t addr )
|
||||||
{
|
{
|
||||||
switch ( addr )
|
switch ( addr )
|
||||||
{
|
{
|
||||||
@ -383,7 +383,7 @@ void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, int addr )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr )
|
void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, uint16_t addr )
|
||||||
{
|
{
|
||||||
if ( addr == r_dspdata ) // 99%
|
if ( addr == r_dspdata ) // 99%
|
||||||
dsp_write( data, time );
|
dsp_write( data, time );
|
||||||
@ -393,23 +393,15 @@ void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr )
|
|||||||
|
|
||||||
void SNES_SPC::cpu_write_high( int data, int i, rel_time_t time )
|
void SNES_SPC::cpu_write_high( int data, int i, rel_time_t time )
|
||||||
{
|
{
|
||||||
if ( i < rom_size )
|
m.hi_ram [i] = (uint8_t) data;
|
||||||
{
|
|
||||||
m.hi_ram [i] = (uint8_t) data;
|
if ( m.rom_enabled )
|
||||||
if ( m.rom_enabled )
|
RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
|
||||||
RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//assert( *(&(RAM [0]) + i + rom_addr) == (uint8_t) data );
|
|
||||||
*(&(RAM [0]) + i + rom_addr) = cpu_pad_fill; // restore overwritten padding
|
|
||||||
cpu_write( data, i + rom_addr - 0x10000, time );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int const bits_in_int = CHAR_BIT * sizeof (int);
|
int const bits_in_int = CHAR_BIT * sizeof (int);
|
||||||
|
|
||||||
void SNES_SPC::cpu_write( int data, int addr, rel_time_t time )
|
void SNES_SPC::cpu_write( int data, uint16_t addr, rel_time_t time )
|
||||||
{
|
{
|
||||||
MEM_ACCESS( time, addr )
|
MEM_ACCESS( time, addr )
|
||||||
|
|
||||||
@ -463,7 +455,7 @@ inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time )
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SNES_SPC::cpu_read( int addr, rel_time_t time )
|
int SNES_SPC::cpu_read( uint16_t addr, rel_time_t time )
|
||||||
{
|
{
|
||||||
MEM_ACCESS( time, addr )
|
MEM_ACCESS( time, addr )
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#ifndef SNES_SPC_H
|
#ifndef SNES_SPC_H
|
||||||
#define SNES_SPC_H
|
#define SNES_SPC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "SPC_DSP.h"
|
#include "SPC_DSP.h"
|
||||||
#include "blargg_endian.h"
|
#include "blargg_endian.h"
|
||||||
|
|
||||||
@ -171,12 +173,12 @@ private:
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int pc;
|
uint16_t pc;
|
||||||
int a;
|
uint8_t a;
|
||||||
int x;
|
uint8_t x;
|
||||||
int y;
|
uint8_t y;
|
||||||
int psw;
|
uint8_t psw;
|
||||||
int sp;
|
uint8_t sp;
|
||||||
} cpu_regs;
|
} cpu_regs;
|
||||||
|
|
||||||
rel_time_t dsp_time;
|
rel_time_t dsp_time;
|
||||||
@ -202,13 +204,11 @@ private:
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
// padding to neutralize address overflow
|
// padding to neutralize address overflow -- but this is
|
||||||
union {
|
// still undefined behavior! TODO: remove and instead properly
|
||||||
uint8_t padding1 [0x100];
|
// guard usage of emulated memory
|
||||||
uint16_t align; // makes compiler align data for 16-bit access
|
uint8_t padding1 [0x100];
|
||||||
} padding1 [1];
|
alignas(uint16_t) uint8_t ram [0x10000 + 0x100];
|
||||||
uint8_t ram [0x10000];
|
|
||||||
uint8_t padding2 [0x100];
|
|
||||||
} ram;
|
} ram;
|
||||||
};
|
};
|
||||||
state_t m;
|
state_t m;
|
||||||
@ -244,13 +244,13 @@ private:
|
|||||||
Timer* run_timer ( Timer* t, rel_time_t );
|
Timer* run_timer ( Timer* t, rel_time_t );
|
||||||
int dsp_read ( rel_time_t );
|
int dsp_read ( rel_time_t );
|
||||||
void dsp_write ( int data, rel_time_t );
|
void dsp_write ( int data, rel_time_t );
|
||||||
void cpu_write_smp_reg_( int data, rel_time_t, int addr );
|
void cpu_write_smp_reg_( int data, rel_time_t, uint16_t addr );
|
||||||
void cpu_write_smp_reg ( int data, rel_time_t, int addr );
|
void cpu_write_smp_reg ( int data, rel_time_t, uint16_t addr );
|
||||||
void cpu_write_high ( int data, int i, rel_time_t );
|
void cpu_write_high ( int data, int i, rel_time_t );
|
||||||
void cpu_write ( int data, int addr, rel_time_t );
|
void cpu_write ( int data, uint16_t addr, rel_time_t );
|
||||||
int cpu_read_smp_reg ( int i, rel_time_t );
|
int cpu_read_smp_reg ( int i, rel_time_t );
|
||||||
int cpu_read ( int addr, rel_time_t );
|
int cpu_read ( uint16_t addr, rel_time_t );
|
||||||
unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t );
|
unsigned CPU_mem_bit ( uint16_t pc, rel_time_t );
|
||||||
|
|
||||||
bool check_echo_access ( int addr );
|
bool check_echo_access ( int addr );
|
||||||
uint8_t* run_until_( time_t end_time );
|
uint8_t* run_until_( time_t end_time );
|
||||||
|
@ -154,7 +154,7 @@ void SNES_SPC::ram_loaded()
|
|||||||
|
|
||||||
// Put STOP instruction around memory to catch PC underflow/overflow
|
// Put STOP instruction around memory to catch PC underflow/overflow
|
||||||
memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
|
memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
|
||||||
memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 );
|
memset( m.ram.ram + 0x10000, cpu_pad_fill, sizeof m.ram.padding1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registers were just loaded. Applies these new values.
|
// Registers were just loaded. Applies these new values.
|
||||||
|
@ -66,62 +66,37 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||||||
#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) )
|
#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) )
|
||||||
#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data )
|
#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data )
|
||||||
|
|
||||||
#define READ_PROG16( addr ) GET_LE16( ram + (addr) )
|
#define READ_PROG16( addr ) (RAM [addr & 0xffff] | (RAM [(addr + 1) & 0xffff] << 8))
|
||||||
|
|
||||||
#define SET_PC( n ) (pc = ram + (n))
|
#define SET_PC( n ) (pc = n)
|
||||||
#define GET_PC() (pc - ram)
|
#define GET_PC() (pc)
|
||||||
#define READ_PC( pc ) (*(pc))
|
#define READ_PC( pc ) (ram [pc])
|
||||||
#define READ_PC16( pc ) GET_LE16( pc )
|
#define READ_PC16( pc ) READ_PROG16( pc )
|
||||||
|
|
||||||
// TODO: remove non-wrapping versions?
|
#define SET_SP( v ) (sp = v)
|
||||||
#define SPC_NO_SP_WRAPAROUND 0
|
#define GET_SP() ((uint8_t) (sp))
|
||||||
|
|
||||||
#define SET_SP( v ) (sp = ram + 0x101 + (v))
|
|
||||||
#define GET_SP() (sp - 0x101 - ram)
|
|
||||||
|
|
||||||
#if SPC_NO_SP_WRAPAROUND
|
|
||||||
#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))
|
|
||||||
#define PUSH( v ) (void) (*--sp = (uint8_t) (v))
|
|
||||||
#define POP( out ) (void) ((out) = *sp++)
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define PUSH16( data )\
|
#define PUSH16( data )\
|
||||||
{\
|
{\
|
||||||
int addr = (sp -= 2) - ram;\
|
PUSH( (data & 0xff00) >> 8 );\
|
||||||
if ( addr > 0x100 )\
|
PUSH( data & 0xff );\
|
||||||
{\
|
|
||||||
SET_LE16( sp, data );\
|
|
||||||
}\
|
|
||||||
else\
|
|
||||||
{\
|
|
||||||
ram [(uint8_t) addr + 0x100] = (uint8_t) data;\
|
|
||||||
sp [1] = (uint8_t) (data >> 8);\
|
|
||||||
sp += 0x100;\
|
|
||||||
}\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PUSH( data )\
|
#define PUSH( data )\
|
||||||
{\
|
{\
|
||||||
*--sp = (uint8_t) (data);\
|
ram [0x100 + sp] = (uint8_t) (data);\
|
||||||
if ( sp - ram == 0x100 )\
|
--sp;\
|
||||||
sp += 0x100;\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define POP( out )\
|
#define POP( out )\
|
||||||
{\
|
{\
|
||||||
out = *sp++;\
|
++sp;\
|
||||||
if ( sp - ram == 0x201 )\
|
out = ram [0x100 + sp];\
|
||||||
{\
|
|
||||||
out = sp [-0x101];\
|
|
||||||
sp -= 0x100;\
|
|
||||||
}\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
|
#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
|
||||||
|
|
||||||
unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time )
|
unsigned SNES_SPC::CPU_mem_bit( uint16_t pc, rel_time_t rel_time )
|
||||||
{
|
{
|
||||||
unsigned addr = READ_PC16( pc );
|
unsigned addr = READ_PC16( pc );
|
||||||
unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);
|
unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13);
|
||||||
@ -163,11 +138,11 @@ int const nz_neg_mask = 0x880; // either bit set indicates N flag set
|
|||||||
SPC_CPU_RUN_FUNC
|
SPC_CPU_RUN_FUNC
|
||||||
{
|
{
|
||||||
uint8_t* const ram = RAM;
|
uint8_t* const ram = RAM;
|
||||||
int a = m.cpu_regs.a;
|
uint8_t a = m.cpu_regs.a;
|
||||||
int x = m.cpu_regs.x;
|
uint8_t x = m.cpu_regs.x;
|
||||||
int y = m.cpu_regs.y;
|
uint8_t y = m.cpu_regs.y;
|
||||||
uint8_t const* pc;
|
uint16_t pc;
|
||||||
uint8_t* sp;
|
uint8_t sp;
|
||||||
int psw;
|
int psw;
|
||||||
int c;
|
int c;
|
||||||
int nz;
|
int nz;
|
||||||
@ -183,7 +158,7 @@ SPC_CPU_RUN_FUNC
|
|||||||
// Main loop
|
// Main loop
|
||||||
|
|
||||||
cbranch_taken_loop:
|
cbranch_taken_loop:
|
||||||
pc += *(BOOST::int8_t const*) pc;
|
pc += (int8_t) ram [pc];
|
||||||
inc_pc_loop:
|
inc_pc_loop:
|
||||||
pc++;
|
pc++;
|
||||||
loop:
|
loop:
|
||||||
@ -195,7 +170,7 @@ loop:
|
|||||||
check( (unsigned) x < 0x100 );
|
check( (unsigned) x < 0x100 );
|
||||||
check( (unsigned) y < 0x100 );
|
check( (unsigned) y < 0x100 );
|
||||||
|
|
||||||
opcode = *pc;
|
opcode = ram [pc];
|
||||||
if (allow_time_overflow && rel_time >= 0 )
|
if (allow_time_overflow && rel_time >= 0 )
|
||||||
goto stop;
|
goto stop;
|
||||||
if ( (rel_time += m.cycle_table [opcode]) > 0 && !allow_time_overflow)
|
if ( (rel_time += m.cycle_table [opcode]) > 0 && !allow_time_overflow)
|
||||||
@ -219,14 +194,9 @@ loop:
|
|||||||
PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 );
|
PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef DEBUGGER
|
|
||||||
if (debug_trace)
|
|
||||||
debug_do_trace(a, x, y, pc, sp, psw, c, nz, dp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: if PC is at end of memory, this will get wrong operand (very obscure)
|
// TODO: if PC is at end of memory, this will get wrong operand (very obscure)
|
||||||
data = *++pc;
|
pc++;
|
||||||
|
data = ram [pc];
|
||||||
switch ( opcode )
|
switch ( opcode )
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -257,23 +227,12 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 0x6F:// RET
|
case 0x6F:// RET
|
||||||
#if SPC_NO_SP_WRAPAROUND
|
|
||||||
{
|
{
|
||||||
SET_PC( GET_LE16( sp ) );
|
uint8_t l, h;
|
||||||
sp += 2;
|
POP( l );
|
||||||
|
POP( h );
|
||||||
|
SET_PC( l | (h << 8) );
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
{
|
|
||||||
int addr = sp - ram;
|
|
||||||
SET_PC( GET_LE16( sp ) );
|
|
||||||
sp += 2;
|
|
||||||
if ( addr < 0x1FF )
|
|
||||||
goto loop;
|
|
||||||
|
|
||||||
SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] );
|
|
||||||
sp -= 0x100;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
case 0xE4: // MOV a,dp
|
case 0xE4: // MOV a,dp
|
||||||
@ -493,7 +452,7 @@ loop:
|
|||||||
|
|
||||||
case 0xAF: // MOV (X)+,A
|
case 0xAF: // MOV (X)+,A
|
||||||
WRITE_DP( 0, x, a + no_read_before_write );
|
WRITE_DP( 0, x, a + no_read_before_write );
|
||||||
x++;
|
x = (uint8_t) (x + 1);
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
// 5. 8-BIT LOGIC OPERATION COMMANDS
|
// 5. 8-BIT LOGIC OPERATION COMMANDS
|
||||||
@ -512,7 +471,7 @@ loop:
|
|||||||
case op + 0x01: /* dp,dp */\
|
case op + 0x01: /* dp,dp */\
|
||||||
data = READ_DP( -3, data );\
|
data = READ_DP( -3, data );\
|
||||||
case op + 0x10:{/*dp,imm*/\
|
case op + 0x10:{/*dp,imm*/\
|
||||||
uint8_t const* addr2 = pc + 1;\
|
uint16_t addr2 = pc + 1;\
|
||||||
pc += 2;\
|
pc += 2;\
|
||||||
addr = READ_PC( addr2 ) + dp;\
|
addr = READ_PC( addr2 ) + dp;\
|
||||||
}\
|
}\
|
||||||
@ -816,7 +775,7 @@ loop:
|
|||||||
unsigned temp = y * a;
|
unsigned temp = y * a;
|
||||||
a = (uint8_t) temp;
|
a = (uint8_t) temp;
|
||||||
nz = ((temp >> 1) | temp) & 0x7F;
|
nz = ((temp >> 1) | temp) & 0x7F;
|
||||||
y = temp >> 8;
|
y = (uint8_t) (temp >> 8);
|
||||||
nz |= y;
|
nz |= y;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
@ -846,6 +805,7 @@ loop:
|
|||||||
|
|
||||||
nz = (uint8_t) a;
|
nz = (uint8_t) a;
|
||||||
a = (uint8_t) a;
|
a = (uint8_t) a;
|
||||||
|
y = (uint8_t) y;
|
||||||
|
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
@ -1009,10 +969,12 @@ loop:
|
|||||||
|
|
||||||
{
|
{
|
||||||
int temp;
|
int temp;
|
||||||
|
uint8_t l, h;
|
||||||
case 0x7F: // RET1
|
case 0x7F: // RET1
|
||||||
temp = *sp;
|
POP (temp);
|
||||||
SET_PC( GET_LE16( sp + 1 ) );
|
POP (l);
|
||||||
sp += 3;
|
POP (h);
|
||||||
|
SET_PC( l | (h << 8) );
|
||||||
goto set_psw;
|
goto set_psw;
|
||||||
case 0x8E: // POP PSW
|
case 0x8E: // POP PSW
|
||||||
POP( temp );
|
POP( temp );
|
||||||
@ -1204,9 +1166,9 @@ loop:
|
|||||||
m.cpu_error = "SPC emulation error";
|
m.cpu_error = "SPC emulation error";
|
||||||
goto stop;
|
goto stop;
|
||||||
} // switch
|
} // switch
|
||||||
}
|
}
|
||||||
out_of_time:
|
out_of_time:
|
||||||
rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode
|
rel_time -= m.cycle_table [ ram [pc] ]; // undo partial execution of opcode
|
||||||
stop:
|
stop:
|
||||||
|
|
||||||
// Uncache registers
|
// Uncache registers
|
||||||
|
Loading…
Reference in New Issue
Block a user