diff options
Diffstat (limited to 'src/emu/machine.cpp')
-rw-r--r-- | src/emu/machine.cpp | 451 |
1 files changed, 203 insertions, 248 deletions
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index 68bf7dc74d9..a77140dba16 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -2,93 +2,44 @@ // copyright-holders:Aaron Giles /*************************************************************************** - machine.c + machine.cpp Controls execution of the core MAME system. -**************************************************************************** - - 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 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 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 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 "render.h" -#include "uiinput.h" #include "crsshair.h" -#include "unzip.h" -#include "debug/debugvw.h" #include "debug/debugcpu.h" +#include "debug/debugvw.h" +#include "debugger.h" #include "dirtc.h" +#include "emuopts.h" +#include "fileio.h" +#include "http.h" #include "image.h" +#include "main.h" +#include "natkeyboard.h" #include "network.h" +#include "render.h" #include "romload.h" #include "tilemap.h" +#include "uiinput.h" + #include "ui/uimain.h" -#include <time.h> + +#include "corestr.h" +#include "unzip.h" + +#include "osdepend.h" + #include <rapidjson/writer.h> #include <rapidjson/stringbuffer.h> +#include <ctime> + #if defined(__EMSCRIPTEN__) #include <emscripten.h> #endif @@ -109,38 +60,33 @@ osd_interface &running_machine::osd() const //------------------------------------------------- running_machine::running_machine(const machine_config &_config, machine_manager &manager) - : m_side_effects_disabled(0), - debug_flags(0), - m_config(_config), - m_system(_config.gamedrv()), - m_manager(manager), - m_current_phase(machine_phase::PREINIT), - m_paused(false), - m_hard_reset_pending(false), - m_exit_pending(false), - m_soft_reset_timer(nullptr), - m_rand_seed(0x9d14abd7), - m_ui_active(_config.options().ui_active()), - m_basename(_config.gamedrv().name), - m_sample_rate(_config.options().sample_rate()), - m_saveload_schedule(saveload_schedule::NONE), - m_saveload_schedule_time(attotime::zero), - m_saveload_searchpath(nullptr), - - m_save(*this), - m_memory(*this), - m_ioport(*this), - m_parameters(*this), - m_scheduler(*this), - m_dummy_space(_config, "dummy_space", &root_device(), 0) + : m_side_effects_disabled(0) + , debug_flags(0) + , m_config(_config) + , m_system(_config.gamedrv()) + , m_manager(manager) + , m_current_phase(machine_phase::PREINIT) + , m_paused(false) + , m_hard_reset_pending(false) + , m_exit_pending(false) + , m_soft_reset_timer(nullptr) + , m_rand_seed(0x9d14abd7) + , m_basename(_config.gamedrv().name) + , m_sample_rate(_config.options().sample_rate()) + , m_saveload_schedule(saveload_schedule::NONE) + , m_saveload_schedule_time(attotime::zero) + , m_saveload_searchpath(nullptr) + + , m_save(*this) + , m_memory(*this) + , m_ioport(*this) + , m_parameters(*this) + , m_scheduler(*this) { memset(&m_base_time, 0, sizeof(m_base_time)); - m_dummy_space.set_machine(*this); - m_dummy_space.config_complete(); - // set the machine on all devices - device_iterator iter(root_device()); + device_enumerator iter(root_device()); for (device_t &device : iter) device.set_machine(*this); @@ -178,7 +124,10 @@ std::string running_machine::describe_context() const } } - return std::string("(no context)"); + if (m_current_phase == machine_phase::RESET) + return std::string("(reset phase)"); + else + return std::string("(no context)"); } @@ -199,14 +148,15 @@ void running_machine::start() m_soft_reset_timer = m_scheduler.timer_alloc(timer_expired_delegate(FUNC(running_machine::soft_reset), this)); // initialize UI input - m_ui_input = make_unique_clear<ui_input_manager>(*this); + m_ui_input = std::make_unique<ui_input_manager>(*this); - // init the osd layer + // init the OSD layer m_manager.osd().init(*this); - // create the video manager + // create the video manager and UI manager m_video = std::make_unique<video_manager>(*this); m_ui = manager().create_ui(*this); + m_ui->set_startup_text("Initializing...", true); // initialize the base time (needed for doing record/playback) ::time(&m_base_time); @@ -218,11 +168,14 @@ void running_machine::start() if (newbase != 0) m_base_time = newbase; + // initialize natural keyboard support after ports have been initialized + m_natkeyboard = std::make_unique<natural_keyboard>(*this); + // initialize the streams engine before the sound devices start m_sound = std::make_unique<sound_manager>(*this); // resolve objects that can be used by memory maps - for (device_t &device : device_iterator(root_device())) + for (device_t &device : device_enumerator(root_device())) device.resolve_pre_map(); // configure the address spaces, load ROMs (which needs @@ -230,7 +183,7 @@ void running_machine::start() // needs rom bases), and finally initialize CPUs (which needs // complete address spaces). These operations must proceed in this // order - m_rom_load = make_unique_clear<rom_load_manager>(*this); + m_rom_load = std::make_unique<rom_load_manager>(*this); m_memory.initialize(); // save the random seed or save states might be broken in drivers that use the rand() method @@ -239,7 +192,7 @@ void running_machine::start() // initialize image devices m_image = std::make_unique<image_manager>(*this); m_tilemap = std::make_unique<tilemap_manager>(*this); - m_crosshair = make_unique_clear<crosshair_manager>(*this); + m_crosshair = std::make_unique<crosshair_manager>(*this); m_network = std::make_unique<network_manager>(*this); // initialize the debugger @@ -249,30 +202,60 @@ void running_machine::start() m_debugger = std::make_unique<debugger_manager>(*this); } - m_render->resolve_tags(); - manager().create_custom(*this); // resolve objects that are created by memory maps - for (device_t &device : device_iterator(root_device())) + for (device_t &device : device_enumerator(root_device())) device.resolve_post_map(); // register callbacks for the devices, then start them add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(&running_machine::reset_all_devices, this)); add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&running_machine::stop_all_devices, this)); save().register_presave(save_prepost_delegate(FUNC(running_machine::presave_all_devices), this)); + m_sound->before_devices_init(); start_all_devices(); + m_sound->after_devices_init(); save().register_postload(save_prepost_delegate(FUNC(running_machine::postload_all_devices), this)); + + // save outputs created before start time + output().register_save(); + + m_render->resolve_tags(); + + // load cheat files manager().load_cheatfiles(*this); - // if we're coming in with a savegame request, process it now + // start recording movie if specified + const char *filename = options().mng_write(); + if (filename[0] != 0) + m_video->begin_recording(filename, movie_recording::format::MNG); + + filename = options().avi_write(); + if (filename[0] != 0 && !m_video->is_recording()) + m_video->begin_recording(filename, movie_recording::format::AVI); + const char *savegame = options().state(); if (savegame[0] != 0) + { + // if we're coming in with a savegame request, process it now schedule_load(savegame); - - // if we're in autosave mode, schedule a load - else if (options().autosave() && (m_system.flags & MACHINE_SUPPORTS_SAVE) != 0) - schedule_load("auto"); + } + else if (options().autosave()) + { + // if we're in autosave mode, schedule a load + // m_save.supported() won't be set until save state registrations are finalised + bool supported = true; + for (device_t &device : device_enumerator(root_device())) + { + if (device.type().emulation_flags() & device_t::flags::SAVE_UNSUPPORTED) + { + supported = false; + break; + } + } + if (supported) + schedule_load("auto"); + } manager().update_machine(); } @@ -298,26 +281,32 @@ int running_machine::run(bool quiet) if (options().log() && !quiet) { m_logfile = std::make_unique<emu_file>(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - osd_file::error filerr = m_logfile->open("error.log"); - if (filerr != osd_file::error::NONE) - throw emu_fatalerror("running_machine::run: unable to open log file"); + std::error_condition const filerr = m_logfile->open("error.log"); + if (filerr) + throw emu_fatalerror("running_machine::run: unable to open error.log file"); using namespace std::placeholders; add_logerror_callback(std::bind(&running_machine::logfile_callback, this, _1)); } + if (options().debug() && options().debuglog()) + { + m_debuglogfile = std::make_unique<emu_file>(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + std::error_condition const filerr = m_debuglogfile->open("debug.log"); + if (filerr) + throw emu_fatalerror("running_machine::run: unable to open debug.log file"); + } + // then finish setting up our local machine start(); + // disallow save state registrations starting here + m_save.allow_registration(false); + // load the configuration settings manager().before_load_settings(*this); m_configuration->load_settings(); - // disallow save state registrations starting here. - // Don't do it earlier, config load can create network - // devices with timers. - m_save.allow_registration(false); - // load the NVRAM nvram_load(); @@ -328,6 +317,8 @@ int running_machine::run(bool quiet) if (!quiet) sound().start_recording(); + m_hard_reset_pending = false; + // initialize ui lists // display the startup screens manager().ui_initialize(*this); @@ -341,8 +332,6 @@ int running_machine::run(bool quiet) export_http_api(); - m_hard_reset_pending = false; - #if defined(__EMSCRIPTEN__) // break out to our async javascript loop and halt emscripten_set_running_machine(this); @@ -351,20 +340,21 @@ int running_machine::run(bool quiet) // run the CPUs until a reset or exit while ((!m_hard_reset_pending && !m_exit_pending) || m_saveload_schedule != saveload_schedule::NONE) { - g_profiler.start(PROFILER_EXTRA); + auto profile = g_profiler.start(PROFILER_EXTRA); // execute CPUs if not paused if (!m_paused) m_scheduler.timeslice(); - // otherwise, just pump video updates through + // otherwise, just pump video updates and sound mapping updates through else + { m_video->frame_update(); + sound().mapping_update(); + } // handle save/load if (m_saveload_schedule != saveload_schedule::NONE) handle_saveload(); - - g_profiler.stop(); } m_manager.http()->clear(); @@ -377,29 +367,29 @@ int running_machine::run(bool quiet) nvram_save(); m_configuration->save_settings(); } - catch (emu_fatalerror &fatal) + catch (emu_fatalerror const &fatal) { - osd_printf_error("Fatal error: %s\n", fatal.string()); + osd_printf_error("Fatal error: %s\n", fatal.what()); error = EMU_ERR_FATALERROR; if (fatal.exitcode() != 0) error = fatal.exitcode(); } - catch (emu_exception &) + catch (emu_exception const &) { osd_printf_error("Caught unhandled emulator exception\n"); error = EMU_ERR_FATALERROR; } - catch (binding_type_exception &btex) + catch (binding_type_exception const &btex) { - osd_printf_error("Error performing a late bind of type %s to %s\n", btex.m_actual_type.name(), btex.m_target_type.name()); + osd_printf_error("Error performing a late bind of function expecting type %s to instance of type %s\n", btex.target_type().name(), btex.actual_type().name()); error = EMU_ERR_FATALERROR; } - catch (tag_add_exception &aex) + catch (tag_add_exception const &aex) { osd_printf_error("Tag '%s' already exists in tagged map\n", aex.tag()); error = EMU_ERR_FATALERROR; } - catch (std::exception &ex) + catch (std::exception const &ex) { osd_printf_error("Caught unhandled %s exception: %s\n", typeid(ex).name(), ex.what()); error = EMU_ERR_FATALERROR; @@ -435,7 +425,7 @@ void running_machine::schedule_exit() m_scheduler.eat_all_cycles(); // if we're autosaving on exit, schedule a save as well - if (options().autosave() && (m_system.flags & MACHINE_SUPPORTS_SAVE) && this->time() > attotime::zero) + if (options().autosave() && m_save.supported() && (this->time() > attotime::zero)) schedule_save("auto"); } @@ -474,7 +464,7 @@ void running_machine::schedule_soft_reset() //------------------------------------------------- // get_statename - allow to specify a subfolder of // the state directory for state loading/saving, -// very useful for MESS and consoles or computers +// very useful for consoles or computers // where you can have separate folders for diff // software //------------------------------------------------- @@ -499,7 +489,7 @@ std::string running_machine::get_statename(const char *option) const if (pos != -1) { // if more %d are found, revert to default and ignore them all - if (statename_str.find(statename_dev.c_str(), pos + 3) != -1) + if (statename_str.find(statename_dev, pos + 3) != -1) statename_str.assign("%g"); // else if there is a single %d, try to create the correct snapname else @@ -507,21 +497,10 @@ std::string running_machine::get_statename(const char *option) const int name_found = 0; // find length of the device name - int end1 = statename_str.find("/", pos + 3); - int end2 = statename_str.find("%", pos + 3); - int end; - - if ((end1 != -1) && (end2 != -1)) - end = std::min(end1, end2); - else if (end1 != -1) - end = end1; - else if (end2 != -1) - end = end2; - else + int end = statename_str.find_first_not_of("abcdefghijklmnopqrstuvwxyz1234567890", pos + 3); + if (end == -1) end = statename_str.length(); - if (end - pos < 3) - fatalerror("Something very wrong is going on!!!\n"); // copy the device name to an std::string std::string devname_str; @@ -529,7 +508,7 @@ std::string running_machine::get_statename(const char *option) const //printf("check template: %s\n", devname_str.c_str()); // verify that there is such a device for this system - for (device_image_interface &image : image_interface_iterator(root_device())) + for (device_image_interface &image : image_interface_enumerator(root_device())) { // get the device name std::string tempdevname(image.brief_instance_name()); @@ -543,7 +522,7 @@ std::string running_machine::get_statename(const char *option) const std::string filename(image.basename_noext()); // setup snapname and remove the %d_ - strreplace(statename_str, devname_str.c_str(), filename.c_str()); + strreplace(statename_str, devname_str, filename); statename_str.erase(pos, 3); //printf("check image: %s\n", filename.c_str()); @@ -633,10 +612,10 @@ void running_machine::schedule_save(std::string &&filename) // immediate_save - save state. //------------------------------------------------- -void running_machine::immediate_save(const char *filename) +void running_machine::immediate_save(std::string_view filename) { // specify the filename to save or load - set_saveload_filename(filename); + set_saveload_filename(std::string(filename)); // set up some parameters for handle_saveload() m_saveload_schedule = saveload_schedule::SAVE; @@ -670,10 +649,10 @@ void running_machine::schedule_load(std::string &&filename) // immediate_load - load state. //------------------------------------------------- -void running_machine::immediate_load(const char *filename) +void running_machine::immediate_load(std::string_view filename) { // specify the filename to save or load - set_saveload_filename(filename); + set_saveload_filename(std::string(filename)); // set up some parameters for handle_saveload() m_saveload_schedule = saveload_schedule::LOAD; @@ -856,7 +835,7 @@ void running_machine::current_datetime(system_time &systime) void running_machine::set_rtc_datetime(const system_time &systime) { - for (device_rtc_interface &rtc : rtc_interface_iterator(root_device())) + for (device_rtc_interface &rtc : rtc_interface_enumerator(root_device())) if (rtc.has_battery()) rtc.set_current_time(systime); } @@ -901,6 +880,7 @@ void running_machine::handle_saveload() if (!m_saveload_pending_file.empty()) { const char *const opname = (m_saveload_schedule == saveload_schedule::LOAD) ? "load" : "save"; + const char *const preposname = (m_saveload_schedule == saveload_schedule::LOAD) ? "from" : "to"; // 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 @@ -908,7 +888,7 @@ void running_machine::handle_saveload() { // 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); + popmessage("Error: Unable to %s state %s %s due to pending anonymous timers. See error.log for details.", opname, preposname, m_saveload_pending_file); else return; // return without cancelling the operation } @@ -919,41 +899,38 @@ void running_machine::handle_saveload() // open the file emu_file file(m_saveload_searchpath ? m_saveload_searchpath : "", openflags); auto const filerr = file.open(m_saveload_pending_file); - if (filerr == osd_file::error::NONE) + if (!filerr) { - const char *const opnamed = (m_saveload_schedule == saveload_schedule::LOAD) ? "loaded" : "saved"; - // read/write the save state save_error saverr = (m_saveload_schedule == saveload_schedule::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 machine.", opname); + popmessage("Error: Unable to %s state %s %s due to an invalid header. Make sure the save state is correct for this system.", opname, preposname, m_saveload_pending_file); break; case STATERR_READ_ERROR: - popmessage("Error: Unable to %s state due to a read error (file is likely corrupt).", opname); + popmessage("Error: Unable to %s state %s %s due to a read error (file is likely corrupt).", opname, preposname, m_saveload_pending_file); break; case STATERR_WRITE_ERROR: - popmessage("Error: Unable to %s state due to a write error. Verify there is enough disk space.", opname); + popmessage("Error: Unable to %s state %s %s due to a write error. Verify there is enough disk space.", opname, preposname, m_saveload_pending_file); break; case STATERR_NONE: - if (!(m_system.flags & MACHINE_SUPPORTS_SAVE)) - popmessage("State successfully %s.\nWarning: Save states are not officially supported for this machine.", opnamed); + { + const char *const opnamed = (m_saveload_schedule == saveload_schedule::LOAD) ? "Loaded" : "Saved"; + if (!m_save.supported()) + popmessage("%s state %s %s.\nWarning: Save states are not officially supported for this system.", opnamed, preposname, m_saveload_pending_file); else - popmessage("State successfully %s.", opnamed); + popmessage("%s state %s %s.", opnamed, preposname, m_saveload_pending_file); break; + } default: - popmessage("Error: Unknown error during state %s.", opnamed); + popmessage("Error: Unknown error during %s state %s %s.", opname, preposname, m_saveload_pending_file); break; } @@ -961,11 +938,15 @@ void running_machine::handle_saveload() if (saverr != STATERR_NONE && m_saveload_schedule == saveload_schedule::SAVE) file.remove_on_close(); } - else if (openflags == OPEN_FLAG_READ && filerr == osd_file::error::NOT_FOUND) + else if ((openflags == OPEN_FLAG_READ) && (std::errc::no_such_file_or_directory == filerr)) + { // attempt to load a non-existent savestate, report empty slot - popmessage("Error: No savestate file to load.", opname); + popmessage("Error: Load state file %s not found.", m_saveload_pending_file); + } else - popmessage("Error: Failed to open file for %s operation.", opname); + { + popmessage("Error: Failed to open %s for %s state operation.", m_saveload_pending_file, opname); + } } } @@ -981,7 +962,7 @@ void running_machine::handle_saveload() // of the system //------------------------------------------------- -void running_machine::soft_reset(void *ptr, s32 param) +void running_machine::soft_reset(s32 param) { logerror("Soft reset\n"); @@ -1012,49 +993,56 @@ void running_machine::logfile_callback(const char *buffer) //------------------------------------------------- +// steal_debuglogfile - relinquish ownership of +// the debug.log file +//------------------------------------------------- + +std::unique_ptr<emu_file> running_machine::steal_debuglogfile() +{ + return std::move(m_debuglogfile); +} + + +//------------------------------------------------- // start_all_devices - start any unstarted devices //------------------------------------------------- void running_machine::start_all_devices() { - m_dummy_space.start(); - // iterate through the devices int last_failed_starts = -1; - while (last_failed_starts != 0) + do { // iterate over all devices int failed_starts = 0; - for (device_t &device : device_iterator(root_device())) + for (device_t &device : device_enumerator(root_device())) if (!device.started()) { // attempt to start the device, catching any expected exceptions try { // if the device doesn't have a machine yet, set it first - if (device.m_machine == nullptr) + if (!device.m_machine) device.set_machine(*this); // now start the device osd_printf_verbose("Starting %s '%s'\n", device.name(), device.tag()); device.start(); } - - // handle missing dependencies by moving the device to the end - catch (device_missing_dependencies &) + catch (device_missing_dependencies const &) { - // if we're the end, fail + // handle missing dependencies by moving the device to the end osd_printf_verbose(" (missing dependencies; rescheduling)\n"); failed_starts++; } } - // each iteration should reduce the number of failed starts; error if - // this doesn't happen + // each iteration should reduce the number of failed starts; error if this doesn't happen if (failed_starts == last_failed_starts) throw emu_fatalerror("Circular dependency in device startup!"); last_failed_starts = failed_starts; } + while (last_failed_starts); } @@ -1082,7 +1070,7 @@ void running_machine::stop_all_devices() debugger().cpu().comment_save(); // iterate over devices and stop them - for (device_t &device : device_iterator(root_device())) + for (device_t &device : device_enumerator(root_device())) device.stop(); } @@ -1094,7 +1082,7 @@ void running_machine::stop_all_devices() void running_machine::presave_all_devices() { - for (device_t &device : device_iterator(root_device())) + for (device_t &device : device_enumerator(root_device())) device.pre_save(); } @@ -1106,7 +1094,7 @@ void running_machine::presave_all_devices() void running_machine::postload_all_devices() { - for (device_t &device : device_iterator(root_device())) + for (device_t &device : device_enumerator(root_device())) device.post_load(); } @@ -1159,12 +1147,13 @@ std::string running_machine::nvram_filename(device_t &device) const void running_machine::nvram_load() { - for (device_nvram_interface &nvram : nvram_interface_iterator(root_device())) + for (device_nvram_interface &nvram : nvram_interface_enumerator(root_device())) { emu_file file(options().nvram_directory(), OPEN_FLAG_READ); - if (file.open(nvram_filename(nvram.device())) == osd_file::error::NONE) + if (nvram.nvram_backup_enabled() && !file.open(nvram_filename(nvram.device()))) { - nvram.nvram_load(file); + if (!nvram.nvram_load(file)) + osd_printf_error("Error reading NVRAM file %s\n", file.filename()); file.close(); } else @@ -1179,13 +1168,26 @@ void running_machine::nvram_load() void running_machine::nvram_save() { - for (device_nvram_interface &nvram : nvram_interface_iterator(root_device())) + for (device_nvram_interface &nvram : nvram_interface_enumerator(root_device())) { - emu_file file(options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - if (file.open(nvram_filename(nvram.device())) == osd_file::error::NONE) + if (nvram.nvram_can_save()) { - nvram.nvram_save(file); - file.close(); + emu_file file(options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (!file.open(nvram_filename(nvram.device()))) + { + bool error = false; + + if (!nvram.nvram_save(file)) + { + error = true; + osd_printf_error("Error writing NVRAM file %s\n", file.filename()); + } + + // close and perhaps delete the file + if (error || file.size() == 0) + file.remove_on_close(); + file.close(); + } } } } @@ -1200,7 +1202,7 @@ void running_machine::popup_clear() const ui().popup_time(0, " "); } -void running_machine::popup_message(util::format_argument_pack<std::ostream> const &args) const +void running_machine::popup_message(util::format_argument_pack<char> const &args) const { std::string const temp(string_format(args)); ui().popup_time(temp.length() / 40 + 2, "%s", temp); @@ -1226,7 +1228,7 @@ running_machine::notifier_callback_item::notifier_callback_item(machine_notify_d //------------------------------------------------- running_machine::logerror_callback_item::logerror_callback_item(logerror_callback func) - : m_func(func) + : m_func(std::move(func)) { } @@ -1244,7 +1246,7 @@ void running_machine::export_http_api() writer.Key("devices"); writer.StartArray(); - device_iterator iter(this->root_device()); + device_enumerator iter(this->root_device()); for (device_t &device : iter) writer.String(device.tag()); @@ -1311,51 +1313,6 @@ void system_time::full_time::set(struct tm &t) //************************************************************************** -// DUMMY ADDRESS SPACE -//************************************************************************** - -READ8_MEMBER(dummy_space_device::read) -{ - throw emu_fatalerror("Attempted to read from generic address space (offs %X)\n", offset); -} - -WRITE8_MEMBER(dummy_space_device::write) -{ - throw emu_fatalerror("Attempted to write to generic address space (offs %X = %02X)\n", offset, data); -} - -void dummy_space_device::dummy(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(dummy_space_device::read), FUNC(dummy_space_device::write)); -} - -DEFINE_DEVICE_TYPE(DUMMY_SPACE, dummy_space_device, "dummy_space", "Dummy Space") - -dummy_space_device::dummy_space_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : - device_t(mconfig, DUMMY_SPACE, tag, owner, clock), - device_memory_interface(mconfig, *this), - m_space_config("dummy", ENDIANNESS_LITTLE, 8, 32, 0, address_map_constructor(FUNC(dummy_space_device::dummy), this)) -{ -} - -void dummy_space_device::device_start() -{ -} - -//------------------------------------------------- -// memory_space_config - return a description of -// any address spaces owned by this device -//------------------------------------------------- - -device_memory_interface::space_config_vector dummy_space_device::memory_space_config() const -{ - return space_config_vector { - std::make_pair(0, &m_space_config) - }; -} - - -//************************************************************************** // JAVASCRIPT PORT-SPECIFIC //************************************************************************** @@ -1367,7 +1324,7 @@ void running_machine::emscripten_main_loop() { running_machine *machine = emscripten_running_machine; - g_profiler.start(PROFILER_EXTRA); + auto profile = g_profiler.start(PROFILER_EXTRA); // execute CPUs if not paused if (!machine->m_paused) @@ -1400,8 +1357,6 @@ void running_machine::emscripten_main_loop() { emscripten_cancel_main_loop(); } - - g_profiler.stop(); } void running_machine::emscripten_set_running_machine(running_machine *machine) |