1 /*
2  * TilEm II
3  *
4  * Copyright (c) 2011 Benjamin Moody
5  *
6  * This program is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <gtk/gtk.h>
28 #include <ticalcs.h>
29 #include <tilem.h>
30 #include <tilemdb.h>
31 
32 #include "gui.h"
33 
tilem_format_addr(TilemDebugger * dbg,dword addr,gboolean physical)34 char * tilem_format_addr(TilemDebugger *dbg, dword addr, gboolean physical)
35 {
36 	dword page, addr_l;
37 
38 	g_return_val_if_fail(dbg != NULL, NULL);
39 	g_return_val_if_fail(dbg->emu != NULL, NULL);
40 	g_return_val_if_fail(dbg->emu->calc != NULL, NULL);
41 
42 	if (!physical)
43 		return g_strdup_printf("%04X", addr);
44 
45 	if (addr >= dbg->emu->calc->hw.romsize)
46 		page = (((addr - dbg->emu->calc->hw.romsize) >> 14)
47 		        + dbg->emu->calc->hw.rampagemask);
48 	else
49 		page = addr >> 14;
50 
51 	addr_l = (*dbg->emu->calc->hw.mem_ptol)(dbg->emu->calc, addr);
52 	if (addr_l == 0xffffffff)
53 		addr_l = (addr & 0x3fff) | 0x4000;
54 
55 	return g_strdup_printf("%02X:%04X", page, addr_l);
56 }
57 
parse_hex(const char * string,dword * value)58 static gboolean parse_hex(const char *string, dword *value)
59 {
60 	const char *n;
61 	char *e;
62 	dword a;
63 
64 	if (string[0] == '$')
65 		n = string + 1;
66 	else if (string[0] == '0' && (string[1] == 'x' || string[1] == 'X'))
67 		n = string + 2;
68 	else
69 		n = string;
70 
71 	a = strtol(n, &e, 16);
72 	if (value)
73 		*value = a;
74 
75 	if (e == n)
76 		return FALSE;
77 
78 	if (*e == 'h' || *e == 'H')
79 		e++;
80 
81 	return (*e == 0);
82 }
83 
tilem_parse_paged_addr(TilemDebugger * dbg,const char * pagestr,const char * offsstr,dword * value)84 gboolean tilem_parse_paged_addr(TilemDebugger *dbg, const char *pagestr,
85                                 const char *offsstr, dword *value)
86 {
87 	dword page, offs;
88 
89 	g_return_val_if_fail(dbg != NULL, FALSE);
90 	g_return_val_if_fail(dbg->emu != NULL, FALSE);
91 	g_return_val_if_fail(dbg->emu->calc != NULL, FALSE);
92 
93 	if (!parse_hex(pagestr, &page))
94 		return FALSE;
95 	if (!tilem_parse_addr(dbg, offsstr, &offs, NULL))
96 		return FALSE;
97 
98 	offs &= 0x3fff;
99 	if (page & dbg->emu->calc->hw.rampagemask) {
100 		page &= ~dbg->emu->calc->hw.rampagemask;
101 		offs += (offs << 14);
102 		if (offs > dbg->emu->calc->hw.ramsize)
103 			return FALSE;
104 		offs += dbg->emu->calc->hw.romsize;
105 	}
106 	else {
107 		offs += (page << 14);
108 		if (offs > dbg->emu->calc->hw.romsize)
109 			return FALSE;
110 	}
111 
112 	if (value) *value = offs;
113 	return TRUE;
114 }
115 
tilem_parse_addr(TilemDebugger * dbg,const char * string,dword * value,gboolean * physical)116 gboolean tilem_parse_addr(TilemDebugger *dbg, const char *string,
117                           dword *value, gboolean *physical)
118 {
119 	const char *offstr;
120 	char *pagestr;
121 
122 	g_return_val_if_fail(dbg != NULL, FALSE);
123 	g_return_val_if_fail(dbg->emu != NULL, FALSE);
124 	g_return_val_if_fail(dbg->emu->calc != NULL, FALSE);
125 
126 	if (parse_hex(string, value)) {
127 		if (physical) *physical = FALSE;
128 		return TRUE;
129 	}
130 
131 	if (physical && (offstr = strchr(string, ':'))) {
132 		pagestr = g_strndup(string, offstr - string);
133 		offstr++;
134 		if (tilem_parse_paged_addr(dbg, pagestr, offstr, value)) {
135 			*physical = TRUE;
136 			return TRUE;
137 		}
138 	}
139 
140 	if (dbg->dasm && tilem_disasm_get_label(dbg->dasm, string, value)) {
141 		if (physical) *physical = FALSE;
142 		return TRUE;
143 	}
144 
145 	return FALSE;
146 }
147 
148 struct addrdlg {
149 	GtkWidget *dlg;
150 	TilemDebugger *dbg;
151 	gboolean physical;
152 };
153 
edited(GtkEntry * entry,gpointer data)154 static void edited(GtkEntry *entry, gpointer data)
155 {
156 	struct addrdlg *adlg = data;
157 	const char *text;
158 	gboolean valid, phys;
159 
160 	text = gtk_entry_get_text(entry);
161 	valid = tilem_parse_addr(adlg->dbg, text, NULL,
162 	                         adlg->physical ? &phys : NULL);
163 	gtk_dialog_set_response_sensitive(GTK_DIALOG(adlg->dlg),
164 	                                  GTK_RESPONSE_OK,
165 	                                  valid);
166 }
167 
tilem_prompt_address(TilemDebugger * dbg,GtkWindow * parent,const char * title,const char * prompt,dword * value,gboolean physical,gboolean usedefault)168 gboolean tilem_prompt_address(TilemDebugger *dbg, GtkWindow *parent,
169                               const char *title, const char *prompt,
170                               dword *value, gboolean physical,
171                               gboolean usedefault)
172 {
173 	GtkWidget *dlg, *hbox, *vbox, *lbl, *ent;
174 	struct addrdlg adlg;
175 	const char *text;
176 	gboolean phys;
177 	char *s;
178 
179 	g_return_val_if_fail(dbg != NULL, FALSE);
180 	g_return_val_if_fail(dbg->emu != NULL, FALSE);
181 	g_return_val_if_fail(dbg->emu->calc != NULL, FALSE);
182 
183 	dlg = gtk_dialog_new_with_buttons(title, parent, GTK_DIALOG_MODAL,
184 	                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
185 	                                  GTK_STOCK_OK, GTK_RESPONSE_OK,
186 	                                  NULL);
187 	gtk_dialog_set_alternative_button_order(GTK_DIALOG(dlg),
188 	                                        GTK_RESPONSE_OK,
189 	                                        GTK_RESPONSE_CANCEL,
190 	                                        -1);
191 	gtk_dialog_set_default_response(GTK_DIALOG(dlg),
192 	                                GTK_RESPONSE_OK);
193 
194 	hbox = gtk_hbox_new(FALSE, 6);
195 	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
196 
197 	lbl = gtk_label_new(prompt);
198 	gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
199 
200 	ent = gtk_entry_new();
201 	gtk_entry_set_activates_default(GTK_ENTRY(ent), TRUE);
202 	gtk_box_pack_start(GTK_BOX(hbox), ent, TRUE, TRUE, 0);
203 
204 	if (usedefault) {
205 		s = tilem_format_addr(dbg, *value, physical);
206 		gtk_entry_set_text(GTK_ENTRY(ent), s);
207 		g_free(s);
208 	}
209 
210 	adlg.dlg = dlg;
211 	adlg.dbg = dbg;
212 	adlg.physical = physical;
213 
214 	g_signal_connect(ent, "changed",
215 	                 G_CALLBACK(edited), &adlg);
216 	edited(GTK_ENTRY(ent), &adlg);
217 
218 	gtk_widget_show_all(hbox);
219 	vbox = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
220 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
221 
222 	if (gtk_dialog_run(GTK_DIALOG(dlg)) != GTK_RESPONSE_OK) {
223 		gtk_widget_destroy(dlg);
224 		return FALSE;
225 	}
226 
227 	text = gtk_entry_get_text(GTK_ENTRY(ent));
228 	if (!tilem_parse_addr(dbg, text, value, physical ? &phys : NULL)) {
229 		gtk_widget_destroy(dlg);
230 		return FALSE;
231 	}
232 
233 	if (physical && !phys) {
234 		tilem_calc_emulator_lock(dbg->emu);
235 		*value &= 0xffff;
236 		*value = (*dbg->emu->calc->hw.mem_ltop)(dbg->emu->calc, *value);
237 		tilem_calc_emulator_unlock(dbg->emu);
238 	}
239 
240 	gtk_widget_destroy(dlg);
241 	return TRUE;
242 }
243