# This shell script emits a C file. -*- C -*-
# Generate the main loop of the simulator.
-# Syntax: genmloop.sh mono|multi cpu mainloop.in
+# Syntax: genmloop.sh /bin/sh [options] cpu mainloop.in
+# Options: [-mono|-multi] -scache -fast -parallel
+#
+# -scache: use the scache
+# -fast: include support for fast execution in addition to full featured mode
+# -parallel: cpu can execute multiple instructions parallely
+#
# FIXME: "multi" support is wip.
-type=$1
-cpu=$2
-file=$3
+# TODO
+# - move this C code to mainloop.in
+# - keep genmloop.sh
+# - build exec.in from .cpu file
+# - have each cpu provide handwritten cycle.in
+# - integrate with common/sim-engine.[ch]
+# - for sparc, have two main loops, outer one handles delay slot when npc != 0
+# - inner loop does not handle delay slots, pc = pc + 4
+
+type=mono
+#scache=
+#fast=
+#parallel=
+
+shell=$1 ; shift
+
+while true
+do
+ case $1 in
+ -mono) type=mono ;;
+ -multi) type=multi ;;
+ -no-scache) ;;
+ -scache) scache=yes ;;
+ -no-fast) ;;
+ -fast) fast=yes ;;
+ -no-parallel) ;;
+ -parallel) parallel=yes ;;
+ *) break ;;
+ esac
+ shift
+done
+
+cpu=$1
+file=$2
cat <<EOF
/* This file is is generated by the genmloop script. DO NOT EDIT! */
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Contributed by Cygnus Support.
-This file is part of GDB, the GNU debugger.
+This file is part of the GNU simulators.
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
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-/* We want the simcache version of SEM_ARG. */
-#define SCACHE_P
+/* We want the scache version of SEM_ARG.
+ This is used by the switch() version of the semantic code. */
+EOF
+
+if [ x$scache = xyes ] ; then
+ echo "#define SCACHE_P"
+else
+ echo '/*#define SCACHE_P*/'
+ echo '#undef WITH_SCACHE'
+ echo '#define WITH_SCACHE 0'
+fi
+
+cat <<EOF
+
+#define WANT_CPU
+#define WANT_CPU_@CPU@
#include "sim-main.h"
#include "bfd.h"
-#include "mem-ops.h"
-#include "sem-ops.h"
-#include "cgen-scache.h"
+#include "cgen-mem.h"
+#include "cgen-ops.h"
#include "cpu-opc.h"
#include "cpu-sim.h"
+#include "sim-assert.h"
/* Tell sim_main_loop to use the cache if it's active.
Collecting profile data and tracing slow us down so we don't do them in
- use or don't use the cache
- run normally (full featured) or run fast
Supporting all four possibilities in one executable is a bit much but
- supporting normal/fast seems reasonable.
+ supporting full/fast seems reasonable.
If the cache is configured in it is always used.
??? Need to see whether it speeds up profiling significantly or not.
Speeding up tracing doesn't seem worth it.
#define SIM_POST_EXEC_HOOK(state)
#endif
+#if 0 /* FIXME:experiment */
+/* "sc" is local to the calling function.
+ It is done this way to keep the internals of the implementation out of
+ the description file. */
+#define EXTRACT(cpu, pc, insn, sc, num, fast_p) \
+@cpu@_extract (cpu, pc, insn, sc + num, fast_p)
+
+#define EXECUTE(cpu, sc, num, fast_p) \
+@cpu@_execute (cpu, sc + num, fast_p)
+#endif
+
+#define GET_ATTR(cpu, num, attr) \
+CGEN_INSN_ATTR (sc[num].argbuf.opcode, CGEN_INSN_##attr)
+
EOF
${SHELL} $file support
cat <<EOF
static volatile int keep_running;
+/* Want to measure simulator speed even in fast mode. */
+static unsigned long insn_count;
+static SIM_ELAPSED_TIME start_time;
+
+/* Forward decls of cpu-specific functions. */
+static void engine_resume (SIM_DESC, int, int);
+static void engine_resume_full (SIM_DESC);
+${scache+static void engine_resume_fast (SIM_DESC);}
int
-engine_stop (SIM_DESC sd)
+@cpu@_engine_stop (SIM_DESC sd)
{
keep_running = 0;
return 1;
}
void
-engine_run (SIM_DESC sd, int step, int siggnal)
+@cpu@_engine_run (SIM_DESC sd, int step, int siggnal)
{
- current_state = sd;
#if WITH_SCACHE
if (USING_SCACHE_P (sd))
scache_flush (sd);
engine_resume (sd, step, siggnal);
}
-void
+static void
engine_resume (SIM_DESC sd, int step, int siggnal)
{
-#ifdef __STDC__
- /* These are volatile to survive setjmp/longjmp.
- This will slow down the simulation a teensy bit, but we want to
- measure simulator speed even in fast mode. */
- volatile unsigned long insn_count;
- volatile SIM_ELAPSED_TIME start_time;
-#else
- /* ??? Not sure what to do for K&R C. */
- static unsigned long insn_count;
- static SIM_ELAPSED_TIME start_time;
-#endif
- SIM_DESC current_state = sd;
sim_cpu *current_cpu = STATE_CPU (sd, 0);
+ /* These are volatile to survive setjmp. */
+ volatile sim_cpu *cpu = current_cpu;
+ volatile sim_engine *engine = STATE_ENGINE (sd);
+ jmp_buf buf;
+ int jmpval;
- keep_running = 1;
+ keep_running = ! step;
start_time = sim_elapsed_time_get ();
+ /* FIXME: Having this global can slow things down a teensy bit.
+ After things are working see about moving engine_resume_{full,fast}
+ back into this function. */
insn_count = 0;
- if (setjmp (STATE_HALT_JMP_BUF (sd)))
+ engine->jmpbuf = &buf;
+ if (setjmp (buf))
{
- TRACE_INSN_FINI (current_cpu);
- PROFILE_EXEC_TIME (CPU_PROFILE_DATA (current_cpu))
+ engine->jmpbuf = NULL;
+ TRACE_INSN_FINI ((sim_cpu *) cpu);
+ PROFILE_EXEC_TIME (CPU_PROFILE_DATA (cpu))
+= sim_elapsed_time_since (start_time);
- PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (current_cpu))
+ PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu))
+= insn_count;
return;
}
+ /* ??? Restart support to be added in time. */
+
+ /* The computed goto switch can be used, and while the number of blocks
+ may swamp the relatively few that this function contains, when running
+ with the scache we put the actual semantic code in their own
+ functions. */
+
+EOF
+
+if [ x$fast = xyes ] ; then
+ cat <<EOF
+ if (step
+ || !RUN_FAST_P (current_cpu))
+ engine_resume_full (sd);
+ else
+ engine_resume_fast (sd);
+EOF
+else
+ cat <<EOF
+ engine_resume_full (sd);
+EOF
+fi
+
+cat <<EOF
+
+ /* If the loop exits, either we single-stepped or engine_stop was called.
+ In either case we need to call engine_halt: to properly exit this
+ function we must go through the setjmp executed above. */
+ if (step)
+ sim_engine_halt (sd, current_cpu, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
+ sim_engine_halt (sd, current_cpu, NULL, NULL_CIA, sim_stopped, SIM_SIGINT);
+}
+
+EOF
+
+if [ x$scache = xyes ] ; then
+ cat <<EOF
+
+static void
+engine_resume_full (SIM_DESC sd)
+{
+#define FAST_P 0
+ /* current_{state,cpu} exist for the generated code to use. */
+ SIM_DESC current_state = sd;
+ sim_cpu *current_cpu = STATE_CPU (sd, 0);
+${parallel+ int icount = 0;}
+
EOF
# Any initialization code before looping starts.
cat <<EOF
- /* ??? Restart support to be added in time. */
+ do
+ {
+ /* FIXME: Later check every insn for events and such. */
- if (step
- || !RUN_FAST_P (current_cpu))
+ SIM_PRE_EXEC_HOOK (current_cpu);
+
+ {
+ unsigned int hash;
+ SCACHE *sc;
+ PCADDR pc = PC;
+
+ /* First step: look up current insn in hash table. */
+ hash = SCACHE_HASH_PC (sd, pc);
+ sc = CPU_SCACHE_CACHE (current_cpu) + hash;
+
+ /* If the entry isn't the one we want (cache miss),
+ fetch and decode the instruction. */
+ if (sc->argbuf.addr != pc)
+ {
+ insn_t insn;
+
+ PROFILE_COUNT_SCACHE_MISS (current_cpu);
+
+/* begin full-extract-scache */
+EOF
+
+${SHELL} $file full-extract-scache
+
+cat <<EOF
+/* end full-extract-scache */
+ }
+ else
+ {
+ PROFILE_COUNT_SCACHE_HIT (current_cpu);
+ }
+
+/* begin full-exec-scache */
+EOF
+
+${SHELL} $file full-exec-scache
+
+cat <<EOF
+/* end full-exec-scache */
+ }
+
+ SIM_POST_EXEC_HOOK (current_cpu);
+
+ ++insn_count;
+ }
+ while (keep_running);
+#undef FAST_P
+}
+EOF
+
+else # ! WITH_SCACHE
+ cat <<EOF
+
+static void
+engine_resume_full (SIM_DESC sd)
+{
+#define FAST_P 0
+ SIM_DESC current_state = sd;
+ sim_cpu *current_cpu = STATE_CPU (sd, 0);
+ SCACHE cache[MAX_LIW_INSNS];
+ SCACHE *sc = &cache[0];
+${parallel+ int icount = 0;}
+
+EOF
+
+# Any initialization code before looping starts.
+${SHELL} $file init
+
+cat <<EOF
+
+ do
{
- do
- {
-#define FAST 0 /* ??? Hopefully this name won't collide with anything. */
- /* FIXME: Later check every insn for events and such. */
+ /* FIXME: Later check every insn for events and such. */
- SIM_PRE_EXEC_HOOK (current_cpu);
+ SIM_PRE_EXEC_HOOK (current_cpu);
+ {
+/* begin full-{extract,exec}-noscache */
EOF
-# Copy of main loop that uses the various compiled in features.
-# FIXME: May want more than one copy of this.
-${SHELL} $file normal
+${SHELL} $file full-extract-noscache
+echo ""
+${SHELL} $file full-exec-noscache
cat <<EOF
+/* end full-{extract,exec}-noscache */
+ }
- SIM_POST_EXEC_HOOK (current_cpu);
+ SIM_POST_EXEC_HOOK (current_cpu);
- ++insn_count;
- if (step)
- engine_halt (current_cpu, EXEC_STATE_STOPPED, SIM_SIGTRAP);
- }
- while (keep_running);
- /* If the loop exists, engine_stop was called. */
- engine_halt (current_cpu, EXEC_STATE_STOPPED, SIM_SIGINT);
-#undef FAST
+ ++insn_count;
}
- else
+ while (keep_running);
+#undef FAST_P
+}
+
+EOF
+fi # ! WITH_SCACHE
+
+if [ x$fast = xyes ] ; then
+ if [ x$scache = xyes ] ; then
+ cat <<EOF
+
+static void
+engine_resume_fast (SIM_DESC sd)
+{
+#define FAST_P 1
+ SIM_DESC current_state = sd;
+ sim_cpu *current_cpu = STATE_CPU (sd, 0);
+${parallel+ int icount = 0;}
+
+EOF
+
+# Any initialization code before looping starts.
+${SHELL} $file init
+
+cat <<EOF
+
+#if defined (WITH_SEM_SWITCH_FAST) && defined (__GNUC__)
+ {
+ static decode_init_p = 0;
+ if (! decode_init_p)
+ {
+/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
+#define DEFINE_LABELS
+#include "sem-switch.c"
+ decode_init_p = 1;
+ }
+ }
+#endif
+
+ do
{
- do
- {
-#define FAST 1
+ {
+ unsigned int hash;
+ SCACHE *sc;
+ PCADDR pc = PC;
+
+ /* First step: look up current insn in hash table. */
+ hash = SCACHE_HASH_PC (sd, pc);
+ sc = CPU_SCACHE_CACHE (current_cpu) + hash;
+
+ /* If the entry isn't the one we want (cache miss),
+ fetch and decode the instruction. */
+ if (sc->argbuf.addr != pc)
+ {
+ insn_t insn;
+
+/* begin fast-extract-scache */
+EOF
+
+${SHELL} $file fast-extract-scache
+
+cat <<EOF
+/* end fast-extract-scache */
+ }
+
+/* begin fast-exec-scache */
+EOF
+
+${SHELL} $file fast-exec-scache
+
+cat <<EOF
+/* end fast-exec-scache */
+
+ }
+
+ ++insn_count;
+ }
+ while (keep_running);
+#undef FAST_P
+}
+
+EOF
+
+else # ! WITH_SCACHE
+ cat <<EOF
+
+static void
+engine_resume_fast (SIM_DESC sd)
+{
+#define FAST_P 1
+ SIM_DESC current_state = sd;
+ sim_cpu *current_cpu = STATE_CPU (sd, 0);
+ SCACHE cache[MAX_LIW_INSNS];
+ SCACHE *sc = &cache[0];
+${parallel+ int icount = 0;}
EOF
-# Copy of main loop that is run purely for fast execution.
-${SHELL} $file fast
+# Any initialization code before looping starts.
+${SHELL} $file init
cat <<EOF
-#undef FAST
- ++insn_count;
- }
- while (keep_running);
- /* If the loop exists, engine_stop was called. */
- engine_halt (current_cpu, EXEC_STATE_STOPPED, SIM_SIGINT);
+ do
+ {
+/* begin fast-{extract,exec}-noscache */
+EOF
+
+${SHELL} $file fast-extract-noscache
+echo ""
+${SHELL} $file fast-exec-noscache
+
+cat <<EOF
+/* end fast-{extract,exec}-noscache */
+
+ ++insn_count;
}
+ while (keep_running);
+#undef FAST_P
}
+
EOF
+
+ fi # ! WITH_SCACHE
+fi # -fast