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