summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/debug/debugcpu.h
blob: fcd648ac7a82073dedf7681d60eb1b701ea9f982 (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
/*********************************************************************

    debugcpu.h

    Debugger CPU/memory interface engine.

    Copyright Nicola Salmoria and the MAME Team.
    Visit http://mamedev.org for licensing and usage restrictions.

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

#pragma once

#ifndef __DEBUGCPU_H__
#define __DEBUGCPU_H__

#include "cpuintrf.h"
#include "express.h"


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

#define TRACE_LOOPS					64
#define DEBUG_HISTORY_SIZE			256

#define WATCHPOINT_READ				1
#define WATCHPOINT_WRITE			2
#define WATCHPOINT_READWRITE		(WATCHPOINT_READ | WATCHPOINT_WRITE)

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

#define DEBUG_FLAG_STEPPING_ANY		(DEBUG_FLAG_STEPPING | \
									 DEBUG_FLAG_STEPPING_OVER | \
									 DEBUG_FLAG_STEPPING_OUT)

#define DEBUG_FLAG_TRACING_ANY		(DEBUG_FLAG_TRACING | \
									 DEBUG_FLAG_TRACING_OVER)

#define DEBUG_FLAG_TRANSIENT		(DEBUG_FLAG_STEPPING_ANY | \
									 DEBUG_FLAG_STOP_PC | \
									 DEBUG_FLAG_STOP_CONTEXT | \
									 DEBUG_FLAG_STOP_INTERRUPT | \
									 DEBUG_FLAG_STOP_EXCEPTION | \
									 DEBUG_FLAG_STOP_VBLANK | \
									 DEBUG_FLAG_STOP_TIME)



/***************************************************************************
    MACROS
***************************************************************************/

#define ADDR2BYTE(val,info,spc) (((val) << (info)->space[spc].addr2byte_lshift) >> (info)->space[spc].addr2byte_rshift)
#define ADDR2BYTE_MASKED(val,info,spc) (ADDR2BYTE(val,info,spc) & (info)->space[spc].logbytemask)
#define BYTE2ADDR(val,info,spc) (((val) << (info)->space[spc].addr2byte_rshift) >> (info)->space[spc].addr2byte_lshift)



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

typedef int (*debug_instruction_hook_func)(const device_config *device, offs_t curpc);


typedef struct _debug_cpu_breakpoint debug_cpu_breakpoint;
typedef struct _debug_cpu_watchpoint debug_cpu_watchpoint;


typedef struct _debug_trace_info debug_trace_info;
struct _debug_trace_info
{
	FILE *			file;						/* tracing file for this CPU */
	char *			action;						/* action to perform during a trace */
	offs_t			history[TRACE_LOOPS];		/* history of recent PCs */
	int				loops;						/* number of instructions in a loop */
	int				nextdex;					/* next index */
	offs_t			trace_over_target;			/* target for tracing over
                                                    (0 = not tracing over,
                                                    ~0 = not currently tracing over) */
};


typedef struct _debug_space_info debug_space_info;
struct _debug_space_info
{
	const address_space *space;					/* pointer to the CPU's address space */
	debug_cpu_watchpoint *wplist;				/* list of watchpoints */
	UINT8			databytes;					/* width of the data bus, in bytes */
	UINT8			pageshift;					/* page shift */
	UINT8			addr2byte_lshift;			/* left shift to convert CPU address to a byte value */
	UINT8			addr2byte_rshift;			/* right shift to convert CPU address to a byte value */
	UINT8			physchars;					/* number of characters to use for physical addresses */
	UINT8			logchars;					/* number of characters to use for logical addresses */
	offs_t			physaddrmask;				/* physical address mask */
	offs_t			logaddrmask;				/* logical address mask */
	offs_t			physbytemask;				/* physical byte mask */
	offs_t			logbytemask;				/* logical byte mask */
};


typedef struct _debug_hotspot_entry debug_hotspot_entry;
struct _debug_hotspot_entry
{
	offs_t			access;						/* access address */
	offs_t			pc;							/* PC of the access */
	int				spacenum;					/* space where the access occurred */
	UINT32			count;						/* number of hits */
};


/* In cpuintrf.h: typedef struct _cpu_debug_data cpu_debug_data; */
struct _cpu_debug_data
{
	const device_config *device;				/* CPU device object */
	symbol_table *	symtable;					/* symbol table for expression evaluation */
	UINT32			flags;						/* debugging flags for this CPU */
	UINT8			endianness;					/* little or bigendian */
	UINT8			opwidth;					/* width of an opcode */
	offs_t			stepaddr;					/* step target address for DEBUG_FLAG_STEPPING_OVER */
	int				stepsleft;					/* number of steps left until done */
	offs_t			stopaddr;					/* stop address for DEBUG_FLAG_STOP_PC */
	attotime		stoptime;					/* stop time for DEBUG_FLAG_STOP_TIME */
	int				stopirq;					/* stop IRQ number for DEBUG_FLAG_STOP_INTERRUPT */
	int				stopexception;				/* stop exception number for DEBUG_FLAG_STOP_EXCEPTION */
	attotime		endexectime;				/* ending time of the current execution */
	debug_trace_info trace;						/* trace info */
	debug_cpu_breakpoint *bplist;				/* list of breakpoints */
	debug_hotspot_entry *hotspots;				/* hotspot list */
	offs_t			pc_history[DEBUG_HISTORY_SIZE]; /* history of recent PCs */
	UINT32			pc_history_index;			/* current history index */
	int				hotspot_count;				/* number of hotspots */
	int				hotspot_threshhold;			/* threshhold for the number of hits to print */
	cpu_translate_func translate;				/* address translation routine */
	cpu_read_func	read; 						/* memory read routine */
	cpu_write_func	write;						/* memory write routine */
	cpu_readop_func	readop;						/* opcode read routine */
	debug_instruction_hook_func instrhook;		/* per-instruction callback hook */
	debug_space_info space[ADDRESS_SPACES];		/* per-address space info */
};


struct _debug_cpu_breakpoint
{
	debug_cpu_breakpoint *next;					/* next in the list */
	int				index;						/* user reported index */
	UINT8			enabled;					/* enabled? */
	offs_t			address;					/* execution address */
	parsed_expression *condition;				/* condition */
	char *			action;						/* action */
};


struct _debug_cpu_watchpoint
{
	int				index;						/* user reported index */
	UINT8			enabled;					/* enabled? */
	UINT8			type;						/* type (read/write) */
	offs_t			address;					/* start address */
	offs_t			length;						/* length of watch area */
	parsed_expression *condition;				/* condition */
	char *			action;						/* action */
	debug_cpu_watchpoint *next;					/* next in the list */
};



/***************************************************************************
    GLOBAL VARIABLES
***************************************************************************/

extern const express_callbacks debug_expression_callbacks;



/***************************************************************************
    FUNCTION PROTOTYPES
***************************************************************************/

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

/* initialize the CPU tracking for the debugger */
void debug_cpu_init(running_machine *machine);

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



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

/* return the visible CPU device (the one that commands should apply to) */
const device_config *debug_cpu_get_visible_cpu(running_machine *machine);

/* TRUE if the debugger is currently stopped within an instruction hook callback */
int debug_cpu_within_instruction_hook(running_machine *machine);

/* return TRUE if the current execution state is stopped */
int	debug_cpu_is_stopped(running_machine *machine);



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

/* return the global symbol table */
symbol_table *debug_cpu_get_global_symtable(running_machine *machine);

/* return the locally-visible symbol table */
symbol_table *debug_cpu_get_visible_symtable(running_machine *machine);

/* return a specific CPU's symbol table */
symbol_table *debug_cpu_get_symtable(const device_config *device);



/* ----- core debugger hooks ----- */

/* the CPU execution system calls this hook before beginning execution for the given CPU */
void debug_cpu_start_hook(const device_config *device, attotime endtime);

/* the CPU execution system calls this hook when ending execution for the given CPU */
void debug_cpu_stop_hook(const device_config *device);

/* the CPU execution system calls this hook when an interrupt is acknowledged */
void debug_cpu_interrupt_hook(const device_config *device, int irqline);

/* called by the CPU cores when an exception is generated */
void debug_cpu_exception_hook(const device_config *device, int exception);

/* called by the CPU cores before executing each instruction */
void debug_cpu_instruction_hook(const device_config *device, offs_t curpc);

/* the memory system calls this hook when watchpoints are enabled and a memory read happens */
void debug_cpu_memory_read_hook(const address_space *space, offs_t address, UINT64 mem_mask);

/* the memory system calls this hook when watchpoints are enabled and a memory write happens */
void debug_cpu_memory_write_hook(const address_space *space, offs_t address, UINT64 data, UINT64 mem_mask);



/* ----- execution control ----- */

/* halt in the debugger on the next instruction */
void debug_cpu_halt_on_next_instruction(const device_config *device, const char *fmt, ...) ATTR_PRINTF(2,3);

/* ignore/observe a given CPU */
void debug_cpu_ignore_cpu(const device_config *cpu, int ignore);

/* single step the visible CPU past the requested number of instructions */
void debug_cpu_single_step(running_machine *machine, int numsteps);

/* single step the visible over the requested number of instructions */
void debug_cpu_single_step_over(running_machine *machine, int numsteps);

/* single step the visible CPU out of the current function */
void debug_cpu_single_step_out(running_machine *machine);

/* execute the visible CPU until it hits the given address */
void debug_cpu_go(running_machine *machine, offs_t targetpc);

/* execute until the next VBLANK */
void debug_cpu_go_vblank(running_machine *machine);

/* execute until the specified interrupt fires on the visible CPU */
void debug_cpu_go_interrupt(running_machine *machine, int irqline);

/* execute until the specified exception fires on the visible CPU */
void debug_cpu_go_exception(running_machine *machine, int exception);

/* execute until the specified delay elapses */
void debug_cpu_go_milliseconds(running_machine *machine, UINT64 milliseconds);

/* execute until we hit the next CPU */
void debug_cpu_next_cpu(running_machine *machine);



/* ----- breakpoints ----- */

/* set a new breakpoint, returning its index */
int	debug_cpu_breakpoint_set(const device_config *device, offs_t address, parsed_expression *condition, const char *action);

/* clear a breakpoint by index */
int	debug_cpu_breakpoint_clear(running_machine *machine, int bpnum);

/* enable/disable a breakpoint by index */
int	debug_cpu_breakpoint_enable(running_machine *machine, int bpnum, int enable);



/* ----- watchpoints ----- */

/* set a new watchpoint, returning its index */
int	debug_cpu_watchpoint_set(const address_space *space, int type, offs_t address, offs_t length, parsed_expression *condition, const char *action);

/* clear a watchpoint by index */
int	debug_cpu_watchpoint_clear(running_machine *machine, int wpnum);

/* enable/disable a watchpoint by index */
int	debug_cpu_watchpoint_enable(running_machine *machine, int wpnum, int enable);



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

/* specifies a debug command script to execute */
void debug_cpu_source_script(running_machine *machine, const char *file);

/* trace execution of a given CPU */
void debug_cpu_trace(const device_config *device, FILE *file, int trace_over, const char *action);

/* output data into the given CPU's tracefile, if tracing */
void debug_cpu_trace_printf(const device_config *device, const char *fmt, ...) ATTR_PRINTF(2,3);

/* set a hook to be called on each instruction for a given CPU */
void debug_cpu_set_instruction_hook(const device_config *device, debug_instruction_hook_func hook);

/* hotspots */
int	debug_cpu_hotspot_track(const device_config *device, int numspots, int threshhold);



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

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

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

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

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

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

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

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

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

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

#endif