filename | src/gui/debug_win.c |
changeset | 437:2c259474b474 |
prev | 435:7a5d71e8560b |
next | 455:3080881d00d4 |
author | nkeynes |
date | Wed Oct 17 11:26:45 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Split config management out to config.[ch] Manage config filename Check home dir + sysconfdir for conf file Initial work on a path settings dialog |
view | annotate | diff | log | raw |
1 /**
2 * $Id: debug_win.c,v 1.24 2007-10-11 08:22:03 nkeynes Exp $
3 * This file is responsible for the main debugger gui frame.
4 *
5 * Copyright (c) 2005 Nathan Keynes.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <gnome.h>
21 #include <math.h>
22 #include "mem.h"
23 #include "cpu.h"
24 #include "debugif.h"
25 #include "gui/gtkui.h"
26 #include "sh4/sh4dasm.h"
27 #include "aica/armdasm.h"
29 GdkColor *msg_colors[] = { &gui_colour_error, &gui_colour_error, &gui_colour_warn,
30 &gui_colour_normal,&gui_colour_debug, &gui_colour_trace };
32 const cpu_desc_t cpu_list[4] = { &sh4_cpu_desc, &arm_cpu_desc, &armt_cpu_desc, NULL };
34 void init_register_list( debug_window_t data );
35 uint32_t row_to_address( debug_window_t data, int row );
36 void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select );
37 void set_disassembly_region( debug_window_t data, unsigned int page );
38 void set_disassembly_cpu( debug_window_t data, const gchar *cpu );
40 struct debug_window_info {
41 int disasm_from;
42 int disasm_to;
43 int disasm_pc;
44 const struct cpu_desc_struct *cpu;
45 const cpu_desc_t *cpu_list;
46 GtkCList *msgs_list;
47 GtkCList *regs_list;
48 GtkCList *disasm_list;
49 GtkEntry *page_field;
50 GtkWidget *win;
51 GtkProgressBar *icounter;
52 char icounter_text[16];
53 char saved_regs[0];
54 };
56 debug_window_t debug_window_new( )
57 {
58 GtkWidget *win = create_debug_win();
59 GnomeAppBar *appbar;
61 debug_window_t data = g_malloc0( sizeof(struct debug_window_info) + cpu_list[0]->regs_size );
62 data->disasm_from = -1;
63 data->disasm_to = -1;
64 data->disasm_pc = -1;
65 data->cpu = cpu_list[0];
66 data->cpu_list = cpu_list;
68 data->regs_list= gtk_object_get_data(GTK_OBJECT(win), "reg_list");
69 data->win = win;
70 gtk_widget_modify_font( GTK_WIDGET(data->regs_list), gui_fixed_font );
71 init_register_list( data );
72 data->msgs_list = gtk_object_get_data(GTK_OBJECT(win), "output_list");
73 data->disasm_list = gtk_object_get_data(GTK_OBJECT(win), "disasm_list");
74 gtk_clist_set_column_width( data->disasm_list, 1, 16 );
75 data->page_field = gtk_object_get_data(GTK_OBJECT(win), "page_field");
77 appbar = gtk_object_get_data(GTK_OBJECT(win), "debug_appbar");
78 data->icounter = gnome_appbar_get_progress( appbar );
79 gtk_progress_bar_set_text(data->icounter, "1");
81 gtk_object_set_data( GTK_OBJECT(win), "debug_data", data );
82 set_disassembly_pc( data, *data->cpu->pc, FALSE );
83 debug_window_set_running( data, FALSE );
85 gtk_widget_show( win );
86 return data;
87 }
89 void debug_window_show( debug_window_t data, gboolean show )
90 {
91 if( show ) {
92 gtk_widget_show( data->win );
93 } else {
94 gtk_widget_hide( data->win );
95 }
96 }
98 void init_register_list( debug_window_t data )
99 {
100 int i;
101 char buf[20];
102 char *arr[2];
104 gtk_clist_clear( data->regs_list );
105 arr[1] = buf;
106 for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
107 arr[0] = data->cpu->regs_info[i].name;
108 if( data->cpu->regs_info->type == REG_INT )
109 sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
110 else
111 sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
112 gtk_clist_append( data->regs_list, arr );
113 }
114 }
116 /*
117 * Check for changed registers and update the display
118 */
119 void debug_window_update( debug_window_t data )
120 {
121 int i;
122 for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
123 if( data->cpu->regs_info[i].type == REG_INT ) {
124 /* Yes this _is_ probably fairly evil */
125 if( *((uint32_t *)data->cpu->regs_info[i].value) !=
126 *((uint32_t *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
127 char buf[20];
128 sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
129 gtk_clist_set_text( data->regs_list, i, 1, buf );
130 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
131 } else {
132 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
133 }
134 } else {
135 if( *((float *)data->cpu->regs_info[i].value) !=
136 *((float *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
137 char buf[20];
138 sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
139 gtk_clist_set_text( data->regs_list, i, 1, buf );
140 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_changed );
141 } else {
142 gtk_clist_set_foreground( data->regs_list, i, &gui_colour_normal );
143 }
144 }
145 }
147 set_disassembly_pc( data, *data->cpu->pc, FALSE );
148 memcpy( data->saved_regs, data->cpu->regs, data->cpu->regs_size );
149 }
151 void set_disassembly_region( debug_window_t data, unsigned int page )
152 {
153 uint32_t i, posn, next;
154 char buf[80];
155 char addr[10];
156 char opcode[16] = "";
157 char *arr[4] = { addr, " ", opcode, buf };
158 unsigned int from = page & 0xFFFFF000;
159 unsigned int to = from + 4096;
161 gtk_clist_clear(data->disasm_list);
163 sprintf( addr, "%08X", from );
164 gtk_entry_set_text( data->page_field, addr );
166 if( !data->cpu->is_valid_page_func( from ) ) {
167 arr[3] = "This page is currently unmapped";
168 gtk_clist_append( data->disasm_list, arr );
169 gtk_clist_set_foreground( data->disasm_list, 0, &gui_colour_error );
170 } else {
171 for( i=from; i<to; i = next ) {
172 next = data->cpu->disasm_func( i, buf, sizeof(buf), opcode );
173 sprintf( addr, "%08X", i );
174 posn = gtk_clist_append( data->disasm_list, arr );
175 if( buf[0] == '?' )
176 gtk_clist_set_foreground( data->disasm_list, posn, &gui_colour_warn );
177 if( data->cpu->get_breakpoint != NULL ) {
178 int type = data->cpu->get_breakpoint( i );
179 switch(type) {
180 case BREAK_ONESHOT:
181 gtk_clist_set_background( data->disasm_list, posn, &gui_colour_temp_break );
182 break;
183 case BREAK_KEEP:
184 gtk_clist_set_background( data->disasm_list, posn, &gui_colour_break );
185 break;
186 }
187 }
188 }
189 if( data->disasm_pc != -1 && data->disasm_pc >= from && data->disasm_pc < to )
190 gtk_clist_set_foreground( data->disasm_list, address_to_row(data, data->disasm_pc),
191 &gui_colour_pc );
192 }
194 if( page != from ) { /* not a page boundary */
195 gtk_clist_moveto( data->disasm_list, (page-from)>>1, 0, 0.5, 0.0 );
196 }
197 data->disasm_from = from;
198 data->disasm_to = to;
199 }
201 void jump_to_disassembly( debug_window_t data, unsigned int addr, gboolean select )
202 {
203 int row;
205 if( addr < data->disasm_from || addr >= data->disasm_to )
206 set_disassembly_region(data,addr);
208 row = address_to_row( data, addr );
209 if(select) {
210 gtk_clist_select_row( data->disasm_list, row, 0 );
211 }
212 if( gtk_clist_row_is_visible( data->disasm_list, row ) != GTK_VISIBILITY_FULL ){
213 gtk_clist_moveto( data->disasm_list, row, 0, 0.5, 0.0 );
214 }
215 }
217 void jump_to_pc( debug_window_t data, gboolean select )
218 {
219 jump_to_disassembly( data, *data->cpu->pc, select );
220 }
222 void set_disassembly_pc( debug_window_t data, unsigned int pc, gboolean select )
223 {
224 int row;
226 jump_to_disassembly( data, pc, select );
227 if( data->disasm_pc != -1 && data->disasm_pc >= data->disasm_from &&
228 data->disasm_pc < data->disasm_to )
229 gtk_clist_set_foreground( data->disasm_list,
230 (data->disasm_pc - data->disasm_from) / data->cpu->instr_size,
231 &gui_colour_normal );
232 row = address_to_row( data, pc );
233 gtk_clist_set_foreground( data->disasm_list, row, &gui_colour_pc );
234 data->disasm_pc = pc;
235 }
237 void set_disassembly_cpu( debug_window_t data, const gchar *cpu )
238 {
239 int i;
240 for( i=0; data->cpu_list[i] != NULL; i++ ) {
241 if( strcmp( data->cpu_list[i]->name, cpu ) == 0 ) {
242 if( data->cpu != data->cpu_list[i] ) {
243 data->cpu = data->cpu_list[i];
244 data->disasm_from = data->disasm_to = -1; /* Force reload */
245 set_disassembly_pc( data, *data->cpu->pc, FALSE );
246 init_register_list( data );
247 }
248 return;
249 }
250 }
251 }
253 void debug_win_toggle_breakpoint( debug_window_t data, int row )
254 {
255 uint32_t pc = row_to_address( data, row );
256 int oldType = data->cpu->get_breakpoint( pc );
257 if( oldType != BREAK_NONE ) {
258 data->cpu->clear_breakpoint( pc, oldType );
259 gtk_clist_set_background( data->disasm_list, row, &gui_colour_white );
260 } else {
261 data->cpu->set_breakpoint( pc, BREAK_KEEP );
262 gtk_clist_set_background( data->disasm_list, row, &gui_colour_break );
263 }
264 }
266 void debug_win_set_oneshot_breakpoint( debug_window_t data, int row )
267 {
268 uint32_t pc = row_to_address( data, row );
269 data->cpu->clear_breakpoint( pc, BREAK_ONESHOT );
270 data->cpu->set_breakpoint( pc, BREAK_ONESHOT );
271 gtk_clist_set_background( data->disasm_list, row, &gui_colour_temp_break );
272 }
274 /**
275 * Execute a single instruction using the current CPU mode.
276 */
277 void debug_win_single_step( debug_window_t data )
278 {
279 data->cpu->step_func();
280 gtk_gui_update();
281 }
283 uint32_t row_to_address( debug_window_t data, int row ) {
284 return data->cpu->instr_size * row + data->disasm_from;
285 }
287 int address_to_row( debug_window_t data, uint32_t address ) {
288 if( data->disasm_from > address || data->disasm_to <= address )
289 return -1;
290 return (address - data->disasm_from) / data->cpu->instr_size;
291 }
293 #if 0
294 void emit( void *ptr, int level, const gchar *source, const char *msg, ... )
295 {
296 char buf[20], addr[10] = "", *p;
297 const gchar *arr[4] = {buf, source, addr};
298 int posn;
299 time_t tm = time(NULL);
300 va_list ap;
301 debug_window_t data = NULL;
302 /*
303 if( ptr == NULL )
304 data = debug_win;
305 else data = (debug_window_t)ptr;
306 */
307 if( level > global_msg_level ) {
308 return; // ignored
309 }
310 va_start(ap, msg);
312 strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
314 if( data == NULL ) {
315 fprintf( stderr, "%s %08X %-5s ", buf, *sh4_cpu_desc.pc, msg_levels[level] );
316 vfprintf( stderr, msg, ap );
317 fprintf( stderr, "\n" );
318 va_end(ap);
319 return;
320 }
322 p = g_strdup_vprintf( msg, ap );
323 sprintf( addr, "%08X", *data->cpu->pc );
324 arr[3] = p;
325 posn = gtk_clist_append(data->msgs_list, (gchar **)arr);
326 free(p);
327 va_end(ap);
329 gtk_clist_set_foreground( data->msgs_list, posn, msg_colors[level] );
330 gtk_clist_moveto( data->msgs_list, posn, 0, 1.0, 0.0 );
332 /* emit _really_ slows down the emu, to the point where the gui can be
333 * completely unresponsive if I don't include this:
334 */
335 while( gtk_events_pending() )
336 gtk_main_iteration();
337 }
338 #endif
339 debug_window_t get_debug_info( GtkWidget *widget ) {
341 GtkWidget *win = gtk_widget_get_toplevel(widget);
342 debug_window_t data = (debug_window_t)gtk_object_get_data( GTK_OBJECT(win), "debug_data" );
343 return data;
344 }
346 void debug_win_enable_widget( debug_window_t data, const char *name,
347 gboolean enabled )
348 {
349 GtkWidget *widget = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(data->win), name));
350 gtk_widget_set_sensitive( widget, enabled );
351 }
353 void debug_window_set_running( debug_window_t data, gboolean isRunning )
354 {
355 if( data != NULL ) {
356 debug_win_enable_widget( data, "stop_btn", isRunning );
357 debug_win_enable_widget( data, "step_btn", !isRunning );
358 debug_win_enable_widget( data, "run_btn", !isRunning );
359 debug_win_enable_widget( data, "runto_btn", !isRunning );
360 }
361 }
.