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
# Note that this code may declare some locals.
${SHELL} $infile init
-if [ x$parallel != xno ] ; 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 WITH_SEM_SWITCH_FULL && defined (__GNUC__)
- {
- if (! CPU_IDESC_SEM_INIT_P (current_cpu))
- {
+ 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"
- CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
- }
- }
#endif
+#else
+ @cpu@_sem_init_idesc_table (current_cpu);
+#endif
+ CPU_IDESC_SEM_INIT_P (current_cpu) = 1;
+ }
do
{
##########################################################################
-# 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
fetch and decode the instruction. */
if (sc->argbuf.addr != vpc)
{
- 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.
EOF
-if [ x$parallel != xno ] ; 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 != xno ] ; then
- cat << EOF
+cat << EOF
-#if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__)
+ 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 *last_insn_p, 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 { *last_insn_p = (last_p); } while (0)
+/* begin extract-scache */
+EOF
+
+${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
SCACHE *scache = CPU_SCACHE_CACHE (current_cpu);
unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu);
SEM_PC vpc;
-
-EOF
-
-if [ x$parallel != xno ] ; 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 != xno ] ; 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 != no
+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
##########################################################################
sc->argbuf.addr = pc;
sc->argbuf.fields.chain.insn_count = _insn_count;
sc->argbuf.fields.chain.next = 0;
+ sc->argbuf.fields.chain.branch_target = 0;
++sc;
}
}
/* 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)
+ SEM_BRANCH_TYPE br_type, PCADDR new_pc)
{
+ SEM_PC *new_vpc_ptr;
+
PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
/* If not running forever, exit back to main loop. */
/* 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)
{
ARGBUF *abuf = SEM_ARGBUF (sem_arg);
- SET_H_PC (abuf->addr);
+ 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
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
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. */
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
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. */