/*
Copyright (C) 2000,2001
Ralf Forsberg
This file is part of gpsim.
gpsim is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
gpsim is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gpsim; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "../config.h"
#ifdef HAVE_GUI
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <string.h>
#include <assert.h>
#include "../src/sim_context.h"
#include "../src/interface.h"
#include "../src/symbol.h"
#include "gui.h"
#include "gui_stack.h"
#include "gui_src.h"
struct stack_entry {
unsigned int depth; // index in stack array
unsigned int retaddress; // last known return address
};
#define COLUMNS 2
#define DEPTHCOL 0
#define RETADDRCOL 1
static char *stack_titles[COLUMNS]={"depth", "return address"};
/*
*/
static gint sigh_button_event(GtkWidget *widget,
GdkEventButton *event,
Stack_Window *sw)
{
struct stack_entry *entry;
assert(event&&sw);
if(!sw->gp || !sw->gp->cpu)
return 0;
if(event->type==GDK_2BUTTON_PRESS &&
event->button==1) {
int row=sw->current_row;
entry = (struct stack_entry*) gtk_clist_get_row_data(GTK_CLIST(sw->stack_clist), row);
if(entry)
sw->gp->cpu->pma->toggle_break_at_address(entry->retaddress);
return 1;
}
return 0;
}
static gint stack_list_row_selected(GtkCList *stacklist,gint row, gint column,GdkEvent *event, Stack_Window *sw)
{
struct stack_entry *entry;
GUI_Processor *gp;
sw->current_row=row;
sw->current_column=column;
gp=sw->gp;
entry = (struct stack_entry*) gtk_clist_get_row_data(GTK_CLIST(sw->stack_clist), row);
if(!entry)
return TRUE;
sw->gp->source_browser->SelectAddress(entry->retaddress);
sw->gp->program_memory->SelectAddress(entry->retaddress);
return 0;
}
static void stack_click_column(GtkCList *clist, int column)
{
static int last_col=-1;
static GtkSortType last_sort_type=GTK_SORT_DESCENDING;
if(last_col==-1)
last_col=column;
if(last_col == column)
{
if(last_sort_type==GTK_SORT_DESCENDING)
{
gtk_clist_set_sort_type(clist,GTK_SORT_ASCENDING);
last_sort_type=GTK_SORT_ASCENDING;
}
else
{
gtk_clist_set_sort_type(clist,GTK_SORT_DESCENDING);
last_sort_type=GTK_SORT_DESCENDING;
}
}
gtk_clist_set_sort_column(clist,column);
gtk_clist_sort(clist);
last_col=column;
}
static int delete_event(GtkWidget *widget,
GdkEvent *event,
Stack_Window *sw)
{
sw->ChangeView(VIEW_HIDE);
return TRUE;
}
// find name of label closest before 'address' and copy found data
// into name and offset
static int get_closest_label(Stack_Window *sw,
int address,
char *name,
int *offset)
{
// this function assumes that address symbols are sorted
Value *closest_symbol = 0;
int minimum_delta=0x2000000;
int delta;
Symbol_Table &st = CSimulationContext::GetContext()->GetSymbolTable();
Symbol_Table::iterator symIt;
Symbol_Table::iterator symItEnd = st.end();
for(symIt=st.begin(); symIt != symItEnd; symIt++) {
Value *s = *symIt;
if( (typeid(*s) == typeid(address_symbol)) /*||
(typeid(*s) == typeid(line_number_symbol))*/) {
int i;
s->get(i);
delta = abs( i - address);
if(delta < minimum_delta) {
minimum_delta = delta;
closest_symbol = s;
}
}
}
if(closest_symbol) {
strcpy(name,closest_symbol->name().data());
int i;
closest_symbol->get(i);
*offset=address-i;
return 1;
}
return 0;
}
void Stack_Window::Update(void)
{
int i=0;
int nrofentries;
//unsigned int pic_id;
char depth_string[64];
char retaddress_string[64];
char labelname[64];
int labeloffset;
char *entry[COLUMNS]={depth_string,retaddress_string};
unsigned int retaddress;
struct stack_entry *stack_entry;
if(!gp || !enabled)
return;
//pic_id = gp->pic_id;
pic_processor *pic = dynamic_cast<pic_processor *>(gp->cpu);
if(!pic)
return;
nrofentries = pic->stack->pointer & pic->stack->stack_mask;
if(last_stacklen!=nrofentries) {
// stack has changed, update stack clist
gtk_clist_freeze (GTK_CLIST (stack_clist));
while(last_stacklen!=nrofentries) {
if(last_stacklen>nrofentries) {
// Stack has shrunk
// remove row 0
stack_entry = (struct stack_entry*) gtk_clist_get_row_data(GTK_CLIST(stack_clist), 0);
free(stack_entry);
gtk_clist_remove(GTK_CLIST(stack_clist),0);
last_stacklen--;
} else {
// stack has grown
strcpy(depth_string,"");
retaddress=pic->stack->contents[last_stacklen & pic->stack->stack_mask];
if(get_closest_label(this,retaddress,labelname,&labeloffset))
sprintf(retaddress_string,"0x%04x (%s+%d)",retaddress,labelname,labeloffset);
else
sprintf(retaddress_string,"0x%04x",retaddress);
gtk_clist_insert (GTK_CLIST(stack_clist),
0,
entry);
// FIXME this memory is never freed?
stack_entry = (struct stack_entry*) malloc(sizeof(struct stack_entry));
stack_entry->retaddress=retaddress;
stack_entry->depth=i;
gtk_clist_set_row_data(GTK_CLIST(stack_clist), 0, (gpointer)stack_entry);
last_stacklen++;
}
}
// update depth column
for(i=0;i<nrofentries;i++)
{
sprintf(depth_string,"#%d",i);
gtk_clist_set_text (GTK_CLIST(stack_clist),i,0,depth_string);
}
gtk_clist_thaw (GTK_CLIST (stack_clist));
}
}
void Stack_Window::Build(void)
{
if(bIsBuilt)
return;
GtkWidget *vbox;
GtkWidget *scrolled_window;
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Stack Viewer");
gtk_window_set_default_size(GTK_WINDOW(window), width,height);
gtk_widget_set_uposition(GTK_WIDGET(window),x,y);
gtk_window_set_wmclass(GTK_WINDOW(window),name(),"Gpsim");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_widget_destroyed), &window);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC(delete_event), (gpointer)this);
gtk_signal_connect_after(GTK_OBJECT(window), "configure_event",
GTK_SIGNAL_FUNC(gui_object_configure_event),this);
gtk_signal_connect_after(GTK_OBJECT(window), "button_press_event",
GTK_SIGNAL_FUNC(sigh_button_event), this);
stack_clist=gtk_clist_new_with_titles(COLUMNS,stack_titles);
gtk_widget_show(stack_clist);
gtk_clist_set_selection_mode (GTK_CLIST(stack_clist), GTK_SELECTION_BROWSE);
gtk_signal_connect(GTK_OBJECT(stack_clist),"click_column",
(GtkSignalFunc)stack_click_column,0);
gtk_signal_connect(GTK_OBJECT(stack_clist),"select_row",
(GtkSignalFunc)stack_list_row_selected,this);
scrolled_window=gtk_scrolled_window_new(0, 0);
gtk_widget_show(scrolled_window);
vbox = gtk_vbox_new(FALSE,1);
gtk_widget_show(vbox);
gtk_container_add(GTK_CONTAINER(scrolled_window), stack_clist);
gtk_container_add(GTK_CONTAINER(window),vbox);
gtk_box_pack_start_defaults(GTK_BOX(vbox),scrolled_window);
gtk_widget_show (window);
bIsBuilt = true;
UpdateMenuItem();
Update();
}
//------------------------------------------------------------------------
// Create
//
//
Stack_Window::Stack_Window(GUI_Processor *_gp)
{
#define MAXROWS (MAX_REGISTERS/REGISTERS_PER_ROW)
#define MAXCOLS (REGISTERS_PER_ROW+1)
menu = "<main>/Windows/Stack";
gp = _gp;
set_name("stack_viewer");
wc = WC_data;
wt = WT_stack_window;
window = 0;
last_stacklen=0;
current_row=0;
get_config();
if(enabled)
Build();
}
#endif // HAVE_GUI
syntax highlighted by Code2HTML, v. 0.9.1