mirror of
https://github.com/holub/mame
synced 2025-05-11 08:38:47 +03:00
Fixed crash bug in DCS games.
Updated the fcompress APIs to allow for specifying a compression level. Removed the concept of state saving tags, which was a hack to get save states to work with multiple CPU cores. Simplified the state saving system as a result, performing the operation in a single pass and without allocating a full blob of memory. Also enabled minimal compression.
This commit is contained in:
parent
4ee312ca39
commit
e26c70d35b
@ -262,11 +262,9 @@ void cpuexec_init(running_machine *machine)
|
|||||||
classdata->timedint_timer = timer_alloc(machine, trigger_periodic_interrupt, device);
|
classdata->timedint_timer = timer_alloc(machine, trigger_periodic_interrupt, device);
|
||||||
|
|
||||||
/* initialize this CPU */
|
/* initialize this CPU */
|
||||||
state_save_push_tag(cpunum + 1);
|
|
||||||
num_regs = state_save_get_reg_count(machine);
|
num_regs = state_save_get_reg_count(machine);
|
||||||
cpu_init(device, cpunum, classdata->clock, standard_irq_callback);
|
cpu_init(device, cpunum, classdata->clock, standard_irq_callback);
|
||||||
num_regs = state_save_get_reg_count(machine) - num_regs;
|
num_regs = state_save_get_reg_count(machine) - num_regs;
|
||||||
state_save_pop_tag();
|
|
||||||
|
|
||||||
/* fetch post-initialization data */
|
/* fetch post-initialization data */
|
||||||
classdata->icount = cpu_get_icount_ptr(device);
|
classdata->icount = cpu_get_icount_ptr(device);
|
||||||
|
@ -386,12 +386,13 @@ void mame_fclose(mame_file *file)
|
|||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
mame_fcompress - enable/disable streaming file
|
mame_fcompress - enable/disable streaming file
|
||||||
compression via zlib
|
compression via zlib; level is 0 to disable
|
||||||
|
compression, or up to 9 for max compression
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
file_error mame_fcompress(mame_file *file, int compress)
|
file_error mame_fcompress(mame_file *file, int level)
|
||||||
{
|
{
|
||||||
return core_fcompress(file->file, compress);
|
return core_fcompress(file->file, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ file_error mame_fopen_ram(const void *data, UINT32 length, UINT32 openflags, mam
|
|||||||
/* close an open file */
|
/* close an open file */
|
||||||
void mame_fclose(mame_file *file);
|
void mame_fclose(mame_file *file);
|
||||||
|
|
||||||
/* enable/disable streaming file compression via zlib */
|
/* enable/disable streaming file compression via zlib; level is 0 to disable compression, or up to 9 for max compression */
|
||||||
file_error mame_fcompress(mame_file *file, int compress);
|
file_error mame_fcompress(mame_file *file, int compress);
|
||||||
|
|
||||||
|
|
||||||
|
@ -3974,7 +3974,7 @@ static time_t playback_init(running_machine *machine)
|
|||||||
fatalerror("Input file is for " GAMENOUN " '%s', not for current " GAMENOUN " '%s'\n", header + 0x14, machine->gamedrv->name);
|
fatalerror("Input file is for " GAMENOUN " '%s', not for current " GAMENOUN " '%s'\n", header + 0x14, machine->gamedrv->name);
|
||||||
|
|
||||||
/* enable compression */
|
/* enable compression */
|
||||||
mame_fcompress(portdata->playback_file, TRUE);
|
mame_fcompress(portdata->playback_file, FCOMPRESS_MEDIUM);
|
||||||
|
|
||||||
return basetime;
|
return basetime;
|
||||||
}
|
}
|
||||||
@ -4174,7 +4174,7 @@ static void record_init(running_machine *machine)
|
|||||||
mame_fwrite(portdata->record_file, header, sizeof(header));
|
mame_fwrite(portdata->record_file, header, sizeof(header));
|
||||||
|
|
||||||
/* enable compression */
|
/* enable compression */
|
||||||
mame_fcompress(portdata->record_file, TRUE);
|
mame_fcompress(portdata->record_file, FCOMPRESS_MEDIUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
113
src/emu/mame.c
113
src/emu/mame.c
@ -1729,46 +1729,46 @@ static void handle_save(running_machine *machine)
|
|||||||
filerr = mame_fopen(mame->saveload_searchpath, astring_c(mame->saveload_pending_file), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
|
filerr = mame_fopen(mame->saveload_searchpath, astring_c(mame->saveload_pending_file), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file);
|
||||||
if (filerr == FILERR_NONE)
|
if (filerr == FILERR_NONE)
|
||||||
{
|
{
|
||||||
int cpunum;
|
astring *fullname = astring_dupc(mame_file_full_name(file));
|
||||||
|
state_save_error staterr;
|
||||||
|
|
||||||
/* write the save state */
|
/* write the save state */
|
||||||
if (state_save_save_begin(machine, file) != 0)
|
staterr = state_save_write_file(machine, file);
|
||||||
|
|
||||||
|
/* handle the result */
|
||||||
|
switch (staterr)
|
||||||
{
|
{
|
||||||
popmessage("Error: Unable to save state due to illegal registrations. See error.log for details.");
|
case STATERR_ILLEGAL_REGISTRATIONS:
|
||||||
mame_fclose(file);
|
popmessage("Error: Unable to save state due to illegal registrations. See error.log for details.");
|
||||||
goto cancel;
|
break;
|
||||||
|
|
||||||
|
case STATERR_WRITE_ERROR:
|
||||||
|
popmessage("Error: Unable to save state due to a write error. Verify there is enough disk space.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATERR_NONE:
|
||||||
|
if (!(machine->gamedrv->flags & GAME_SUPPORTS_SAVE))
|
||||||
|
popmessage("State successfully saved.\nWarning: Save states are not officially supported for this game.");
|
||||||
|
else
|
||||||
|
popmessage("State successfully saved.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
popmessage("Error: Unknwon error during state save.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write the default tag */
|
/* close and perhaps delete the file */
|
||||||
state_save_push_tag(0);
|
|
||||||
state_save_save_continue(machine);
|
|
||||||
state_save_pop_tag();
|
|
||||||
|
|
||||||
/* loop over CPUs */
|
|
||||||
for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++)
|
|
||||||
if (machine->cpu[cpunum] != NULL)
|
|
||||||
{
|
|
||||||
/* save the CPU data */
|
|
||||||
state_save_push_tag(cpunum + 1);
|
|
||||||
state_save_save_continue(machine);
|
|
||||||
state_save_pop_tag();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* finish and close */
|
|
||||||
state_save_save_finish(machine);
|
|
||||||
mame_fclose(file);
|
mame_fclose(file);
|
||||||
|
if (staterr != STATERR_NONE)
|
||||||
/* pop a warning if the game doesn't support saves */
|
osd_rmfile(astring_c(fullname));
|
||||||
if (!(machine->gamedrv->flags & GAME_SUPPORTS_SAVE))
|
astring_free(fullname);
|
||||||
popmessage("State successfully saved.\nWarning: Save states are not officially supported for this game.");
|
|
||||||
else
|
|
||||||
popmessage("State successfully saved.");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
popmessage("Error: Failed to save state");
|
popmessage("Error: Failed to create save state file.");
|
||||||
|
|
||||||
cancel:
|
|
||||||
/* unschedule the save */
|
/* unschedule the save */
|
||||||
|
cancel:
|
||||||
astring_free(mame->saveload_pending_file);
|
astring_free(mame->saveload_pending_file);
|
||||||
mame->saveload_searchpath = NULL;
|
mame->saveload_searchpath = NULL;
|
||||||
mame->saveload_pending_file = NULL;
|
mame->saveload_pending_file = NULL;
|
||||||
@ -1810,39 +1810,46 @@ static void handle_load(running_machine *machine)
|
|||||||
filerr = mame_fopen(mame->saveload_searchpath, astring_c(mame->saveload_pending_file), OPEN_FLAG_READ, &file);
|
filerr = mame_fopen(mame->saveload_searchpath, astring_c(mame->saveload_pending_file), OPEN_FLAG_READ, &file);
|
||||||
if (filerr == FILERR_NONE)
|
if (filerr == FILERR_NONE)
|
||||||
{
|
{
|
||||||
/* start loading */
|
state_save_error staterr;
|
||||||
if (state_save_load_begin(machine, file) == 0)
|
|
||||||
|
/* write the save state */
|
||||||
|
staterr = state_save_read_file(machine, file);
|
||||||
|
|
||||||
|
/* handle the result */
|
||||||
|
switch (staterr)
|
||||||
{
|
{
|
||||||
int cpunum;
|
case STATERR_ILLEGAL_REGISTRATIONS:
|
||||||
|
popmessage("Error: Unable to load state due to illegal registrations. See error.log for details.");
|
||||||
|
break;
|
||||||
|
|
||||||
/* read tag 0 */
|
case STATERR_INVALID_HEADER:
|
||||||
state_save_push_tag(0);
|
popmessage("Error: Unable to load state due to an invalid header. Make sure the save state is correct for this game.");
|
||||||
state_save_load_continue(machine);
|
break;
|
||||||
state_save_pop_tag();
|
|
||||||
|
|
||||||
/* loop over CPUs */
|
case STATERR_READ_ERROR:
|
||||||
for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++)
|
popmessage("Error: Unable to load state due to a read error (file is likely corrupt).");
|
||||||
if (machine->cpu[cpunum] != NULL)
|
break;
|
||||||
{
|
|
||||||
/* load the CPU data */
|
|
||||||
state_save_push_tag(cpunum + 1);
|
|
||||||
state_save_load_continue(machine);
|
|
||||||
state_save_pop_tag();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* finish and close */
|
case STATERR_NONE:
|
||||||
state_save_load_finish(machine);
|
if (!(machine->gamedrv->flags & GAME_SUPPORTS_SAVE))
|
||||||
popmessage("State successfully loaded.");
|
popmessage("State successfully loaded.\nWarning: Save states are not officially supported for this game.");
|
||||||
|
else
|
||||||
|
popmessage("State successfully loaded.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
popmessage("Error: Unknwon error during state load.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
popmessage("Error: Failed to load state");
|
/* close the file */
|
||||||
mame_fclose(file);
|
mame_fclose(file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
popmessage("Error: Failed to load state");
|
popmessage("Error: Failed to open save state file.");
|
||||||
|
|
||||||
cancel:
|
|
||||||
/* unschedule the load */
|
/* unschedule the load */
|
||||||
|
cancel:
|
||||||
astring_free(mame->saveload_pending_file);
|
astring_free(mame->saveload_pending_file);
|
||||||
mame->saveload_pending_file = NULL;
|
mame->saveload_pending_file = NULL;
|
||||||
mame->saveload_schedule_callback = NULL;
|
mame->saveload_schedule_callback = NULL;
|
||||||
|
483
src/emu/state.c
483
src/emu/state.c
@ -11,12 +11,15 @@
|
|||||||
|
|
||||||
Save state file format:
|
Save state file format:
|
||||||
|
|
||||||
0.. 7 'MAMESAVE"
|
00..07 'MAMESAVE'
|
||||||
8 Format version (this is format 1)
|
08 Format version (this is format 2)
|
||||||
9 Flags
|
09 Flags
|
||||||
a..13 Game name padded with \0
|
0A..1B Game name padded with \0
|
||||||
14..17 Signature
|
1C..1F Signature
|
||||||
18..end Save game data
|
20..end Save game data (compressed)
|
||||||
|
|
||||||
|
Data is always written as native-endian.
|
||||||
|
Data is converted from the endiannness it was written upon load.
|
||||||
|
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
@ -40,9 +43,8 @@
|
|||||||
CONSTANTS
|
CONSTANTS
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#define SAVE_VERSION 1
|
#define SAVE_VERSION 2
|
||||||
|
#define HEADER_SIZE 32
|
||||||
#define TAG_STACK_SIZE 4
|
|
||||||
|
|
||||||
/* Available flags */
|
/* Available flags */
|
||||||
enum
|
enum
|
||||||
@ -65,7 +67,6 @@ struct _state_entry
|
|||||||
astring * name; /* full name */
|
astring * name; /* full name */
|
||||||
UINT8 typesize; /* size of the raw data type */
|
UINT8 typesize; /* size of the raw data type */
|
||||||
UINT32 typecount; /* number of items */
|
UINT32 typecount; /* number of items */
|
||||||
int tag; /* saving tag */
|
|
||||||
UINT32 offset; /* offset within the final structure */
|
UINT32 offset; /* offset within the final structure */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -76,7 +77,6 @@ struct _state_callback
|
|||||||
state_callback * next; /* pointer to next entry */
|
state_callback * next; /* pointer to next entry */
|
||||||
running_machine * machine; /* pointer back to the owning machine */
|
running_machine * machine; /* pointer back to the owning machine */
|
||||||
void * param; /* function parameter */
|
void * param; /* function parameter */
|
||||||
int tag; /* saving tag */
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
state_presave_func presave; /* presave callback */
|
state_presave_func presave; /* presave callback */
|
||||||
@ -106,11 +106,6 @@ struct _state_private
|
|||||||
GLOBAL VARIABLES
|
GLOBAL VARIABLES
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/* this stuff goes away when CPU cores are fully pointer-ized */
|
|
||||||
static int ss_tag_stack[TAG_STACK_SIZE];
|
|
||||||
static int ss_tag_stack_index;
|
|
||||||
static int ss_current_tag;
|
|
||||||
|
|
||||||
#ifdef MESS
|
#ifdef MESS
|
||||||
static const char ss_magic_num[8] = { 'M', 'E', 'S', 'S', 'S', 'A', 'V', 'E' };
|
static const char ss_magic_num[8] = { 'M', 'E', 'S', 'S', 'S', 'A', 'V', 'E' };
|
||||||
#else
|
#else
|
||||||
@ -120,14 +115,42 @@ static const char ss_magic_num[8] = { 'M', 'A', 'M', 'E', 'S', 'A', 'V', 'E' };
|
|||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
FUNCTION PROTOTYPES
|
INLINE FUNCTIONS
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
static void ss_c2(UINT8 *, UINT32);
|
/*-------------------------------------------------
|
||||||
static void ss_c4(UINT8 *, UINT32);
|
flip_data - reverse the endianness of a
|
||||||
static void ss_c8(UINT8 *, UINT32);
|
block of data
|
||||||
|
-------------------------------------------------*/
|
||||||
|
|
||||||
static void (*const ss_conv[])(UINT8 *, UINT32) = { 0, 0, ss_c2, 0, ss_c4, 0, 0, 0, ss_c8 };
|
INLINE void flip_data(state_entry *entry)
|
||||||
|
{
|
||||||
|
UINT16 *data16;
|
||||||
|
UINT32 *data32;
|
||||||
|
UINT64 *data64;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
switch (entry->typesize)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
data16 = entry->data;
|
||||||
|
for (count = 0; count < entry->typecount; count++)
|
||||||
|
data16[count] = FLIPENDIAN_INT16(data16[count]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
data32 = entry->data;
|
||||||
|
for (count = 0; count < entry->typecount; count++)
|
||||||
|
data32[count] = FLIPENDIAN_INT32(data32[count]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
data64 = entry->data;
|
||||||
|
for (count = 0; count < entry->typecount; count++)
|
||||||
|
data64[count] = FLIPENDIAN_INT64(data64[count]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -158,7 +181,7 @@ int state_save_get_reg_count(running_machine *machine)
|
|||||||
state_entry *entry;
|
state_entry *entry;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
/* iterate over entries with matching tags */
|
/* count entries */
|
||||||
for (entry = global->entrylist; entry != NULL; entry = entry->next)
|
for (entry = global->entrylist; entry != NULL; entry = entry->next)
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
@ -167,38 +190,6 @@ int state_save_get_reg_count(running_machine *machine)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
TAGGING
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
state_save_push_tag - push the current tag
|
|
||||||
onto the stack and set a new tag
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
void state_save_push_tag(int tag)
|
|
||||||
{
|
|
||||||
if (ss_tag_stack_index == TAG_STACK_SIZE - 1)
|
|
||||||
fatalerror("state_save tag stack overflow");
|
|
||||||
ss_tag_stack[ss_tag_stack_index++] = ss_current_tag;
|
|
||||||
ss_current_tag = tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
state_save_pop_tag - pop the tag from the top
|
|
||||||
of the stack
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
void state_save_pop_tag(void)
|
|
||||||
{
|
|
||||||
if (ss_tag_stack_index == 0)
|
|
||||||
fatalerror("state_save tag stack underflow");
|
|
||||||
ss_current_tag = ss_tag_stack[--ss_tag_stack_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
REGISTRATION HANDLING
|
REGISTRATION HANDLING
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
@ -254,9 +245,9 @@ void state_save_register_memory(running_machine *machine, const char *module, co
|
|||||||
/* create the full name */
|
/* create the full name */
|
||||||
totalname = astring_alloc();
|
totalname = astring_alloc();
|
||||||
if (tag != NULL)
|
if (tag != NULL)
|
||||||
astring_printf(totalname, "%X/%s/%s/%X/%s", ss_current_tag, module, tag, index, name);
|
astring_printf(totalname, "%s/%s/%X/%s", module, tag, index, name);
|
||||||
else
|
else
|
||||||
astring_printf(totalname, "%X/%s/%X/%s", ss_current_tag, module, index, name);
|
astring_printf(totalname, "%s/%X/%s", module, index, name);
|
||||||
|
|
||||||
/* look for duplicates and an entry to insert in front of */
|
/* look for duplicates and an entry to insert in front of */
|
||||||
for (entryptr = &global->entrylist; *entryptr != NULL; entryptr = &(*entryptr)->next)
|
for (entryptr = &global->entrylist; *entryptr != NULL; entryptr = &(*entryptr)->next)
|
||||||
@ -267,8 +258,8 @@ void state_save_register_memory(running_machine *machine, const char *module, co
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* error if we are equal */
|
/* error if we are equal */
|
||||||
if ((*entryptr)->tag == ss_current_tag && cmpval == 0)
|
if (cmpval == 0)
|
||||||
fatalerror("Duplicate save state registration entry (%d, %s)", ss_current_tag, astring_c(totalname));
|
fatalerror("Duplicate save state registration entry (%s)", astring_c(totalname));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* didn't find one; allocate a new one */
|
/* didn't find one; allocate a new one */
|
||||||
@ -283,7 +274,6 @@ void state_save_register_memory(running_machine *machine, const char *module, co
|
|||||||
(*entryptr)->name = totalname;
|
(*entryptr)->name = totalname;
|
||||||
(*entryptr)->typesize = valsize;
|
(*entryptr)->typesize = valsize;
|
||||||
(*entryptr)->typecount = valcount;
|
(*entryptr)->typecount = valcount;
|
||||||
(*entryptr)->tag = ss_current_tag;
|
|
||||||
restrack_register_object(OBJTYPE_STATEREG, *entryptr, 0, __FILE__, __LINE__);
|
restrack_register_object(OBJTYPE_STATEREG, *entryptr, 0, __FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,8 +310,8 @@ void state_save_register_presave(running_machine *machine, state_presave_func fu
|
|||||||
|
|
||||||
/* scan for duplicates and push through to the end */
|
/* scan for duplicates and push through to the end */
|
||||||
for (cbptr = &global->prefunclist; *cbptr != NULL; cbptr = &(*cbptr)->next)
|
for (cbptr = &global->prefunclist; *cbptr != NULL; cbptr = &(*cbptr)->next)
|
||||||
if ((*cbptr)->func.presave == func && (*cbptr)->param == param && (*cbptr)->tag == ss_current_tag)
|
if ((*cbptr)->func.presave == func && (*cbptr)->param == param)
|
||||||
fatalerror("Duplicate save state function (%d, %p, %p)", ss_current_tag, param, func);
|
fatalerror("Duplicate save state function (%p, %p)", param, func);
|
||||||
|
|
||||||
/* allocate a new entry */
|
/* allocate a new entry */
|
||||||
*cbptr = malloc_or_die(sizeof(state_callback));
|
*cbptr = malloc_or_die(sizeof(state_callback));
|
||||||
@ -331,7 +321,6 @@ void state_save_register_presave(running_machine *machine, state_presave_func fu
|
|||||||
(*cbptr)->machine = machine;
|
(*cbptr)->machine = machine;
|
||||||
(*cbptr)->func.presave = func;
|
(*cbptr)->func.presave = func;
|
||||||
(*cbptr)->param = param;
|
(*cbptr)->param = param;
|
||||||
(*cbptr)->tag = ss_current_tag;
|
|
||||||
restrack_register_object(OBJTYPE_STATEREG, *cbptr, 1, __FILE__, __LINE__);
|
restrack_register_object(OBJTYPE_STATEREG, *cbptr, 1, __FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,8 +341,8 @@ void state_save_register_postload(running_machine *machine, state_postload_func
|
|||||||
|
|
||||||
/* scan for duplicates and push through to the end */
|
/* scan for duplicates and push through to the end */
|
||||||
for (cbptr = &global->postfunclist; *cbptr != NULL; cbptr = &(*cbptr)->next)
|
for (cbptr = &global->postfunclist; *cbptr != NULL; cbptr = &(*cbptr)->next)
|
||||||
if ((*cbptr)->func.postload == func && (*cbptr)->param == param && (*cbptr)->tag == ss_current_tag)
|
if ((*cbptr)->func.postload == func && (*cbptr)->param == param)
|
||||||
fatalerror("Duplicate save state function (%d, %p, %p)", ss_current_tag, param, func);
|
fatalerror("Duplicate save state function (%p, %p)", param, func);
|
||||||
|
|
||||||
/* allocate a new entry */
|
/* allocate a new entry */
|
||||||
*cbptr = malloc_or_die(sizeof(state_callback));
|
*cbptr = malloc_or_die(sizeof(state_callback));
|
||||||
@ -363,7 +352,6 @@ void state_save_register_postload(running_machine *machine, state_postload_func
|
|||||||
(*cbptr)->machine = machine;
|
(*cbptr)->machine = machine;
|
||||||
(*cbptr)->func.postload = func;
|
(*cbptr)->func.postload = func;
|
||||||
(*cbptr)->param = param;
|
(*cbptr)->param = param;
|
||||||
(*cbptr)->tag = ss_current_tag;
|
|
||||||
restrack_register_object(OBJTYPE_STATEREG, *cbptr, 2, __FILE__, __LINE__);
|
restrack_register_object(OBJTYPE_STATEREG, *cbptr, 2, __FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,83 +435,10 @@ void state_destructor(void *ptr, size_t size)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
ENDIAN CONVERSION
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
ss_c2 - byte swap an array of 16-bit data
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static void ss_c2(UINT8 *data, UINT32 size)
|
|
||||||
{
|
|
||||||
UINT16 *convert = (UINT16 *)data;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
convert[i] = FLIPENDIAN_INT16(convert[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
ss_c4 - byte swap an array of 32-bit data
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static void ss_c4(UINT8 *data, UINT32 size)
|
|
||||||
{
|
|
||||||
UINT32 *convert = (UINT32 *)data;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
convert[i] = FLIPENDIAN_INT32(convert[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
ss_c8 - byte swap an array of 64-bit data
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static void ss_c8(UINT8 *data, UINT32 size)
|
|
||||||
{
|
|
||||||
UINT64 *convert = (UINT64 *)data;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
convert[i] = FLIPENDIAN_INT64(convert[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
PROCESSING HELPERS
|
PROCESSING HELPERS
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
compute_size_and_offsets - compute the total
|
|
||||||
size and offsets of each individual item
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static int compute_size_and_offsets(state_private *global)
|
|
||||||
{
|
|
||||||
state_entry *entry;
|
|
||||||
int total_size;
|
|
||||||
|
|
||||||
/* start with the header size */
|
|
||||||
total_size = 0x18;
|
|
||||||
|
|
||||||
/* iterate over entries */
|
|
||||||
for (entry = global->entrylist; entry; entry = entry->next)
|
|
||||||
{
|
|
||||||
/* note the offset and accumulate a total size */
|
|
||||||
entry->offset = total_size;
|
|
||||||
total_size += entry->typesize * entry->typecount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return the total size */
|
|
||||||
return total_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
get_signature - compute the signature, which
|
get_signature - compute the signature, which
|
||||||
is a CRC over the structure of the data
|
is a CRC over the structure of the data
|
||||||
@ -536,7 +451,7 @@ static UINT32 get_signature(running_machine *machine)
|
|||||||
UINT32 crc = 0;
|
UINT32 crc = 0;
|
||||||
|
|
||||||
/* iterate over entries */
|
/* iterate over entries */
|
||||||
for (entry = global->entrylist; entry; entry = entry->next)
|
for (entry = global->entrylist; entry != NULL; entry = entry->next)
|
||||||
{
|
{
|
||||||
UINT32 temp[2];
|
UINT32 temp[2];
|
||||||
|
|
||||||
@ -546,7 +461,7 @@ static UINT32 get_signature(running_machine *machine)
|
|||||||
/* add the type and size to the CRC */
|
/* add the type and size to the CRC */
|
||||||
temp[0] = LITTLE_ENDIANIZE_INT32(entry->typecount);
|
temp[0] = LITTLE_ENDIANIZE_INT32(entry->typecount);
|
||||||
temp[1] = LITTLE_ENDIANIZE_INT32(entry->typesize);
|
temp[1] = LITTLE_ENDIANIZE_INT32(entry->typesize);
|
||||||
crc = crc32(crc, (UINT8 *)&temp[0], 8);
|
crc = crc32(crc, (UINT8 *)&temp[0], sizeof(temp));
|
||||||
}
|
}
|
||||||
|
|
||||||
return crc;
|
return crc;
|
||||||
@ -555,7 +470,7 @@ static UINT32 get_signature(running_machine *machine)
|
|||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
STATE FILE VALIDATION
|
SAVE STATE FILE PROCESSING
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
@ -563,46 +478,45 @@ static UINT32 get_signature(running_machine *machine)
|
|||||||
header
|
header
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
static int validate_header(const UINT8 *header, const char *gamename, UINT32 signature,
|
static state_save_error validate_header(const UINT8 *header, const char *gamename, UINT32 signature,
|
||||||
void (CLIB_DECL *errormsg)(const char *fmt, ...), const char *error_prefix)
|
void (CLIB_DECL *errormsg)(const char *fmt, ...), const char *error_prefix)
|
||||||
{
|
{
|
||||||
/* check magic number */
|
/* check magic number */
|
||||||
if (memcmp(header, ss_magic_num, 8))
|
if (memcmp(header, ss_magic_num, 8))
|
||||||
{
|
{
|
||||||
if (errormsg)
|
if (errormsg != NULL)
|
||||||
errormsg("%sThis is not a " APPNAME " save file", error_prefix);
|
(*errormsg)("%sThis is not a " APPNAME " save file", error_prefix);
|
||||||
return -1;
|
return STATERR_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check save state version */
|
/* check save state version */
|
||||||
if (header[8] != SAVE_VERSION)
|
if (header[8] != SAVE_VERSION)
|
||||||
{
|
{
|
||||||
if (errormsg)
|
if (errormsg != NULL)
|
||||||
errormsg("%sWrong version in save file (%d, 1 expected)", error_prefix, header[8]);
|
(*errormsg)("%sWrong version in save file (version %d, expected %d)", error_prefix, header[8], SAVE_VERSION);
|
||||||
return -1;
|
return STATERR_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check gamename, if we were asked to */
|
/* check gamename, if we were asked to */
|
||||||
if (gamename && strcmp(gamename, (const char *)&header[10]))
|
if (gamename != NULL && strncmp(gamename, (const char *)&header[0x0a], 0x1c - 0x0a))
|
||||||
{
|
{
|
||||||
if (errormsg)
|
if (errormsg != NULL)
|
||||||
errormsg("%s'%s' is not a valid savestate file for game '%s'.", error_prefix, gamename);
|
(*errormsg)("%s'File is not a valid savestate file for game '%s'.", error_prefix, gamename);
|
||||||
return -1;
|
return STATERR_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check signature, if we were asked to */
|
/* check signature, if we were asked to */
|
||||||
if (signature)
|
if (signature != 0)
|
||||||
{
|
{
|
||||||
UINT32 rawsig = *(UINT32 *)&header[0x14];
|
UINT32 rawsig = *(UINT32 *)&header[0x1c];
|
||||||
UINT32 filesig = LITTLE_ENDIANIZE_INT32(rawsig);
|
if (signature != LITTLE_ENDIANIZE_INT32(rawsig))
|
||||||
if (signature != filesig)
|
|
||||||
{
|
{
|
||||||
if (errormsg)
|
if (errormsg != NULL)
|
||||||
errormsg("%sIncompatible save file (signature %08x, expected %08x)", error_prefix, filesig, signature);
|
(*errormsg)("%sIncompatible save file (signature %08x, expected %08x)", error_prefix, LITTLE_ENDIANIZE_INT32(rawsig), signature);
|
||||||
return -1;
|
return STATERR_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return STATERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -611,22 +525,23 @@ static int validate_header(const UINT8 *header, const char *gamename, UINT32 sig
|
|||||||
a valid save state
|
a valid save state
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
int state_save_check_file(running_machine *machine, mame_file *file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...))
|
state_save_error state_save_check_file(running_machine *machine, mame_file *file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...))
|
||||||
{
|
{
|
||||||
|
UINT8 header[HEADER_SIZE];
|
||||||
UINT32 signature = 0;
|
UINT32 signature = 0;
|
||||||
UINT8 header[0x18];
|
|
||||||
|
|
||||||
/* if we want to validate the signature, compute it */
|
/* if we want to validate the signature, compute it */
|
||||||
if (machine != NULL)
|
if (machine != NULL)
|
||||||
signature = get_signature(machine);
|
signature = get_signature(machine);
|
||||||
|
|
||||||
/* seek to the beginning and read the header */
|
/* seek to the beginning and read the header */
|
||||||
|
mame_fcompress(file, FCOMPRESS_NONE);
|
||||||
mame_fseek(file, 0, SEEK_SET);
|
mame_fseek(file, 0, SEEK_SET);
|
||||||
if (mame_fread(file, header, sizeof(header)) != sizeof(header))
|
if (mame_fread(file, header, sizeof(header)) != sizeof(header))
|
||||||
{
|
{
|
||||||
if (errormsg)
|
if (errormsg != NULL)
|
||||||
errormsg("Could not read " APPNAME " save file header");
|
(*errormsg)("Could not read " APPNAME " save file header");
|
||||||
return -1;
|
return STATERR_READ_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* let the generic header check work out the rest */
|
/* let the generic header check work out the rest */
|
||||||
@ -634,215 +549,109 @@ int state_save_check_file(running_machine *machine, mame_file *file, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
SAVE STATE PROCESSING
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
state_save_save_begin - begin the process of
|
state_save_write_file - writes the data to
|
||||||
saving
|
a file
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
int state_save_save_begin(running_machine *machine, mame_file *file)
|
state_save_error state_save_write_file(running_machine *machine, mame_file *file)
|
||||||
{
|
{
|
||||||
state_private *global = machine->state_data;
|
state_private *global = machine->state_data;
|
||||||
|
UINT32 signature = get_signature(machine);
|
||||||
|
UINT8 header[HEADER_SIZE];
|
||||||
|
state_callback *func;
|
||||||
|
state_entry *entry;
|
||||||
|
|
||||||
/* if we have illegal registrations, return an error */
|
/* if we have illegal registrations, return an error */
|
||||||
if (global->illegal_regs > 0)
|
if (global->illegal_regs > 0)
|
||||||
return 1;
|
return STATERR_ILLEGAL_REGISTRATIONS;
|
||||||
|
|
||||||
LOG(("Beginning save\n"));
|
/* generate the header */
|
||||||
global->iofile = file;
|
memcpy(&header[0], ss_magic_num, 8);
|
||||||
|
header[8] = SAVE_VERSION;
|
||||||
|
#ifdef LSB_FIRST
|
||||||
|
header[9] = 0;
|
||||||
|
#else
|
||||||
|
header[9] = SS_MSB_FIRST;
|
||||||
|
#endif
|
||||||
|
strncpy((char *)&header[0x0a], machine->gamedrv->name, 0x1c - 0x0a);
|
||||||
|
*(UINT32 *)&header[0x1c] = LITTLE_ENDIANIZE_INT32(signature);
|
||||||
|
|
||||||
/* compute the total dump size and the offsets of each element */
|
/* write the header and turn on compression for the rest of the file */
|
||||||
global->ioarraysize = compute_size_and_offsets(global);
|
mame_fcompress(file, FCOMPRESS_NONE);
|
||||||
LOG((" total size %u\n", global->ioarraysize));
|
mame_fseek(file, 0, SEEK_SET);
|
||||||
|
if (mame_fwrite(file, header, sizeof(header)) != sizeof(header))
|
||||||
/* allocate memory for the array */
|
return STATERR_WRITE_ERROR;
|
||||||
global->ioarray = malloc_or_die(global->ioarraysize);
|
mame_fcompress(file, FCOMPRESS_MEDIUM);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
state_save_save_continue - save within the
|
|
||||||
current tag
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
void state_save_save_continue(running_machine *machine)
|
|
||||||
{
|
|
||||||
state_private *global = machine->state_data;
|
|
||||||
state_entry *entry;
|
|
||||||
state_callback *func;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
LOG(("Saving tag %d\n", ss_current_tag));
|
|
||||||
|
|
||||||
/* call the pre-save functions */
|
/* call the pre-save functions */
|
||||||
LOG((" calling pre-save functions\n"));
|
|
||||||
|
|
||||||
/* iterate over the list of functions */
|
|
||||||
for (func = global->prefunclist; func != NULL; func = func->next)
|
for (func = global->prefunclist; func != NULL; func = func->next)
|
||||||
if (func->tag == ss_current_tag)
|
(*func->func.presave)(machine, func->param);
|
||||||
{
|
|
||||||
count++;
|
|
||||||
(*func->func.presave)(machine, func->param);
|
|
||||||
}
|
|
||||||
LOG((" %d functions called\n", count));
|
|
||||||
|
|
||||||
/* then copy in all the data */
|
/* then write all the data */
|
||||||
LOG((" copying data\n"));
|
|
||||||
|
|
||||||
/* iterate over entries with matching tags */
|
|
||||||
for (entry = global->entrylist; entry != NULL; entry = entry->next)
|
for (entry = global->entrylist; entry != NULL; entry = entry->next)
|
||||||
if (entry->tag == ss_current_tag)
|
{
|
||||||
{
|
UINT32 totalsize = entry->typesize * entry->typecount;
|
||||||
memcpy(global->ioarray + entry->offset, entry->data, entry->typesize * entry->typecount);
|
if (mame_fwrite(file, entry->data, totalsize) != totalsize)
|
||||||
LOG((" %s: %x..%x\n", astring_c(entry->name), entry->offset, entry->offset + entry->typesize * entry->typecount - 1));
|
return STATERR_WRITE_ERROR;
|
||||||
}
|
}
|
||||||
|
return STATERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
state_save_save_finish - finish saving the
|
state_save_read_file - read the data from a
|
||||||
file by writing the header and closing
|
file
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
void state_save_save_finish(running_machine *machine)
|
state_save_error state_save_read_file(running_machine *machine, mame_file *file)
|
||||||
{
|
{
|
||||||
state_private *global = machine->state_data;
|
state_private *global = machine->state_data;
|
||||||
UINT32 signature;
|
UINT32 signature = get_signature(machine);
|
||||||
UINT8 flags = 0;
|
UINT8 header[HEADER_SIZE];
|
||||||
|
state_callback *func;
|
||||||
|
state_entry *entry;
|
||||||
|
int flip;
|
||||||
|
|
||||||
LOG(("Finishing save\n"));
|
/* if we have illegal registrations, return an error */
|
||||||
|
if (global->illegal_regs > 0)
|
||||||
|
return STATERR_ILLEGAL_REGISTRATIONS;
|
||||||
|
|
||||||
/* compute the flags */
|
/* read the header and turn on compression for the rest of the file */
|
||||||
#ifndef LSB_FIRST
|
mame_fcompress(file, FCOMPRESS_NONE);
|
||||||
flags |= SS_MSB_FIRST;
|
mame_fseek(file, 0, SEEK_SET);
|
||||||
#endif
|
if (mame_fread(file, header, sizeof(header)) != sizeof(header))
|
||||||
|
return STATERR_READ_ERROR;
|
||||||
/* build up the header */
|
mame_fcompress(file, FCOMPRESS_MEDIUM);
|
||||||
memcpy(global->ioarray, ss_magic_num, 8);
|
|
||||||
global->ioarray[8] = SAVE_VERSION;
|
|
||||||
global->ioarray[9] = flags;
|
|
||||||
memset(global->ioarray+0xa, 0, 10);
|
|
||||||
strcpy((char *)global->ioarray+0xa, machine->gamedrv->name);
|
|
||||||
|
|
||||||
/* copy in the signature */
|
|
||||||
signature = get_signature(machine);
|
|
||||||
*(UINT32 *)&global->ioarray[0x14] = LITTLE_ENDIANIZE_INT32(signature);
|
|
||||||
|
|
||||||
/* write the file */
|
|
||||||
mame_fwrite(global->iofile, global->ioarray, global->ioarraysize);
|
|
||||||
|
|
||||||
/* free memory and reset the global states */
|
|
||||||
free(global->ioarray);
|
|
||||||
global->ioarray = NULL;
|
|
||||||
global->ioarraysize = 0;
|
|
||||||
global->iofile = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
LOAD STATE PROCESSING
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
state_save_load_begin - begin the process
|
|
||||||
of loading the state
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
int state_save_load_begin(running_machine *machine, mame_file *file)
|
|
||||||
{
|
|
||||||
state_private *global = machine->state_data;
|
|
||||||
|
|
||||||
LOG(("Beginning load\n"));
|
|
||||||
|
|
||||||
/* read the file into memory */
|
|
||||||
global->ioarraysize = mame_fsize(file);
|
|
||||||
global->ioarray = malloc_or_die(global->ioarraysize);
|
|
||||||
global->iofile = file;
|
|
||||||
mame_fread(global->iofile, global->ioarray, global->ioarraysize);
|
|
||||||
|
|
||||||
/* verify the header and report an error if it doesn't match */
|
/* verify the header and report an error if it doesn't match */
|
||||||
if (validate_header(global->ioarray, NULL, get_signature(machine), popmessage, "Error: "))
|
if (validate_header(header, machine->gamedrv->name, signature, popmessage, "Error: ") != STATERR_NONE)
|
||||||
{
|
return STATERR_INVALID_HEADER;
|
||||||
free(global->ioarray);
|
|
||||||
global->ioarray = NULL;
|
|
||||||
global->ioarraysize = 0;
|
|
||||||
global->iofile = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compute the total size and offset of all the entries */
|
/* determine whether or not to flip the data when done */
|
||||||
compute_size_and_offsets(global);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
state_save_load_continue - load all state in
|
|
||||||
the current tag
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
void state_save_load_continue(running_machine *machine)
|
|
||||||
{
|
|
||||||
state_private *global = machine->state_data;
|
|
||||||
state_entry *entry;
|
|
||||||
state_callback *func;
|
|
||||||
int need_convert;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
/* first determine whether or not we need to convert the endianness of the data */
|
|
||||||
#ifdef LSB_FIRST
|
#ifdef LSB_FIRST
|
||||||
need_convert = (global->ioarray[9] & SS_MSB_FIRST) != 0;
|
flip = ((header[9] & SS_MSB_FIRST) != 0);
|
||||||
#else
|
#else
|
||||||
need_convert = (global->ioarray[9] & SS_MSB_FIRST) == 0;
|
flip = ((header[9] & SS_MSB_FIRST) == 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LOG(("Loading tag %d\n", ss_current_tag));
|
/* read all the data, flipping if necessary */
|
||||||
LOG((" copying data\n"));
|
|
||||||
|
|
||||||
/* iterate over entries with matching tags */
|
|
||||||
for (entry = global->entrylist; entry != NULL; entry = entry->next)
|
for (entry = global->entrylist; entry != NULL; entry = entry->next)
|
||||||
if (entry->tag == ss_current_tag)
|
{
|
||||||
{
|
UINT32 totalsize = entry->typesize * entry->typecount;
|
||||||
memcpy(entry->data, global->ioarray + entry->offset, entry->typesize * entry->typecount);
|
if (mame_fread(file, entry->data, totalsize) != totalsize)
|
||||||
if (need_convert && ss_conv[entry->typesize])
|
return STATERR_READ_ERROR;
|
||||||
(*ss_conv[entry->typesize])(entry->data, entry->typecount);
|
|
||||||
LOG((" %s: %x..%x\n", astring_c(entry->name), entry->offset, entry->offset + entry->typesize * entry->typecount - 1));
|
/* handle flipping */
|
||||||
}
|
if (flip)
|
||||||
|
flip_data(entry);
|
||||||
|
}
|
||||||
|
|
||||||
/* call the post-load functions */
|
/* call the post-load functions */
|
||||||
LOG((" calling post-load functions\n"));
|
|
||||||
for (func = global->postfunclist; func != NULL; func = func->next)
|
for (func = global->postfunclist; func != NULL; func = func->next)
|
||||||
if (func->tag == ss_current_tag)
|
(*func->func.postload)(machine, func->param);
|
||||||
{
|
|
||||||
count++;
|
|
||||||
(*func->func.postload)(machine, func->param);
|
|
||||||
}
|
|
||||||
LOG((" %d functions called\n", count));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return STATERR_NONE;
|
||||||
/*-------------------------------------------------
|
|
||||||
state_save_load_finish - complete the process
|
|
||||||
of loading the state
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
void state_save_load_finish(running_machine *machine)
|
|
||||||
{
|
|
||||||
state_private *global = machine->state_data;
|
|
||||||
|
|
||||||
LOG(("Finishing load\n"));
|
|
||||||
|
|
||||||
/* free memory and reset the global states */
|
|
||||||
free(global->ioarray);
|
|
||||||
global->ioarray = NULL;
|
|
||||||
global->ioarraysize = 0;
|
|
||||||
global->iofile = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,22 @@ typedef void (*state_postload_func)(running_machine *machine, void *param);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
CONSTANTS
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
enum _state_save_error
|
||||||
|
{
|
||||||
|
STATERR_NONE,
|
||||||
|
STATERR_ILLEGAL_REGISTRATIONS,
|
||||||
|
STATERR_INVALID_HEADER,
|
||||||
|
STATERR_READ_ERROR,
|
||||||
|
STATERR_WRITE_ERROR
|
||||||
|
};
|
||||||
|
typedef enum _state_save_error state_save_error;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
MACROS
|
MACROS
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
@ -124,16 +140,6 @@ int state_save_get_reg_count(running_machine *machine);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ----- tagging ----- */
|
|
||||||
|
|
||||||
/* push the current tag onto the stack and set a new tag */
|
|
||||||
void state_save_push_tag(int tag);
|
|
||||||
|
|
||||||
/* pop the tag from the top of the stack */
|
|
||||||
void state_save_pop_tag(void);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ----- registration handling ----- */
|
/* ----- registration handling ----- */
|
||||||
|
|
||||||
/* allow/disallow registrations to happen (called by the core) */
|
/* allow/disallow registrations to happen (called by the core) */
|
||||||
@ -167,36 +173,16 @@ void state_destructor(void *ptr, size_t size);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ----- state file validation ----- */
|
/* ----- save state file processing ----- */
|
||||||
|
|
||||||
/* check if a file is a valid save state */
|
/* check if a file is a valid save state */
|
||||||
int state_save_check_file(running_machine *machine, mame_file *file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));
|
state_save_error state_save_check_file(running_machine *machine, mame_file *file, const char *gamename, void (CLIB_DECL *errormsg)(const char *fmt, ...));
|
||||||
|
|
||||||
|
/* write out the save state file */
|
||||||
|
state_save_error state_save_write_file(running_machine *machine, mame_file *file);
|
||||||
|
|
||||||
|
/* read in a save state file */
|
||||||
/* ----- save state processing ----- */
|
state_save_error state_save_read_file(running_machine *machine, mame_file *file);
|
||||||
|
|
||||||
/* begin the process of saving */
|
|
||||||
int state_save_save_begin(running_machine *machine, mame_file *file);
|
|
||||||
|
|
||||||
/* save within the current tag */
|
|
||||||
void state_save_save_continue(running_machine *machine);
|
|
||||||
|
|
||||||
/* finish saving the file by writing the header and closing */
|
|
||||||
void state_save_save_finish(running_machine *machine);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ----- load state processing ----- */
|
|
||||||
|
|
||||||
/* begin the process of loading the state */
|
|
||||||
int state_save_load_begin(running_machine *machine, mame_file *file);
|
|
||||||
|
|
||||||
/* load all state in the current tag */
|
|
||||||
void state_save_load_continue(running_machine *machine);
|
|
||||||
|
|
||||||
/* complete the process of loading the state */
|
|
||||||
void state_save_load_finish(running_machine *machine);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -296,11 +296,9 @@ void timer_init(running_machine *machine)
|
|||||||
global->callback_timer_modified = FALSE;
|
global->callback_timer_modified = FALSE;
|
||||||
|
|
||||||
/* register with the save state system */
|
/* register with the save state system */
|
||||||
state_save_push_tag(0);
|
|
||||||
state_save_register_item(machine, "timer", NULL, 0, global->basetime.seconds);
|
state_save_register_item(machine, "timer", NULL, 0, global->basetime.seconds);
|
||||||
state_save_register_item(machine, "timer", NULL, 0, global->basetime.attoseconds);
|
state_save_register_item(machine, "timer", NULL, 0, global->basetime.attoseconds);
|
||||||
state_save_register_postload(machine, timer_postload, NULL);
|
state_save_register_postload(machine, timer_postload, NULL);
|
||||||
state_save_pop_tag();
|
|
||||||
|
|
||||||
/* initialize the lists */
|
/* initialize the lists */
|
||||||
global->activelist = NULL;
|
global->activelist = NULL;
|
||||||
@ -523,7 +521,6 @@ static void timer_register_save(emu_timer *timer)
|
|||||||
count++;
|
count++;
|
||||||
|
|
||||||
/* use different instances to differentiate the bits */
|
/* use different instances to differentiate the bits */
|
||||||
state_save_push_tag(0);
|
|
||||||
state_save_register_item(timer->machine, "timer", timer->func, count, timer->param);
|
state_save_register_item(timer->machine, "timer", timer->func, count, timer->param);
|
||||||
state_save_register_item(timer->machine, "timer", timer->func, count, timer->enabled);
|
state_save_register_item(timer->machine, "timer", timer->func, count, timer->enabled);
|
||||||
state_save_register_item(timer->machine, "timer", timer->func, count, timer->period.seconds);
|
state_save_register_item(timer->machine, "timer", timer->func, count, timer->period.seconds);
|
||||||
@ -532,7 +529,6 @@ static void timer_register_save(emu_timer *timer)
|
|||||||
state_save_register_item(timer->machine, "timer", timer->func, count, timer->start.attoseconds);
|
state_save_register_item(timer->machine, "timer", timer->func, count, timer->start.attoseconds);
|
||||||
state_save_register_item(timer->machine, "timer", timer->func, count, timer->expire.seconds);
|
state_save_register_item(timer->machine, "timer", timer->func, count, timer->expire.seconds);
|
||||||
state_save_register_item(timer->machine, "timer", timer->func, count, timer->expire.attoseconds);
|
state_save_register_item(timer->machine, "timer", timer->func, count, timer->expire.attoseconds);
|
||||||
state_save_pop_tag();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,10 +45,8 @@ void watchdog_init(running_machine *machine)
|
|||||||
add_reset_callback(machine, watchdog_internal_reset);
|
add_reset_callback(machine, watchdog_internal_reset);
|
||||||
|
|
||||||
/* save some stuff in the default tag */
|
/* save some stuff in the default tag */
|
||||||
state_save_push_tag(0);
|
|
||||||
state_save_register_item(machine, "watchdog", NULL, 0, watchdog_enabled);
|
state_save_register_item(machine, "watchdog", NULL, 0, watchdog_enabled);
|
||||||
state_save_register_item(machine, "watchdog", NULL, 0, watchdog_counter);
|
state_save_register_item(machine, "watchdog", NULL, 0, watchdog_counter);
|
||||||
state_save_pop_tag();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ void core_fclose(core_file *file)
|
|||||||
{
|
{
|
||||||
/* close files and free memory */
|
/* close files and free memory */
|
||||||
if (file->zdata != NULL)
|
if (file->zdata != NULL)
|
||||||
core_fcompress(file, FALSE);
|
core_fcompress(file, FCOMPRESS_NONE);
|
||||||
if (file->file != NULL)
|
if (file->file != NULL)
|
||||||
osd_close(file->file);
|
osd_close(file->file);
|
||||||
if (file->data != NULL && file->data_allocated)
|
if (file->data != NULL && file->data_allocated)
|
||||||
@ -224,10 +224,11 @@ void core_fclose(core_file *file)
|
|||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
core_fcompress - enable/disable streaming file
|
core_fcompress - enable/disable streaming file
|
||||||
compression via zlib
|
compression via zlib; level is 0 to disable
|
||||||
|
compression, or up to 9 for max compression
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
file_error core_fcompress(core_file *file, int compress)
|
file_error core_fcompress(core_file *file, int level)
|
||||||
{
|
{
|
||||||
file_error result = FILERR_NONE;
|
file_error result = FILERR_NONE;
|
||||||
|
|
||||||
@ -236,7 +237,7 @@ file_error core_fcompress(core_file *file, int compress)
|
|||||||
return FILERR_INVALID_ACCESS;
|
return FILERR_INVALID_ACCESS;
|
||||||
|
|
||||||
/* if we have been compressing, flush and free the data */
|
/* if we have been compressing, flush and free the data */
|
||||||
if (file->zdata != NULL && !compress)
|
if (file->zdata != NULL && level == FCOMPRESS_NONE)
|
||||||
{
|
{
|
||||||
int zerr = Z_OK;
|
int zerr = Z_OK;
|
||||||
|
|
||||||
@ -278,7 +279,7 @@ file_error core_fcompress(core_file *file, int compress)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if we are just starting to compress, allocate a new buffer */
|
/* if we are just starting to compress, allocate a new buffer */
|
||||||
if (file->zdata == NULL && compress)
|
if (file->zdata == NULL && level > FCOMPRESS_NONE)
|
||||||
{
|
{
|
||||||
int zerr;
|
int zerr;
|
||||||
|
|
||||||
@ -293,7 +294,7 @@ file_error core_fcompress(core_file *file, int compress)
|
|||||||
{
|
{
|
||||||
file->zdata->stream.next_out = file->zdata->buffer;
|
file->zdata->stream.next_out = file->zdata->buffer;
|
||||||
file->zdata->stream.avail_out = sizeof(file->zdata->buffer);
|
file->zdata->stream.avail_out = sizeof(file->zdata->buffer);
|
||||||
zerr = deflateInit(&file->zdata->stream, Z_BEST_COMPRESSION);
|
zerr = deflateInit(&file->zdata->stream, level);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
zerr = inflateInit(&file->zdata->stream);
|
zerr = inflateInit(&file->zdata->stream);
|
||||||
|
@ -26,6 +26,11 @@
|
|||||||
|
|
||||||
#define OPEN_FLAG_NO_BOM 0x0100 /* don't output BOM */
|
#define OPEN_FLAG_NO_BOM 0x0100 /* don't output BOM */
|
||||||
|
|
||||||
|
#define FCOMPRESS_NONE 0 /* no compression */
|
||||||
|
#define FCOMPRESS_MIN 1 /* minimal compression */
|
||||||
|
#define FCOMPRESS_MEDIUM 6 /* standard compression */
|
||||||
|
#define FCOMPRESS_MAX 9 /* maximum compression */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
@ -55,8 +60,8 @@ file_error core_fopen_ram_copy(const void *data, size_t length, UINT32 openflags
|
|||||||
/* close an open file */
|
/* close an open file */
|
||||||
void core_fclose(core_file *file);
|
void core_fclose(core_file *file);
|
||||||
|
|
||||||
/* enable/disable streaming file compression via zlib */
|
/* enable/disable streaming file compression via zlib; level is 0 to disable compression, or up to 9 for max compression */
|
||||||
file_error core_fcompress(core_file *file, int compress);
|
file_error core_fcompress(core_file *file, int level);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1507,7 +1507,7 @@ static READ16_HANDLER( latch_status_r )
|
|||||||
if (IS_OUTPUT_EMPTY())
|
if (IS_OUTPUT_EMPTY())
|
||||||
result |= 0x40;
|
result |= 0x40;
|
||||||
if (dcs.fifo_status_r != NULL && (!transfer.hle_enabled || transfer.state == 0))
|
if (dcs.fifo_status_r != NULL && (!transfer.hle_enabled || transfer.state == 0))
|
||||||
result |= (*dcs.fifo_status_r)(NULL) & 0x38;
|
result |= (*dcs.fifo_status_r)(dcs.cpu) & 0x38;
|
||||||
if (transfer.hle_enabled && transfer.state != 0)
|
if (transfer.hle_enabled && transfer.state != 0)
|
||||||
result |= 0x08;
|
result |= 0x08;
|
||||||
return result;
|
return result;
|
||||||
@ -1517,7 +1517,7 @@ static READ16_HANDLER( latch_status_r )
|
|||||||
static READ16_HANDLER( fifo_input_r )
|
static READ16_HANDLER( fifo_input_r )
|
||||||
{
|
{
|
||||||
if (dcs.fifo_data_r)
|
if (dcs.fifo_data_r)
|
||||||
return (*dcs.fifo_data_r)(NULL);
|
return (*dcs.fifo_data_r)(dcs.cpu);
|
||||||
else
|
else
|
||||||
return 0xffff;
|
return 0xffff;
|
||||||
}
|
}
|
||||||
@ -2064,7 +2064,7 @@ void dcs_fifo_notify(int count, int max)
|
|||||||
if (transfer.state != 5 || transfer.fifo_entries == transfer.writes_left || transfer.fifo_entries >= 256)
|
if (transfer.state != 5 || transfer.fifo_entries == transfer.writes_left || transfer.fifo_entries >= 256)
|
||||||
{
|
{
|
||||||
for ( ; transfer.fifo_entries; transfer.fifo_entries--)
|
for ( ; transfer.fifo_entries; transfer.fifo_entries--)
|
||||||
preprocess_write(Machine, (*dcs.fifo_data_r)(NULL));
|
preprocess_write(Machine, (*dcs.fifo_data_r)(dcs.cpu));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2076,7 +2076,7 @@ static TIMER_CALLBACK( transfer_watchdog_callback )
|
|||||||
if (transfer.fifo_entries && starting_writes_left == transfer.writes_left)
|
if (transfer.fifo_entries && starting_writes_left == transfer.writes_left)
|
||||||
{
|
{
|
||||||
for ( ; transfer.fifo_entries; transfer.fifo_entries--)
|
for ( ; transfer.fifo_entries; transfer.fifo_entries--)
|
||||||
preprocess_write(machine, (*dcs.fifo_data_r)(NULL));
|
preprocess_write(machine, (*dcs.fifo_data_r)(dcs.cpu));
|
||||||
}
|
}
|
||||||
timer_adjust_oneshot(transfer.watchdog, ATTOTIME_IN_MSEC(1), transfer.writes_left);
|
timer_adjust_oneshot(transfer.watchdog, ATTOTIME_IN_MSEC(1), transfer.writes_left);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user