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:
Aaron Giles 2008-12-11 17:03:13 +00:00
parent 4ee312ca39
commit e26c70d35b
12 changed files with 264 additions and 463 deletions

View File

@ -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);

View File

@ -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);
} }

View File

@ -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);

View File

@ -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);
} }

View File

@ -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)
{ {
case STATERR_ILLEGAL_REGISTRATIONS:
popmessage("Error: Unable to save state due to illegal registrations. See error.log for details."); popmessage("Error: Unable to save state due to illegal registrations. See error.log for details.");
mame_fclose(file); break;
goto cancel;
}
/* write the default tag */ case STATERR_WRITE_ERROR:
state_save_push_tag(0); popmessage("Error: Unable to save state due to a write error. Verify there is enough disk space.");
state_save_save_continue(machine); break;
state_save_pop_tag();
/* loop over CPUs */ case STATERR_NONE:
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);
/* pop a warning if the game doesn't support saves */
if (!(machine->gamedrv->flags & GAME_SUPPORTS_SAVE)) if (!(machine->gamedrv->flags & GAME_SUPPORTS_SAVE))
popmessage("State successfully saved.\nWarning: Save states are not officially supported for this game."); popmessage("State successfully saved.\nWarning: Save states are not officially supported for this game.");
else else
popmessage("State successfully saved."); popmessage("State successfully saved.");
break;
default:
popmessage("Error: Unknwon error during state save.");
break;
}
/* close and perhaps delete the file */
mame_fclose(file);
if (staterr != STATERR_NONE)
osd_rmfile(astring_c(fullname));
astring_free(fullname);
} }
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 else
popmessage("Error: Failed to load state"); popmessage("State successfully loaded.");
break;
default:
popmessage("Error: Unknwon error during state load.");
break;
}
/* 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;

View File

@ -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)
{
count++;
(*func->func.presave)(machine, func->param); (*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)
{ {
memcpy(global->ioarray + entry->offset, entry->data, entry->typesize * entry->typecount); UINT32 totalsize = entry->typesize * entry->typecount;
LOG((" %s: %x..%x\n", astring_c(entry->name), entry->offset, entry->offset + entry->typesize * entry->typecount - 1)); if (mame_fwrite(file, entry->data, totalsize) != totalsize)
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)
{ {
memcpy(entry->data, global->ioarray + entry->offset, entry->typesize * entry->typecount); UINT32 totalsize = entry->typesize * entry->typecount;
if (need_convert && ss_conv[entry->typesize]) if (mame_fread(file, entry->data, totalsize) != totalsize)
(*ss_conv[entry->typesize])(entry->data, entry->typecount); return STATERR_READ_ERROR;
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)
{
count++;
(*func->func.postload)(machine, func->param); (*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;
} }

View File

@ -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);

View File

@ -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();
} }

View File

@ -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();
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);
} }