Search
lxdream.org :: lxdream/src/gui/debug_win.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gui/debug_win.c
changeset 429:e581b90c3fb3
prev415:5e57f29bfd4d
next435:7a5d71e8560b
author nkeynes
date Mon Oct 08 12:09:06 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Fix compilation warnings
view annotate diff log raw
     1 /**
     2  * $Id: debug_win.c,v 1.22 2007-10-08 11:48:56 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 "sh4/sh4dasm.h"
    23 #include "gui/gui.h"
    24 #include "mem.h"
    25 #include "cpu.h"
    26 #include "display.h"
    27 #include "pvr2/pvr2.h"
    29 GdkColor *msg_colors[] = { &clrError, &clrError, &clrWarn, &clrNormal,
    30                            &clrDebug, &clrTrace };
    31 char *msg_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
    32 int global_msg_level = EMIT_WARN;
    34 void init_register_list( debug_info_t data );
    36 struct debug_info_struct {
    37     int disasm_from;
    38     int disasm_to;
    39     int disasm_pc;
    40     const struct cpu_desc_struct *cpu;
    41     const cpu_desc_t *cpu_list;
    42     GtkCList *msgs_list;
    43     GtkCList *regs_list;
    44     GtkCList *disasm_list;
    45     GtkEntry *page_field;
    46     GtkWidget *win;
    47     GtkProgressBar *icounter;
    48     char icounter_text[16];
    49     char saved_regs[0];
    50 };
    52 debug_info_t init_debug_win(GtkWidget *win, const cpu_desc_t *cpu_list )
    53 {
    54     GnomeAppBar *appbar;
    56     debug_info_t data = g_malloc0( sizeof(struct debug_info_struct) + cpu_list[0]->regs_size );
    57     data->disasm_from = -1;
    58     data->disasm_to = -1;
    59     data->disasm_pc = -1;
    60     data->cpu = cpu_list[0];
    61     data->cpu_list = cpu_list;
    63     data->regs_list= gtk_object_get_data(GTK_OBJECT(win), "reg_list");
    64     data->win = win;
    65     gtk_widget_modify_font( GTK_WIDGET(data->regs_list), fixed_list_font );
    66     init_register_list( data );
    67     data->msgs_list = gtk_object_get_data(GTK_OBJECT(win), "output_list");
    68     data->disasm_list = gtk_object_get_data(GTK_OBJECT(win), "disasm_list");
    69     gtk_clist_set_column_width( data->disasm_list, 1, 16 );
    70     data->page_field = gtk_object_get_data(GTK_OBJECT(win), "page_field");
    72     appbar = gtk_object_get_data(GTK_OBJECT(win), "debug_appbar");
    73     data->icounter = gnome_appbar_get_progress( appbar );
    74     gtk_progress_bar_set_text(data->icounter, "1");
    76     gtk_object_set_data( GTK_OBJECT(win), "debug_data", data );
    77     set_disassembly_pc( data, *data->cpu->pc, FALSE );
    78     debug_win_set_running( data, FALSE );
    79     return data;
    80 }
    82 void init_register_list( debug_info_t data ) 
    83 {
    84     int i;
    85     char buf[20];
    86     char *arr[2];
    88     gtk_clist_clear( data->regs_list );
    89     arr[1] = buf;
    90     for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
    91         arr[0] = data->cpu->regs_info[i].name;
    92         if( data->cpu->regs_info->type == REG_INT )
    93             sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
    94         else
    95             sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
    96         gtk_clist_append( data->regs_list, arr );
    97     }
    98 }
   100 /*
   101  * Check for changed registers and update the display
   102  */
   103 void update_registers( debug_info_t data )
   104 {
   105     int i;
   106     for( i=0; data->cpu->regs_info[i].name != NULL; i++ ) {
   107         if( data->cpu->regs_info[i].type == REG_INT ) {
   108             /* Yes this _is_ probably fairly evil */
   109             if( *((uint32_t *)data->cpu->regs_info[i].value) !=
   110                 *((uint32_t *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
   111                 char buf[20];
   112                 sprintf( buf, "%08X", *((uint32_t *)data->cpu->regs_info[i].value) );
   113                 gtk_clist_set_text( data->regs_list, i, 1, buf );
   114                 gtk_clist_set_foreground( data->regs_list, i, &clrChanged );
   115             } else {
   116                 gtk_clist_set_foreground( data->regs_list, i, &clrNormal );
   117             }
   118         } else {
   119             if( *((float *)data->cpu->regs_info[i].value) !=
   120                 *((float *)((char *)data->saved_regs + ((char *)data->cpu->regs_info[i].value - (char *)data->cpu->regs))) ) {
   121                 char buf[20];
   122                 sprintf( buf, "%f", *((float *)data->cpu->regs_info[i].value) );
   123                 gtk_clist_set_text( data->regs_list, i, 1, buf );
   124                 gtk_clist_set_foreground( data->regs_list, i, &clrChanged );
   125             } else {
   126                 gtk_clist_set_foreground( data->regs_list, i, &clrNormal );
   127             }
   128         }
   129     }
   131     set_disassembly_pc( data, *data->cpu->pc, FALSE );
   132     memcpy( data->saved_regs, data->cpu->regs, data->cpu->regs_size );
   133 }
   135 void update_icount( debug_info_t data )
   136 {
   137     if( data != NULL ) {
   138 	//    sprintf( data->icounter_text, "%d", *data->cpu->icount );
   139 	sprintf( data->icounter_text, "%d", pvr2_get_frame_count() );
   140 	gtk_progress_bar_set_text( data->icounter, data->icounter_text );
   141     }
   142 }
   144 void set_disassembly_region( debug_info_t data, unsigned int page )
   145 {
   146     uint32_t i, posn, next;
   147     char buf[80];
   148     char addr[10];
   149     char opcode[16] = "";
   150     char *arr[4] = { addr, " ", opcode, buf };
   151     unsigned int from = page & 0xFFFFF000;
   152     unsigned int to = from + 4096;
   154     gtk_clist_clear(data->disasm_list);
   156     sprintf( addr, "%08X", from );
   157     gtk_entry_set_text( data->page_field, addr );
   159     if( !data->cpu->is_valid_page_func( from ) ) {
   160         arr[3] = "This page is currently unmapped";
   161         gtk_clist_append( data->disasm_list, arr );
   162         gtk_clist_set_foreground( data->disasm_list, 0, &clrError );
   163     } else {
   164         for( i=from; i<to; i = next ) {
   165 	    next = data->cpu->disasm_func( i, buf, sizeof(buf), opcode );
   166             sprintf( addr, "%08X", i );
   167             posn = gtk_clist_append( data->disasm_list, arr );
   168             if( buf[0] == '?' )
   169                 gtk_clist_set_foreground( data->disasm_list, posn, &clrWarn );
   170 	    if( data->cpu->get_breakpoint != NULL ) {
   171 		int type = data->cpu->get_breakpoint( i );
   172 		switch(type) {
   173 		case BREAK_ONESHOT:
   174 		    gtk_clist_set_background( data->disasm_list, posn, &clrTempBreak );
   175 		    break;
   176 		case BREAK_KEEP:
   177 		    gtk_clist_set_background( data->disasm_list, posn, &clrBreak );
   178 		    break;
   179 		}
   180 	    }
   181         }
   182         if( data->disasm_pc != -1 && data->disasm_pc >= from && data->disasm_pc < to )
   183             gtk_clist_set_foreground( data->disasm_list, address_to_row(data, data->disasm_pc),
   184                                       &clrPC );
   185     }
   187     if( page != from ) { /* not a page boundary */
   188         gtk_clist_moveto( data->disasm_list, (page-from)>>1, 0, 0.5, 0.0 );
   189     }
   190     data->disasm_from = from;
   191     data->disasm_to = to;
   192 }
   194 void jump_to_disassembly( debug_info_t data, unsigned int addr, gboolean select )
   195 {
   196     int row;
   198     if( addr < data->disasm_from || addr >= data->disasm_to )
   199         set_disassembly_region(data,addr);
   201     row = address_to_row( data, addr );
   202     if(select) {
   203         gtk_clist_select_row( data->disasm_list, row, 0 );
   204     }
   205     if( gtk_clist_row_is_visible( data->disasm_list, row ) != GTK_VISIBILITY_FULL ){
   206         gtk_clist_moveto( data->disasm_list, row, 0, 0.5, 0.0 );
   207     }
   208 }
   210 void jump_to_pc( debug_info_t data, gboolean select )
   211 {
   212     jump_to_disassembly( data, *data->cpu->pc, select );
   213 }
   215 void set_disassembly_pc( debug_info_t data, unsigned int pc, gboolean select )
   216 {
   217     int row;
   219     jump_to_disassembly( data, pc, select );
   220     if( data->disasm_pc != -1 && data->disasm_pc >= data->disasm_from && 
   221 	data->disasm_pc < data->disasm_to )
   222         gtk_clist_set_foreground( data->disasm_list, 
   223 				  (data->disasm_pc - data->disasm_from) / data->cpu->instr_size,
   224                                   &clrNormal );
   225     row = address_to_row( data, pc );
   226     gtk_clist_set_foreground( data->disasm_list, row, &clrPC );
   227     data->disasm_pc = pc;
   228 }
   230 void set_disassembly_cpu( debug_info_t data, const gchar *cpu )
   231 {
   232     int i;
   233     for( i=0; data->cpu_list[i] != NULL; i++ ) {
   234 	if( strcmp( data->cpu_list[i]->name, cpu ) == 0 ) {
   235 	    if( data->cpu != data->cpu_list[i] ) {
   236 		data->cpu = data->cpu_list[i];
   237 		data->disasm_from = data->disasm_to = -1; /* Force reload */
   238 		set_disassembly_pc( data, *data->cpu->pc, FALSE );
   239 		init_register_list( data );
   240 		update_icount( data );
   241 	    }
   242 	    return;
   243 	}
   244     }
   245 }
   247 void debug_win_toggle_breakpoint( debug_info_t data, int row )
   248 {
   249     uint32_t pc = row_to_address( data, row );
   250     int oldType = data->cpu->get_breakpoint( pc );
   251     if( oldType != BREAK_NONE ) {
   252 	data->cpu->clear_breakpoint( pc, oldType );
   253 	gtk_clist_set_background( data->disasm_list, row, &clrWhite );
   254     } else {
   255 	data->cpu->set_breakpoint( pc, BREAK_KEEP );
   256 	gtk_clist_set_background( data->disasm_list, row, &clrBreak );
   257     }
   258 }
   260 void debug_win_set_oneshot_breakpoint( debug_info_t data, int row )
   261 {
   262     uint32_t pc = row_to_address( data, row );
   263     data->cpu->clear_breakpoint( pc, BREAK_ONESHOT );
   264     data->cpu->set_breakpoint( pc, BREAK_ONESHOT );
   265     gtk_clist_set_background( data->disasm_list, row, &clrTempBreak );
   266 }
   268 /**
   269  * Execute a single instruction using the current CPU mode.
   270  */
   271 void debug_win_single_step( debug_info_t data )
   272 {
   273     data->cpu->step_func();
   274     gtk_gui_update();
   275 }
   277 uint32_t row_to_address( debug_info_t data, int row ) {
   278     return data->cpu->instr_size * row + data->disasm_from;
   279 }
   281 int address_to_row( debug_info_t data, uint32_t address ) {
   282     if( data->disasm_from > address || data->disasm_to <= address )
   283 	return -1;
   284     return (address - data->disasm_from) / data->cpu->instr_size;
   285 }
   288 void emit( void *ptr, int level, const gchar *source, const char *msg, ... )
   289 {
   290     char buf[20], addr[10] = "", *p;
   291     const gchar *arr[4] = {buf, source, addr};
   292     int posn;
   293     time_t tm = time(NULL);
   294     va_list ap;
   295     debug_info_t data;
   296     if( ptr == NULL )
   297 	data = main_debug;
   298     else data = (debug_info_t)ptr;
   300     if( level > global_msg_level ) {
   301 	return; // ignored
   302     }
   303     va_start(ap, msg);
   305     strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
   307     if( data == NULL ) {
   308 	fprintf( stderr, "%s %08X %-5s ", buf, *sh4_cpu_desc.pc, msg_levels[level] );
   309 	vfprintf( stderr, msg, ap );
   310 	fprintf( stderr, "\n" );
   311 	va_end(ap);
   312 	return;
   313     }
   315     p = g_strdup_vprintf( msg, ap );
   316     sprintf( addr, "%08X", *data->cpu->pc );
   317     arr[3] = p;
   318     posn = gtk_clist_append(data->msgs_list, (gchar **)arr);
   319     free(p);
   320     va_end(ap);
   322     gtk_clist_set_foreground( data->msgs_list, posn, msg_colors[level] );
   323     gtk_clist_moveto( data->msgs_list, posn, 0, 1.0, 0.0 );
   325     /* emit _really_ slows down the emu, to the point where the gui can be
   326      * completely unresponsive if I don't include this:
   327      */
   328     while( gtk_events_pending() )
   329         gtk_main_iteration();
   330 }
   332 debug_info_t get_debug_info( GtkWidget *widget ) {
   334     GtkWidget *win = gtk_widget_get_toplevel(widget);
   335     debug_info_t data = (debug_info_t)gtk_object_get_data( GTK_OBJECT(win), "debug_data" );
   336     return data;
   337 }
   339 void debug_win_enable_widget( debug_info_t data, const char *name, 
   340 			      gboolean enabled )
   341 {
   342     GtkWidget *widget = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(data->win), name));
   343     gtk_widget_set_sensitive( widget, enabled );
   344 }    
   346 void debug_win_set_running( debug_info_t data, gboolean isRunning ) 
   347 {
   348     if( data != NULL ) {
   349 	debug_win_enable_widget( data, "stop_btn", isRunning );
   350 	debug_win_enable_widget( data, "step_btn", !isRunning );
   351 	debug_win_enable_widget( data, "run_btn", !isRunning );
   352 	debug_win_enable_widget( data, "runto_btn", !isRunning );
   353     }
   354 }
.