summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/machine.c')
-rw-r--r--trunk/src/emu/machine.c1241
1 files changed, 1241 insertions, 0 deletions
diff --git a/trunk/src/emu/machine.c b/trunk/src/emu/machine.c
new file mode 100644
index 00000000000..840a17591a0
--- /dev/null
+++ b/trunk/src/emu/machine.c
@@ -0,0 +1,1241 @@
+/***************************************************************************
+
+ 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 "crsshair.h"
+#include "validity.h"
+#include "unzip.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 machine_config &_config, osd_interface &osd, bool exit_to_game_select)
+ : firstcpu(NULL),
+ primary_screen(NULL),
+ palette(NULL),
+ pens(NULL),
+ colortable(NULL),
+ shadow_table(NULL),
+ priority_bitmap(NULL),
+ debug_flags(0),
+ memory_data(NULL),
+ palette_data(NULL),
+ tilemap_data(NULL),
+ romload_data(NULL),
+ input_data(NULL),
+ input_port_data(NULL),
+ ui_input_data(NULL),
+ debugcpu_data(NULL),
+ generic_machine_data(NULL),
+ generic_video_data(NULL),
+ generic_audio_data(NULL),
+
+ m_config(_config),
+ m_system(_config.gamedrv()),
+ m_osd(osd),
+ m_regionlist(m_respool),
+ m_save(*this),
+ m_scheduler(*this),
+ m_cheat(NULL),
+ m_render(NULL),
+ m_input(NULL),
+ m_sound(NULL),
+ m_video(NULL),
+ m_debug_view(NULL),
+ m_driver_device(NULL),
+ 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_rand_seed(0x9d14abd7),
+ m_ui_active(false),
+ m_basename(_config.gamedrv().name),
+ m_sample_rate(_config.options().sample_rate()),
+ m_logfile(NULL),
+ m_saveload_schedule(SLS_NONE),
+ m_saveload_schedule_time(attotime::zero),
+ m_saveload_searchpath(NULL),
+ m_logerror_list(m_respool)
+{
+ memset(gfx, 0, sizeof(gfx));
+ memset(&generic, 0, sizeof(generic));
+ memset(&m_base_time, 0, sizeof(m_base_time));
+
+ // set the machine on all devices
+ const_cast<device_list &>(devicelist()).set_machine_all(*this);
+
+ // find the driver device config and tell it which game
+ m_driver_device = device<driver_device>("root");
+ if (m_driver_device == NULL)
+ throw emu_fatalerror("Machine configuration missing driver_device");
+
+ // find devices
+ primary_screen = downcast<screen_device *>(devicelist().first(SCREEN));
+ for (device_t *device = devicelist().first(); device != NULL; device = device->next())
+ if (dynamic_cast<cpu_device *>(device) != NULL)
+ {
+ firstcpu = downcast<cpu_device *>(device);
+ break;
+ }
+
+ // fetch core options
+ if (options().debug())
+ debug_flags = (DEBUG_FLAG_ENABLED | DEBUG_FLAG_CALL_HOOK) | (options().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->pc(), cpu->space(AS_PROGRAM)->logaddrchars()));
+ }
+ 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
+ config_init(*this);
+ m_input = auto_alloc(*this, input_manager(*this));
+ output_init(*this);
+ palette_init(*this);
+ m_render = auto_alloc(*this, render_manager(*this));
+ generic_machine_init(*this);
+ generic_sound_init(*this);
+
+ // allocate a soft_reset timer
+ m_soft_reset_timer = m_scheduler.timer_alloc(timer_expired_delegate(FUNC(running_machine::soft_reset), this));
+
+ // init the osd layer
+ m_osd.init(*this);
+
+ // create the video manager
+ m_video = auto_alloc(*this, video_manager(*this));
+ ui_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);
+ if (newbase != 0)
+ m_base_time = newbase;
+
+ // intialize UI input
+ ui_input_init(*this);
+
+ // initialize the streams engine before the sound devices start
+ m_sound = auto_alloc(*this, sound_manager(*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);
+
+ // must happen after memory_init because this relies on generic.spriteram
+ generic_video_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);
+ tilemap_init(*this);
+ crosshair_init(*this);
+
+ // initialize the debugger
+ if ((debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ debugger_init(*this);
+
+ // 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);
+
+ // start up the devices
+ const_cast<device_list &>(devicelist()).start_all();
+
+ // if we're coming in with a savegame request, process it now
+ const char *savegame = options().state();
+ if (savegame[0] != 0)
+ schedule_load(savegame);
+
+ // if we're in autosave mode, schedule a load
+ else if (options().autosave() && (m_system.flags & GAME_SUPPORTS_SAVE) != 0)
+ schedule_load("auto");
+
+ // set up the cheat engine
+ m_cheat = auto_alloc(*this, cheat_manager(*this));
+
+ // disallow save state registrations starting here
+ m_save.allow_registration(false);
+}
+
+
+//-------------------------------------------------
+// add_dynamic_device - dynamically add a device
+//-------------------------------------------------
+
+device_t &running_machine::add_dynamic_device(device_t &owner, device_type type, const char *tag, UINT32 clock)
+{
+ // allocate and append this device
+ astring fulltag;
+ owner.subtag(fulltag, tag);
+ device_t &device = const_cast<device_list &>(devicelist()).append(fulltag, *type(m_config, fulltag, &owner, clock));
+
+ // append any machine config additions from new devices
+ for (device_t *curdevice = devicelist().first(); curdevice != NULL; curdevice = curdevice->next())
+ if (!curdevice->configured())
+ {
+ machine_config_constructor machconfig = curdevice->machine_config_additions();
+ if (machconfig != NULL)
+ (*machconfig)(const_cast<machine_config &>(m_config), curdevice);
+ }
+
+ // notify any new devices that their configurations are complete
+ for (device_t *curdevice = devicelist().first(); curdevice != NULL; curdevice = curdevice->next())
+ if (!curdevice->configured())
+ curdevice->config_complete();
+ return device;
+}
+
+
+//-------------------------------------------------
+// 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().log())
+ {
+ m_logfile = auto_alloc(*this, emu_file(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS));
+ file_error filerr = m_logfile->open("error.log");
+ 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().ui_mute(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)
+ {
+ g_profiler.start(PROFILER_EXTRA);
+
+ // execute CPUs if not paused
+ if (!m_paused)
+ m_scheduler.timeslice();
+
+ // otherwise, just pump video updates through
+ else
+ m_video->frame_update();
+
+ // handle save/load
+ if (m_saveload_schedule != SLS_NONE)
+ handle_saveload();
+
+ g_profiler.stop();
+ }
+
+ // and out via the exit phase
+ m_current_phase = MACHINE_PHASE_EXIT;
+
+ // save the NVRAM and configuration
+ sound().ui_mute(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);
+ zip_file_cache_clear();
+
+ // close the logfile
+ auto_free(*this, 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().system_name()[0] != 0)
+ {
+ options().set_system_name("");
+ ui_menu_force_game_select(*this, &render().ui_container());
+ }
+
+ // 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().autosave() && (m_system.flags & GAME_SUPPORTS_SAVE) && this->time() > attotime::zero)
+ 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()
+{
+ m_soft_reset_timer->adjust(attotime::zero);
+
+ // 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 = options().state_directory();
+ 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 = this->time();
+
+ // 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 = this->time();
+
+ // 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
+//-------------------------------------------------
+
+memory_region *running_machine::region_alloc(const char *name, UINT32 length, UINT8 width, endianness_t endian)
+{
+ // make sure we don't have a region of the same name; also find the end of the list
+ memory_region *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, memory_region(*this, name, length, width, endian)));
+}
+
+
+//-------------------------------------------------
+// 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, machine_notify_delegate 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)
+ m_notifier_list[event].prepend(*global_alloc(notifier_callback_item(callback)));
+
+ // all other notifiers are added to the tail, and executed in the order registered
+ else
+ m_notifier_list[event].append(*global_alloc(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!");
+ m_logerror_list.append(*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.first() != 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.first() != NULL)
+ {
+ g_profiler.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.first(); cb != NULL; cb = cb->next())
+ (*cb->m_func)(*this, giant_string_buffer);
+
+ g_profiler.stop();
+ }
+}
+
+
+//-------------------------------------------------
+// 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 + this->time().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].first(); cb != NULL; cb = cb->next())
+ cb->m_func();
+}
+
+
+//-------------------------------------------------
+// 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
+ emu_file file(m_saveload_searchpath, openflags);
+ if (!m_saveload_pending_file)
+ 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 (!m_scheduler.can_save())
+ {
+ // if more than a second has passed, we're probably screwed
+ if ((this->time() - m_saveload_schedule_time) > attotime::from_seconds(1))
+ {
+ popmessage("Unable to %s due to pending anonymous timers. See error.log for details.", opname);
+ goto cancel;
+ }
+ return;
+ }
+
+ // open the file
+ filerr = file.open(m_saveload_pending_file);
+ if (filerr == FILERR_NONE)
+ {
+ // read/write the save state
+ save_error saverr = (m_saveload_schedule == SLS_LOAD) ? m_save.read_file(file) : m_save.write_file(file);
+
+ // handle the result
+ switch (saverr)
+ {
+ 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_system.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
+ if (saverr != STATERR_NONE && m_saveload_schedule == SLS_SAVE)
+ file.remove_on_close();
+ }
+ 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
+//-------------------------------------------------
+
+void running_machine::soft_reset(void *ptr, INT32 param)
+{
+ 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);
+
+ // now we're running
+ m_current_phase = MACHINE_PHASE_RUNNING;
+}
+
+
+//-------------------------------------------------
+// logfile_callback - callback for logging to
+// logfile
+//-------------------------------------------------
+
+void running_machine::logfile_callback(running_machine &machine, const char *buffer)
+{
+ if (machine.m_logfile != NULL)
+ machine.m_logfile->puts(buffer);
+}
+
+
+
+/***************************************************************************
+ MEMORY REGIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// memory_region - constructor
+//-------------------------------------------------
+
+memory_region::memory_region(running_machine &machine, const char *name, UINT32 length, UINT8 width, endianness_t endian)
+ : m_machine(machine),
+ m_next(NULL),
+ m_name(name),
+ m_length(length),
+ m_width(width),
+ m_endianness(endian)
+{
+ assert(width == 1 || width == 2 || width == 4 || width == 8);
+ m_base.u8 = auto_alloc_array(machine, UINT8, length);
+}
+
+
+//-------------------------------------------------
+// ~memory_region - destructor
+//-------------------------------------------------
+
+memory_region::~memory_region()
+{
+ auto_free(machine(), m_base.v);
+}
+
+
+
+//**************************************************************************
+// CALLBACK ITEMS
+//**************************************************************************
+
+//-------------------------------------------------
+// notifier_callback_item - constructor
+//-------------------------------------------------
+
+running_machine::notifier_callback_item::notifier_callback_item(machine_notify_delegate 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)
+{
+}
+
+
+
+//**************************************************************************
+// DRIVER DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// driver_device - constructor
+//-------------------------------------------------
+
+driver_device::driver_device(const machine_config &mconfig, device_type type, const char *tag)
+ : device_t(mconfig, type, "Driver Device", tag, NULL, 0),
+ m_system(NULL),
+ m_palette_init(NULL)
+{
+ memset(m_callbacks, 0, sizeof(m_callbacks));
+}
+
+
+//-------------------------------------------------
+// driver_device - destructor
+//-------------------------------------------------
+
+driver_device::~driver_device()
+{
+}
+
+
+//-------------------------------------------------
+// static_set_game - set the game in the device
+// configuration
+//-------------------------------------------------
+
+void driver_device::static_set_game(device_t &device, const game_driver &game)
+{
+ driver_device &driver = downcast<driver_device &>(device);
+
+ // set the system
+ driver.m_system = &game;
+
+ // set the short name to the game's name
+ driver.m_shortname = game.name;
+
+ // and set the search path to include all parents
+ driver.m_searchpath = game.name;
+ for (int parent = driver_list::clone(game); parent != -1; parent = driver_list::clone(parent))
+ driver.m_searchpath.cat(";").cat(driver_list::driver(parent).name);
+}
+
+
+//-------------------------------------------------
+// static_set_machine_start - set the legacy
+// machine start callback in the device
+// configuration
+//-------------------------------------------------
+
+void driver_device::static_set_callback(device_t &device, callback_type type, legacy_callback_func callback)
+{
+ downcast<driver_device &>(device).m_callbacks[type] = callback;
+}
+
+
+//-------------------------------------------------
+// static_set_palette_init - set the legacy
+// palette init callback in the device
+// configuration
+//-------------------------------------------------
+
+void driver_device::static_set_palette_init(device_t &device, palette_init_func callback)
+{
+ downcast<driver_device &>(device).m_palette_init = callback;
+}
+
+
+//-------------------------------------------------
+// driver_start - default implementation which
+// does nothing
+//-------------------------------------------------
+
+void driver_device::driver_start()
+{
+}
+
+
+//-------------------------------------------------
+// machine_start - default implementation which
+// calls to the legacy machine_start function
+//-------------------------------------------------
+
+void driver_device::machine_start()
+{
+ if (m_callbacks[CB_MACHINE_START] != NULL)
+ (*m_callbacks[CB_MACHINE_START])(machine());
+}
+
+
+//-------------------------------------------------
+// sound_start - default implementation which
+// calls to the legacy sound_start function
+//-------------------------------------------------
+
+void driver_device::sound_start()
+{
+ if (m_callbacks[CB_SOUND_START] != NULL)
+ (*m_callbacks[CB_SOUND_START])(machine());
+}
+
+
+//-------------------------------------------------
+// video_start - default implementation which
+// calls to the legacy video_start function
+//-------------------------------------------------
+
+void driver_device::video_start()
+{
+ if (m_callbacks[CB_VIDEO_START] != NULL)
+ (*m_callbacks[CB_VIDEO_START])(machine());
+}
+
+
+//-------------------------------------------------
+// driver_reset - default implementation which
+// does nothing
+//-------------------------------------------------
+
+void driver_device::driver_reset()
+{
+}
+
+
+//-------------------------------------------------
+// machine_reset - default implementation which
+// calls to the legacy machine_reset function
+//-------------------------------------------------
+
+void driver_device::machine_reset()
+{
+ if (m_callbacks[CB_MACHINE_RESET] != NULL)
+ (*m_callbacks[CB_MACHINE_RESET])(machine());
+}
+
+
+//-------------------------------------------------
+// sound_reset - default implementation which
+// calls to the legacy sound_reset function
+//-------------------------------------------------
+
+void driver_device::sound_reset()
+{
+ if (m_callbacks[CB_SOUND_RESET] != NULL)
+ (*m_callbacks[CB_SOUND_RESET])(machine());
+}
+
+
+//-------------------------------------------------
+// video_reset - default implementation which
+// calls to the legacy video_reset function
+//-------------------------------------------------
+
+void driver_device::video_reset()
+{
+ if (m_callbacks[CB_VIDEO_RESET] != NULL)
+ (*m_callbacks[CB_VIDEO_RESET])(machine());
+}
+
+
+//-------------------------------------------------
+// video_update - default implementation which
+// calls to the legacy video_update function
+//-------------------------------------------------
+
+bool driver_device::screen_update(screen_device &screen, bitmap_t &bitmap, const rectangle &cliprect)
+{
+ return 0;
+}
+
+
+//-------------------------------------------------
+// video_eof - default implementation which
+// calls to the legacy video_eof function
+//-------------------------------------------------
+
+void driver_device::screen_eof()
+{
+}
+
+
+//-------------------------------------------------
+// device_rom_region - return a pointer to the
+// game's ROMs
+//-------------------------------------------------
+
+const rom_entry *driver_device::device_rom_region() const
+{
+ return m_system->rom;
+}
+
+
+//-------------------------------------------------
+// device_input_ports - return a pointer to the
+// game's input ports
+//-------------------------------------------------
+
+ioport_constructor driver_device::device_input_ports() const
+{
+ return m_system->ipt;
+}
+
+
+//-------------------------------------------------
+// device_start - device override which calls
+// the various helpers
+//-------------------------------------------------
+
+void driver_device::device_start()
+{
+ // reschedule ourselves to be last
+ if (next() != NULL)
+ throw device_missing_dependencies();
+
+ // call the game-specific init
+ if (m_system->driver_init != NULL)
+ (*m_system->driver_init)(machine());
+
+ // finish image devices init process
+ image_postdevice_init(machine());
+
+ // call palette_init if present
+ if (m_palette_init != NULL)
+ (*m_palette_init)(machine(), machine().region("proms")->base());
+
+ // start the various pieces
+ driver_start();
+ machine_start();
+ sound_start();
+ video_start();
+}
+
+
+//-------------------------------------------------
+// device_reset - device override which calls
+// the various helpers
+//-------------------------------------------------
+
+void driver_device::device_reset()
+{
+ // reset each piece
+ driver_reset();
+ machine_reset();
+ sound_reset();
+ video_reset();
+}
+
+
+
+//**************************************************************************
+// 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;
+}