ti83-sdk/tool/tilem-src/gui/address.c

243 lines
6.2 KiB
C

/*
* TilEm II
*
* Copyright (c) 2011 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 <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <ticalcs.h>
#include <tilem.h>
#include <tilemdb.h>
#include "gui.h"
char * tilem_format_addr(TilemDebugger *dbg, dword addr, gboolean physical)
{
dword page, addr_l;
g_return_val_if_fail(dbg != NULL, NULL);
g_return_val_if_fail(dbg->emu != NULL, NULL);
g_return_val_if_fail(dbg->emu->calc != NULL, NULL);
if (!physical)
return g_strdup_printf("%04X", addr);
if (addr >= dbg->emu->calc->hw.romsize)
page = (((addr - dbg->emu->calc->hw.romsize) >> 14)
+ dbg->emu->calc->hw.rampagemask);
else
page = addr >> 14;
addr_l = (*dbg->emu->calc->hw.mem_ptol)(dbg->emu->calc, addr);
if (addr_l == 0xffffffff)
addr_l = (addr & 0x3fff) | 0x4000;
return g_strdup_printf("%02X:%04X", page, addr_l);
}
static gboolean parse_hex(const char *string, dword *value)
{
const char *n;
char *e;
dword a;
if (string[0] == '$')
n = string + 1;
else if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
n = string + 2;
else
n = string;
a = strtol(n, &e, 16);
if (value)
*value = a;
if (e == n)
return FALSE;
if (*e == 'h' || *e == 'H')
e++;
return (*e == 0);
}
gboolean tilem_parse_paged_addr(TilemDebugger *dbg, const char *pagestr,
const char *offsstr, dword *value)
{
dword page, offs;
g_return_val_if_fail(dbg != NULL, FALSE);
g_return_val_if_fail(dbg->emu != NULL, FALSE);
g_return_val_if_fail(dbg->emu->calc != NULL, FALSE);
if (!parse_hex(pagestr, &page))
return FALSE;
if (!tilem_parse_addr(dbg, offsstr, &offs, NULL))
return FALSE;
offs &= 0x3fff;
if (page & dbg->emu->calc->hw.rampagemask) {
page &= ~dbg->emu->calc->hw.rampagemask;
offs += (offs << 14);
if (offs > dbg->emu->calc->hw.ramsize)
return FALSE;
offs += dbg->emu->calc->hw.romsize;
}
else {
offs += (page << 14);
if (offs > dbg->emu->calc->hw.romsize)
return FALSE;
}
if (value) *value = offs;
return TRUE;
}
gboolean tilem_parse_addr(TilemDebugger *dbg, const char *string,
dword *value, gboolean *physical)
{
const char *offstr;
char *pagestr;
g_return_val_if_fail(dbg != NULL, FALSE);
g_return_val_if_fail(dbg->emu != NULL, FALSE);
g_return_val_if_fail(dbg->emu->calc != NULL, FALSE);
if (parse_hex(string, value)) {
if (physical) *physical = FALSE;
return TRUE;
}
if (physical && (offstr = strchr(string, ':'))) {
pagestr = g_strndup(string, offstr - string);
offstr++;
if (tilem_parse_paged_addr(dbg, pagestr, offstr, value)) {
*physical = TRUE;
return TRUE;
}
}
if (dbg->dasm && tilem_disasm_get_label(dbg->dasm, string, value)) {
if (physical) *physical = FALSE;
return TRUE;
}
return FALSE;
}
struct addrdlg {
GtkWidget *dlg;
TilemDebugger *dbg;
gboolean physical;
};
static void edited(GtkEntry *entry, gpointer data)
{
struct addrdlg *adlg = data;
const char *text;
gboolean valid, phys;
text = gtk_entry_get_text(entry);
valid = tilem_parse_addr(adlg->dbg, text, NULL,
adlg->physical ? &phys : NULL);
gtk_dialog_set_response_sensitive(GTK_DIALOG(adlg->dlg),
GTK_RESPONSE_OK,
valid);
}
gboolean tilem_prompt_address(TilemDebugger *dbg, GtkWindow *parent,
const char *title, const char *prompt,
dword *value, gboolean physical,
gboolean usedefault)
{
GtkWidget *dlg, *hbox, *vbox, *lbl, *ent;
struct addrdlg adlg;
const char *text;
gboolean phys;
char *s;
g_return_val_if_fail(dbg != NULL, FALSE);
g_return_val_if_fail(dbg->emu != NULL, FALSE);
g_return_val_if_fail(dbg->emu->calc != NULL, FALSE);
dlg = gtk_dialog_new_with_buttons(title, parent, GTK_DIALOG_MODAL,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_dialog_set_default_response(GTK_DIALOG(dlg),
GTK_RESPONSE_OK);
hbox = gtk_hbox_new(FALSE, 6);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
lbl = gtk_label_new(prompt);
gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
ent = gtk_entry_new();
gtk_entry_set_activates_default(GTK_ENTRY(ent), TRUE);
gtk_box_pack_start(GTK_BOX(hbox), ent, TRUE, TRUE, 0);
if (usedefault) {
s = tilem_format_addr(dbg, *value, physical);
gtk_entry_set_text(GTK_ENTRY(ent), s);
g_free(s);
}
adlg.dlg = dlg;
adlg.dbg = dbg;
adlg.physical = physical;
g_signal_connect(ent, "changed",
G_CALLBACK(edited), &adlg);
edited(GTK_ENTRY(ent), &adlg);
gtk_widget_show_all(hbox);
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
if (gtk_dialog_run(GTK_DIALOG(dlg)) != GTK_RESPONSE_OK) {
gtk_widget_destroy(dlg);
return FALSE;
}
text = gtk_entry_get_text(GTK_ENTRY(ent));
if (!tilem_parse_addr(dbg, text, value, physical ? &phys : NULL)) {
gtk_widget_destroy(dlg);
return FALSE;
}
if (physical && !phys) {
tilem_calc_emulator_lock(dbg->emu);
*value &= 0xffff;
*value = (*dbg->emu->calc->hw.mem_ltop)(dbg->emu->calc, *value);
tilem_calc_emulator_unlock(dbg->emu);
}
gtk_widget_destroy(dlg);
return TRUE;
}