aboutsummaryrefslogtreecommitdiff
path: root/sim/common
diff options
context:
space:
mode:
authorFrank Ch. Eigler <fche@redhat.com>1998-11-14 04:35:47 +0000
committerFrank Ch. Eigler <fche@redhat.com>1998-11-14 04:35:47 +0000
commit92fa45795dc1b8427de0c1e310bbe1bd52d4bd05 (patch)
treeb9e8e3d84758508a6d59901dca64974cecafdda7 /sim/common
parentfca5abc13a6d7df76b3ecef15c31a77973fb35e2 (diff)
downloadgdb-92fa45795dc1b8427de0c1e310bbe1bd52d4bd05.zip
gdb-92fa45795dc1b8427de0c1e310bbe1bd52d4bd05.tar.gz
gdb-92fa45795dc1b8427de0c1e310bbe1bd52d4bd05.tar.bz2
* Personal prototype "gx" translation-based JIT engine for M32R.
[ChangeLog] start-sanitize-gxsim 1998-11-13 Frank Ch. Eigler <fche@elastic.org> * configure.in: Added "--enable-sim-gx" option. * configure: Regenerated. end-sanitize-gxsim [common/ChangeLog] 1998-11-13 Frank Ch. Eigler <fche@elastic.org> start-sanitize-gxsim * Make-common.im: Build sim-gx.o and sim-gx-run.o. * sim-gx.c: New file: target-independent gx routines. * sim-gx.h: Declarations for gx structs and routines. * sim-gx-run.c: New file: target-independent gx driver. * sim-base.h: Add gx block vector to state struct. end-sanitize-gxsim * aclocal.m4: Add tests for dlopen family.
Diffstat (limited to 'sim/common')
-rw-r--r--sim/common/.Sanitize35
-rw-r--r--sim/common/ChangeLog12
-rw-r--r--sim/common/Make-common.in15
-rw-r--r--sim/common/sim-gx-run.c148
-rw-r--r--sim/common/sim-gx.c807
-rw-r--r--sim/common/sim-gx.h142
6 files changed, 1159 insertions, 0 deletions
diff --git a/sim/common/.Sanitize b/sim/common/.Sanitize
index b468d63..e6b50e3 100644
--- a/sim/common/.Sanitize
+++ b/sim/common/.Sanitize
@@ -22,6 +22,13 @@ else
lose_these_too="${cygnus_files} ${lose_these_too}"
fi
+gxsim_files="sim-gx-run.c sim-gx.c sim-gx.h"
+if ( echo $* | grep keep\-gxsim > /dev/null ) ; then
+ keep_these_too="${gxsim_files} ${keep_these_too}"
+else
+ lose_these_too="${gxsim_files} ${lose_these_too}"
+fi
+
# All files listed between the "Things-to-keep:" line and the
# "Files-to-sed:" line will be kept. All other files will be removed.
# Directories listed in this section will have their own Sanitize
@@ -179,4 +186,32 @@ else
done
fi
+gxsim_files="ChangeLog Make-common.in sim-base.h"
+if ( echo $* | grep keep\-gxsim > /dev/null ) ; then
+ for i in $gxsim_files ; do
+ if test ! -d $i && (grep sanitize-gxsim $i > /dev/null) ; then
+ if [ -n "${verbose}" ] ; then
+ echo Keeping gxsim stuff in $i
+ fi
+ fi
+ done
+else
+ for i in $gxsim_files ; do
+ if test ! -d $i && (grep sanitize-gxsim $i > /dev/null) ; then
+ if [ -n "${verbose}" ] ; then
+ echo Removing traces of \"gxsim\" from $i...
+ fi
+ cp $i new
+ sed '/start\-sanitize\-gxsim/,/end-\sanitize\-gxsim/d' < $i > new
+ if [ -n "${safe}" -a ! -f .Recover/$i ] ; then
+ if [ -n "${verbose}" ] ; then
+ echo Caching $i in .Recover...
+ fi
+ mv $i .Recover
+ fi
+ mv new $i
+ fi
+ done
+fi
+
# End of file.
diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog
index b7e6f2e..8a334a2 100644
--- a/sim/common/ChangeLog
+++ b/sim/common/ChangeLog
@@ -1,3 +1,15 @@
+1998-11-13 Frank Ch. Eigler <fche@elastic.org>
+
+start-sanitize-gxsim
+ * Make-common.im: Build sim-gx.o and sim-gx-run.o.
+ * sim-gx.c: New file: target-independent gx routines.
+ * sim-gx.h: Declarations for gx structs and routines.
+ * sim-gx-run.c: New file: target-independent gx driver.
+ * sim-base.h: Add gx block vector to state struct.
+end-sanitize-gxsim
+ * aclocal.m4: Add tests for dlopen family.
+ * config.in: Regenerated.
+
Wed Nov 11 14:02:25 1998 Doug Evans <devans@canuck.cygnus.com>
* sim-hload.c (sim_load): Pass `prog_name' to sim_load_file, not NULL.
diff --git a/sim/common/Make-common.in b/sim/common/Make-common.in
index 809160b..3622bec 100644
--- a/sim/common/Make-common.in
+++ b/sim/common/Make-common.in
@@ -318,6 +318,9 @@ sim-n-core_h = $(srccom)/sim-n-core.h
sim-engine_h = $(srccom)/sim-engine.h
sim-events_h = $(srccom)/sim-events.h
sim-fpu_h = $(srccom)/sim-fpu.h
+# start-sanitize-gxsim
+sim-gx_h = $(srccom)/sim-gx.h
+# end-sanitize-gxsim
sim-io_h = $(srccom)/sim-io.h
sim-options_h = $(srccom)/sim-options.h
sim-break_h = $(srccom)/sim-break.h
@@ -383,6 +386,18 @@ sim-fpu.o: $(srccom)/sim-fpu.c $(sim-fpu_h) \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-fpu.c $(ALL_CFLAGS)
+# start-sanitize-gxsim
+sim-gx.o: $(srccom)/sim-gx.c $(sim_main_headers) \
+ $(sim-gx_h) \
+ $(SIM_EXTRA_DEPS)
+ $(CC) -c $(srccom)/sim-gx.c $(ALL_CFLAGS)
+
+sim-gx-run.o: $(srccom)/sim-gx-run.c $(sim_main_headers) \
+ $(sim-gx_h) \
+ $(SIM_EXTRA_DEPS)
+ $(CC) -c $(srccom)/sim-gx-run.c $(ALL_CFLAGS)
+# end-sanitize-gxsim
+
sim-hload.o: $(srccom)/sim-hload.c $(sim-assert_h) \
$(srcroot)/include/remote-sim.h \
$(SIM_EXTRA_DEPS)
diff --git a/sim/common/sim-gx-run.c b/sim/common/sim-gx-run.c
new file mode 100644
index 0000000..a4d8865
--- /dev/null
+++ b/sim/common/sim-gx-run.c
@@ -0,0 +1,148 @@
+/* GX generic simulator run.
+ Copyright (C) 1998 Cygnus Solutions.
+*/
+
+#include "sim-main.h"
+#include "sim-assert.h"
+#include "sim-gx.h"
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+
+/* GX implementation of sim_engine_run that works within the
+ sim_engine setjmp/longjmp framework. */
+
+
+void
+sim_engine_run (SIM_DESC sd,
+ int next_cpu_nr,
+ int nr_cpus, /* ignore */
+ int siggnal) /* ignore */
+{
+ sim_cpu* cpu;
+ int cont = 1;
+ int rc;
+
+ SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+ cpu = STATE_CPU (sd, next_cpu_nr);
+
+ while(cont)
+ {
+ sim_gx_block* block;
+ sim_gx_compiled_block* compiled_block;
+ sim_gx_function f;
+ sim_cia cia = CIA_GET(cpu);
+ int optimized;
+ int pre_checksum, post_checksum;
+
+ /* find optimized gx block that includes this PC */
+ block = sim_gx_block_find(cia);
+ if(block == NULL)
+ {
+ /* start new learning block */
+ block = sim_gx_block_create(cia);
+ }
+ ASSERT(block != NULL);
+
+ /* pick preferred compiled block */
+ if(block->optimized_block != NULL)
+ {
+ compiled_block = block->optimized_block;
+ /* no stats */
+ }
+ else
+ {
+ /* test for optimization policy */
+ if(tgx_optimize_test(block))
+ {
+ block->opt_compile_count ++;
+ sim_gx_block_translate(block, 1 /* optimized */);
+ compiled_block = block->optimized_block;
+ optimized = 1;
+ }
+ else
+ {
+ compiled_block = block->learning_block;
+ optimized = 0;
+ }
+ }
+ ASSERT(compiled_block != NULL);
+
+ /* load & resolve gx function */
+ f = sim_gx_compiled_block_f(compiled_block);
+
+ /* XXX: debug
+ printf("calling into gx function %p, pc=%08lx, opt %d\n",
+ (void*) f, (unsigned long) cpu->regs.h_pc, optimized);
+ */
+
+ /* compute pc_flags checksum */
+ if(! optimized)
+ {
+ int i;
+ pre_checksum = 0;
+ for(i=0; i < block->length / block->divisor; i++)
+ pre_checksum += block->pc_flags[i];
+ }
+
+ /* call into gx function */
+ rc = (*f)(& cpu->regs, block->pc_flags, block->callbacks);
+
+ /* compute pc_flags checksum */
+ if(! optimized)
+ {
+ int i;
+ post_checksum = 0;
+ for(i=0; i < block->length / block->divisor; i++)
+ post_checksum += block->pc_flags[i];
+
+ if(post_checksum != pre_checksum) /* system changing */
+ {
+ block->learn_last_change = time(NULL);
+ }
+ }
+
+ /* XXX: debug
+ printf("returned from gx function %p, rc=%d, pc=%08lx\n",
+ (void*) f, rc, (unsigned long) cpu->regs.h_pc);
+ */
+
+ switch(rc)
+ {
+ case GX_F_YIELD: /* gx block voluntarily gave up control */
+ case GX_F_RANGE: /* PC travelled outside this block */
+ ; /* continue block dispatch loop */
+ break;
+
+ case GX_F_NONPC: /* non-instruction PC in this block */
+ if(compiled_block == block->optimized_block)
+ {
+ /* sim_io_printf(sd, "NOTE: cancelling premature optimization, GX block %p, PC %08lx\n",
+ block, (long) cpu->regs.h_pc); */
+ sim_gx_compiled_block_dispose(compiled_block);
+ block->learn_last_change = time(NULL);
+ block->optimized_block = NULL;
+ }
+ else
+ {
+ /* learning-mode gx block should not fail this way */
+ sim_io_error(sd, "Internal error - GX block cia %08lx NONPC\n", (long) cia);
+ }
+ break;
+
+ case GX_F_HALT: /* gx function returning control */
+ cont = 0; /* merely exit loop */
+ break;
+
+ /* should not happen */
+ default:
+ sim_io_error(sd, "Translation error (bad rc 0x%d in gx block)", rc);
+ /* NOTREACHED */
+ }
+
+ if(sim_events_tick(sd))
+ sim_events_process(sd);
+ }
+}
diff --git a/sim/common/sim-gx.c b/sim/common/sim-gx.c
new file mode 100644
index 0000000..413739d
--- /dev/null
+++ b/sim/common/sim-gx.c
@@ -0,0 +1,807 @@
+/* GX target-independent functions for block translation.
+ Copyright (C) 1998 Cygnus Solutions. */
+
+
+#include "sim-main.h"
+#include "sim-assert.h"
+#include "sim-gx.h"
+
+#include "config.h"
+#include "cconfig.h"
+
+/* shared object functions */
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#else
+#error "need dlfcn.h"
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+#error "need errno.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include "bfd.h"
+
+
+
+
+/* Load the object file with given gx block. Return pointer to GX
+ function or NULL on failure. */
+
+sim_gx_function
+sim_gx_compiled_block_f(sim_gx_compiled_block* gx)
+{
+ sim_gx_function f = gx->function_dlhandle;
+ SIM_DESC sd = current_state;
+ int rc;
+
+ if(f == NULL)
+ {
+ /* compile object */
+ if(gx->object_name == NULL && gx->source_name != NULL)
+ {
+ char compile_command[2000];
+
+ gx->object_name = strdup(gx->source_name);
+ /* turn *.c into *.o */
+ gx->object_name[strlen(gx->object_name)]='o';
+
+ /* compute command string to compile object */
+ sprintf(compile_command,
+ "make -f %s OBJ=%s SRC=%s gx",
+#define GX_MAKEFILE "--no-makefile-yet--"
+ GX_MAKEFILE,
+ gx->object_name,
+ gx->source_name);
+
+ rc = system(compile_command);
+ if(rc != 0)
+ {
+ sim_io_error(sd, "Compile error rc %d for GX source %s: %s",
+ rc,
+ gx->source_name,
+ strerror(errno));
+ }
+ }
+
+ /* load object */
+ if(gx->object_dlhandle == NULL && gx->object_name != NULL)
+ {
+ gx->object_dlhandle = dlopen(gx->object_name, RTLD_NOW);
+ if(gx->object_dlhandle == NULL)
+ {
+ sim_io_error(sd, "Load error for GX object %s: %s",
+ gx->object_name,
+ dlerror());
+ }
+ }
+
+ /* locate function */
+ if(gx->function_dlhandle == NULL && gx->object_dlhandle != NULL && gx->symbol_name != NULL)
+ {
+ f = gx->function_dlhandle = dlsym(gx->object_dlhandle, gx->symbol_name);
+ if(f == NULL)
+ {
+ sim_io_error(sd, "Resolve error for GX object %s symbol %s: %s",
+ gx->object_name,
+ gx->symbol_name,
+ dlerror());
+ }
+ }
+ } /* f == NULL */
+
+ return f;
+}
+
+
+
+/* Forget about given GX block. Remove its source/object; unload it
+ from memory. */
+void
+sim_gx_compiled_block_dispose(sim_gx_compiled_block* gx)
+{
+ SIM_DESC sd = current_state;
+ int rc;
+
+ /* forget dl information */
+ gx->function_dlhandle = NULL;
+
+ /* unload shared library */
+ if(gx->object_dlhandle != NULL)
+ {
+ rc = dlclose(gx->object_dlhandle);
+ if(rc != 0)
+ {
+ sim_io_error(sd, "dlclose() error for GX object %s: %s",
+ gx->object_name,
+ dlerror());
+ }
+ gx->object_dlhandle = NULL;
+ }
+
+ /* final gasps */
+ zfree(gx->source_name);
+ zfree(gx->object_name);
+ zfree(gx->symbol_name);
+ zfree(gx);
+}
+
+
+
+/* Translate a piece of the code segment around given PC, in given mode. */
+sim_gx_block*
+sim_gx_block_create(sim_cia cia)
+{
+ sim_gx_block* block;
+
+ /* allocate emtpy block */
+ block = zalloc(sizeof(sim_gx_block));
+
+ /* initialize block bounds, callback struct etc. */
+ tgx_block_ctor(block, cia);
+
+ /* create learning mode translation */
+ sim_gx_block_translate(block, 0 /* learning mode */);
+
+ /* add block to block list */
+ sim_gx_block_add(block);
+
+ return block;
+}
+
+
+
+/* Write the current block list to the state file */
+void
+sim_gx_write_block_list()
+{
+ int i;
+ SIM_DESC sd = current_state;
+ sim_gx_block_list* blocks = STATE_BLOCKS(sd);
+ FILE* f;
+ char state_file_name[PATH_MAX];
+ char *exec_name;
+
+ /* get base of executable name */
+ exec_name = bfd_get_filename(STATE_PROG_BFD(sd));
+ if(strrchr(exec_name, '/') != NULL)
+ exec_name = strrchr(exec_name, '/') + 1;
+
+ /* generate base name */
+ sprintf(state_file_name, "%s/%s.gx",
+ GX_DIR,
+ exec_name);
+
+ f = fopen(state_file_name, "w");
+ if(f == NULL)
+ {
+ sim_io_error(sd, "Error: cannot write to state file %s, errno %d",
+ state_file_name, errno);
+ }
+
+ fprintf(f, "# This file was automatically generated. Do not edit.\n");
+
+ /* write block descriptors into state file */
+ for(i=0; i<blocks->gx_blocks_used; i++)
+ {
+ sim_gx_block* gx = blocks->gx_blocks[i];
+ sim_gx_compiled_block* block;
+ int j;
+ int age;
+
+ age = time(NULL) - gx->learn_last_change; /* store interval */
+ fprintf(f, "BLOCK 0x%lx 0x%lx %u %u\n", gx->origin, gx->length, gx->divisor, age);
+ fprintf(f, "FLAGS ");
+ for(j=0; j<GX_PC_FLAGS_INDEX(gx, gx->origin + gx->length); j++)
+ {
+ fprintf(f, "%2x ", gx->pc_flags[j]);
+ }
+ fprintf(f, "\n");
+
+ /* write learning mode names */
+ block = gx->learning_block;
+ fprintf(f, "LEARNING %s %s %s %lu %u\n",
+ block->source_name, block->object_name, block->symbol_name,
+ gx->compile_time, gx->opt_compile_count);
+
+ /* write optimized mode names */
+ block = gx->optimized_block;
+ if(block)
+ fprintf(f, "OPTIMIZED %s %s %s\n",
+ block->source_name, block->object_name, block->symbol_name);
+
+ /* NB: other fields will be filled in with freshly guessed values */
+ }
+
+ (void) fclose(f);
+}
+
+
+
+void
+print_gx_blocks(sim_gx_block_list* blocks, char* where)
+{
+ printf("print_gx_blocks: %s\n", where);
+
+ if(blocks == NULL)
+ printf("(null)\n");
+ else
+ {
+ int i;
+ printf("size: %d, used: %d\n",
+ blocks->gx_blocks_size, blocks->gx_blocks_used);
+
+ /* linear search */
+ for(i=0; i<blocks->gx_blocks_used; i++)
+ {
+ sim_gx_block* gx = blocks->gx_blocks[i];
+ printf("block %d: %p\n", i, (void*) gx);
+ if(gx == NULL)
+ printf("** NULL!\n");
+ else
+ printf(" begin 0x%08x length 0x%08x [opt %d%s]\n",
+ (unsigned)gx->origin, (unsigned)gx->length,
+ gx->opt_compile_count,
+ (gx->optimized_block ? " loaded" : " discarded"));
+ }
+
+ }
+}
+
+
+
+/* Read the current block list from the cache */
+void
+sim_gx_read_block_list()
+{
+ SIM_DESC sd = current_state;
+ FILE* f;
+ char state_file_name[PATH_MAX];
+ char *exec_name;
+
+ /* check for block */
+ if(STATE_PROG_BFD(sd) == NULL)
+ return;
+
+ /* get base of executable name */
+ exec_name = bfd_get_filename(STATE_PROG_BFD(sd));
+ if(strrchr(exec_name, '/') != NULL)
+ exec_name = strrchr(exec_name, '/') + 1;
+
+ /* generate base name */
+ sprintf(state_file_name, "%s/%s.gx",
+ GX_DIR,
+ exec_name);
+
+ f = fopen(state_file_name, "r");
+ if(f == NULL)
+ {
+ /* XXX: print warning */
+ return;
+ }
+
+ fscanf(f, "#%*[^\n]\n"); /* swallow # comment line */
+
+ while(1)
+ {
+ unsigned_4 origin, length;
+ unsigned divisor;
+ sim_gx_block* gx;
+ int rc;
+ sim_gx_compiled_block* block;
+ unsigned age;
+ int j;
+
+ rc = fscanf(f, "BLOCK 0x%0lx 0x%lx %u %u\n", & origin, & length, & divisor, & age);
+ if(rc != 4) /* not all fields matched - assume EOF */
+ break;
+
+ gx = zalloc(sizeof(sim_gx_block));
+
+ /* initialize block bounds, callback struct etc. */
+ tgx_block_ctor2(gx, origin, length, divisor);
+
+ /* read flags */
+ fscanf(f, "FLAGS");
+ for(j=0; j<GX_PC_FLAGS_INDEX(gx, gx->origin + gx->length); j++)
+ {
+ unsigned value;
+ fscanf(f, "%2x ", & value);
+ gx->pc_flags[j] = (unsigned_1) value;
+ }
+ fscanf(f, "\n");
+
+ /* read learning mode info */
+ block = zalloc(sizeof(sim_gx_compiled_block));
+ gx->learning_block = block;
+ block->source_name = zalloc(PATH_MAX);
+ block->object_name = zalloc(PATH_MAX);
+ block->symbol_name = zalloc(PATH_MAX);
+ fscanf(f, "LEARNING %s %s %s %lu %u\n",
+ block->source_name, block->object_name, block->symbol_name,
+ & gx->compile_time, & gx->opt_compile_count);
+
+ /* read optimized mode info */
+ block = zalloc(sizeof(sim_gx_compiled_block));
+ gx->optimized_block = block;
+ block->source_name = zalloc(PATH_MAX);
+ block->object_name = zalloc(PATH_MAX);
+ block->symbol_name = zalloc(PATH_MAX);
+ rc = fscanf(f, "OPTIMIZED %s %s %s\n",
+ block->source_name, block->object_name, block->symbol_name);
+ if(rc != 3)
+ {
+ /* oops, not an optimized block */
+ zfree(block->source_name);
+ zfree(block->object_name);
+ zfree(block->symbol_name);
+ zfree(block);
+ gx->optimized_block = NULL;
+ }
+
+ /* fill in remaining fields */
+ gx->learn_last_change = time(NULL) - age; /* make absolute */
+
+ /* store it away */
+ sim_gx_block_add(gx);
+ }
+
+ print_gx_blocks(STATE_BLOCKS(sd), "after restoring state");
+}
+
+
+
+
+
+
+/* Add a gx block to list */
+void
+sim_gx_block_add(sim_gx_block* block)
+{
+ SIM_DESC sd = current_state;
+ sim_gx_block_list* blocks = STATE_BLOCKS(sd);
+ int i;
+
+ /* print_gx_blocks(blocks, "pre add"); */
+
+ if(blocks == NULL)
+ blocks = STATE_BLOCKS(sd) = zalloc(sizeof(sim_gx_block_list));
+
+ /* need to enlarge block vector? */
+ if(blocks->gx_blocks_used == blocks->gx_blocks_size)
+ {
+ sim_gx_block** new_blocks;
+ int j;
+
+ blocks->gx_blocks_size += 20;
+ new_blocks = zalloc(blocks->gx_blocks_size * sizeof(sim_gx_block*));
+ for(j=0; j<blocks->gx_blocks_used; j++)
+ new_blocks[j] = blocks->gx_blocks[j];
+ if(blocks->gx_blocks) zfree(blocks->gx_blocks);
+ blocks->gx_blocks = new_blocks;
+ }
+
+ /* insert new block */
+ for(i=0; i<blocks->gx_blocks_used; i++)
+ {
+ ASSERT(blocks->gx_blocks[i] != NULL);
+
+ /* insertion point reached? */
+ if(blocks->gx_blocks[i]->origin > block->origin)
+ {
+ int j;
+ for(j=blocks->gx_blocks_used; j>=i; j--)
+ blocks->gx_blocks[j] = blocks->gx_blocks[j-1];
+ blocks->gx_blocks[i] = block;
+ blocks->gx_blocks_used ++;
+ break;
+ }
+ }
+
+ /* end of block vector */
+ if(i == blocks->gx_blocks_used)
+ {
+ blocks->gx_blocks[blocks->gx_blocks_used ++] = block;
+ }
+
+ /* print_gx_blocks(blocks, "post add"); */
+}
+
+
+
+/* Remove a gx block from list */
+void
+sim_gx_block_remove(sim_gx_block* block)
+{
+ SIM_DESC sd = current_state;
+ sim_gx_block_list* blocks = STATE_BLOCKS(sd);
+ int i;
+
+ /* print_gx_blocks(blocks, "pre remove"); */
+
+ /* linear search */
+ for(i=0; i<blocks->gx_blocks_used; i++)
+ {
+ if(blocks->gx_blocks[i] == block)
+ {
+ /* found it */
+ while(i < blocks->gx_blocks_used - 1)
+ {
+ blocks->gx_blocks[i] = blocks->gx_blocks[i+1];
+ i++;
+ }
+ blocks->gx_blocks_used --;
+ break;
+ }
+ }
+
+ /* print_gx_blocks(blocks, "post remove"); */
+}
+
+
+/* Find a gx block from list */
+sim_gx_block*
+sim_gx_block_find(sim_cia cia)
+{
+ SIM_DESC sd = current_state;
+ sim_gx_block_list* blocks = STATE_BLOCKS(sd);
+ int i;
+
+ if(blocks == NULL) return NULL;
+
+ /* print_gx_blocks(blocks, "pre find"); */
+
+ /* linear search */
+ for(i=0; i<blocks->gx_blocks_used; i++)
+ {
+ sim_gx_block* gx = blocks->gx_blocks[i];
+ ASSERT(gx != NULL);
+
+ if(GX_PC_INCLUDES(gx,cia))
+ {
+ return gx;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+/* generate */
+void
+sim_gx_block_translate(sim_gx_block* gx, int optimized)
+{
+ char pwd_name[PATH_MAX];
+ char dir_name[PATH_MAX];
+ char base_name[PATH_MAX];
+ char compile_command[PATH_MAX*4];
+ char* exec_name;
+ SIM_DESC sd = current_state;
+ int rc;
+ sim_cia gx_cia;
+ sim_gx_compiled_block* block = zalloc(sizeof(sim_gx_compiled_block));
+ unsigned time_begin, time_end;
+
+ time_begin = time(NULL);
+
+ if(optimized) gx->optimized_block = block;
+ else gx->learning_block = block;
+
+ /* get base of executable name */
+ exec_name = bfd_get_filename(STATE_PROG_BFD(sd));
+ if(strrchr(exec_name, '/') != NULL)
+ exec_name = strrchr(exec_name, '/') + 1;
+
+ /* generate base name */
+ sprintf(dir_name, "%s/%s",
+ GX_DIR,
+ exec_name);
+
+ /* generate base name */
+ getcwd(pwd_name, sizeof(pwd_name));
+
+ /* create work directory */
+ rc = mkdir(GX_DIR, 0777);
+ if(rc != 0 &&
+ errno != EEXIST)
+ {
+ sim_io_error(sd, "Error: cannot create directory %s, errno %d",
+ GX_DIR, errno);
+ }
+
+ rc = mkdir(dir_name, 0777);
+ if(rc != 0 &&
+ errno != EEXIST)
+ {
+ sim_io_error(sd, "Error: cannot create directory %s, errno %d",
+ dir_name, errno);
+ }
+
+ /* compute base name */
+ if(optimized)
+ sprintf(base_name, "%08lx_opt%d", gx->origin, gx->opt_compile_count);
+ else
+ sprintf(base_name, "%08lx", gx->origin);
+
+ /* generate source/object file names */
+ block->source_name = zalloc(PATH_MAX);
+ block->object_name = zalloc(PATH_MAX);
+ sprintf(block->source_name, "%s/%s.c", dir_name, base_name);
+
+ /* generate symbol name for gx function */
+ block->symbol_name = zalloc(PATH_MAX);
+ sprintf(block->symbol_name, "gx_%s", base_name);
+
+ /* open source file */
+ block->source_file = fopen(block->source_name, "w");
+ if(block->source_file == NULL)
+ {
+ sim_io_error(sd, "Error: cannot open file %s, errno %d",
+ block->source_name, errno);
+ }
+
+ /* front matter */
+ fprintf(block->source_file, "/* sim-gx version %d */\n", GX_VERSION);
+ fprintf(block->source_file, "/* gx block date stamp %lu */\n\n", time(NULL));
+
+ /* emit head end of source */
+ tgx_emit_pre_function(gx, optimized);
+
+ /* emit function header */
+ fprintf(block->source_file, "\n\n");
+ fprintf(block->source_file, "extern int\n");
+ fprintf(block->source_file, "%s", block->symbol_name);
+ fprintf(block->source_file, "(struct tgx_cpu_regs* regs, char* pc_flags, struct tgx_callbacks* callbacks)\n");
+ fprintf(block->source_file, "{\n");
+ fprintf(block->source_file, " int rc = 0;\n");
+ if(! optimized)
+ fprintf(block->source_file, " unsigned int insn_count = 0;\n");
+
+ /* pre-block gunk: register load */
+ tgx_emit_load_block(gx, optimized);
+
+ /* emit intra-block jump label */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, "shortjump:\n");
+ fprintf(block->source_file, " pc = npc;\n");
+
+ /* translate jumptarget table */
+ if(! optimized)
+ {
+ fprintf(block->source_file, " pc_flags[(pc - 0x%08x) / %u] |= %d;\n",
+ (unsigned)gx->origin, gx->divisor, GX_PCF_JUMPTARGET);
+ }
+
+ /* enforce learning mode run limit */
+ if(! optimized)
+ {
+ fprintf(block->source_file, " insn_count++;\n");
+ fprintf(block->source_file, " if (insn_count > %d)\n", GX_LEARN_RUN_LIMIT);
+ fprintf(block->source_file, " {\n");
+ fprintf(block->source_file, " rc = %d;\n", GX_F_YIELD);
+ fprintf(block->source_file, " npc = pc;\n");
+ fprintf(block->source_file, " goto save;\n");
+ fprintf(block->source_file, " }\n");
+ }
+
+ /* emit PC switch, use compressed case numbers */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, " switch((pc - 0x%08x) / %u)\n",
+ (unsigned)gx->origin, gx->divisor);
+ fprintf(block->source_file, " {\n");
+
+ /* handle bad-PC event */
+ fprintf(block->source_file, " /* handle unknown jump target */\n");
+ fprintf(block->source_file, " default:\n");
+ fprintf(block->source_file, " rc = %d;\n", GX_F_NONPC);
+ fprintf(block->source_file, " npc = pc;\n");
+ fprintf(block->source_file, " goto save;\n");
+
+ /* start translating at the origin */
+ gx_cia = gx->origin;
+
+ /* translate instructions in block */
+ while(GX_PC_INCLUDES(gx,gx_cia))
+ {
+ sim_cia next_gx_cia;
+
+ /* translate PC case statement */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, " /* PC: 0x%08x, flags %02x */\n",
+ gx_cia, (int) GX_PC_FLAGS(gx, gx_cia));
+
+
+ /* skip over this instruction if it is not executed */
+ if(optimized && !(GX_PC_FLAGS(gx, gx_cia) & GX_PCF_INSTRUCTION))
+ {
+ fprintf(block->source_file, " /* (not reached) */\n");
+
+ /* prevent fall-through from previous translated insn */
+ if(gx_cia > gx->origin &&
+ GX_PC_FLAGS(gx, (gx_cia - gx->divisor)) & GX_PCF_INSTRUCTION)
+ {
+ fprintf(block->source_file, " /* prevent fall-through */\n");
+ fprintf(block->source_file, " npc = 0x%08x;\n", gx_cia);
+ fprintf(block->source_file, " rc = %d;\n", GX_F_NONPC);
+ fprintf(block->source_file, " goto save;\n");
+ }
+
+ next_gx_cia = gx_cia + gx->divisor;
+ goto skip_instruction;
+ }
+
+ /* translate PC case statement */
+ if((! optimized) ||
+ (GX_PC_FLAGS(gx, gx_cia) & GX_PCF_JUMPTARGET))
+ {
+ fprintf(block->source_file, " case %ld:\n",
+ ((gx_cia - gx->origin) / gx->divisor));
+ }
+
+ /* translate breakpoint check & exit */
+ if(GX_PC_FLAGS(gx, gx_cia) & GX_PCF_COND_HALT)
+ {
+ fprintf(block->source_file, " if(pc_flags[%ld] & %d)\n",
+ GX_PC_FLAGS_INDEX(gx, gx_cia),
+ GX_PCF_HALT);
+ fprintf(block->source_file, " {\n");
+ fprintf(block->source_file, " rc = %d;\n", GX_F_HALT);
+ fprintf(block->source_file, " npc = pc;\n");
+ fprintf(block->source_file, " goto save;\n");
+ fprintf(block->source_file, " }\n");
+ }
+
+ /* [don't] emit PC-setting */
+ /* fprintf(block->source_file, " pc = 0x%08x;\n", gx_cia); */
+
+ /* mark traversed instructions */
+ if(! optimized)
+ {
+ fprintf(block->source_file, " pc_flags[%ld] |= %d;\n",
+ GX_PC_FLAGS_INDEX(gx, gx_cia),
+ GX_PCF_INSTRUCTION);
+ }
+
+
+ /* translate instruction semantics */
+ next_gx_cia = tgx_emit_insn(gx, gx_cia, optimized);
+
+ skip_instruction:
+
+ /* go to next instruction */
+ gx_cia = next_gx_cia;
+ }
+ fprintf(block->source_file, " }\n");
+
+ /* dropped through last instruction in switch block */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, " /* dropped through PC switch */\n");
+ fprintf(block->source_file, " npc = 0x%08x;\n", gx_cia);
+ fprintf(block->source_file, " rc = %d;\n", GX_F_RANGE);
+ fprintf(block->source_file, " goto save;\n");
+
+ /* unknown length jump */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, "unknownjump:\n");
+ fprintf(block->source_file, " if(npc >= 0x%08lx && npc < 0x%08lx)\n",
+ gx->origin, gx->origin + gx->length);
+ fprintf(block->source_file, " goto shortjump;\n");
+
+ /* long jump */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, "longjump:\n");
+ fprintf(block->source_file, " rc = %d;\n", GX_F_RANGE);
+
+ /* post-block gunk: SAVE etc. */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, "save:\n");
+
+ tgx_emit_save_block(gx, optimized);
+
+ /* emit tail end of function */
+ fprintf(block->source_file, "\n");
+ fprintf(block->source_file, " return rc;\n");
+ fprintf(block->source_file, "}\n");
+
+ /* emit tail end of source */
+ tgx_emit_post_function(gx, optimized);
+
+ /* close source file */
+ fclose(block->source_file);
+ block->source_file = NULL;
+
+ /* compile source & produce shared object */
+
+ sprintf(compile_command,
+ "gxtool --silent --mode=compile gcc -c -g %s %s",
+ (optimized ? "-O3" : "-O"), block->source_name);
+
+ rc = system(compile_command);
+ if(rc != 0)
+ {
+ sim_io_error(sd, "Error during compiling: `%s' rc %d",
+ compile_command, rc);
+ }
+
+ /* link source */
+
+ sprintf(compile_command,
+ "gxtool --silent --mode=link gcc -export-dynamic -rpath %s -g -o lib%s.la %s.lo",
+ dir_name, base_name, base_name);
+
+ rc = system(compile_command);
+ if(rc != 0)
+ {
+ sim_io_error(sd, "Error during linking: `%s' rc %d",
+ compile_command, rc);
+ }
+
+
+ /* install */
+
+ sprintf(compile_command,
+ "gxtool --silent --mode=install cp lib%s.la %s/%s >/dev/null 2>/dev/null",
+ base_name, pwd_name, dir_name);
+
+ rc = system(compile_command);
+ if(rc != 0)
+ {
+ sim_io_error(sd, "Error during install: `%s' rc %d",
+ compile_command, rc);
+ }
+
+
+ /* finish */
+
+ sprintf(compile_command,
+ "gxtool --silent --mode=finish %s >/dev/null 2>/dev/null",
+ dir_name);
+
+ rc = system(compile_command);
+ if(rc != 0)
+ {
+ sim_io_error(sd, "Error during finish: `%s' rc %d",
+ compile_command, rc);
+ }
+
+ /* clean up */
+
+ sprintf(compile_command, "rm -f lib%s.la %s.lo", base_name, base_name);
+ rc = system(compile_command);
+ if(rc != 0)
+ {
+ sim_io_error(sd, "Error during cleanup: `%s' rc %d",
+ compile_command, rc);
+ }
+
+ /* XXX: FILL IN block->object_name from .la file */
+ sprintf(block->object_name, "%s/%s/lib%s.so.0",
+ pwd_name, dir_name, base_name);
+
+ /* measure compile time */
+ time_end = time(NULL);
+
+ if(time_end == time_begin) time_end ++; /* clamp minimum duration to 1 */
+ gx->compile_time += time_end - time_begin;
+ /* fprintf(stderr, "*** compile time: %d\n", gx->compile_time); */
+}
+
diff --git a/sim/common/sim-gx.h b/sim/common/sim-gx.h
new file mode 100644
index 0000000..b0d0673
--- /dev/null
+++ b/sim/common/sim-gx.h
@@ -0,0 +1,142 @@
+/* GX generic simulator structs.
+ Copyright (C) 1998 Cygnus Solutions.
+*/
+
+#ifndef SIM_GX_H
+#define SIM_GX_H
+
+#include <stdio.h>
+#include "sim-base.h"
+#include "sim-core.h"
+
+
+/*
+#ifndef SIM_GX
+#error "Compile this file only if configured SIM_GX"
+#endif
+*/
+
+
+/* configuration */
+
+#define GX_DIR ".gx"
+#define GX_VERSION 1
+
+
+struct sim_gx_compiled_block;
+
+
+/* record for a particular GX block */
+typedef struct sim_gx_block
+{
+ /* ---- BLOCK EXTENT ---- */
+ address_word origin; /* first code-segment address translated */
+ unsigned_4 length; /* length of translated code-segment */
+
+#define GX_PC_INCLUDES(gx,pc) ((gx)->origin <= (pc) && (pc) < (gx)->origin + (gx)->length)
+
+ short divisor; /* minimum instruction word size; address_word -> index divisor */
+ char* pc_flags; /* see GX_PC_* below */
+
+#define GX_PCF_INSTRUCTION 0x01 /* learned */
+#define GX_PCF_JUMPTARGET 0x02 /* learned */
+#define GX_PCF_COND_HALT 0x10 /* translate-time input */
+#define GX_PCF_HALT 0x20 /* run-time input */
+#define GX_PC_FLAGS_INDEX(gx,pc) ((((pc) - ((gx)->origin)) / (gx)->divisor))
+#define GX_PC_FLAGS(gx,pc) ((gx)->pc_flags[GX_PC_FLAGS_INDEX((gx),(pc))])
+
+ /* GX callbacks */
+ struct tgx_callbacks* callbacks;
+
+ /* compilation statistics */
+ unsigned_4 compile_time; /* time to compile [s] */
+
+ /* ---- LEARNING MODE STATE ---- */
+ unsigned_4 learn_last_change; /* time of last flag change */
+ struct sim_gx_compiled_block* learning_block;
+
+ /* ---- OPTIMIZED MODE STATE ---- */
+ unsigned opt_compile_count; /* number of optimized compile attempts */
+ struct sim_gx_compiled_block* optimized_block;
+} sim_gx_block;
+
+
+
+
+typedef struct sim_gx_compiled_block
+{
+ /* ---- TRANSLATION OBJECTS ---- */
+ char* source_name; /* source file for translated object */
+ char* object_name; /* file name of translated object */
+ char* symbol_name; /* symbol name of function */
+ /* (all above pointers are zalloc()'d buffers, to be zfree()'d. */
+
+ FILE* source_file; /* working file pointer during translation */
+
+ /* ---- LOADED TRANSLATIONS ---- */
+ void* object_dlhandle; /* dlopen() handle to loaded object (if open) */
+ void* function_dlhandle; /* dlsym() pointer to function (if found) */
+} sim_gx_compiled_block;
+
+
+
+/* GX block vector: for quick search of translated blocks */
+typedef struct sim_gx_block_list
+{
+ /* ---- BLOCK VECTOR ---- */
+ sim_gx_block** gx_blocks; /* vector of GX blocks, sorted by origin field */
+ unsigned gx_blocks_size; /* vector length */
+ unsigned gx_blocks_used; /* number of elements used in vector */
+ address_word gx_first, gx_last; /* first & last addresses translated by any gx block */
+} sim_gx_block_list;
+
+
+/* actual gx function pointer type */
+struct tgx_cpu_regs;
+typedef int (*sim_gx_function)(struct tgx_cpu_regs* cpu, char* pc_flags, struct tgx_callbacks* callbacks);
+
+
+/* return values from gx function */
+#define GX_F_HALT 0
+#define GX_F_NONPC 1
+#define GX_F_RANGE 2
+#define GX_F_YIELD 3
+
+
+/* Limit on loop cycles within a learning mode gx block */
+#define GX_LEARN_RUN_LIMIT 10000
+
+/* Operations */
+sim_gx_block* sim_gx_block_create(sim_cia cia);
+
+sim_gx_block* sim_gx_block_find(sim_cia cia);
+void sim_gx_block_add(sim_gx_block* block);
+void sim_gx_block_remove(sim_gx_block* block);
+
+/* State save/restore */
+void sim_gx_write_block_list();
+void sim_gx_read_block_list();
+
+sim_gx_function sim_gx_compiled_block_f(sim_gx_compiled_block* gx);
+void sim_gx_compiled_block_dispose(sim_gx_compiled_block* gx);
+void sim_gx_block_translate(sim_gx_block* gx, int optimized);
+
+
+
+/* Target-specific translation operations */
+
+int tgx_optimize_test(sim_gx_block* block);
+
+void tgx_block_ctor(sim_gx_block* block, sim_cia cia);
+void tgx_block_ctor2(sim_gx_block* block, unsigned_4 origin,
+ unsigned_4 length, unsigned_4 divisor);
+void tgx_block_dtor(sim_gx_block* block);
+
+void tgx_emit_pre_function(sim_gx_block* block, int optimized);
+void tgx_emit_load_block(sim_gx_block* block, int optimized);
+sim_cia tgx_emit_insn(sim_gx_block* block, sim_cia cia, int optimized);
+void tgx_emit_save_block(sim_gx_block* block, int optimized);
+void tgx_emit_post_function(sim_gx_block* block, int optimized);
+
+
+#endif /* SIM_GX_H */