1201 lines
29 KiB
C
1201 lines
29 KiB
C
|
/*
|
||
|
* TilEm II
|
||
|
*
|
||
|
* Copyright (c) 2011-2012 Benjamin Moody
|
||
|
*
|
||
|
* This program 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 3 of the
|
||
|
* License, or (at your option) any later version.
|
||
|
*
|
||
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
# include <config.h>
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <gtk/gtk.h>
|
||
|
#include <ticalcs.h>
|
||
|
#include <tilem.h>
|
||
|
#include <tilemdb.h>
|
||
|
|
||
|
#include "gui.h"
|
||
|
#include "disasmview.h"
|
||
|
|
||
|
G_DEFINE_TYPE(TilemDisasmView, tilem_disasm_view, GTK_TYPE_TREE_VIEW);
|
||
|
|
||
|
/*
|
||
|
This is a HORRIBLE kludge. Don't ever do anything like this. ;)
|
||
|
|
||
|
We want a widget that has the look and feel of a GtkTreeView. But
|
||
|
our "data model" isn't consistent with a GtkTreeModel, since it
|
||
|
changes depending on where we are.
|
||
|
|
||
|
This widget keeps track of how high each row will be once rendered,
|
||
|
and uses that to construct a GtkListStore with the appropriate
|
||
|
number of rows to fill the window. We also override the move-cursor
|
||
|
signal so that we can handle the boundaries.
|
||
|
*/
|
||
|
|
||
|
/* Model columns */
|
||
|
enum {
|
||
|
COL_POSITION,
|
||
|
COL_ADDRESS,
|
||
|
COL_MNEMONIC,
|
||
|
COL_ARGUMENTS,
|
||
|
COL_SHOW_MNEMONIC,
|
||
|
COL_ICON,
|
||
|
NUM_COLUMNS
|
||
|
};
|
||
|
|
||
|
static GtkTreeViewClass *parent_class;
|
||
|
|
||
|
/* We define two "positions" for each actual address; the second is
|
||
|
used if there's a label to be displayed at that address. */
|
||
|
|
||
|
#define POS_TO_ADDR(x) ((x) >> 1)
|
||
|
#define ADDR_TO_POS(x) ((x) << 1)
|
||
|
|
||
|
/* Disassembly */
|
||
|
|
||
|
/* Convert physical to logical address; if address is not currently
|
||
|
mapped, use the bank-A address */
|
||
|
static dword default_ptol(TilemCalc *calc, dword addr)
|
||
|
{
|
||
|
dword addr_l;
|
||
|
|
||
|
g_return_val_if_fail(calc != NULL, 0);
|
||
|
|
||
|
addr_l = (*calc->hw.mem_ptol)(calc, addr);
|
||
|
if (addr_l == 0xffffffff)
|
||
|
addr_l = (addr & 0x3fff) | 0x4000;
|
||
|
|
||
|
return addr_l;
|
||
|
}
|
||
|
|
||
|
/* Check for a label at the given address (physical or logical
|
||
|
depending on the mode of the DisasmView) */
|
||
|
static const char *get_label(TilemDisasmView *dv, TilemCalc *calc,
|
||
|
dword addr)
|
||
|
{
|
||
|
g_return_val_if_fail(calc != NULL, NULL);
|
||
|
g_return_val_if_fail(dv->dbg->dasm != NULL, NULL);
|
||
|
|
||
|
if (!dv->use_logical)
|
||
|
addr = default_ptol(calc, addr);
|
||
|
|
||
|
return tilem_disasm_get_label_at_address(dv->dbg->dasm, addr);
|
||
|
}
|
||
|
|
||
|
/* Disassemble a line */
|
||
|
static void disassemble(TilemDisasmView *dv, TilemCalc *calc, dword pos,
|
||
|
dword *nextpos, char **mnemonic, char **args)
|
||
|
{
|
||
|
dword addr = POS_TO_ADDR(pos);
|
||
|
const char *lbl;
|
||
|
char buf[500], *p;
|
||
|
|
||
|
g_return_if_fail(calc != NULL);
|
||
|
g_return_if_fail(dv->dbg->dasm != NULL);
|
||
|
|
||
|
if (!(pos & 1) && (lbl = get_label(dv, calc, addr))) {
|
||
|
if (mnemonic) {
|
||
|
*mnemonic = NULL;
|
||
|
*args = g_strdup_printf("%s:", lbl);
|
||
|
}
|
||
|
|
||
|
if (nextpos)
|
||
|
*nextpos = pos + 1;
|
||
|
}
|
||
|
else if (mnemonic) {
|
||
|
tilem_disasm_disassemble(dv->dbg->dasm, calc,
|
||
|
!dv->use_logical, addr,
|
||
|
&addr, buf, sizeof(buf));
|
||
|
|
||
|
p = strchr(buf, '\t');
|
||
|
if (p) {
|
||
|
*mnemonic = g_strndup(buf, p - buf);
|
||
|
*args = g_strdup(p + 1);
|
||
|
}
|
||
|
else {
|
||
|
*mnemonic = g_strdup(buf);
|
||
|
*args = NULL;
|
||
|
}
|
||
|
|
||
|
if (nextpos)
|
||
|
*nextpos = ADDR_TO_POS(addr);
|
||
|
}
|
||
|
else {
|
||
|
tilem_disasm_disassemble(dv->dbg->dasm, calc,
|
||
|
!dv->use_logical, addr,
|
||
|
&addr, NULL, 0);
|
||
|
if (nextpos)
|
||
|
*nextpos = ADDR_TO_POS(addr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Get "next" position */
|
||
|
static dword get_next_pos(TilemDisasmView *dv, TilemCalc *calc, dword pos)
|
||
|
{
|
||
|
disassemble(dv, calc, pos, &pos, NULL, NULL);
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
/* Get "previous" position */
|
||
|
static dword get_prev_pos(TilemDisasmView *dv, TilemCalc *calc, dword pos)
|
||
|
{
|
||
|
dword addr = POS_TO_ADDR(pos);
|
||
|
|
||
|
g_return_val_if_fail(calc != NULL, 0);
|
||
|
|
||
|
if (pos & 1) {
|
||
|
return pos - 1;
|
||
|
}
|
||
|
else {
|
||
|
if (addr > 0)
|
||
|
addr--;
|
||
|
else if (dv->use_logical)
|
||
|
addr = 0xffff;
|
||
|
else
|
||
|
addr = (calc->hw.romsize + calc->hw.ramsize - 1);
|
||
|
|
||
|
if (get_label(dv, calc, addr))
|
||
|
return ADDR_TO_POS(addr) + 1;
|
||
|
else
|
||
|
return ADDR_TO_POS(addr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Convert physical to logical position */
|
||
|
static dword pos_ptol(TilemCalc *calc, dword pos)
|
||
|
{
|
||
|
dword addr;
|
||
|
|
||
|
g_return_val_if_fail(calc != NULL, 0);
|
||
|
|
||
|
if (pos == (dword) -1)
|
||
|
return pos;
|
||
|
|
||
|
addr = default_ptol(calc, POS_TO_ADDR(pos));
|
||
|
return ADDR_TO_POS(addr) + (pos & 1);
|
||
|
}
|
||
|
|
||
|
/* Convert logical to physical position */
|
||
|
static dword pos_ltop(TilemCalc *calc, dword pos)
|
||
|
{
|
||
|
dword addr;
|
||
|
|
||
|
g_return_val_if_fail(calc != NULL, 0);
|
||
|
|
||
|
if (pos == (dword) -1)
|
||
|
return pos;
|
||
|
|
||
|
addr = (*calc->hw.mem_ltop)(calc, POS_TO_ADDR(pos));
|
||
|
return ADDR_TO_POS(addr) + (pos & 1);
|
||
|
}
|
||
|
|
||
|
/* Icons */
|
||
|
|
||
|
static GdkPixbuf *get_icon(TilemDisasmView *dv, gboolean ispc, gboolean isbp)
|
||
|
{
|
||
|
const char *name;
|
||
|
|
||
|
if (ispc && isbp)
|
||
|
name = "tilem-disasm-break-pc";
|
||
|
else if (isbp)
|
||
|
name = "tilem-disasm-break";
|
||
|
else if (ispc)
|
||
|
name = "tilem-disasm-pc";
|
||
|
else
|
||
|
return NULL;
|
||
|
|
||
|
return gtk_widget_render_icon(GTK_WIDGET(dv), name,
|
||
|
GTK_ICON_SIZE_MENU, NULL);
|
||
|
}
|
||
|
|
||
|
/* List model management */
|
||
|
|
||
|
/* Create a new list store for disassembly */
|
||
|
static GtkTreeModel * new_dasm_model()
|
||
|
{
|
||
|
GtkListStore *store;
|
||
|
|
||
|
g_assert(NUM_COLUMNS == 6);
|
||
|
store = gtk_list_store_new(6,
|
||
|
G_TYPE_INT,
|
||
|
G_TYPE_STRING,
|
||
|
G_TYPE_STRING,
|
||
|
G_TYPE_STRING,
|
||
|
G_TYPE_BOOLEAN,
|
||
|
GDK_TYPE_PIXBUF);
|
||
|
|
||
|
return GTK_TREE_MODEL(store);
|
||
|
}
|
||
|
|
||
|
/* Append dummy data to the model; used for sizing */
|
||
|
static void append_dummy_line(TilemDisasmView *dv, GtkTreeModel *model,
|
||
|
GtkTreeIter *iter)
|
||
|
{
|
||
|
GtkTreeIter iter1;
|
||
|
GdkPixbuf *icon;
|
||
|
|
||
|
gtk_list_store_append(GTK_LIST_STORE(model), &iter1);
|
||
|
|
||
|
icon = get_icon(dv, TRUE, FALSE);
|
||
|
|
||
|
gtk_list_store_set(GTK_LIST_STORE(model), &iter1,
|
||
|
COL_ICON, icon,
|
||
|
COL_ADDRESS, "DD:DDDD",
|
||
|
COL_MNEMONIC, "ROM_CALL",
|
||
|
COL_ARGUMENTS, "_fnord",
|
||
|
COL_SHOW_MNEMONIC, TRUE,
|
||
|
-1);
|
||
|
|
||
|
if (icon)
|
||
|
g_object_unref(icon);
|
||
|
|
||
|
if (iter)
|
||
|
*iter = iter1;
|
||
|
}
|
||
|
|
||
|
/* Check if given logical address is a breakpoint (according to
|
||
|
current mapping) */
|
||
|
static TilemDebugBreakpoint *find_bp_logical(TilemDebugger *dbg,
|
||
|
TilemCalc *calc,
|
||
|
dword addr)
|
||
|
{
|
||
|
GSList *l;
|
||
|
TilemDebugBreakpoint *bp;
|
||
|
dword pa = (*calc->hw.mem_ltop)(calc, addr);
|
||
|
|
||
|
for (l = dbg->breakpoints; l; l = l->next) {
|
||
|
bp = l->data;
|
||
|
if (!(bp->mode & TILEM_DB_BREAK_EXEC))
|
||
|
continue;
|
||
|
|
||
|
if (bp->type == TILEM_DB_BREAK_LOGICAL
|
||
|
&& bp->start <= addr
|
||
|
&& bp->end >= addr
|
||
|
&& !bp->disabled)
|
||
|
return bp;
|
||
|
|
||
|
if (bp->type == TILEM_DB_BREAK_PHYSICAL
|
||
|
&& bp->start <= pa
|
||
|
&& bp->end >= pa
|
||
|
&& !bp->disabled)
|
||
|
return bp;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Check if given physical address is a breakpoint (according to
|
||
|
current mapping) */
|
||
|
static TilemDebugBreakpoint *find_bp_physical(TilemDebugger *dbg,
|
||
|
TilemCalc *calc,
|
||
|
dword addr)
|
||
|
{
|
||
|
GSList *l;
|
||
|
TilemDebugBreakpoint *bp;
|
||
|
dword la, pa;
|
||
|
int i, mapped[4];
|
||
|
|
||
|
/* NOTE: this assumes that bits 0-13 are unaffected by the
|
||
|
mapping! This is true for all current models, but might
|
||
|
need to be changed in the future */
|
||
|
for (i = 0; i < 4; i++) {
|
||
|
la = (i << 14) + (addr & 0x3fff);
|
||
|
pa = (*calc->hw.mem_ltop)(calc, la);
|
||
|
mapped[i] = (addr == pa);
|
||
|
}
|
||
|
|
||
|
for (l = dbg->breakpoints; l; l = l->next) {
|
||
|
bp = l->data;
|
||
|
if (!(bp->mode & TILEM_DB_BREAK_EXEC))
|
||
|
continue;
|
||
|
|
||
|
if (bp->type == TILEM_DB_BREAK_PHYSICAL
|
||
|
&& bp->start <= addr
|
||
|
&& bp->end >= addr
|
||
|
&& !bp->disabled)
|
||
|
return bp;
|
||
|
|
||
|
if (bp->type == TILEM_DB_BREAK_LOGICAL
|
||
|
&& !bp->disabled) {
|
||
|
for (i = 0; i < 4; i++) {
|
||
|
la = (i << 14) + (addr & 0x3fff);
|
||
|
if (bp->start <= la
|
||
|
&& bp->end >= la
|
||
|
&& mapped[i])
|
||
|
return bp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Check if line has a breakpoint set */
|
||
|
static TilemDebugBreakpoint *find_line_bp(TilemDisasmView *dv, dword pos)
|
||
|
{
|
||
|
TilemDebugBreakpoint *bp;
|
||
|
dword addr = POS_TO_ADDR(pos);
|
||
|
TilemCalc *calc;
|
||
|
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
|
||
|
if (dv->use_logical)
|
||
|
bp = find_bp_logical(dv->dbg, calc, addr);
|
||
|
else
|
||
|
bp = find_bp_physical(dv->dbg, calc, addr);
|
||
|
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
return bp;
|
||
|
}
|
||
|
|
||
|
/* Enable breakpoint on the given line */
|
||
|
static void enable_line_bp(TilemDisasmView *dv, dword pos)
|
||
|
{
|
||
|
TilemDebugBreakpoint *bp, tmpbp;
|
||
|
|
||
|
if ((bp = find_line_bp(dv, pos)))
|
||
|
return;
|
||
|
|
||
|
tmpbp.type = (dv->use_logical
|
||
|
? TILEM_DB_BREAK_LOGICAL
|
||
|
: TILEM_DB_BREAK_PHYSICAL);
|
||
|
tmpbp.mode = TILEM_DB_BREAK_EXEC;
|
||
|
tmpbp.start = POS_TO_ADDR(pos);
|
||
|
tmpbp.end = POS_TO_ADDR(pos);
|
||
|
tmpbp.mask = (dv->use_logical ? 0xffff : 0xffffffff);
|
||
|
tmpbp.disabled = 0;
|
||
|
tilem_debugger_add_breakpoint(dv->dbg, &tmpbp);
|
||
|
}
|
||
|
|
||
|
/* Disable breakpoint on the given line */
|
||
|
static void disable_line_bp(TilemDisasmView *dv, dword pos)
|
||
|
{
|
||
|
TilemDebugBreakpoint *bp, tmpbp;
|
||
|
|
||
|
if (!(bp = find_line_bp(dv, pos)))
|
||
|
return;
|
||
|
|
||
|
if (bp->mode != TILEM_DB_BREAK_EXEC || bp->start != bp->end) {
|
||
|
/* special breakpoint; do not delete it, just disable it */
|
||
|
tmpbp = *bp;
|
||
|
tmpbp.disabled = 1;
|
||
|
tilem_debugger_change_breakpoint(dv->dbg, bp, &tmpbp);
|
||
|
}
|
||
|
else {
|
||
|
/* regular breakpoint */
|
||
|
tilem_debugger_remove_breakpoint(dv->dbg, bp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Append a line to the dasm model */
|
||
|
static void append_dasm_line(TilemDisasmView *dv, TilemCalc *calc,
|
||
|
GtkTreeModel *model, GtkTreeIter *iter,
|
||
|
dword pos, dword *nextpos)
|
||
|
{
|
||
|
GtkTreeIter iter1;
|
||
|
char *astr, *mnem, *args;
|
||
|
dword addr, pc;
|
||
|
gboolean ispc;
|
||
|
TilemDebugBreakpoint *bp;
|
||
|
GdkPixbuf *icon;
|
||
|
|
||
|
g_return_if_fail(calc != NULL);
|
||
|
|
||
|
gtk_list_store_append(GTK_LIST_STORE(model), &iter1);
|
||
|
|
||
|
addr = POS_TO_ADDR(pos);
|
||
|
astr = tilem_format_addr(dv->dbg, addr, !dv->use_logical);
|
||
|
|
||
|
disassemble(dv, calc, pos, nextpos, &mnem, &args);
|
||
|
|
||
|
if (!mnem)
|
||
|
bp = NULL;
|
||
|
else if (dv->use_logical)
|
||
|
bp = find_bp_logical(dv->dbg, calc, addr);
|
||
|
else
|
||
|
bp = find_bp_physical(dv->dbg, calc, addr);
|
||
|
|
||
|
if (!mnem || !dv->dbg->emu->paused) {
|
||
|
ispc = FALSE;
|
||
|
}
|
||
|
else {
|
||
|
pc = calc->z80.r.pc.w.l;
|
||
|
if (!dv->use_logical)
|
||
|
pc = (*calc->hw.mem_ltop)(calc, pc);
|
||
|
ispc = (addr == pc);
|
||
|
}
|
||
|
|
||
|
icon = get_icon(dv, ispc, (bp != NULL));
|
||
|
|
||
|
gtk_list_store_set(GTK_LIST_STORE(model), &iter1,
|
||
|
COL_POSITION, (int) pos,
|
||
|
COL_ADDRESS, astr,
|
||
|
COL_MNEMONIC, mnem,
|
||
|
COL_SHOW_MNEMONIC, (mnem ? TRUE : FALSE),
|
||
|
COL_ARGUMENTS, args,
|
||
|
COL_ICON, icon,
|
||
|
-1);
|
||
|
|
||
|
if (icon)
|
||
|
g_object_unref(icon);
|
||
|
|
||
|
g_free(astr);
|
||
|
g_free(mnem);
|
||
|
g_free(args);
|
||
|
|
||
|
if (iter)
|
||
|
*iter = iter1;
|
||
|
}
|
||
|
|
||
|
/* Refresh the view by creating and populating a new model */
|
||
|
static void refresh_disassembly(TilemDisasmView *dv, dword pos, int nlines,
|
||
|
dword selectpos)
|
||
|
{
|
||
|
GtkTreeModel *model;
|
||
|
GtkTreeIter iter;
|
||
|
GtkTreePath *selectpath = NULL;
|
||
|
TilemCalc *calc;
|
||
|
dword nextpos;
|
||
|
int i;
|
||
|
|
||
|
model = new_dasm_model();
|
||
|
|
||
|
dv->startpos = pos;
|
||
|
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
|
||
|
if (!calc)
|
||
|
nlines = 0;
|
||
|
|
||
|
for (i = 0; i < nlines; i++) {
|
||
|
append_dasm_line(dv, calc, model, &iter, pos, &nextpos);
|
||
|
|
||
|
if (pos == selectpos)
|
||
|
selectpath = gtk_tree_model_get_path(model, &iter);
|
||
|
|
||
|
pos = nextpos;
|
||
|
}
|
||
|
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
dv->endpos = pos;
|
||
|
dv->nlines = nlines;
|
||
|
|
||
|
gtk_tree_view_set_model(GTK_TREE_VIEW(dv), model);
|
||
|
g_object_unref(model);
|
||
|
|
||
|
if (selectpath) {
|
||
|
gtk_tree_view_set_cursor(GTK_TREE_VIEW(dv), selectpath,
|
||
|
NULL, FALSE);
|
||
|
gtk_tree_path_free(selectpath);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Determine the (absolute) position and (display-relative) line
|
||
|
number of the cursor, if any */
|
||
|
static gboolean get_cursor_line(TilemDisasmView *dv, dword *pos,
|
||
|
int *linenum)
|
||
|
{
|
||
|
GtkTreePath *path;
|
||
|
GtkTreeModel *model;
|
||
|
GtkTreeIter iter;
|
||
|
gint *i, p;
|
||
|
|
||
|
gtk_tree_view_get_cursor(GTK_TREE_VIEW(dv), &path, NULL);
|
||
|
if (!path) {
|
||
|
if (pos) *pos = (dword) -1;
|
||
|
if (linenum) *linenum = -1;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (pos) {
|
||
|
model = gtk_tree_view_get_model(GTK_TREE_VIEW(dv));
|
||
|
if (gtk_tree_model_get_iter(model, &iter, path)) {
|
||
|
gtk_tree_model_get(model, &iter,
|
||
|
COL_POSITION, &p, -1);
|
||
|
*pos = p;
|
||
|
}
|
||
|
else {
|
||
|
*pos = (dword) -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (linenum) {
|
||
|
i = gtk_tree_path_get_indices(path);
|
||
|
*linenum = i[0];
|
||
|
}
|
||
|
|
||
|
gtk_tree_path_free(path);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Size allocation */
|
||
|
|
||
|
/* Get the desired height for the tree view (based on size of the data
|
||
|
we've inserted into the model) */
|
||
|
static int get_parent_request_height(GtkWidget *w)
|
||
|
{
|
||
|
GtkRequisition req;
|
||
|
(*GTK_WIDGET_CLASS(parent_class)->size_request)(w, &req);
|
||
|
return req.height;
|
||
|
}
|
||
|
|
||
|
/* Widget is assigned a size and position */
|
||
|
static void tilem_disasm_view_size_allocate(GtkWidget *w,
|
||
|
GtkAllocation *alloc)
|
||
|
{
|
||
|
TilemDisasmView *dv;
|
||
|
GtkTreeModel *model;
|
||
|
dword curpos;
|
||
|
int n, height1, height2;
|
||
|
|
||
|
g_return_if_fail(TILEM_IS_DISASM_VIEW(w));
|
||
|
dv = TILEM_DISASM_VIEW(w);
|
||
|
|
||
|
(*GTK_WIDGET_CLASS(parent_class)->size_allocate)(w, alloc);
|
||
|
|
||
|
if (alloc->height < 1)
|
||
|
return;
|
||
|
|
||
|
get_cursor_line(dv, &curpos, NULL);
|
||
|
|
||
|
/* Calculate line height */
|
||
|
if (!dv->line_height) {
|
||
|
model = new_dasm_model();
|
||
|
|
||
|
append_dummy_line(dv, model, NULL);
|
||
|
gtk_tree_view_set_model(GTK_TREE_VIEW(dv), model);
|
||
|
height1 = get_parent_request_height(w);
|
||
|
|
||
|
append_dummy_line(dv, model, NULL);
|
||
|
height2 = get_parent_request_height(w);
|
||
|
|
||
|
dv->line_height = height2 - height1;
|
||
|
dv->base_height = height1 - dv->line_height;
|
||
|
|
||
|
g_object_unref(model);
|
||
|
|
||
|
dv->nlines = 0;
|
||
|
|
||
|
if (dv->line_height <= 0) {
|
||
|
dv->line_height = 0;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
n = (alloc->height - dv->base_height) / dv->line_height;
|
||
|
|
||
|
if (n < 1)
|
||
|
n = 1;
|
||
|
|
||
|
if (n != dv->nlines)
|
||
|
refresh_disassembly(dv, dv->startpos, n, curpos);
|
||
|
}
|
||
|
|
||
|
/* Get widget's desired size */
|
||
|
static void tilem_disasm_view_size_request(GtkWidget *w, GtkRequisition *req)
|
||
|
{
|
||
|
(*GTK_WIDGET_CLASS(parent_class)->size_request)(w, req);
|
||
|
req->height = 100; /* ignore requested height */
|
||
|
}
|
||
|
|
||
|
/* Widget style set */
|
||
|
static void tilem_disasm_view_style_set(GtkWidget *w, GtkStyle *oldstyle)
|
||
|
{
|
||
|
TilemDisasmView *dv;
|
||
|
GtkTreeModel *model;
|
||
|
GtkTreeIter iter;
|
||
|
GList *cols, *cp;
|
||
|
GtkTreeViewColumn *col;
|
||
|
int width;
|
||
|
|
||
|
g_return_if_fail(TILEM_IS_DISASM_VIEW(w));
|
||
|
dv = TILEM_DISASM_VIEW(w);
|
||
|
|
||
|
(*GTK_WIDGET_CLASS(parent_class)->style_set)(w, oldstyle);
|
||
|
|
||
|
/* line height must be recalculated */
|
||
|
dv->line_height = 0;
|
||
|
|
||
|
/* set column widths based on a dummy model */
|
||
|
|
||
|
model = new_dasm_model();
|
||
|
append_dummy_line(dv, model, &iter);
|
||
|
|
||
|
cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(dv));
|
||
|
for (cp = cols; cp; cp = cp->next) {
|
||
|
col = cp->data;
|
||
|
gtk_tree_view_column_cell_set_cell_data(col, model, &iter,
|
||
|
FALSE, FALSE);
|
||
|
gtk_tree_view_column_cell_get_size(col, NULL, NULL, NULL,
|
||
|
&width, NULL);
|
||
|
gtk_tree_view_column_set_fixed_width(col, width + 2);
|
||
|
}
|
||
|
g_list_free(cols);
|
||
|
|
||
|
g_object_unref(model);
|
||
|
}
|
||
|
|
||
|
/* Cursor movement commands */
|
||
|
|
||
|
/* Move up by COUNT lines */
|
||
|
static gboolean move_up_lines(TilemDisasmView *dv, int count)
|
||
|
{
|
||
|
TilemCalc *calc;
|
||
|
dword pos;
|
||
|
int linenum;
|
||
|
|
||
|
if (!get_cursor_line(dv, NULL, &linenum))
|
||
|
linenum = 0;
|
||
|
|
||
|
if (linenum >= count)
|
||
|
return FALSE;
|
||
|
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
|
||
|
pos = dv->startpos;
|
||
|
count -= linenum;
|
||
|
while (count > 0) {
|
||
|
pos = get_prev_pos(dv, calc, pos);
|
||
|
count--;
|
||
|
}
|
||
|
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
refresh_disassembly(dv, pos, dv->nlines, pos);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Move down by COUNT lines */
|
||
|
static gboolean move_down_lines(TilemDisasmView *dv, int count)
|
||
|
{
|
||
|
TilemCalc *calc;
|
||
|
dword startpos, selpos;
|
||
|
int linenum;
|
||
|
|
||
|
if (!get_cursor_line(dv, NULL, &linenum))
|
||
|
linenum = -1;
|
||
|
|
||
|
if (linenum + count < dv->nlines)
|
||
|
return FALSE;
|
||
|
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
|
||
|
startpos = get_next_pos(dv, calc, dv->startpos);
|
||
|
selpos = dv->endpos;
|
||
|
count -= dv->nlines - linenum;
|
||
|
|
||
|
while (count > 0) {
|
||
|
startpos = get_next_pos(dv, calc, startpos);
|
||
|
selpos = get_next_pos(dv, calc, selpos);
|
||
|
count--;
|
||
|
}
|
||
|
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
refresh_disassembly(dv, startpos, dv->nlines, selpos);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Move down by COUNT bytes */
|
||
|
static void move_bytes(TilemDisasmView *dv, int count)
|
||
|
{
|
||
|
dword pos, addr;
|
||
|
const TilemCalc *calc = dv->dbg->emu->calc;
|
||
|
|
||
|
g_return_if_fail(calc != NULL);
|
||
|
|
||
|
if (!get_cursor_line(dv, &pos, NULL))
|
||
|
pos = dv->startpos;
|
||
|
|
||
|
addr = POS_TO_ADDR(pos);
|
||
|
|
||
|
if (dv->use_logical)
|
||
|
addr = (addr + count) & 0xffff;
|
||
|
else {
|
||
|
addr += calc->hw.romsize + calc->hw.ramsize + count;
|
||
|
addr %= calc->hw.romsize + calc->hw.ramsize;
|
||
|
}
|
||
|
|
||
|
pos = ADDR_TO_POS(addr);
|
||
|
refresh_disassembly(dv, pos, dv->nlines, pos - 1);
|
||
|
}
|
||
|
|
||
|
/* Move the cursor (action signal) */
|
||
|
static gboolean tilem_disasm_view_move_cursor(GtkTreeView *tv,
|
||
|
GtkMovementStep step,
|
||
|
gint count)
|
||
|
{
|
||
|
TilemDisasmView *dv;
|
||
|
|
||
|
g_return_val_if_fail(TILEM_IS_DISASM_VIEW(tv), FALSE);
|
||
|
dv = TILEM_DISASM_VIEW(tv);
|
||
|
|
||
|
if (!dv->dbg->emu->calc)
|
||
|
return FALSE;
|
||
|
|
||
|
switch (step) {
|
||
|
case GTK_MOVEMENT_DISPLAY_LINES:
|
||
|
if (count < 0) {
|
||
|
if (move_up_lines(dv, -count))
|
||
|
return TRUE;
|
||
|
}
|
||
|
else {
|
||
|
if (move_down_lines(dv, count))
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case GTK_MOVEMENT_PARAGRAPHS:
|
||
|
case GTK_MOVEMENT_PARAGRAPH_ENDS:
|
||
|
case GTK_MOVEMENT_PAGES:
|
||
|
/* FIXME: might be better to move by actual "pages" of code */
|
||
|
move_bytes(dv, count * 0x100);
|
||
|
return TRUE;
|
||
|
|
||
|
case GTK_MOVEMENT_BUFFER_ENDS:
|
||
|
move_bytes(dv, count * 0x4000);
|
||
|
return TRUE;
|
||
|
|
||
|
case GTK_MOVEMENT_LOGICAL_POSITIONS:
|
||
|
case GTK_MOVEMENT_VISUAL_POSITIONS:
|
||
|
case GTK_MOVEMENT_WORDS:
|
||
|
case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
|
||
|
case GTK_MOVEMENT_HORIZONTAL_PAGES:
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return (*GTK_TREE_VIEW_CLASS(parent_class)->move_cursor)(tv, step, count);
|
||
|
}
|
||
|
|
||
|
/* Popup menu */
|
||
|
|
||
|
static void toggle_bp(G_GNUC_UNUSED GtkCheckMenuItem *item, gpointer data)
|
||
|
{
|
||
|
TilemDisasmView *dv = data;
|
||
|
tilem_disasm_view_toggle_breakpoint(dv);
|
||
|
}
|
||
|
|
||
|
void tilem_disasm_view_toggle_breakpoint(TilemDisasmView *dv)
|
||
|
{
|
||
|
dword curpos;
|
||
|
|
||
|
g_return_if_fail(TILEM_IS_DISASM_VIEW(dv));
|
||
|
|
||
|
get_cursor_line(dv, &curpos, NULL);
|
||
|
if (curpos == (dword) -1)
|
||
|
return;
|
||
|
|
||
|
if (find_line_bp(dv, curpos))
|
||
|
disable_line_bp(dv, curpos);
|
||
|
else
|
||
|
enable_line_bp(dv, curpos);
|
||
|
}
|
||
|
|
||
|
static void prompt_go_to(G_GNUC_UNUSED GtkMenuItem *item, gpointer data)
|
||
|
{
|
||
|
TilemDisasmView *dv = data;
|
||
|
GtkWidget *window;
|
||
|
dword curpos, addr;
|
||
|
|
||
|
window = gtk_widget_get_toplevel(GTK_WIDGET(dv));
|
||
|
|
||
|
get_cursor_line(dv, &curpos, NULL);
|
||
|
addr = POS_TO_ADDR(curpos);
|
||
|
|
||
|
if (tilem_prompt_address(dv->dbg, GTK_WINDOW(window),
|
||
|
"Go to Address", "Address:",
|
||
|
&addr, !dv->use_logical,
|
||
|
(curpos != (dword) -1)))
|
||
|
tilem_disasm_view_go_to_address(dv, addr, dv->use_logical);
|
||
|
}
|
||
|
|
||
|
static void go_to_pc(G_GNUC_UNUSED GtkMenuItem *item, gpointer data)
|
||
|
{
|
||
|
TilemDisasmView *dv = data;
|
||
|
TilemCalc *calc;
|
||
|
dword pc;
|
||
|
|
||
|
g_return_if_fail(dv->dbg != NULL);
|
||
|
g_return_if_fail(dv->dbg->emu != NULL);
|
||
|
g_return_if_fail(dv->dbg->emu->calc != NULL);
|
||
|
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
pc = calc->z80.r.pc.w.l;
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
tilem_disasm_view_go_to_address(dv, pc, TRUE);
|
||
|
}
|
||
|
|
||
|
/* Determine where to pop up menu (if not activated by a mouse event) */
|
||
|
static void place_menu(GtkMenu *menu, gint *x, gint *y,
|
||
|
gboolean *push_in, gpointer data)
|
||
|
{
|
||
|
TilemDisasmView *dv = data;
|
||
|
GtkTreePath *path;
|
||
|
GdkRectangle rect;
|
||
|
GdkWindow *win;
|
||
|
GdkScreen *screen;
|
||
|
int n;
|
||
|
|
||
|
win = gtk_tree_view_get_bin_window(GTK_TREE_VIEW(dv));
|
||
|
gdk_window_get_origin(win, x, y);
|
||
|
|
||
|
gtk_tree_view_get_cursor(GTK_TREE_VIEW(dv), &path, NULL);
|
||
|
if (path) {
|
||
|
gtk_tree_view_get_cell_area(GTK_TREE_VIEW(dv), path, NULL, &rect);
|
||
|
gtk_tree_path_free(path);
|
||
|
*y += rect.y + rect.height;
|
||
|
}
|
||
|
|
||
|
screen = gdk_drawable_get_screen(win);
|
||
|
n = gdk_screen_get_monitor_at_point(screen, *x, *y);
|
||
|
gtk_menu_set_monitor(menu, n);
|
||
|
|
||
|
*push_in = FALSE;
|
||
|
}
|
||
|
|
||
|
/* Create and show the popup menu */
|
||
|
static void show_popup_menu(TilemDisasmView *dv, GdkEventButton *event)
|
||
|
{
|
||
|
GtkWidget *menu, *item;
|
||
|
dword curpos;
|
||
|
|
||
|
if (dv->popup_menu)
|
||
|
gtk_widget_destroy(dv->popup_menu);
|
||
|
dv->popup_menu = menu = gtk_menu_new();
|
||
|
|
||
|
/* Enable/disable breakpoint */
|
||
|
|
||
|
item = gtk_check_menu_item_new_with_mnemonic("_Breakpoint Here");
|
||
|
|
||
|
get_cursor_line(dv, &curpos, NULL);
|
||
|
if (curpos == (dword) -1)
|
||
|
gtk_widget_set_sensitive(item, FALSE);
|
||
|
else if (find_line_bp(dv, curpos))
|
||
|
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
|
||
|
|
||
|
g_signal_connect(item, "toggled",
|
||
|
G_CALLBACK(toggle_bp), dv);
|
||
|
|
||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
||
|
gtk_widget_show(item);
|
||
|
|
||
|
item = gtk_separator_menu_item_new();
|
||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
||
|
gtk_widget_show(item);
|
||
|
|
||
|
/* Jump to address */
|
||
|
|
||
|
item = gtk_menu_item_new_with_mnemonic("_Go to Address...");
|
||
|
g_signal_connect(item, "activate", G_CALLBACK(prompt_go_to), dv);
|
||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
||
|
gtk_widget_show(item);
|
||
|
|
||
|
item = gtk_menu_item_new_with_mnemonic("Go to P_C");
|
||
|
g_signal_connect(item, "activate", G_CALLBACK(go_to_pc), dv);
|
||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
||
|
gtk_widget_show(item);
|
||
|
|
||
|
if (event)
|
||
|
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
|
||
|
event->button, event->time);
|
||
|
else
|
||
|
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, &place_menu, dv,
|
||
|
0, gtk_get_current_event_time());
|
||
|
}
|
||
|
|
||
|
/* Button pressed */
|
||
|
static gboolean tilem_disasm_view_button_press(GtkWidget *w,
|
||
|
GdkEventButton *event)
|
||
|
{
|
||
|
g_return_val_if_fail(TILEM_IS_DISASM_VIEW(w), FALSE);
|
||
|
|
||
|
(*GTK_WIDGET_CLASS(parent_class)->button_press_event)(w, event);
|
||
|
|
||
|
if (event->button == 3)
|
||
|
show_popup_menu(TILEM_DISASM_VIEW(w), event);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Key pressed to activate context menu */
|
||
|
static gboolean tilem_disasm_view_popup_menu(GtkWidget *w)
|
||
|
{
|
||
|
g_return_val_if_fail(TILEM_IS_DISASM_VIEW(w), FALSE);
|
||
|
show_popup_menu(TILEM_DISASM_VIEW(w), NULL);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Row activated (double-clicked) */
|
||
|
static void tilem_disasm_view_row_activated(GtkTreeView *tv, GtkTreePath *path,
|
||
|
GtkTreeViewColumn *col)
|
||
|
{
|
||
|
TilemDisasmView *dv = TILEM_DISASM_VIEW(tv);
|
||
|
GtkTreeModel *model;
|
||
|
GtkTreeIter iter;
|
||
|
gint pos;
|
||
|
|
||
|
model = gtk_tree_view_get_model(tv);
|
||
|
if (!gtk_tree_model_get_iter(model, &iter, path))
|
||
|
return;
|
||
|
|
||
|
gtk_tree_model_get(model, &iter, COL_POSITION, &pos, -1);
|
||
|
|
||
|
if (col == dv->icon_column) {
|
||
|
if (find_line_bp(dv, pos))
|
||
|
disable_line_bp(dv, pos);
|
||
|
else
|
||
|
enable_line_bp(dv, pos);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Unrealize widget */
|
||
|
static void tilem_disasm_view_unrealize(GtkWidget *w)
|
||
|
{
|
||
|
TilemDisasmView *dv = TILEM_DISASM_VIEW(w);
|
||
|
|
||
|
if (dv->popup_menu)
|
||
|
gtk_widget_destroy(dv->popup_menu);
|
||
|
dv->popup_menu = NULL;
|
||
|
|
||
|
(*GTK_WIDGET_CLASS(parent_class)->unrealize)(w);
|
||
|
}
|
||
|
|
||
|
/* Initialize a new TilemDisasmView */
|
||
|
static void tilem_disasm_view_init(TilemDisasmView *dv)
|
||
|
{
|
||
|
GtkTreeView *tv = GTK_TREE_VIEW(dv);
|
||
|
GtkCellRenderer *cell;
|
||
|
GtkTreeViewColumn *col;
|
||
|
|
||
|
dv->use_logical = TRUE;
|
||
|
|
||
|
gtk_tree_view_set_enable_search(tv, FALSE);
|
||
|
gtk_tree_view_set_fixed_height_mode(tv, TRUE);
|
||
|
gtk_tree_view_set_headers_visible(tv, FALSE);
|
||
|
|
||
|
cell = gtk_cell_renderer_pixbuf_new();
|
||
|
col = gtk_tree_view_column_new_with_attributes(NULL, cell,
|
||
|
"pixbuf", COL_ICON,
|
||
|
NULL);
|
||
|
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
|
||
|
gtk_tree_view_append_column(tv, col);
|
||
|
dv->icon_column = col;
|
||
|
|
||
|
cell = gtk_cell_renderer_text_new();
|
||
|
col = gtk_tree_view_column_new_with_attributes("Addr", cell,
|
||
|
"text", COL_ADDRESS,
|
||
|
NULL);
|
||
|
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
|
||
|
gtk_tree_view_append_column(tv, col);
|
||
|
|
||
|
col = gtk_tree_view_column_new();
|
||
|
gtk_tree_view_column_set_title(col, "Disassembly");
|
||
|
|
||
|
cell = gtk_cell_renderer_text_new();
|
||
|
g_object_set(cell, "xpad", 10, NULL);
|
||
|
gtk_tree_view_column_pack_start(col, cell, FALSE);
|
||
|
gtk_tree_view_column_set_attributes(col, cell,
|
||
|
"text", COL_MNEMONIC,
|
||
|
"visible", COL_SHOW_MNEMONIC,
|
||
|
NULL);
|
||
|
|
||
|
cell = gtk_cell_renderer_text_new();
|
||
|
gtk_tree_view_column_pack_start(col, cell, TRUE);
|
||
|
gtk_tree_view_column_set_attributes(col, cell,
|
||
|
"text", COL_ARGUMENTS,
|
||
|
NULL);
|
||
|
|
||
|
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
|
||
|
gtk_tree_view_column_set_expand(col, TRUE);
|
||
|
gtk_tree_view_append_column(tv, col);
|
||
|
}
|
||
|
|
||
|
static const char default_style[] =
|
||
|
"style \"tilem-disasm-default\" { font_name = \"Monospace\" } "
|
||
|
"widget \"*.TilemDisasmView\" style:application \"tilem-disasm-default\"";
|
||
|
|
||
|
/* Initialize the TilemDisasmView class */
|
||
|
static void tilem_disasm_view_class_init(TilemDisasmViewClass *klass)
|
||
|
{
|
||
|
GtkTreeViewClass *tv_class = GTK_TREE_VIEW_CLASS(klass);
|
||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
||
|
|
||
|
gtk_rc_parse_string(default_style);
|
||
|
|
||
|
parent_class = g_type_class_peek_parent(klass);
|
||
|
|
||
|
widget_class->style_set = &tilem_disasm_view_style_set;
|
||
|
widget_class->size_request = &tilem_disasm_view_size_request;
|
||
|
widget_class->size_allocate = &tilem_disasm_view_size_allocate;
|
||
|
widget_class->button_press_event = &tilem_disasm_view_button_press;
|
||
|
widget_class->popup_menu = &tilem_disasm_view_popup_menu;
|
||
|
widget_class->unrealize = &tilem_disasm_view_unrealize;
|
||
|
tv_class->move_cursor = &tilem_disasm_view_move_cursor;
|
||
|
tv_class->row_activated = &tilem_disasm_view_row_activated;
|
||
|
}
|
||
|
|
||
|
GtkWidget * tilem_disasm_view_new(TilemDebugger *dbg)
|
||
|
{
|
||
|
TilemDisasmView *dv;
|
||
|
|
||
|
g_return_val_if_fail(dbg != NULL, NULL);
|
||
|
|
||
|
dv = g_object_new(TILEM_TYPE_DISASM_VIEW, NULL);
|
||
|
dv->dbg = dbg;
|
||
|
|
||
|
return GTK_WIDGET(dv);
|
||
|
}
|
||
|
|
||
|
/* Select memory addressing mode. */
|
||
|
void tilem_disasm_view_set_logical(TilemDisasmView *dv, gboolean logical)
|
||
|
{
|
||
|
dword start, curpos;
|
||
|
TilemCalc *calc;
|
||
|
|
||
|
g_return_if_fail(TILEM_IS_DISASM_VIEW(dv));
|
||
|
g_return_if_fail(dv->dbg->emu->calc != NULL);
|
||
|
|
||
|
get_cursor_line(dv, &curpos, NULL);
|
||
|
|
||
|
if (logical && !dv->use_logical) {
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
curpos = pos_ptol(calc, curpos);
|
||
|
start = pos_ptol(calc, dv->startpos);
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
dv->use_logical = TRUE;
|
||
|
refresh_disassembly(dv, start, dv->nlines, curpos);
|
||
|
}
|
||
|
else if (!logical && dv->use_logical) {
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
curpos = pos_ltop(calc, curpos);
|
||
|
start = pos_ltop(calc, dv->startpos);
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
dv->use_logical = FALSE;
|
||
|
refresh_disassembly(dv, start, dv->nlines, curpos);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Refresh contents of view. */
|
||
|
void tilem_disasm_view_refresh(TilemDisasmView *dv)
|
||
|
{
|
||
|
dword curpos;
|
||
|
g_return_if_fail(TILEM_IS_DISASM_VIEW(dv));
|
||
|
get_cursor_line(dv, &curpos, NULL);
|
||
|
refresh_disassembly(dv, dv->startpos, dv->nlines, curpos);
|
||
|
}
|
||
|
|
||
|
/* Find tree path for the given position */
|
||
|
static GtkTreePath *find_path_for_position(GtkTreeModel *model, int pos)
|
||
|
{
|
||
|
gint p;
|
||
|
GtkTreeIter iter;
|
||
|
|
||
|
if (!gtk_tree_model_get_iter_first(model, &iter))
|
||
|
return NULL;
|
||
|
|
||
|
do {
|
||
|
gtk_tree_model_get(model, &iter, COL_POSITION, &p, -1);
|
||
|
if (p == pos) {
|
||
|
return gtk_tree_model_get_path(model, &iter);
|
||
|
}
|
||
|
} while (gtk_tree_model_iter_next(model, &iter));
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Highlight the specified address. */
|
||
|
void tilem_disasm_view_go_to_address(TilemDisasmView *dv, dword addr,
|
||
|
gboolean logical)
|
||
|
{
|
||
|
dword pos;
|
||
|
GtkTreeModel *model;
|
||
|
GtkTreePath *path;
|
||
|
TilemCalc *calc;
|
||
|
|
||
|
g_return_if_fail(TILEM_IS_DISASM_VIEW(dv));
|
||
|
|
||
|
tilem_calc_emulator_lock(dv->dbg->emu);
|
||
|
calc = dv->dbg->emu->calc;
|
||
|
|
||
|
if (logical) {
|
||
|
addr &= 0xffff;
|
||
|
if (dv->use_logical)
|
||
|
pos = ADDR_TO_POS(addr);
|
||
|
else
|
||
|
pos = pos_ltop(calc, ADDR_TO_POS(addr));
|
||
|
}
|
||
|
else {
|
||
|
if (dv->use_logical) {
|
||
|
addr = (*calc->hw.mem_ptol)(calc, addr);
|
||
|
if (addr == (dword) -1) {
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
pos = ADDR_TO_POS(addr);
|
||
|
}
|
||
|
|
||
|
tilem_calc_emulator_unlock(dv->dbg->emu);
|
||
|
|
||
|
if (pos >= dv->startpos && pos < dv->endpos) {
|
||
|
model = gtk_tree_view_get_model(GTK_TREE_VIEW(dv));
|
||
|
path = find_path_for_position(model, pos);
|
||
|
if (path) {
|
||
|
gtk_tree_view_set_cursor(GTK_TREE_VIEW(dv), path,
|
||
|
NULL, FALSE);
|
||
|
gtk_tree_path_free(path);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
refresh_disassembly(dv, pos, dv->nlines, pos);
|
||
|
}
|
||
|
|
||
|
/* Get currently selected address. */
|
||
|
gboolean tilem_disasm_view_get_cursor(TilemDisasmView *dv, dword *addr,
|
||
|
gboolean *is_logical)
|
||
|
{
|
||
|
dword pos;
|
||
|
|
||
|
g_return_val_if_fail(TILEM_IS_DISASM_VIEW(dv), FALSE);
|
||
|
|
||
|
if (is_logical) *is_logical = dv->use_logical;
|
||
|
|
||
|
if (!get_cursor_line(dv, &pos, NULL))
|
||
|
return FALSE;
|
||
|
|
||
|
if (addr) *addr = POS_TO_ADDR(pos);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|