diff options
Diffstat (limited to 'src/emu/machine.cpp')
-rw-r--r-- | src/emu/machine.cpp | 311 |
1 files changed, 113 insertions, 198 deletions
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index aecaf26ed15..573c1b9e095 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -6,91 +6,40 @@ 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 "natkeyboard.h" +#include "uiinput.h" + #include "ui/uimain.h" + #include "corestr.h" -#include <ctime> +#include "unzip.h" + +#include "osdepend.h" + #include <rapidjson/writer.h> #include <rapidjson/stringbuffer.h> +#include <ctime> + #if defined(__EMSCRIPTEN__) #include <emscripten.h> #endif @@ -111,36 +60,31 @@ 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_enumerator iter(root_device()); for (device_t &device : iter) @@ -180,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)"); } @@ -203,12 +150,13 @@ void running_machine::start() // initialize UI input 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); @@ -317,8 +265,8 @@ 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) + 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; @@ -328,8 +276,8 @@ int running_machine::run(bool quiet) if (options().debug() && options().debuglog()) { m_debuglogfile = std::make_unique<emu_file>(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - osd_file::error filerr = m_debuglogfile->open("debug.log"); - if (filerr != osd_file::error::NONE) + std::error_condition const filerr = m_debuglogfile->open("debug.log"); + if (filerr) throw emu_fatalerror("running_machine::run: unable to open debug.log file"); } @@ -378,7 +326,7 @@ 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) @@ -390,8 +338,6 @@ int running_machine::run(bool quiet) // handle save/load if (m_saveload_schedule != saveload_schedule::NONE) handle_saveload(); - - g_profiler.stop(); } m_manager.http()->clear(); @@ -404,29 +350,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.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; @@ -501,7 +447,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 //------------------------------------------------- @@ -649,10 +595,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; @@ -686,10 +632,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; @@ -917,6 +863,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 @@ -924,7 +871,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 } @@ -935,41 +882,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: + { + const char *const opnamed = (m_saveload_schedule == saveload_schedule::LOAD) ? "Loaded" : "Saved"; if (!(m_system.flags & MACHINE_SUPPORTS_SAVE)) - popmessage("State successfully %s.\nWarning: Save states are not officially supported for this machine.", opnamed); + 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; } @@ -977,14 +921,14 @@ 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); } } } @@ -1001,7 +945,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"); @@ -1032,16 +976,25 @@ 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; @@ -1052,29 +1005,27 @@ void running_machine::start_all_devices() 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); } @@ -1182,9 +1133,10 @@ void running_machine::nvram_load() 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 @@ -1204,9 +1156,19 @@ void running_machine::nvram_save() if (nvram.nvram_can_save()) { 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 (!file.open(nvram_filename(nvram.device()))) { - nvram.nvram_save(file); + 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(); } } @@ -1223,7 +1185,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); @@ -1334,51 +1296,6 @@ void system_time::full_time::set(struct tm &t) //************************************************************************** -// DUMMY ADDRESS SPACE -//************************************************************************** - -u8 dummy_space_device::read(offs_t offset) -{ - throw emu_fatalerror("Attempted to read from generic address space (offs %X)\n", offset); -} - -void dummy_space_device::write(offs_t offset, u8 data) -{ - 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 //************************************************************************** @@ -1390,7 +1307,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) @@ -1423,8 +1340,6 @@ void running_machine::emscripten_main_loop() { emscripten_cancel_main_loop(); } - - g_profiler.stop(); } void running_machine::emscripten_set_running_machine(running_machine *machine) |