* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
- * 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 2 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ * This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
#endif
#include <stdio.h>
+#include <stdbool.h>
#include <ctype.h> /* For isprint */
#include <zlib.h> /* For crc32 routine */
#include "cpu8051.h"
#include "regwin.h"
#include "memwin.h"
-#include "emugtk.h"
+#include "main.h"
#include "options.h"
+#include "log.h"
#include "app-config.h"
extern struct app_config_t *cfg;
static int COL_ASCII;
static int N_COLUMNS;
-enum
-{
+enum {
COL_ADDRESS = 0,
COL_DATA0,
};
-static GtkWidget *memlist_internal;
-static GtkWidget *memlist_external;
-
-static int data_rows_internal;
-static int data_rows_external;
+/* Contains informations for the two different memory window types. */
+struct memwin_infos_t {
+ GtkWidget *memlist;
+ int data_rows;
+ u_int32_t *crc;
+ int crc_init;
+};
-static u_int32_t *crc_internal;
-static u_int32_t *crc_external;
+static struct memwin_infos_t memwin_infos_internal;
+static struct memwin_infos_t memwin_infos_external;
+static struct memwin_infos_t *memwin_infos;
/* Creating a model */
static GtkListStore *
int new;
char *str;
- if (!model) {
- g_error("Unable to get model from cell renderer");
- }
+ if (!model)
+ log_err("Unable to get model from cell renderer");
/* Column number is passed as renderer object data */
- columnptr = g_object_get_data(G_OBJECT(cell), "column");
- column = GPOINTER_TO_UINT(columnptr);
+ columnptr = g_object_get_data(G_OBJECT(cell), "column");
+ column = GPOINTER_TO_UINT(columnptr);
/* Memory ID is passed as renderer object data */
memory_id_ptr = g_object_get_data(G_OBJECT(cell), "memory_id");
memory_id = GPOINTER_TO_UINT(memory_id_ptr);
/* Get the iterator */
- gtk_tree_model_get_iter_from_string(model, &iter, path_string);
+ gtk_tree_model_get_iter_from_string(model, &iter, path_string);
/* Get base address. */
gtk_tree_model_get(model, &iter, COL_ADDRESS, &str, -1);
int2asciihex(new, str, 2);
/* Store new value in gtk model. */
- gtk_list_store_set(GTK_LIST_STORE(model), &iter, column, str, -1);
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter, column, str, -1);
/*
* Make sure to update all registers and memory.
* For example, BANKed registers depends on internal memory.
*/
- emugtk_UpdateDisplay();
+ emugtk_update_display();
};
static void
gtk_tree_view_get_model(
GTK_TREE_VIEW(listview)));
- /* Add column index and memory_id, used when editing the cell. */
+ /* Add column index and memory_id, used when editing the cell */
g_object_set_data(G_OBJECT(renderer), "column",
GUINT_TO_POINTER(i));
g_object_set_data(G_OBJECT(renderer), "memory_id",
gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
}
-static int
-compute_data_rows(int memory_id)
+static void
+memwin_infos_select(int memory_id)
{
- int data_rows;
- u_int32_t *crc;
-
if (memory_id == INT_MEM_ID) {
- data_rows = options.iram_size / cfg->bytes_per_row;
- crc = crc_internal;
+ log_debug("memory ID = INTERNAL");
+ memwin_infos = &memwin_infos_internal;
} else if (memory_id == EXT_MEM_ID) {
- data_rows = options.xram_size / cfg->bytes_per_row;
- crc = crc_external;
+ log_debug("memory ID = EXTERNAL");
+ memwin_infos = &memwin_infos_external;
} else {
log_fail("Invalid memory type");
exit(1);
}
+}
- if (crc)
- free(crc);
-
- crc = malloc(data_rows * sizeof(u_int32_t));
-
- if (memory_id == INT_MEM_ID) {
- data_rows_internal = data_rows;
- crc_internal = crc;
- } else if (memory_id == EXT_MEM_ID) {
- data_rows_external = data_rows;
- crc_external = crc;
- }
-
- return data_rows;
+static void
+compute_data_rows(int memory_id)
+{
+ if (memory_id == INT_MEM_ID)
+ memwin_infos->data_rows = options.iram_size /
+ cfg->bytes_per_row;
+ else if (memory_id == EXT_MEM_ID)
+ memwin_infos->data_rows = options.xram_size /
+ cfg->bytes_per_row;
+
+ if (memwin_infos->crc)
+ free(memwin_infos->crc);
+
+ memwin_infos->crc = malloc(memwin_infos->data_rows * sizeof(u_int32_t));
+ memwin_infos->crc_init = false;
}
GtkWidget *
GtkWidget *frame;
GtkWidget *scrollwin;
GtkListStore *store;
- GtkWidget *memlist;
- int data_rows;
+
+ log_debug("memwin_init");
COL_ASCII = cfg->bytes_per_row + 1;
N_COLUMNS = COL_ASCII + 1;
gtk_container_add(GTK_CONTAINER(frame), scrollwin);
- data_rows = compute_data_rows(memory_id);
+ memwin_infos_select(memory_id);
+ compute_data_rows(memory_id);
/* Creating a model */
- store = memwin_init_store(data_rows);
+ store = memwin_init_store(memwin_infos->data_rows);
/* Creating the view component */
- memlist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
- gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(memlist), TRUE);
- gtk_container_add(GTK_CONTAINER(scrollwin), memlist);
-
- if (memory_id == INT_MEM_ID) {
- memlist_internal = memlist;
- } else if (memory_id == EXT_MEM_ID) {
- memlist_external = memlist;
- } else {
- log_fail("Invalid memory type");
- exit(1);
- }
+ memwin_infos->memlist = gtk_tree_view_new_with_model(
+ GTK_TREE_MODEL(store));
+ gtk_tree_view_set_headers_visible(
+ GTK_TREE_VIEW(memwin_infos->memlist), TRUE);
+ gtk_container_add(GTK_CONTAINER(scrollwin), memwin_infos->memlist);
- memwin_init_columns(memlist, memory_id);
+ memwin_init_columns(memwin_infos->memlist, memory_id);
/*
* The tree view has acquired its own reference to the model, so we can
return frame;
}
+/*
+ * Use CRC to detect which rows have changed. This is only to
+ * improve performance when using stepping mode, as we then only update
+ * rows which have been modified.
+ */
+static int
+memwin_row_changed(int memory_id, int row, unsigned int address)
+{
+ int row_changed;
+ u_int32_t crc_new = 0;
+ u_int8_t *buf8;
+
+ buf8 = memory_getbuf(memory_id, address);
+ crc_new = crc32(0L, Z_NULL, 0);
+ crc_new = crc32(crc_new, buf8, cfg->bytes_per_row);
+
+ if ((memwin_infos->crc_init) &&
+ (crc_new == memwin_infos->crc[row])) {
+ row_changed = false;
+ } else {
+ memwin_infos->crc[row] = crc_new;
+ log_debug(" Row %02d value(s) change", row);
+ row_changed = true;
+ }
+
+ return row_changed;
+}
+
/* Dump internal or external memory. */
void
memwin_refresh(int memory_id)
{
int row;
- unsigned int Address;
+ unsigned int address = 0;
GtkListStore *store;
- GtkWidget *memlist;
- int data_rows;
- Address = 0;
+ log_debug("memwin_refresh");
- if (memory_id == INT_MEM_ID) {
- log_debug("memory ID = INTERNAL");
- memlist = memlist_internal;
- data_rows = data_rows_internal;
- } else if (memory_id == EXT_MEM_ID) {
- log_debug("memory ID = EXTERNAL");
- memlist = memlist_external;
- data_rows = data_rows_external;
- } else {
- log_fail("Invalid memory type");
- exit(1);
- }
+ memwin_infos_select(memory_id);
- store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(memlist)));
+ store = GTK_LIST_STORE(gtk_tree_view_get_model(
+ GTK_TREE_VIEW(memwin_infos->memlist)));
- for (row = 0; row < data_rows; row++, Address += cfg->bytes_per_row) {
+ for (row = 0; row < memwin_infos->data_rows;
+ row++, address += cfg->bytes_per_row) {
int valid;
GtkTreeIter iter;
- char str[4+1]; /* Maximum str len is for address column (4 digits) */
+ char str[4+1]; /* Max. str len for address column (4 digits) */
char ascii_str[16+1]; /* Maximum 16 data columns. */
int col;
- u_int32_t crc_new = 0;
- u_int32_t *crc_old = NULL;
- u_int8_t *buf8;
if (row == 0) {
/* Get first row in list store */
}
if (!valid) {
- printf("Invalid iter...\n");
+ log_err("Tree model: invalid iter");
return;
}
- if (memory_id == INT_MEM_ID) {
- crc_old = crc_internal;
- } else if (memory_id == EXT_MEM_ID) {
- crc_old = crc_external;
- }
-
- /*
- * Use CRC to detect which rows have changed. This is only to
- * improve performance when using stepping mode, as we then only update
- * rows which have been modified.
- */
- buf8 = memory_getbuf(memory_id, Address);
- crc_new = crc32(0L, Z_NULL, 0);
- crc_new = crc32(crc_new, buf8, cfg->bytes_per_row);
-
- if (crc_new == crc_old[row]) {
- continue;
- } else {
- crc_old[row] = crc_new;
- log_debug(" Row %02d value(s) change", row);
- }
+ /* Only update row if it has been modified. */
+ if (memwin_row_changed(memory_id, row, address)) {
+ /* Display base address. */
+ int2asciihex(address, str, 4);
- /* Display base address. */
- int2asciihex(Address, str, 4);
+ gtk_list_store_set(store, &iter, COL_ADDRESS, str, -1);
- gtk_list_store_set(store, &iter, COL_ADDRESS, str, -1);
+ for (col = 0; col < cfg->bytes_per_row; col++) {
+ u_int8_t data;
- for (col = 0; col < cfg->bytes_per_row; col++) {
- u_int8_t data;
+ data = memory_read8(memory_id, address + col);
- data = memory_read8(memory_id, Address + col);
+ /* Display hex data */
+ int2asciihex(data, str, 2);
- /* Display hex data */
- int2asciihex(data, str, 2);
+ gtk_list_store_set(store, &iter, col + 1, str,
+ -1);
- gtk_list_store_set(store, &iter, col + 1, str, -1);
+ /* Append to ASCII string (if applicable). */
+ if (!isprint(data))
+ data = '.';
+ sprintf(&ascii_str[col], "%c", data);
+ }
- /* Append to ASCII string (if applicable). */
- if (!isprint(data))
- data = '.';
- sprintf(&ascii_str[col], "%c", data);
+ /* Display ASCII characters. */
+ gtk_list_store_set(store, &iter, COL_ASCII, ascii_str,
+ -1);
}
-
- /* Display ASCII characters. */
- gtk_list_store_set(store, &iter, COL_ASCII, ascii_str, -1);
}
+
+ /* At this point we know all rows crc have been initialized. */
+ memwin_infos->crc_init = true;
}