filename | src/gui/debug_win.c |
changeset | 144:7f0714e89aaa |
prev | 134:d194907efdab |
next | 392:39e596b3b6dd |
author | nkeynes |
date | Thu Jun 15 10:27:10 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Add preliminary call-stack tracing ability Fix INTC state save/load/reset |
view | annotate | diff | log | raw |
1 /**
2 * $Id: debug_win.c,v 1.19 2006-05-15 08:28:52 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 "gui/gui.h"
23 #include "mem.h"
24 #include "cpu.h"
25 #include "display.h"
27 GdkColor *msg_colors[] = { &clrError, &clrError, &clrWarn, &clrNormal,
28 &clrDebug, &clrTrace };
30 void init_register_list( debug_info_t data );
32 struct debug_info_struct {
33 int disasm_from;
34 int disasm_to;
35 int disasm_pc;
36 struct cpu_desc_struct *cpu;
37 struct cpu_desc_struct **cpu_list;
38 GtkCList *msgs_list;
39 GtkCList *regs_list;
40 GtkCList *disasm_list;
41 GtkEntry *page_field;
42 GtkWidget *win;
43 GtkProgressBar *icounter;
44 char icounter_text[16];
45 char saved_regs[0];
46 };
48 debug_info_t init_debug_win(GtkWidget *win, const cpu_desc_t *cpu_list )
49 {
50 GnomeAppBar *appbar;
52 debug_info_t data = g_malloc0( sizeof(struct debug_info_struct) + cpu_list[0]->regs_size );
53 data->disasm_from = -1;
54 data->disasm_to = -1;
55 data->disasm_pc = -1;
56 data->cpu = cpu_list[0];
57 data->cpu_list = cpu_list;
59 data->regs_list= gtk_object_get_data(GTK_OBJECT(win), "reg_list");
60 data->win = win;
61 gtk_widget_modify_font( GTK_WIDGET(data->regs_list), fixed_list_font );
62 init_register_list( data );
63 data->msgs_list = gtk_object_get_data(GTK_OBJECT(win), "output_list");
64 data->disasm_list = gtk_object_get_data(GTK_OBJECT(win), "disasm_list");
65 gtk_clist_set_column_width( data->disasm_list, 1, 16 );
66 data->page_field = gtk_object_get_data(GTK_OBJECT(win), "page_field");
68 appbar = gtk_object_get_data(GTK_OBJECT(win), "debug_appbar");
69 data->icounter = gnome_appbar_get_progress( appbar );
70 gtk_progress_bar_set_text(data->icounter, "1");
72 gtk_object_set_data( GTK_OBJECT(win), "debug_data", data );
73 set_disassembly_pc( data, *data->cpu->pc, FALSE );
74 debug_win_set_running( data, FALSE );
75 return data;
76 }
78 void init_register_list( debug_info_t data )
79 {
80 int i;
81 char buf[20];
82 char *arr[2];
84 gtk_clist_clear( data->regs_list );
85 arr[1] = buf;
86 for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
87 arr[0] = data->cpu->regs_info[i].name;
88 if( data->cpu->regs_info->type == REG_INT )
89 sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
90 else
91 sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
92 gtk_clist_append( data->regs_list, arr );
93 }
94 }
96 /*
97 * Check for changed registers and update the display
98 */
99 void update_registers( debug_info_t data )
100 {
101 int i;
102 for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
103 if( data->cpu->regs_info[i].type == REG_INT ) {
104 /* Yes this _is_ probably fairly evil */
105 if( *((uint32_t *)data->cpu->regs_info[i].value) !=
106 *((uint32_t *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
107 char buf[20];
108 sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
109 gtk_clist_set_text( data->regs_list, i, 1, buf );
110 gtk_clist_set_foreground( data->regs_list, i, &clrChanged );
111 } else {
112 gtk_clist_set_foreground( data->regs_list, i, &clrNormal );
113 }
114 } else {
115 if( *((float *)data->cpu->regs_info[i].value) !=
116 *((float *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
117 char buf[20];
118 sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
119 gtk_clist_set_text( data->regs_list, i, 1, buf );
120 gtk_clist_set_foreground( data->regs_list, i, &clrChanged );
121 } else {
122 gtk_clist_set_foreground( data->regs_list, i, &clrNormal );
123 }
124 }
125 }
127 set_disassembly_pc( data, *data->cpu->pc, FALSE );
128 memcpy( data->saved_regs, data->cpu->regs, data->cpu->regs_size );
129 }
131 void update_icount( debug_info_t data )
132 {
133 // sprintf( data->icounter_text, "%d", *data->cpu->icount );
134 sprintf( data->icounter_text, "%d", pvr2_get_frame_count() );
135 gtk_progress_bar_set_text( data->icounter, data->icounter_text );
136 }
138 void set_disassembly_region( debug_info_t data, unsigned int page )
139 {
140 uint32_t i, posn, next;
141 char buf[80];
142 char addr[10];
143 char opcode[16] = "";
144 char *arr[4] = { addr, " ", opcode, buf };
145 unsigned int from = page & 0xFFFFF000;
146 unsigned int to = from + 4096;
148 gtk_clist_clear(data->disasm_list);
150 sprintf( addr, "%08X", from );
151 gtk_entry_set_text( data->page_field, addr );
153 if( !data->cpu->is_valid_page_func( from ) ) {
154 arr[3] = "This page is currently unmapped";
155 gtk_clist_append( data->disasm_list, arr );
156 gtk_clist_set_foreground( data->disasm_list, 0, &clrError );
157 } else {
158 for( i=from; i<to; i = next ) {
159 next = data->cpu->disasm_func( i, buf, sizeof(buf), opcode );
160 sprintf( addr, "%08X", i );
161 posn = gtk_clist_append( data->disasm_list, arr );
162 if( buf[0] == '?' )
163 gtk_clist_set_foreground( data->disasm_list, posn, &clrWarn );
164 if( data->cpu->get_breakpoint != NULL ) {
165 int type = data->cpu->get_breakpoint( i );
166 switch(type) {
167 case BREAK_ONESHOT:
168 gtk_clist_set_background( data->disasm_list, posn, &clrTempBreak );
169 break;
170 case BREAK_KEEP:
171 gtk_clist_set_background( data->disasm_list, posn, &clrBreak );
172 break;
173 }
174 }
175 }
176 if( data->disasm_pc != -1 && data->disasm_pc >= from && data->disasm_pc < to )
177 gtk_clist_set_foreground( data->disasm_list, address_to_row(data, data->disasm_pc),
178 &clrPC );
179 }
181 if( page != from ) { /* not a page boundary */
182 gtk_clist_moveto( data->disasm_list, (page-from)>>1, 0, 0.5, 0.0 );
183 }
184 data->disasm_from = from;
185 data->disasm_to = to;
186 }
188 void jump_to_disassembly( debug_info_t data, unsigned int addr, gboolean select )
189 {
190 int row;
192 if( addr < data->disasm_from || addr >= data->disasm_to )
193 set_disassembly_region(data,addr);
195 row = address_to_row( data, addr );
196 if(select) {
197 gtk_clist_select_row( data->disasm_list, row, 0 );
198 }
199 if( gtk_clist_row_is_visible( data->disasm_list, row ) != GTK_VISIBILITY_FULL ){
200 gtk_clist_moveto( data->disasm_list, row, 0, 0.5, 0.0 );
201 }
202 }
204 void jump_to_pc( debug_info_t data, gboolean select )
205 {
206 jump_to_disassembly( data, *data->cpu->pc, select );
207 }
209 void set_disassembly_pc( debug_info_t data, unsigned int pc, gboolean select )
210 {
211 int row;
213 jump_to_disassembly( data, pc, select );
214 if( data->disasm_pc != -1 && data->disasm_pc >= data->disasm_from &&
215 data->disasm_pc < data->disasm_to )
216 gtk_clist_set_foreground( data->disasm_list,
217 (data->disasm_pc - data->disasm_from) / data->cpu->instr_size,
218 &clrNormal );
219 row = address_to_row( data, pc );
220 gtk_clist_set_foreground( data->disasm_list, row, &clrPC );
221 data->disasm_pc = pc;
222 }
224 void set_disassembly_cpu( debug_info_t data, const gchar *cpu )
225 {
226 int i;
227 for( i=0; data->cpu_list[i] != NULL; i++ ) {
228 if( strcmp( data->cpu_list[i]->name, cpu ) == 0 ) {
229 if( data->cpu != data->cpu_list[i] ) {
230 data->cpu = data->cpu_list[i];
231 data->disasm_from = data->disasm_to = -1; /* Force reload */
232 set_disassembly_pc( data, *data->cpu->pc, FALSE );
233 init_register_list( data );
234 update_icount( data );
235 }
236 return;
237 }
238 }
239 }
241 void debug_win_toggle_breakpoint( debug_info_t data, int row )
242 {
243 uint32_t pc = row_to_address( data, row );
244 int oldType = data->cpu->get_breakpoint( pc );
245 if( oldType != BREAK_NONE ) {
246 data->cpu->clear_breakpoint( pc, oldType );
247 gtk_clist_set_background( data->disasm_list, row, &clrWhite );
248 } else {
249 data->cpu->set_breakpoint( pc, BREAK_KEEP );
250 gtk_clist_set_background( data->disasm_list, row, &clrBreak );
251 }
252 }
254 void debug_win_set_oneshot_breakpoint( debug_info_t data, int row )
255 {
256 uint32_t pc = row_to_address( data, row );
257 data->cpu->clear_breakpoint( pc, BREAK_ONESHOT );
258 data->cpu->set_breakpoint( pc, BREAK_ONESHOT );
259 gtk_clist_set_background( data->disasm_list, row, &clrTempBreak );
260 }
262 /**
263 * Execute a single instruction using the current CPU mode.
264 */
265 void debug_win_single_step( debug_info_t data )
266 {
267 data->cpu->step_func();
268 gtk_gui_update();
269 }
271 uint32_t row_to_address( debug_info_t data, int row ) {
272 return data->cpu->instr_size * row + data->disasm_from;
273 }
275 int address_to_row( debug_info_t data, uint32_t address ) {
276 if( data->disasm_from > address || data->disasm_to <= address )
277 return -1;
278 return (address - data->disasm_from) / data->cpu->instr_size;
279 }
282 void emit( void *ptr, int level, const gchar *source, const char *msg, ... )
283 {
284 char buf[20], addr[10] = "", *p;
285 const char *arr[4] = {buf, source, addr};
286 int posn;
287 time_t tm = time(NULL);
288 va_list ap;
289 debug_info_t data;
290 if( ptr == NULL )
291 data = main_debug;
292 else data = (debug_info_t)ptr;
293 va_start(ap, msg);
295 if( data == NULL ) {
296 vfprintf( stderr, msg, ap );
297 fprintf( stderr, "\n" );
298 va_end(ap);
299 return;
300 }
302 p = g_strdup_vprintf( msg, ap );
303 strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
304 sprintf( addr, "%08X", *data->cpu->pc );
305 arr[3] = p;
306 posn = gtk_clist_append(data->msgs_list, arr);
307 free(p);
308 va_end(ap);
310 gtk_clist_set_foreground( data->msgs_list, posn, msg_colors[level] );
311 gtk_clist_moveto( data->msgs_list, posn, 0, 1.0, 0.0 );
313 /* emit _really_ slows down the emu, to the point where the gui can be
314 * completely unresponsive if I don't include this:
315 */
316 while( gtk_events_pending() )
317 gtk_main_iteration();
318 }
320 debug_info_t get_debug_info( GtkWidget *widget ) {
322 GtkWidget *win = gtk_widget_get_toplevel(widget);
323 debug_info_t data = (debug_info_t)gtk_object_get_data( GTK_OBJECT(win), "debug_data" );
324 return data;
325 }
327 void debug_win_enable_widget( debug_info_t data, const char *name,
328 gboolean enabled )
329 {
330 GtkWidget *widget = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(data->win), name));
331 gtk_widget_set_sensitive( widget, enabled );
332 }
334 void debug_win_set_running( debug_info_t data, gboolean isRunning )
335 {
336 debug_win_enable_widget( data, "stop_btn", isRunning );
337 debug_win_enable_widget( data, "step_btn", !isRunning );
338 debug_win_enable_widget( data, "run_btn", !isRunning );
339 debug_win_enable_widget( data, "runto_btn", !isRunning );
340 }
.