Improve performance of GUI step operations
authorHugo Villeneuve <hugo@hugovil.com>
Tue, 14 Jan 2014 04:07:41 +0000 (23:07 -0500)
committerHugo Villeneuve <hugo@hugovil.com>
Tue, 14 Jan 2014 04:36:37 +0000 (23:36 -0500)
Use CRC to detect which memory rows have changed.

This is only to improve GUI performance when using stepping mode, as we then
only update rows which have been modified.

configure.ac
src/common/memory.c
src/common/memory.h
src/gtk/Makefile.am
src/gtk/memwin.c

index 7deeb84..ca66cc0 100644 (file)
@@ -82,6 +82,21 @@ AM_CONDITIONAL([USE_AS504HV],[test x"$AS504HV_CHECK" = x"yes"])
 AM_CONDITIONAL([USE_AS504],[test x"$AS504_CHECK" = x"yes"])
 AM_CONDITIONAL([USE_AS51],[test x"$ASEM51_CHECK" = x"yes"])
 
+dnl zlib required for its crc32 function
+ac_have_zlib=no
+
+PKG_CHECK_MODULES([zlib], [zlib > 1.2.1],
+                 [AC_CHECK_LIB([z], [crc32],
+                               [ac_have_zlib=yes],
+                               [ac_have_zlib=no])])
+
+if test x"$ac_have_zlib" = x"yes" ; then
+    ZLIB_LIBS='-lz'
+    AC_SUBST(ZLIB_LIBS)
+else
+    AC_MSG_ERROR([Please install zlib and zlib-devel packages])
+fi
+
 AC_SUBST(WARNINGCFLAGS)
 AC_SUBST(LIBS)
 AC_SUBST(ac_aux_dir)
index c5b2acf..9332ea7 100644 (file)
@@ -75,6 +75,12 @@ memory_init(void)
        }
 }
 
+u_int8_t *
+memory_getbuf(enum mem_id_t id, unsigned long address)
+{
+       return &mem_infos[id].buf[address];
+}
+
 void
 memory_clear(enum mem_id_t id)
 {
index 2d65d5e..7beb0e8 100644 (file)
@@ -46,6 +46,9 @@ enum mem_id_t {
 void
 memory_init(void);
 
+u_int8_t *
+memory_getbuf(enum mem_id_t id, unsigned long address);
+
 void
 memory_clear(enum mem_id_t id);
 
index 699d76e..6db03db 100644 (file)
@@ -15,6 +15,7 @@ AM_CPPFLAGS = \
 LDADD = \
     $(top_builddir)/src/common/libemu8051.a \
     @GTK_LIBS@ \
+    @ZLIB_LIBS@ \
     @GLIB_LIBS@
 
 bin_PROGRAMS = emu8051-gtk
index 58ce1d2..b31551f 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <stdio.h>
 #include <ctype.h> /* For isprint */
+#include <zlib.h> /* For crc32 routine */
 
 #include "common.h"
 #include "memory.h"
@@ -51,6 +52,12 @@ enum
 static GtkWidget *memlist_internal;
 static GtkWidget *memlist_external;
 
+static int data_rows_internal;
+static int data_rows_external;
+
+static u_int32_t *crc_internal;
+static u_int32_t *crc_external;
+
 /* Creating a model */
 static GtkListStore *
 memwin_init_store(int data_rows)
@@ -201,16 +208,32 @@ static int
 compute_data_rows(int memory_id)
 {
        int data_rows;
+       u_int32_t *crc;
 
        if (memory_id == INT_MEM_ID) {
                data_rows = options.iram_size / cfg->bits_per_row;
+               crc = crc_internal;
        } else if (memory_id == EXT_MEM_ID) {
                data_rows = options.xram_size / cfg->bits_per_row;
+               crc = crc_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;
 }
 
@@ -282,12 +305,14 @@ memwin_refresh(int memory_id)
 
        Address = 0;
 
-       data_rows = compute_data_rows(memory_id);
-
        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);
@@ -295,12 +320,15 @@ memwin_refresh(int memory_id)
 
        store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(memlist)));
 
-       for (row = 0; row < data_rows; row++) {
+       for (row = 0; row < data_rows; row++, Address += cfg->bits_per_row) {
                int valid;
                GtkTreeIter iter;
                char str[4+1]; /* Maximum str len is 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 */
@@ -317,6 +345,28 @@ memwin_refresh(int memory_id)
                        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->bits_per_row);
+
+               if (crc_new == crc_old[row]) {
+                       continue;
+               } else {
+                       crc_old[row] = crc_new;
+                       log_debug("    Row %02d value(s) change", row);
+               }
+
                /* Display base address. */
                int2asciihex(Address, str, 4);
 
@@ -340,7 +390,5 @@ memwin_refresh(int memory_id)
 
                /* Display ASCII characters. */
                gtk_list_store_set(store, &iter, COL_ASCII, ascii_str, -1);
-
-               Address += cfg->bits_per_row;
        }
 }