summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/machine.c')
-rw-r--r--src/emu/machine.c1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/src/emu/machine.c b/src/emu/machine.c
new file mode 100644
index 00000000000..0dcd62d6b99
--- /dev/null
+++ b/src/emu/machine.c
@@ -0,0 +1,1003 @@
+/***************************************************************************
+
+ machine.c
+
+ Controls execution of the core MAME system.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+****************************************************************************
+
+ Since there has been confusion in the past over the order of
+ initialization and other such things, here it is, all spelled out
+ as of January, 2008:
+
+ main()
+ - does platform-specific init
+ - calls mame_execute() [mame.c]
+
+ mame_execute() [mame.c]
+ - calls mame_validitychecks() [validity.c] to perform validity checks on all compiled drivers
+ - begins resource tracking (level 1)
+ - calls create_machine [mame.c] to initialize the running_machine structure
+ - calls init_machine() [mame.c]
+
+ init_machine() [mame.c]
+ - calls fileio_init() [fileio.c] to initialize file I/O info
+ - calls config_init() [config.c] to initialize configuration system
+ - calls input_init() [input.c] to initialize the input system
+ - calls output_init() [output.c] to initialize the output system
+ - calls state_init() [state.c] to initialize save state system
+ - calls state_save_allow_registration() [state.c] to allow registrations
+ - calls palette_init() [palette.c] to initialize palette system
+ - calls render_init() [render.c] to initialize the rendering system
+ - calls ui_init() [ui.c] to initialize the user interface
+ - calls generic_machine_init() [machine/generic.c] to initialize generic machine structures
+ - calls generic_video_init() [video/generic.c] to initialize generic video structures
+ - calls generic_sound_init() [audio/generic.c] to initialize generic sound structures
+ - calls timer_init() [timer.c] to reset the timer system
+ - calls osd_init() [osdepend.h] to do platform-specific initialization
+ - calls input_port_init() [inptport.c] to set up the input ports
+ - calls rom_init() [romload.c] to load the game's ROMs
+ - calls memory_init() [memory.c] to process the game's memory maps
+ - calls watchdog_init() [watchdog.c] to initialize the watchdog system
+ - calls the driver's DRIVER_INIT callback
+ - calls device_list_start() [devintrf.c] to start any devices
+ - calls video_init() [video.c] to start the video system
+ - calls tilemap_init() [tilemap.c] to start the tilemap system
+ - calls crosshair_init() [crsshair.c] to configure the crosshairs
+ - calls sound_init() [sound.c] to start the audio system
+ - calls debugger_init() [debugger.c] to set up the debugger
+ - calls the driver's MACHINE_START, SOUND_START, and VIDEO_START callbacks
+ - calls cheat_init() [cheat.c] to initialize the cheat system
+ - calls image_init() [image.c] to initialize the image system
+
+ - calls config_load_settings() [config.c] to load the configuration file
+ - calls nvram_load [machine/generic.c] to load NVRAM
+ - calls ui_display_startup_screens() [ui.c] to display the the startup screens
+ - begins resource tracking (level 2)
+ - calls soft_reset() [mame.c] to reset all systems
+
+ -------------------( at this point, we're up and running )----------------------
+
+ - calls scheduler->timeslice() [schedule.c] over and over until we exit
+ - ends resource tracking (level 2), freeing all auto_mallocs and timers
+ - calls the nvram_save() [machine/generic.c] to save NVRAM
+ - calls config_save_settings() [config.c] to save the game's configuration
+ - calls all registered exit routines [mame.c]
+ - ends resource tracking (level 1), freeing all auto_mallocs and timers
+
+ - exits the program
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "osdepend.h"
+#include "config.h"
+#include "debugger.h"
+#include "image.h"
+#include "profiler.h"
+#include "render.h"
+#include "cheat.h"
+#include "ui.h"
+#include "uimenu.h"
+#include "uiinput.h"
+#include "streams.h"
+#include "crsshair.h"
+#include "validity.h"
+#include "debug/debugcon.h"
+
+#include <time.h>
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// a giant string buffer for temporary strings
+static char giant_string_buffer[65536] = { 0 };
+
+
+
+//**************************************************************************
+// RUNNING MACHINE
+//**************************************************************************
+
+//-------------------------------------------------
+// running_machine - constructor
+//-------------------------------------------------
+
+running_machine::running_machine(const game_driver &driver, const machine_config &_config, core_options &options, bool exit_to_game_select)
+ : m_regionlist(m_respool),
+ m_devicelist(m_respool),
+ config(&_config),
+ m_config(_config),
+ firstcpu(NULL),
+ gamedrv(&driver),
+ m_game(driver),
+ primary_screen(NULL),
+ palette(NULL),
+ pens(NULL),
+ colortable(NULL),
+ shadow_table(NULL),
+ priority_bitmap(NULL),
+ sample_rate(options_get_int(&options, OPTION_SAMPLERATE)),
+ debug_flags(0),
+ ui_active(false),
+ mame_data(NULL),
+ timer_data(NULL),
+ state_data(NULL),
+ memory_data(NULL),
+ palette_data(NULL),
+ tilemap_data(NULL),
+ streams_data(NULL),
+ devices_data(NULL),
+ romload_data(NULL),
+ sound_data(NULL),
+ input_data(NULL),
+ input_port_data(NULL),
+ ui_input_data(NULL),
+ cheat_data(NULL),
+ debugcpu_data(NULL),
+ generic_machine_data(NULL),
+ generic_video_data(NULL),
+ generic_audio_data(NULL),
+ m_debug_view(NULL),
+ driver_data(NULL),
+ m_logerror_list(NULL),
+ m_scheduler(*this),
+ m_options(options),
+ m_basename(driver.name),
+ m_current_phase(MACHINE_PHASE_PREINIT),
+ m_paused(false),
+ m_hard_reset_pending(false),
+ m_exit_pending(false),
+ m_exit_to_game_select(exit_to_game_select),
+ m_new_driver_pending(NULL),
+ m_soft_reset_timer(NULL),
+ m_logfile(NULL),
+ m_saveload_schedule(SLS_NONE),
+ m_saveload_schedule_time(attotime_zero),
+ m_saveload_searchpath(NULL),
+ m_rand_seed(0x9d14abd7)
+{
+ memset(gfx, 0, sizeof(gfx));
+ memset(&generic, 0, sizeof(generic));
+ memset(m_notifier_list, 0, sizeof(m_notifier_list));
+ memset(&m_base_time, 0, sizeof(m_base_time));
+
+ // attach this machine to all the devices in the configuration
+ m_devicelist.import_config_list(m_config.m_devicelist, *this);
+
+ // allocate the driver data (after devices)
+ if (m_config.m_driver_data_alloc != NULL)
+ driver_data = (*m_config.m_driver_data_alloc)(*this);
+
+ // find devices
+ firstcpu = cpu_first(this);
+ primary_screen = screen_first(*this);
+
+ // fetch core options
+ if (options_get_bool(&m_options, OPTION_DEBUG))
+ debug_flags = (DEBUG_FLAG_ENABLED | DEBUG_FLAG_CALL_HOOK) | (options_get_bool(&m_options, OPTION_DEBUG_INTERNAL) ? 0 : DEBUG_FLAG_OSD_ENABLED);
+}
+
+
+//-------------------------------------------------
+// ~running_machine - destructor
+//-------------------------------------------------
+
+running_machine::~running_machine()
+{
+}
+
+
+//-------------------------------------------------
+// describe_context - return a string describing
+// which device is currently executing and its
+// PC
+//-------------------------------------------------
+
+const char *running_machine::describe_context()
+{
+ device_execute_interface *executing = m_scheduler.currently_executing();
+ if (executing != NULL)
+ {
+ cpu_device *cpu = downcast<cpu_device *>(&executing->device());
+ if (cpu != NULL)
+ m_context.printf("'%s' (%s)", cpu->tag(), core_i64_hex_format(cpu_get_pc(cpu), cpu->space(AS_PROGRAM)->logaddrchars));
+ else
+ m_context.printf("'%s'", cpu->tag());
+ }
+ else
+ m_context.cpy("(no context)");
+
+ return m_context;
+}
+
+
+//-------------------------------------------------
+// start - initialize the emulated machine
+//-------------------------------------------------
+
+void running_machine::start()
+{
+ // initialize basic can't-fail systems here
+ fileio_init(this);
+ config_init(this);
+ input_init(this);
+ output_init(this);
+ state_init(this);
+ state_save_allow_registration(this, true);
+ palette_init(this);
+ render_init(this);
+ ui_init(this);
+ generic_machine_init(this);
+ generic_video_init(this);
+ generic_sound_init(this);
+
+ // initialize the timers and allocate a soft_reset timer
+ // this must be done before cpu_init so that CPU's can allocate timers
+ timer_init(this);
+ m_soft_reset_timer = timer_alloc(this, static_soft_reset, NULL);
+
+ // init the osd layer
+ osd_init(this);
+
+ // initialize the base time (needed for doing record/playback)
+ time(&m_base_time);
+
+ // initialize the input system and input ports for the game
+ // this must be done before memory_init in order to allow specifying
+ // callbacks based on input port tags
+ time_t newbase = input_port_init(this, m_game.ipt);
+ if (newbase != 0)
+ m_base_time = newbase;
+
+ // intialize UI input
+ ui_input_init(this);
+
+ // initialize the streams engine before the sound devices start
+ streams_init(this);
+
+ // first load ROMs, then populate memory, and finally initialize CPUs
+ // these operations must proceed in this order
+ rom_init(this);
+ memory_init(this);
+ watchdog_init(this);
+
+ // allocate the gfx elements prior to device initialization
+ gfx_init(this);
+
+ // initialize natural keyboard support
+ inputx_init(this);
+
+ // initialize image devices
+ image_init(this);
+
+ // start up the devices
+ m_devicelist.start_all();
+
+ // call the game driver's init function
+ // this is where decryption is done and memory maps are altered
+ // so this location in the init order is important
+ ui_set_startup_text(this, "Initializing...", true);
+ if (m_game.driver_init != NULL)
+ (*m_game.driver_init)(this);
+
+ // finish image devices init process
+ image_postdevice_init(this);
+
+ // start the video and audio hardware
+ video_init(this);
+ tilemap_init(this);
+ crosshair_init(this);
+
+ sound_init(this);
+
+ // initialize the debugger
+ if ((debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ debugger_init(this);
+
+ // call the driver's _START callbacks
+ if (m_config.m_machine_start != NULL)
+ (*m_config.m_machine_start)(this);
+ if (m_config.m_sound_start != NULL)
+ (*m_config.m_sound_start)(this);
+ if (m_config.m_video_start != NULL)
+ (*m_config.m_video_start)(this);
+
+ // if we're coming in with a savegame request, process it now
+ const char *savegame = options_get_string(&m_options, OPTION_STATE);
+ if (savegame[0] != 0)
+ schedule_load(savegame);
+
+ // if we're in autosave mode, schedule a load
+ else if (options_get_bool(&m_options, OPTION_AUTOSAVE) && (m_game.flags & GAME_SUPPORTS_SAVE) != 0)
+ schedule_load("auto");
+
+ // set up the cheat engine
+ if (options_get_bool(&m_options, OPTION_CHEAT))
+ cheat_init(this);
+
+ // disallow save state registrations starting here
+ state_save_allow_registration(this, false);
+}
+
+
+//-------------------------------------------------
+// run - execute the machine
+//-------------------------------------------------
+
+int running_machine::run(bool firstrun)
+{
+ int error = MAMERR_NONE;
+
+ // use try/catch for deep error recovery
+ try
+ {
+ // move to the init phase
+ m_current_phase = MACHINE_PHASE_INIT;
+
+ // if we have a logfile, set up the callback
+ if (options_get_bool(&m_options, OPTION_LOG))
+ {
+ file_error filerr = mame_fopen(SEARCHPATH_DEBUGLOG, "error.log", OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &m_logfile);
+ assert_always(filerr == FILERR_NONE, "unable to open log file");
+ add_logerror_callback(logfile_callback);
+ }
+
+ // then finish setting up our local machine
+ start();
+
+ // load the configuration settings and NVRAM
+ bool settingsloaded = config_load_settings(this);
+ nvram_load(this);
+ sound_mute(this, FALSE);
+
+ // display the startup screens
+ ui_display_startup_screens(this, firstrun, !settingsloaded);
+
+ // perform a soft reset -- this takes us to the running phase
+ soft_reset();
+
+ // run the CPUs until a reset or exit
+ m_hard_reset_pending = false;
+ while ((!m_hard_reset_pending && !m_exit_pending) || m_saveload_schedule != SLS_NONE)
+ {
+ profiler_mark_start(PROFILER_EXTRA);
+
+ // execute CPUs if not paused
+ if (!m_paused)
+ m_scheduler.timeslice();
+
+ // otherwise, just pump video updates through
+ else
+ video_frame_update(this, false);
+
+ // handle save/load
+ if (m_saveload_schedule != SLS_NONE)
+ handle_saveload();
+
+ profiler_mark_end();
+ }
+
+ // and out via the exit phase
+ m_current_phase = MACHINE_PHASE_EXIT;
+
+ // save the NVRAM and configuration
+ sound_mute(this, true);
+ nvram_save(this);
+ config_save_settings(this);
+ }
+ catch (emu_fatalerror &fatal)
+ {
+ mame_printf_error("%s\n", fatal.string());
+ error = MAMERR_FATALERROR;
+ if (fatal.exitcode() != 0)
+ error = fatal.exitcode();
+ }
+ catch (emu_exception &)
+ {
+ mame_printf_error("Caught unhandled emulator exception\n");
+ error = MAMERR_FATALERROR;
+ }
+ catch (std::bad_alloc &)
+ {
+ mame_printf_error("Out of memory!\n");
+ error = MAMERR_FATALERROR;
+ }
+
+ // call all exit callbacks registered
+ call_notifiers(MACHINE_NOTIFY_EXIT);
+
+ // close the logfile
+ if (m_logfile != NULL)
+ mame_fclose(m_logfile);
+ return error;
+}
+
+
+//-------------------------------------------------
+// schedule_exit - schedule a clean exit
+//-------------------------------------------------
+
+void running_machine::schedule_exit()
+{
+ // if we are in-game but we started with the select game menu, return to that instead
+ if (m_exit_to_game_select && options_get_string(&m_options, OPTION_GAMENAME)[0] != 0)
+ {
+ options_set_string(&m_options, OPTION_GAMENAME, "", OPTION_PRIORITY_CMDLINE);
+ ui_menu_force_game_select(this, render_container_get_ui());
+ }
+
+ // otherwise, exit for real
+ else
+ m_exit_pending = true;
+
+ // if we're executing, abort out immediately
+ m_scheduler.eat_all_cycles();
+
+ // if we're autosaving on exit, schedule a save as well
+ if (options_get_bool(&m_options, OPTION_AUTOSAVE) && (m_game.flags & GAME_SUPPORTS_SAVE))
+ schedule_save("auto");
+}
+
+
+//-------------------------------------------------
+// schedule_hard_reset - schedule a hard-reset of
+// the machine
+//-------------------------------------------------
+
+void running_machine::schedule_hard_reset()
+{
+ m_hard_reset_pending = true;
+
+ // if we're executing, abort out immediately
+ m_scheduler.eat_all_cycles();
+}
+
+
+//-------------------------------------------------
+// schedule_soft_reset - schedule a soft-reset of
+// the system
+//-------------------------------------------------
+
+void running_machine::schedule_soft_reset()
+{
+ timer_adjust_oneshot(m_soft_reset_timer, attotime_zero, 0);
+
+ // we can't be paused since the timer needs to fire
+ resume();
+
+ // if we're executing, abort out immediately
+ m_scheduler.eat_all_cycles();
+}
+
+
+//-------------------------------------------------
+// schedule_new_driver - schedule a new game to
+// be loaded
+//-------------------------------------------------
+
+void running_machine::schedule_new_driver(const game_driver &driver)
+{
+ m_hard_reset_pending = true;
+ m_new_driver_pending = &driver;
+
+ // if we're executing, abort out immediately
+ m_scheduler.eat_all_cycles();
+}
+
+
+//-------------------------------------------------
+// set_saveload_filename - specifies the filename
+// for state loading/saving
+//-------------------------------------------------
+
+void running_machine::set_saveload_filename(const char *filename)
+{
+ // free any existing request and allocate a copy of the requested name
+ if (osd_is_absolute_path(filename))
+ {
+ m_saveload_searchpath = NULL;
+ m_saveload_pending_file.cpy(filename);
+ }
+ else
+ {
+ m_saveload_searchpath = SEARCHPATH_STATE;
+ m_saveload_pending_file.cpy(basename()).cat(PATH_SEPARATOR).cat(filename).cat(".sta");
+ }
+}
+
+
+//-------------------------------------------------
+// schedule_save - schedule a save to occur as
+// soon as possible
+//-------------------------------------------------
+
+void running_machine::schedule_save(const char *filename)
+{
+ // specify the filename to save or load
+ set_saveload_filename(filename);
+
+ // note the start time and set a timer for the next timeslice to actually schedule it
+ m_saveload_schedule = SLS_SAVE;
+ m_saveload_schedule_time = timer_get_time(this);
+
+ // we can't be paused since we need to clear out anonymous timers
+ resume();
+}
+
+
+//-------------------------------------------------
+// schedule_load - schedule a load to occur as
+// soon as possible
+//-------------------------------------------------
+
+void running_machine::schedule_load(const char *filename)
+{
+ // specify the filename to save or load
+ set_saveload_filename(filename);
+
+ // note the start time and set a timer for the next timeslice to actually schedule it
+ m_saveload_schedule = SLS_LOAD;
+ m_saveload_schedule_time = timer_get_time(this);
+
+ // we can't be paused since we need to clear out anonymous timers
+ resume();
+}
+
+
+//-------------------------------------------------
+// pause - pause the system
+//-------------------------------------------------
+
+void running_machine::pause()
+{
+ // ignore if nothing has changed
+ if (m_paused)
+ return;
+ m_paused = true;
+
+ // call the callbacks
+ call_notifiers(MACHINE_NOTIFY_PAUSE);
+}
+
+
+//-------------------------------------------------
+// resume - resume the system
+//-------------------------------------------------
+
+void running_machine::resume()
+{
+ // ignore if nothing has changed
+ if (!m_paused)
+ return;
+ m_paused = false;
+
+ // call the callbacks
+ call_notifiers(MACHINE_NOTIFY_RESUME);
+}
+
+
+//-------------------------------------------------
+// region_alloc - allocates memory for a region
+//-------------------------------------------------
+
+region_info *running_machine::region_alloc(const char *name, UINT32 length, UINT32 flags)
+{
+ // make sure we don't have a region of the same name; also find the end of the list
+ region_info *info = m_regionlist.find(name);
+ if (info != NULL)
+ fatalerror("region_alloc called with duplicate region name \"%s\"\n", name);
+
+ // allocate the region
+ return m_regionlist.append(name, auto_alloc(this, region_info(*this, name, length, flags)));
+}
+
+
+//-------------------------------------------------
+// region_free - releases memory for a region
+//-------------------------------------------------
+
+void running_machine::region_free(const char *name)
+{
+ m_regionlist.remove(name);
+}
+
+
+//-------------------------------------------------
+// add_notifier - add a notifier of the
+// given type
+//-------------------------------------------------
+
+void running_machine::add_notifier(machine_notification event, notify_callback callback)
+{
+ assert_always(m_current_phase == MACHINE_PHASE_INIT, "Can only call add_notifier at init time!");
+
+ // exit notifiers are added to the head, and executed in reverse order
+ if (event == MACHINE_NOTIFY_EXIT)
+ {
+ notifier_callback_item *notifier = auto_alloc(this, notifier_callback_item(callback));
+ notifier->m_next = m_notifier_list[event];
+ m_notifier_list[event] = notifier;
+ }
+
+ // all other notifiers are added to the tail, and executed in the order registered
+ else
+ {
+ notifier_callback_item **tailptr;
+ for (tailptr = &m_notifier_list[event]; *tailptr != NULL; tailptr = &(*tailptr)->m_next) ;
+ *tailptr = auto_alloc(this, notifier_callback_item(callback));
+ }
+}
+
+
+//-------------------------------------------------
+// add_logerror_callback - adds a callback to be
+// called on logerror()
+//-------------------------------------------------
+
+void running_machine::add_logerror_callback(logerror_callback callback)
+{
+ assert_always(m_current_phase == MACHINE_PHASE_INIT, "Can only call add_logerror_callback at init time!");
+
+ logerror_callback_item **tailptr;
+ for (tailptr = &m_logerror_list; *tailptr != NULL; tailptr = &(*tailptr)->m_next) ;
+ *tailptr = auto_alloc(this, logerror_callback_item(callback));
+}
+
+
+//-------------------------------------------------
+// logerror - printf-style error logging
+//-------------------------------------------------
+
+void CLIB_DECL running_machine::logerror(const char *format, ...)
+{
+ // process only if there is a target
+ if (m_logerror_list != NULL)
+ {
+ va_list arg;
+ va_start(arg, format);
+ vlogerror(format, arg);
+ va_end(arg);
+ }
+}
+
+
+//-------------------------------------------------
+// vlogerror - vprintf-style error logging
+//-------------------------------------------------
+
+void CLIB_DECL running_machine::vlogerror(const char *format, va_list args)
+{
+ // process only if there is a target
+ if (m_logerror_list != NULL)
+ {
+ profiler_mark_start(PROFILER_LOGERROR);
+
+ // dump to the buffer
+ vsnprintf(giant_string_buffer, ARRAY_LENGTH(giant_string_buffer), format, args);
+
+ // log to all callbacks
+ for (logerror_callback_item *cb = m_logerror_list; cb != NULL; cb = cb->m_next)
+ (*cb->m_func)(*this, giant_string_buffer);
+
+ profiler_mark_end();
+ }
+}
+
+
+//-------------------------------------------------
+// base_datetime - retrieve the time of the host
+// system; useful for RTC implementations
+//-------------------------------------------------
+
+void running_machine::base_datetime(system_time &systime)
+{
+ systime.set(m_base_time);
+}
+
+
+//-------------------------------------------------
+// current_datetime - retrieve the current time
+// (offset by the base); useful for RTC
+// implementations
+//-------------------------------------------------
+
+void running_machine::current_datetime(system_time &systime)
+{
+ systime.set(m_base_time + timer_get_time(this).seconds);
+}
+
+
+//-------------------------------------------------
+// rand - standardized random numbers
+//-------------------------------------------------
+
+UINT32 running_machine::rand()
+{
+ m_rand_seed = 1664525 * m_rand_seed + 1013904223;
+
+ // return rotated by 16 bits; the low bits have a short period
+ // and are frequently used
+ return (m_rand_seed >> 16) | (m_rand_seed << 16);
+}
+
+
+//-------------------------------------------------
+// call_notifiers - call notifiers of the given
+// type
+//-------------------------------------------------
+
+void running_machine::call_notifiers(machine_notification which)
+{
+ for (notifier_callback_item *cb = m_notifier_list[which]; cb != NULL; cb = cb->m_next)
+ (*cb->m_func)(*this);
+}
+
+
+//-------------------------------------------------
+// handle_saveload - attempt to perform a save
+// or load
+//-------------------------------------------------
+
+void running_machine::handle_saveload()
+{
+ UINT32 openflags = (m_saveload_schedule == SLS_LOAD) ? OPEN_FLAG_READ : (OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ const char *opnamed = (m_saveload_schedule == SLS_LOAD) ? "loaded" : "saved";
+ const char *opname = (m_saveload_schedule == SLS_LOAD) ? "load" : "save";
+ file_error filerr = FILERR_NONE;
+
+ // if no name, bail
+ if (m_saveload_pending_file.len() == 0)
+ goto cancel;
+
+ // if there are anonymous timers, we can't save just yet, and we can't load yet either
+ // because the timers might overwrite data we have loaded
+ if (timer_count_anonymous(this) > 0)
+ {
+ // if more than a second has passed, we're probably screwed
+ if (attotime_sub(timer_get_time(this), m_saveload_schedule_time).seconds > 0)
+ {
+ popmessage("Unable to %s due to pending anonymous timers. See error.log for details.", opname);
+ goto cancel;
+ }
+ return;
+ }
+
+ // open the file
+ mame_file *file;
+ filerr = mame_fopen(m_saveload_searchpath, m_saveload_pending_file, openflags, &file);
+ if (filerr == FILERR_NONE)
+ {
+ astring fullname(mame_file_full_name(file));
+
+ // read/write the save state
+ state_save_error staterr = (m_saveload_schedule == SLS_LOAD) ? state_save_read_file(this, file) : state_save_write_file(this, file);
+
+ // handle the result
+ switch (staterr)
+ {
+ case STATERR_ILLEGAL_REGISTRATIONS:
+ popmessage("Error: Unable to %s state due to illegal registrations. See error.log for details.", opname);
+ break;
+
+ case STATERR_INVALID_HEADER:
+ popmessage("Error: Unable to %s state due to an invalid header. Make sure the save state is correct for this game.", opname);
+ break;
+
+ case STATERR_READ_ERROR:
+ popmessage("Error: Unable to %s state due to a read error (file is likely corrupt).", opname);
+ break;
+
+ case STATERR_WRITE_ERROR:
+ popmessage("Error: Unable to %s state due to a write error. Verify there is enough disk space.", opname);
+ break;
+
+ case STATERR_NONE:
+ if (!(m_game.flags & GAME_SUPPORTS_SAVE))
+ popmessage("State successfully %s.\nWarning: Save states are not officially supported for this game.", opnamed);
+ else
+ popmessage("State successfully %s.", opnamed);
+ break;
+
+ default:
+ popmessage("Error: Unknown error during state %s.", opnamed);
+ break;
+ }
+
+ // close and perhaps delete the file
+ mame_fclose(file);
+ if (staterr != STATERR_NONE && m_saveload_schedule == SLS_SAVE)
+ osd_rmfile(fullname);
+ }
+ else
+ popmessage("Error: Failed to open file for %s operation.", opname);
+
+ // unschedule the operation
+cancel:
+ m_saveload_pending_file.reset();
+ m_saveload_searchpath = NULL;
+ m_saveload_schedule = SLS_NONE;
+}
+
+
+//-------------------------------------------------
+// soft_reset - actually perform a soft-reset
+// of the system
+//-------------------------------------------------
+
+TIMER_CALLBACK( running_machine::static_soft_reset ) { machine->soft_reset(); }
+
+void running_machine::soft_reset()
+{
+ logerror("Soft reset\n");
+
+ // temporarily in the reset phase
+ m_current_phase = MACHINE_PHASE_RESET;
+
+ // call all registered reset callbacks
+ call_notifiers(MACHINE_NOTIFY_RESET);
+
+ // run the driver's reset callbacks
+ if (m_config.m_machine_reset != NULL)
+ (*m_config.m_machine_reset)(this);
+ if (m_config.m_sound_reset != NULL)
+ (*m_config.m_sound_reset)(this);
+ if (m_config.m_video_reset != NULL)
+ (*m_config.m_video_reset)(this);
+
+ // now we're running
+ m_current_phase = MACHINE_PHASE_RUNNING;
+
+ // allow 0-time queued callbacks to run before any CPUs execute
+ timer_execute_timers(this);
+}
+
+
+//-------------------------------------------------
+// logfile_callback - callback for logging to
+// logfile
+//-------------------------------------------------
+
+void running_machine::logfile_callback(running_machine &machine, const char *buffer)
+{
+ if (machine.m_logfile != NULL)
+ mame_fputs(machine.m_logfile, buffer);
+}
+
+
+
+/***************************************************************************
+ MEMORY REGIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// region_info - constructor
+//-------------------------------------------------
+
+region_info::region_info(running_machine &machine, const char *name, UINT32 length, UINT32 flags)
+ : m_machine(machine),
+ m_next(NULL),
+ m_name(name),
+ m_length(length),
+ m_flags(flags)
+{
+ m_base.u8 = auto_alloc_array(&machine, UINT8, length);
+}
+
+
+//-------------------------------------------------
+// ~region_info - destructor
+//-------------------------------------------------
+
+region_info::~region_info()
+{
+ auto_free(&m_machine, m_base.v);
+}
+
+
+
+//**************************************************************************
+// CALLBACK ITEMS
+//**************************************************************************
+
+//-------------------------------------------------
+// notifier_callback_item - constructor
+//-------------------------------------------------
+
+running_machine::notifier_callback_item::notifier_callback_item(notify_callback func)
+ : m_next(NULL),
+ m_func(func)
+{
+}
+
+
+//-------------------------------------------------
+// logerror_callback_item - constructor
+//-------------------------------------------------
+
+running_machine::logerror_callback_item::logerror_callback_item(logerror_callback func)
+ : m_next(NULL),
+ m_func(func)
+{
+}
+
+
+
+//**************************************************************************
+// SYSTEM TIME
+//**************************************************************************
+
+//-------------------------------------------------
+// system_time - constructor
+//-------------------------------------------------
+
+system_time::system_time()
+{
+ set(0);
+}
+
+
+//-------------------------------------------------
+// set - fills out a system_time structure
+//-------------------------------------------------
+
+void system_time::set(time_t t)
+{
+ time = t;
+ local_time.set(*localtime(&t));
+ utc_time.set(*gmtime(&t));
+}
+
+
+//-------------------------------------------------
+// get_tm_time - converts a tm struction to a
+// MAME mame_system_tm structure
+//-------------------------------------------------
+
+void system_time::full_time::set(struct tm &t)
+{
+ second = t.tm_sec;
+ minute = t.tm_min;
+ hour = t.tm_hour;
+ mday = t.tm_mday;
+ month = t.tm_mon;
+ year = t.tm_year + 1900;
+ weekday = t.tm_wday;
+ day = t.tm_yday;
+ is_dst = t.tm_isdst;
+}