1 // license:BSD-3-Clause 2 // copyright-holders:Aaron Giles 3 /*************************************************************************** 4 5 machine.h 6 7 Controls execution of the core MAME system. 8 9 ***************************************************************************/ 10 11 #pragma once 12 13 #ifndef __EMU_H__ 14 #error Dont include this file directly; include emu.h instead. 15 #endif 16 17 #ifndef MAME_EMU_MACHINE_H 18 #define MAME_EMU_MACHINE_H 19 20 #include <functional> 21 22 #include <ctime> 23 24 //************************************************************************** 25 // CONSTANTS 26 //************************************************************************** 27 28 // machine phases 29 enum class machine_phase 30 { 31 PREINIT, 32 INIT, 33 RESET, 34 RUNNING, 35 EXIT 36 }; 37 38 39 // notification callback types 40 enum machine_notification 41 { 42 MACHINE_NOTIFY_FRAME, 43 MACHINE_NOTIFY_RESET, 44 MACHINE_NOTIFY_PAUSE, 45 MACHINE_NOTIFY_RESUME, 46 MACHINE_NOTIFY_EXIT, 47 MACHINE_NOTIFY_COUNT 48 }; 49 50 51 // debug flags 52 constexpr int DEBUG_FLAG_ENABLED = 0x00000001; // debugging is enabled 53 constexpr int DEBUG_FLAG_CALL_HOOK = 0x00000002; // CPU cores must call instruction hook 54 constexpr int DEBUG_FLAG_WPR_PROGRAM = 0x00000010; // watchpoints are enabled for PROGRAM memory reads 55 constexpr int DEBUG_FLAG_WPR_DATA = 0x00000020; // watchpoints are enabled for DATA memory reads 56 constexpr int DEBUG_FLAG_WPR_IO = 0x00000040; // watchpoints are enabled for IO memory reads 57 constexpr int DEBUG_FLAG_WPW_PROGRAM = 0x00000100; // watchpoints are enabled for PROGRAM memory writes 58 constexpr int DEBUG_FLAG_WPW_DATA = 0x00000200; // watchpoints are enabled for DATA memory writes 59 constexpr int DEBUG_FLAG_WPW_IO = 0x00000400; // watchpoints are enabled for IO memory writes 60 constexpr int DEBUG_FLAG_OSD_ENABLED = 0x00001000; // The OSD debugger is enabled 61 62 63 64 //************************************************************************** 65 // MACROS 66 //************************************************************************** 67 68 // global allocation helpers 69 #define auto_alloc(m, t) pool_alloc(static_cast<running_machine &>(m).respool(), t) 70 #define auto_alloc_clear(m, t) pool_alloc_clear(static_cast<running_machine &>(m).respool(), t) 71 #define auto_alloc_array(m, t, c) pool_alloc_array(static_cast<running_machine &>(m).respool(), t, c) 72 #define auto_alloc_array_clear(m, t, c) pool_alloc_array_clear(static_cast<running_machine &>(m).respool(), t, c) 73 #define auto_free(m, v) pool_free(static_cast<running_machine &>(m).respool(), v) 74 75 76 //************************************************************************** 77 // TYPE DEFINITIONS 78 //************************************************************************** 79 80 // ======================> system_time 81 82 // system time description, both local and UTC 83 class system_time 84 { 85 public: 86 system_time(); 87 explicit system_time(time_t t); 88 void set(time_t t); 89 90 struct full_time 91 { 92 void set(struct tm &t); 93 94 u8 second; // seconds (0-59) 95 u8 minute; // minutes (0-59) 96 u8 hour; // hours (0-23) 97 u8 mday; // day of month (1-31) 98 u8 month; // month (0-11) 99 s32 year; // year (1=1 AD) 100 u8 weekday; // day of week (0-6) 101 u16 day; // day of year (0-365) 102 u8 is_dst; // is this daylight savings? 103 }; 104 105 s64 time; // number of seconds elapsed since midnight, January 1 1970 UTC 106 full_time local_time; // local time 107 full_time utc_time; // UTC coordinated time 108 }; 109 110 111 112 // ======================> dummy_space_device 113 114 // a dummy address space for passing to handlers outside of the memory system 115 116 class dummy_space_device : public device_t, 117 public device_memory_interface 118 { 119 public: 120 dummy_space_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); 121 122 u8 read(offs_t offset); 123 void write(offs_t offset, u8 data); 124 125 void dummy(address_map &map); 126 protected: 127 // device-level overrides 128 virtual void device_start() override; 129 130 // device_memory_interface overrides 131 virtual space_config_vector memory_space_config() const override; 132 133 private: 134 const address_space_config m_space_config; 135 }; 136 137 138 139 // ======================> running_machine 140 141 typedef delegate<void ()> machine_notify_delegate; 142 143 // description of the currently-running machine 144 class running_machine 145 { 146 DISABLE_COPYING(running_machine); 147 148 class side_effects_disabler; 149 150 friend class sound_manager; 151 friend class memory_manager; 152 153 typedef std::function<void (const char*)> logerror_callback; 154 155 // must be at top of member variables 156 resource_pool m_respool; // pool of resources for this machine 157 158 public: 159 // construction/destruction 160 running_machine(const machine_config &config, machine_manager &manager); 161 ~running_machine(); 162 163 // getters config()164 const machine_config &config() const { return m_config; } root_device()165 device_t &root_device() const { return m_config.root_device(); } system()166 const game_driver &system() const { return m_system; } 167 osd_interface &osd() const; manager()168 machine_manager &manager() const { return m_manager; } respool()169 resource_pool &respool() { return m_respool; } scheduler()170 device_scheduler &scheduler() { return m_scheduler; } save()171 save_manager &save() { return m_save; } memory()172 memory_manager &memory() { return m_memory; } ioport()173 ioport_manager &ioport() { return m_ioport; } parameters()174 parameters_manager ¶meters() { return m_parameters; } render()175 render_manager &render() const { assert(m_render != nullptr); return *m_render; } input()176 input_manager &input() const { assert(m_input != nullptr); return *m_input; } sound()177 sound_manager &sound() const { assert(m_sound != nullptr); return *m_sound; } video()178 video_manager &video() const { assert(m_video != nullptr); return *m_video; } network()179 network_manager &network() const { assert(m_network != nullptr); return *m_network; } bookkeeping()180 bookkeeping_manager &bookkeeping() const { assert(m_network != nullptr); return *m_bookkeeping; } configuration()181 configuration_manager &configuration() const { assert(m_configuration != nullptr); return *m_configuration; } output()182 output_manager &output() const { assert(m_output != nullptr); return *m_output; } ui()183 ui_manager &ui() const { assert(m_ui != nullptr); return *m_ui; } ui_input()184 ui_input_manager &ui_input() const { assert(m_ui_input != nullptr); return *m_ui_input; } crosshair()185 crosshair_manager &crosshair() const { assert(m_crosshair != nullptr); return *m_crosshair; } image()186 image_manager &image() const { assert(m_image != nullptr); return *m_image; } rom_load()187 rom_load_manager &rom_load() const { assert(m_rom_load != nullptr); return *m_rom_load; } tilemap()188 tilemap_manager &tilemap() const { assert(m_tilemap != nullptr); return *m_tilemap; } debug_view()189 debug_view_manager &debug_view() const { assert(m_debug_view != nullptr); return *m_debug_view; } debugger()190 debugger_manager &debugger() const { assert(m_debugger != nullptr); return *m_debugger; } driver_data()191 template <class DriverClass> DriverClass *driver_data() const { return &downcast<DriverClass &>(root_device()); } phase()192 machine_phase phase() const { return m_current_phase; } paused()193 bool paused() const { return m_paused || (m_current_phase != machine_phase::RUNNING); } exit_pending()194 bool exit_pending() const { return m_exit_pending; } hard_reset_pending()195 bool hard_reset_pending() const { return m_hard_reset_pending; } ui_active()196 bool ui_active() const { return m_ui_active; } basename()197 const std::string &basename() const { return m_basename; } sample_rate()198 int sample_rate() const { return m_sample_rate; } save_or_load_pending()199 bool save_or_load_pending() const { return !m_saveload_pending_file.empty(); } 200 201 // RAII-based side effect disable 202 // NOP-ed when passed false, to make it more easily conditional 203 side_effects_disabler disable_side_effects(bool disable_se = true) { return side_effects_disabler(this, disable_se); } side_effects_disabled()204 bool side_effects_disabled() const { return m_side_effects_disabled != 0; } 205 206 // additional helpers options()207 emu_options &options() const { return m_config.options(); } time()208 attotime time() const noexcept { return m_scheduler.time(); } scheduled_event_pending()209 bool scheduled_event_pending() const { return m_exit_pending || m_hard_reset_pending; } allow_logging()210 bool allow_logging() const { return !m_logerror_list.empty(); } 211 212 // fetch items by name device(const char * tag)213 [[deprecated("absolute tag lookup; use subdevice or finder instead")]] inline device_t *device(const char *tag) const { return root_device().subdevice(tag); } device(const char * tag)214 template <class DeviceClass> [[deprecated("absolute tag lookup; use subdevice or finder instead")]] inline DeviceClass *device(const char *tag) { return downcast<DeviceClass *>(device(tag)); } 215 216 // immediate operations 217 int run(bool quiet); 218 void pause(); 219 void resume(); 220 void toggle_pause(); 221 void add_notifier(machine_notification event, machine_notify_delegate callback, bool first = false); 222 void call_notifiers(machine_notification which); 223 void add_logerror_callback(logerror_callback callback); set_ui_active(bool active)224 void set_ui_active(bool active) { m_ui_active = active; } 225 void debug_break(); 226 void export_http_api(); 227 228 // TODO: Do saves and loads still require scheduling? 229 void immediate_save(const char *filename); 230 void immediate_load(const char *filename); 231 232 // rewind operations 233 bool rewind_capture(); 234 bool rewind_step(); 235 void rewind_invalidate(); 236 237 // scheduled operations 238 void schedule_exit(); 239 void schedule_hard_reset(); 240 void schedule_soft_reset(); 241 void schedule_save(std::string &&filename); 242 void schedule_load(std::string &&filename); 243 244 // date & time 245 void base_datetime(system_time &systime); 246 void current_datetime(system_time &systime); 247 void set_rtc_datetime(const system_time &systime); 248 249 // misc dummy_space()250 address_space &dummy_space() const { return m_dummy_space.space(AS_PROGRAM); } popmessage()251 void popmessage() const { popmessage(static_cast<char const *>(nullptr)); } 252 template <typename Format, typename... Params> void popmessage(Format &&fmt, Params &&... args) const; 253 template <typename Format, typename... Params> void logerror(Format &&fmt, Params &&... args) const; 254 void strlog(const char *str) const; 255 u32 rand(); 256 std::string describe_context() const; 257 std::string compose_saveload_filename(std::string &&base_filename, const char **searchpath = nullptr); 258 std::string get_statename(const char *statename_opt) const; 259 260 private: 261 // side effect disable counter 262 u32 m_side_effects_disabled; 263 264 public: 265 // debugger-related information 266 u32 debug_flags; // the current debug flags debug_enabled()267 bool debug_enabled() { return (debug_flags & DEBUG_FLAG_ENABLED) != 0; } 268 269 // used by debug_console to take ownership of the debug.log file steal_debuglogfile()270 std::unique_ptr<emu_file> steal_debuglogfile() { return std::move(m_debuglogfile); } 271 272 private: 273 class side_effects_disabler { 274 running_machine *m_machine; 275 bool m_disable_se; 276 277 public: side_effects_disabler(running_machine * m,bool disable_se)278 side_effects_disabler(running_machine *m, bool disable_se) : m_machine(m), m_disable_se(disable_se) { 279 if(m_disable_se) 280 m_machine->disable_side_effects_count(); 281 } 282 ~side_effects_disabler()283 ~side_effects_disabler() { 284 if(m_disable_se) 285 m_machine->enable_side_effects_count(); 286 } 287 288 side_effects_disabler(const side_effects_disabler &) = delete; 289 side_effects_disabler(side_effects_disabler &&) = default; 290 }; 291 disable_side_effects_count()292 void disable_side_effects_count() { m_side_effects_disabled++; } enable_side_effects_count()293 void enable_side_effects_count() { m_side_effects_disabled--; } 294 295 // internal helpers valueis_null296 template <typename T> struct is_null { template <typename U> static bool value(U &&x) { return false; } }; 297 template <typename T> struct is_null<T *> { template <typename U> static bool value(U &&x) { return !x; } }; 298 void start(); 299 void set_saveload_filename(std::string &&filename); 300 void handle_saveload(); 301 void soft_reset(void *ptr = nullptr, s32 param = 0); 302 std::string nvram_filename(device_t &device) const; 303 void nvram_load(); 304 void nvram_save(); 305 void popup_clear() const; 306 void popup_message(util::format_argument_pack<std::ostream> const &args) const; 307 308 // internal callbacks 309 void logfile_callback(const char *buffer); 310 311 // internal device helpers 312 void start_all_devices(); 313 void reset_all_devices(); 314 void stop_all_devices(); 315 void presave_all_devices(); 316 void postload_all_devices(); 317 318 // internal state 319 const machine_config & m_config; // reference to the constructed machine_config 320 const game_driver & m_system; // reference to the definition of the game machine 321 machine_manager & m_manager; // reference to machine manager system 322 // managers 323 std::unique_ptr<render_manager> m_render; // internal data from render.cpp 324 std::unique_ptr<input_manager> m_input; // internal data from input.cpp 325 std::unique_ptr<sound_manager> m_sound; // internal data from sound.cpp 326 std::unique_ptr<video_manager> m_video; // internal data from video.cpp 327 ui_manager *m_ui; // internal data from ui.cpp 328 std::unique_ptr<ui_input_manager> m_ui_input; // internal data from uiinput.cpp 329 std::unique_ptr<tilemap_manager> m_tilemap; // internal data from tilemap.cpp 330 std::unique_ptr<debug_view_manager> m_debug_view; // internal data from debugvw.cpp 331 std::unique_ptr<network_manager> m_network; // internal data from network.cpp 332 std::unique_ptr<bookkeeping_manager> m_bookkeeping;// internal data from bookkeeping.cpp 333 std::unique_ptr<configuration_manager> m_configuration; // internal data from config.cpp 334 std::unique_ptr<output_manager> m_output; // internal data from output.cpp 335 std::unique_ptr<crosshair_manager> m_crosshair; // internal data from crsshair.cpp 336 std::unique_ptr<image_manager> m_image; // internal data from image.cpp 337 std::unique_ptr<rom_load_manager> m_rom_load; // internal data from romload.cpp 338 std::unique_ptr<debugger_manager> m_debugger; // internal data from debugger.cpp 339 340 // system state 341 machine_phase m_current_phase; // current execution phase 342 bool m_paused; // paused? 343 bool m_hard_reset_pending; // is a hard reset pending? 344 bool m_exit_pending; // is an exit pending? 345 emu_timer * m_soft_reset_timer; // timer used to schedule a soft reset 346 347 // misc state 348 u32 m_rand_seed; // current random number seed 349 bool m_ui_active; // ui active or not (useful for games / systems with keyboard inputs) 350 time_t m_base_time; // real time at initial emulation time 351 std::string m_basename; // basename used for game-related paths 352 int m_sample_rate; // the digital audio sample rate 353 std::unique_ptr<emu_file> m_logfile; // pointer to the active error.log file 354 std::unique_ptr<emu_file> m_debuglogfile; // pointer to the active debug.log file 355 356 // load/save management 357 enum class saveload_schedule 358 { 359 NONE, 360 SAVE, 361 LOAD 362 }; 363 saveload_schedule m_saveload_schedule; 364 attotime m_saveload_schedule_time; 365 std::string m_saveload_pending_file; 366 const char * m_saveload_searchpath; 367 368 // notifier callbacks 369 struct notifier_callback_item 370 { 371 // construction/destruction 372 notifier_callback_item(machine_notify_delegate func); 373 374 // state 375 machine_notify_delegate m_func; 376 }; 377 std::list<std::unique_ptr<notifier_callback_item>> m_notifier_list[MACHINE_NOTIFY_COUNT]; 378 379 // logerror callbacks 380 class logerror_callback_item 381 { 382 public: 383 // construction/destruction 384 logerror_callback_item(logerror_callback func); 385 386 // state 387 logerror_callback m_func; 388 }; 389 std::list<std::unique_ptr<logerror_callback_item>> m_logerror_list; 390 391 // embedded managers and objects 392 save_manager m_save; // save manager 393 memory_manager m_memory; // memory manager 394 ioport_manager m_ioport; // I/O port manager 395 parameters_manager m_parameters; // parameters manager 396 device_scheduler m_scheduler; // scheduler object 397 398 // string formatting buffer 399 mutable util::ovectorstream m_string_buffer; 400 401 // configuration state 402 dummy_space_device m_dummy_space; 403 404 #if defined(__EMSCRIPTEN__) 405 private: 406 static running_machine *emscripten_running_machine; 407 static void emscripten_main_loop(); 408 public: 409 static void emscripten_set_running_machine(running_machine *machine); 410 static running_machine * emscripten_get_running_machine(); 411 static ui_manager * emscripten_get_ui(); 412 static sound_manager * emscripten_get_sound(); 413 414 static void emscripten_exit(); 415 static void emscripten_hard_reset(); 416 static void emscripten_soft_reset(); 417 static void emscripten_save(const char *name); 418 static void emscripten_load(const char *name); 419 #endif 420 }; 421 422 423 424 //************************************************************************** 425 // MEMBER TEMPLATES 426 //************************************************************************** 427 428 /*------------------------------------------------- 429 popmessage - pop up a user-visible message 430 -------------------------------------------------*/ 431 432 template <typename Format, typename... Params> 433 inline void running_machine::popmessage(Format &&fmt, Params &&... args) const 434 { 435 // if the format is nullptr, it is a signal to clear the popmessage 436 // otherwise, generate the buffer and call the UI to display the message 437 if (is_null<Format>::value(fmt)) 438 popup_clear(); 439 else 440 popup_message(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...)); 441 } 442 443 444 /*------------------------------------------------- 445 logerror - log to the debugger and any other 446 OSD-defined output streams 447 -------------------------------------------------*/ 448 449 template <typename Format, typename... Params> 450 inline void running_machine::logerror(Format &&fmt, Params &&... args) const 451 { 452 // process only if there is a target 453 if (allow_logging()) 454 { 455 g_profiler.start(PROFILER_LOGERROR); 456 457 // dump to the buffer 458 m_string_buffer.clear(); 459 m_string_buffer.seekp(0); 460 util::stream_format(m_string_buffer, std::forward<Format>(fmt), std::forward<Params>(args)...); 461 m_string_buffer.put('\0'); 462 463 strlog(&m_string_buffer.vec()[0]); 464 465 g_profiler.stop(); 466 } 467 } 468 469 #endif /* MAME_EMU_MACHINE_H */ 470