1 /*
2  * TilEm II
3  *
4  * Copyright (c) 2010-2011 Thibault Duponchelle
5  * Copyright (c) 2010-2011 Benjamin Moody
6  *
7  * This program is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <gtk/gtk.h>
29 #include <glib/gstdio.h>
30 #include <ticalcs.h>
31 #include <tilem.h>
32 #include <tilemdb.h>
33 
34 #include "gui.h"
35 #include "memmodel.h"
36 #include "fixedtreeview.h"
37 
get_column_index(GtkWidget * view,GtkTreeViewColumn * col)38 static int get_column_index(GtkWidget *view, GtkTreeViewColumn *col)
39 {
40 	GList *cols;
41 	int i;
42 
43 	cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
44 	i = g_list_index(cols, col);
45 	g_list_free(cols);
46 	return -1;
47 }
48 
49 /* Determine current position in the memory view. */
get_mem_view_position(GtkWidget * mem_view,dword * row_addr,dword * col_addr,gboolean * cur_hex)50 static void get_mem_view_position(GtkWidget *mem_view, dword *row_addr,
51                                   dword *col_addr, gboolean *cur_hex)
52 {
53 	GtkTreePath *path;
54 	GtkTreeViewColumn *col;
55 	GtkTreeModel *model;
56 	TilemMemModel *mm;
57 	const int *indices;
58 	int n;
59 
60 	*row_addr = *col_addr = (dword) -1;
61 	*cur_hex = FALSE;
62 
63 	gtk_tree_view_get_cursor(GTK_TREE_VIEW(mem_view), &path, &col);
64 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mem_view));
65 	if (!TILEM_IS_MEM_MODEL(model))
66 		return;
67 
68 	mm = TILEM_MEM_MODEL(model);
69 
70 	if (!path)
71 		return;
72 
73 	indices = gtk_tree_path_get_indices(path);
74 	*row_addr = mm->start_addr + indices[0] * mm->row_size;
75 
76 	n = get_column_index(mem_view, col);
77 	if (n > 0 && n <= mm->row_size) {
78 		*col_addr = *row_addr + n - 1;
79 		*cur_hex = TRUE;
80 	}
81 	else if (n > mm->row_size && n < mm->row_size * 2) {
82 		*col_addr = *row_addr + n - mm->row_size - 1;
83 		*cur_hex = FALSE;
84 	}
85 
86 	gtk_tree_path_free(path);
87 }
88 
addr_to_pos(TilemMemModel * mm,dword addr,int * rownum,int * colnum)89 static void addr_to_pos(TilemMemModel *mm, dword addr,
90                         int *rownum, int *colnum)
91 {
92 	if (addr < mm->start_addr)
93 		addr += mm->wrap_addr;
94 	addr -= mm->start_addr;
95 	if (rownum) *rownum = (addr / mm->row_size);
96 	if (colnum) *colnum = (addr % mm->row_size);
97 }
98 
99 /* Move memory view cursor */
set_mem_view_position(GtkWidget * mem_view,dword row_addr,dword col_addr,gboolean cur_hex)100 static void set_mem_view_position(GtkWidget *mem_view, dword row_addr,
101                                   dword col_addr, gboolean cur_hex)
102 {
103 	int rownum, colnum;
104 	GtkTreePath *path = NULL;
105 	GtkTreeViewColumn *col = NULL;
106 	GtkTreeModel *model;
107 	TilemMemModel *mm;
108 
109 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mem_view));
110 	if (!TILEM_IS_MEM_MODEL(model))
111 		return;
112 
113 	mm = TILEM_MEM_MODEL(model);
114 
115 	if (col_addr != (dword) -1) {
116 		addr_to_pos(mm, col_addr, &rownum, &colnum);
117 		path = gtk_tree_path_new_from_indices(rownum, -1);
118 
119 		if (!cur_hex)
120 			colnum += mm->row_size;
121 
122 		col = gtk_tree_view_get_column(GTK_TREE_VIEW(mem_view),
123 		                               colnum + 1);
124 	}
125 	else if (row_addr != (dword) -1) {
126 		addr_to_pos(mm, row_addr, &rownum, NULL);
127 		path = gtk_tree_path_new_from_indices(rownum, -1);
128 	}
129 
130 	if (path) {
131 		gtk_tree_view_set_cursor(GTK_TREE_VIEW(mem_view),
132 		                         path, col, FALSE);
133 		gtk_tree_path_free(path);
134 	}
135 }
136 
137 /* Cell edited in memory view */
hex_cell_edited(GtkCellRendererText * renderer,gchar * pathstr,gchar * text,gpointer data)138 static void hex_cell_edited(GtkCellRendererText *renderer,
139                             gchar *pathstr, gchar *text,
140                             gpointer data)
141 {
142 	GtkTreeView *mem_view = data;
143 	TilemDebugger *dbg;
144 	GtkTreeModel *model;
145 	GtkTreePath *path;
146 	GtkTreeIter iter;
147 	byte *bptr = NULL;
148 	int col;
149 	int value;
150 	char *end;
151 
152 	value = strtol(text, &end, 16);
153 	if (end == text || *end != 0)
154 		return;
155 
156 	dbg = g_object_get_data(G_OBJECT(mem_view), "tilem-debugger");
157 	g_return_if_fail(dbg != NULL);
158 
159 	col = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(renderer),
160 	                                        "tilem-mem-column"));
161 
162 	model = gtk_tree_view_get_model(mem_view);
163 	path = gtk_tree_path_new_from_string(pathstr);
164 	gtk_tree_model_get_iter(model, &iter, path);
165 	gtk_tree_path_free(path);
166 
167 	gtk_tree_model_get(model, &iter, MM_COL_BYTE_PTR(col), &bptr, -1);
168 	g_return_if_fail(bptr != NULL);
169 
170 	*bptr = (byte) value;
171 	tilem_debugger_refresh(dbg, TRUE);
172 }
173 
174 /* Create the GtkTreeView to show the memory */
tilem_debugger_mem_view_new(TilemDebugger * dbg)175 GtkWidget *tilem_debugger_mem_view_new(TilemDebugger *dbg)
176 {
177 	GtkCellRenderer     *renderer;
178 	GtkTreeViewColumn   *column;
179 	GtkWidget           *treeview;
180 
181 	/* Create the memory list tree view and set title invisible */
182 	treeview = gtk_tree_view_new();
183 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
184 	gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), TRUE);
185 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
186 
187 	g_object_set_data(G_OBJECT(treeview), "tilem-debugger", dbg);
188 
189 	/* Create the columns */
190 	renderer = gtk_cell_renderer_text_new ();
191 	column = gtk_tree_view_column_new_with_attributes
192 		("ADDR", renderer, "text", MM_COL_ADDRESS(0), NULL);
193 
194 	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
195 	gtk_tree_view_column_set_expand(column, TRUE);
196 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
197 
198 	return treeview;
199 }
200 
create_columns(GtkWidget * mem_view,int width)201 static void create_columns(GtkWidget *mem_view, int width)
202 {
203 	GtkCellRenderer     *renderer;
204 	GtkTreeViewColumn   *column;
205 	int i;
206 
207 	for (i = 0; i < width; i++) {
208 		renderer = gtk_cell_renderer_text_new();
209 		column = gtk_tree_view_column_new_with_attributes
210 			(NULL, renderer,
211 			 "text", MM_COL_HEX(i),
212 			 "editable", MM_COL_EDITABLE(i),
213 			 NULL);
214 
215 		g_object_set_data(G_OBJECT(renderer), "tilem-mem-column",
216 		                  GINT_TO_POINTER(i));
217 		g_signal_connect(renderer, "edited",
218 		                 G_CALLBACK(hex_cell_edited), mem_view);
219 
220 		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
221 		gtk_tree_view_column_set_expand(column, (i == width - 1));
222 		gtk_tree_view_append_column(GTK_TREE_VIEW(mem_view), column);
223 	}
224 
225 	for (i = 0; i < width; i++) {
226 		renderer = gtk_cell_renderer_text_new();
227 		column = gtk_tree_view_column_new_with_attributes
228 			(NULL, renderer, "text", MM_COL_CHAR(i), NULL);
229 
230 		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
231 		gtk_tree_view_column_set_expand(column, (i == width - 1));
232 		gtk_tree_view_append_column(GTK_TREE_VIEW(mem_view), column);
233 	}
234 }
235 
translate_addr(TilemCalcEmulator * emu,dword a,gboolean ptol)236 static dword translate_addr(TilemCalcEmulator *emu, dword a, gboolean ptol)
237 {
238 	if (!emu->calc || a == (dword) -1)
239 		return a;
240 	if (ptol)
241 		return (*emu->calc->hw.mem_ptol)(emu->calc, a);
242 	else
243 		return (*emu->calc->hw.mem_ltop)(emu->calc, a & 0xffff);
244 }
245 
tilem_debugger_mem_view_configure(GtkWidget * mem_view,TilemCalcEmulator * emu,int rowsize,int start,gboolean logical)246 void tilem_debugger_mem_view_configure(GtkWidget *mem_view,
247                                        TilemCalcEmulator *emu,
248                                        int rowsize, int start,
249                                        gboolean logical)
250 {
251 	GtkTreeModel *model;
252 	dword row_addr, col_addr;
253 	gboolean cur_hex;
254 	GList *cols, *l;
255 	int old_rowsize;
256 
257 	get_mem_view_position(mem_view, &row_addr, &col_addr, &cur_hex);
258 
259 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(mem_view));
260 	if (TILEM_IS_MEM_MODEL(model)
261 	    && TILEM_MEM_MODEL(model)->use_logical != logical) {
262 		tilem_calc_emulator_lock(emu);
263 		row_addr = translate_addr(emu, row_addr, logical);
264 		col_addr = translate_addr(emu, col_addr, logical);
265 		tilem_calc_emulator_unlock(emu);
266 	}
267 
268 	cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(mem_view));
269 	old_rowsize = (g_list_length(cols) - 1) / 2;
270 	if (old_rowsize != rowsize)
271 		for (l = g_list_next(cols); l; l = l->next)
272 			gtk_tree_view_remove_column(GTK_TREE_VIEW(mem_view),
273 			                            l->data);
274 	g_list_free(cols);
275 
276 	model = tilem_mem_model_new(emu, rowsize, start, logical);
277 	gtk_tree_view_set_model(GTK_TREE_VIEW(mem_view), model);
278 	g_object_unref(model);
279 
280 	if (old_rowsize != rowsize)
281 		create_columns(mem_view, rowsize);
282 
283 	fixed_tree_view_init(mem_view, MM_COLUMNS_PER_BYTE,
284 	                     MM_COL_ADDRESS_0, "DD:DDDD ",
285 	                     MM_COL_HEX_0, "DD ",
286 	                     MM_COL_CHAR_0, "M ",
287 	                     MM_COL_EDITABLE_0, TRUE,
288 	                     -1);
289 
290 	set_mem_view_position(mem_view, row_addr, col_addr, cur_hex);
291 }
292