From e26c70d35b6e2dae5a4a663466a9f6049875ac0e Mon Sep 17 00:00:00 2001 From: Aaron Giles Date: Thu, 11 Dec 2008 17:03:13 +0000 Subject: [PATCH] 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. --- src/emu/cpuexec.c | 2 - src/emu/fileio.c | 7 +- src/emu/fileio.h | 2 +- src/emu/inptport.c | 4 +- src/emu/mame.c | 119 +++++----- src/emu/state.c | 499 +++++++++++++--------------------------- src/emu/state.h | 58 ++--- src/emu/timer.c | 4 - src/emu/watchdog.c | 2 - src/lib/util/corefile.c | 13 +- src/lib/util/corefile.h | 9 +- src/mame/audio/dcs.c | 8 +- 12 files changed, 264 insertions(+), 463 deletions(-) diff --git a/src/emu/cpuexec.c b/src/emu/cpuexec.c index c6d97101383..3d0582df84e 100644 --- a/src/emu/cpuexec.c +++ b/src/emu/cpuexec.c @@ -262,11 +262,9 @@ void cpuexec_init(running_machine *machine) classdata->timedint_timer = timer_alloc(machine, trigger_periodic_interrupt, device); /* initialize this CPU */ - state_save_push_tag(cpunum + 1); num_regs = state_save_get_reg_count(machine); cpu_init(device, cpunum, classdata->clock, standard_irq_callback); num_regs = state_save_get_reg_count(machine) - num_regs; - state_save_pop_tag(); /* fetch post-initialization data */ classdata->icount = cpu_get_icount_ptr(device); diff --git a/src/emu/fileio.c b/src/emu/fileio.c index efcf2152515..eeadf45329c 100644 --- a/src/emu/fileio.c +++ b/src/emu/fileio.c @@ -386,12 +386,13 @@ void mame_fclose(mame_file *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); } diff --git a/src/emu/fileio.h b/src/emu/fileio.h index 2bd0c48e800..fbe58dbbfa7 100644 --- a/src/emu/fileio.h +++ b/src/emu/fileio.h @@ -98,7 +98,7 @@ file_error mame_fopen_ram(const void *data, UINT32 length, UINT32 openflags, mam /* close an open 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); diff --git a/src/emu/inptport.c b/src/emu/inptport.c index fff9bca81da..269147fe077 100644 --- a/src/emu/inptport.c +++ b/src/emu/inptport.c @@ -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); /* enable compression */ - mame_fcompress(portdata->playback_file, TRUE); + mame_fcompress(portdata->playback_file, FCOMPRESS_MEDIUM); return basetime; } @@ -4174,7 +4174,7 @@ static void record_init(running_machine *machine) mame_fwrite(portdata->record_file, header, sizeof(header)); /* enable compression */ - mame_fcompress(portdata->record_file, TRUE); + mame_fcompress(portdata->record_file, FCOMPRESS_MEDIUM); } diff --git a/src/emu/mame.c b/src/emu/mame.c index a5f654f18dd..0d7fcb14ebe 100644 --- a/src/emu/mame.c +++ b/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); if (filerr == FILERR_NONE) { - int cpunum; - + astring *fullname = astring_dupc(mame_file_full_name(file)); + state_save_error staterr; + /* 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."); - mame_fclose(file); - goto cancel; + case STATERR_ILLEGAL_REGISTRATIONS: + popmessage("Error: Unable to save state due to illegal registrations. See error.log for details."); + 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 */ - 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); + /* close and perhaps delete the file */ mame_fclose(file); - - /* pop a warning if the game doesn't support saves */ - 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."); + if (staterr != STATERR_NONE) + osd_rmfile(astring_c(fullname)); + astring_free(fullname); } else - popmessage("Error: Failed to save state"); + popmessage("Error: Failed to create save state file."); -cancel: /* unschedule the save */ +cancel: astring_free(mame->saveload_pending_file); mame->saveload_searchpath = 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); if (filerr == FILERR_NONE) { - /* start loading */ - if (state_save_load_begin(machine, file) == 0) + state_save_error staterr; + + /* 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 */ - state_save_push_tag(0); - state_save_load_continue(machine); - state_save_pop_tag(); - - /* loop over CPUs */ - for (cpunum = 0; cpunum < ARRAY_LENGTH(machine->cpu); cpunum++) - if (machine->cpu[cpunum] != NULL) - { - /* load the CPU data */ - state_save_push_tag(cpunum + 1); - state_save_load_continue(machine); - state_save_pop_tag(); - } - - /* finish and close */ - state_save_load_finish(machine); - popmessage("State successfully loaded."); + case STATERR_INVALID_HEADER: + popmessage("Error: Unable to load state due to an invalid header. Make sure the save state is correct for this game."); + break; + + case STATERR_READ_ERROR: + popmessage("Error: Unable to load state due to a read error (file is likely corrupt)."); + break; + + case STATERR_NONE: + if (!(machine->gamedrv->flags & GAME_SUPPORTS_SAVE)) + 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); } else - popmessage("Error: Failed to load state"); + popmessage("Error: Failed to open save state file."); -cancel: /* unschedule the load */ +cancel: astring_free(mame->saveload_pending_file); mame->saveload_pending_file = NULL; mame->saveload_schedule_callback = NULL; diff --git a/src/emu/state.c b/src/emu/state.c index f6134b83111..b296c7e702d 100644 --- a/src/emu/state.c +++ b/src/emu/state.c @@ -11,12 +11,15 @@ Save state file format: - 0.. 7 'MAMESAVE" - 8 Format version (this is format 1) - 9 Flags - a..13 Game name padded with \0 - 14..17 Signature - 18..end Save game data + 00..07 'MAMESAVE' + 08 Format version (this is format 2) + 09 Flags + 0A..1B Game name padded with \0 + 1C..1F Signature + 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 ***************************************************************************/ -#define SAVE_VERSION 1 - -#define TAG_STACK_SIZE 4 +#define SAVE_VERSION 2 +#define HEADER_SIZE 32 /* Available flags */ enum @@ -65,7 +67,6 @@ struct _state_entry astring * name; /* full name */ UINT8 typesize; /* size of the raw data type */ UINT32 typecount; /* number of items */ - int tag; /* saving tag */ UINT32 offset; /* offset within the final structure */ }; @@ -76,7 +77,6 @@ struct _state_callback state_callback * next; /* pointer to next entry */ running_machine * machine; /* pointer back to the owning machine */ void * param; /* function parameter */ - int tag; /* saving tag */ union { state_presave_func presave; /* presave callback */ @@ -106,11 +106,6 @@ struct _state_private 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 static const char ss_magic_num[8] = { 'M', 'E', 'S', 'S', 'S', 'A', 'V', 'E' }; #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); -static void ss_c8(UINT8 *, UINT32); +/*------------------------------------------------- + flip_data - reverse the endianness of a + 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; int count = 0; - /* iterate over entries with matching tags */ + /* count entries */ for (entry = global->entrylist; entry != NULL; entry = entry->next) 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 ***************************************************************************/ @@ -254,9 +245,9 @@ void state_save_register_memory(running_machine *machine, const char *module, co /* create the full name */ totalname = astring_alloc(); 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 - 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 */ 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; /* error if we are equal */ - if ((*entryptr)->tag == ss_current_tag && cmpval == 0) - fatalerror("Duplicate save state registration entry (%d, %s)", ss_current_tag, astring_c(totalname)); + if (cmpval == 0) + fatalerror("Duplicate save state registration entry (%s)", astring_c(totalname)); } /* 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)->typesize = valsize; (*entryptr)->typecount = valcount; - (*entryptr)->tag = ss_current_tag; 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 */ for (cbptr = &global->prefunclist; *cbptr != NULL; cbptr = &(*cbptr)->next) - if ((*cbptr)->func.presave == func && (*cbptr)->param == param && (*cbptr)->tag == ss_current_tag) - fatalerror("Duplicate save state function (%d, %p, %p)", ss_current_tag, param, func); + if ((*cbptr)->func.presave == func && (*cbptr)->param == param) + fatalerror("Duplicate save state function (%p, %p)", param, func); /* allocate a new entry */ *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)->func.presave = func; (*cbptr)->param = param; - (*cbptr)->tag = ss_current_tag; 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 */ for (cbptr = &global->postfunclist; *cbptr != NULL; cbptr = &(*cbptr)->next) - if ((*cbptr)->func.postload == func && (*cbptr)->param == param && (*cbptr)->tag == ss_current_tag) - fatalerror("Duplicate save state function (%d, %p, %p)", ss_current_tag, param, func); + if ((*cbptr)->func.postload == func && (*cbptr)->param == param) + fatalerror("Duplicate save state function (%p, %p)", param, func); /* allocate a new entry */ *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)->func.postload = func; (*cbptr)->param = param; - (*cbptr)->tag = ss_current_tag; 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 ***************************************************************************/ -/*------------------------------------------------- - 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 is a CRC over the structure of the data @@ -536,7 +451,7 @@ static UINT32 get_signature(running_machine *machine) UINT32 crc = 0; /* iterate over entries */ - for (entry = global->entrylist; entry; entry = entry->next) + for (entry = global->entrylist; entry != NULL; entry = entry->next) { UINT32 temp[2]; @@ -546,7 +461,7 @@ static UINT32 get_signature(running_machine *machine) /* add the type and size to the CRC */ temp[0] = LITTLE_ENDIANIZE_INT32(entry->typecount); temp[1] = LITTLE_ENDIANIZE_INT32(entry->typesize); - crc = crc32(crc, (UINT8 *)&temp[0], 8); + crc = crc32(crc, (UINT8 *)&temp[0], sizeof(temp)); } 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 -------------------------------------------------*/ -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) { /* check magic number */ if (memcmp(header, ss_magic_num, 8)) { - if (errormsg) - errormsg("%sThis is not a " APPNAME " save file", error_prefix); - return -1; + if (errormsg != NULL) + (*errormsg)("%sThis is not a " APPNAME " save file", error_prefix); + return STATERR_INVALID_HEADER; } /* check save state version */ if (header[8] != SAVE_VERSION) { - if (errormsg) - errormsg("%sWrong version in save file (%d, 1 expected)", error_prefix, header[8]); - return -1; + if (errormsg != NULL) + (*errormsg)("%sWrong version in save file (version %d, expected %d)", error_prefix, header[8], SAVE_VERSION); + return STATERR_INVALID_HEADER; } /* 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) - errormsg("%s'%s' is not a valid savestate file for game '%s'.", error_prefix, gamename); - return -1; + if (errormsg != NULL) + (*errormsg)("%s'File is not a valid savestate file for game '%s'.", error_prefix, gamename); + return STATERR_INVALID_HEADER; } /* check signature, if we were asked to */ - if (signature) + if (signature != 0) { - UINT32 rawsig = *(UINT32 *)&header[0x14]; - UINT32 filesig = LITTLE_ENDIANIZE_INT32(rawsig); - if (signature != filesig) + UINT32 rawsig = *(UINT32 *)&header[0x1c]; + if (signature != LITTLE_ENDIANIZE_INT32(rawsig)) { - if (errormsg) - errormsg("%sIncompatible save file (signature %08x, expected %08x)", error_prefix, filesig, signature); - return -1; + if (errormsg != NULL) + (*errormsg)("%sIncompatible save file (signature %08x, expected %08x)", error_prefix, LITTLE_ENDIANIZE_INT32(rawsig), signature); + 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 -------------------------------------------------*/ -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; - UINT8 header[0x18]; /* if we want to validate the signature, compute it */ if (machine != NULL) signature = get_signature(machine); /* seek to the beginning and read the header */ + mame_fcompress(file, FCOMPRESS_NONE); mame_fseek(file, 0, SEEK_SET); if (mame_fread(file, header, sizeof(header)) != sizeof(header)) { - if (errormsg) - errormsg("Could not read " APPNAME " save file header"); - return -1; + if (errormsg != NULL) + (*errormsg)("Could not read " APPNAME " save file header"); + return STATERR_READ_ERROR; } /* 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 - saving + state_save_write_file - writes the data to + 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; + UINT32 signature = get_signature(machine); + UINT8 header[HEADER_SIZE]; + state_callback *func; + state_entry *entry; /* if we have illegal registrations, return an error */ if (global->illegal_regs > 0) - return 1; - - LOG(("Beginning save\n")); - global->iofile = file; - - /* compute the total dump size and the offsets of each element */ - global->ioarraysize = compute_size_and_offsets(global); - LOG((" total size %u\n", global->ioarraysize)); - - /* allocate memory for the array */ - global->ioarray = malloc_or_die(global->ioarraysize); - 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)); + return STATERR_ILLEGAL_REGISTRATIONS; + /* generate the header */ + 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); + + /* write the header and turn on compression for the rest of the file */ + mame_fcompress(file, FCOMPRESS_NONE); + mame_fseek(file, 0, SEEK_SET); + if (mame_fwrite(file, header, sizeof(header)) != sizeof(header)) + return STATERR_WRITE_ERROR; + mame_fcompress(file, FCOMPRESS_MEDIUM); + /* 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) - if (func->tag == ss_current_tag) - { - count++; - (*func->func.presave)(machine, func->param); - } - LOG((" %d functions called\n", count)); - - /* then copy in all the data */ - LOG((" copying data\n")); - - /* iterate over entries with matching tags */ + (*func->func.presave)(machine, func->param); + + /* then write all the data */ 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); - LOG((" %s: %x..%x\n", astring_c(entry->name), entry->offset, entry->offset + entry->typesize * entry->typecount - 1)); - } + { + UINT32 totalsize = entry->typesize * entry->typecount; + if (mame_fwrite(file, entry->data, totalsize) != totalsize) + return STATERR_WRITE_ERROR; + } + return STATERR_NONE; } /*------------------------------------------------- - state_save_save_finish - finish saving the - file by writing the header and closing + state_save_read_file - read the data from a + 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; - UINT32 signature; - UINT8 flags = 0; + UINT32 signature = get_signature(machine); + UINT8 header[HEADER_SIZE]; + state_callback *func; + state_entry *entry; + int flip; + + /* if we have illegal registrations, return an error */ + if (global->illegal_regs > 0) + return STATERR_ILLEGAL_REGISTRATIONS; + + /* read the header and turn on compression for the rest of the file */ + mame_fcompress(file, FCOMPRESS_NONE); + mame_fseek(file, 0, SEEK_SET); + if (mame_fread(file, header, sizeof(header)) != sizeof(header)) + return STATERR_READ_ERROR; + mame_fcompress(file, FCOMPRESS_MEDIUM); + + /* verify the header and report an error if it doesn't match */ + if (validate_header(header, machine->gamedrv->name, signature, popmessage, "Error: ") != STATERR_NONE) + return STATERR_INVALID_HEADER; - LOG(("Finishing save\n")); - - /* compute the flags */ -#ifndef LSB_FIRST - flags |= SS_MSB_FIRST; + /* determine whether or not to flip the data when done */ +#ifdef LSB_FIRST + flip = ((header[9] & SS_MSB_FIRST) != 0); +#else + flip = ((header[9] & SS_MSB_FIRST) == 0); #endif - /* build up the header */ - 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 */ - if (validate_header(global->ioarray, NULL, get_signature(machine), popmessage, "Error: ")) + /* read all the data, flipping if necessary */ + for (entry = global->entrylist; entry != NULL; entry = entry->next) { - free(global->ioarray); - global->ioarray = NULL; - global->ioarraysize = 0; - global->iofile = NULL; - return 1; + UINT32 totalsize = entry->typesize * entry->typecount; + if (mame_fread(file, entry->data, totalsize) != totalsize) + return STATERR_READ_ERROR; + + /* handle flipping */ + if (flip) + flip_data(entry); } - /* compute the total size and offset of all the entries */ - 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 - need_convert = (global->ioarray[9] & SS_MSB_FIRST) != 0; -#else - need_convert = (global->ioarray[9] & SS_MSB_FIRST) == 0; -#endif - - LOG(("Loading tag %d\n", ss_current_tag)); - LOG((" copying data\n")); - - /* iterate over entries with matching tags */ - 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); - if (need_convert && ss_conv[entry->typesize]) - (*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)); - } - /* call the post-load functions */ - LOG((" calling post-load functions\n")); for (func = global->postfunclist; func != NULL; func = func->next) - if (func->tag == ss_current_tag) - { - count++; - (*func->func.postload)(machine, func->param); - } - LOG((" %d functions called\n", count)); -} + (*func->func.postload)(machine, func->param); - -/*------------------------------------------------- - 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; + return STATERR_NONE; } diff --git a/src/emu/state.h b/src/emu/state.h index 0fe0bf169a4..352af38780b 100644 --- a/src/emu/state.h +++ b/src/emu/state.h @@ -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 ***************************************************************************/ @@ -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 ----- */ /* 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 */ -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); - -/* ----- save state processing ----- */ - -/* 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); +/* read in a save state file */ +state_save_error state_save_read_file(running_machine *machine, mame_file *file); diff --git a/src/emu/timer.c b/src/emu/timer.c index 34a7979e6b2..b0dd3487b82 100644 --- a/src/emu/timer.c +++ b/src/emu/timer.c @@ -296,11 +296,9 @@ void timer_init(running_machine *machine) global->callback_timer_modified = FALSE; /* 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.attoseconds); state_save_register_postload(machine, timer_postload, NULL); - state_save_pop_tag(); /* initialize the lists */ global->activelist = NULL; @@ -523,7 +521,6 @@ static void timer_register_save(emu_timer *timer) count++; /* 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->enabled); 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->expire.seconds); state_save_register_item(timer->machine, "timer", timer->func, count, timer->expire.attoseconds); - state_save_pop_tag(); } diff --git a/src/emu/watchdog.c b/src/emu/watchdog.c index 6a935b75f9d..b505072149d 100644 --- a/src/emu/watchdog.c +++ b/src/emu/watchdog.c @@ -45,10 +45,8 @@ void watchdog_init(running_machine *machine) add_reset_callback(machine, watchdog_internal_reset); /* 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_counter); - state_save_pop_tag(); } diff --git a/src/lib/util/corefile.c b/src/lib/util/corefile.c index 061d59523f8..1a4b5653981 100644 --- a/src/lib/util/corefile.c +++ b/src/lib/util/corefile.c @@ -213,7 +213,7 @@ void core_fclose(core_file *file) { /* close files and free memory */ if (file->zdata != NULL) - core_fcompress(file, FALSE); + core_fcompress(file, FCOMPRESS_NONE); if (file->file != NULL) osd_close(file->file); if (file->data != NULL && file->data_allocated) @@ -224,10 +224,11 @@ void core_fclose(core_file *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; @@ -236,7 +237,7 @@ file_error core_fcompress(core_file *file, int compress) return FILERR_INVALID_ACCESS; /* 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; @@ -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 (file->zdata == NULL && compress) + if (file->zdata == NULL && level > FCOMPRESS_NONE) { 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.avail_out = sizeof(file->zdata->buffer); - zerr = deflateInit(&file->zdata->stream, Z_BEST_COMPRESSION); + zerr = deflateInit(&file->zdata->stream, level); } else zerr = inflateInit(&file->zdata->stream); diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h index 944ad19e97a..1fdec4cc761 100644 --- a/src/lib/util/corefile.h +++ b/src/lib/util/corefile.h @@ -26,6 +26,11 @@ #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 */ void core_fclose(core_file *file); -/* enable/disable streaming file compression via zlib */ -file_error core_fcompress(core_file *file, int compress); +/* 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 level); diff --git a/src/mame/audio/dcs.c b/src/mame/audio/dcs.c index 230b9c9f808..eac01fed9dc 100644 --- a/src/mame/audio/dcs.c +++ b/src/mame/audio/dcs.c @@ -1507,7 +1507,7 @@ static READ16_HANDLER( latch_status_r ) if (IS_OUTPUT_EMPTY()) result |= 0x40; 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) result |= 0x08; return result; @@ -1517,7 +1517,7 @@ static READ16_HANDLER( latch_status_r ) static READ16_HANDLER( fifo_input_r ) { if (dcs.fifo_data_r) - return (*dcs.fifo_data_r)(NULL); + return (*dcs.fifo_data_r)(dcs.cpu); else 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) { 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) { 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); }