summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/debugcpu.h
blob: aa2018201ddc16db48fc727adb65e9abd6ffc474 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*********************************************************************

    debugcpu.h

    Debugger CPU/memory interface engine.

***************************************************************************/

#pragma once

#ifndef __DEBUGCPU_H__
#define __DEBUGCPU_H__

#include "express.h"

#include <set>


//**************************************************************************
//  CONSTANTS
//**************************************************************************

const UINT8 WATCHPOINT_READ             = 1;
const UINT8 WATCHPOINT_WRITE            = 2;
const UINT8 WATCHPOINT_READWRITE        = WATCHPOINT_READ | WATCHPOINT_WRITE;

const int COMMENT_VERSION               = 1;



//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

typedef int (*debug_instruction_hook_func)(device_t &device, offs_t curpc);


struct xml_data_node;


// ======================> device_debug

// [TODO] This whole thing is terrible.

class device_debug
{
public:
	// breakpoint class
	class breakpoint
	{
		friend class device_debug;

	public:
		// construction/destruction
		breakpoint(device_debug* debugInterface,
					symbol_table &symbols,
					int index,
					offs_t address,
					const char *condition = nullptr,
					const char *action = nullptr);

		// getters
		const device_debug *debugInterface() const { return m_debugInterface; }
		breakpoint *next() const { return m_next; }
		int index() const { return m_index; }
		bool enabled() const { return m_enabled; }
		offs_t address() const { return m_address; }
		const char *condition() const { return m_condition.original_string(); }
		const char *action() const { return m_action.c_str(); }

		// setters
		void setEnabled(bool value) { m_enabled = value; }

	private:
		// internals
		bool hit(offs_t pc);

		const device_debug * m_debugInterface;           // the interface we were created from
		breakpoint *         m_next;                     // next in the list
		int                  m_index;                    // user reported index
		UINT8                m_enabled;                  // enabled?
		offs_t               m_address;                  // execution address
		parsed_expression    m_condition;                // condition
		std::string          m_action;                   // action
	};

	// watchpoint class
	class watchpoint
	{
		friend class device_debug;

	public:
		// construction/destruction
		watchpoint(device_debug* debugInterface,
					symbol_table &symbols,
					int index,
					address_space &space,
					int type,
					offs_t address,
					offs_t length,
					const char *condition = nullptr,
					const char *action = nullptr);

		// getters
		const device_debug *debugInterface() const { return m_debugInterface; }
		watchpoint *next() const { return m_next; }
		address_space &space() const { return m_space; }
		int index() const { return m_index; }
		int type() const { return m_type; }
		bool enabled() const { return m_enabled; }
		offs_t address() const { return m_address; }
		offs_t length() const { return m_length; }
		const char *condition() const { return m_condition.original_string(); }
		const char *action() const { return m_action.c_str(); }

		// setters
		void setEnabled(bool value) { m_enabled = value; }

		// internals
		bool hit(int type, offs_t address, int size);

	private:
		const device_debug * m_debugInterface;           // the interface we were created from
		watchpoint *         m_next;                     // next in the list
		address_space &      m_space;                    // address space
		int                  m_index;                    // user reported index
		bool                 m_enabled;                  // enabled?
		UINT8                m_type;                     // type (read/write)
		offs_t               m_address;                  // start address
		offs_t               m_length;                   // length of watch area
		parsed_expression    m_condition;                // condition
		std::string          m_action;                   // action
	};

	// registerpoint class
	class registerpoint
	{
		friend class device_debug;

	public:
		// construction/destruction
		registerpoint(symbol_table &symbols, int index, const char *condition, const char *action = nullptr);

		// getters
		registerpoint *next() const { return m_next; }
		int index() const { return m_index; }
		bool enabled() const { return m_enabled; }
		const char *condition() const { return m_condition.original_string(); }
		const char *action() const { return m_action.c_str(); }

	private:
		// internals
		bool hit();

