# Generate the main loop of the simulator.
-# Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
# Contributed by Cygnus Support.
#
# This file is part of the GNU simulators.
#
# ??? Rename mloop.c to eng.c?
# ??? Rename mainloop.in to engine.in?
+# ??? Add options to specify output file names?
# ??? Rename this file to genengine.sh?
#
# Syntax: genmloop.sh [options]
# -simple: simple execution engine (the default)
#
# This engine fetches and executes one instruction at a time.
-# ??? The implementation is currently slower than necessary for
-# simplicity. Instead of storing extract insn fields in ARGBUF,
-# they should just be extracted from the insn when needed.
+# Field extraction is done in the semantic routines.
+#
+# ??? There are two possible flavours of -simple. One that extracts
+# fields in the semantic routine (which is what is implemented here),
+# and one that stores the extracted fields in ARGBUF before calling the
+# semantic routine. The latter is essentially the -scache case with a
+# cache size of one (and the scache lookup code removed). There are no
+# current uses of this and it's not clear when doing this would be a win.
+# More complicated ISA's that want to use -simple may find this a win.
+# Should this ever be desirable, implement a new engine style here and
+# call it -extract (or some such). It's believed that the CGEN-generated
+# code for the -scache case would be usable here, so no new code
+# generation option would be needed for CGEN.
#
# -scache: use the scache to speed things up (not always a win)
#
# We call them pseudo-basic-block's instead of just basic-blocks because
# they're not necessarily basic-blocks, though normally are.
#
-# -parallel: cpu can execute multiple instructions parallely
+# -parallel-read: support parallel execution with read-before-exec support.
+# -parallel-write: support parallel execution with write-after-exec support.
+# -parallel-generic-write: support parallel execution with generic queued
+# writes.
#
-# This option is specified in addition to -simple, -scache, -pbb.
-# Note that while the code can determine if the cpu supports parallel
-# execution with HAVE_PARALLEL_INSNS [and thus this option is
+# One of these options is specified in addition to -simple, -scache,
+# -pbb. Note that while the code can determine if the cpu supports
+# parallel execution with HAVE_PARALLEL_INSNS [and thus this option is
# technically unnecessary], having this option cuts down on the clutter
# in the result.
#
+# -parallel-only: semantic code only supports parallel version of insn
+#
+# Semantic code only supports parallel versions of each insn.
+# Things can be sped up by generating both serial and parallel versions
+# and is better suited to mixed parallel architectures like the m32r.
+#
# -switch file: specify file containing semantics implemented as a switch()
#
# -cpu <cpu-family>
#fast=
#full_switch=
#pbb=
-#parallel=
+parallel=no
+parallel_only=no
switch=
cpu="unknown"
infile=""
-scache) scache=yes ;;
-pbb) pbb=yes ;;
-no-parallel) ;;
- -parallel) parallel=yes ;;
+ -parallel-read) parallel=read ;;
+ -parallel-write) parallel=write ;;
+ -parallel-generic-write) parallel=genwrite ;;
+ -parallel-only) parallel_only=yes ;;
-switch) shift ; switch=$1 ;;
-cpu) shift ; cpu=$1 ;;
-infile) shift ; infile=$1 ;;
echo ""
echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */"
-if [ x$parallel = xyes ] ; then
- echo "#define HAVE_PARALLEL_INSNS 1"
-else
- echo "#define HAVE_PARALLEL_INSNS 0"
-fi
+# blah blah blah, other ways to do this, blah blah blah
+case x$parallel in
+xno)
+ echo "#define HAVE_PARALLEL_INSNS 0"
+ echo "#define WITH_PARALLEL_READ 0"
+ echo "#define WITH_PARALLEL_WRITE 0"
+ echo "#define WITH_PARALLEL_GENWRITE 0"
+ ;;
+xread)
+ echo "#define HAVE_PARALLEL_INSNS 1"
+ echo "/* Parallel execution is supported by read-before-exec. */"
+ echo "#define WITH_PARALLEL_READ 1"
+ echo "#define WITH_PARALLEL_WRITE 0"
+ echo "#define WITH_PARALLEL_GENWRITE 0"
+ ;;
+xwrite)
+ echo "#define HAVE_PARALLEL_INSNS 1"
+ echo "/* Parallel execution is supported by write-after-exec. */"
+ echo "#define WITH_PARALLEL_READ 0"
+ echo "#define WITH_PARALLEL_WRITE 1"
+ echo "#define WITH_PARALLEL_GENWRITE 0"
+ ;;
+xgenwrite)
+ echo "#define HAVE_PARALLEL_INSNS 1"
+ echo "/* Parallel execution is supported by generic write-after-exec. */"
+ echo "#define WITH_PARALLEL_READ 0"
+ echo "#define WITH_PARALLEL_WRITE 0"
+ echo "#define WITH_PARALLEL_GENWRITE 1"
+ ;;
+esac
if [ "x$switch" != x ] ; then
echo ""
echo ""
echo "extern SEM_PC ${cpu}_pbb_begin (SIM_CPU *, int);"
echo "extern SEM_PC ${cpu}_pbb_chain (SIM_CPU *, SEM_ARG);"
- echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_PC *, PCADDR);"
+ echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_BRANCH_TYPE, PCADDR);"
echo "extern void ${cpu}_pbb_before (SIM_CPU *, SCACHE *);"
echo "extern void ${cpu}_pbb_after (SIM_CPU *, SCACHE *);"
fi
rm -f tmp-mloop.cin mloop.cin
exec 1>tmp-mloop.cin
-# We use @cpu@ instead of ${cpu} because we still want to run sed to handle
-# transformation of @cpu@ for mainloop.in.
+# We use @cpu@ instead of ${cpu} because we still need to run sed to handle
+# transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu}
+# here.
cat << EOF
/* This file is generated by the genmloop script. DO NOT EDIT! */
/* Enable switch() support in cgen headers. */
#define SEM_IN_SWITCH
-#define WANT_CPU
-#define WANT_CPU_${CPU}
+#define WANT_CPU @cpu@
+#define WANT_CPU_@CPU@
#include "sim-main.h"
#include "bfd.h"
#include "cgen-mem.h"
#include "cgen-ops.h"
-#include "cpu-opc.h"
-#include "cpu-sim.h"
#include "sim-assert.h"
+/* Fill in the administrative ARGBUF fields required by all insns,
+ virtual and real. */
+
+static INLINE void
+@cpu@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc,
+ PCADDR pc, int fast_p)
+{
+#if WITH_SCACHE
+ SEM_SET_CODE (abuf, idesc, fast_p);
+ ARGBUF_ADDR (abuf) = pc;
+#endif
+ ARGBUF_IDESC (abuf) = idesc;
+}
+
+/* Fill in tracing/profiling fields of an ARGBUF. */
+
+static INLINE void
+@cpu@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf,
+ int trace_p, int profile_p)
+{
+ ARGBUF_TRACE_P (abuf) = trace_p;
+ ARGBUF_PROFILE_P (abuf) = profile_p;
+}
+
+#if WITH_SCACHE_PBB
+
+/* Emit the "x-before" handler.
+ x-before is emitted before each insn (serial or parallel).
+ This is as opposed to x-after which is only emitted at the end of a group
+ of parallel insns. */
+
+static INLINE void
+@cpu@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p)
+{
+ ARGBUF *abuf = &sc[0].argbuf;
+ const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEFORE];
+
+ abuf->fields.before.first_p = first_p;
+ @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
+ /* no need to set trace_p,profile_p */
+}
+
+/* Emit the "x-after" handler.
+ x-after is emitted after a serial insn or at the end of a group of
+ parallel insns. */
+
+static INLINE void
+@cpu@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc)
+{
+ ARGBUF *abuf = &sc[0].argbuf;
+ const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_AFTER];
+
+ @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0);
+ /* no need to set trace_p,profile_p */
+}
+
+#endif /* WITH_SCACHE_PBB */
+
EOF
${SHELL} $infile support
##########################################################################
# Simple engine: fetch an instruction, execute the instruction.
+#
+# Instruction fields are not extracted into ARGBUF, they are extracted in
+# the semantic routines themselves. However, there is still a need to pass
+# and return misc. information to the semantic routines so we still use ARGBUF.
+# [One could certainly implement things differently and remove ARGBUF.
+# It's not clear this is necessarily always a win.]
+# ??? The use of the SCACHE struct is for consistency with the with-scache
+# case though it might be a source of confusion.
if [ x$scache != xyes -a x$pbb != xyes ] ; then
#define FAST_P 0
void
-${cpu}_engine_run_full (SIM_CPU *current_cpu)
+@cpu@_engine_run_full (SIM_CPU *current_cpu)
{
#define FAST_P 0
SIM_DESC current_state = CPU_STATE (current_cpu);
+ /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache.
+ We do however use ARGBUF so for consistency with the other engine flavours
+ the SCACHE type is used. */
SCACHE cache[MAX_LIW_INSNS];
SCACHE *sc = &cache[0];
EOF
-if [ x$parallel = xyes ] ; then
- cat << EOF
+case x$parallel in
+xread | xwrite)
+ cat << EOF
PAREXEC pbufs[MAX_PARALLEL_INSNS];
PAREXEC *par_exec;
EOF
-fi
+ ;;
+esac
# Any initialization code before looping starts.
# Note that this code may declare some locals.
${SHELL} $infile init
-if [ x$parallel = xyes ] ; then
+if [ x$parallel = xread ] ; then
cat << EOF
-#if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
+#if defined (__GNUC__)
{
if (! CPU_IDESC_READ_INIT_P (current_cpu))
{
cat << EOF
+ if (! CPU_IDESC_SEM_INIT_P (current_cpu))
+ {
+#if WITH_SEM_SWITCH_FULL
+#if defined (__GNUC__)
+/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
+#define DEFINE_LABELS
+#include "$switch"
+#endif
+#else
+ @cpu@_sem_init_idesc_table (current_cpu);
+#endif
+ CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
+ }
+
do
{
-/* begin full-{extract,exec}-simple */
+/* begin full-exec-simple */
EOF
-${SHELL} $infile extract-simple
-echo ""
${SHELL} $infile full-exec-simple
cat << EOF
-/* end full-{extract,exec}-simple */
+/* end full-exec-simple */
++ CPU_INSN_COUNT (current_cpu);
}
while (0 /*CPU_RUNNING_P (current_cpu)*/);
-#undef FAST_P
}
#undef FAST_P
#define FAST_P 1
-FIXME
+FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
#undef FAST_P
##########################################################################
-# Scache engine: lookup insn in scache, fetch if missing, then execute it.
+# Non-parallel scache engine: lookup insn in scache, fetch if missing,
+# then execute it.
-if [ x$scache = xyes ] ; then
+if [ x$scache = xyes -a x$parallel = xno ] ; then
cat << EOF
static INLINE SCACHE *
-${cpu}_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
+@cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
unsigned int hash_mask, int FAST_P)
{
/* First step: look up current insn in hash table. */
fetch and decode the instruction. */
if (sc->argbuf.addr != vpc)
{
- insn_t insn;
-
- if (FAST_P)
+ if (! FAST_P)
PROFILE_COUNT_SCACHE_MISS (current_cpu);
/* begin extract-scache */
cat << EOF
/* end extract-scache */
}
- else if (FAST_P)
+ else if (! FAST_P)
{
PROFILE_COUNT_SCACHE_HIT (current_cpu);
/* Make core access statistics come out right.
#define FAST_P 0
void
-${cpu}_engine_run_full (SIM_CPU *current_cpu)
+@cpu@_engine_run_full (SIM_CPU *current_cpu)
{
SIM_DESC current_state = CPU_STATE (current_cpu);
SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
EOF
-if [ x$parallel = xyes ] ; then
- cat << EOF
- PAREXEC pbufs[MAX_PARALLEL_INSNS];
- PAREXEC *par_exec;
+# Any initialization code before looping starts.
+# Note that this code may declare some locals.
+${SHELL} $infile init
+
+cat << EOF
+
+ if (! CPU_IDESC_SEM_INIT_P (current_cpu))
+ {
+#if ! WITH_SEM_SWITCH_FULL
+ @cpu@_sem_init_idesc_table (current_cpu);
+#endif
+ CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
+ }
+
+ vpc = GET_H_PC ();
+
+ do
+ {
+ SCACHE *sc;
+
+ sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
+
+/* begin full-exec-scache */
+EOF
+
+${SHELL} $infile full-exec-scache
+
+cat << EOF
+/* end full-exec-scache */
+
+ SET_H_PC (vpc);
+
+ ++ CPU_INSN_COUNT (current_cpu);
+ }
+ while (0 /*CPU_RUNNING_P (current_cpu)*/);
+}
+
+#undef FAST_P
+
+EOF
+
+####################################
+
+# Non-parallel scache engine: fast version.
+
+if [ x$fast = xyes ] ; then
+
+ cat << EOF
+
+#define FAST_P 1
+
+void
+@cpu@_engine_run_fast (SIM_CPU *current_cpu)
+{
+ SIM_DESC current_state = CPU_STATE (current_cpu);
+ SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
+ unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
+ SEM_PC vpc;
EOF
-fi
# Any initialization code before looping starts.
# Note that this code may declare some locals.
${SHELL} $infile init
-if [ x$parallel = xyes ] ; then
- cat << EOF
+cat << EOF
+
+ if (! CPU_IDESC_SEM_INIT_P (current_cpu))
+ {
+#if WITH_SEM_SWITCH_FAST
+#if defined (__GNUC__)
+/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
+#define DEFINE_LABELS
+#include "$switch"
+#endif
+#else
+ @cpu@_semf_init_idesc_table (current_cpu);
+#endif
+ CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
+ }
+
+ vpc = GET_H_PC ();
+
+ do
+ {
+ SCACHE *sc;
+
+ sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
+
+/* begin fast-exec-scache */
+EOF
+
+${SHELL} $infile fast-exec-scache
+
+cat << EOF
+/* end fast-exec-scache */
+
+ SET_H_PC (vpc);
+
+ ++ CPU_INSN_COUNT (current_cpu);
+ }
+ while (0 /*CPU_RUNNING_P (current_cpu)*/);
+}
+
+#undef FAST_P
+
+EOF
+
+fi # -fast
+
+fi # -scache && ! parallel
+
+##########################################################################
+
+# Parallel scache engine: lookup insn in scache, fetch if missing,
+# then execute it.
+# For the parallel case we give the target more flexibility.
+
+if [ x$scache = xyes -a x$parallel != xno ] ; then
+
+ cat << EOF
+
+static INLINE SCACHE *
+@cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache,
+ unsigned int hash_mask, int FAST_P)
+{
+ /* First step: look up current insn in hash table. */
+ SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask);
+
+ /* If the entry isn't the one we want (cache miss),
+ fetch and decode the instruction. */
+ if (sc->argbuf.addr != vpc)
+ {
+ if (! FAST_P)
+ PROFILE_COUNT_SCACHE_MISS (current_cpu);
+
+#define SET_LAST_INSN_P(last_p) do { sc->last_insn_p = (last_p); } while (0)
+/* begin extract-scache */
+EOF
-#if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
+${SHELL} $infile extract-scache
+
+cat << EOF
+/* end extract-scache */
+#undef SET_LAST_INSN_P
+ }
+ else if (! FAST_P)
+ {
+ PROFILE_COUNT_SCACHE_HIT (current_cpu);
+ /* Make core access statistics come out right.
+ The size is a guess, but it's currently not used either. */
+ PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map);
+ }
+
+ return sc;
+}
+
+#define FAST_P 0
+
+void
+@cpu@_engine_run_full (SIM_CPU *current_cpu)
+{
+ SIM_DESC current_state = CPU_STATE (current_cpu);
+ SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
+ unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
+ SEM_PC vpc;
+
+EOF
+
+# Any initialization code before looping starts.
+# Note that this code may declare some locals.
+${SHELL} $infile init
+
+if [ x$parallel = xread ] ; then
+cat << EOF
+#if defined (__GNUC__)
{
if (! CPU_IDESC_READ_INIT_P (current_cpu))
{
cat << EOF
+ if (! CPU_IDESC_SEM_INIT_P (current_cpu))
+ {
+#if ! WITH_SEM_SWITCH_FULL
+ @cpu@_sem_init_idesc_table (current_cpu);
+#endif
+ CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
+ }
+
vpc = GET_H_PC ();
do
{
- SCACHE *sc;
-
- sc = ${cpu}_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
-
/* begin full-exec-scache */
EOF
cat << EOF
/* end full-exec-scache */
-
- SET_H_PC (vpc);
-
- ++ CPU_INSN_COUNT (current_cpu);
}
while (0 /*CPU_RUNNING_P (current_cpu)*/);
}
####################################
-# Scache engine: fast version.
+# Parallel scache engine: fast version.
if [ x$fast = xyes ] ; then
#define FAST_P 1
void
-${cpu}_engine_run_fast (SIM_CPU *current_cpu)
+@cpu@_engine_run_fast (SIM_CPU *current_cpu)
{
SIM_DESC current_state = CPU_STATE (current_cpu);
SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
SEM_PC vpc;
-
-EOF
-
-if [ x$parallel = xyes ] ; then
- cat << EOF
PAREXEC pbufs[MAX_PARALLEL_INSNS];
PAREXEC *par_exec;
EOF
-fi
# Any initialization code before looping starts.
# Note that this code may declare some locals.
${SHELL} $infile init
-if [ x$parallel = xyes ] ; then
- cat << EOF
+if [ x$parallel = xread ] ; then
+cat << EOF
-#if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
+#if defined (__GNUC__)
{
if (! CPU_IDESC_READ_INIT_P (current_cpu))
{
#endif
EOF
-fi # parallel = yes
+fi
cat << EOF
-#if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
- {
- if (! CPU_IDESC_SEM_INIT_P (current_cpu))
- {
+ if (! CPU_IDESC_SEM_INIT_P (current_cpu))
+ {
+#if WITH_SEM_SWITCH_FAST
+#if defined (__GNUC__)
/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
#define DEFINE_LABELS
#include "$switch"
- CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
- }
- }
#endif
+#else
+ @cpu@_semf_init_idesc_table (current_cpu);
+#endif
+ CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
+ }
vpc = GET_H_PC ();
do
{
- SCACHE *sc;
-
- sc = ${cpu}_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
-
/* begin fast-exec-scache */
EOF
cat << EOF
/* end fast-exec-scache */
-
- SET_H_PC (vpc);
-
- ++ CPU_INSN_COUNT (current_cpu);
}
while (0 /*CPU_RUNNING_P (current_cpu)*/);
}
fi # -fast
-fi # -scache
+fi # -scache && parallel
##########################################################################
cat << EOF
/* Record address of cti terminating a pbb. */
-#define SET_CTI_VPC(sc) do { cti_sc = (sc); } while (0)
+#define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0)
/* Record number of [real] insns in pbb. */
-#define SET_INSN_COUNT(n) do { insn_count = (n); } while (0)
+#define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0)
/* Fetch and extract a pseudo-basic-block.
FAST_P is non-zero if no tracing/profiling/etc. is wanted. */
INLINE SEM_PC
-${cpu}_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
+@cpu@_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
{
SEM_PC new_vpc;
PCADDR pc;
new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc);
if (! new_vpc)
{
- int insn_count = 0;
+ /* Leading '_' to avoid collision with mainloop.in. */
+ int _insn_count = 0;
SCACHE *orig_sc = sc;
- SCACHE *cti_sc = NULL;
+ SCACHE *_cti_sc = NULL;
int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu);
/* First figure out how many instructions to compile.
const IDESC *id;
/* Was pbb terminated by a cti? */
- if (cti_sc)
+ if (_cti_sc)
{
- id = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_CTI_CHAIN];
+ id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CTI_CHAIN];
}
else
{
- id = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_CHAIN];
+ id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CHAIN];
}
SEM_SET_CODE (&sc->argbuf, id, FAST_P);
sc->argbuf.idesc = id;
sc->argbuf.addr = pc;
- sc->argbuf.fields.chain.insn_count = insn_count;
+ sc->argbuf.fields.chain.insn_count = _insn_count;
sc->argbuf.fields.chain.next = 0;
+ sc->argbuf.fields.chain.branch_target = 0;
++sc;
}
- /* Update the pointer to the next free entry. */
+ /* Update the pointer to the next free entry, may not have used as
+ many entries as was asked for. */
CPU_SCACHE_NEXT_FREE (current_cpu) = sc;
/* Record length of chain if profiling.
This includes virtual insns since they count against
/* Chain to the next block from a non-cti terminated previous block. */
INLINE SEM_PC
-${cpu}_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
+@cpu@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
{
ARGBUF *abuf = SEM_ARGBUF (sem_arg);
SET_H_PC (abuf->addr);
/* If not running forever, exit back to main loop. */
- if (CPU_MAX_SLICE_INSNS (current_cpu) != 0)
+ if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
+ /* Also exit back to main loop if there's an event.
+ Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
+ at the "right" time, but then that was what was asked for.
+ There is no silver bullet for simulator engines.
+ ??? Clearly this needs a cleaner interface.
+ At present it's just so Ctrl-C works. */
+ || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
CPU_RUNNING_P (current_cpu) = 0;
/* If chained to next block, go straight to it. */
}
/* Chain to the next block from a cti terminated previous block.
- NEW_VPC_PTR is one of SEM_BRANCH_UNTAKEN, SEM_BRANCH_UNCACHEABLE, or
- a pointer to a location containing the SEM_PC of the branch's address.
+ BR_TYPE indicates whether the branch was taken and whether we can cache
+ the vpc of the branch target.
NEW_PC is the target's branch address, and is only valid if
- NEW_VPC_PTR != SEM_BRANCH_UNTAKEN. */
+ BR_TYPE != SEM_BRANCH_UNTAKEN. */
INLINE SEM_PC
-${cpu}_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
- SEM_PC *new_vpc_ptr, PCADDR new_pc)
+@cpu@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
+ SEM_BRANCH_TYPE br_type, PCADDR new_pc)
{
- ARGBUF *abuf;
+ SEM_PC *new_vpc_ptr;
PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
/* If not running forever, exit back to main loop. */
- if (CPU_MAX_SLICE_INSNS (current_cpu) != 0)
+ if (CPU_MAX_SLICE_INSNS (current_cpu) != 0
+ /* Also exit back to main loop if there's an event.
+ Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed
+ at the "right" time, but then that was what was asked for.
+ There is no silver bullet for simulator engines.
+ ??? Clearly this needs a cleaner interface.
+ At present it's just so Ctrl-C works. */
+ || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending)
CPU_RUNNING_P (current_cpu) = 0;
/* Restart compiler if we branched to an uncacheable address
(e.g. "j reg"). */
- if (new_vpc_ptr == SEM_BRANCH_UNCACHEABLE)
+ if (br_type == SEM_BRANCH_UNCACHEABLE)
{
SET_H_PC (new_pc);
return CPU_SCACHE_PBB_BEGIN (current_cpu);
/* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our
next chain ptr. */
- if (new_vpc_ptr == SEM_BRANCH_UNTAKEN)
+ if (br_type == SEM_BRANCH_UNTAKEN)
{
- abuf = SEM_ARGBUF (sem_arg);
- SET_H_PC (abuf->addr);
+ ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+ new_pc = abuf->addr;
+ SET_H_PC (new_pc);
new_vpc_ptr = &abuf->fields.chain.next;
}
else
{
+ ARGBUF *abuf = SEM_ARGBUF (sem_arg);
SET_H_PC (new_pc);
+ new_vpc_ptr = &abuf->fields.chain.branch_target;
}
/* If chained to next block, go straight to it. */
if (*new_vpc_ptr)
return *new_vpc_ptr;
/* See if next block has already been compiled. */
- *new_vpc_ptr = scache_lookup (current_cpu, GET_H_PC ());
+ *new_vpc_ptr = scache_lookup (current_cpu, new_pc);
if (*new_vpc_ptr)
return *new_vpc_ptr;
/* Nope, so next insn is a virtual insn to invoke the compiler
This is called before each insn. */
void
-${cpu}_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
+@cpu@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
{
SEM_ARG sem_arg = sc;
const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
const IDESC *cur_idesc = cur_abuf->idesc;
PCADDR pc = cur_abuf->addr;
- PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
+ if (ARGBUF_PROFILE_P (cur_abuf))
+ PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num);
/* If this isn't the first insn, finish up the previous one. */
const IDESC *prev_idesc = prev_abuf->idesc;
int cycles;
- cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
- ${cpu}_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
+ /* ??? May want to measure all insns if doing insn tracing. */
+ if (ARGBUF_PROFILE_P (prev_abuf))
+ {
+ cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
+ @cpu@_model_insn_after (current_cpu, 0 /*last_p*/, cycles);
+ }
}
- TRACE_INSN_FINI (current_cpu, 0 /*last_p*/);
+ TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/);
}
/* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
- if (PROFILE_MODEL_P (current_cpu))
- ${cpu}_model_insn_before (current_cpu, first_p);
+ if (PROFILE_MODEL_P (current_cpu)
+ && ARGBUF_PROFILE_P (cur_abuf))
+ @cpu@_model_insn_before (current_cpu, first_p);
- TRACE_INSN_INIT (current_cpu, first_p);
- TRACE_INSN (current_cpu, cur_idesc->opcode, cur_abuf, cur_abuf->addr);
+ TRACE_INSN_INIT (current_cpu, cur_abuf, first_p);
+ TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc);
}
/* x-after handler.
insns. */
void
-${cpu}_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
+@cpu@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc)
{
SEM_ARG sem_arg = sc;
const ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+ const SEM_ARG prev_sem_arg = sc - 1;
+ const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
- if (PROFILE_MODEL_P (current_cpu))
+ /* ??? May want to measure all insns if doing insn tracing. */
+ if (PROFILE_MODEL_P (current_cpu)
+ && ARGBUF_PROFILE_P (prev_abuf))
{
- const SEM_ARG prev_sem_arg = sc - 1;
- const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg);
const IDESC *prev_idesc = prev_abuf->idesc;
int cycles;
cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg);
- ${cpu}_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
+ @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
}
- TRACE_INSN_FINI (current_cpu, 1 /*last_p*/);
+ TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/);
}
#define FAST_P 0
void
-${cpu}_engine_run_full (SIM_CPU *current_cpu)
+@cpu@_engine_run_full (SIM_CPU *current_cpu)
{
SIM_DESC current_state = CPU_STATE (current_cpu);
SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
SEM_PC vpc;
#if WITH_SEM_SWITCH_FULL
/* For communication between cti's and cti-chain. */
+ SEM_BRANCH_TYPE pbb_br_type;
PCADDR pbb_br_npc;
- SEM_PC *pbb_br_npc_ptr;
#endif
EOF
-if [ x$parallel = xyes ] ; then
- cat << EOF
+case x$parallel in
+xread | xwrite)
+ cat << EOF
PAREXEC pbufs[MAX_PARALLEL_INSNS];
PAREXEC *par_exec = &pbufs[0];
EOF
-fi
+ ;;
+esac
# Any initialization code before looping starts.
# Note that this code may declare some locals.
a pbb). And in the "let's run until we're done" case we don't return
until the program exits. */
-#if WITH_SEM_SWITCH_FULL && defined (__GNUC__)
+#if WITH_SEM_SWITCH_FULL
+#if defined (__GNUC__)
/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
#define DEFINE_LABELS
#include "$switch"
+#endif
+#else
+ @cpu@_sem_init_idesc_table (current_cpu);
#endif
/* Initialize the "begin (compile) a pbb" virtual insn. */
vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
SEM_SET_FULL_CODE (SEM_ARGBUF (vpc),
- & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN]);
- vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN];
+ & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
+ vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
}
pbb we don't want to call pbb_begin each time (which hashes on the pc
and does a table lookup). A way to speed this up is to save vpc
between calls. */
- vpc = ${cpu}_pbb_begin (current_cpu, FAST_P);
+ vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
do
{
#define FAST_P 1
void
-${cpu}_engine_run_fast (SIM_CPU *current_cpu)
+@cpu@_engine_run_fast (SIM_CPU *current_cpu)
{
SIM_DESC current_state = CPU_STATE (current_cpu);
SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
SEM_PC vpc;
#if WITH_SEM_SWITCH_FAST
/* For communication between cti's and cti-chain. */
+ SEM_BRANCH_TYPE pbb_br_type;
PCADDR pbb_br_npc;
- SEM_PC *pbb_br_npc_ptr;
#endif
EOF
-if [ x$parallel = xyes ] ; then
- cat << EOF
+case x$parallel in
+xread | xwrite)
+ cat << EOF
PAREXEC pbufs[MAX_PARALLEL_INSNS];
PAREXEC *par_exec = &pbufs[0];
EOF
-fi
+ ;;
+esac
# Any initialization code before looping starts.
# Note that this code may declare some locals.
a pbb). And in the "let's run until we're done" case we don't return
until the program exits. */
-#if WITH_SEM_SWITCH_FAST && defined (__GNUC__)
+#if WITH_SEM_SWITCH_FAST
+#if defined (__GNUC__)
/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */
#define DEFINE_LABELS
#include "$switch"
+#endif
+#else
+ @cpu@_semf_init_idesc_table (current_cpu);
#endif
/* Initialize the "begin (compile) a pbb" virtual insn. */
vpc = CPU_SCACHE_PBB_BEGIN (current_cpu);
SEM_SET_FAST_CODE (SEM_ARGBUF (vpc),
- & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN]);
- vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [${CPU}_INSN_X_BEGIN];
+ & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]);
+ vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN];
CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
}
pbb we don't want to call pbb_begin each time (which hashes on the pc
and does a table lookup). A way to speed this up is to save vpc
between calls. */
- vpc = ${cpu}_pbb_begin (current_cpu, FAST_P);
+ vpc = @cpu@_pbb_begin (current_cpu, FAST_P);
do
{
fi # -pbb
+# Process @cpu@,@CPU@ appearing in mainloop.in.
sed -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" < tmp-mloop.cin > mloop.cin
rc=$?
rm -f tmp-mloop.cin