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 &parameters() { 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