		registerpoint *     m_next;                     // next in the list
		int                 m_index;                    // user reported index
		UINT8               m_enabled;                  // enabled?
		parsed_expression   m_condition;                // condition
		std::string         m_action;                   // action
	};

public:
	// construction/destruction
	device_debug(device_t &device);
	~device_debug();

	// getters
	symbol_table &symtable() { return m_symtable; }

	// commonly-used pass-throughs
	int logaddrchars() const { return (m_memory != nullptr && m_memory->has_space(AS_PROGRAM)) ? m_memory->space(AS_PROGRAM).logaddrchars() : 8; }
	device_t& device() const { return m_device; }

	// hooks used by the rest of the system
	void start_hook(const attotime &endtime);
	void stop_hook();
	void interrupt_hook(int irqline);
	void exception_hook(int exception);
	void instruction_hook(offs_t curpc);
	void memory_read_hook(address_space &space, offs_t address, UINT64 mem_mask);
	void memory_write_hook(address_space &space, offs_t address, UINT64 data, UINT64 mem_mask);

	// hooks into our operations
	void set_instruction_hook(debug_instruction_hook_func hook);

	// debugger focus
	void ignore(bool ignore = true);
	bool observing() const { return ((m_flags & DEBUG_FLAG_OBSERVING) != 0); }

	// single stepping
	void single_step(int numsteps = 1);
	void single_step_over(int numsteps = 1);
	void single_step_out();

	// execution
	void go(offs_t targetpc = ~0);
	void go_vblank();
	void go_interrupt(int irqline = -1);
	void go_exception(int exception);
	void go_milliseconds(UINT64 milliseconds);
	void go_next_device();

