mirror of
https://github.com/libretro/mame2003-plus-libretro.git
synced 2026-11-07 04:16:07 -10:00
Save states: the missing YM2203/YM2610/YM2612, MultiPCM and 6809 state (RunAhead, netplay) (#2176)
Loading a state, and so every RunAhead or netplay rollback, put back an incomplete sound chip or CPU, and the game went on differently from the run that never loaded: the audio of the Mega Drive based boards, Neo Geo and the YM2203 games diverged, and on the 6809 games the game itself. OPN chips (sound/fm.c): - The reset sets the L/R pan of all the channels (0xb4-0xb6) and clears 0x30-0xb2 without storing them in REGS; the postload rewrites REGS, so a channel the game never panned itself was muted after a load (the DAC of the Bare Knuckle games). The reset values are now in REGS (YM2203, YM2608, YM2610, YM2612), and the YM2612 DAC select too. - The postloads of the YM2608 and YM2610 skipped 0xb6 (pan, AMS, PMS of the 3rd channel of each bank), as the YM2612 one did before. - The chip recomputes its phase steps and envelope rates only when a register asks for it, so they can lag behind the registers (e.g. after a 3 slot mode change). They are now saved as they are, with the key codes and the LFO step, instead of being remade from the registers. The YM2612 and YM2610 extra state is one shared block (OPN_EXT), now also used by the YM2203, which had none. - The YM2612 DAC value is saved as it is: before the first write it is 0, which is not what the register gives (aladmdb). - YM2610: the extra FM and SSG state was opt-in (only zn.c asked for it); it is now always saved (Neo Geo). The opt-in FM timers stay as they were. SSG (sound/ay8910.c): the periods of the SSG of a YM chip are saved as they were made; the register rewrite of the postload remade them with the current clock. The YM2203 now saves the SSG extra state too. MultiPCM (sound/multipcm.c): the sample pointer of a voice was remade from the registers at load, without the bank and with the sample number of now, not of the key on; it is saved as its offset in the ROM. The release counter is saved too (Star Wars Arcade). 6809 family: the M6809 did not save the accumulators (D), the HD6309 D and W; the M6809, HD6309 and Konami did not save the cycles of an interrupt taken outside the execute loop. Claude-Session: https://claude.ai/code/session_01N3fzdsnzkQVtgYtYzqepjX Co-authored-by: Claude <[email protected]>
This commit is contained in:
1 parent
9649c81834
commit
6266128ce8
8 files changed
+190
-156
No files matched your search
@@ -587,6 +587,8 @@ void hd6309_init(void)
|
||||
state_save_register_UINT16("hd6309", cpu, "X", &X, 1);
|
||||
state_save_register_UINT16("hd6309", cpu, "Y", &Y, 1);
|
||||
state_save_register_UINT16("hd6309", cpu, "V", &V, 1);
|
||||
state_save_register_UINT16("hd6309", cpu, "D", &D, 1); /* the accumulators A and B */
|
||||
state_save_register_UINT16("hd6309", cpu, "W", &W, 1); /* the accumulators E and F */
|
||||
state_save_register_UINT8("hd6309", cpu, "DP", &DP, 1);
|
||||
state_save_register_UINT8("hd6309", cpu, "CC", &CC, 1);
|
||||
state_save_register_UINT8("hd6309", cpu, "MD", &MD, 1);
|
||||
@@ -595,6 +597,7 @@ void hd6309_init(void)
|
||||
state_save_register_UINT8("hd6309", cpu, "NMI", &hd6309.nmi_state, 1);
|
||||
state_save_register_UINT8("hd6309", cpu, "IRQ", &hd6309.irq_state[0], 1);
|
||||
state_save_register_UINT8("hd6309", cpu, "FIRQ", &hd6309.irq_state[1], 1);
|
||||
state_save_register_int("hd6309", cpu, "extra_cycles", &hd6309.extra_cycles); /* the cycles of an interrupt taken outside the execute loop */
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -483,6 +483,7 @@ void konami_init(void)
|
||||
state_save_register_UINT8("konami", cpu, "NMI", &konami.nmi_state, 1);
|
||||
state_save_register_UINT8("konami", cpu, "IRQ", &konami.irq_state[0], 1);
|
||||
state_save_register_UINT8("konami", cpu, "FIRQ", &konami.irq_state[1], 1);
|
||||
state_save_register_int("konami", cpu, "extra_cycles", &konami.extra_cycles); /* the cycles of an interrupt taken outside the execute loop */
|
||||
}
|
||||
|
||||
void konami_reset(void *param)
|
||||
|
||||
@@ -512,12 +512,14 @@ void m6809_init(void)
|
||||
state_save_register_UINT16("m6809", cpu, "S", &S, 1);
|
||||
state_save_register_UINT16("m6809", cpu, "X", &X, 1);
|
||||
state_save_register_UINT16("m6809", cpu, "Y", &Y, 1);
|
||||
state_save_register_UINT16("m6809", cpu, "D", &D, 1); /* the accumulators A and B */
|
||||
state_save_register_UINT8("m6809", cpu, "DP", &DP, 1);
|
||||
state_save_register_UINT8("m6809", cpu, "CC", &CC, 1);
|
||||
state_save_register_UINT8("m6809", cpu, "INT", &m6809.int_state, 1);
|
||||
state_save_register_UINT8("m6809", cpu, "NMI", &m6809.nmi_state, 1);
|
||||
state_save_register_UINT8("m6809", cpu, "IRQ", &m6809.irq_state[0], 1);
|
||||
state_save_register_UINT8("m6809", cpu, "FIRQ", &m6809.irq_state[1], 1);
|
||||
state_save_register_int("m6809", cpu, "extra_cycles", &m6809.extra_cycles); /* the cycles of an interrupt taken outside the execute loop */
|
||||
}
|
||||
|
||||
void m6809_reset(void *param)
|
||||
|
||||
@@ -73,6 +73,10 @@ int YM2203_sh_start(const struct MachineSound *msound)
|
||||
|
||||
intf = msound->sound_interface;
|
||||
|
||||
/* the SSG state the YM2203 save state leaves out (before YM2203Init:
|
||||
the postloads run last registered first) */
|
||||
AY8910_ym_ext_state_register(intf->num);
|
||||
|
||||
/* Timer Handler set */
|
||||
FMTimerInit();
|
||||
/* stream system initialize */
|
||||
|
||||
+12
-12
@@ -76,10 +76,8 @@ static void FMTimerInit( void )
|
||||
}
|
||||
}
|
||||
|
||||
/* optional: keep the two FM timers of each chip in save states (the core
|
||||
does not save its timers), with the parts of the FM and SSG state the
|
||||
YM2610 save state leaves out. Opt-in, so the save states of the other
|
||||
YM2610 drivers keep their layout. */
|
||||
/* optional: keep the two FM timers of each chip in save states (from before
|
||||
the core saved its timers) */
|
||||
static void YM2610_timer_presave( void )
|
||||
{
|
||||
int n, c;
|
||||
@@ -116,16 +114,18 @@ static void YM2610_timer_state_start( void )
|
||||
{
|
||||
int n;
|
||||
memset( timer_on, 0, sizeof( timer_on ) );
|
||||
if( !timer_state_wanted )
|
||||
return;
|
||||
for( n = 0; n < intf->num; n++ )
|
||||
if( timer_state_wanted )
|
||||
{
|
||||
state_save_register_UINT8( "ym2610timer", n, "on", timer_on[n], 2 );
|
||||
state_save_register_double( "ym2610timer", n, "left", timer_left[n], 2 );
|
||||
for( n = 0; n < intf->num; n++ )
|
||||
{
|
||||
state_save_register_UINT8( "ym2610timer", n, "on", timer_on[n], 2 );
|
||||
state_save_register_double( "ym2610timer", n, "left", timer_left[n], 2 );
|
||||
}
|
||||
state_save_register_func_presave( YM2610_timer_presave );
|
||||
state_save_register_func_postload( YM2610_timer_postload );
|
||||
}
|
||||
state_save_register_func_presave( YM2610_timer_presave );
|
||||
state_save_register_func_postload( YM2610_timer_postload );
|
||||
/* the chip and SSG state the YM2610 save state leaves out */
|
||||
/* the chip and SSG state the YM2610 save state leaves out: for all the
|
||||
games (Neo Geo too), the save states and RunAhead lost it */
|
||||
YM2610_ext_state_register( intf->num );
|
||||
AY8910_ym_ext_state_register( intf->num );
|
||||
}
|
||||
|
||||
+7
-1
@@ -832,7 +832,7 @@ int AY8910_sh_start_ym(const struct MachineSound *msound)
|
||||
/* optional: the internal counters of the SSG of a YM chip in save states.
|
||||
The YM postload rewrites the SSG registers, which restarts the envelope,
|
||||
so the counters are kept in a copy and put back after it. */
|
||||
#define AY_EXT_INT 12
|
||||
#define AY_EXT_INT 17
|
||||
#define AY_EXT_U8 13
|
||||
static INT32 ay_ext_int[MAX_8910][AY_EXT_INT];
|
||||
static UINT8 ay_ext_u8[MAX_8910][AY_EXT_U8];
|
||||
@@ -850,6 +850,10 @@ static void AY8910_ext_presave(void)
|
||||
i[3] = PSG->CountN; i[4] = PSG->CountE; i[5] = PSG->RNG;
|
||||
i[6] = PSG->VolA; i[7] = PSG->VolB; i[8] = PSG->VolC; i[9] = PSG->VolE;
|
||||
i[10] = PSG->lastEnable; i[11] = PSG->register_latch;
|
||||
/* the periods as they were made: a clock change (the YM prescaler)
|
||||
does not remake them, the register rewrite of the postload does */
|
||||
i[12] = PSG->PeriodA; i[13] = PSG->PeriodB; i[14] = PSG->PeriodC;
|
||||
i[15] = PSG->PeriodN; i[16] = PSG->PeriodE;
|
||||
u[0] = PSG->EnvelopeA; u[1] = PSG->EnvelopeB; u[2] = PSG->EnvelopeC;
|
||||
u[3] = PSG->OutputA; u[4] = PSG->OutputB; u[5] = PSG->OutputC; u[6] = PSG->OutputN;
|
||||
u[7] = (UINT8)PSG->CountEnv; u[8] = PSG->Hold; u[9] = PSG->Alternate;
|
||||
@@ -869,6 +873,8 @@ static void AY8910_ext_postload(void)
|
||||
PSG->CountN = i[3]; PSG->CountE = i[4]; PSG->RNG = i[5];
|
||||
PSG->VolA = i[6]; PSG->VolB = i[7]; PSG->VolC = i[8]; PSG->VolE = i[9];
|
||||
PSG->lastEnable = i[10]; PSG->register_latch = i[11];
|
||||
PSG->PeriodA = i[12]; PSG->PeriodB = i[13]; PSG->PeriodC = i[14];
|
||||
PSG->PeriodN = i[15]; PSG->PeriodE = i[16];
|
||||
PSG->EnvelopeA = u[0]; PSG->EnvelopeB = u[1]; PSG->EnvelopeC = u[2];
|
||||
PSG->OutputA = u[3]; PSG->OutputB = u[4]; PSG->OutputC = u[5]; PSG->OutputN = u[6];
|
||||
PSG->CountEnv = (signed char)u[7]; PSG->Hold = u[8]; PSG->Alternate = u[9];
|
||||
|
||||
+140
-134
@@ -1820,6 +1820,86 @@ static void FMsave_state_st(const char *state_name,int num,FM_ST *ST)
|
||||
state_save_register_UINT8 (state_name, num, "TIMER B" , &ST->TB , 1);
|
||||
state_save_register_int (state_name, num, "TIMER Bcnt", &ST->TBC );
|
||||
}
|
||||
|
||||
#if (BUILD_YM2203||BUILD_YM2610||BUILD_YM2610B||BUILD_YM2612||BUILD_YM3438)
|
||||
/* the parts of an OPN chip state that the registers and FMsave_state_channel
|
||||
leave out: global envelope and LFO counters, key state, SSG-EG negation,
|
||||
envelope output, algorithm memory, key codes and the phase steps and
|
||||
envelope rates. The chip recomputes the steps and rates only when a
|
||||
register write asks for it, so they can lag behind the registers (e.g.
|
||||
after a 3 slot mode change) and are saved as they are. The postload of
|
||||
the chip rewrites the registers, which changes some of them, so they are
|
||||
kept in a copy and put back after it. */
|
||||
typedef struct
|
||||
{
|
||||
UINT32 eg_cnt, eg_timer, lfo_cnt, lfo_inc;
|
||||
UINT32 key[6*4], vol_out[6*4];
|
||||
UINT8 ssgn[6*4];
|
||||
INT32 mem_value[6];
|
||||
UINT8 kcode[6];
|
||||
UINT32 block_fnum[6];
|
||||
UINT32 sl3_block_fnum[3];
|
||||
INT32 incr[6*4];
|
||||
UINT8 ksr[6*4];
|
||||
UINT8 eg_rates[6*4*8];
|
||||
} OPN_EXT;
|
||||
|
||||
static void opn_ext_copy(FM_OPN *OPN, FM_CH *CH, int channels, OPN_EXT *e, int restore)
|
||||
{
|
||||
int c, s, i;
|
||||
|
||||
#define OPN_EXT_COPY(chip, saved) if (restore) (chip) = (saved); else (saved) = (chip)
|
||||
OPN_EXT_COPY(OPN->eg_cnt, e->eg_cnt);
|
||||
OPN_EXT_COPY(OPN->eg_timer, e->eg_timer);
|
||||
OPN_EXT_COPY(OPN->lfo_cnt, e->lfo_cnt);
|
||||
OPN_EXT_COPY(OPN->lfo_inc, e->lfo_inc);
|
||||
for (c = 0; c < 3; c++)
|
||||
OPN_EXT_COPY(OPN->SL3.block_fnum[c], e->sl3_block_fnum[c]);
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
OPN_EXT_COPY(CH[c].mem_value, e->mem_value[c]);
|
||||
OPN_EXT_COPY(CH[c].kcode, e->kcode[c]);
|
||||
OPN_EXT_COPY(CH[c].block_fnum, e->block_fnum[c]);
|
||||
for (s = 0; s < 4; s++)
|
||||
{
|
||||
FM_SLOT *SLOT = &CH[c].SLOT[s];
|
||||
UINT8 *rates[8];
|
||||
UINT8 *r = &e->eg_rates[(c*4+s)*8];
|
||||
|
||||
OPN_EXT_COPY(SLOT->key, e->key[c*4+s]);
|
||||
OPN_EXT_COPY(SLOT->vol_out, e->vol_out[c*4+s]);
|
||||
OPN_EXT_COPY(SLOT->ssgn, e->ssgn[c*4+s]);
|
||||
OPN_EXT_COPY(SLOT->Incr, e->incr[c*4+s]);
|
||||
OPN_EXT_COPY(SLOT->ksr, e->ksr[c*4+s]);
|
||||
rates[0] = &SLOT->eg_sh_ar; rates[1] = &SLOT->eg_sel_ar;
|
||||
rates[2] = &SLOT->eg_sh_d1r; rates[3] = &SLOT->eg_sel_d1r;
|
||||
rates[4] = &SLOT->eg_sh_d2r; rates[5] = &SLOT->eg_sel_d2r;
|
||||
rates[6] = &SLOT->eg_sh_rr; rates[7] = &SLOT->eg_sel_rr;
|
||||
for (i = 0; i < 8; i++)
|
||||
OPN_EXT_COPY(*rates[i], r[i]);
|
||||
}
|
||||
}
|
||||
#undef OPN_EXT_COPY
|
||||
}
|
||||
|
||||
static void opn_ext_register(const char *name, int num, OPN_EXT *e)
|
||||
{
|
||||
state_save_register_UINT32(name, num, "eg_cnt", &e->eg_cnt, 1);
|
||||
state_save_register_UINT32(name, num, "eg_timer", &e->eg_timer, 1);
|
||||
state_save_register_UINT32(name, num, "lfo_cnt", &e->lfo_cnt, 1);
|
||||
state_save_register_UINT32(name, num, "key", e->key, 6*4);
|
||||
state_save_register_UINT32(name, num, "vol_out", e->vol_out, 6*4);
|
||||
state_save_register_UINT8(name, num, "ssgn", e->ssgn, 6*4);
|
||||
state_save_register_INT32(name, num, "mem_value", e->mem_value, 6);
|
||||
state_save_register_UINT32(name, num, "lfo_inc", &e->lfo_inc, 1);
|
||||
state_save_register_UINT8(name, num, "kcode", e->kcode, 6);
|
||||
state_save_register_UINT32(name, num, "block_fnum", e->block_fnum, 6);
|
||||
state_save_register_UINT32(name, num, "sl3_block_fnum", e->sl3_block_fnum, 3);
|
||||
state_save_register_INT32(name, num, "incr", e->incr, 6*4);
|
||||
state_save_register_UINT8(name, num, "ksr", e->ksr, 6*4);
|
||||
state_save_register_UINT8(name, num, "eg_rates", e->eg_rates, 6*4*8);
|
||||
}
|
||||
#endif
|
||||
#endif /* _STATE_H */
|
||||
|
||||
#if BUILD_OPN
|
||||
@@ -2305,7 +2385,11 @@ void YM2203ResetChip(int num)
|
||||
|
||||
reset_channels( &OPN->ST , FM2203[num].CH , 3 );
|
||||
/* reset OPerator paramater */
|
||||
for(i = 0xb2 ; i >= 0x30 ; i-- ) OPNWriteReg(OPN,i,0);
|
||||
for(i = 0xb2 ; i >= 0x30 ; i-- )
|
||||
{
|
||||
OPNWriteReg(OPN,i,0);
|
||||
FM2203[num].REGS[i] = 0; /* the reset values, for the save states */
|
||||
}
|
||||
for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
|
||||
}
|
||||
|
||||
@@ -2342,11 +2426,40 @@ static void YM2203_postload(void)
|
||||
cur_chip = NULL;
|
||||
}
|
||||
|
||||
/* the parts of the chip state that the registers leave out (see OPN_EXT) */
|
||||
static OPN_EXT *ym2203_ext;
|
||||
|
||||
static void YM2203_ext_presave(void)
|
||||
{
|
||||
int num;
|
||||
for (num = 0; num < YM2203NumChips; num++)
|
||||
opn_ext_copy(&FM2203[num].OPN, FM2203[num].CH, 3, &ym2203_ext[num], 0);
|
||||
}
|
||||
|
||||
static void YM2203_ext_postload(void)
|
||||
{
|
||||
int num;
|
||||
for (num = 0; num < YM2203NumChips; num++)
|
||||
opn_ext_copy(&FM2203[num].OPN, FM2203[num].CH, 3, &ym2203_ext[num], 1);
|
||||
}
|
||||
|
||||
static void YM2203_save_state(void)
|
||||
{
|
||||
int num;
|
||||
const char statename[] = "YM2203";
|
||||
|
||||
/* registered before YM2203_postload (the postloads run last registered
|
||||
first), so it puts its values back after the registers are rewritten */
|
||||
ym2203_ext = auto_malloc(sizeof(*ym2203_ext) * YM2203NumChips);
|
||||
if (ym2203_ext != NULL)
|
||||
{
|
||||
memset(ym2203_ext, 0, sizeof(*ym2203_ext) * YM2203NumChips);
|
||||
for (num = 0; num < YM2203NumChips; num++)
|
||||
opn_ext_register("YM2203ext", num, &ym2203_ext[num]);
|
||||
state_save_register_func_presave(YM2203_ext_presave);
|
||||
state_save_register_func_postload(YM2203_ext_postload);
|
||||
}
|
||||
|
||||
for(num=0;num<YM2203NumChips;num++)
|
||||
{
|
||||
state_save_register_UINT8 (statename, num, "regs" , FM2203[num].REGS , 256);
|
||||
@@ -3565,7 +3678,7 @@ static void YM2608_postload(void)
|
||||
OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]);
|
||||
}
|
||||
/* FB / CONNECT , L / R / AMS / PMS */
|
||||
for(r=0xb0;r<0xb6;r++)
|
||||
for(r=0xb0;r<0xb7;r++) /* b4-b6: L/R, AMS, PMS of channels 1-3 */
|
||||
if((r&3) != 3)
|
||||
{
|
||||
OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]);
|
||||
@@ -3729,11 +3842,13 @@ void YM2608ResetChip(int num)
|
||||
{
|
||||
OPNWriteReg(OPN,i ,0xc0);
|
||||
OPNWriteReg(OPN,i|0x100,0xc0);
|
||||
FM2608[num].REGS[i] = FM2608[num].REGS[i|0x100] = 0xc0; /* the reset values, for the save states (the postload writes them back) */
|
||||
}
|
||||
for(i = 0xb2 ; i >= 0x30 ; i-- )
|
||||
{
|
||||
OPNWriteReg(OPN,i ,0);
|
||||
OPNWriteReg(OPN,i|0x100,0);
|
||||
FM2608[num].REGS[i] = FM2608[num].REGS[i|0x100] = 0;
|
||||
}
|
||||
for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
|
||||
|
||||
@@ -4269,7 +4384,7 @@ static void YM2610_postload(void)
|
||||
OPNWriteReg(&F2610->OPN,r|0x100,F2610->REGS[r|0x100]);
|
||||
}
|
||||
/* FB / CONNECT , L / R / AMS / PMS */
|
||||
for(r=0xb0;r<0xb6;r++)
|
||||
for(r=0xb0;r<0xb7;r++) /* b4-b6: L/R, AMS, PMS of channels 1-3 */
|
||||
if((r&3) != 3)
|
||||
{
|
||||
OPNWriteReg(&F2610->OPN,r,F2610->REGS[r]);
|
||||
@@ -4295,62 +4410,23 @@ static void YM2610_postload(void)
|
||||
}
|
||||
|
||||
/* optional: the parts of the chip state that YM2610_save_state leaves out
|
||||
(global envelope and LFO counters, key state, SSG-EG negation, the
|
||||
envelope output and the algorithm memory). The postload of the chip
|
||||
rewrites the registers, which changes some of them, so they are kept in
|
||||
a copy and put back after it. */
|
||||
(see OPN_EXT) */
|
||||
#define YM2610_EXT_CHIPS 2
|
||||
static struct
|
||||
{
|
||||
UINT32 eg_cnt, eg_timer, lfo_cnt;
|
||||
UINT32 key[6*4], vol_out[6*4];
|
||||
UINT8 ssgn[6*4];
|
||||
INT32 mem_value[6];
|
||||
} ym2610_ext[YM2610_EXT_CHIPS];
|
||||
static OPN_EXT ym2610_ext[YM2610_EXT_CHIPS];
|
||||
static int ym2610_ext_chips;
|
||||
|
||||
static void YM2610_ext_presave(void)
|
||||
{
|
||||
int num, c, s;
|
||||
int num;
|
||||
for (num = 0; num < ym2610_ext_chips && num < YM2610NumChips; num++)
|
||||
{
|
||||
YM2610 *F2610 = &(FM2610[num]);
|
||||
ym2610_ext[num].eg_cnt = F2610->OPN.eg_cnt;
|
||||
ym2610_ext[num].eg_timer = F2610->OPN.eg_timer;
|
||||
ym2610_ext[num].lfo_cnt = F2610->OPN.lfo_cnt;
|
||||
for (c = 0; c < 6; c++)
|
||||
{
|
||||
ym2610_ext[num].mem_value[c] = F2610->CH[c].mem_value;
|
||||
for (s = 0; s < 4; s++)
|
||||
{
|
||||
ym2610_ext[num].key[c*4+s] = F2610->CH[c].SLOT[s].key;
|
||||
ym2610_ext[num].vol_out[c*4+s] = F2610->CH[c].SLOT[s].vol_out;
|
||||
ym2610_ext[num].ssgn[c*4+s] = F2610->CH[c].SLOT[s].ssgn;
|
||||
}
|
||||
}
|
||||
}
|
||||
opn_ext_copy(&FM2610[num].OPN, FM2610[num].CH, 6, &ym2610_ext[num], 0);
|
||||
}
|
||||
|
||||
static void YM2610_ext_postload(void)
|
||||
{
|
||||
int num, c, s;
|
||||
int num;
|
||||
for (num = 0; num < ym2610_ext_chips && num < YM2610NumChips; num++)
|
||||
{
|
||||
YM2610 *F2610 = &(FM2610[num]);
|
||||
F2610->OPN.eg_cnt = ym2610_ext[num].eg_cnt;
|
||||
F2610->OPN.eg_timer = ym2610_ext[num].eg_timer;
|
||||
F2610->OPN.lfo_cnt = ym2610_ext[num].lfo_cnt;
|
||||
for (c = 0; c < 6; c++)
|
||||
{
|
||||
F2610->CH[c].mem_value = ym2610_ext[num].mem_value[c];
|
||||
for (s = 0; s < 4; s++)
|
||||
{
|
||||
F2610->CH[c].SLOT[s].key = ym2610_ext[num].key[c*4+s];
|
||||
F2610->CH[c].SLOT[s].vol_out = ym2610_ext[num].vol_out[c*4+s];
|
||||
F2610->CH[c].SLOT[s].ssgn = ym2610_ext[num].ssgn[c*4+s];
|
||||
}
|
||||
}
|
||||
}
|
||||
opn_ext_copy(&FM2610[num].OPN, FM2610[num].CH, 6, &ym2610_ext[num], 1);
|
||||
}
|
||||
|
||||
/* call before YM2610Init (the postload functions run last registered first) */
|
||||
@@ -4360,15 +4436,7 @@ void YM2610_ext_state_register(int chips)
|
||||
if (chips > YM2610_EXT_CHIPS) chips = YM2610_EXT_CHIPS;
|
||||
ym2610_ext_chips = chips;
|
||||
for (num = 0; num < chips; num++)
|
||||
{
|
||||
state_save_register_UINT32("YM2610ext", num, "eg_cnt", &ym2610_ext[num].eg_cnt, 1);
|
||||
state_save_register_UINT32("YM2610ext", num, "eg_timer", &ym2610_ext[num].eg_timer, 1);
|
||||
state_save_register_UINT32("YM2610ext", num, "lfo_cnt", &ym2610_ext[num].lfo_cnt, 1);
|
||||
state_save_register_UINT32("YM2610ext", num, "key", ym2610_ext[num].key, 6*4);
|
||||
state_save_register_UINT32("YM2610ext", num, "vol_out", ym2610_ext[num].vol_out, 6*4);
|
||||
state_save_register_UINT8("YM2610ext", num, "ssgn", ym2610_ext[num].ssgn, 6*4);
|
||||
state_save_register_INT32("YM2610ext", num, "mem_value", ym2610_ext[num].mem_value, 6);
|
||||
}
|
||||
opn_ext_register("YM2610ext", num, &ym2610_ext[num]);
|
||||
state_save_register_func_presave(YM2610_ext_presave);
|
||||
state_save_register_func_postload(YM2610_ext_postload);
|
||||
}
|
||||
@@ -4505,11 +4573,13 @@ void YM2610ResetChip(int num)
|
||||
{
|
||||
OPNWriteReg(OPN,i ,0xc0);
|
||||
OPNWriteReg(OPN,i|0x100,0xc0);
|
||||
F2610->REGS[i] = F2610->REGS[i|0x100] = 0xc0; /* the reset values, for the save states (the postload writes them back) */
|
||||
}
|
||||
for(i = 0xb2 ; i >= 0x30 ; i-- )
|
||||
{
|
||||
OPNWriteReg(OPN,i ,0);
|
||||
OPNWriteReg(OPN,i|0x100,0);
|
||||
F2610->REGS[i] = F2610->REGS[i|0x100] = 0;
|
||||
}
|
||||
for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
|
||||
/**** ADPCM work initial ****/
|
||||
@@ -4853,8 +4923,8 @@ static void YM2612_postload(void)
|
||||
|
||||
for(num=0;num<YM2612NumChips;num++)
|
||||
{
|
||||
/* DAC data & port */
|
||||
FM2612[num].dacout = ((int)FM2612[num].REGS[0x2a] - 0x80) << 6; /* level unknown */
|
||||
/* DAC port (the DAC data is saved as it is: before the first write
|
||||
it is 0, which is not what the register would give) */
|
||||
FM2612[num].dacen = FM2612[num].REGS[0x2b] & 0x80; /* DAC Sel (0x2b), as YM2612Write */
|
||||
/* OPN registers */
|
||||
/* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
|
||||
@@ -4877,77 +4947,21 @@ static void YM2612_postload(void)
|
||||
cur_chip = NULL;
|
||||
}
|
||||
|
||||
/* the parts of the chip state that the registers and FMsave_state_channel
|
||||
leave out (global envelope and LFO counters, key state, SSG-EG negation,
|
||||
envelope output, algorithm memory), as for the YM2610: kept in a copy
|
||||
because the postload rewrites the registers, which changes some of them */
|
||||
static struct
|
||||
{
|
||||
UINT32 eg_cnt, eg_timer, lfo_cnt, lfo_inc;
|
||||
UINT32 key[6*4], vol_out[6*4];
|
||||
UINT8 ssgn[6*4];
|
||||
INT32 mem_value[6];
|
||||
UINT8 kcode[6];
|
||||
UINT32 block_fnum[6];
|
||||
UINT32 sl3_block_fnum[3];
|
||||
} *ym2612_ext;
|
||||
/* the parts of the chip state that the registers leave out (see OPN_EXT) */
|
||||
static OPN_EXT *ym2612_ext;
|
||||
|
||||
static void YM2612_ext_presave(void)
|
||||
{
|
||||
int num, c, s;
|
||||
int num;
|
||||
for (num = 0; num < YM2612NumChips; num++)
|
||||
{
|
||||
YM2612 *F2612 = &(FM2612[num]);
|
||||
ym2612_ext[num].eg_cnt = F2612->OPN.eg_cnt;
|
||||
ym2612_ext[num].eg_timer = F2612->OPN.eg_timer;
|
||||
ym2612_ext[num].lfo_cnt = F2612->OPN.lfo_cnt;
|
||||
ym2612_ext[num].lfo_inc = F2612->OPN.lfo_inc;
|
||||
for (c = 0; c < 3; c++)
|
||||
ym2612_ext[num].sl3_block_fnum[c] = F2612->OPN.SL3.block_fnum[c];
|
||||
for (c = 0; c < 6; c++)
|
||||
{
|
||||
ym2612_ext[num].mem_value[c] = F2612->CH[c].mem_value;
|
||||
ym2612_ext[num].kcode[c] = F2612->CH[c].kcode;
|
||||
ym2612_ext[num].block_fnum[c] = F2612->CH[c].block_fnum;
|
||||
for (s = 0; s < 4; s++)
|
||||
{
|
||||
ym2612_ext[num].key[c*4+s] = F2612->CH[c].SLOT[s].key;
|
||||
ym2612_ext[num].vol_out[c*4+s] = F2612->CH[c].SLOT[s].vol_out;
|
||||
ym2612_ext[num].ssgn[c*4+s] = F2612->CH[c].SLOT[s].ssgn;
|
||||
}
|
||||
}
|
||||
}
|
||||
opn_ext_copy(&FM2612[num].OPN, FM2612[num].CH, 6, &ym2612_ext[num], 0);
|
||||
}
|
||||
|
||||
static void YM2612_ext_postload(void)
|
||||
{
|
||||
int num, c, s;
|
||||
int num;
|
||||
for (num = 0; num < YM2612NumChips; num++)
|
||||
{
|
||||
YM2612 *F2612 = &(FM2612[num]);
|
||||
F2612->OPN.eg_cnt = ym2612_ext[num].eg_cnt;
|
||||
F2612->OPN.eg_timer = ym2612_ext[num].eg_timer;
|
||||
F2612->OPN.lfo_cnt = ym2612_ext[num].lfo_cnt;
|
||||
F2612->OPN.lfo_inc = ym2612_ext[num].lfo_inc;
|
||||
for (c = 0; c < 3; c++)
|
||||
F2612->OPN.SL3.block_fnum[c] = ym2612_ext[num].sl3_block_fnum[c];
|
||||
for (c = 0; c < 6; c++)
|
||||
{
|
||||
F2612->CH[c].mem_value = ym2612_ext[num].mem_value[c];
|
||||
F2612->CH[c].kcode = ym2612_ext[num].kcode[c];
|
||||
F2612->CH[c].block_fnum = ym2612_ext[num].block_fnum[c];
|
||||
/* recompute the phase steps and the envelope rates */
|
||||
F2612->CH[c].SLOT[SLOT1].Incr = -1;
|
||||
for (s = 0; s < 4; s++)
|
||||
F2612->CH[c].SLOT[s].ksr = 0xff;
|
||||
for (s = 0; s < 4; s++)
|
||||
{
|
||||
F2612->CH[c].SLOT[s].key = ym2612_ext[num].key[c*4+s];
|
||||
F2612->CH[c].SLOT[s].vol_out = ym2612_ext[num].vol_out[c*4+s];
|
||||
F2612->CH[c].SLOT[s].ssgn = ym2612_ext[num].ssgn[c*4+s];
|
||||
}
|
||||
}
|
||||
}
|
||||
opn_ext_copy(&FM2612[num].OPN, FM2612[num].CH, 6, &ym2612_ext[num], 1);
|
||||
}
|
||||
|
||||
static void YM2612_save_state(void)
|
||||
@@ -4962,19 +4976,7 @@ static void YM2612_save_state(void)
|
||||
{
|
||||
memset(ym2612_ext, 0, sizeof(*ym2612_ext) * YM2612NumChips);
|
||||
for (num = 0; num < YM2612NumChips; num++)
|
||||
{
|
||||
state_save_register_UINT32("YM2612ext", num, "eg_cnt", &ym2612_ext[num].eg_cnt, 1);
|
||||
state_save_register_UINT32("YM2612ext", num, "eg_timer", &ym2612_ext[num].eg_timer, 1);
|
||||
state_save_register_UINT32("YM2612ext", num, "lfo_cnt", &ym2612_ext[num].lfo_cnt, 1);
|
||||
state_save_register_UINT32("YM2612ext", num, "key", ym2612_ext[num].key, 6*4);
|
||||
state_save_register_UINT32("YM2612ext", num, "vol_out", ym2612_ext[num].vol_out, 6*4);
|
||||
state_save_register_UINT8("YM2612ext", num, "ssgn", ym2612_ext[num].ssgn, 6*4);
|
||||
state_save_register_INT32("YM2612ext", num, "mem_value", ym2612_ext[num].mem_value, 6);
|
||||
state_save_register_UINT32("YM2612ext", num, "lfo_inc", &ym2612_ext[num].lfo_inc, 1);
|
||||
state_save_register_UINT8("YM2612ext", num, "kcode", ym2612_ext[num].kcode, 6);
|
||||
state_save_register_UINT32("YM2612ext", num, "block_fnum", ym2612_ext[num].block_fnum, 6);
|
||||
state_save_register_UINT32("YM2612ext", num, "sl3_block_fnum", ym2612_ext[num].sl3_block_fnum, 3);
|
||||
}
|
||||
opn_ext_register("YM2612ext", num, &ym2612_ext[num]);
|
||||
state_save_register_func_presave(YM2612_ext_presave);
|
||||
state_save_register_func_postload(YM2612_ext_postload);
|
||||
}
|
||||
@@ -4982,6 +4984,7 @@ static void YM2612_save_state(void)
|
||||
for(num=0;num<YM2612NumChips;num++)
|
||||
{
|
||||
state_save_register_UINT8 (statename, num, "regs" , FM2612[num].REGS , 512);
|
||||
state_save_register_INT32 (statename, num, "dacout" , &FM2612[num].dacout, 1);
|
||||
FMsave_state_st(statename,num,&FM2612[num].OPN.ST);
|
||||
FMsave_state_channel(statename,num,FM2612[num].CH,6);
|
||||
/* 3slots */
|
||||
@@ -5070,15 +5073,18 @@ void YM2612ResetChip(int num)
|
||||
{
|
||||
OPNWriteReg(OPN,i ,0xc0);
|
||||
OPNWriteReg(OPN,i|0x100,0xc0);
|
||||
F2612->REGS[i] = F2612->REGS[i|0x100] = 0xc0; /* the reset values, for the save states (the postload writes them back) */
|
||||
}
|
||||
for(i = 0xb2 ; i >= 0x30 ; i-- )
|
||||
{
|
||||
OPNWriteReg(OPN,i ,0);
|
||||
OPNWriteReg(OPN,i|0x100,0);
|
||||
F2612->REGS[i] = F2612->REGS[i|0x100] = 0;
|
||||
}
|
||||
for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
|
||||
/* DAC mode clear */
|
||||
F2612->dacen = 0;
|
||||
F2612->REGS[0x2b] = 0;
|
||||
}
|
||||
|
||||
/* YM2612 write */
|
||||
|
||||
+21
-9
@@ -83,6 +83,7 @@ typedef struct Voice_t
|
||||
int relamt; /* release amount*/
|
||||
int relcount; /* release counter*/
|
||||
INT8 relstage; /* release stage*/
|
||||
INT32 samp_offset; /* pSamp in the ROM, for the save states */
|
||||
} VoiceT;
|
||||
|
||||
/* chip structure*/
|
||||
@@ -104,19 +105,27 @@ typedef struct MultiPCM_t
|
||||
|
||||
static MultiPCMT mpcm[MAX_MULTIPCM];
|
||||
|
||||
/* the sample pointer of each voice as its offset in the ROM: it was made at
|
||||
the key on, with the bank and the sample number of then (the registers
|
||||
can have changed since) */
|
||||
static void MultiPCM_presave(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < MAX_MULTIPCM; i++)
|
||||
for (j = 0; j < 28; j++)
|
||||
mpcm[i].Voices[j].samp_offset = (mpcm[i].Voices[j].pSamp && mpcm[i].romptr) ?
|
||||
(INT32)(mpcm[i].Voices[j].pSamp - (INT8 *)mpcm[i].romptr) : -1;
|
||||
}
|
||||
|
||||
static void MultiPCM_postload(void)
|
||||
{
|
||||
int i, j, inum;
|
||||
int i, j;
|
||||
|
||||
/* recalculate all the proper voice pointers*/
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
for (i = 0; i < MAX_MULTIPCM; i++)
|
||||
for (j = 0; j < 28; j++)
|
||||
{
|
||||
inum = mpcm[i].registers[j][1] | ((mpcm[i].registers[j][2]&0x1)<<8);
|
||||
mpcm[i].Voices[j].pSamp = &mpcm[i].romptr[mpcm[i].samples[inum].st];
|
||||
}
|
||||
}
|
||||
mpcm[i].Voices[j].pSamp = (mpcm[i].Voices[j].samp_offset >= 0 && mpcm[i].romptr) ?
|
||||
(INT8 *)&mpcm[i].romptr[mpcm[i].Voices[j].samp_offset] : NULL;
|
||||
}
|
||||
|
||||
static void MultiPCM_update(int chip, INT16 **buffer, int length )
|
||||
@@ -340,12 +349,15 @@ int MultiPCM_sh_start(const struct MachineSound *msound)
|
||||
state_save_register_INT32(mname2, 1, "ptsum", &mpcm[i].Voices[v].ptsum, 1);
|
||||
state_save_register_int(mname2, 1, "relamt", &mpcm[i].Voices[v].relamt);
|
||||
state_save_register_INT8(mname2, 1, "relstage", &mpcm[i].Voices[v].relstage, 1);
|
||||
state_save_register_int(mname2, 1, "relcount", &mpcm[i].Voices[v].relcount);
|
||||
state_save_register_INT32(mname2, 1, "sample offset", &mpcm[i].Voices[v].samp_offset, 1);
|
||||
}
|
||||
|
||||
state_save_register_int(mname, i, "curreg", &mpcm[i].curreg);
|
||||
state_save_register_int(mname, i, "curvoice", &mpcm[i].curvoice);
|
||||
}
|
||||
|
||||
state_save_register_func_presave(MultiPCM_presave);
|
||||
state_save_register_func_postload(MultiPCM_postload);
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user