Save states: exact load for Ms. Pac-Man, SNK, Bubble Bobble, OPL, SCSP and Sega Model 2 (#2182)

- mspacman: the mapped ROM (decoded set or boot ROM)
- snk.c: the sound command/busy register, the sprite blink parity, the
  tile cache marked dirty after a load
- fmopl.c: the whole YM3812/YM3526/Y8950 state (channels, operators,
  envelopes, LFO, noise, timers, status, Delta-T ADPCM); replaces the
  register replay of #2045 (3812intf.c back to its earlier version)
- scsp.c: chip registers, slots, LFOs, DSP, timers, MIDI FIFOs, DMA
- model2: which CPU waits on the i960/copro FIFOs, the SCSP IRQ line
- bublbobl: ROM bank, display enable, sound NMI, MCU port latches
- m6800.c: the 6801/6803/63701 internal registers (ports, timer, TCSR,
  RAM control, WAI state)
- mb86233.c: the stall flag


Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX

Co-authored-by: Claude <[email protected]>
This commit is contained in:
zanacandClaude authored and GitHub committed 2026-10-30 02:47:53 -04:00
1 parent 0ad96d5104
commit d7117cdcdc
12 files changed
+472 -55

No files matched your search

+18
View File
@@ -554,6 +554,24 @@ static void state_register(const char *type)
state_save_register_UINT8 (type, cpu, "NMI_STATE", &m6800.nmi_state, 1);
state_save_register_UINT8 (type, cpu, "IRQ_STATE", &m6800.irq_state[M6800_IRQ_LINE], 1);
state_save_register_UINT8 (type, cpu, "TIN_STATE", &m6800.irq_state[M6800_TIN_LINE], 1);
state_save_register_UINT16(type, cpu, "PPC", &m6800.ppc.w.l, 1);
state_save_register_UINT8 (type, cpu, "WAI_STATE", &m6800.wai_state, 1);
state_save_register_UINT8 (type, cpu, "IC_EDDGE", &m6800.ic_eddge, 1);
state_save_register_int (type, cpu, "EXTRA_CYCLES", &m6800.extra_cycles);
/* the internal registers of the 6801/6803/63701: ports, timer, RAM control */
state_save_register_UINT8 (type, cpu, "PORT1_DDR", &m6800.port1_ddr, 1);
state_save_register_UINT8 (type, cpu, "PORT2_DDR", &m6800.port2_ddr, 1);
state_save_register_UINT8 (type, cpu, "PORT1_DATA", &m6800.port1_data, 1);
state_save_register_UINT8 (type, cpu, "PORT2_DATA", &m6800.port2_data, 1);
state_save_register_UINT8 (type, cpu, "TCSR", &m6800.tcsr, 1);
state_save_register_UINT8 (type, cpu, "PENDING_TCSR", &m6800.pending_tcsr, 1);
state_save_register_UINT8 (type, cpu, "IRQ2", &m6800.irq2, 1);
state_save_register_UINT8 (type, cpu, "RAM_CTRL", &m6800.ram_ctrl, 1);
state_save_register_UINT32(type, cpu, "COUNTER", &m6800.counter.d, 1);
state_save_register_UINT32(type, cpu, "OUTPUT_COMPARE", &m6800.output_compare.d, 1);
state_save_register_UINT16(type, cpu, "INPUT_CAPTURE", &m6800.input_capture, 1);
state_save_register_UINT32(type, cpu, "TIMER_OVER", &m6800.timer_over.d, 1);
state_save_register_UINT32(type, cpu, "TIMER_NEXT", &timer_next, 1);
}
void m6800_init(void)
+2
View File
@@ -1160,6 +1160,8 @@ void mb86233_init( void )
state_save_register_int( "mb86233", cpu, "gpio1", &mb.gpio[ 1 ] );
state_save_register_int( "mb86233", cpu, "gpio2", &mb.gpio[ 2 ] );
state_save_register_int( "mb86233", cpu, "gpio3", &mb.gpio[ 3 ] );
/* a stalled FIFO access is retried when the CPU runs again */
state_save_register_int( "mb86233", cpu, "stall", &mb.stall );
}
void mb86233_reset( void *param )
+41 -1
View File
@@ -138,6 +138,7 @@ CPU 3
#include "driver.h"
#include "vidhrdw/generic.h"
#include "cpu/m6805/m6805.h"
#include "state.h"
static int ddr1, ddr2, ddr3, ddr4;
static int port1_in, port2_in, port3_in, port4_in;
@@ -170,6 +171,26 @@ WRITE_HANDLER( bublbobl_sh_nmi_disable_w );
WRITE_HANDLER( bublbobl_sh_nmi_enable_w );
void bublbobl_save_state(void);
/* save states: the M6801 ports here, the rest in machine/bublbobl_machine.c */
static void bublbobl_register_state(void)
{
bublbobl_save_state();
state_save_register_int("bublbobl", 0, "ddr1", &ddr1);
state_save_register_int("bublbobl", 0, "ddr2", &ddr2);
state_save_register_int("bublbobl", 0, "ddr3", &ddr3);
state_save_register_int("bublbobl", 0, "ddr4", &ddr4);
state_save_register_int("bublbobl", 0, "port1_in", &port1_in);
state_save_register_int("bublbobl", 0, "port2_in", &port2_in);
state_save_register_int("bublbobl", 0, "port3_in", &port3_in);
state_save_register_int("bublbobl", 0, "port4_in", &port4_in);
state_save_register_int("bublbobl", 0, "port1_out", &port1_out);
state_save_register_int("bublbobl", 0, "port2_out", &port2_out);
state_save_register_int("bublbobl", 0, "port3_out", &port3_out);
state_save_register_int("bublbobl", 0, "port4_out", &port4_out);
}
READ_HANDLER( bublbobl_mcu_ddr1_r )
{
return ddr1;
@@ -302,6 +323,24 @@ static unsigned char portA_in,portA_out,ddrA;
static unsigned char portB_in,portB_out,ddrB;
static unsigned char portC_in,portC_out,ddrC;
static void tokio_register_state(void)
{
bublbobl_save_state();
state_save_register_UINT8("tokio", 0, "from_main", &from_main, 1);
state_save_register_UINT8("tokio", 0, "from_mcu", &from_mcu, 1);
state_save_register_int ("tokio", 0, "mcu_sent", &mcu_sent);
state_save_register_int ("tokio", 0, "main_sent", &main_sent);
state_save_register_UINT8("tokio", 0, "portA_in", &portA_in, 1);
state_save_register_UINT8("tokio", 0, "portA_out", &portA_out, 1);
state_save_register_UINT8("tokio", 0, "ddrA", &ddrA, 1);
state_save_register_UINT8("tokio", 0, "portB_in", &portB_in, 1);
state_save_register_UINT8("tokio", 0, "portB_out", &portB_out, 1);
state_save_register_UINT8("tokio", 0, "ddrB", &ddrB, 1);
state_save_register_UINT8("tokio", 0, "portC_in", &portC_in, 1);
state_save_register_UINT8("tokio", 0, "portC_out", &portC_out, 1);
state_save_register_UINT8("tokio", 0, "ddrC", &ddrC, 1);
}
READ_HANDLER( tokio_68705_portA_r )
{
return (portA_out & ddrA) | (portA_in & ~ddrA);
@@ -1720,6 +1759,7 @@ static DRIVER_INIT( bublbobl )
memcpy(ROM+0x08000,ROM+0x10000,0x4000);
bublbobl_video_enable = 1;
bublbobl_register_state();
}
static DRIVER_INIT( boblbobl )
@@ -1745,7 +1785,7 @@ static DRIVER_INIT( tokio )
/* preemptively enable video, the bit is not mapped for this game and */
/* I don't know if it even has it. */
bublbobl_video_enable = 1;
bublbobl_video_enable = 1; tokio_register_state();
}
+1
View File
@@ -1881,6 +1881,7 @@ static DRIVER_INIT( model2a )
state_save_register_UINT8( "model2comm", 0, "zfg", &m2comm_zfg, 1 );
state_save_register_UINT8( "model2", 0, "io_analog_channel", &io_analog_channel, 1 );
state_save_register_UINT8( "model2", 0, "lightgun_mux", &m_lightgun_mux, 1 );
state_save_register_int( "model2", 0, "scsp_last_line", &scsp_last_line );
state_save_register_func_postload( model2_postload );
}
+20
View File
@@ -216,6 +216,7 @@ Credits (in alphabetical order)
***************************************************************************/
#include "driver.h"
#include "state.h"
#include "vidhrdw/generic.h"
#include "cpu/z80/z80.h"
#include "snk.h"
@@ -289,6 +290,14 @@ static int hard_flags;
*/
static int snk_sound_register;
/* the sound handshake register is part of the save state (the sound CPU
went another way after loading a state in a new instance) */
static MACHINE_INIT( snk )
{
snk_sound_register = 0;
state_save_register_int("snk", 0, "sound_register", &snk_sound_register);
}
/*********************************************************************/
static int snk_rot8( int which ){
@@ -1058,6 +1067,7 @@ static MACHINE_DRIVER_START( tnk3 )
MDRV_PALETTE_INIT(aso)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(tnk3)
/* sound hardware */
@@ -1094,6 +1104,7 @@ static MACHINE_DRIVER_START( athena )
MDRV_PALETTE_INIT(aso)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(tnk3)
/* sound hardware */
@@ -1130,6 +1141,7 @@ static MACHINE_DRIVER_START( ikari )
MDRV_PALETTE_INIT(snk_3bpp_shadow)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(ikari)
/* sound hardware */
@@ -1168,6 +1180,7 @@ static MACHINE_DRIVER_START( victroad )
MDRV_PALETTE_INIT(snk_3bpp_shadow)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(ikari)
/* sound hardware */
@@ -1205,6 +1218,7 @@ static MACHINE_DRIVER_START( gwar )
MDRV_PALETTE_INIT(RRRR_GGGG_BBBB)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(gwar)
/* sound hardware */
@@ -1243,6 +1257,7 @@ static MACHINE_DRIVER_START( bermudat )
MDRV_PALETTE_INIT(RRRR_GGGG_BBBB)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(gwar)
/* sound hardware */
@@ -1280,6 +1295,7 @@ static MACHINE_DRIVER_START( psychos )
MDRV_PALETTE_INIT(RRRR_GGGG_BBBB)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(gwar)
/* sound hardware */
@@ -1317,6 +1333,7 @@ static MACHINE_DRIVER_START( chopper1 )
MDRV_PALETTE_INIT(RRRR_GGGG_BBBB)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(gwar)
/* sound hardware */
@@ -1354,6 +1371,7 @@ static MACHINE_DRIVER_START( tdfever )
MDRV_PALETTE_INIT(snk_4bpp_shadow)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(tdfever)
/* sound hardware */
@@ -1391,6 +1409,7 @@ static MACHINE_DRIVER_START( tdfever2 )
MDRV_PALETTE_INIT(snk_4bpp_shadow)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(tdfever)
/* sound hardware */
@@ -1428,6 +1447,7 @@ static MACHINE_DRIVER_START( ftsoccer )
MDRV_PALETTE_INIT(snk_4bpp_shadow)
MDRV_VIDEO_START(snk)
MDRV_MACHINE_INIT(snk)
MDRV_VIDEO_UPDATE(tdfever)
/* sound hardware */
+39 -2
View File
@@ -10,12 +10,26 @@
#include "driver.h"
#include "cpu/z80/z80.h"
#include "vidhrdw/generic.h"
#include "state.h"
unsigned char *bublbobl_sharedram1,*bublbobl_sharedram2;
extern int bublbobl_video_enable;
/* the ROM bank at 0x8000, -1 until the game selects one */
static int bublbobl_bank = -1;
static void bublbobl_set_bank(void)
{
unsigned char *ROM = memory_region(REGION_CPU1);
if (bublbobl_bank >= 0)
cpu_setbank(1,&ROM[0x10000 + 0x4000 * bublbobl_bank]);
else
cpu_setbank(1,&ROM[0x8000]);
}
READ_HANDLER( bublbobl_sharedram1_r )
{
@@ -41,7 +55,8 @@ WRITE_HANDLER( bublbobl_bankswitch_w )
unsigned char *ROM = memory_region(REGION_CPU1);
/* bits 0-2 select ROM bank */
cpu_setbank(1,&ROM[0x10000 + 0x4000 * ((data ^ 4) & 7)]);
bublbobl_bank = (data ^ 4) & 7;
cpu_setbank(1,&ROM[0x10000 + 0x4000 * bublbobl_bank]);
/* bit 3 n.c. */
@@ -65,7 +80,8 @@ WRITE_HANDLER( tokio_bankswitch_w )
unsigned char *ROM = memory_region(REGION_CPU1);
/* bits 0-2 select ROM bank */
cpu_setbank(1,&ROM[0x10000 + 0x4000 * (data & 7)]);
bublbobl_bank = data & 7;
cpu_setbank(1,&ROM[0x10000 + 0x4000 * bublbobl_bank]);
/* bits 3-7 unknown */
}
@@ -257,3 +273,24 @@ WRITE_HANDLER( bublbobl_68705_ddrB_w )
{
ddrB = data;
}
/* save states: the ROM bank, the display enable, the sound NMI and the
68705 ports of Bubble Bobble and Tokio */
void bublbobl_save_state(void)
{
bublbobl_bank = -1;
state_save_register_int ("bublbobl", 0, "bank", &bublbobl_bank);
state_save_register_int ("bublbobl", 0, "video_enable", &bublbobl_video_enable);
state_save_register_int ("bublbobl", 0, "sound_nmi_enable", &sound_nmi_enable);
state_save_register_int ("bublbobl", 0, "pending_nmi", &pending_nmi);
state_save_register_UINT8("bublbobl", 0, "portA_in", &portA_in, 1);
state_save_register_UINT8("bublbobl", 0, "portA_out", &portA_out, 1);
state_save_register_UINT8("bublbobl", 0, "ddrA", &ddrA, 1);
state_save_register_UINT8("bublbobl", 0, "portB_in", &portB_in, 1);
state_save_register_UINT8("bublbobl", 0, "portB_out", &portB_out, 1);
state_save_register_UINT8("bublbobl", 0, "ddrB", &ddrB, 1);
state_save_register_int ("bublbobl", 0, "address", &address);
state_save_register_int ("bublbobl", 0, "latch", &latch);
state_save_register_func_postload(bublbobl_set_bank);
}
+23
View File
@@ -526,11 +526,27 @@ READ32_HANDLER( model2_copro_status_r )
static UINT32 fifo_in_save[ FIFO_ALLOC ], fifo_out_save[ FIFO_ALLOC ];
static int fifo_in_count, fifo_out_count;
static INT32 fifo_waits_save[ 4 ];
static void fifo_wait_load( struct m2_fifo *f, int reader_waits, int writer_waits )
{
f->reader_waits = reader_waits ? 1 : 0;
f->writer_waits = writer_waits ? 1 : 0;
if( f->reader_waits )
cpunum_suspend( f->reader, SUSPEND_REASON_SPIN, 1 );
if( f->writer_waits )
cpunum_suspend( f->writer, SUSPEND_REASON_SPIN, 1 );
}
static void copro_presave( void )
{
int i;
fifo_in_count = fifo_in.count;
fifo_out_count = fifo_out.count;
fifo_waits_save[ 0 ] = fifo_in.reader_waits;
fifo_waits_save[ 1 ] = fifo_in.writer_waits;
fifo_waits_save[ 2 ] = fifo_out.reader_waits;
fifo_waits_save[ 3 ] = fifo_out.writer_waits;
for( i = 0; i < fifo_in.count; i++ )
fifo_in_save[ i ] = fifo_in.data[ ( fifo_in.head + i ) % FIFO_ALLOC ];
for( i = 0; i < fifo_out.count; i++ )
@@ -548,6 +564,12 @@ static void copro_postload( void )
fifo_out.data[ i ] = fifo_out_save[ i ];
fifo_in.count = fifo_in_count;
fifo_out.count = fifo_out_count;
if( model2_copro_type == MODEL2_COPRO_SHARC )
sharc_flags_update();
/* the CPUs waiting on a FIFO at the save wait again, so that the
access that ends the wait resumes them */
fifo_wait_load( &fifo_in, fifo_waits_save[ 0 ], fifo_waits_save[ 1 ] );
fifo_wait_load( &fifo_out, fifo_waits_save[ 2 ], fifo_waits_save[ 3 ] );
if( tgp_booted )
cpunum_resume( CPU_TGP, SUSPEND_REASON_HALT );
else
@@ -585,6 +607,7 @@ void model2_copro_init( void )
state_save_register_UINT32( "model2tgp", 0, "fifo_out", fifo_out_save, FIFO_ALLOC );
state_save_register_int( "model2tgp", 0, "fifo_in_count", &fifo_in_count );
state_save_register_int( "model2tgp", 0, "fifo_out_count", &fifo_out_count );
state_save_register_INT32( "model2tgp", 0, "fifo_waits", fifo_waits_save, 4 );
state_save_register_func_presave( copro_presave );
state_save_register_func_postload( copro_postload );
}
+23 -5
View File
@@ -1,6 +1,7 @@
#include "driver.h"
#include "vidhrdw/generic.h"
#include "state.h"
/*
@@ -180,11 +181,26 @@ void mspacman_decode(void)
}
MACHINE_INIT( mspacman )
/* the board boots from the original Pac-Man ROMs and switches to the
decoded Ms. Pac-Man ROMs on a write to 0x5006; the switch is part of the
save state, so that a state loaded in a new instance runs the same code */
static UINT8 mspacman_rom_active;
static void mspacman_set_bank(void)
{
unsigned char *RAM = memory_region(REGION_CPU1);
cpu_setbank (1, &RAM[mspacman_rom_active ? 0x10000 : 0x00000]);
}
MACHINE_INIT( mspacman )
{
mspacman_decode();
cpu_setbank (1, &RAM[0x00000]);
mspacman_rom_active = 0;
mspacman_set_bank();
state_save_register_UINT8("mspacman", 0, "rom_active", &mspacman_rom_active, 1);
state_save_register_func_postload(mspacman_set_bank);
machine_init_pacman();
}
@@ -192,7 +208,9 @@ MACHINE_INIT( mspacman )
WRITE_HANDLER( mspacman_activate_rom )
{
unsigned char *RAM = memory_region(REGION_CPU1);
if(data==1) cpu_setbank (1, &RAM[0x10000]);
if (data == 1)
{
mspacman_rom_active = 1;
mspacman_set_bank();
}
}
+4 -47
View File
@@ -18,7 +18,6 @@
******************************************************************************/
#include "driver.h"
#include "3812intf.h"
#include "state.h"
#include "fm.h"
#include "sound/fmopl.h"
@@ -28,42 +27,6 @@
static int stream_3812[MAX_3812];
static void *Timer_3812[MAX_3812*2];
static const struct YM3812interface *intf_3812 = NULL;
/* The OPL core keeps no save state: the interface keeps a copy of every
register written (and the address register), saves it, and writes it all
back on load. That restores the channels and starts the timers again, which
sound CPUs that wait on the timer flag or take its interrupt need. */
static UINT8 regs_3812[MAX_3812][256];
static UINT8 addr_3812[MAX_3812];
static void YM3812_postload(void)
{
int i, r;
for (i = 0; i < intf_3812->num; i++)
{
YM3812ResetChip(i);
for (r = 0x01; r < 0x100; r++)
{
if (r == 0x04)
continue;
YM3812Write(i, 0, r);
YM3812Write(i, 1, regs_3812[i][r]);
}
/* the timers last: their load values are in place, start them (bit 7, the IRQ reset, is an action) */
YM3812Write(i, 0, 0x04);
YM3812Write(i, 1, regs_3812[i][0x04] & 0x63);
YM3812Write(i, 0, addr_3812[i]);
}
}
static void YM3812_write_shadow(int n, int a, int data)
{
if (a == 0)
addr_3812[n] = data;
else
regs_3812[n][addr_3812[n]] = data;
YM3812Write(n, a, data);
}
static void IRQHandler_3812(int n,int irq)
{
if (intf_3812->handler[n]) (intf_3812->handler[n])(irq ? ASSERT_LINE : CLEAR_LINE);
@@ -123,13 +86,7 @@ int YM3812_sh_start(const struct MachineSound *msound)
Timer_3812[i*2+0] = timer_alloc(timer_callback_3812);
Timer_3812[i*2+1] = timer_alloc(timer_callback_3812);
memset(regs_3812[i], 0, sizeof(regs_3812[i]));
addr_3812[i] = 0;
state_save_register_UINT8("YM3812", i, "regs", regs_3812[i], 256);
state_save_register_UINT8("YM3812", i, "address", &addr_3812[i], 1);
}
state_save_register_func_postload(YM3812_postload);
return 0;
}
@@ -148,10 +105,10 @@ void YM3812_sh_reset(void)
}
WRITE_HANDLER( YM3812_control_port_0_w ) {
YM3812_write_shadow(0, 0, data);
YM3812Write(0, 0, data);
}
WRITE_HANDLER( YM3812_write_port_0_w ) {
YM3812_write_shadow(0, 1, data);
YM3812Write(0, 1, data);
}
READ_HANDLER( YM3812_status_port_0_r ) {
return YM3812Read(0, 0);
@@ -162,10 +119,10 @@ READ_HANDLER( YM3812_read_port_0_r ) {
WRITE_HANDLER( YM3812_control_port_1_w ) {
YM3812_write_shadow(1, 0, data);
YM3812Write(1, 0, data);
}
WRITE_HANDLER( YM3812_write_port_1_w ) {
YM3812_write_shadow(1, 1, data);
YM3812Write(1, 1, data);
}
READ_HANDLER( YM3812_status_port_1_r ) {
return YM3812Read(1, 0);
+161
View File
@@ -73,6 +73,7 @@ Revision History:
#include "driver.h" /* use M.A.M.E. */
#include "state.h"
#include "ymdeltat.h"
#include "fmopl.h"
@@ -2006,6 +2007,157 @@ static int OPLTimerOver(FM_OPL *OPL,int c)
#define MAX_OPL_CHIPS 2
/* Save states: the whole chip state, so that a state loaded in a new
instance (netplay, RunAhead with a second instance) goes on exactly as
the running one. Only pointers are left out: connect1 is rebuilt from
CON, and the Delta-T pan pointer is kept as its index. */
static FM_OPL *OPL_saved[3 * MAX_OPL_CHIPS];
static int OPL_saved_count;
#if BUILD_Y8950
static UINT8 OPL_deltat_pan[3 * MAX_OPL_CHIPS];
#endif
static void OPL_save_presave(void)
{
#if BUILD_Y8950
int i;
for (i = 0; i < OPL_saved_count; i++)
{
YM_DELTAT *DELTAT = OPL_saved[i]->deltat;
if (DELTAT && DELTAT->pan && DELTAT->output_pointer)
OPL_deltat_pan[i] = DELTAT->pan - DELTAT->output_pointer;
}
#endif
}
static void OPL_save_postload(void)
{
int i, ch;
for (i = 0; i < OPL_saved_count; i++)
{
FM_OPL *OPL = OPL_saved[i];
for (ch = 0; ch < 9; ch++)
{
OPL_SLOT *SLOT = &OPL->P_CH[ch].SLOT[SLOT1];
SLOT->connect1 = SLOT->CON ? &output[0] : &phase_modulation;
}
#if BUILD_Y8950
if (OPL->deltat && OPL->deltat->output_pointer)
{
OPL->deltat->pan = &OPL->deltat->output_pointer[OPL_deltat_pan[i] & 3];
}
#endif
}
}
static void OPL_save_state(FM_OPL *OPL, const char *name, int num)
{
char buf[32];
int ch, s;
if (OPL_saved_count >= 3 * MAX_OPL_CHIPS)
return;
OPL_saved[OPL_saved_count++] = OPL;
for (ch = 0; ch < 9; ch++)
{
OPL_CH *CH = &OPL->P_CH[ch];
sprintf(buf, "%s.ch%d", name, ch);
state_save_register_UINT32(buf, num, "block_fnum", &CH->block_fnum, 1);
state_save_register_UINT32(buf, num, "fc", &CH->fc, 1);
state_save_register_UINT32(buf, num, "ksl_base", &CH->ksl_base, 1);
state_save_register_UINT8 (buf, num, "kcode", &CH->kcode, 1);
for (s = 0; s < 2; s++)
{
OPL_SLOT *SLOT = &CH->SLOT[s];
sprintf(buf, "%s.ch%d.slot%d", name, ch, s);
state_save_register_UINT32(buf, num, "ar", &SLOT->ar, 1);
state_save_register_UINT32(buf, num, "dr", &SLOT->dr, 1);
state_save_register_UINT32(buf, num, "rr", &SLOT->rr, 1);
state_save_register_UINT8 (buf, num, "KSR", &SLOT->KSR, 1);
state_save_register_UINT8 (buf, num, "ksl", &SLOT->ksl, 1);
state_save_register_UINT8 (buf, num, "ksr", &SLOT->ksr, 1);
state_save_register_UINT8 (buf, num, "mul", &SLOT->mul, 1);
state_save_register_UINT32(buf, num, "Cnt", &SLOT->Cnt, 1);
state_save_register_UINT32(buf, num, "Incr", &SLOT->Incr, 1);
state_save_register_UINT8 (buf, num, "FB", &SLOT->FB, 1);
state_save_register_INT32 (buf, num, "op1_out", SLOT->op1_out, 2);
state_save_register_UINT8 (buf, num, "CON", &SLOT->CON, 1);
state_save_register_UINT8 (buf, num, "eg_type", &SLOT->eg_type, 1);
state_save_register_UINT8 (buf, num, "state", &SLOT->state, 1);
state_save_register_UINT32(buf, num, "TL", &SLOT->TL, 1);
state_save_register_INT32 (buf, num, "TLL", &SLOT->TLL, 1);
state_save_register_INT32 (buf, num, "volume", &SLOT->volume, 1);
state_save_register_UINT32(buf, num, "sl", &SLOT->sl, 1);
state_save_register_UINT8 (buf, num, "eg_sh_ar", &SLOT->eg_sh_ar, 1);
state_save_register_UINT8 (buf, num, "eg_sel_ar", &SLOT->eg_sel_ar, 1);
state_save_register_UINT8 (buf, num, "eg_sh_dr", &SLOT->eg_sh_dr, 1);
state_save_register_UINT8 (buf, num, "eg_sel_dr", &SLOT->eg_sel_dr, 1);
state_save_register_UINT8 (buf, num, "eg_sh_rr", &SLOT->eg_sh_rr, 1);
state_save_register_UINT8 (buf, num, "eg_sel_rr", &SLOT->eg_sel_rr, 1);
state_save_register_UINT32(buf, num, "key", &SLOT->key, 1);
state_save_register_UINT32(buf, num, "AMmask", &SLOT->AMmask, 1);
state_save_register_UINT8 (buf, num, "vib", &SLOT->vib, 1);
state_save_register_UINT16(buf, num, "wavetable", &SLOT->wavetable, 1);
}
}
state_save_register_UINT32(name, num, "eg_cnt", &OPL->eg_cnt, 1);
state_save_register_UINT32(name, num, "eg_timer", &OPL->eg_timer, 1);
state_save_register_UINT8 (name, num, "rhythm", &OPL->rhythm, 1);
state_save_register_UINT8 (name, num, "lfo_am_depth", &OPL->lfo_am_depth, 1);
state_save_register_UINT8 (name, num, "lfo_pm_depth_range", &OPL->lfo_pm_depth_range, 1);
state_save_register_UINT32(name, num, "lfo_am_cnt", &OPL->lfo_am_cnt, 1);
state_save_register_UINT32(name, num, "lfo_pm_cnt", &OPL->lfo_pm_cnt, 1);
state_save_register_UINT32(name, num, "noise_rng", &OPL->noise_rng, 1);
state_save_register_UINT32(name, num, "noise_p", &OPL->noise_p, 1);
state_save_register_UINT8 (name, num, "wavesel", &OPL->wavesel, 1);
state_save_register_UINT32(name, num, "T", OPL->T, 2);
state_save_register_UINT8 (name, num, "st", OPL->st, 2);
state_save_register_UINT8 (name, num, "address", &OPL->address, 1);
state_save_register_UINT8 (name, num, "status", &OPL->status, 1);
state_save_register_UINT8 (name, num, "statusmask", &OPL->statusmask, 1);
state_save_register_UINT8 (name, num, "mode", &OPL->mode, 1);
#if BUILD_Y8950
if (OPL->deltat)
{
YM_DELTAT *DELTAT = OPL->deltat;
state_save_register_UINT8 (name, num, "portDirection", &OPL->portDirection, 1);
state_save_register_UINT8 (name, num, "portLatch", &OPL->portLatch, 1);
sprintf(buf, "%s.deltat", name);
state_save_register_UINT32(buf, num, "now_addr", &DELTAT->now_addr, 1);
state_save_register_UINT32(buf, num, "now_step", &DELTAT->now_step, 1);
state_save_register_UINT32(buf, num, "step", &DELTAT->step, 1);
state_save_register_UINT32(buf, num, "start", &DELTAT->start, 1);
state_save_register_UINT32(buf, num, "limit", &DELTAT->limit, 1);
state_save_register_UINT32(buf, num, "end", &DELTAT->end, 1);
state_save_register_UINT32(buf, num, "delta", &DELTAT->delta, 1);
state_save_register_INT32 (buf, num, "volume", &DELTAT->volume, 1);
state_save_register_INT32 (buf, num, "acc", &DELTAT->acc, 1);
state_save_register_INT32 (buf, num, "adpcmd", &DELTAT->adpcmd, 1);
state_save_register_INT32 (buf, num, "adpcml", &DELTAT->adpcml, 1);
state_save_register_INT32 (buf, num, "prev_acc", &DELTAT->prev_acc, 1);
state_save_register_UINT8 (buf, num, "now_data", &DELTAT->now_data, 1);
state_save_register_UINT8 (buf, num, "CPU_data", &DELTAT->CPU_data, 1);
state_save_register_UINT8 (buf, num, "portstate", &DELTAT->portstate, 1);
state_save_register_UINT8 (buf, num, "control2", &DELTAT->control2, 1);
state_save_register_UINT8 (buf, num, "portshift", &DELTAT->portshift, 1);
state_save_register_UINT8 (buf, num, "DRAMportshift", &DELTAT->DRAMportshift, 1);
state_save_register_UINT8 (buf, num, "memread", &DELTAT->memread, 1);
state_save_register_UINT8 (buf, num, "PCM_BSY", &DELTAT->PCM_BSY, 1);
state_save_register_UINT8 (buf, num, "reg", DELTAT->reg, 16);
state_save_register_UINT8 (buf, num, "pan", &OPL_deltat_pan[OPL_saved_count - 1], 1);
}
#endif
state_save_register_func_presave(OPL_save_presave);
state_save_register_func_postload(OPL_save_postload);
}
static void OPL_save_reset(void)
{
OPL_saved_count = 0;
}
#if (BUILD_YM3812)
static FM_OPL *OPL_YM3812[MAX_OPL_CHIPS]; /* array of pointers to the YM3812's */
@@ -2032,6 +2184,7 @@ int YM3812Init(int num, int clock, int rate)
}
/* reset */
YM3812ResetChip(i);
OPL_save_state(OPL_YM3812[i], "YM3812", i);
}
return 0;
@@ -2041,6 +2194,8 @@ void YM3812Shutdown(void)
{
int i;
OPL_save_reset();
for (i = 0;i < YM3812NumChips; i++)
{
/* emulator shutdown */
@@ -2183,6 +2338,7 @@ int YM3526Init(int num, int clock, int rate)
}
/* reset */
YM3526ResetChip(i);
OPL_save_state(OPL_YM3526[i], "YM3526", i);
}
return 0;
@@ -2192,6 +2348,8 @@ void YM3526Shutdown(void)
{
int i;
OPL_save_reset();
for (i = 0;i < YM3526NumChips; i++)
{
/* emulator shutdown */
@@ -2352,6 +2510,7 @@ int Y8950Init(int num, int clock, int rate)
/*OPL_Y8950[i]->deltat->read_time = 8.0 / clock;*/ /* a single byte read takes 8 cycles of main clock */
/* reset */
Y8950ResetChip(i);
OPL_save_state(OPL_Y8950[i], "Y8950", i);
}
return 0;
@@ -2361,6 +2520,8 @@ void Y8950Shutdown(void)
{
int i;
OPL_save_reset();
for (i = 0;i < Y8950NumChips; i++)
{
/* emulator shutdown */
+131
View File
@@ -23,6 +23,7 @@
#include <string.h>
#include "driver.h"
#include "cpuintrf.h"
#include "state.h"
static signed short *bufferl;
static signed short *bufferr;
@@ -1095,6 +1096,134 @@ static void SCSP_Update(int num, short **buf, int samples)
SCSP_DoMasterSamples(num, samples);
}
/* Save states: the chip registers, the slots (phase, envelope, LFOs),
the effect DSP, the timers, the interrupts and the MIDI FIFOs, so that
a state loaded in a new instance goes on exactly as the running one.
The pointers (sample base, LFO tables) are kept as offsets. */
static UINT32 SCSP_ss_base[MAX_SCSP][32];
static UINT8 SCSP_ss_lfo[MAX_SCSP][32][4]; /* PLFO table, PLFO scale, ALFO table, ALFO scale */
static int SCSP_lfo_table_index(int *table, int alfo)
{
if (alfo)
{
if (table == ALFO_SQR) return 1;
if (table == ALFO_TRI) return 2;
if (table == ALFO_NOI) return 3;
return 0;
}
if (table == PLFO_SQR) return 1;
if (table == PLFO_TRI) return 2;
if (table == PLFO_NOI) return 3;
return 0;
}
static int *SCSP_lfo_table(int index, int alfo)
{
static int *atab[4] = { ALFO_SAW, ALFO_SQR, ALFO_TRI, ALFO_NOI };
static int *ptab[4] = { PLFO_SAW, PLFO_SQR, PLFO_TRI, PLFO_NOI };
return alfo ? atab[index & 3] : ptab[index & 3];
}
static void SCSP_presave(void)
{
int i, s;
for (i = 0; i < MAX_SCSP; i++)
for (s = 0; s < 32; s++)
{
struct _SLOT *slot = &SCSPs[i].Slots[s];
SCSP_ss_base[i][s] = (slot->base && SCSPs[i].SCSPRAM) ? (UINT32)(slot->base - SCSPs[i].SCSPRAM) : 0;
SCSP_ss_lfo[i][s][0] = slot->PLFO.table ? SCSP_lfo_table_index(slot->PLFO.table, 0) : 0;
SCSP_ss_lfo[i][s][1] = slot->PLFO.scale ? (UINT8)((slot->PLFO.scale - PSCALES[0]) / 256) : 0;
SCSP_ss_lfo[i][s][2] = slot->ALFO.table ? SCSP_lfo_table_index(slot->ALFO.table, 1) : 0;
SCSP_ss_lfo[i][s][3] = slot->ALFO.scale ? (UINT8)((slot->ALFO.scale - ASCALES[0]) / 256) : 0;
}
}
static void SCSP_postload(void)
{
int i, s;
for (i = 0; i < MAX_SCSP; i++)
for (s = 0; s < 32; s++)
{
struct _SLOT *slot = &SCSPs[i].Slots[s];
slot->base = SCSPs[i].SCSPRAM ? SCSPs[i].SCSPRAM + SCSP_ss_base[i][s] : NULL;
slot->PLFO.table = SCSP_lfo_table(SCSP_ss_lfo[i][s][0], 0);
slot->PLFO.scale = PSCALES[SCSP_ss_lfo[i][s][1] & 7];
slot->ALFO.table = SCSP_lfo_table(SCSP_ss_lfo[i][s][2], 1);
slot->ALFO.scale = ASCALES[SCSP_ss_lfo[i][s][3] & 7];
}
}
static void SCSP_save_state(int num)
{
char buf[32];
int i, s;
for (i = 0; i < num; i++)
{
struct _SCSP *chip = &SCSPs[i];
struct _SCSPDSP *DSP = &chip->DSP;
state_save_register_UINT16("SCSP", i, "regs", chip->udata.data, 0x30/2);
state_save_register_int ("SCSP", i, "MvolSet", &chip->MvolSet);
for (s = 0; s < 32; s++)
{
struct _SLOT *slot = &chip->Slots[s];
sprintf(buf, "SCSP.slot%d", s);
state_save_register_UINT16(buf, i, "regs", slot->udata.data, 0x10);
state_save_register_UINT8 (buf, i, "active", &slot->active, 1);
state_save_register_UINT32(buf, i, "base", &SCSP_ss_base[i][s], 1);
state_save_register_UINT32(buf, i, "cur_addr", &slot->cur_addr, 1);
state_save_register_UINT32(buf, i, "step", &slot->step, 1);
state_save_register_int (buf, i, "EG.volume", &slot->EG.volume);
state_save_register_int (buf, i, "EG.state", (int *)&slot->EG.state);
state_save_register_int (buf, i, "EG.step", &slot->EG.step);
state_save_register_int (buf, i, "EG.AR", &slot->EG.AR);
state_save_register_int (buf, i, "EG.D1R", &slot->EG.D1R);
state_save_register_int (buf, i, "EG.D2R", &slot->EG.D2R);
state_save_register_int (buf, i, "EG.RR", &slot->EG.RR);
state_save_register_int (buf, i, "EG.DL", &slot->EG.DL);
state_save_register_UINT8 (buf, i, "EG.EGHOLD", &slot->EG.EGHOLD, 1);
state_save_register_UINT8 (buf, i, "EG.LPLINK", &slot->EG.LPLINK, 1);
state_save_register_UINT16(buf, i, "PLFO.phase", &slot->PLFO.phase, 1);
state_save_register_UINT32(buf, i, "PLFO.phase_step", &slot->PLFO.phase_step, 1);
state_save_register_UINT16(buf, i, "ALFO.phase", &slot->ALFO.phase, 1);
state_save_register_UINT32(buf, i, "ALFO.phase_step", &slot->ALFO.phase_step, 1);
state_save_register_UINT8 (buf, i, "LFO.tables", SCSP_ss_lfo[i][s], 4);
}
state_save_register_UINT32("SCSP.DSP", i, "RBP", &DSP->RBP, 1);
state_save_register_UINT32("SCSP.DSP", i, "RBL", &DSP->RBL, 1);
state_save_register_INT16 ("SCSP.DSP", i, "COEF", DSP->COEF, 64);
state_save_register_UINT16("SCSP.DSP", i, "MADRS", DSP->MADRS, 32);
state_save_register_UINT16("SCSP.DSP", i, "MPRO", DSP->MPRO, 128*4);
state_save_register_INT32 ("SCSP.DSP", i, "TEMP", DSP->TEMP, 128);
state_save_register_INT32 ("SCSP.DSP", i, "MEMS", DSP->MEMS, 32);
state_save_register_UINT32("SCSP.DSP", i, "DEC", &DSP->DEC, 1);
state_save_register_INT32 ("SCSP.DSP", i, "MIXS", DSP->MIXS, 16);
state_save_register_INT16 ("SCSP.DSP", i, "EXTS", DSP->EXTS, 2);
state_save_register_INT16 ("SCSP.DSP", i, "EFREG", DSP->EFREG, 16);
state_save_register_int ("SCSP.DSP", i, "Stopped", &DSP->Stopped);
state_save_register_int ("SCSP.DSP", i, "LastStep", &DSP->LastStep);
}
state_save_register_UINT32("SCSP", 0, "IrqTimA", &IrqTimA, 1);
state_save_register_UINT32("SCSP", 0, "IrqTimBC", &IrqTimBC, 1);
state_save_register_UINT32("SCSP", 0, "IrqMidi", &IrqMidi, 1);
state_save_register_UINT8 ("SCSP", 0, "MidiOutW", &MidiOutW, 1);
state_save_register_UINT8 ("SCSP", 0, "MidiOutR", &MidiOutR, 1);
state_save_register_UINT8 ("SCSP", 0, "MidiStack", MidiStack, 32);
state_save_register_UINT8 ("SCSP", 0, "MidiOutStack", MidiOutStack, 16);
state_save_register_UINT8 ("SCSP", 0, "MidiW", &MidiW, 1);
state_save_register_UINT8 ("SCSP", 0, "MidiR", &MidiR, 1);
state_save_register_INT32 ("SCSP", 0, "TimPris", (INT32 *)TimPris, 3);
state_save_register_INT32 ("SCSP", 0, "TimCnt", (INT32 *)TimCnt, 3);
state_save_register_UINT32("SCSP", 0, "dmea", &scsp_dmea, 1);
state_save_register_UINT16("SCSP", 0, "drga", &scsp_drga, 1);
state_save_register_UINT16("SCSP", 0, "dtlg", &scsp_dtlg, 1);
state_save_register_func_presave(SCSP_presave);
state_save_register_func_postload(SCSP_postload);
}
int SCSP_sh_start(const struct MachineSound *msound)
{
char buf[2][40];
@@ -1124,6 +1253,8 @@ int SCSP_sh_start(const struct MachineSound *msound)
SCSP = &SCSPs[0];
SCSP_save_state(intf->num);
return 0;
}
+9
View File
@@ -1,4 +1,5 @@
#include "driver.h"
#include "state.h"
#include "vidhrdw/generic.h"
#include "snk.h"
@@ -71,9 +72,17 @@ PALETTE_INIT( snk_4bpp_shadow )
gfx_drawmode_table[15] = DRAWMODE_NONE;
}
/* after a state load the tile cache doesn't match the restored video RAM */
static void snk_postload(void)
{
memset( dirtybuffer, 0xff, MAX_VRAM_SIZE );
}
VIDEO_START( snk )
{
snk_blink_parity = 0;
state_save_register_int("snk", 0, "blink_parity", &snk_blink_parity);
state_save_register_func_postload(snk_postload);
dirtybuffer = auto_malloc( MAX_VRAM_SIZE );
if(!dirtybuffer) return 1;