	template <typename Format, typename... Params>
	void halt_on_next_instruction(Format &&fmt, Params &&... args)
	{
		halt_on_next_instruction_impl(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
	}

	// breakpoints
	breakpoint *breakpoint_first() const { return m_bplist; }
	int breakpoint_set(offs_t address, const char *condition = nullptr, const char *action = nullptr);
	bool breakpoint_clear(int index);
	void breakpoint_clear_all();
	bool breakpoint_enable(int index, bool enable = true);
	void breakpoint_enable_all(bool enable = true);

	// watchpoints
	watchpoint *watchpoint_first(address_spacenum spacenum) const { return m_wplist[spacenum]; }
	int watchpoint_set(address_space &space, int type, offs_t address, offs_t length, const char *condition, const char *action);
	bool watchpoint_clear(int wpnum);
	void watchpoint_clear_all();
	bool watchpoint_enable(int index, bool enable = true);
	void watchpoint_enable_all(bool enable = true);

	// registerpoints
	registerpoint *registerpoint_first() const { return m_rplist; }
	int registerpoint_set(const char *condition, const char *action = nullptr);
	bool registerpoint_clear(int index);
	void registerpoint_clear_all();
	bool registerpoint_enable(int index, bool enable = true);
	void registerpoint_enable_all(bool enable = true );

	// hotspots
	bool hotspot_tracking_enabled() const { return !m_hotspots.empty(); }
	void hotspot_track(int numspots, int threshhold);

	// comments
	void comment_add(offs_t address, const char *comment, rgb_t color);
	bool comment_remove(offs_t addr);
	const char *comment_text(offs_t addr) const;
	UINT32 comment_count() const { return m_comment_set.size(); }
	UINT32 comment_change_count() const { return m_comment_change; }
	bool comment_export(xml_data_node &node);
	bool comment_import(xml_data_node &node,bool is_inline);
	UINT32 compute_opcode_crc32(offs_t pc) const;

	// history
	offs_t history_pc(int index) const;

	// pc tracking
	void set_track_pc(bool value) { m_track_pc = value; }
	bool track_pc_visited(const offs_t& pc) const;
	void set_track_pc_visited(const offs_t& pc);
	void track_pc_data_clear() { m_track_pc_set.clear(); }

	// memory tracking
	void set_track_mem(bool value) { m_track_mem = value; }
	offs_t track_mem_pc_from_space_address_data(const address_spacenum& space,
												const offs_t& address,
												const UINT64& data) const;
	void track_mem_data_clear() { m_track_mem_set.clear(); }

	// tracing
	void trace(FILE *file, bool trace_over, bool detect_loops, const char *action);
	void trace_printf(const char *fmt, ...) ATTR_PRINTF(2,3);
	void trace_flush() { if (m_trace != nullptr) m_trace->flush(); }

	void reset_transient_flag() { m_flags &= ~DEBUG_FLAG_TRANSIENT; }

	static const int HISTORY_SIZE = 256;

	// debugger_cpu helpers
	void compute_debug_flags();

private:
	void halt_on_next_instruction_impl(util::format_argument_pack<std::ostream> &&args);

	// internal helpers
	void prepare_for_step_overout(offs_t pc);
	UINT32 dasm_wrapped(std::string &buffer, offs_t pc);

	// breakpoint and watchpoint helpers
	void breakpoint_update_flags();
	void breakpoint_check(offs_t pc);
	void watchpoint_update_flags(address_space &space);
	void watchpoint_check(address_space &space, int type, offs_t address, UINT64 value_to_write, UINT64 mem_mask);
	void hotspot_check(address_space &space, offs_t address);

	// symbol get/set callbacks
	static UINT64 get_current_pc(symbol_table &table, void *ref);
	static UINT64 get_cycles(symbol_table &table, void *ref);
	static UINT64 get_totalcycles(symbol_table &table, void *ref);
	static UINT64 get_lastinstructioncycles(symbol_table &table, void *ref);
	static UINT64 get_logunmap(symbol_table &table, void *ref);
	static void set_logunmap(symbol_table &table, void *ref, UINT64 value);
	static UINT64 get_state(symbol_table &table, void *ref);
	static void set_state(symbol_table &table, void *ref, UINT64 value);

	// basic device information
	device_t &                 m_device;                // device we are attached to
	device_execute_interface * m_exec;                  // execute interface, if present
	device_memory_interface *  m_memory;                // memory interface, if present
	device_state_interface *   m_state;                 // state interface, if present
	device_disasm_interface *  m_disasm;                // disasm interface, if present

	// global state
	UINT32                      m_flags;                // debugging flags for this CPU
	symbol_table                m_symtable;             // symbol table for expression evaluation
	debug_instruction_hook_func m_instrhook;            // per-instruction callback hook

	// stepping information
	offs_t                  m_stepaddr;                 // step target address for DEBUG_FLAG_STEPPING_OVER
	int                     m_stepsleft;                // number of steps left until done

	// execution information
	offs_t                  m_stopaddr;                 // stop address for DEBUG_FLAG_STOP_PC
	attotime                m_stoptime;                 // stop time for DEBUG_FLAG_STOP_TIME
	int                     m_stopirq;                  // stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT
	int                     m_stopexception;            // stop exception number for DEBUG_FLAG_STOP_EXCEPTION
	attotime                m_endexectime;              // ending time of the current execution
	UINT64                  m_total_cycles;             // current total cycles
	UINT64                  m_last_total_cycles;        // last total cycles

	// history
	offs_t                  m_pc_history[HISTORY_SIZE]; // history of recent PCs
	UINT32                  m_pc_history_index;         // current history index

	// breakpoints and watchpoints
	breakpoint *            m_bplist;                   // list of breakpoints
	watchpoint *            m_wplist[ADDRESS_SPACES];   // watchpoint lists for each address space
	registerpoint *         m_rplist;                   // list of registerpoints

	// tracing
	class tracer
	{
	public:
		tracer(device_debug &debug, FILE &file, bool trace_over, bool detect_loops, const char *action);
		~tracer();

		void update(offs_t pc);
		void vprintf(const char *format, va_list va);
		void flush();

	private:
		static const int TRACE_LOOPS = 64;

		device_debug &      m_debug;                    // reference to our owner
		FILE &              m_file;                     // tracing file for this CPU
		std::string         m_action;                   // action to perform during a trace
		offs_t              m_history[TRACE_LOOPS];     // history of recent PCs
		bool				m_detect_loops;				// whether or not we should detect loops
		int                 m_loops;                    // number of instructions in a loop
		int                 m_nextdex;                  // next index
		bool                m_trace_over;               // true if we're tracing over
		offs_t              m_trace_over_target;        // target for tracing over
														//    (0 = not tracing over,
														//    ~0 = not currently tracing over)
	};
	std::unique_ptr<tracer>                m_trace;                    // tracer state

	// hotspots
	struct hotspot_entry
	{
		offs_t              m_access;                   // access address
		offs_t              m_pc;                       // PC of the access
		address_space *     m_space;                    // space where the access occurred
		UINT32              m_count;                    // number of hits
	};
	std::vector<hotspot_entry> m_hotspots;            // hotspot list
	int                     m_hotspot_threshhold;       // threshhold for the number of hits to print

	// pc tracking
	class dasm_pc_tag
	{
	public:
		dasm_pc_tag(const offs_t& address, const UINT32& crc);

		// required to be included in a set
		bool operator < (const dasm_pc_tag& rhs) const
		{
			if (m_address == rhs.m_address)
				return m_crc < rhs.m_crc;
			return (m_address < rhs.m_address);
		}

		offs_t m_address;       // Stores [nothing] for a given address & crc32
		UINT32 m_crc;
	};
	std::set<dasm_pc_tag> m_track_pc_set;
	bool m_track_pc;

	// comments
	class dasm_comment : public dasm_pc_tag
	{
	public:
		dasm_comment(offs_t address, UINT32 crc, const char *text, rgb_t color);

		std::string  m_text;        // Stores comment text & color for a given address & crc32
		rgb_t    m_color;
	};
	std::set<dasm_comment> m_comment_set;               // collection of comments
	UINT32                 m_comment_change;            // change counter for comments

	// memory tracking
	class dasm_memory_access
	{
	public:
		dasm_memory_access(const address_spacenum& address_space,
							const offs_t& address,
							const UINT64& data,
							const offs_t& pc);

		// required to be included in a set
		bool operator < (const dasm_memory_access& rhs) const
		{
			if ((m_address == rhs.m_address) && (m_address_space == rhs.m_address_space))
				return m_data < rhs.m_data;
			else if (m_address_space == rhs.m_address_space)
				return m_address < rhs.m_address;
			else
				return m_address_space < rhs.m_address_space;
		}

		// Stores the PC for a given address, memory region, and data value
		address_spacenum m_address_space;
		offs_t           m_address;
		UINT64           m_data;
		mutable offs_t   m_pc;
	};
	std::set<dasm_memory_access> m_track_mem_set;
	bool m_track_mem;

	// internal flag values
	static const UINT32 DEBUG_FLAG_OBSERVING        = 0x00000001;       // observing this CPU
	static const UINT32 DEBUG_FLAG_HISTORY          = 0x00000002;       // tracking this CPU's history
	static const UINT32 DEBUG_FLAG_TRACING          = 0x00000004;       // tracing this CPU
	static const UINT32 DEBUG_FLAG_TRACING_OVER     = 0x00000008;       // tracing this CPU with step over behavior
	static const UINT32 DEBUG_FLAG_HOOKED           = 0x00000010;       // per-instruction callback hook
	static const UINT32 DEBUG_FLAG_STEPPING         = 0x00000020;       // CPU is single stepping
	static const UINT32 DEBUG_FLAG_STEPPING_OVER    = 0x00000040;       // CPU is stepping over a function
	static const UINT32 DEBUG_FLAG_STEPPING_OUT     = 0x00000080;       // CPU is stepping out of a function
	static const UINT32 DEBUG_FLAG_STOP_PC          = 0x00000100;       // there is a pending stop at cpu->breakpc
	static const UINT32 DEBUG_FLAG_STOP_INTERRUPT   = 0x00000400;       // there is a pending stop on the next interrupt
	static const UINT32 DEBUG_FLAG_STOP_EXCEPTION   = 0x00000800;       // there is a pending stop on the next exception
	static const UINT32 DEBUG_FLAG_STOP_VBLANK      = 0x00001000;       // there is a pending stop on the next VBLANK
	static const UINT32 DEBUG_FLAG_STOP_TIME        = 0x00002000;       // there is a pending stop at cpu->stoptime
	static const UINT32 DEBUG_FLAG_LIVE_BP          = 0x00010000;       // there are live breakpoints for this CPU

	static const UINT32 DEBUG_FLAG_STEPPING_ANY     = DEBUG_FLAG_STEPPING | DEBUG_FLAG_STEPPING_OVER | DEBUG_FLAG_STEPPING_OUT;
	static const UINT32 DEBUG_FLAG_TRACING_ANY      = DEBUG_FLAG_TRACING | DEBUG_FLAG_TRACING_OVER;
	static const UINT32 DEBUG_FLAG_TRANSIENT        = DEBUG_FLAG_STEPPING_ANY | DEBUG_FLAG_STOP_PC |
			DEBUG_FLAG_STOP_INTERRUPT | DEBUG_FLAG_STOP_EXCEPTION | DEBUG_FLAG_STOP_VBLANK | DEBUG_FLAG_STOP_TIME;
};

//**************************************************************************
//  CPU DEBUGGING
//**************************************************************************

class debugger_cpu
{
public:
	debugger_cpu(running_machine &machine);

