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
|
||||
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 )
|
||||
{
|
||||
@ -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%
|
||||
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 )
|
||||
{
|
||||
if ( i < rom_size )
|
||||
{
|
||||
m.hi_ram [i] = (uint8_t) data;
|
||||
if ( m.rom_enabled )
|
||||
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 );
|
||||
}
|
||||
m.hi_ram [i] = (uint8_t) data;
|
||||
|
||||
if ( m.rom_enabled )
|
||||
RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
|
||||
}
|
||||
|
||||
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 )
|
||||
|
||||
@ -463,7 +455,7 @@ inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time )
|
||||
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 )
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
#ifndef SNES_SPC_H
|
||||
#define SNES_SPC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "SPC_DSP.h"
|
||||
#include "blargg_endian.h"
|
||||
|
||||
@ -171,12 +173,12 @@ private:
|
||||
|
||||
struct
|
||||
{
|
||||
int pc;
|
||||
int a;
|
||||
int x;
|
||||
int y;
|
||||
int psw;
|
||||
int sp;
|
||||
uint16_t pc;
|
||||
uint8_t a;
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t psw;
|
||||
uint8_t sp;
|
||||
} cpu_regs;
|
||||
|
||||
rel_time_t dsp_time;
|
||||
@ -202,13 +204,11 @@ private:
|
||||
|
||||
struct
|
||||
{
|
||||
// padding to neutralize address overflow
|
||||
union {
|
||||
uint8_t padding1 [0x100];
|
||||
uint16_t align; // makes compiler align data for 16-bit access
|
||||
} padding1 [1];
|
||||
uint8_t ram [0x10000];
|
||||
uint8_t padding2 [0x100];
|
||||
// padding to neutralize address overflow -- but this is
|
||||
// still undefined behavior! TODO: remove and instead properly
|
||||
// guard usage of emulated memory
|
||||
uint8_t padding1 [0x100];
|
||||
alignas(uint16_t) uint8_t ram [0x10000 + 0x100];
|
||||
} ram;
|
||||
};
|
||||
state_t m;
|
||||
@ -244,13 +244,13 @@ private:
|
||||
Timer* run_timer ( Timer* t, rel_time_t );
|
||||
int dsp_read ( 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, 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, uint16_t addr );
|
||||
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 ( int addr, rel_time_t );
|
||||
unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t );
|
||||
int cpu_read ( uint16_t addr, rel_time_t );
|
||||
unsigned CPU_mem_bit ( uint16_t pc, rel_time_t );
|
||||
|
||||
bool check_echo_access ( int addr );
|
||||
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
|
||||
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.
|
||||
|
@ -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 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 GET_PC() (pc - ram)
|
||||
#define READ_PC( pc ) (*(pc))
|
||||
#define READ_PC16( pc ) GET_LE16( pc )
|
||||
#define SET_PC( n ) (pc = n)
|
||||
#define GET_PC() (pc)
|
||||
#define READ_PC( pc ) (ram [pc])
|
||||
#define READ_PC16( pc ) READ_PROG16( pc )
|
||||
|
||||
// TODO: remove non-wrapping versions?
|
||||
#define SPC_NO_SP_WRAPAROUND 0
|
||||
#define SET_SP( v ) (sp = v)
|
||||
#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 )\
|
||||
{\
|
||||
int addr = (sp -= 2) - ram;\
|
||||
if ( addr > 0x100 )\
|
||||
{\
|
||||
SET_LE16( sp, data );\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
ram [(uint8_t) addr + 0x100] = (uint8_t) data;\
|
||||
sp [1] = (uint8_t) (data >> 8);\
|
||||
sp += 0x100;\
|
||||
}\
|
||||
PUSH( (data & 0xff00) >> 8 );\
|
||||
PUSH( data & 0xff );\
|
||||
}
|
||||
|
||||
#define PUSH( data )\
|
||||
{\
|
||||
*--sp = (uint8_t) (data);\
|
||||
if ( sp - ram == 0x100 )\
|
||||
sp += 0x100;\
|
||||
ram [0x100 + sp] = (uint8_t) (data);\
|
||||
--sp;\
|
||||
}
|
||||
|
||||
#define POP( out )\
|
||||
{\
|
||||
out = *sp++;\
|
||||
if ( sp - ram == 0x201 )\
|
||||
{\
|
||||
out = sp [-0x101];\
|
||||
sp -= 0x100;\
|
||||
}\
|
||||
++sp;\
|
||||
out = ram [0x100 + sp];\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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 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
|
||||
{
|
||||
uint8_t* const ram = RAM;
|
||||
int a = m.cpu_regs.a;
|
||||
int x = m.cpu_regs.x;
|
||||
int y = m.cpu_regs.y;
|
||||
uint8_t const* pc;
|
||||
uint8_t* sp;
|
||||
uint8_t a = m.cpu_regs.a;
|
||||
uint8_t x = m.cpu_regs.x;
|
||||
uint8_t y = m.cpu_regs.y;
|
||||
uint16_t pc;
|
||||
uint8_t sp;
|
||||
int psw;
|
||||
int c;
|
||||
int nz;
|
||||
@ -183,7 +158,7 @@ SPC_CPU_RUN_FUNC
|
||||
// Main loop
|
||||
|
||||
cbranch_taken_loop:
|
||||
pc += *(BOOST::int8_t const*) pc;
|
||||
pc += (int8_t) ram [pc];
|
||||
inc_pc_loop:
|
||||
pc++;
|
||||
loop:
|
||||
@ -195,7 +170,7 @@ loop:
|
||||
check( (unsigned) x < 0x100 );
|
||||
check( (unsigned) y < 0x100 );
|
||||
|
||||
opcode = *pc;
|
||||
opcode = ram [pc];
|
||||
if (allow_time_overflow && rel_time >= 0 )
|
||||
goto stop;
|
||||
if ( (rel_time += m.cycle_table [opcode]) > 0 && !allow_time_overflow)
|
||||
@ -219,14 +194,9 @@ loop:
|
||||
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)
|
||||
data = *++pc;
|
||||
pc++;
|
||||
data = ram [pc];
|
||||
switch ( opcode )
|
||||
{
|
||||
|
||||
@ -257,23 +227,12 @@ loop:
|
||||
}
|
||||
|
||||
case 0x6F:// RET
|
||||
#if SPC_NO_SP_WRAPAROUND
|
||||
{
|
||||
SET_PC( GET_LE16( sp ) );
|
||||
sp += 2;
|
||||
uint8_t l, h;
|
||||
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;
|
||||
|
||||
case 0xE4: // MOV a,dp
|
||||
@ -493,7 +452,7 @@ loop:
|
||||
|
||||
case 0xAF: // MOV (X)+,A
|
||||
WRITE_DP( 0, x, a + no_read_before_write );
|
||||
x++;
|
||||
x = (uint8_t) (x + 1);
|
||||
goto loop;
|
||||
|
||||
// 5. 8-BIT LOGIC OPERATION COMMANDS
|
||||
@ -512,7 +471,7 @@ loop:
|
||||
case op + 0x01: /* dp,dp */\
|
||||
data = READ_DP( -3, data );\
|
||||
case op + 0x10:{/*dp,imm*/\
|
||||
uint8_t const* addr2 = pc + 1;\
|
||||
uint16_t addr2 = pc + 1;\
|
||||
pc += 2;\
|
||||
addr = READ_PC( addr2 ) + dp;\
|
||||
}\
|
||||
@ -816,7 +775,7 @@ loop:
|
||||
unsigned temp = y * a;
|
||||
a = (uint8_t) temp;
|
||||
nz = ((temp >> 1) | temp) & 0x7F;
|
||||
y = temp >> 8;
|
||||
y = (uint8_t) (temp >> 8);
|
||||
nz |= y;
|
||||
goto loop;
|
||||
}
|
||||
@ -846,6 +805,7 @@ loop:
|
||||
|
||||
nz = (uint8_t) a;
|
||||
a = (uint8_t) a;
|
||||
y = (uint8_t) y;
|
||||
|
||||
goto loop;
|
||||
}
|
||||
@ -1009,10 +969,12 @@ loop:
|
||||
|
||||
{
|
||||
int temp;
|
||||
uint8_t l, h;
|
||||
case 0x7F: // RET1
|
||||
temp = *sp;
|
||||
SET_PC( GET_LE16( sp + 1 ) );
|
||||
sp += 3;
|
||||
POP (temp);
|
||||
POP (l);
|
||||
POP (h);
|
||||
SET_PC( l | (h << 8) );
|
||||
goto set_psw;
|
||||
case 0x8E: // POP PSW
|
||||
POP( temp );
|
||||
@ -1204,9 +1166,9 @@ loop:
|
||||
m.cpu_error = "SPC emulation error";
|
||||
goto stop;
|
||||
} // switch
|
||||
}
|
||||
}
|
||||
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:
|
||||
|
||||
// Uncache registers
|
||||
|
Loading…
Reference in New Issue
Block a user