// license:BSD-3-Clause // copyright-holders:Aaron Giles /*************************************************************************** machine.h Controls execution of the core MAME system. ***************************************************************************/ #pragma once #ifndef __EMU_H__ #error Dont include this file directly; include emu.h instead. #endif #ifndef MAME_EMU_MACHINE_H #define MAME_EMU_MACHINE_H #include #include //************************************************************************** // CONSTANTS //************************************************************************** // machine phases enum class machine_phase { PREINIT, INIT, RESET, RUNNING, EXIT }; // notification callback types enum machine_notification { MACHINE_NOTIFY_FRAME, MACHINE_NOTIFY_RESET, MACHINE_NOTIFY_PAUSE, MACHINE_NOTIFY_RESUME, MACHINE_NOTIFY_EXIT, MACHINE_NOTIFY_COUNT }; // debug flags constexpr int DEBUG_FLAG_ENABLED = 0x00000001; // debugging is enabled constexpr int DEBUG_FLAG_CALL_HOOK = 0x00000002; // CPU cores must call instruction hook constexpr int DEBUG_FLAG_WPR_PROGRAM = 0x00000010; // watchpoints are enabled for PROGRAM memory reads constexpr int DEBUG_FLAG_WPR_DATA = 0x00000020; // watchpoints are enabled for DATA memory reads constexpr int DEBUG_FLAG_WPR_IO = 0x00000040; // watchpoints are enabled for IO memory reads constexpr int DEBUG_FLAG_WPW_PROGRAM = 0x00000100; // watchpoints are enabled for PROGRAM memory writes constexpr int DEBUG_FLAG_WPW_DATA = 0x00000200; // watchpoints are enabled for DATA memory writes constexpr int DEBUG_FLAG_WPW_IO = 0x00000400; // watchpoints are enabled for IO memory writes constexpr int DEBUG_FLAG_OSD_ENABLED = 0x00001000; // The OSD debugger is enabled //************************************************************************** // MACROS //************************************************************************** // global allocation helpers #define auto_alloc(m, t) pool_alloc(static_cast(m).respool(), t) #define auto_alloc_clear(m, t) pool_alloc_clear(static_cast(m).respool(), t) #define auto_alloc_array(m, t, c) pool_alloc_array(static_cast(m).respool(), t, c) #define auto_alloc_array_clear(m, t, c) pool_alloc_array_clear(static_cast(m).respool(), t, c) #define auto_free(m, v) pool_free(static_cast(m).respool(), v) //************************************************************************** // TYPE DEFINITIONS //************************************************************************** // ======================> system_time // system time description, both local and UTC class system_time { public: system_time(); explicit system_time(time_t t); void set(time_t t); struct full_time { void set(struct tm &t); u8 second; // seconds (0-59) u8 minute; // minutes (0-59) u8 hour; // hours (0-23) u8 mday; // day of month (1-31) u8 month; // month (0-11) s32 year; // year (1=1 AD) u8 weekday; // day of week (0-6) u16 day; // day of year (0-365) u8 is_dst; // is this daylight savings? }; s64 time; // number of seconds elapsed since midnight, January 1 1970 UTC full_time local_time; // local time full_time utc_time; // UTC coordinated time }; // ======================> dummy_space_device // a dummy address space for passing to handlers outside of the memory system class dummy_space_device : public device_t, public device_memory_interface { public: dummy_space_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); DECLARE_READ8_MEMBER(read); DECLARE_WRITE8_MEMBER(write); void dummy(address_map &map); protected: // device-level overrides virtual void device_start() override; // device_memory_interface overrides virtual space_config_vector memory_space_config() const override; private: const address_space_config m_space_config; }; // ======================> running_machine typedef delegate machine_notify_delegate; // description of the currently-running machine class running_machine { DISABLE_COPYING(running_machine); class side_effects_disabler; friend class sound_manager; friend class memory_manager; typedef std::function logerror_callback; // must be at top of member variables resource_pool m_respool; // pool of resources for this machine public: // construction/destruction running_machine(const machine_config &config, machine_manager &manager); ~running_machine(); // getters const machine_config &config() const { return m_config; } device_t &root_device() const { return m_config.root_device(); } const game_driver &system() const { return m_system; } osd_interface &osd() const; machine_manager &manager() const { return m_manager; } resource_pool &respool() { return m_respool; } device_scheduler &scheduler() { return m_scheduler; } save_manager &save() { return m_save; } memory_manager &memory() { return m_memory; } ioport_manager &ioport() { return m_ioport; } parameters_manager ¶meters() { return m_parameters; } render_manager &render() const { assert(m_render != nullptr); return *m_render; } input_manager &input() const { assert(m_input != nullptr); return *m_input; } sound_manager &sound() const { assert(m_sound != nullptr); return *m_sound; } video_manager &video() const { assert(m_video != nullptr); return *m_video; } network_manager &network() const { assert(m_network != nullptr); return *m_network; } bookkeeping_manager &bookkeeping() const { assert(m_network != nullptr); return *m_bookkeeping; } configuration_manager &configuration() const { assert(m_configuration != nullptr); return *m_configuration; } output_manager &output() const { assert(m_output != nullptr); return *m_output; } ui_manager &ui() const { assert(m_ui != nullptr); return *m_ui; } ui_input_manager &ui_input() const { assert(m_ui_input != nullptr); return *m_ui_input; } crosshair_manager &crosshair() const { assert(m_crosshair != nullptr); return *m_crosshair; } image_manager &image() const { assert(m_image != nullptr); return *m_image; } rom_load_manager &rom_load() const { assert(m_rom_load != nullptr); return *m_rom_load; } tilemap_manager &tilemap() const { assert(m_tilemap != nullptr); return *m_tilemap; } debug_view_manager &debug_view() const { assert(m_debug_view != nullptr); return *m_debug_view; } debugger_manager &debugger() const { assert(m_debugger != nullptr); return *m_debugger; } driver_device *driver_data() const { return &downcast(root_device()); } template DriverClass *driver_data() const { return &downcast(root_device()); } machine_phase phase() const { return m_current_phase; } bool paused() const { return m_paused || (m_current_phase != machine_phase::RUNNING); } bool exit_pending() const { return m_exit_pending; } bool hard_reset_pending() const { return m_hard_reset_pending; } bool ui_active() const { return m_ui_active; } const std::string &basename() const { return m_basename; } int sample_rate() const { return m_sample_rate; } bool save_or_load_pending() const { return !m_saveload_pending_file.empty(); } // RAII-based side effect disable // NOP-ed when passed false, to make it more easily conditional side_effects_disabler disable_side_effects(bool disable_se = true) { return side_effects_disabler(this, disable_se); } bool side_effects_disabled() const { return m_side_effects_disabled != 0; } // additional helpers emu_options &options() const { return m_config.options(); } attotime time() const noexcept { return m_scheduler.time(); } bool scheduled_event_pending() const { return m_exit_pending || m_hard_reset_pending; } bool allow_logging() const { return !m_logerror_list.empty(); } // fetch items by name [[deprecated("absolute tag lookup; use subdevice or finder instead")]] inline device_t *device(const char *tag) const { return root_device().subdevice(tag); } template [[deprecated("absolute tag lookup; use subdevice or finder instead")]] inline DeviceClass *device(const char *tag) { return downcast(device(tag)); } // immediate operations int run(bool quiet); void pause(); void resume(); void toggle_pause(); void add_notifier(machine_notification event, machine_notify_delegate callback, bool first = false); void call_notifiers(machine_notification which); void add_logerror_callback(logerror_callback callback); void set_ui_active(bool active) { m_ui_active = active; } void debug_break(); void export_http_api(); // TODO: Do saves and loads still require scheduling? void immediate_save(const char *filename); void immediate_load(const char *filename); // rewind operations bool rewind_capture(); bool rewind_step(); void rewind_invalidate(); // scheduled operations void schedule_exit(); void schedule_hard_reset(); void schedule_soft_reset(); void schedule_save(std::string &&filename); void schedule_load(std::string &&filename); // date & time void base_datetime(system_time &systime); void current_datetime(system_time &systime); void set_rtc_datetime(const system_time &systime); // misc address_space &dummy_space() const { return m_dummy_space.space(AS_PROGRAM); } void popmessage() const { popmessage(static_cast(nullptr)); } template void popmessage(Format &&fmt, Params &&... args) const; template void logerror(Format &&fmt, Params &&... args) const; void strlog(const char *str) const; u32 rand(); std::string describe_context() const; std::string compose_saveload_filename(std::string &&base_filename, const char **searchpath = nullptr); std::string get_statename(const char *statename_opt) const; private: // side effect disable counter u32 m_side_effects_disabled; public: // debugger-related information u32 debug_flags; // the current debug flags private: class side_effects_disabler { running_machine *m_machine; bool m_disable_se; public: side_effects_disabler(running_machine *m, bool disable_se) : m_machine(m), m_disable_se(disable_se) { if(m_disable_se) m_machine->disable_side_effects_count(); } ~side_effects_disabler() { if(m_disable_se) m_machine->enable_side_effects_count(); } side_effects_disabler(const side_effects_disabler &) = delete; side_effects_disabler(side_effects_disabler &&) = default; }; void disable_side_effects_count() { m_side_effects_disabled++; } void enable_side_effects_count() { m_side_effects_disabled--; } // internal helpers template struct is_null { template static bool value(U &&x) { return false; } }; template struct is_null { template static bool value(U &&x) { return !x; } }; void start(); void set_saveload_filename(std::string &&filename); void handle_saveload(); void soft_reset(void *ptr = nullptr, s32 param = 0); std::string nvram_filename(device_t &device) const; void nvram_load(); void nvram_save(); void popup_clear() const; void popup_message(util::format_argument_pack const &args) const; // internal callbacks void logfile_callback(const char *buffer); // internal device helpers void start_all_devices(); void reset_all_devices(); void stop_all_devices(); void presave_all_devices(); void postload_all_devices(); // internal state const machine_config & m_config; // reference to the constructed machine_config const game_driver & m_system; // reference to the definition of the game machine machine_manager & m_manager; // reference to machine manager system // managers std::unique_ptr m_render; // internal data from render.cpp std::unique_ptr m_input; // internal data from input.cpp std::unique_ptr m_sound; // internal data from sound.cpp std::unique_ptr m_video; // internal data from video.cpp ui_manager *m_ui; // internal data from ui.cpp std::unique_ptr m_ui_input; // internal data from uiinput.cpp std::unique_ptr m_tilemap; // internal data from tilemap.cpp std::unique_ptr m_debug_view; // internal data from debugvw.cpp std::unique_ptr m_network; // internal data from network.cpp std::unique_ptr m_bookkeeping;// internal data from bookkeeping.cpp std::unique_ptr m_configuration; // internal data from config.cpp std::unique_ptr m_output; // internal data from output.cpp std::unique_ptr m_crosshair; // internal data from crsshair.cpp std::unique_ptr m_image; // internal data from image.cpp std::unique_ptr m_rom_load; // internal data from romload.cpp std::unique_ptr m_debugger; // internal data from debugger.cpp // system state machine_phase m_current_phase; // current execution phase bool m_paused; // paused? bool m_hard_reset_pending; // is a hard reset pending? bool m_exit_pending; // is an exit pending? emu_timer * m_soft_reset_timer; // timer used to schedule a soft reset // misc state u32 m_rand_seed; // current random number seed bool m_ui_active; // ui active or not (useful for games / systems with keyboard inputs) time_t m_base_time; // real time at initial emulation time std::string m_basename; // basename used for game-related paths int m_sample_rate; // the digital audio sample rate std::unique_ptr m_logfile; // pointer to the active log file // load/save management enum class saveload_schedule { NONE, SAVE, LOAD }; saveload_schedule m_saveload_schedule; attotime m_saveload_schedule_time; std::string m_saveload_pending_file; const char * m_saveload_searchpath; // notifier callbacks struct notifier_callback_item { // construction/destruction notifier_callback_item(machine_notify_delegate func); // state machine_notify_delegate m_func; }; std::list> m_notifier_list[MACHINE_NOTIFY_COUNT]; // logerror callbacks class logerror_callback_item { public: // construction/destruction logerror_callback_item(logerror_callback func); // state logerror_callback m_func; }; std::list> m_logerror_list; // embedded managers and objects save_manager m_save; // save manager memory_manager m_memory; // memory manager ioport_manager m_ioport; // I/O port manager parameters_manager m_parameters; // parameters manager device_scheduler m_scheduler; // scheduler object // string formatting buffer mutable util::ovectorstream m_string_buffer; // configuration state dummy_space_device m_dummy_space; #if defined(__EMSCRIPTEN__) private: static running_machine *emscripten_running_machine; static void emscripten_main_loop(); public: static void emscripten_set_running_machine(running_machine *machine); static running_machine * emscripten_get_running_machine(); static ui_manager * emscripten_get_ui(); static sound_manager * emscripten_get_sound(); static void emscripten_exit(); static void emscripten_hard_reset(); static void emscripten_soft_reset(); static void emscripten_save(const char *name); static void emscripten_load(const char *name); #endif }; //************************************************************************** // MEMBER TEMPLATES //************************************************************************** /*------------------------------------------------- popmessage - pop up a user-visible message -------------------------------------------------*/ template inline void running_machine::popmessage(Format &&fmt, Params &&... args) const { // if the format is nullptr, it is a signal to clear the popmessage // otherwise, generate the buffer and call the UI to display the message if (is_null::value(fmt)) popup_clear(); else popup_message(util::make_format_argument_pack(std::forward(fmt), std::forward(args)...)); } /*------------------------------------------------- logerror - log to the debugger and any other OSD-defined output streams -------------------------------------------------*/ template inline void running_machine::logerror(Format &&fmt, Params &&... args) const { // process only if there is a target if (allow_logging()) { g_profiler.start(PROFILER_LOGERROR); // dump to the buffer m_string_buffer.clear(); m_string_buffer.seekp(0); util::stream_format(m_string_buffer, std::forward(fmt), std::forward(args)...); m_string_buffer.put('\0'); strlog(&m_string_buffer.vec()[0]); g_profiler.stop(); } } #endif /* MAME_EMU_MACHINE_H */