	/* ----- initialization and cleanup ----- */

	/* flushes all traces; this is useful if a trace is going on when we fatalerror */
	void flush_traces();

	void configure_memory(symbol_table &table);


	/* ----- debugging status & information ----- */

	/* return the visible CPU device (the one that commands should apply to) */
	device_t *get_visible_cpu();

	/* true if the debugger is currently stopped within an instruction hook callback */
	bool within_instruction_hook();

	/* return true if the current execution state is stopped */
	bool is_stopped();


	/* ----- symbol table interfaces ----- */

	/* return the global symbol table */
	symbol_table *get_global_symtable();

	/* return the locally-visible symbol table */
	symbol_table *get_visible_symtable();


	/* ----- misc debugger functions ----- */

	/* specifies a debug command script to execute */
	void source_script(const char *file);


	/* ----- debugger comment helpers ----- */

	// save all comments for a given machine
	bool comment_save();

	// load all comments for a given machine
	bool comment_load(bool is_inline);


	/* ----- debugger memory accessors ----- */

	/* return a byte from the specified memory space */
	UINT8 read_byte(address_space &space, offs_t address, int apply_translation);

	/* return a word from the specified memory space */
	UINT16 read_word(address_space &space, offs_t address, int apply_translation);

	/* return a dword from the specified memory space */
	UINT32 read_dword(address_space &space, offs_t address, int apply_translation);

