diff options
Diffstat (limited to 'sim/common/sim-gx-run.c')
-rw-r--r-- | sim/common/sim-gx-run.c | 148 |
1 files changed, 148 insertions, 0 deletions
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); + } +} |