mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-03-06 14:27:44 +00:00
Save state support for 68K, Z80, sound board, DSB1, and MPEG playback.
This commit is contained in:
parent
52cd9d834b
commit
06f6bf093b
|
@ -25,6 +25,12 @@
|
|||
* 68K CPU interface. This is presently just a wrapper for the Musashi 68K core
|
||||
* and therefore, only a single CPU is supported. In the future, we may want to
|
||||
* add in another 68K core (eg., Turbo68K, A68K, or a recompiler).
|
||||
*
|
||||
* To-Do List
|
||||
* ----------
|
||||
* - Registers may not completely describe the 68K state. Musashi also has
|
||||
* additional CPU state information in the context that its MAME interface
|
||||
* accesses (interrupts pending, halted status, etc.)
|
||||
*/
|
||||
|
||||
#include "Supermodel.h"
|
||||
|
@ -97,6 +103,102 @@ UINT32 M68KGetPC(void)
|
|||
return m68k_get_reg(NULL, M68K_REG_PC);
|
||||
}
|
||||
|
||||
void M68KSaveState(CBlockFile *StateFile, const char *name)
|
||||
{
|
||||
StateFile->NewBlock(name, __FILE__);
|
||||
|
||||
/*
|
||||
* Rather than writing the context directly to the save state, each
|
||||
* register is copied into an array first to ensure the same result across
|
||||
* different compilers (in case the struct is ordered differently). This
|
||||
* also prevents us from inadvertently modifying the callback pointers.
|
||||
*
|
||||
* Note: Some of these are undoubtedly 68010 or 68020 registers and not
|
||||
* really necessary. But if the layout is changed now, the save state
|
||||
* version has to be changed, so don't do it!
|
||||
*/
|
||||
|
||||
UINT32 data[31];
|
||||
|
||||
data[0] = m68k_get_reg(NULL, M68K_REG_D0);
|
||||
data[1] = m68k_get_reg(NULL, M68K_REG_D1);
|
||||
data[2] = m68k_get_reg(NULL, M68K_REG_D2);
|
||||
data[3] = m68k_get_reg(NULL, M68K_REG_D3);
|
||||
data[4] = m68k_get_reg(NULL, M68K_REG_D4);
|
||||
data[5] = m68k_get_reg(NULL, M68K_REG_D5);
|
||||
data[6] = m68k_get_reg(NULL, M68K_REG_D6);
|
||||
data[7] = m68k_get_reg(NULL, M68K_REG_D7);
|
||||
data[8] = m68k_get_reg(NULL, M68K_REG_A0);
|
||||
data[9] = m68k_get_reg(NULL, M68K_REG_A1);
|
||||
data[10] = m68k_get_reg(NULL, M68K_REG_A2);
|
||||
data[11] = m68k_get_reg(NULL, M68K_REG_A3);
|
||||
data[12] = m68k_get_reg(NULL, M68K_REG_A4);
|
||||
data[13] = m68k_get_reg(NULL, M68K_REG_A5);
|
||||
data[14] = m68k_get_reg(NULL, M68K_REG_A6);
|
||||
data[15] = m68k_get_reg(NULL, M68K_REG_A7);
|
||||
data[16] = m68k_get_reg(NULL, M68K_REG_PC);
|
||||
data[17] = m68k_get_reg(NULL, M68K_REG_SR);
|
||||
data[18] = m68k_get_reg(NULL, M68K_REG_SP);
|
||||
data[19] = m68k_get_reg(NULL, M68K_REG_USP);
|
||||
data[20] = m68k_get_reg(NULL, M68K_REG_ISP);
|
||||
data[21] = m68k_get_reg(NULL, M68K_REG_MSP);
|
||||
data[22] = m68k_get_reg(NULL, M68K_REG_SFC);
|
||||
data[23] = m68k_get_reg(NULL, M68K_REG_DFC);
|
||||
data[24] = m68k_get_reg(NULL, M68K_REG_VBR);
|
||||
data[25] = m68k_get_reg(NULL, M68K_REG_CACR);
|
||||
data[26] = m68k_get_reg(NULL, M68K_REG_CAAR);
|
||||
data[27] = m68k_get_reg(NULL, M68K_REG_PREF_ADDR);
|
||||
data[28] = m68k_get_reg(NULL, M68K_REG_PREF_DATA);
|
||||
data[29] = m68k_get_reg(NULL, M68K_REG_PPC);
|
||||
data[30] = m68k_get_reg(NULL, M68K_REG_IR);
|
||||
|
||||
StateFile->Write(data, sizeof(data));
|
||||
}
|
||||
|
||||
void M68KLoadState(CBlockFile *StateFile, const char *name)
|
||||
{
|
||||
if (OKAY != StateFile->FindBlock(name))
|
||||
{
|
||||
ErrorLog("Unable to load 68K state. Save state file is corrupted.");
|
||||
return;
|
||||
}
|
||||
|
||||
UINT32 data[31];
|
||||
|
||||
StateFile->Read(data, sizeof(data));
|
||||
m68k_set_reg(M68K_REG_D0, data[0]);
|
||||
m68k_set_reg(M68K_REG_D1, data[1]);
|
||||
m68k_set_reg(M68K_REG_D2, data[2]);
|
||||
m68k_set_reg(M68K_REG_D3, data[3]);
|
||||
m68k_set_reg(M68K_REG_D4, data[4]);
|
||||
m68k_set_reg(M68K_REG_D5, data[5]);
|
||||
m68k_set_reg(M68K_REG_D6, data[6]);
|
||||
m68k_set_reg(M68K_REG_D7, data[7]);
|
||||
m68k_set_reg(M68K_REG_A0, data[8]);
|
||||
m68k_set_reg(M68K_REG_A1, data[9]);
|
||||
m68k_set_reg(M68K_REG_A2, data[10]);
|
||||
m68k_set_reg(M68K_REG_A3, data[11]);
|
||||
m68k_set_reg(M68K_REG_A4, data[12]);
|
||||
m68k_set_reg(M68K_REG_A5, data[13]);
|
||||
m68k_set_reg(M68K_REG_A6, data[14]);
|
||||
m68k_set_reg(M68K_REG_A7, data[15]);
|
||||
m68k_set_reg(M68K_REG_PC, data[16]);
|
||||
m68k_set_reg(M68K_REG_SR, data[17]);
|
||||
m68k_set_reg(M68K_REG_SP, data[18]);
|
||||
m68k_set_reg(M68K_REG_USP, data[19]);
|
||||
m68k_set_reg(M68K_REG_ISP, data[20]);
|
||||
m68k_set_reg(M68K_REG_MSP, data[21]);
|
||||
m68k_set_reg(M68K_REG_SFC, data[22]);
|
||||
m68k_set_reg(M68K_REG_DFC, data[23]);
|
||||
m68k_set_reg(M68K_REG_VBR, data[24]);
|
||||
m68k_set_reg(M68K_REG_CACR, data[25]);
|
||||
m68k_set_reg(M68K_REG_CAAR, data[26]);
|
||||
m68k_set_reg(M68K_REG_PREF_ADDR, data[27]);
|
||||
m68k_set_reg(M68K_REG_PREF_DATA, data[28]);
|
||||
m68k_set_reg(M68K_REG_PPC, data[29]);
|
||||
m68k_set_reg(M68K_REG_IR, data[30]);
|
||||
}
|
||||
|
||||
// Emulation functions
|
||||
|
||||
void M68KSetIRQ(int irqLevel)
|
||||
|
|
|
@ -122,6 +122,29 @@ extern UINT32 M68KGetDRegister(int reg);
|
|||
*/
|
||||
extern UINT32 M68KGetPC(void);
|
||||
|
||||
/*
|
||||
* M68KSaveState(StateFile, name):
|
||||
*
|
||||
* Saves the CPU state to the block file.
|
||||
*
|
||||
* Parameters:
|
||||
* StateFile Block file.
|
||||
* name Name of block to create (e.g. "Main 68K"), to facilitate
|
||||
* multiple 68K states in the same file.
|
||||
*/
|
||||
extern void M68KSaveState(CBlockFile *StateFile, const char *name);
|
||||
|
||||
/*
|
||||
* M68KLoadState(StateFile, name):
|
||||
*
|
||||
* Loads the CPU state.
|
||||
*
|
||||
* Parameters:
|
||||
* StateFile Block file.
|
||||
* name Name of block to load.
|
||||
*/
|
||||
extern void M68KLoadState(CBlockFile *StateFile, const char *name);
|
||||
|
||||
/*
|
||||
* M68KSetIRQ(irqLevel):
|
||||
*
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
*/
|
||||
|
||||
#include <cstdio> // for NULL
|
||||
#include "Z80.h"
|
||||
#include "Z80.h" // must include this first to define CZ80
|
||||
#include "Supermodel.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -3766,6 +3767,60 @@ void CZ80::Reset(void)
|
|||
nmiTrigger = FALSE;
|
||||
}
|
||||
|
||||
void CZ80::SaveState(CBlockFile *StateFile, const char *name)
|
||||
{
|
||||
StateFile->NewBlock(name, __FILE__);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
StateFile->Write(®s[i].bc, sizeof(regs[i].bc));
|
||||
StateFile->Write(®s[i].de, sizeof(regs[i].de));
|
||||
StateFile->Write(®s[i].hl, sizeof(regs[i].hl));
|
||||
}
|
||||
|
||||
StateFile->Write(af, sizeof(af));
|
||||
StateFile->Write(&ir, sizeof(ir));
|
||||
StateFile->Write(&ix, sizeof(ix));
|
||||
StateFile->Write(&iy, sizeof(iy));
|
||||
StateFile->Write(&sp, sizeof(sp));
|
||||
StateFile->Write(&pc, sizeof(pc));
|
||||
StateFile->Write(&iff, sizeof(iff));
|
||||
StateFile->Write(&im, sizeof(im));
|
||||
StateFile->Write(®s_sel, sizeof(regs_sel));
|
||||
StateFile->Write(&af_sel, sizeof(af_sel));
|
||||
StateFile->Write(&nmiTrigger, sizeof(nmiTrigger));
|
||||
StateFile->Write(&intLine, sizeof(intLine));
|
||||
}
|
||||
|
||||
void CZ80::LoadState(CBlockFile *StateFile, const char *name)
|
||||
{
|
||||
if (OKAY != StateFile->FindBlock(name))
|
||||
{
|
||||
ErrorLog("Unable to load Z80 state. Save state file is corrupted.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
StateFile->Read(®s[i].bc, sizeof(regs[i].bc));
|
||||
StateFile->Read(®s[i].de, sizeof(regs[i].de));
|
||||
StateFile->Read(®s[i].hl, sizeof(regs[i].hl));
|
||||
}
|
||||
|
||||
StateFile->Read(af, sizeof(af));
|
||||
StateFile->Read(&ir, sizeof(ir));
|
||||
StateFile->Read(&ix, sizeof(ix));
|
||||
StateFile->Read(&iy, sizeof(iy));
|
||||
StateFile->Read(&sp, sizeof(sp));
|
||||
StateFile->Read(&pc, sizeof(pc));
|
||||
StateFile->Read(&iff, sizeof(iff));
|
||||
StateFile->Read(&im, sizeof(im));
|
||||
StateFile->Read(®s_sel, sizeof(regs_sel));
|
||||
StateFile->Read(&af_sel, sizeof(af_sel));
|
||||
StateFile->Read(&nmiTrigger, sizeof(nmiTrigger));
|
||||
StateFile->Read(&intLine, sizeof(intLine));
|
||||
}
|
||||
|
||||
void CZ80::Init(CBus *BusPtr, int (*INTF)(CZ80 *Z80))
|
||||
{
|
||||
Bus = BusPtr;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "Types.h"
|
||||
#include "CPU/Bus.h"
|
||||
#include "BlockFile.h"
|
||||
|
||||
/*
|
||||
* Special Return Codes for Interrupt Callbacks
|
||||
|
@ -115,6 +116,29 @@ public:
|
|||
*/
|
||||
void Reset(void);
|
||||
|
||||
/*
|
||||
* SaveState(StateFile, name):
|
||||
*
|
||||
* Saves the CPU state to the block file.
|
||||
*
|
||||
* Parameters:
|
||||
* StateFile Block file.
|
||||
* name Name of block to create (e.g. "Main Z80"), to facilitate
|
||||
* multiple Z80 states in the same file.
|
||||
*/
|
||||
void SaveState(CBlockFile *StateFile, const char *name);
|
||||
|
||||
/*
|
||||
* LoadState(StateFile, name):
|
||||
*
|
||||
* Loads the CPU state.
|
||||
*
|
||||
* Parameters:
|
||||
* StateFile Block file.
|
||||
* name Name of block to load.
|
||||
*/
|
||||
void LoadState(CBlockFile *StateFile, const char *name);
|
||||
|
||||
/*
|
||||
* Init(BusPtr, INTF):
|
||||
*
|
||||
|
|
|
@ -222,7 +222,9 @@ static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
|
|||
/******************************************************************************
|
||||
Save States and NVRAM
|
||||
|
||||
Save states and NVRAM use the same basic format.
|
||||
Save states and NVRAM use the same basic format. When anything changes that
|
||||
breaks compatibility with previous versions of Supermodel, the save state
|
||||
and NVRAM version numbers must be incremented as needed.
|
||||
|
||||
Header block name: "Supermodel Save State" or "Supermodel NVRAM State"
|
||||
Data: Save state file version (4-byte integer), ROM set ID (up to 9 bytes,
|
||||
|
@ -231,7 +233,8 @@ static CInputs *CreateInputs(CInputSystem *InputSystem, BOOL configure)
|
|||
Different subsystems output their own blocks.
|
||||
******************************************************************************/
|
||||
|
||||
#define STATE_FILE_VERSION 0 // save state file version
|
||||
#define STATE_FILE_VERSION 1 // save state file version
|
||||
#define NVRAM_FILE_VERSION 0 // NVRAM file version
|
||||
|
||||
static unsigned saveSlot = 0; // save state slot #
|
||||
|
||||
|
@ -284,7 +287,7 @@ static void LoadState(CModel3 *Model3)
|
|||
SaveState.Read(&fileVersion, sizeof(fileVersion));
|
||||
if (fileVersion != STATE_FILE_VERSION)
|
||||
{
|
||||
ErrorLog("Format of %s is incompatible with this version of Supermodel.", filePath);
|
||||
ErrorLog("%s is incompatible with this version of Supermodel.", filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -299,7 +302,7 @@ static void SaveNVRAM(CModel3 *Model3)
|
|||
{
|
||||
CBlockFile NVRAM;
|
||||
char filePath[24];
|
||||
int fileVersion = STATE_FILE_VERSION;
|
||||
int fileVersion = NVRAM_FILE_VERSION;
|
||||
|
||||
sprintf(filePath, "NVRAM/%s.nv", Model3->GetGameInfo()->id);
|
||||
if (OKAY != NVRAM.Create(filePath, "Supermodel NVRAM State", "Supermodel Version " SUPERMODEL_VERSION))
|
||||
|
@ -341,9 +344,9 @@ static void LoadNVRAM(CModel3 *Model3)
|
|||
}
|
||||
|
||||
NVRAM.Read(&fileVersion, sizeof(fileVersion));
|
||||
if (fileVersion != STATE_FILE_VERSION)
|
||||
if (fileVersion != NVRAM_FILE_VERSION)
|
||||
{
|
||||
ErrorLog("Format of %s is incompatible with this version of Supermodel.", filePath);
|
||||
ErrorLog("%s is incompatible with this version of Supermodel.", filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,13 +39,32 @@
|
|||
These functions are located in audio.cpp and getbits.cpp.
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* MPEG_IsPlaying(void):
|
||||
*
|
||||
* Returns:
|
||||
* TRUE if an MPEG stream is currently playing, otherwise FALSE.
|
||||
*/
|
||||
extern BOOL MPEG_IsPlaying(void);
|
||||
|
||||
/*
|
||||
* MPEG_GetProgress(void):
|
||||
*
|
||||
* Returns:
|
||||
* The current byte offset within the MPEG stream.
|
||||
* The current byte offset within the MPEG stream, relative to the start.
|
||||
*/
|
||||
extern int MPEG_GetProgress(void);
|
||||
extern int MPEG_GetProgress(void);
|
||||
|
||||
/*
|
||||
* MPEG_SetOffset(pos):
|
||||
*
|
||||
* Sets the playback position within an MPEG stream.
|
||||
*
|
||||
* Parameters:
|
||||
* pos Byte offset relative to the beginning of the current MPEG
|
||||
* stream.
|
||||
*/
|
||||
extern void MPEG_SetOffset(int pos);
|
||||
|
||||
/*
|
||||
* MPEG_SetLoop(loop, loopend):
|
||||
|
@ -54,7 +73,7 @@ extern int MPEG_GetProgress(void);
|
|||
*
|
||||
* Parameters:
|
||||
* loop Start address.
|
||||
* loopend End address.
|
||||
* loopend End offset.
|
||||
*/
|
||||
extern void MPEG_SetLoop(const char *loop, int loopend);
|
||||
|
||||
|
@ -77,7 +96,8 @@ extern void MPEG_Decode(INT16 **outputs, int length);
|
|||
* MPEG_PlayMemory(sa, length):
|
||||
*
|
||||
* Specifies the memory buffer to decode from. This initializes the playback
|
||||
* process and will decode the first MPEG frame internally.
|
||||
* process and will decode the first MPEG frame internally. The loop start
|
||||
* position is cleared (set looping after this call).
|
||||
*
|
||||
* Parameters:
|
||||
* sa Start address of MPEG stream.
|
||||
|
|
|
@ -370,6 +370,11 @@ void MPEG_StopPlaying(void)
|
|||
}
|
||||
}
|
||||
|
||||
BOOL MPEG_IsPlaying(void)
|
||||
{
|
||||
return playing ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
BOOL MPEG_Init(void)
|
||||
{
|
||||
if (!decoder_init)
|
||||
|
|
|
@ -27,6 +27,11 @@ int MPEG_GetProgress(void)
|
|||
return offset;
|
||||
}
|
||||
|
||||
void MPEG_SetOffset(int pos)
|
||||
{
|
||||
offset = pos;
|
||||
}
|
||||
|
||||
void m1setfile(const char *mstart, int mend)
|
||||
{
|
||||
fstart = mstart;
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
/*
|
||||
* SCSP.cpp
|
||||
*
|
||||
* WARNING: Here be dragons! Tread carefully. Enabling/disabling things may
|
||||
* break save state support.
|
||||
*
|
||||
* SCSP (Sega Custom Sound Processor) emulation. This code was generously
|
||||
* donated by ElSemi. Interfaces directly to the 68K processor through
|
||||
* callbacks. Some minor interface changes were made (external global variables
|
||||
|
@ -148,7 +151,6 @@ static int RPANTABLE[0x10000];
|
|||
|
||||
static int TimPris[3];
|
||||
static int TimCnt[3];
|
||||
static DWORD OnIRQ=0;
|
||||
|
||||
#define SHIFT 12
|
||||
#define FIX(v) ((DWORD) ((float) (1<<SHIFT)*(v)))
|
||||
|
@ -2012,9 +2014,194 @@ unsigned int SCSP_Slave_r32(unsigned int addr)
|
|||
|
||||
|
||||
/******************************************************************************
|
||||
Extra Supermodel Interface Functions
|
||||
Supermodel Interface Functions
|
||||
******************************************************************************/
|
||||
|
||||
void SCSP_SaveState(CBlockFile *StateFile)
|
||||
{
|
||||
StateFile->NewBlock("SCSP x 2", __FILE__);
|
||||
|
||||
/*
|
||||
* Save global variables.
|
||||
*
|
||||
* Difficult to say exactly what is necessary given that many things are
|
||||
* commented out and should not be enabled but I try to save as much as
|
||||
* possible.
|
||||
*
|
||||
* Things not saved:
|
||||
*
|
||||
* - Reverb buffers and pointers
|
||||
* - FNS table (populated by SCSP_Init() and only read)
|
||||
* - RB_VOLUME stuff
|
||||
* - ARTABLE, DRTABLE
|
||||
* - RBUFDST
|
||||
*/
|
||||
StateFile->Write(&IrqTimA, sizeof(IrqTimA));
|
||||
StateFile->Write(&IrqTimBC, sizeof(IrqTimBC));
|
||||
StateFile->Write(&IrqMidi, sizeof(IrqMidi));
|
||||
StateFile->Write(MidiOutStack, sizeof(MidiOutStack));
|
||||
StateFile->Write(&MidiOutW, sizeof(MidiOutW));
|
||||
StateFile->Write(&MidiOutR, sizeof(MidiOutR));
|
||||
StateFile->Write(MidiStack, sizeof(MidiStack));
|
||||
StateFile->Write(&MidiOutFill, sizeof(MidiOutFill));
|
||||
StateFile->Write(&MidiInFill, sizeof(MidiInFill));
|
||||
StateFile->Write(&MidiW, sizeof(MidiW));
|
||||
StateFile->Write(&MidiR, sizeof(MidiR));
|
||||
StateFile->Write(TimPris, sizeof(TimPris));
|
||||
StateFile->Write(TimCnt, sizeof(TimCnt));
|
||||
|
||||
// Save both SCSP states
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
StateFile->Write(SCSPs[i].datab, sizeof(SCSPs[i].datab));
|
||||
StateFile->Write(&(SCSPs[i].BUFPTR), sizeof(SCSPs[i].BUFPTR));
|
||||
StateFile->Write(&(SCSPs[i].Master), sizeof(SCSPs[i].Master));
|
||||
|
||||
// Save each slot
|
||||
for (int j = 0; j < 32; j++)
|
||||
{
|
||||
UINT32 baseOffset;
|
||||
UINT8 egState;
|
||||
|
||||
StateFile->Write(SCSPs[i].Slots[j].datab, sizeof(SCSPs[i].Slots[j].datab));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].active), sizeof(SCSPs[i].Slots[j].active));
|
||||
baseOffset = (UINT32) (SCSPs[i].Slots[j].base - SCSPs[i].SCSPRAM);
|
||||
StateFile->Write(&baseOffset, sizeof(baseOffset));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].cur_addr), sizeof(SCSPs[i].Slots[j].cur_addr));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].step), sizeof(SCSPs[i].Slots[j].step));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].Back), sizeof(SCSPs[i].Slots[j].Back));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].slot), sizeof(SCSPs[i].Slots[j].slot));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].Prev), sizeof(SCSPs[i].Slots[j].Prev));
|
||||
|
||||
// EG
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.volume), sizeof(SCSPs[i].Slots[j].EG.volume));
|
||||
egState = SCSPs[i].Slots[j].EG.state;
|
||||
StateFile->Write(&egState, sizeof(egState));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.step), sizeof(SCSPs[i].Slots[j].EG.step));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.AR), sizeof(SCSPs[i].Slots[j].EG.AR));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.D1R), sizeof(SCSPs[i].Slots[j].EG.D1R));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.D2R), sizeof(SCSPs[i].Slots[j].EG.D2R));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.RR), sizeof(SCSPs[i].Slots[j].EG.RR));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.DL), sizeof(SCSPs[i].Slots[j].EG.DL));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.EGHOLD), sizeof(SCSPs[i].Slots[j].EG.EGHOLD));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].EG.LPLINK), sizeof(SCSPs[i].Slots[j].EG.LPLINK));
|
||||
|
||||
// PLFO
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].PLFO.phase), sizeof(SCSPs[i].Slots[j].PLFO.phase));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].PLFO.phase_step), sizeof(SCSPs[i].Slots[j].PLFO.phase_step));
|
||||
|
||||
// ALFO
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].ALFO.phase), sizeof(SCSPs[i].Slots[j].ALFO.phase));
|
||||
StateFile->Write(&(SCSPs[i].Slots[j].ALFO.phase_step), sizeof(SCSPs[i].Slots[j].ALFO.phase_step));
|
||||
|
||||
//when loading, make sure to compute lfo
|
||||
}
|
||||
|
||||
// DSP
|
||||
StateFile->Write(&(SCSPs[i].DSP.RBP), sizeof(SCSPs[i].DSP.RBP));
|
||||
StateFile->Write(&(SCSPs[i].DSP.RBL), sizeof(SCSPs[i].DSP.RBL));
|
||||
StateFile->Write(SCSPs[i].DSP.COEF, sizeof(SCSPs[i].DSP.COEF));
|
||||
StateFile->Write(SCSPs[i].DSP.MADRS, sizeof(SCSPs[i].DSP.MADRS));
|
||||
StateFile->Write(SCSPs[i].DSP.MPRO, sizeof(SCSPs[i].DSP.MPRO));
|
||||
StateFile->Write(SCSPs[i].DSP.TEMP, sizeof(SCSPs[i].DSP.TEMP));
|
||||
StateFile->Write(SCSPs[i].DSP.MEMS, sizeof(SCSPs[i].DSP.MEMS));
|
||||
StateFile->Write(&(SCSPs[i].DSP.DEC), sizeof(SCSPs[i].DSP.DEC));
|
||||
StateFile->Write(SCSPs[i].DSP.MIXS, sizeof(SCSPs[i].DSP.MIXS));
|
||||
StateFile->Write(SCSPs[i].DSP.EXTS, sizeof(SCSPs[i].DSP.EXTS));
|
||||
StateFile->Write(SCSPs[i].DSP.EFREG, sizeof(SCSPs[i].DSP.EFREG));
|
||||
StateFile->Write(&(SCSPs[i].DSP.Stopped), sizeof(SCSPs[i].DSP.Stopped));
|
||||
StateFile->Write(&(SCSPs[i].DSP.LastStep), sizeof(SCSPs[i].DSP.LastStep));
|
||||
}
|
||||
}
|
||||
|
||||
void SCSP_LoadState(CBlockFile *StateFile)
|
||||
{
|
||||
if (OKAY != StateFile->FindBlock("SCSP x 2"))
|
||||
{
|
||||
ErrorLog("Unable to load SCSP state. Save state file is corrupted.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load global variables
|
||||
StateFile->Read(&IrqTimA, sizeof(IrqTimA));
|
||||
StateFile->Read(&IrqTimBC, sizeof(IrqTimBC));
|
||||
StateFile->Read(&IrqMidi, sizeof(IrqMidi));
|
||||
StateFile->Read(MidiOutStack, sizeof(MidiOutStack));
|
||||
StateFile->Read(&MidiOutW, sizeof(MidiOutW));
|
||||
StateFile->Read(&MidiOutR, sizeof(MidiOutR));
|
||||
StateFile->Read(MidiStack, sizeof(MidiStack));
|
||||
StateFile->Read(&MidiOutFill, sizeof(MidiOutFill));
|
||||
StateFile->Read(&MidiInFill, sizeof(MidiInFill));
|
||||
StateFile->Read(&MidiW, sizeof(MidiW));
|
||||
StateFile->Read(&MidiR, sizeof(MidiR));
|
||||
StateFile->Read(TimPris, sizeof(TimPris));
|
||||
StateFile->Read(TimCnt, sizeof(TimCnt));
|
||||
|
||||
// Load both SCSP states
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
StateFile->Read(SCSPs[i].datab, sizeof(SCSPs[i].datab));
|
||||
StateFile->Read(&(SCSPs[i].BUFPTR), sizeof(SCSPs[i].BUFPTR));
|
||||
StateFile->Read(&(SCSPs[i].Master), sizeof(SCSPs[i].Master));
|
||||
|
||||
// Load each slot
|
||||
for (int j = 0; j < 32; j++)
|
||||
{
|
||||
UINT32 baseOffset;
|
||||
UINT8 egState;
|
||||
|
||||
StateFile->Read(SCSPs[i].Slots[j].datab, sizeof(SCSPs[i].Slots[j].datab));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].active), sizeof(SCSPs[i].Slots[j].active));
|
||||
StateFile->Read(&baseOffset, sizeof(baseOffset));
|
||||
SCSPs[i].Slots[j].base = &(SCSPs[i].SCSPRAM[baseOffset&0xFFFFF]); // clamp to 1 MB
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].cur_addr), sizeof(SCSPs[i].Slots[j].cur_addr));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].step), sizeof(SCSPs[i].Slots[j].step));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].Back), sizeof(SCSPs[i].Slots[j].Back));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].slot), sizeof(SCSPs[i].Slots[j].slot));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].Prev), sizeof(SCSPs[i].Slots[j].Prev));
|
||||
|
||||
// EG
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.volume), sizeof(SCSPs[i].Slots[j].EG.volume));
|
||||
StateFile->Read(&egState, sizeof(egState));
|
||||
SCSPs[i].Slots[j].EG.state = (_STATE) egState;
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.step), sizeof(SCSPs[i].Slots[j].EG.step));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.AR), sizeof(SCSPs[i].Slots[j].EG.AR));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.D1R), sizeof(SCSPs[i].Slots[j].EG.D1R));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.D2R), sizeof(SCSPs[i].Slots[j].EG.D2R));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.RR), sizeof(SCSPs[i].Slots[j].EG.RR));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.DL), sizeof(SCSPs[i].Slots[j].EG.DL));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.EGHOLD), sizeof(SCSPs[i].Slots[j].EG.EGHOLD));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].EG.LPLINK), sizeof(SCSPs[i].Slots[j].EG.LPLINK));
|
||||
|
||||
// PLFO
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].PLFO.phase), sizeof(SCSPs[i].Slots[j].PLFO.phase));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].PLFO.phase_step), sizeof(SCSPs[i].Slots[j].PLFO.phase_step));
|
||||
|
||||
// ALFO
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].ALFO.phase), sizeof(SCSPs[i].Slots[j].ALFO.phase));
|
||||
StateFile->Read(&(SCSPs[i].Slots[j].ALFO.phase_step), sizeof(SCSPs[i].Slots[j].ALFO.phase_step));
|
||||
|
||||
// Recompute LFOs
|
||||
Compute_LFO(&(SCSPs[i].Slots[j]));
|
||||
}
|
||||
|
||||
// DSP
|
||||
StateFile->Read(&(SCSPs[i].DSP.RBP), sizeof(SCSPs[i].DSP.RBP));
|
||||
StateFile->Read(&(SCSPs[i].DSP.RBL), sizeof(SCSPs[i].DSP.RBL));
|
||||
StateFile->Read(SCSPs[i].DSP.COEF, sizeof(SCSPs[i].DSP.COEF));
|
||||
StateFile->Read(SCSPs[i].DSP.MADRS, sizeof(SCSPs[i].DSP.MADRS));
|
||||
StateFile->Read(SCSPs[i].DSP.MPRO, sizeof(SCSPs[i].DSP.MPRO));
|
||||
StateFile->Read(SCSPs[i].DSP.TEMP, sizeof(SCSPs[i].DSP.TEMP));
|
||||
StateFile->Read(SCSPs[i].DSP.MEMS, sizeof(SCSPs[i].DSP.MEMS));
|
||||
StateFile->Read(&(SCSPs[i].DSP.DEC), sizeof(SCSPs[i].DSP.DEC));
|
||||
StateFile->Read(SCSPs[i].DSP.MIXS, sizeof(SCSPs[i].DSP.MIXS));
|
||||
StateFile->Read(SCSPs[i].DSP.EXTS, sizeof(SCSPs[i].DSP.EXTS));
|
||||
StateFile->Read(SCSPs[i].DSP.EFREG, sizeof(SCSPs[i].DSP.EFREG));
|
||||
StateFile->Read(&(SCSPs[i].DSP.Stopped), sizeof(SCSPs[i].DSP.Stopped));
|
||||
StateFile->Read(&(SCSPs[i].DSP.LastStep), sizeof(SCSPs[i].DSP.LastStep));
|
||||
}
|
||||
}
|
||||
|
||||
void SCSP_SetBuffers(INT16 *leftBufferPtr, INT16 *rightBufferPtr, int bufferLength)
|
||||
{
|
||||
SysFPS = 60.0; // should this be updated to reflect actual FPS?
|
||||
|
|
|
@ -63,6 +63,8 @@ unsigned short SCSP_Slave_r16(unsigned int addr);
|
|||
unsigned int SCSP_Slave_r32(unsigned int addr);
|
||||
|
||||
// Supermodel interface functions
|
||||
void SCSP_SaveState(CBlockFile *StateFile);
|
||||
void SCSP_LoadState(CBlockFile *StateFile);
|
||||
void SCSP_SetBuffers(INT16 *leftBufferPtr, INT16 *rightBufferPtr, int bufferLength);
|
||||
void SCSP_Deinit(void);
|
||||
|
||||
|
|
|
@ -1075,6 +1075,7 @@ void SCSPDSP_Start(_SCSPDSP *DSP)
|
|||
}
|
||||
DSP->LastStep=i+1;
|
||||
|
||||
/*
|
||||
int test=0;
|
||||
if(test)
|
||||
{
|
||||
|
@ -1086,6 +1087,7 @@ void SCSPDSP_Start(_SCSPDSP *DSP)
|
|||
fwrite(DSP->MADRS,32*2,1,f1);
|
||||
fclose(f1);
|
||||
}
|
||||
*/
|
||||
|
||||
for(int t=0;t<0x10000;++t)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue