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