	/* return a qword from the specified memory space */
	UINT64 read_qword(address_space &space, offs_t address, int apply_translation);

	/* return 1,2,4 or 8 bytes from the specified memory space */
	UINT64 read_memory(address_space &space, offs_t address, int size, int apply_translation);

	/* write a byte to the specified memory space */
	void write_byte(address_space &space, offs_t address, UINT8 data, int apply_translation);

	/* write a word to the specified memory space */
	void write_word(address_space &space, offs_t address, UINT16 data, int apply_translation);

	/* write a dword to the specified memory space */
	void write_dword(address_space &space, offs_t address, UINT32 data, int apply_translation);

	/* write a qword to the specified memory space */
	void write_qword(address_space &space, offs_t address, UINT64 data, int apply_translation);

	/* write 1,2,4 or 8 bytes to the specified memory space */
	void write_memory(address_space &space, offs_t address, UINT64 data, int size, int apply_translation);

	/* read 1,2,4 or 8 bytes at the given offset from opcode space */
	UINT64 read_opcode(address_space &space, offs_t offset, int size);

	// getters
	bool within_instruction_hook() const { return m_within_instruction_hook; }
	bool memory_modified() const { return m_memory_modified; }
	int execution_state() const { return m_execution_state; }
	device_t *live_cpu() { return m_livecpu; }
	UINT32 get_breakpoint_index() { return m_bpindex++; }
	UINT32 get_watchpoint_index() { return m_wpindex++; }
	UINT32 get_registerpoint_index() { return m_rpindex++; }

