Develop and Download Open Source Software

Browse CVS Repository

Contents of /mame32jp/mame32jp/src/mamedbg.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Wed Apr 24 03:53:20 2002 UTC (21 years, 11 months ago) by zero
Branch: MAIN
CVS Tags: ver_0_60_1, ver0_59_13, ver0_59_14, ver0_60_2, ver0_60_3, ver0_60_4, ver0_60_5, HEAD
Changes since 1.4: +0 -0 lines
File MIME type: text/x-csrc
*** empty log message ***

1 /****************************************************************************
2 * MAME debugger V0.54
3 * Juergen Buchmueller <pullmoll@t-online.de>
4 *
5 * Based on code found in the preivous version of the MAME debugger
6 * written by: Martin Scragg, John Butler, Mirko Buffoni
7 * Chris Moore, Aaron Giles, Ernesto Corvi
8 *
9 * Online help is available by pressing F1 (context sensitive!)
10 *
11 * TODO:
12 * - Add stack view using activecpu_get_reg(REG_SP_CONTENTS+offset)
13 * - Add more display modes for the memory windows (binary? octal? decimal?)
14 *
15 ****************************************************************************/
16
17 #include <stdio.h>
18
19 #ifdef MAME_DEBUG
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdarg.h>
23 #include <ctype.h>
24 #include "driver.h"
25 #include "vidhrdw/generic.h"
26 #include "mamedbg.h"
27 #include "window.h"
28
29 #ifndef INVALID
30 #define INVALID -1
31 #endif
32
33 /****************************************************************************
34 * Externals (define in the header files)
35 ****************************************************************************/
36 /* Long(er) function names, short macro names... */
37 #define ABITS activecpu_address_bits()
38 #define AMASK activecpu_address_mask()
39 #define ASHIFT activecpu_address_shift()
40 #define ALIGN activecpu_align_unit()
41 #define INSTL activecpu_max_inst_len()
42 #define ENDIAN activecpu_endianess()
43
44 #define RDMEM(a) (*cputype_get_interface(cputype)->memory_read)(a)
45 #define WRMEM(a,v) (*cputype_get_interface(cputype)->memory_write)(a,v)
46 #define RDINT(a) (*cputype_get_interface(cputype)->internal_read)(a)
47 #define WRINT(a,v) (*cputype_get_interface(cputype)->internal_write)(a,v)
48 #define PGM_MEMORY cputype_get_interface(cputype)->pgm_memory_base
49
50 /****************************************************************************
51 * Globals
52 ****************************************************************************/
53 int debug_key_pressed = 0; /* set to non zero to break into the debugger */
54 int debug_key_delay = 0; /* set to 0x7ffe to force keyboard check on next update */
55 int debug_trace_delay = 0; /* set to 0 to force a screen update */
56
57 /****************************************************************************
58 * Limits
59 ****************************************************************************/
60 #define MAX_DATA 512 /* Maximum memory size in bytes of a dump window */
61 #define MAX_MEM 2 /* You can't redefine this... too easy */
62
63 #define MAX_LOOPS 64 /* Maximum loop addresses recognized by trace */
64
65 #define MAX_HIST 16 /* Maximum history depth */
66
67 #define EDIT_CMDS 0
68 #define EDIT_REGS 1 /* Just the order of the windows */
69 #define EDIT_DASM 2
70 #define EDIT_MEM1 3
71 #define EDIT_MEM2 4
72
73 #define DBG_WINDOWS 5
74
75 /* Some convenience macros to address the cpu'th window */
76 #define WIN_CMDS(cpu) (cpu*DBG_WINDOWS+EDIT_CMDS)
77 #define WIN_REGS(cpu) (cpu*DBG_WINDOWS+EDIT_REGS)
78 #define WIN_DASM(cpu) (cpu*DBG_WINDOWS+EDIT_DASM)
79 #define WIN_MEM(cpu,n) (cpu*DBG_WINDOWS+EDIT_MEM1+n)
80 #define WIN_MEM1(cpu) (cpu*DBG_WINDOWS+EDIT_MEM1)
81 #define WIN_MEM2(cpu) (cpu*DBG_WINDOWS+EDIT_MEM2)
82 #define WIN_HELP (MAX_WINDOWS-1)
83 #define WIN_MSGBOX (MAX_WINDOWS-2)
84
85 enum {
86 MODE_HEX_UINT8,
87 MODE_HEX_UINT16,
88 MODE_HEX_UINT32,
89 MODE_HEX_COUNT
90 };
91
92 enum {
93 MODE_CHR_HEX,
94 MODE_CHR_XLATE,
95 MODE_CHR_PLAIN,
96 MODE_CHR_COUNT
97 };
98
99 #define UINT16_XOR_LE(o) (((o)&~1)|(((o)&1)^1))
100 #define UINT32_XOR_LE(o) (((o)&~3)|(((o)&3)^3))
101 #define HOST_XOR_LE 0
102 #define UINT16_XOR_BE(o) (o)
103 #define UINT32_XOR_BE(o) (o)
104 #define HOST_XOR_BE 0
105
106 /****************************************************************************
107 * Statics
108 ****************************************************************************/
109 static int first_time = 1;
110
111 static int active_cpu = INVALID;
112 static int previous_active_cpu = INVALID;
113 static int total_cpu = 0;
114 static int cputype = 0;
115
116 static int dbg_fast = 0;
117 static int dbg_step = 0;
118 static int dbg_trace = 0;
119 static int dbg_update = 0;
120 static int dbg_update_cur = 0;
121 static int dbg_active = 0;
122 static int dbg_trace_delay = 0;
123
124 /* 0 = dont, 1 = do allow squeezed display w/alternating dim, bright colors */
125 static int dbg_mem_squeezed = 0;
126 /* 0 = display disassembly only, 1 = display opcodes too */
127 static int dbg_dasm_opcodes = 0;
128 /* 0 = default, 1 = lower or 2 = upper case */
129 static int dbg_dasm_case = 0;
130 /* 0 = absolute, 1 = relative format for relative jumps/branches */
131 static int dbg_dasm_relative_jumps = 0;
132
133 static const char *dbg_info_once = NULL;
134
135 /****************************************************************************
136 * Color settings
137 ****************************************************************************/
138 #define COLOR_NAMES \
139 "BLACK\0" \
140 "BLUE\0" \
141 "GREEN\0" \
142 "CYAN\0" \
143 "RED\0" \
144 "MAGENTA\0" \
145 "BROWN\0" \
146 "LIGHTGRAY\0" \
147 "DARKGRAY\0" \
148 "LIGHTBLUE\0" \
149 "LIGHTGREEN\0" \
150 "LIGHTCYAN\0" \
151 "LIGHTRED\0" \
152 "LIGHTMAGENTA\0" \
153 "YELLOW\0" \
154 "WHITE\0"
155
156 #define ELEMENT_NAMES \
157 "TITLE\0" \
158 "FRAME\0" \
159 "REGS\0" \
160 "DASM\0" \
161 "MEM1\0" \
162 "MEM2\0" \
163 "CMDS\0" \
164 "BRK_EXEC\0" \
165 "BRK_DATA\0" \
166 "BRK_REGS\0" \
167 "ERROR\0" \
168 "HELP\0" \
169 "PROMPT\0" \
170 "CHANGES\0" \
171 "PC\0" \
172 "CURSOR\0"
173
174 enum ELEMENT {
175 E_TITLE,
176 E_FRAME,
177 E_REGS,
178 E_DASM,
179 E_MEM1,
180 E_MEM2,
181 E_CMDS,
182 E_BRK_EXEC,
183 E_BRK_DATA,
184 E_BRK_REGS,
185 E_ERROR,
186 E_HELP,
187 E_PROMPT,
188 E_CHANGES,
189 E_PC,
190 E_CURSOR,
191 E_COUNT
192 };
193
194 static UINT8 cur_col[E_COUNT] = {
195 COLOR_TITLE,
196 COLOR_FRAME,
197 COLOR_REGS,
198 COLOR_DASM,
199 COLOR_MEM1,
200 COLOR_MEM2,
201 COLOR_CMDS,
202 COLOR_BRK_EXEC,
203 COLOR_BRK_DATA,
204 COLOR_BRK_REGS,
205 COLOR_ERROR,
206 COLOR_HELP,
207 COLOR_PROMPT,
208 COLOR_CHANGES,
209 COLOR_PC,
210 COLOR_CURSOR,
211 };
212
213 static UINT8 def_col[E_COUNT] = {
214 COLOR_TITLE,
215 COLOR_FRAME,
216 COLOR_REGS,
217 COLOR_DASM,
218 COLOR_MEM1,
219 COLOR_MEM2,
220 COLOR_CMDS,
221 COLOR_BRK_EXEC,
222 COLOR_BRK_DATA,
223 COLOR_BRK_REGS,
224 COLOR_ERROR,
225 COLOR_HELP,
226 COLOR_PROMPT,
227 COLOR_CHANGES,
228 COLOR_PC,
229 COLOR_CURSOR,
230 };
231
232 /****************************************************************************
233 * Code to ASCII translation table; may be redefined (later)
234 ****************************************************************************/
235 static char trans_table[256] = {
236 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
237 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
238 ' ','!','"','#','$','%','&', 39,'(',')','*','+',',','-','.','/',
239 '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
240 '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
241 'P','Q','R','S','T','U','V','W','X','Y','Z','[', 92,']','^','_',
242 '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
243 'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','.',
244 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
245 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
246 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
247 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
248 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
249 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
250 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
251 '.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
252 };
253
254 /****************************************************************************
255 * Function prototypes
256 ****************************************************************************/
257 static unsigned get_register_id( char **parg, int *size );
258 static const char *get_register_name( int id );
259 static unsigned get_register_or_value( char **parg, int *size );
260 static void trace_init( const char *filename, UINT8 *regs );
261 static void trace_done( void );
262 static void trace_select( void );
263 static void trace_output( void );
264
265 static int hit_brk_exec( void );
266 static int hit_brk_data( void );
267 static int hit_brk_regs( void );
268
269 static const char *name_rom( const char *type, int region, unsigned *base, unsigned start );
270 static const char *name_rdmem( unsigned base );
271 static const char *name_wrmem( unsigned base );
272 static const char *name_memory( unsigned base );
273
274 static int win_create(int n, UINT8 prio, int x, int y, int w, int h,
275 UINT8 co_text, UINT8 co_frame, UINT8 chr, UINT32 attributes);
276 static int DECL_SPEC win_msgbox( UINT8 color, const char *title, const char *fmt, ... );
277 static void dbg_open_windows( void );
278 static void dbg_close_windows( void );
279
280 static unsigned dasm_line( unsigned pc, int times );
281
282 static void dump_regs( void );
283 static unsigned dump_dasm( unsigned pc );
284 static void dump_mem_hex( int which, unsigned len_addr, unsigned len_data );
285 static void dump_mem( int which, int set_title );
286
287 static int edit_cmds_info( void );
288 static int edit_cmds_parse( char *cmdline );
289 static void edit_cmds_append( const char *src );
290
291 static void edit_regs( void );
292 static void edit_dasm( void );
293 static void edit_mem( int which );
294 static void edit_cmds(void);
295
296 static void cmd_help( void );
297 static void cmd_default( int code );
298
299 static void cmd_display_memory( void );
300 static void cmd_edit_memory( void );
301 static void cmd_set_memory_mode( void );
302 static void cmd_fast( void );
303 static void cmd_go_break( void );
304 static void cmd_jump( void );
305 static void cmd_replace_register( void );
306 static void cmd_brk_exec_set( void );
307 static void cmd_brk_exec_clear( void );
308 static void cmd_brk_regs_set( void );
309 static void cmd_brk_regs_clear( void );
310 static void cmd_brk_data_set( void );
311 static void cmd_brk_data_clear( void );
312 static void cmd_here( void );
313 static void cmd_dasm_to_file( void );
314 static void cmd_dump_to_file( void );
315 static void cmd_trace_to_file( void );
316 static void cmd_save_to_file( void );
317 static void cmd_set_ignore( void );
318 static void cmd_set_observe( void );
319 static void cmd_set_key_repeat( void );
320 static void cmd_set_dasm_case( void );
321 static void cmd_set_dasm_opcodes( void );
322 static void cmd_set_dasm_relative_jumps( void );
323 static void cmd_set_mem_squeezed( void );
324 static void cmd_set_element_color( void );
325 static void cmd_brk_exec_toggle( void );
326 static void cmd_brk_data_toggle( void );
327
328 static void cmd_switch_window( void );
329 static void cmd_dasm_up( void );
330 static void cmd_dasm_down( void );
331 static void cmd_dasm_page_up( void );
332 static void cmd_dasm_page_down( void );
333 static void cmd_dasm_home( void );
334 static void cmd_dasm_end( void );
335 static void cmd_dasm_hist_follow( void );
336 static void cmd_dasm_hist_back( void );
337 static void cmd_run_to_cursor( void );
338 static void cmd_focus_next_cpu( void );
339 static void cmd_step( void );
340 static void cmd_animate( void );
341 static void cmd_step_over( void );
342 static void cmd_go( void );
343 static void cmd_search_memory( void );
344
345 /****************************************************************************
346 * Generic structure for saving points in the 'follow history'
347 ****************************************************************************/
348 typedef struct {
349 UINT32 dasm_top; /* previous top of window PC */
350 UINT32 dasm_cur; /* previous cursor PC */
351 UINT32 mem1_base; /* previous memory 1 base address */
352 UINT32 mem1_offset; /* previous memory 1 offset */
353 UINT32 mem1_nibble; /* previous memory 1 nibble */
354 } s_hist;
355
356 /****************************************************************************
357 * Symbol table entry
358 ****************************************************************************/
359 typedef struct {
360 UINT32 value; /* value of the symbol */
361 INT32 access; /* access mode (EA_... enum) */
362 INT32 size; /* size of the element */
363 UINT32 times; /* repeat how many times */
364 char name[47+1]; /* name of the symbol */
365 } s_symbol;
366
367 /****************************************************************************
368 * Generic structure for editing values
369 * x,y are the coordinates inside a window
370 * w is the width in hex digits (aka nibbles)
371 * n is the distance of the hex part from the start of the output (register)
372 ****************************************************************************/
373 typedef struct {
374 UINT8 x,y,w,n;
375 } s_edit;
376
377 /****************************************************************************
378 * Register display and editing structure
379 ****************************************************************************/
380 typedef struct {
381 UINT32 backup[MAX_REGS]; /* backup register values */
382 UINT32 newval[MAX_REGS]; /* new register values */
383 s_edit edit[MAX_REGS]; /* list of x,y,w triplets for the register values */
384 char name[MAX_REGS][15+1]; /* ...fifteen characters enough!? */
385 UINT8 id[MAX_REGS]; /* the ID of the register (activecpu_get_reg/activecpu_set_reg) */
386 UINT32 max_width; /* maximum width of any dumped register */
387 INT32 idx; /* index of current register */
388 INT32 count; /* number of registers */
389 INT32 nibble; /* edit nibble */
390 INT32 changed;
391 INT32 top;
392 INT32 base;
393 } s_regs;
394
395 /****************************************************************************
396 * Memory display and editing structure
397 ****************************************************************************/
398 typedef struct {
399 UINT8 backup[MAX_DATA]; /* backup data */
400 UINT8 newval[MAX_DATA]; /* newly read data */
401 s_edit edit[MAX_DATA]; /* list of x,y,w triplets for the memory elements */
402 UINT32 base; /* current base address */
403 UINT32 address; /* current cursor address */
404 UINT32 pgm_memory_base; /* program/data memory base toggle */
405 INT32 offset; /* edit offset */
406 INT32 nibble; /* edit nibble */
407 INT32 bytes; /* number of bytes per edit line */
408 INT32 width; /* width in nibbles of the edit line */
409 INT32 size; /* number of bytes in the edit window */
410 UINT8 mode; /* 0 bytes, 1 words, 2 dword */
411 UINT8 ascii; /* display ASCII values */
412 UINT8 internal; /* display CPU internal memory instead of ROM/RAM? */
413 UINT8 changed;
414 } s_mem;
415
416 /****************************************************************************
417 * Disassembly structure
418 ****************************************************************************/
419 typedef struct {
420 UINT32 pc_cpu; /* The CPUs PC */
421 UINT32 pc_top; /* Top of the disassembly window PC */
422 UINT32 pc_cur; /* Cursor PC */
423 UINT32 pc_end; /* End of the disassembly window PC */
424 UINT32 dst_ea_value; /* effective destination address or value */
425 INT32 dst_ea_access; /* destination access mode */
426 INT32 dst_ea_size; /* destination access size */
427 UINT32 src_ea_value; /* effective source address or value */
428 INT32 src_ea_access; /* source access mode */
429 INT32 src_ea_size; /* source access size */
430 } s_dasm;
431
432 /****************************************************************************
433 * Tracing structure
434 ****************************************************************************/
435 typedef struct {
436 UINT32 last_pc[MAX_LOOPS];
437 UINT8 regs[MAX_REGS];
438 FILE *file;
439 INT32 iters;
440 INT32 loops;
441 } s_trace;
442
443 /****************************************************************************
444 * Debugger structure. There is one instance per CPU
445 ****************************************************************************/
446 typedef struct {
447 UINT32 ignore; /* ignore this CPU while debugging? */
448 UINT32 next_pc;
449 UINT32 prev_sp;
450
451 /* Break- and Watchpoints */
452 UINT32 brk_exec; /* execution breakpoint (program counter) */
453 UINT32 brk_exec_times; /* how many times to ignore the breakpoint */
454 UINT32 brk_exec_reset; /* reset value for times once it counted down */
455 UINT32 brk_data; /* data watchpoint (memory address) */
456 UINT32 brk_data_oldval; /* old data watchpoint value */
457 UINT32 brk_data_newval; /* expected new value (INVALID: always break) */
458 UINT32 brk_regs; /* register watchpoint (register ID) */
459 UINT32 brk_regs_oldval; /* old register watchpoint value */
460 UINT32 brk_regs_newval; /* expected new value (INVALID: always break) */
461 UINT32 brk_regs_mask; /* mask register value before comparing */
462 UINT32 brk_temp; /* temporary execution breakpoint */
463
464 s_regs regs;
465 s_dasm dasm;
466 s_mem mem[MAX_MEM];
467 s_trace trace;
468 INT32 hist_cnt;
469 s_hist hist[MAX_HIST];
470
471 char cmdline[80+1];
472 UINT8 window; /* edit what: cmds, regs, dasm, mem1, mem2 */
473
474 } s_dbg;
475
476 static s_dbg dbg[MAX_CPU];
477
478 /* Covenience macros... keep the code readable */
479 #define DBG dbg[active_cpu]
480 #define DBGREGS dbg[active_cpu].regs
481 #define DBGDASM dbg[active_cpu].dasm
482 #define DBGMEM dbg[active_cpu].mem
483 #define TRACE dbg[tracecpu].trace
484
485 #define CMD dbg[active_cpu].cmdline
486
487 /****************************************************************************
488 * Graphics output using debug_bitmap
489 ****************************************************************************/
490
491 static int cursor_x, cursor_y, cursor_on;
492
493 /* This will be intialized depending on the game framerate */
494 static int dbg_key_repeat = 4;
495
496 UINT8 debugger_idle;
497
498 UINT8 debugger_palette[] = {
499 0x00,0x00,0x00, /* black */
500 0x00,0x00,0x7f, /* blue */
501 0x00,0x7f,0x00, /* green */
502 0x00,0x7f,0x7f, /* cyan */
503 0x7f,0x00,0x00, /* red */
504 0x7f,0x00,0x7f, /* magenta */
505 0x7f,0x7f,0x00, /* brown */
506 0x7f,0x7f,0x7f, /* ltgray */
507 0x5f,0x5f,0x5f, /* dkgray */
508 0x00,0x00,0xff, /* ltblue */
509 0x00,0xff,0x00, /* ltgreen */
510 0x00,0xff,0xff, /* ltcyan */
511 0xff,0x00,0x00, /* ltred */
512 0xff,0x00,0xff, /* ltmagenta */
513 0xff,0xff,0x00, /* yellow */
514 0xff,0xff,0xff /* white */
515 };
516
517
518 #include "dbgfonts/m0813fnt.c"
519
520 struct GfxElement *build_debugger_font(void)
521 {
522 struct GfxElement *font;
523
524 switch_ui_orientation(NULL);
525
526 font = decodegfx(fontdata,&fontlayout);
527
528 if (font)
529 {
530 font->colortable = Machine->debug_remapped_colortable;
531 font->total_colors = DEBUGGER_TOTAL_COLORS*DEBUGGER_TOTAL_COLORS;
532 }
533
534 switch_true_orientation(NULL);
535
536 return font;
537 }
538
539 static void toggle_cursor(struct mame_bitmap *bitmap, struct GfxElement *font)
540 {
541 int sx, sy, x, y;
542 int saved_depth = Machine->color_depth;
543
544 /* ASG: this allows the debug bitmap to be a different depth than the screen */
545 Machine->color_depth = bitmap->depth;
546 switch_ui_orientation(bitmap);
547 sx = cursor_x * font->width;
548 sy = cursor_y * font->height;
549 for (y = 0; y < font->height; y++)
550 {
551 for (x = 0; x < font->width; x++)
552 {
553 int i;
554 int pen = read_pixel(bitmap, sx+x, sy+y);
555 for (i = 0;i < DEBUGGER_TOTAL_COLORS;i++)
556 {
557 if (pen == Machine->debug_pens[i])
558 {
559 pen = Machine->debug_pens[DEBUGGER_TOTAL_COLORS-1 - i];
560 break;
561 }
562 }
563 plot_pixel(bitmap, sx+x, sy+y, pen);
564 }
565 }
566 Machine->color_depth = saved_depth;
567 switch_true_orientation(bitmap);
568 cursor_on ^= 1;
569 }
570
571 void dbg_put_screen_char(int ch, int attr, int x, int y)
572 {
573 struct mame_bitmap *bitmap = Machine->debug_bitmap;
574 struct GfxElement *font = Machine->debugger_font;
575
576 switch_ui_orientation(bitmap);
577 drawgfx(bitmap, font,
578 ch, attr, 0, 0, x*font->width, y*font->height,
579 0, TRANSPARENCY_NONE, 0);
580 switch_true_orientation(bitmap);
581 }
582
583 static void set_screen_curpos(int x, int y)
584 {
585 cursor_x = x;
586 cursor_y = y;
587 }
588
589 static void get_screen_size( unsigned *width, unsigned *height )
590 {
591 *width = Machine->debug_bitmap->width / Machine->debugger_font->width;
592 *height = Machine->debug_bitmap->height / Machine->debugger_font->height;
593 }
594
595 static int readkey(void)
596 {
597 int i, k;
598 int cursor_flash = 0;
599
600 i = 0;
601 debugger_idle = 0;
602 do
603 {
604 if ((cursor_flash++ & 15) == 0)
605 toggle_cursor(Machine->debug_bitmap, Machine->debugger_font);
606 reset_partial_updates();
607 draw_screen(); /* so we can change stuff in RAM and see the effect on screen */
608 update_video_and_audio();
609
610 k = KEYCODE_NONE;
611 if (keyboard_pressed_memory_repeat(KEYCODE_A,dbg_key_repeat)) k = KEYCODE_A;
612 if (keyboard_pressed_memory_repeat(KEYCODE_B,dbg_key_repeat)) k = KEYCODE_B;
613 if (keyboard_pressed_memory_repeat(KEYCODE_C,dbg_key_repeat)) k = KEYCODE_C;
614 if (keyboard_pressed_memory_repeat(KEYCODE_D,dbg_key_repeat)) k = KEYCODE_D;
615 if (keyboard_pressed_memory_repeat(KEYCODE_E,dbg_key_repeat)) k = KEYCODE_E;
616 if (keyboard_pressed_memory_repeat(KEYCODE_F,dbg_key_repeat)) k = KEYCODE_F;
617 if (keyboard_pressed_memory_repeat(KEYCODE_G,dbg_key_repeat)) k = KEYCODE_G;
618 if (keyboard_pressed_memory_repeat(KEYCODE_H,dbg_key_repeat)) k = KEYCODE_H;
619 if (keyboard_pressed_memory_repeat(KEYCODE_I,dbg_key_repeat)) k = KEYCODE_I;
620 if (keyboard_pressed_memory_repeat(KEYCODE_J,dbg_key_repeat)) k = KEYCODE_J;
621 if (keyboard_pressed_memory_repeat(KEYCODE_K,dbg_key_repeat)) k = KEYCODE_K;
622 if (keyboard_pressed_memory_repeat(KEYCODE_L,dbg_key_repeat)) k = KEYCODE_L;
623 if (keyboard_pressed_memory_repeat(KEYCODE_M,dbg_key_repeat)) k = KEYCODE_M;
624 if (keyboard_pressed_memory_repeat(KEYCODE_N,dbg_key_repeat)) k = KEYCODE_N;
625 if (keyboard_pressed_memory_repeat(KEYCODE_O,dbg_key_repeat)) k = KEYCODE_O;
626 if (keyboard_pressed_memory_repeat(KEYCODE_P,dbg_key_repeat)) k = KEYCODE_P;
627 if (keyboard_pressed_memory_repeat(KEYCODE_Q,dbg_key_repeat)) k = KEYCODE_Q;
628 if (keyboard_pressed_memory_repeat(KEYCODE_R,dbg_key_repeat)) k = KEYCODE_R;
629 if (keyboard_pressed_memory_repeat(KEYCODE_S,dbg_key_repeat)) k = KEYCODE_S;
630 if (keyboard_pressed_memory_repeat(KEYCODE_T,dbg_key_repeat)) k = KEYCODE_T;
631 if (keyboard_pressed_memory_repeat(KEYCODE_U,dbg_key_repeat)) k = KEYCODE_U;
632 if (keyboard_pressed_memory_repeat(KEYCODE_V,dbg_key_repeat)) k = KEYCODE_V;
633 if (keyboard_pressed_memory_repeat(KEYCODE_W,dbg_key_repeat)) k = KEYCODE_W;
634 if (keyboard_pressed_memory_repeat(KEYCODE_X,dbg_key_repeat)) k = KEYCODE_X;
635 if (keyboard_pressed_memory_repeat(KEYCODE_Y,dbg_key_repeat)) k = KEYCODE_Y;
636 if (keyboard_pressed_memory_repeat(KEYCODE_Z,dbg_key_repeat)) k = KEYCODE_Z;
637 if (keyboard_pressed_memory_repeat(KEYCODE_0,dbg_key_repeat)) k = KEYCODE_0;
638 if (keyboard_pressed_memory_repeat(KEYCODE_1,dbg_key_repeat)) k = KEYCODE_1;
639 if (keyboard_pressed_memory_repeat(KEYCODE_2,dbg_key_repeat)) k = KEYCODE_2;
640 if (keyboard_pressed_memory_repeat(KEYCODE_3,dbg_key_repeat)) k = KEYCODE_3;
641 if (keyboard_pressed_memory_repeat(KEYCODE_4,dbg_key_repeat)) k = KEYCODE_4;
642 if (keyboard_pressed_memory_repeat(KEYCODE_5,dbg_key_repeat)) k = KEYCODE_5;
643 if (keyboard_pressed_memory_repeat(KEYCODE_6,dbg_key_repeat)) k = KEYCODE_6;
644 if (keyboard_pressed_memory_repeat(KEYCODE_7,dbg_key_repeat)) k = KEYCODE_7;
645 if (keyboard_pressed_memory_repeat(KEYCODE_8,dbg_key_repeat)) k = KEYCODE_8;
646 if (keyboard_pressed_memory_repeat(KEYCODE_9,dbg_key_repeat)) k = KEYCODE_9;
647 if (keyboard_pressed_memory_repeat(KEYCODE_0_PAD,dbg_key_repeat)) k = KEYCODE_0_PAD;
648 if (keyboard_pressed_memory_repeat(KEYCODE_1_PAD,dbg_key_repeat)) k = KEYCODE_1_PAD;
649 if (keyboard_pressed_memory_repeat(KEYCODE_2_PAD,dbg_key_repeat)) k = KEYCODE_2_PAD;
650 if (keyboard_pressed_memory_repeat(KEYCODE_3_PAD,dbg_key_repeat)) k = KEYCODE_3_PAD;
651 if (keyboard_pressed_memory_repeat(KEYCODE_4_PAD,dbg_key_repeat)) k = KEYCODE_4_PAD;
652 if (keyboard_pressed_memory_repeat(KEYCODE_5_PAD,dbg_key_repeat)) k = KEYCODE_5_PAD;
653 if (keyboard_pressed_memory_repeat(KEYCODE_6_PAD,dbg_key_repeat)) k = KEYCODE_6_PAD;
654 if (keyboard_pressed_memory_repeat(KEYCODE_7_PAD,dbg_key_repeat)) k = KEYCODE_7_PAD;
655 if (keyboard_pressed_memory_repeat(KEYCODE_8_PAD,dbg_key_repeat)) k = KEYCODE_8_PAD;
656 if (keyboard_pressed_memory_repeat(KEYCODE_9_PAD,dbg_key_repeat)) k = KEYCODE_9_PAD;
657 if (keyboard_pressed_memory(KEYCODE_F1)) k = KEYCODE_F1;
658 if (keyboard_pressed_memory(KEYCODE_F2)) k = KEYCODE_F2;
659 if (keyboard_pressed_memory(KEYCODE_F3)) k = KEYCODE_F3;
660 if (keyboard_pressed_memory(KEYCODE_F4)) k = KEYCODE_F4;
661 /* if (keyboard_pressed_memory(KEYCODE_F5)) k = KEYCODE_F5; */
662 if (keyboard_pressed_memory(KEYCODE_F6)) k = KEYCODE_F6;
663 if (keyboard_pressed_memory(KEYCODE_F7)) k = KEYCODE_F7;
664 if (keyboard_pressed_memory(KEYCODE_F8)) k = KEYCODE_F8;
665 if (keyboard_pressed_memory(KEYCODE_F9)) k = KEYCODE_F9;
666 if (keyboard_pressed_memory(KEYCODE_F10)) k = KEYCODE_F10;
667 if (keyboard_pressed_memory(KEYCODE_F11)) k = KEYCODE_F11;
668 if (keyboard_pressed_memory(KEYCODE_F12)) k = KEYCODE_F12;
669 if (keyboard_pressed_memory(KEYCODE_ESC)) k = KEYCODE_ESC;
670 /* if (keyboard_pressed_memory_repeat(KEYCODE_TILDE,dbg_key_repeat)) k = KEYCODE_TILDE; */
671 if (keyboard_pressed_memory_repeat(KEYCODE_MINUS,dbg_key_repeat)) k = KEYCODE_MINUS;
672 if (keyboard_pressed_memory_repeat(KEYCODE_EQUALS,dbg_key_repeat)) k = KEYCODE_EQUALS;
673 if (keyboard_pressed_memory_repeat(KEYCODE_BACKSPACE,dbg_key_repeat)) k = KEYCODE_BACKSPACE;
674 if (keyboard_pressed_memory_repeat(KEYCODE_TAB,dbg_key_repeat)) k = KEYCODE_TAB;
675 if (keyboard_pressed_memory_repeat(KEYCODE_OPENBRACE,dbg_key_repeat)) k = KEYCODE_OPENBRACE;
676 if (keyboard_pressed_memory_repeat(KEYCODE_CLOSEBRACE,dbg_key_repeat)) k = KEYCODE_CLOSEBRACE;
677 if (keyboard_pressed_memory_repeat(KEYCODE_ENTER,dbg_key_repeat)) k = KEYCODE_ENTER;
678 if (keyboard_pressed_memory_repeat(KEYCODE_COLON,dbg_key_repeat)) k = KEYCODE_COLON;
679 if (keyboard_pressed_memory_repeat(KEYCODE_QUOTE,dbg_key_repeat)) k = KEYCODE_QUOTE;
680 if (keyboard_pressed_memory_repeat(KEYCODE_BACKSLASH,dbg_key_repeat)) k = KEYCODE_BACKSLASH;
681 if (keyboard_pressed_memory_repeat(KEYCODE_BACKSLASH2,dbg_key_repeat)) k = KEYCODE_BACKSLASH2;
682 if (keyboard_pressed_memory_repeat(KEYCODE_COMMA,dbg_key_repeat)) k = KEYCODE_COMMA;
683 if (keyboard_pressed_memory_repeat(KEYCODE_STOP,dbg_key_repeat)) k = KEYCODE_STOP;
684 if (keyboard_pressed_memory_repeat(KEYCODE_SLASH,dbg_key_repeat)) k = KEYCODE_SLASH;
685 if (keyboard_pressed_memory_repeat(KEYCODE_SPACE,dbg_key_repeat)) k = KEYCODE_SPACE;
686 if (keyboard_pressed_memory_repeat(KEYCODE_INSERT,dbg_key_repeat)) k = KEYCODE_INSERT;
687 if (keyboard_pressed_memory_repeat(KEYCODE_DEL,dbg_key_repeat)) k = KEYCODE_DEL;
688 if (keyboard_pressed_memory_repeat(KEYCODE_HOME,dbg_key_repeat)) k = KEYCODE_HOME;
689 if (keyboard_pressed_memory_repeat(KEYCODE_END,dbg_key_repeat)) k = KEYCODE_END;
690 if (keyboard_pressed_memory_repeat(KEYCODE_PGUP,dbg_key_repeat)) k = KEYCODE_PGUP;
691 if (keyboard_pressed_memory_repeat(KEYCODE_PGDN,dbg_key_repeat)) k = KEYCODE_PGDN;
692 if (keyboard_pressed_memory_repeat(KEYCODE_LEFT,dbg_key_repeat)) k = KEYCODE_LEFT;
693 if (keyboard_pressed_memory_repeat(KEYCODE_RIGHT,dbg_key_repeat)) k = KEYCODE_RIGHT;
694 if (keyboard_pressed_memory_repeat(KEYCODE_UP,dbg_key_repeat)) k = KEYCODE_UP;
695 if (keyboard_pressed_memory_repeat(KEYCODE_DOWN,dbg_key_repeat)) k = KEYCODE_DOWN;
696 if (keyboard_pressed_memory_repeat(KEYCODE_SLASH_PAD,dbg_key_repeat)) k = KEYCODE_SLASH_PAD;
697 if (keyboard_pressed_memory_repeat(KEYCODE_ASTERISK,dbg_key_repeat)) k = KEYCODE_ASTERISK;
698 if (keyboard_pressed_memory_repeat(KEYCODE_MINUS_PAD,dbg_key_repeat)) k = KEYCODE_MINUS_PAD;
699 if (keyboard_pressed_memory_repeat(KEYCODE_PLUS_PAD,dbg_key_repeat)) k = KEYCODE_PLUS_PAD;
700 /* if (keyboard_pressed_memory_repeat(KEYCODE_DEL_PAD,dbg_key_repeat)) k = KEYCODE_DEL_PAD; */
701 /* if (keyboard_pressed_memory_repeat(KEYCODE_ENTER_PAD,dbg_key_repeat)) k = KEYCODE_ENTER_PAD; */
702 /* if (keyboard_pressed_memory(KEYCODE_PRTSCR)) k = KEYCODE_PRTSCR; */
703 /* if (keyboard_pressed_memory(KEYCODE_PAUSE)) k = KEYCODE_PAUSE; */
704 /* if (keyboard_pressed_memory(KEYCODE_SCRLOCK)) k = KEYCODE_SCRLOCK; */
705 /* if (keyboard_pressed_memory(KEYCODE_NUMLOCK)) k = KEYCODE_NUMLOCK; */
706 /* if (keyboard_pressed_memory(KEYCODE_CAPSLOCK)) k = KEYCODE_CAPSLOCK; */
707 /* if (keyboard_pressed(KEYCODE_LWIN)) k = KEYCODE_LWIN; */
708 /* if (keyboard_pressed(KEYCODE_RWIN)) k = KEYCODE_RWIN; */
709 /* if (keyboard_pressed(KEYCODE_MENU)) k = KEYCODE_MENU; */
710
711 if (k == KEYCODE_NONE)
712 debugger_idle = 1;
713
714 } while (k == KEYCODE_NONE);
715 debugger_idle = 0;
716 if (cursor_on)
717 toggle_cursor(Machine->debug_bitmap, Machine->debugger_font);
718
719 return k;
720 }
721
722
723
724
725
726 /****************************************************************************
727 * Tracing
728 ****************************************************************************/
729 static int tracecpu = 0;
730 static int trace_on = 0;
731
732 /****************************************************************************
733 * Commands structure
734 ****************************************************************************/
735 typedef struct {
736 int valid; /* command is valid for which windows (bit mask) */
737 const char *name; /* command name (NULL none) */
738 const char *alias; /* command name alias (NULL none) */
739 int key; /* key code (0 none) */
740 const char *args; /* description of expected arguments */
741 const char *info; /* description of the function */
742 void (*function)(void); /* function handling the key/command */
743 } s_command;
744
745 #define ALL ((1<<EDIT_CMDS)|(1<<EDIT_REGS)|(1<<EDIT_DASM)|(1<<EDIT_MEM1)|(1<<EDIT_MEM2))
746
747 static s_command commands[] = {
748 { (1<<EDIT_CMDS),
749 "A", 0, CODE_NONE,
750 "[<update>]",
751 "Animate (trace) and update display once per frame [or every <update> opcodes only]",
752 cmd_animate },
753 { (1<<EDIT_CMDS),
754 "D", 0, CODE_NONE,
755 "<1|2> <address>",
756 "Display memory <1|2> starting at <address>",
757 cmd_display_memory },
758 { (1<<EDIT_CMDS),
759 "E", 0, CODE_NONE,
760 "<1|2> [<address>]",
761 "Edit memory window <1|2> [at <address>]",
762 cmd_edit_memory },
763 { (1<<EDIT_CMDS),
764 "M", 0, CODE_NONE,
765 "<1|2> [BYTE|WORD|DWORD]",
766 "Change memory window mode to default [to BYTE|WORD|DWORD (or 0|1|2)]",
767 cmd_set_memory_mode },
768 { (1<<EDIT_CMDS),
769 "F", 0, CODE_NONE,
770 "",
771 "Fast",
772 cmd_fast },
773 { (1<<EDIT_CMDS),
774 "G", 0, CODE_NONE,
775 "[<address>]",
776 "Go [and break at <address>]",
777 cmd_go_break },
778 { (1<<EDIT_CMDS),
779 "J", 0, CODE_NONE,
780 "<address>",
781 "Jump to <address> in disassembly window",
782 cmd_jump },
783 { (1<<EDIT_CMDS),
784 "R", 0, CODE_NONE,
785 "<register> <value>",
786 "Replace <register> with <value> (<value> may also be a <register>)",
787 cmd_replace_register },
788 { (1<<EDIT_CMDS),
789 "BP", "BPX", CODE_NONE,
790 "<address> [<times>]",
791 "Break on execution of <address> [after ignoring it <times>]",
792 cmd_brk_exec_set },
793 { (1<<EDIT_CMDS),
794 "BC", 0, CODE_NONE,
795 "",
796 "Clear execution breakpoint",
797 cmd_brk_exec_clear },
798 { (1<<EDIT_CMDS),
799 "RP", 0, CODE_NONE,
800 "<register> [<value> [<mask>]]",
801 "Break if <register> changes [to <value> [compare after applying <mask>]]",
802 cmd_brk_regs_set },
803 { (1<<EDIT_CMDS),
804 "RC", 0, CODE_NONE,
805 "",
806 "Clear register watchpoint",
807 cmd_brk_regs_clear },
808 { (1<<EDIT_CMDS),
809 "WP", "BPW", CODE_NONE,
810 "<address> [<value>]",
811 "Break if data at <address> changes [to <value>]",
812 cmd_brk_data_set },
813 { (1<<EDIT_CMDS),
814 "WC", 0, CODE_NONE,
815 "",
816 "Clear data watchpoint",
817 cmd_brk_data_clear },
818 { (1<<EDIT_CMDS),
819 "HERE", 0, CODE_NONE,
820 "",
821 "Run to cursor",
822 cmd_here },
823 { (1<<EDIT_CMDS),
824 "DASM", 0, CODE_NONE,
825 "<filename> <start> <end> [<boolean>]",
826 "Disassemble to <filename> from address <start> to <end>\n" \
827 "Opcode dump on by default [OFF|NO|0 without]",
828 cmd_dasm_to_file },
829 { (1<<EDIT_CMDS),
830 "DUMP", 0, CODE_NONE,
831 "<filename> <start> <end> [<data size> [<ASCII mode> [<prog/data memory>]]]",
832 "Dump to <filename> from address <start> to <end>\n" \
833 "[data size BYTE|WORD|DWORD (also 0|1|2)]\n" \
834 "[ASCII mode OFF|TRANSLATE|FULL (also 0|1|2)]\n" \
835 "[PROG or DATA memory (also 0|1) for CPUs supporting it]\n",
836 cmd_dump_to_file },
837 { (1<<EDIT_CMDS),
838 "TRACE", 0, CODE_NONE,
839 "{<filename> [<reg1> [<reg2>...]]}|OFF",
840 "Trace to <filename> [dumping <reg1> [<reg2>...]] | OFF to stop tracing.",
841 cmd_trace_to_file },
842 { (1<<EDIT_CMDS),
843 "SAVE", 0, CODE_NONE,
844 "<filename> <start> <end> [OPCODES|DATA]",
845 "Save binary to <filename> from address <start> to <end>\n" \
846 "[either OPCODES (from OP_ROM, default) or DATA (from OP_RAM), also 0|1].",
847 cmd_save_to_file },
848 { (1<<EDIT_CMDS),
849 "IGNORE", 0, CODE_NONE,
850 "<cpunum>",
851 "Ignore CPU #<cpunum> while debugging or tracing",
852 cmd_set_ignore },
853 { (1<<EDIT_CMDS),
854 "OBSERVE", 0, CODE_NONE,
855 "<cpunum>",
856 "Observe CPU #<cpunum> while debugging or tracing",
857 cmd_set_observe },
858 { (1<<EDIT_CMDS),
859 "REPEAT", 0, CODE_NONE,
860 "rate",
861 "Set keyboard initial repeat rate (rate/frame will increase to 1/frame)",
862 cmd_set_key_repeat },
863 { (1<<EDIT_CMDS),
864 "CASE", 0, CODE_NONE,
865 "DEFAULT|LOWER|UPPER (also 0|1|2)",
866 "Set disassembly case style.",
867 cmd_set_dasm_case },
868 { (1<<EDIT_CMDS),
869 "OPCODES", 0, CODE_NONE,
870 "<boolean>",
871 "Display opcodes in disassembly window",
872 cmd_set_dasm_opcodes },
873 { (1<<EDIT_CMDS),
874 "RELATIVE", 0, CODE_NONE,
875 "<boolean>",
876 "Display relative jump addresses in disassembly window",
877 cmd_set_dasm_relative_jumps },
878 { (1<<EDIT_CMDS),
879 "SQUEEZE", 0, CODE_NONE,
880 "<boolean>",
881 "Allow squeezed memory display",
882 cmd_set_mem_squeezed },
883 { (1<<EDIT_CMDS),
884 "COLOR", 0, CODE_NONE,
885 "<element> <foreground> [<background>]",
886 "Set <element> color to <foreground> on BLACK [or <background>].\nFor a list of <elements> and <colors> see mamedbg.cfg",
887 cmd_set_element_color },
888 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
889 0, 0, KEYCODE_UP,
890 "",
891 "Move cursor up in disassembly window",
892 cmd_dasm_up },
893 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
894 0, 0, KEYCODE_DOWN,
895 "",
896 "Move cursor down in disassembly window",
897 cmd_dasm_down },
898 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
899 0, 0, KEYCODE_PGUP,
900 "",
901 "Move cursor up one page in disassembly window",
902 cmd_dasm_page_up },
903 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
904 0, 0, KEYCODE_PGDN,
905 "",
906 "Move cursor down one page in disassembly window",
907 cmd_dasm_page_down },
908 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
909 0, 0, KEYCODE_HOME,
910 "",
911 "Move cursor to first page in disassembly window",
912 cmd_dasm_home },
913 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
914 0, 0, KEYCODE_END,
915 "",
916 "Move cursor to last page in disassembly window",
917 cmd_dasm_end },
918 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
919 0, 0, KEYCODE_LEFT,
920 "",
921 "Back to the previous point in 'follow history'",
922 cmd_dasm_hist_back },
923 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
924 0, 0, KEYCODE_RIGHT,
925 "",
926 "Follow the current instruction's code or data reference",
927 cmd_dasm_hist_follow },
928 { ALL,
929 0, 0, KEYCODE_TAB,
930 "",
931 "Switch between windows (backwards SHIFT+TAB)",
932 cmd_switch_window },
933 { (1<<EDIT_DASM),
934 0, 0, KEYCODE_D,
935 "",
936 "Change disassembly case style to default",
937 NULL },
938 { (1<<EDIT_DASM),
939 0, 0, KEYCODE_L,
940 "",
941 "Change disassembly case style to lower case",
942 NULL },
943 { (1<<EDIT_DASM),
944 0, 0, KEYCODE_U,
945 "",
946 "Change disassembly case style to upper case",
947 NULL },
948 { (1<<EDIT_DASM),
949 0, 0, KEYCODE_M,
950 "",
951 "Toggle disassembly opcode display mode",
952 NULL },
953 { (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
954 0, 0, KEYCODE_H,
955 "",
956 "Toggle between hex, ASCII and full character set mode",
957 NULL },
958 { (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
959 0, 0, KEYCODE_P,
960 "",
961 "Toggle memory display between DATA and PROGRAM memory (Harvard-architecture CPUs)",
962 NULL },
963 { (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
964 0, 0, KEYCODE_I,
965 "",
966 "Toggle memory display between CPU internal and normal memory",
967 NULL },
968 { (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
969 0, 0, KEYCODE_M,
970 "",
971 "Switch memory display mode between bytes, words and dwords",
972 NULL },
973 { (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
974 0, 0, KEYCODE_S,
975 "",
976 "Search memory for a sequence of bytes",
977 cmd_search_memory },
978 { ALL,
979 0, 0, KEYCODE_F1,
980 "",
981 "Help - maybe you realized this ;)",
982 cmd_help },
983 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
984 0, 0, KEYCODE_F2,
985 "",
986 "Toggle breakpoint at current cursor position",
987 cmd_brk_exec_toggle },
988 { (1<<EDIT_CMDS)|(1<<EDIT_DASM),
989 0, 0, KEYCODE_F4,
990 "",
991 "Run to cursor",
992 cmd_run_to_cursor },
993 { (1<<EDIT_MEM1)|(1<<EDIT_MEM2),
994 0, 0, KEYCODE_F4,
995 "",
996 "Set data watchpoint to current memory location",
997 cmd_brk_data_toggle },
998 { ALL,
999 0, 0, KEYCODE_F6,
1000 "",
1001 "Set the focus to the next (not ignored) CPU",
1002 cmd_focus_next_cpu },
1003 { ALL,
1004 0, 0, KEYCODE_F8,
1005 "",
1006 "Step one instruction",
1007 cmd_step },
1008 { ALL,
1009 0, 0, KEYCODE_F9,
1010 "",
1011 "Animate (trace) at speed set by last \"A\" command",
1012 cmd_animate },
1013 { ALL,
1014 0, 0, KEYCODE_F10,
1015 "",
1016 "Step over instruction at cursor (ie. execute call, jsr or bsr)",
1017 cmd_step_over },
1018 { ALL,
1019 0, 0, KEYCODE_F12,
1020 "",
1021 "Go!",
1022 cmd_go },
1023 { ALL,
1024 0, 0, KEYCODE_ESC,
1025 "",
1026 "Go!",
1027 cmd_go },
1028 /* This is the end of the list! */
1029 { 0, },
1030 };
1031
1032 INLINE unsigned order( unsigned offset, unsigned size )
1033 {
1034 switch( size )
1035 {
1036 case 1:
1037 return offset;
1038 break;
1039 case 2:
1040 switch( ENDIAN )
1041 {
1042 case CPU_IS_LE: return UINT16_XOR_LE(offset);
1043 case CPU_IS_BE: return UINT16_XOR_BE(offset);
1044 }
1045 break;
1046 case 4:
1047 switch( ENDIAN )
1048 {
1049 case CPU_IS_LE: return UINT32_XOR_LE(offset);
1050 case CPU_IS_BE: return UINT32_XOR_BE(offset);
1051 }
1052 break;
1053 }
1054 return offset;
1055 }
1056
1057 /* adjust an offset by shifting it left activecpu_address_shift() times */
1058 INLINE unsigned lshift( unsigned offset )
1059 {
1060 switch( ASHIFT )
1061 {
1062 case -1: return offset / 2;
1063 case 3: return offset * 8;
1064 }
1065 return offset;
1066 }
1067
1068 /* adjust an offset by shifting it right activecpu_address_shift() times */
1069 INLINE unsigned rshift( unsigned offset )
1070 {
1071 switch( ASHIFT )
1072 {
1073 case -1: return offset * 2;
1074 case 3: return offset / 8;
1075 }
1076 return offset;
1077 }
1078
1079
1080 /**************************************************************************
1081 * dtou
1082 * Decimal to unsigned.
1083 * The pointer to the char* is placed after all consecutive digits
1084 * and trailing space. The pointer to int size (if given) contains the
1085 * number of digits found.
1086 **************************************************************************/
1087 INLINE unsigned dtou( char **parg, int *size)
1088 {
1089 unsigned val = 0, digit;
1090
1091 if (size) *size = 0;
1092 while( isdigit( *(*parg) ) )
1093 {
1094 digit = *(*parg) - '0';
1095 val = (val * 10) + digit;
1096 if( size ) (*size)++;
1097 (*parg) += 1;
1098 }
1099 while( isspace(*(*parg)) ) *parg += 1;
1100 return val;
1101 }
1102
1103 /**************************************************************************
1104 * xtou
1105 * Hex to unsigned.
1106 * The pointer to the char* is placed after all consecutive hex digits
1107 * and trailing space. The pointer to int size (if given) contains the
1108 * number of digits found.
1109 **************************************************************************/
1110 INLINE unsigned xtou( char **parg, int *size)
1111 {
1112 unsigned val = 0, digit;
1113
1114 if (size) *size = 0;
1115 while( isxdigit( *(*parg) ) )
1116 {
1117 digit = toupper(*(*parg)) - '0';
1118 if( digit > 9 ) digit -= 7;
1119 val = (val << 4) | digit;
1120 if( size ) (*size)++;
1121 (*parg) += 1;
1122 }
1123 while( isspace(*(*parg)) ) *parg += 1;
1124 return val;
1125 }
1126
1127 const char *set_ea_info( int what, unsigned value, int size, int access )
1128 {
1129 static char buffer[8][63+1];
1130 static int which = 0;
1131 const char *sign = "";
1132 unsigned width, result;
1133
1134 which = (which+1) % 8;
1135
1136 if( access == EA_REL_PC )
1137 /* PC relative calls set_ea_info with value = PC and size = offset */
1138 result = value + size;
1139 else
1140 result = value;
1141
1142 /* set source EA? */
1143 if( what == EA_SRC )
1144 {
1145 DBGDASM.src_ea_access = access;
1146 DBGDASM.src_ea_value = result;
1147 DBGDASM.src_ea_size = size;
1148 }
1149 else
1150 if( what == EA_DST )
1151 {
1152 DBGDASM.dst_ea_access = access;
1153 DBGDASM.dst_ea_value = result;
1154 DBGDASM.dst_ea_size = size;
1155 }
1156 else
1157 {
1158 return "set_ea_info: invalid <what>!";
1159 }
1160
1161 switch( access )
1162 {
1163 case EA_VALUE: /* Immediate value */
1164 switch( size )
1165 {
1166 case EA_INT8:
1167 width = 2;
1168 result &= 0xff;
1169 if( result & 0x80 )
1170 {
1171 sign = "-";
1172 result = (unsigned)-result;
1173 }
1174 break;
1175 case EA_INT16:
1176 width = 4;
1177 result &= 0xffff;
1178 if( result & 0x8000 )
1179 {
1180 sign = "-";
1181 result = (unsigned)-result;
1182 }
1183 break;
1184 case EA_INT32:
1185 width = 8;
1186 if( result & 0x80000000 )
1187 {
1188 sign = "-";
1189 result = (unsigned)-result;
1190 }
1191 break;
1192 case EA_UINT8:
1193 width = 2;
1194 result &= 0xff;
1195 break;
1196 case EA_UINT16:
1197 width = 4;
1198 result &= 0xffff;
1199 break;
1200 case EA_UINT32:
1201 width = 8;
1202 break;
1203 default:
1204 return "set_ea_info: invalid <size>!";
1205 }
1206 break;
1207
1208 case EA_ZPG_RD:
1209 case EA_ZPG_WR:
1210 case EA_ZPG_RDWR:
1211 result &= 0xff;
1212 width = 2;
1213 break;
1214
1215 case EA_ABS_PC: /* Absolute program counter change */
1216 result &= AMASK;
1217 if( size == EA_INT8 || size == EA_UINT8 )
1218 width = 2;
1219 else
1220 if( size == EA_INT16 || size == EA_UINT16 )
1221 width = 4;
1222 else
1223 if( size == EA_INT32 || size == EA_UINT32 )
1224 width = 8;
1225 else
1226 width = (ABITS + 3) / 4;
1227 break;
1228
1229 case EA_REL_PC: /* Relative program counter change */
1230 if( dbg_dasm_relative_jumps )
1231 {
1232 if( size == 0 )
1233 return "$";
1234 if( size < 0 )
1235 {
1236 sign = "-";
1237 result = (unsigned) -size;
1238 }
1239 else
1240 {
1241 sign = "+";
1242 result = (unsigned) size;
1243 }
1244 sprintf( buffer[which], "$%s%u", sign, result );
1245 return buffer[which];
1246 }
1247 /* fall through */
1248 default:
1249 result &= AMASK;
1250 width = (ABITS + 3) / 4;
1251 }
1252 sprintf( buffer[which], "%s$%0*X", sign, width, result );
1253 return buffer[which];
1254 }
1255
1256 /**************************************************************************
1257 * lower
1258 * Convert string into all lower case.
1259 **************************************************************************/
1260 INLINE char *lower( const char *src)
1261 {
1262 static char buffer[127+1];
1263 char *dst = buffer;
1264 while( *src )
1265 *dst++ = tolower(*src++);
1266 *dst = '\0';
1267 return buffer;
1268 }
1269
1270 /**************************************************************************
1271 * upper
1272 * Convert string into all upper case.
1273 **************************************************************************/
1274 INLINE char *upper( const char *src)
1275 {
1276 static char buffer[127+1];
1277 char *dst = buffer;
1278 while( *src )
1279 *dst++ = toupper(*src++);
1280 *dst = '\0';
1281 return buffer;
1282 }
1283
1284 /**************************************************************************
1285 * kilobyte
1286 * Format a byte count or size to a kilo or mega bytes string
1287 **************************************************************************/
1288 INLINE char *kilobyte( unsigned bytes )
1289 {
1290 static char buffer[2][31+1];
1291 static int which = 0;
1292 char *dst = buffer[which];
1293 which ^= 1;
1294 if( bytes < 1024 )
1295 sprintf( dst, "%u", bytes );
1296 else
1297 if( bytes < 1024 * 1024 )
1298 sprintf( dst, "%u.%02uK", bytes / 1024, 100 * bytes / 1024 );
1299 else
1300 sprintf( dst, "%u.%02uM", bytes / 1024 / 1024, 100 * ((bytes / 1024) % 1024) / 1024 );
1301 return dst;
1302 }
1303
1304 /**************************************************************************
1305 * my_stricmp
1306 * Compare strings case insensitive
1307 **************************************************************************/
1308 INLINE int my_stricmp( const char *dst, const char *src)
1309 {
1310 while( *src && *dst )
1311 {
1312 if( tolower(*src) != tolower(*dst) ) return *dst - *src;
1313 src++;
1314 dst++;
1315 }
1316 return *dst - *src;
1317 }
1318
1319 /**************************************************************************
1320 * get_boolean
1321 * Get a boolean argument (on/off, yes/no, y/n, 1/0)
1322 **************************************************************************/
1323 static unsigned get_boolean( char **parg, int *size )
1324 {
1325 char *p = *parg;
1326 unsigned result = 0;
1327 int length = 0;
1328
1329 if( toupper(p[0]) == 'O' )
1330 {
1331 if( toupper(p[1]) == 'N' && !isalnum(p[2]) )
1332 {
1333 result = 1;
1334 length = 2;
1335 *parg += length;
1336 }
1337 else
1338 if( toupper(p[1]) == 'F' && toupper(p[2]) == 'F' && !isalnum(p[3]) )
1339 {
1340 result = 0;
1341 length = 3;
1342 *parg += length;
1343 }
1344 }
1345 else
1346 if( toupper(p[0]) == 'N' )
1347 {
1348 if( toupper(p[1]) == 'O' && !isalnum(p[2]) )
1349 {
1350 result = 0;
1351 length = 2;
1352 *parg += length;
1353 }
1354 else
1355 if( !isalnum(p[1]) )
1356 {
1357 result = 0;
1358 length = 1;
1359 *parg += length;
1360 }
1361 }
1362 else
1363 if( toupper(p[0]) == 'Y' )
1364 {
1365 if( toupper(p[1]) == 'E' && toupper(p[2]) == 'S' && !isalnum(p[3]) )
1366 {
1367 result = 1;
1368 length = 3;
1369 *parg += length;
1370 }
1371 else
1372 if( !isalnum(p[1]) )
1373 {
1374 result = 0;
1375 length = 1;
1376 *parg += length;
1377 }
1378 }
1379
1380 if( length )
1381 {
1382 while( isspace(*(*parg)) ) *parg += 1;
1383 }
1384 else
1385 {
1386 /* found nothing yet: assume numeric */
1387 result = xtou( parg, &length );
1388 }
1389
1390 if( size ) *size += length;
1391
1392 return result;
1393 }
1394
1395 /**************************************************************************
1396 * get_option_or_value
1397 * Get a option argument (from opt_list) or a number in the
1398 * range of 0 .. number of options - 1
1399 **************************************************************************/
1400 static unsigned get_option_or_value( char **parg, int *size, const char *opt_list )
1401 {
1402 char *p = *parg;
1403 const char *opt;
1404 unsigned result = 0, opt_count = 0;
1405 int length = 0;
1406
1407 /* length of the next argument */
1408 while( isalnum(*p) ) p++;
1409 length = (int) (p - *parg);
1410 while( isspace(*p) ) p++;
1411
1412 /* sacn options */
1413 for( opt = opt_list; *opt ; opt += strlen(opt) + 1 )
1414 {
1415 if( strncmp(*parg, opt, length) == 0 )
1416 {
1417 *parg = p;
1418 if( size ) *size = length;
1419 return opt_count;
1420 }
1421 opt_count++;
1422 }
1423
1424 result = xtou( parg, &length );
1425 if( size ) *size += length;
1426
1427 return result;
1428 }
1429
1430 static const char *get_file_name( char **parg, int *size )
1431 {
1432 static char filename[127+1];
1433 char *s, *d;
1434 int l;
1435
1436 for( l = 0, s = *parg, d = filename; *s && (isalnum(*s) || ispunct(*s)); l++ )
1437 *d++ = *s++;
1438
1439 *d = '\0';
1440 while( isspace(*s) ) s++;
1441 *parg = s;
1442
1443 if( size ) *size = l;
1444
1445 return filename;
1446 }
1447
1448 const char *get_ea_info( unsigned pc )
1449 {
1450 static char buffer[63+1];
1451 static char *access[EA_COUNT] =
1452 {
1453 "", /* no EA mode */
1454 "#", /* immediate */
1455 "=", /* absolute PC */
1456 "$", /* relative PC */
1457 "<", /* zero page memory read */
1458 ">", /* zero page memory write */
1459 "*", /* zero page memory modify */
1460 "<", /* memory read */
1461 ">", /* memory write */
1462 "*", /* memory modify */
1463 "P<", /* port read */
1464 "P>" /* port write */
1465 };
1466
1467 unsigned wdst, wsrc;
1468
1469 switch( DBGDASM.dst_ea_size )
1470 {
1471 case EA_INT8: wdst = 2; break;
1472 case EA_INT16: wdst = 4; break;
1473 case EA_INT32: wdst = 8; break;
1474 case EA_UINT8: wdst = 2; break;
1475 case EA_UINT16: wdst = 4; break;
1476 case EA_UINT32: wdst = 8; break;
1477 default:
1478 wdst = (ABITS + 3) / 4;
1479 }
1480
1481 switch( DBGDASM.src_ea_size )
1482 {
1483 case EA_INT8: wsrc = 2; break;
1484 case EA_INT16: wsrc = 4; break;
1485 case EA_INT32: wsrc = 8; break;
1486 case EA_UINT8: wsrc = 2; break;
1487 case EA_UINT16: wsrc = 4; break;
1488 case EA_UINT32: wsrc = 8; break;
1489 default:
1490 wsrc = (ABITS + 3) / 4;
1491 }
1492
1493 if( DBGDASM.dst_ea_value != INVALID && DBGDASM.src_ea_value != INVALID )
1494 sprintf( buffer, "%s\t%s%0*X %s%0*X",
1495 name_rdmem(rshift(pc)),
1496 access[DBGDASM.src_ea_access], wsrc, DBGDASM.src_ea_value,
1497 access[DBGDASM.dst_ea_access], wdst, DBGDASM.dst_ea_value );
1498 else
1499 if( DBGDASM.dst_ea_value != INVALID )
1500 sprintf( buffer, "%s\t%s%0*X",
1501 name_rdmem(rshift(pc)),
1502 access[DBGDASM.dst_ea_access], wdst, DBGDASM.dst_ea_value );
1503 else
1504 if( DBGDASM.src_ea_value != INVALID )
1505 sprintf( buffer, "%s\t%s%0*X",
1506 name_rdmem(rshift(pc)),
1507 access[DBGDASM.src_ea_access], wsrc, DBGDASM.src_ea_value );
1508 else
1509 sprintf( buffer, "%s", name_rdmem(rshift(pc)) );
1510
1511 return buffer;
1512 }
1513
1514 /**************************************************************************
1515 * get_register_id
1516 * Return the ID for a register if the string at *parg matches one
1517 * of the register names for the active cpu.
1518 **************************************************************************/
1519 static unsigned get_register_id( char **parg, int *size )
1520 {
1521 int i, l;
1522 for( i = 0; i < DBGREGS.count; i++ )
1523 {
1524 l = strlen( DBGREGS.name[i] );
1525 if( l > 0 && !strnicmp( *parg, DBGREGS.name[i], l ) )
1526 {
1527 if( !isalnum( (*parg)[l] ) )
1528 {
1529 if( size ) *size = l;
1530 *parg += l;
1531 while( isspace(*(*parg)) ) *parg += 1;
1532 return DBGREGS.id[i];
1533 }
1534 }
1535 }
1536 if( size ) *size = 0;
1537 return 0;
1538 }
1539
1540 /**************************************************************************
1541 * get_register_name
1542 * Get the name of a register with ID
1543 **************************************************************************/
1544 static const char *get_register_name( int id )
1545 {
1546 int i;
1547 for( i = 0; i < DBGREGS.count; i++ )
1548 {
1549 if( DBGREGS.id[i] == id )
1550 return DBGREGS.name[i];
1551 }
1552 return "??";
1553 }
1554
1555 /**************************************************************************
1556 * get_register_or_value
1557 * Return the value for a register if the string at *parg matches one
1558 * of the register names for the active cpu. Otherwise get a hex
1559 * value from *parg. In both cases set the pointer int size to the
1560 * length of the name or digits found (if size is not NULL)
1561 **************************************************************************/
1562 static unsigned get_register_or_value( char **parg, int *size )
1563 {
1564 int regnum, l;
1565
1566 regnum = get_register_id( parg, &l );
1567 if( regnum > 0 )
1568 {
1569 if( size ) *size = l;
1570 return activecpu_get_reg( regnum );
1571 }
1572 /* default to hex value */
1573 return xtou( parg, size );
1574 }
1575
1576 /**************************************************************************
1577 * trace_init
1578 * Creates trace output files for all CPUs
1579 * Resets the loop and iteration counters and the last PC array
1580 **************************************************************************/
1581 static void trace_init( const char *filename, UINT8 *regs )
1582 {
1583 char name[100];
1584
1585 if( trace_on )
1586 return;
1587
1588 for( tracecpu = 0; tracecpu < total_cpu; tracecpu++ )
1589 {
1590 sprintf( name, "%s.%d", filename, tracecpu );
1591 TRACE.file = fopen(name,"w");
1592 if( tracecpu == active_cpu )
1593 memcpy( TRACE.regs, regs, MAX_REGS );
1594 else
1595 TRACE.regs[0] = 0;
1596 TRACE.iters = 0;
1597 TRACE.loops = 0;
1598 memset(TRACE.last_pc, 0xff, sizeof(TRACE.last_pc));
1599 }
1600 tracecpu = active_cpu;
1601 trace_on = 1;
1602 }
1603
1604 /**************************************************************************
1605 * trace_done
1606 * Closes the trace output files
1607 **************************************************************************/
1608 void trace_done(void)
1609 {
1610 if( !trace_on )
1611 return;
1612
1613 for( tracecpu = 0; tracecpu < total_cpu; tracecpu++ )
1614 {
1615 if( TRACE.file )
1616 fclose( TRACE.file );
1617 TRACE.file = NULL;
1618 }
1619
1620 trace_on = 0;
1621 }
1622
1623 /**************************************************************************
1624 * trace_select
1625 * Switches tracing to the active CPU
1626 **************************************************************************/
1627 static void trace_select( void )
1628 {
1629 if( tracecpu == active_cpu )
1630 return;
1631 if( trace_on && TRACE.file )
1632 {
1633 if( TRACE.loops )
1634 {
1635 fprintf( TRACE.file,
1636 "\n (loops for %d instructions)\n\n",
1637 TRACE.loops );
1638 TRACE.loops = 0;
1639 }
1640 fprintf(TRACE.file,"\n=============== End of iteration #%d ===============\n\n",TRACE.iters++);
1641 fflush(TRACE.file);
1642 }
1643 if( active_cpu < total_cpu )
1644 tracecpu = active_cpu;
1645 }
1646
1647 /**************************************************************************
1648 * trace_output
1649 * Outputs the next disassembled instruction to the trace file
1650 * Loops are detected and a loop count is output after the
1651 * first repetition instead of disassembling the loop over and over
1652 **************************************************************************/
1653 static void trace_output( void )
1654 {
1655 static char buffer[127+1];
1656 char *dst = buffer;
1657
1658 if( trace_on && TRACE.file )
1659 {
1660 unsigned pc = activecpu_get_pc();
1661 unsigned addr_width = (ABITS + 3) / 4;
1662 int count, i;
1663
1664 /* check for trace_loops */
1665 for( i = count = 0; i < MAX_LOOPS; i++ )
1666 if( TRACE.last_pc[i] == pc )
1667 count++;
1668 if( count > 1 )
1669 {
1670 TRACE.loops++;
1671 }
1672 else
1673 {
1674 if( TRACE.loops )
1675 {
1676 dst += sprintf( dst,
1677 "\n (loops for %d instructions)\n\n",
1678 TRACE.loops );
1679 TRACE.loops = 0;
1680 }
1681 if( TRACE.regs[0] )
1682 {
1683 for( i = 0; i < MAX_REGS && TRACE.regs[i]; i++ )
1684 dst += sprintf( dst, "%s ", activecpu_dump_reg(TRACE.regs[i]) );
1685 }
1686 dst += sprintf( dst, "%0*X: ", addr_width, pc );
1687 activecpu_dasm( dst, pc );
1688 strcat( dst, "\n" );
1689 fprintf( TRACE.file, "%s", buffer );
1690 memmove(
1691 &TRACE.last_pc[0],
1692 &TRACE.last_pc[1],
1693 (MAX_LOOPS-1)*sizeof(TRACE.last_pc[0]) );
1694 TRACE.last_pc[MAX_LOOPS-1] = pc;
1695 }
1696 }
1697 }
1698
1699 /**************************************************************************
1700 * hit_brk_exec
1701 * Return non zero if execution breakpoint for the active_cpu,
1702 * the temporary breakpoint or the break on 'active_cpu' was hit
1703 **************************************************************************/
1704 static int hit_brk_exec(void)
1705 {
1706 static char dbg_info[63+1];
1707 UINT32 pc = activecpu_get_pc();
1708
1709 if( DBG.brk_temp != INVALID && DBG.brk_temp == pc )
1710 {
1711 sprintf( dbg_info, "Hit temp breakpoint at $%X", DBG.brk_temp);
1712 dbg_info_once = dbg_info;
1713 return 1;
1714 }
1715 if( DBG.brk_exec != INVALID && DBG.brk_exec == pc )
1716 {
1717 if( DBG.brk_exec_times > 0 )
1718 {
1719 if( --DBG.brk_exec_times == 0 )
1720 {
1721 sprintf( dbg_info, "Hit exec breakpoint %d times", DBG.brk_exec_reset);
1722 dbg_info_once = dbg_info;
1723 return 1;
1724 }
1725 return 0;
1726 }
1727 sprintf( dbg_info, "Hit exec breakpoint at $%X", DBG.brk_exec);
1728 dbg_info_once = dbg_info;
1729 return 1;
1730 }
1731
1732 return 0;
1733 }
1734
1735 /**************************************************************************
1736 * hit_brk_data
1737 * Return non zero if the data watchpoint for the active_cpu
1738 * was hit (ie. monitored data changed)
1739 **************************************************************************/
1740 static int hit_brk_data(void)
1741 {
1742 static char dbg_info[63+1];
1743 UINT32 data;
1744
1745 if( DBG.brk_data == INVALID ) return 0;
1746
1747 data = RDMEM(DBG.brk_data);
1748
1749 if( DBG.brk_data_oldval != data )
1750 {
1751 DBG.brk_data_oldval = data;
1752 if( DBG.brk_data_newval != INVALID )
1753 {
1754 if( DBG.brk_data_newval == data )
1755 {
1756 sprintf( dbg_info, "Hit data watchpoint at $%X value $%X", DBG.brk_data, DBG.brk_data_newval);
1757 dbg_info_once = dbg_info;
1758 return 1;
1759 }
1760 return 0;
1761 }
1762 sprintf( dbg_info, "Hit data watchpoint at $%X", DBG.brk_data);
1763 dbg_info_once = dbg_info;
1764 return 1;
1765 }
1766 return 0;
1767 }
1768
1769
1770 /**************************************************************************
1771 * hit_brk_regs
1772 * Return non zero if the register breakpoint for the active CPU
1773 * was hit (ie. monitored register changed)
1774 **************************************************************************/
1775 static int hit_brk_regs(void)
1776 {
1777 static char dbg_info[63+1];
1778 UINT32 data;
1779
1780 if( DBG.brk_regs == INVALID ) return 0;
1781
1782 data = activecpu_get_reg(DBG.brk_regs);
1783
1784 if( DBG.brk_regs_oldval != data )
1785 {
1786 DBG.brk_regs_oldval = data;
1787 if( DBG.brk_regs_newval != INVALID )
1788 {
1789 if( DBG.brk_regs_newval == (data & DBG.brk_regs_mask) )
1790 {
1791 if( DBG.brk_regs_mask != 0xffffffff )
1792 sprintf( dbg_info, "Hit register %s & $%X watchpoint value $%X", get_register_name(DBG.brk_regs), DBG.brk_regs_mask, DBG.brk_regs_newval);
1793 else
1794 sprintf( dbg_info, "Hit register %s watchpoint value $%X", get_register_name(DBG.brk_regs), DBG.brk_regs_newval);
1795 dbg_info_once = dbg_info;
1796 return 1;
1797 }
1798 return 0;
1799 }
1800 sprintf( dbg_info, "Hit register %s watchpoint", get_register_name(DBG.brk_regs));
1801 dbg_info_once = dbg_info;
1802 return 1;
1803 }
1804 return 0;
1805 }
1806
1807
1808 /**************************************************************************
1809 * name_rom
1810 * Find the name for a rom from the drivers list
1811 **************************************************************************/
1812 static const char *name_rom( const char *type, int regnum, unsigned *base, unsigned start )
1813 {
1814 const struct RomModule *region, *rom, *chunk;
1815 unsigned offset = *base;
1816
1817 for (region = rom_first_region(Machine->gamedrv); region; region = rom_next_region(region))
1818 if (ROMREGION_GETTYPE(region) == regnum)
1819 {
1820 for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
1821 {
1822 const char *name = ROM_GETNAME(rom);
1823 int length = 0;
1824
1825 for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk))
1826 length += ROM_GETLENGTH(chunk);
1827
1828 /* address inside that range ? */
1829 if( offset < length )
1830 {
1831 /* put back that offset */
1832 *base = offset;
1833 return name;
1834 }
1835 /* subtract length of that ROM */
1836 offset -= length;
1837 }
1838 break;
1839 }
1840
1841 /* default to ROM + xxxx (base - start) */
1842 *base -= start;
1843 return type;
1844 }
1845
1846 /**************************************************************************
1847 * name_rdmem
1848 * Find a descriptive name for the given memory read region of active_cpu
1849 **************************************************************************/
1850 static const char *name_rdmem( unsigned base )
1851 {
1852 static char buffer[16][79+1];
1853 static int which = 0;
1854 const struct MachineCPU *cpu = &Machine->drv->cpu[active_cpu];
1855 const struct Memory_ReadAddress *mr = cpu->memory_read;
1856 int ram_cnt = 1, nop_cnt = 1;
1857 const char *name;
1858 char *dst;
1859
1860 which = (which+1) % 16;
1861 dst = buffer[which];
1862 *dst = '\0';
1863
1864 while( *dst == '\0' && !IS_MEMPORT_END(mr))
1865 {
1866 if (!IS_MEMPORT_MARKER(mr))
1867 {
1868 if( base >= mr->start && base <= mr->end )
1869 {
1870 unsigned offset = base - mr->start;
1871
1872 #if 0
1873 /* Won't work since the MemoryWrite doesn't support ->base anymore */
1874 if( mr->description )
1875 sprintf(dst, "%s+%04X", mr->description, lshift(offset) );
1876 else
1877 if( mr->base && *mr->base == videoram )
1878 sprintf(dst, "video+%04X", lshift(offset) );
1879 else
1880 if( mr->base && *mr->base == colorram )
1881 sprintf(dst, "color+%04X", lshift(offset) );
1882 else
1883 if( mr->base && *mr->base == spriteram )
1884 sprintf(dst, "sprite+%04X", lshift(offset) );
1885 else
1886 #endif
1887 switch( (FPTR)mr->handler )
1888 {
1889 case (FPTR)MRA_RAM:
1890 sprintf(dst, "RAM%d+%04X", ram_cnt, lshift(offset) );
1891 break;
1892 case (FPTR)MRA_ROM:
1893 name = name_rom("ROM", REGION_CPU1+active_cpu, &base, mr->start );
1894 sprintf(dst, "%s+%04X", name, lshift(base) );
1895 break;
1896 case (FPTR)MRA_BANK1: case (FPTR)MRA_BANK2:
1897 case (FPTR)MRA_BANK3: case (FPTR)MRA_BANK4:
1898 case (FPTR)MRA_BANK5: case (FPTR)MRA_BANK6:
1899 case (FPTR)MRA_BANK7: case (FPTR)MRA_BANK8:
1900 case (FPTR)MRA_BANK9: case (FPTR)MRA_BANK10:
1901 case (FPTR)MRA_BANK11: case (FPTR)MRA_BANK12:
1902 case (FPTR)MRA_BANK13: case (FPTR)MRA_BANK14:
1903 case (FPTR)MRA_BANK15: case (FPTR)MRA_BANK16:
1904 sprintf(dst, "BANK%d+%04X", 1 + (int)(MRA_BANK1) - (int)(mr->handler), lshift(offset) );
1905 break;
1906 case (FPTR)MRA_NOP:
1907 sprintf(dst, "NOP%d+%04X", nop_cnt, lshift(offset) );
1908 break;
1909 default:
1910 if( (FPTR)mr->handler == (FPTR)input_port_0_r )
1911 sprintf(dst, "input_port_0+%04X", lshift(offset) );
1912 else
1913 if( (FPTR)mr->handler == (FPTR)input_port_1_r )
1914 sprintf(dst, "input_port_1+%04X", lshift(offset) );
1915 else
1916 if( (FPTR)mr->handler == (FPTR)input_port_2_r )
1917 sprintf(dst, "input_port_2+%04X", lshift(offset) );
1918 else
1919 if( (FPTR)mr->handler == (FPTR)input_port_3_r )
1920 sprintf(dst, "input_port_3+%04X", lshift(offset) );
1921 else
1922 if( (FPTR)mr->handler == (FPTR)input_port_4_r )
1923 sprintf(dst, "input_port_4+%04X", lshift(offset) );
1924 else
1925 if( (FPTR)mr->handler == (FPTR)input_port_5_r )
1926 sprintf(dst, "input_port_5+%04X", lshift(offset) );
1927 else
1928 if( (FPTR)mr->handler == (FPTR)input_port_6_r )
1929 sprintf(dst, "input_port_6+%04X", lshift(offset) );
1930 else
1931 if( (FPTR)mr->handler == (FPTR)input_port_7_r )
1932 sprintf(dst, "input_port_7+%04X", lshift(offset) );
1933 else
1934 if( (FPTR)mr->handler == (FPTR)input_port_8_r )
1935 sprintf(dst, "input_port_8+%04X", lshift(offset) );
1936 else
1937 if( (FPTR)mr->handler == (FPTR)input_port_9_r )
1938 sprintf(dst, "input_port_9+%04X", lshift(offset) );
1939 else
1940 if( (FPTR)mr->handler == (FPTR)input_port_10_r )
1941 sprintf(dst, "input_port_10+%04X", lshift(offset) );
1942 else
1943 if( (FPTR)mr->handler == (FPTR)input_port_11_r )
1944 sprintf(dst, "input_port_11+%04X", lshift(offset) );
1945 else
1946 if( (FPTR)mr->handler == (FPTR)input_port_12_r )
1947 sprintf(dst, "input_port_12+%04X", lshift(offset) );
1948 else
1949 if( (FPTR)mr->handler == (FPTR)input_port_13_r )
1950 sprintf(dst, "input_port_13+%04X", lshift(offset) );
1951 else
1952 if( (FPTR)mr->handler == (FPTR)input_port_14_r )
1953 sprintf(dst, "input_port_14+%04X", lshift(offset) );
1954 else
1955 if( (FPTR)mr->handler == (FPTR)input_port_15_r )
1956 sprintf(dst, "input_port_15+%04X", lshift(offset) );
1957 }
1958 }
1959 switch( (FPTR)mr->handler )
1960 {
1961 case (FPTR)MRA_RAM: ram_cnt++; break;
1962 case (FPTR)MRA_NOP: nop_cnt++; break;
1963 }
1964 }
1965 mr++;
1966 }
1967
1968 return dst;
1969 }
1970
1971 /**************************************************************************
1972 * name_wrmem
1973 * Find a descriptive name for the given memory write region of active_cpu
1974 **************************************************************************/
1975 static const char *name_wrmem( unsigned base )
1976 {
1977 static char buffer[16][79+1];
1978 static int which = 0;
1979 const struct MachineCPU *cpu = &Machine->drv->cpu[active_cpu];
1980 const struct Memory_WriteAddress *mw = cpu->memory_write;
1981 int ram_cnt = 1, nop_cnt = 1;
1982 const char *name;
1983 char *dst;
1984
1985 which = (which+1) % 16;
1986 dst = buffer[which];
1987 *dst = '\0';
1988
1989 ram_cnt = nop_cnt = 1;
1990 while( *dst == '\0' && !IS_MEMPORT_END(mw))
1991 {
1992 if (!IS_MEMPORT_MARKER(mw))
1993 {
1994 if( base >= mw->start && base <= mw->end )
1995 {
1996 #if 0
1997 /* Won't work since the MemoryRead doesn't support ->description anymore */
1998 if( mw->description )
1999 sprintf(dst, "%s+%04X", mw->description, lshift(base - mw->start) );
2000 else
2001 #endif
2002 #if 0
2003 if( mw->base && *mw->base == videoram )
2004 sprintf(dst, "video+%04X", lshift(base - mw->start) );
2005 else
2006 if( mw->base && *mw->base == colorram )
2007 sprintf(dst, "color+%04X", lshift(base - mw->start) );
2008 else
2009 if( mw->base && *mw->base == spriteram )
2010 sprintf(dst, "sprite+%04X", lshift(base - mw->start) );
2011 else
2012 #endif
2013 switch( (FPTR)mw->handler )
2014 {
2015 case (FPTR)MWA_RAM:
2016 sprintf(dst, "RAM%d+%04X", ram_cnt, lshift(base - mw->start) );
2017 break;
2018 case (FPTR)MWA_ROM:
2019 name = name_rom("ROM", REGION_CPU1+active_cpu, &base, mw->start );
2020 sprintf(dst, "%s+%04X", name, lshift(base) );
2021 break;
2022 case (FPTR)MWA_RAMROM:
2023 name = name_rom("RAMROM", REGION_CPU1+active_cpu, &base, mw->start);
2024 sprintf(dst, "%s+%04X", name, lshift(base) );
2025 break;
2026 case (FPTR)MWA_BANK1: case (FPTR)MWA_BANK2:
2027 case (FPTR)MWA_BANK3: case (FPTR)MWA_BANK4:
2028 case (FPTR)MWA_BANK5: case (FPTR)MWA_BANK6:
2029 case (FPTR)MWA_BANK7: case (FPTR)MWA_BANK8:
2030 case (FPTR)MWA_BANK9: case (FPTR)MWA_BANK10:
2031 case (FPTR)MWA_BANK11: case (FPTR)MWA_BANK12:
2032 case (FPTR)MWA_BANK13: case (FPTR)MWA_BANK14:
2033 case (FPTR)MWA_BANK15: case (FPTR)MWA_BANK16:
2034 sprintf(dst, "BANK%d+%04X", 1 + (int)(MWA_BANK1) - (int)(mw->handler), lshift(base - mw->start) );
2035 break;
2036 case (FPTR)MWA_NOP:
2037 sprintf(dst, "NOP%d+%04X", nop_cnt, lshift(base - mw->start) );
2038 break;
2039 }
2040 }
2041 switch( (FPTR)mw->handler )
2042 {
2043 case (FPTR)MRA_RAM: ram_cnt++; break;
2044 case (FPTR)MRA_NOP: nop_cnt++; break;
2045 }
2046 }
2047 mw++;
2048 }
2049
2050 return dst;
2051 }
2052
2053 /**************************************************************************
2054 * name_memory
2055 * Find a descriptive name for the given memory region of active_cpu
2056 **************************************************************************/
2057 static const char *name_memory( unsigned base )
2058 {
2059 static char buffer[8][79+1];
2060 static int which = 0;
2061 const char *rd, *wr;
2062
2063 /* search readmem and writemem names */
2064 rd = name_rdmem( base );
2065 wr = name_wrmem( base );
2066
2067 /* both empty, so it's no specific region */
2068 if( *rd == '\0' && *wr == '\0' )
2069 {
2070 which = (which+1) % 8;
2071 sprintf(buffer[which], "N/A:%04X", base);
2072 return buffer[which];
2073 }
2074
2075 which = (which+1) % 8;
2076
2077 /* both names differ? */
2078 if( strcmp(rd,wr) )
2079 /* well, return both (separated by tab means left/right aligned) */
2080 sprintf(buffer[which], "%s\t%s", rd, wr);
2081 else
2082 /* return the name for readmem... */
2083 sprintf(buffer[which], "%s", rd);
2084
2085 return buffer[which];
2086 }
2087
2088 /**************************************************************************
2089 * win_create
2090 * Wrapper function to fill a struct sWindow and call win_open()
2091 **************************************************************************/
2092 static int win_create(int n, UINT8 prio, int x, int y, int w, int h,
2093 UINT8 co_text, UINT8 co_frame, UINT8 chr, UINT32 attributes)
2094 {
2095 struct sWindow win;
2096 /* fill in the default values for window creation */
2097 memset( &win, 0, sizeof(struct sWindow) );
2098 win.filler = chr;
2099 win.prio = prio;
2100 win.x = x;
2101 win.y = y;
2102 win.w = w;
2103 win.h = h;
2104 win.flags = NO_SCROLL | NO_WRAP | BORDER_TOP | ((n)? HIDDEN : 0) | attributes;
2105 win.co_text = co_text;
2106 win.co_frame = co_frame;
2107 win.co_title = cur_col[E_TITLE];
2108 win.saved_text = ' ';
2109 win.saved_attr = WIN_WHITE;
2110 return win_open(n, &win);
2111 }
2112
2113 static int DECL_SPEC win_msgbox( UINT8 color, const char *title, const char *fmt, ... )
2114 {
2115 UINT32 win = WIN_MSGBOX;
2116 va_list arg;
2117 int i;
2118
2119 win_create( win, 0,
2120 4,6,60,3, color, cur_col[E_FRAME], ' ',
2121 BORDER_TOP | BORDER_LEFT | BORDER_RIGHT | BORDER_BOTTOM | SHADOW );
2122 win_set_title( win, title );
2123
2124 va_start( arg, fmt );
2125 win_vprintf( win, fmt, arg );
2126 va_end( arg );
2127
2128 win_show( win );
2129 i = readkey();
2130 win_close( win );
2131
2132 return i;
2133 }
2134
2135 /**************************************************************************
2136 * dbg_set_rect
2137 * set a rectangle from x,y,w and h
2138 **************************************************************************/
2139 INLINE void dbg_set_rect( struct rectangle *r, int x, int y, int w, int h )
2140 {
2141 r->min_x = x;
2142 r->max_x = x + w - 1;
2143 r->min_y = y;
2144 r->max_y = y + h - 1;
2145 }
2146
2147 /**************************************************************************
2148 * dbg_open_windows
2149 * Depending on the CPU type, create a window layout specified
2150 * by the CPU core - returned by function cputype_win_layout()
2151 **************************************************************************/
2152 static void dbg_open_windows( void )
2153 {
2154 UINT32 flags;
2155 UINT32 i, w, h, aw, ah;
2156
2157 /* Initialize windowing engine */
2158 get_screen_size( &w, &h );
2159 win_init_engine( w, h );
2160
2161 /* anything more than 80x25 available? */
2162 aw = w - 80;
2163 ah = h - 25;
2164
2165 for( i = 0; i < total_cpu; i++ )
2166 {
2167 const UINT8 *win_layout = (UINT8*)cpunum_win_layout(i);
2168 struct rectangle regs, dasm, mem1, mem2, cmds;
2169
2170 #define REGS_X win_layout[0*4+0]
2171 #define REGS_Y win_layout[0*4+1]
2172 #define REGS_W win_layout[0*4+2]
2173 #define REGS_H win_layout[0*4+3]
2174 #define DASM_X win_layout[1*4+0]
2175 #define DASM_Y win_layout[1*4+1]
2176 #define DASM_W win_layout[1*4+2]
2177 #define DASM_H win_layout[1*4+3]
2178 #define MEM1_X win_layout[2*4+0]
2179 #define MEM1_Y win_layout[2*4+1]
2180 #define MEM1_W win_layout[2*4+2]
2181 #define MEM1_H win_layout[2*4+3]
2182 #define MEM2_X win_layout[3*4+0]
2183 #define MEM2_Y win_layout[3*4+1]
2184 #define MEM2_W win_layout[3*4+2]
2185 #define MEM2_H win_layout[3*4+3]
2186 #define CMDS_X win_layout[4*4+0]
2187 #define CMDS_Y win_layout[4*4+1]
2188 #define CMDS_W win_layout[4*4+2]
2189 #define CMDS_H win_layout[4*4+3]
2190
2191 /* cmds window is fixed w and h, always at the bottom */
2192 dbg_set_rect(&cmds, CMDS_X,CMDS_Y+ah,CMDS_W+aw,CMDS_H);
2193 if( DASM_Y == 0 )
2194 {
2195 if( DASM_H + 1 == CMDS_Y )
2196 {
2197 /********************
2198 * dasm * regs *
2199 * ***********
2200 * * mem1 *
2201 * ***********
2202 * * mem2 *
2203 ********************
2204 * cmds *
2205 ********************/
2206 dbg_set_rect(&regs, REGS_X+aw,REGS_Y,REGS_W,REGS_H);
2207 dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+aw,DASM_H+ah);
2208 dbg_set_rect(&mem1, MEM1_X+aw,MEM1_Y,MEM1_W,MEM1_H+(ah+1)/2);
2209 dbg_set_rect(&mem2, MEM2_X+aw,MEM2_Y+(ah+1)/2,MEM2_W,MEM2_H+ah/2);
2210 }
2211 else
2212 if( MEM1_X == MEM2_X )
2213 {
2214 /********************
2215 * dasm * regs *
2216 ********** *
2217 * mem1 * *
2218 ********** *
2219 * mem2 * *
2220 ********************
2221 * cmds *
2222 ********************/
2223 dbg_set_rect(&regs, REGS_X+aw,REGS_Y,REGS_W,REGS_H);
2224 dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+aw,DASM_H);
2225 dbg_set_rect(&mem1, MEM1_X,MEM1_Y,MEM1_W+aw,MEM1_H+(ah+1)/2);
2226 dbg_set_rect(&mem2, MEM2_X,MEM2_Y+(ah+1)/2,MEM2_W+aw,MEM2_H+ah/2);
2227 }
2228 else
2229 if( DASM_X < REGS_X )
2230 {
2231 /********************
2232 * dasm * regs *
2233 * * *
2234 * * *
2235 ********************
2236 * mem1 * mem2 *
2237 ********************
2238 * cmds *
2239 ********************/
2240 dbg_set_rect(&regs, REGS_X+aw,REGS_Y,REGS_W,REGS_H);
2241 dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+aw,DASM_H+(ah+1)/2);
2242 dbg_set_rect(&mem1, MEM1_X,MEM1_Y+(ah+1)/2,MEM1_W+aw,MEM1_H+ah/2);
2243 dbg_set_rect(&mem2, MEM2_X+aw,MEM2_Y,MEM2_W,MEM2_H+ah);
2244 }
2245 else
2246 {
2247 /********************
2248 * regs * dasm *
2249 * * *
2250 * * *
2251 ********************
2252 * mem1 * mem2 *
2253 ********************
2254 * cmds *
2255 ********************/
2256 dbg_set_rect(&dasm, DASM_X+aw,DASM_Y,DASM_W,DASM_H);
2257 dbg_set_rect(&regs, REGS_X,REGS_Y,REGS_W+aw,REGS_H+(ah+1)/2);
2258 dbg_set_rect(&mem1, MEM1_X,MEM1_Y+(ah+1)/2,MEM1_W+aw,MEM1_H+ah/2);
2259 dbg_set_rect(&mem2, MEM2_X+aw,MEM2_Y,MEM2_W,MEM2_H+ah);
2260 }
2261 }
2262 else
2263 {
2264 /********************
2265 * regs *
2266 ********************
2267 * dasm * mem1 *
2268 * ***********
2269 * * mem2 *
2270 ********************
2271 * cmds *
2272 ********************/
2273 dbg_set_rect(&regs, REGS_X,REGS_Y,REGS_W+aw,REGS_H);
2274 dbg_set_rect(&dasm, DASM_X,DASM_Y,DASM_W+(aw+1)/2,DASM_H+ah);
2275 dbg_set_rect(&mem1, MEM1_X+(aw+1)/2,MEM1_Y,MEM1_W+aw/2,MEM1_H+(ah+1)/2);
2276 dbg_set_rect(&mem2, MEM2_X+(aw+1)/2,MEM2_Y+(ah+1)/2,MEM2_W+aw/2,MEM2_H+ah/2);
2277 }
2278
2279 flags = BORDER_TOP;
2280 if( regs.max_x + 1 < w ) flags |= BORDER_RIGHT;
2281 win_create(WIN_REGS(i), 1,
2282 regs.min_x,regs.min_y,
2283 regs.max_x+1-regs.min_x,regs.max_y+1-regs.min_y,
2284 cur_col[E_REGS], cur_col[E_FRAME], ' ', flags );
2285
2286 flags = BORDER_TOP | BORDER_RIGHT;
2287 win_create(WIN_DASM(i), 1,
2288 dasm.min_x, dasm.min_y,
2289 dasm.max_x+1-dasm.min_x,dasm.max_y+1-dasm.min_y,
2290 cur_col[E_DASM], cur_col[E_FRAME], ' ', flags );
2291
2292 flags = BORDER_TOP;
2293 if( mem1.max_x + 1 < w ) flags |= BORDER_RIGHT;
2294 win_create(WIN_MEM1(i), 1,
2295 mem1.min_x,mem1.min_y,
2296 mem1.max_x+1-mem1.min_x,mem1.max_y+1-mem1.min_y,
2297 cur_col[E_MEM1], cur_col[E_FRAME], ' ', flags );
2298
2299 flags = BORDER_TOP;
2300 if( mem2.max_x + 1 < w) flags |= BORDER_RIGHT;
2301 win_create(WIN_MEM2(i), 1,
2302 mem2.min_x,mem2.min_y,
2303 mem2.max_x+1-mem2.min_x,mem2.max_y+1-mem2.min_y,
2304 cur_col[E_MEM2], cur_col[E_FRAME], ' ', flags );
2305
2306 flags = BORDER_TOP;
2307 win_create(WIN_CMDS(i), 1,
2308 cmds.min_x,cmds.min_y,
2309 cmds.max_x+1-cmds.min_x,cmds.max_y+1-cmds.min_y,
2310 cur_col[E_CMDS], cur_col[E_FRAME], ' ', flags );
2311
2312 win_set_title(WIN_CMDS(i), "Command (press F1 for help)");
2313 }
2314 }
2315
2316 /**************************************************************************
2317 * dbg_close_windows
2318 * Close all windows and shut down the window engine
2319 **************************************************************************/
2320 static void dbg_close_windows( void )
2321 {
2322 int i;
2323
2324 for( i = 0; i < total_cpu; i++ )
2325 {
2326 win_close( WIN_REGS(i) );
2327 win_close( WIN_DASM(i) );
2328 win_close( WIN_MEM1(i) );
2329 win_close( WIN_MEM2(i) );
2330 win_close( WIN_CMDS(i) );
2331 }
2332 win_exit_engine();
2333 }
2334
2335 /**************************************************************************
2336 * dasm_line
2337 * disassemble <times> instructions from pc and return the final pc
2338 **************************************************************************/
2339 static unsigned dasm_line( unsigned pc, int times )
2340 {
2341 static char buffer[127+1];
2342
2343 while( times-- > 0 )
2344 pc += activecpu_dasm( buffer, pc );
2345 pc = lshift( rshift(pc) & AMASK );
2346
2347 return pc;
2348 }
2349
2350
2351 /**************************************************************************
2352 * dump_regs
2353 * Update the register display
2354 * Compare register values against the ones stored in reg->backup[]
2355 * Store new values in reg->newval[] which is copied to reg->backup[]
2356 * before the next instruction is executed (at the end of MAME_Debug).
2357 **************************************************************************/
2358 static void dump_regs( void )
2359 {
2360 char title[80+1];
2361 UINT32 win = WIN_REGS(active_cpu);
2362 s_regs *regs = &DBGREGS;
2363 s_edit *pedit = regs->edit;
2364 UINT32 *old = regs->backup;
2365 UINT32 *val = regs->newval;
2366 UINT32 width;
2367 const char *name = activecpu_name(), *flags = activecpu_flags();
2368 int w = win_get_w(win);
2369 int h = win_get_h(win);
2370 int i, j, l, x, y;
2371 UINT8 color;
2372 const INT8 *reg = (INT8*)activecpu_reg_layout();
2373
2374 /* Called the very first time: find max_width */
2375 if( regs->count == 0 )
2376 {
2377 for(i = 0; reg[i]; i++)
2378 {
2379 if( reg[i] == -1 )
2380 continue; /* skip row breaks */
2381 width = strlen( activecpu_dump_reg(reg[i]) );
2382 if( width >= regs->max_width )
2383 regs->max_width = width + 1;
2384 }
2385 }
2386
2387 x = 0;
2388 y = 0;
2389 win_set_curpos( win, 0, 0 );
2390 sprintf( title, "CPU #%d %-8s Flags:%s Cycles:%6u", active_cpu, name, flags, activecpu_get_icount() );
2391 l = strlen(title);
2392 if( l + 2 < w )
2393 {
2394 /* Everything should fit into the caption */
2395 if( l + 4 < w )
2396 /* We can even separate the cycles to the right corner */
2397 sprintf( title, "CPU #%d %-8s Flags:%s\tCycles:%6u", active_cpu, name, flags, activecpu_get_icount() );
2398 win_set_title( win, title );
2399 }
2400 else
2401 {
2402 /* At least CPU # and flags should fit into the caption */
2403 sprintf( title, "CPU #%d %-8s Flags:%s", active_cpu, name, flags );
2404 l = strlen(title);
2405 if( l + 2 < w )
2406 {
2407 if( l + 4 < w )
2408 sprintf( title, "CPU #%d %-8s\tFlags:%s", active_cpu, name, flags );
2409 win_set_title( win, title );
2410 if( y < h )
2411 {
2412 win_printf( win, "Cycles:%6u\n", activecpu_get_icount() );
2413 }
2414 y++;
2415 }
2416 else
2417 {
2418 sprintf( title, "CPU #%d %-8s Cyc:%6u", active_cpu, name, activecpu_get_icount() );
2419 l = strlen(title);
2420 if( l + 2 < w )
2421 {
2422 if( l + 4 < w )
2423 sprintf( title, "CPU #%d %-8s\tCyc:%6u", active_cpu, name, activecpu_get_icount() );
2424 win_set_title( win, title );
2425 if( y < h )
2426 {
2427 if( strlen(activecpu_flags()) + 8 < w )
2428 win_printf( win, "Flags: %s\n", flags );
2429 else
2430 if( strlen(activecpu_flags()) + 2 < w )
2431 win_printf( win, "F:%s\n", flags );
2432 else
2433 win_printf( win, "%s\n", flags );
2434 }
2435 y++;
2436 }
2437 else
2438 {
2439 /* Only CPU # and name fit into the caption */
2440 sprintf( title, "CPU #%d %-8s", active_cpu, name );
2441 l = strlen(title);
2442 win_set_title( win, title );
2443 if( y < h )
2444 {
2445 if( strlen(activecpu_flags()) + 8 < w )
2446 win_printf( win, "Flags: %s\n", flags );
2447 else
2448 if( strlen(activecpu_flags()) + 2 < w )
2449 win_printf( win, "F:%s\n", flags );
2450 else
2451 win_printf( win, "%s\n", flags );
2452 }
2453 y++;
2454 if( y < h )
2455 {
2456 win_printf( win, "Cycles:%6u\n", activecpu_get_icount() );
2457 }
2458 y++;
2459 }
2460 }
2461 }
2462 regs->top = y;
2463 y = 0;
2464
2465 for( i = 0, j = 0; *reg; i++, reg++ )
2466 {
2467 if( *reg == -1 )
2468 {
2469 if( y >= regs->base && y < regs->base + h - regs->top )
2470 {
2471 win_erase_eol( win, ' ' );
2472 win_putc( win, '\n');
2473 }
2474 x = 0;
2475 y++;
2476 }
2477 else
2478 {
2479 name = activecpu_dump_reg(*reg);
2480 if( *name == '\0' )
2481 continue;
2482
2483 regs->id[j] = *reg;
2484 *val = activecpu_get_reg(regs->id[j]);
2485 color = cur_col[E_REGS];
2486 if( DBG.brk_regs == *reg )
2487 color = cur_col[E_BRK_REGS];
2488 if( *val != *old )
2489 {
2490 regs->changed = 1;
2491 color = (color & 0xf0) | cur_col[E_CHANGES];
2492 }
2493 win_set_color( win, color );
2494
2495 /* edit structure not yet initialized? */
2496 if( regs->count == 0 )
2497 {
2498 const char *p;
2499 /* Get the cursor position */
2500 pedit->x = x;
2501 pedit->y = y + regs->base;
2502 if( strlen(name) >= regs->max_width )
2503 regs->max_width = strlen(name) + 1;
2504 /* Find a colon */
2505 p = strchr( name, ':' );
2506 if( p )
2507 {
2508 pedit->w = strlen( p + 1 );
2509 }
2510 else
2511 {
2512 /* Or else find an apostrophe */
2513 p = strchr( name, '\'' );
2514 if( p )
2515 {
2516 /* Include the apostrophe in the name! */
2517 ++p;
2518 pedit->w = strlen( p );
2519 }
2520 else
2521 {
2522 /* TODO: other characters to delimit a register name from it's value? */
2523 /* this is certainly wrong :( */
2524 p = name;
2525 pedit->w = strlen( p );
2526 }
2527 }
2528 /* length of the name (total length - length of nibbles) */
2529 pedit->n = strlen( name ) - pedit->w;
2530
2531 /* strip trailing spaces */
2532 l = p - name;
2533 while( l != 0 && name[ l - 1 ] == ' ' )
2534 {
2535 l--;
2536 }
2537 if( l > sizeof( regs->name[ j ] ) - 1 )
2538 {
2539 l = sizeof( regs->name[ j ] ) - 1;
2540 }
2541 memcpy( regs->name[ j ], name, l );
2542 regs->name[ j ][ l ] = 0;
2543 }
2544 if( y >= regs->base && y < regs->base + h - regs->top )
2545 {
2546 win_printf( win, "%s", name );
2547
2548 win_set_color( win, cur_col[E_REGS] );
2549 /* If no row break follows, advance to the next tab stop */
2550 if( reg[1] != -1 )
2551 win_printf( win, "%*s", regs->max_width - pedit->w - pedit->n, "" );
2552 }
2553 x += strlen( name ) + regs->max_width - pedit->w - pedit->n;
2554 pedit++;
2555 val++;
2556 old++;
2557 j++;
2558 }
2559 }
2560 while( y >= regs->base && y < regs->base + h - regs->top )
2561 {
2562 win_erase_eol( win, ' ' );
2563 win_putc( win, '\n' );
2564 y++;
2565 }
2566
2567 /* Set the total count of registers */
2568 regs->count = j;
2569 }
2570
2571 /**************************************************************************
2572 * dump_dasm
2573 * Update the disassembly display
2574 **************************************************************************/
2575 static unsigned dump_dasm( unsigned pc )
2576 {
2577 UINT32 win = WIN_DASM(active_cpu);
2578 int w = win_get_w(win);
2579 int h = win_get_h(win);
2580 int x, y, l, line_pc_cpu = INVALID, line_pc_cur = INVALID;
2581 UINT8 color;
2582 char dasm[127+1];
2583 unsigned pc_first = pc, pc_next;
2584 unsigned width = (ABITS + 3) / 4;
2585
2586 while( line_pc_cpu == INVALID )
2587 {
2588 pc = pc_first;
2589
2590 for( y = 0; y < h; y++ )
2591 {
2592 win_set_curpos( win, 0, y );
2593 if( pc == DBG.brk_exec )
2594 color = cur_col[E_BRK_EXEC];
2595 else
2596 color = cur_col[E_DASM];
2597 if( pc == DBGDASM.pc_cpu )
2598 {
2599 color = (color & 0x0f) | (cur_col[E_PC] & 0xf0);
2600 line_pc_cpu = y;
2601 }
2602 if( pc == DBGDASM.pc_cur )
2603 {
2604 color = (color & 0x0f) | (cur_col[E_CURSOR] & 0xf0);
2605 line_pc_cur = y;
2606 }
2607 win_set_color( win, color );
2608 l = win_printf( win, "%0*X: ", width, pc );
2609
2610 DBGDASM.dst_ea_value = INVALID;
2611 DBGDASM.src_ea_value = INVALID;
2612 pc_next = pc + activecpu_dasm( dasm, pc );
2613
2614 if( DBGDASM.pc_cur == pc )
2615 win_set_title( win, "%s", get_ea_info(pc) );
2616
2617 if( dbg_dasm_opcodes )
2618 {
2619 unsigned p = rshift(pc);
2620 unsigned n = rshift(pc_next);
2621 switch( ALIGN )
2622 {
2623 case 1:
2624 for( x = 0; x < INSTL; x++ )
2625 {
2626 if ( p < n )
2627 {
2628 l += win_printf( win, "%02X ",
2629 RDMEM(order(p,1)) );
2630 p++;
2631 }
2632 else l += win_printf( win, " " );
2633 }
2634 break;
2635 case 2:
2636 for( x = 0; x < INSTL; x += 2 )
2637 {
2638 if ( p < n )
2639 {
2640 l += win_printf( win, "%02X%02X ",
2641 RDMEM(order(p+0,2)), RDMEM(order(p+1,2)) );
2642 p += 2;
2643 }
2644 else l += win_printf( win, " " );
2645 }
2646 break;
2647 case 4:
2648 for( x = 0; x < INSTL; x += 4 )
2649 {
2650 if ( p < n)
2651 {
2652 l += win_printf( win, "%02X%02X%02X%02X ",
2653 RDMEM(order(p+0,4)), RDMEM(order(p+1,4)),
2654 RDMEM(order(p+2,4)), RDMEM(order(p+3,4)) );
2655 p += 4;
2656 }
2657 else l += win_printf( win, " " );
2658 }
2659 break;
2660 }
2661 }
2662 pc = lshift(rshift(pc_next) & AMASK);
2663 switch( dbg_dasm_case )
2664 {
2665 case 0: win_printf( win, "%-*.*s", w-l, w-l, dasm ); break;
2666 case 1: win_printf( win, "%-*.*s", w-l, w-l, lower(dasm) ); break;
2667 case 2: win_printf( win, "%-*.*s", w-l, w-l, upper(dasm) ); break;
2668 }
2669 }
2670 if( line_pc_cpu == INVALID )
2671 {
2672 /*
2673 * We didn't find the exact instruction of the CPU PC.
2674 * This has to be caused by a jump into the midst of
2675 * another instruction down from the top. If the CPU PC
2676 * is between pc_first and pc (end), try again on next
2677 * instruction size boundary, else bail out...
2678 */
2679 if( DBGDASM.pc_cpu > pc_first && DBGDASM.pc_cpu < pc )
2680 pc_first += ALIGN;
2681 else
2682 line_pc_cpu = 0;
2683 }
2684 }
2685
2686 win_set_curpos( win, 0, line_pc_cur );
2687
2688 return pc;
2689 }
2690
2691 /**************************************************************************
2692 * dump_mem_hex
2693 * Update a memory window using the cpu_readmemXXX function
2694 * Changed values are displayed using foreground color cur_col[E_CHANGES]
2695 * The new values are stored into mem->newval[] of the active_cpu
2696 **************************************************************************/
2697 static void dump_mem_hex( int which, unsigned len_addr, unsigned len_data )
2698 {
2699 UINT32 win = WIN_MEM(active_cpu,which);
2700 s_edit *pedit = DBGMEM[which].edit;
2701 int w = win_get_w(win);
2702 int h = win_get_h(win);
2703 UINT8 *old = DBGMEM[which].backup;
2704 UINT8 *val = DBGMEM[which].newval;
2705 UINT8 color, dim_bright = 0;
2706 UINT8 spc_left = 0; /* assume no space left of address */
2707 UINT8 spc_addr = 0; /* assume no space after address */
2708 UINT8 spc_data = 1; /* assume one space between adjacent data elements */
2709 UINT8 spc_hyphen = 0; /* assume no space around center hyphen */
2710 unsigned offs, column;
2711
2712 /* how many elements (bytes,words,dwords) will fit in a line? */
2713 DBGMEM[which].width = (w - len_addr - 1) / (len_data + spc_data);
2714
2715 /* display multiples of eight bytes per line only */
2716 if( DBGMEM[which].width > ((16/len_data)-1) )
2717 DBGMEM[which].width &= ~((16/len_data)-1);
2718
2719 /* Is bytes per line not divideable by eight? */
2720 if( dbg_mem_squeezed && (DBGMEM[which].width & 7) )
2721 {
2722 /* We try an alternating dim,bright layout w/o data spacing */
2723 spc_data = 0;
2724 /* how many bytes will fit in a line? */
2725 DBGMEM[which].width = (w - len_addr - 1) / len_data;
2726 /* display multiples of eight data elements per line only */
2727 if( DBGMEM[which].width > ((16/len_data)-1) )
2728 DBGMEM[which].width &= ~((16/len_data)-1);
2729 dim_bright = 0x08;
2730 }
2731
2732 /* calculate number of bytes per line */
2733 DBGMEM[which].bytes = DBGMEM[which].width * len_data / 2;
2734 /* calculate the DBGMEM[which].size using that data width */
2735 DBGMEM[which].size = DBGMEM[which].bytes * h;
2736
2737 /* will a space after the address fit into the line? */
2738 if( ( len_addr + spc_addr + DBGMEM[which].width * (len_data + spc_data) + 1 ) < w )
2739 spc_addr = 1;
2740
2741 /* will two spaces around the center hyphen fit into the line ? */
2742 if( ( len_addr + spc_addr + DBGMEM[which].width * (len_data + spc_data) + 2 ) < w )
2743 spc_hyphen = 1;
2744
2745 while( ( 2*spc_left + len_addr + spc_addr + DBGMEM[which].width * (len_data + spc_data) - 1 + spc_hyphen ) + 2 < w )
2746 spc_left++;
2747
2748 win_set_curpos( win, 0, 0 );
2749
2750 for( offs = 0, column = 0; offs < DBGMEM[which].size; offs++, old++, val++ )
2751 {
2752 color = cur_col[E_MEM1+which];
2753 switch( len_data )
2754 {
2755 case 2: /* UINT8 mode */
2756 DBGMEM[which].address = (DBGMEM[which].base + order(offs,1)) & AMASK;
2757 break;
2758 case 4: /* UINT16 mode */
2759 DBGMEM[which].address = (DBGMEM[which].base + order(offs,2)) & AMASK;
2760 break;
2761 case 8: /* UINT32 mode */
2762 DBGMEM[which].address = (DBGMEM[which].base + order(offs,4)) & AMASK;
2763 break;
2764 }
2765
2766 if( column == 0 )
2767 {
2768 win_set_color( win, cur_col[E_MEM1+which] );
2769 win_printf( win, "%*s%0*X:%*s",
2770 spc_left, "", len_addr, lshift((DBGMEM[which].base + offs) & AMASK), spc_addr, "" );
2771 }
2772
2773 if( DBGMEM[which].address == DBG.brk_data )
2774 color = cur_col[E_BRK_DATA];
2775
2776 if( DBGMEM[which].internal )
2777 *val = RDINT( DBGMEM[which].address );
2778 else
2779 if( DBGMEM[which].pgm_memory_base )
2780 *val = OP_ROM[DBGMEM[which].pgm_memory_base + DBGMEM[which].address];
2781 else
2782 *val = RDMEM( DBGMEM[which].address );
2783
2784 if( *val != *old )
2785 {
2786 DBGMEM[which].changed = 1;
2787 color = (color & 0xf0) | (cur_col[E_CHANGES] & 0x0f);
2788 }
2789
2790 if( (column * 2 / len_data) & 1 )
2791 color ^= dim_bright;
2792
2793 /* store memory edit x,y */
2794 pedit->x = win_get_cx( win );
2795 pedit->y = win_get_cy( win );
2796 pedit->w = 2;
2797 pedit->n = order(column % (len_data / 2), len_data / 2);
2798 pedit++;
2799
2800 win_set_color( win, color );
2801 switch( DBGMEM[which].ascii )
2802 {
2803 case MODE_CHR_HEX:
2804 win_printf( win, "%02X", *val );
2805 break;
2806 case MODE_CHR_XLATE:
2807 win_printf( win, "%c ", trans_table[*val] );
2808 break;
2809 case MODE_CHR_PLAIN:
2810 if( *val == '\0' || *val == '\b' || *val == '\t' ||
2811 *val == '\r' || *val == '\n' )
2812 win_printf( win, ". " );
2813 else
2814 win_printf( win, "%c ", *val );
2815 break;
2816 }
2817
2818 if( ++column < DBGMEM[which].bytes )
2819 {
2820 win_set_color( win, cur_col[E_MEM1+which] );
2821 if( column == DBGMEM[which].bytes / 2 )
2822 win_printf( win, "%*s-%*s", spc_hyphen, "", spc_hyphen, "" );
2823 else
2824 if( spc_data && (column * 2 % len_data) == 0 )
2825 win_putc( win, ' ' );
2826 }
2827 else
2828 {
2829 win_putc( win, '\n');
2830 column = 0;
2831 }
2832 }
2833 }
2834
2835 /**************************************************************************
2836 * dump_mem
2837 * Update a memory window
2838 * Dispatch to one of the memory handler specific output functions
2839 **************************************************************************/
2840 static void dump_mem( int which, int set_title )
2841 {
2842 unsigned len_addr = (ABITS + ASHIFT + 3) / 4;
2843
2844 if( set_title )
2845 {
2846 if( DBGMEM[which].internal )
2847 win_set_title( WIN_MEM(active_cpu,which), "CPU internal" );
2848 else
2849 win_set_title( WIN_MEM(active_cpu,which), name_memory(DBGMEM[which].base + DBGMEM[which].pgm_memory_base) );
2850 }
2851
2852 switch( DBGMEM[which].mode )
2853 {
2854 case MODE_HEX_UINT8: dump_mem_hex( which, len_addr, 2 ); break;
2855 case MODE_HEX_UINT16: dump_mem_hex( which, len_addr, 4 ); break;
2856 case MODE_HEX_UINT32: dump_mem_hex( which, len_addr, 8 ); break;
2857 }
2858 }
2859
2860 /**************************************************************************
2861 * edit_regs
2862 * Edit the registers
2863 **************************************************************************/
2864 static void edit_regs( void )
2865 {
2866 UINT32 win = WIN_REGS(active_cpu);
2867 s_regs *regs = &DBGREGS;
2868 s_edit *pedit = regs->edit;
2869 unsigned shift, mask, val;
2870 const char *k;
2871 int i, x, y;
2872
2873 /* Eventually update the cmdline window caption */
2874 edit_cmds_info();
2875
2876 if( regs->base > pedit[ regs->idx ].y )
2877 {
2878 regs->base = pedit[ regs->idx ].y;
2879 dump_regs();
2880 }
2881 else
2882 if( pedit[ regs->idx ].y >= regs->base + win_get_h( win ) - regs->top )
2883 {
2884 regs->base = pedit[ regs->idx ].y - win_get_h( win ) + regs->top + 1;
2885 dump_regs();
2886 }
2887 win_set_curpos( win, pedit[regs->idx].x + pedit[regs->idx].n + regs->nibble, pedit[regs->idx].y - regs->base + regs->top );
2888 set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
2889
2890 i = readkey();
2891 k = keyboard_name(i);
2892
2893 shift = ( pedit[ regs->idx ].w - 1 - regs->nibble ) * 4;
2894 mask = ~(0x0000000f << shift);
2895
2896 if( strlen(k) == 1 )
2897 {
2898 switch( k[0] )
2899 {
2900 case '0': case '1': case '2': case '3':
2901 case '4': case '5': case '6': case '7':
2902 case '8': case '9': case 'A': case 'B':
2903 case 'C': case 'D': case 'E': case 'F':
2904 val = k[0] - '0';
2905 if( val > 9 ) val -= 7;
2906 val <<= shift;
2907 /* now modify the register */
2908 activecpu_set_reg( regs->id[regs->idx],
2909 ( activecpu_get_reg( regs->id[regs->idx] ) & mask ) | val );
2910 dump_regs();
2911 i = KEYCODE_RIGHT; /* advance to next nibble */
2912 }
2913 }
2914
2915 switch( i )
2916 {
2917 case KEYCODE_LEFT:
2918 if( --regs->nibble < 0 )
2919 {
2920 if( --regs->idx < 0 )
2921 {
2922 regs->idx = regs->count - 1;
2923 }
2924 regs->nibble = pedit[regs->idx].w - 1;
2925 }
2926 break;
2927
2928 case KEYCODE_RIGHT:
2929 if( ++regs->nibble >= pedit[regs->idx].w )
2930 {
2931 regs->nibble = 0;
2932 if( ++regs->idx >= regs->count )
2933 {
2934 regs->idx = 0;
2935 }
2936 }
2937 break;
2938
2939 case KEYCODE_UP:
2940 i = regs->idx;
2941 x = pedit[regs->idx].x;
2942 y = pedit[regs->idx].y;
2943 while( x != pedit[i].x || pedit[i].y == y )
2944 {
2945 if( --i < 0 )
2946 {
2947 i = regs->count - 1;
2948 if( pedit[i].y == y )
2949 {
2950 i = regs->idx;
2951 break;
2952 }
2953 }
2954 }
2955 if( i != regs->idx )
2956 {
2957 if( regs->nibble >= pedit[i].w )
2958 regs->nibble = pedit[i].w - 1;
2959 regs->idx = i;
2960 }
2961 break;
2962
2963 case KEYCODE_DOWN:
2964 i = regs->idx;
2965 x = pedit[regs->idx].x;
2966 y = pedit[regs->idx].y;
2967 while( x != pedit[i].x || pedit[i].y == y )
2968 {
2969 if( ++i >= regs->count )
2970 {
2971 i = 0;
2972 if( pedit[i].y == y )
2973 {
2974 i = regs->idx;
2975 break;
2976 }
2977 }
2978 }
2979 if( i != regs->idx )
2980 {
2981 if( regs->nibble >= pedit[i].w )
2982 regs->nibble = pedit[i].w - 1;
2983 regs->idx = i;
2984 }
2985 break;
2986
2987 case KEYCODE_ENTER:
2988 DBG.window = EDIT_CMDS;
2989 break;
2990
2991 default:
2992 cmd_default( i );
2993 }
2994 }
2995
2996
2997 /**************************************************************************
2998 * edit_dasm
2999 * Edit the disassembly output
3000 **************************************************************************/
3001 static void edit_dasm(void)
3002 {
3003 UINT32 win = WIN_DASM(active_cpu);
3004 const char *k;
3005 int i, update_window = 0;
3006
3007 /* Eventually update the cmdline window caption */
3008 edit_cmds_info();
3009
3010 set_screen_curpos( win_get_cx_abs(win), win_get_cy_abs(win) );
3011
3012 i = readkey();
3013 k = keyboard_name(i);
3014
3015 switch( i )
3016 {
3017 case KEYCODE_M: /* Toggle mode (opcode display) */
3018 sprintf( CMD, "%d", dbg_dasm_opcodes ^ 1 );
3019 cmd_set_dasm_opcodes();
3020 break;
3021
3022 case KEYCODE_D: /* Default case disassembly */
3023 dbg_dasm_case = 0;
3024 update_window = 1;
3025 break;
3026
3027 case KEYCODE_L: /* Lower case disassembly */
3028 dbg_dasm_case = 1;
3029 update_window = 1;
3030 break;
3031
3032 case KEYCODE_U: /* Upper case disassembly */
3033 dbg_dasm_case = 2;
3034 update_window = 1;
3035 break;
3036
3037 case KEYCODE_R: /* Toggle relative jumps display */
3038 dbg_dasm_relative_jumps ^= 1;
3039 update_window = 1;
3040 break;
3041
3042 case KEYCODE_ENTER:
3043 DBG.window = EDIT_CMDS;
3044 break;
3045
3046 default:
3047 cmd_default( i );
3048 }
3049 if( update_window )
3050 {
3051 DBGDASM.pc_end = dump_dasm( DBGDASM.pc_top );
3052 }
3053 }
3054
3055
3056 /**************************************************************************
3057 * edit_mem
3058 * Edit the memory dumps output
3059 **************************************************************************/
3060 static void edit_mem( int which )
3061 {
3062 UINT32 win = WIN_MEM(active_cpu,which);
3063 s_edit *pedit = DBGMEM[which].edit;
3064 const char *k;
3065