	// setters
	void set_visible_cpu(device_t * visiblecpu) { m_visiblecpu = visiblecpu; }
	void set_break_cpu(device_t * breakcpu) { m_breakcpu = breakcpu; }
	void set_within_instruction(bool within_instruction) { m_within_instruction_hook = within_instruction; }
	void set_memory_modified(bool memory_modified) { m_memory_modified = memory_modified; }
	void set_execution_state(int execution_state) { m_execution_state = execution_state; }

	// device_debug helpers
	// [TODO] [RH]: Look into this more later, can possibly merge these two classes
	void start_hook(device_t *device, bool stop_on_vblank);
	void stop_hook(device_t *device);
	void go_next_device(device_t *device);
	void go_vblank();
	void halt_on_next_instruction(device_t *device, util::format_argument_pack<std::ostream> &&args);
	void ensure_comments_loaded();
	void reset_transient_flags();
	void process_source_file();
	void watchpoint_check(address_space& space, int type, offs_t address, UINT64 value_to_write, UINT64 mem_mask, device_debug::watchpoint** wplist);

private:
	static const size_t NUM_TEMP_VARIABLES;

	/* expression handlers */
	UINT64 expression_read_memory(void *param, const char *name, expression_space space, UINT32 address, int size);
	UINT64 expression_read_program_direct(address_space &space, int opcode, offs_t address, int size);
	UINT64 expression_read_memory_region(const char *rgntag, offs_t address, int size);
	void expression_write_memory(void *param, const char *name, expression_space space, UINT32 address, int size, UINT64 data);
	void expression_write_program_direct(address_space &space, int opcode, offs_t address, int size, UINT64 data);
	void expression_write_memory_region(const char *rgntag, offs_t address, int size, UINT64 data);
	expression_error::error_code expression_validate(void *param, const char *name, expression_space space);
	device_t* expression_get_device(const char *tag);

	/* variable getters/setters */
	UINT64 get_cpunum(symbol_table &table, void *ref);
	UINT64 get_beamx(symbol_table &table, void *ref);
	UINT64 get_beamy(symbol_table &table, void *ref);
	UINT64 get_frame(symbol_table &table, void *ref);

	/* internal helpers */
	void on_vblank(screen_device &device, bool vblank_state);

	running_machine&    m_machine;

	device_t *  m_livecpu;
	device_t *  m_visiblecpu;
	device_t *  m_breakcpu;

	FILE *      m_source_file;          // script source file

	std::unique_ptr<symbol_table> m_symtable;           // global symbol table

	bool    m_within_instruction_hook;
	bool    m_vblank_occurred;
	bool    m_memory_modified;
	bool    m_debugger_access;

	int         m_execution_state;
	device_t *  m_stop_when_not_device; // stop execution when the device ceases to be this

	UINT32      m_bpindex;
	UINT32      m_wpindex;
	UINT32      m_rpindex;

	UINT64      m_wpdata;
	UINT64      m_wpaddr;
	std::unique_ptr<UINT64[]> m_tempvar;

	osd_ticks_t m_last_periodic_update_time;

	bool        m_comments_loaded;
};

#endif