import gdb-1999-09-28 snapshot
[deliverable/binutils-gdb.git] / sim / common / genmloop.sh
index 865fe7242f5edbdc412007c0cbbc557e9659deac..d3e17b085dfcd2eca6e1d3f314c46ccba3f16c3f 100644 (file)
@@ -85,6 +85,8 @@
 #
 # -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.
 #
 #      One of these options is specified in addition to -simple, -scache,
 #      -pbb.  Note that while the code can determine if the cpu supports
 #      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>
@@ -116,6 +124,7 @@ type=mono
 #full_switch=
 #pbb=
 parallel=no
+parallel_only=no
 switch=
 cpu="unknown"
 infile=""
@@ -134,6 +143,8 @@ do
        -no-parallel) ;;
        -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 ;;
@@ -189,22 +200,36 @@ fi
 
 echo ""
 echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn.  */"
-if [ x$parallel != xno ] ; then
-       echo "#define HAVE_PARALLEL_INSNS 1"
-       if [ x$parallel = xread ] ; then
-           echo "/* Parallel execution is supported by read-before-exec.  */"
-           echo "#define WITH_PARALLEL_READ 1"
-           echo "#define WITH_PARALLEL_WRITE 0"
-       else
-           echo "/* Parallel execution is supported by write-after-exec.  */"
-           echo "#define WITH_PARALLEL_READ 0"
-           echo "#define WITH_PARALLEL_WRITE 1"
-       fi
-else
-       echo "#define HAVE_PARALLEL_INSNS 0"
-       echo "#define WITH_PARALLEL_READ 0"
-       echo "#define WITH_PARALLEL_WRITE 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 ""
@@ -238,7 +263,7 @@ if [ x$pbb = xyes ] ; then
        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
@@ -360,22 +385,24 @@ void
 
 EOF
 
-if [ x$parallel != xno ] ; 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 != 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))
       {
@@ -392,17 +419,19 @@ fi
 
 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
     {
@@ -446,9 +475,10 @@ fi # simple engine
 
 ##########################################################################
 
-# 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
 
@@ -463,9 +493,7 @@ static INLINE SCACHE *
      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 */
@@ -476,7 +504,7 @@ ${SHELL} $infile 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.
@@ -499,22 +527,182 @@ void
 
 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 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
+
+${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))
       {
@@ -531,14 +719,18 @@ fi
 
 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
 
@@ -546,10 +738,6 @@ ${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)*/);
 }
@@ -560,7 +748,7 @@ EOF
 
 ####################################
 
-# Scache engine: fast version.
+# Parallel scache engine: fast version.
 
 if [ x$fast = xyes ] ; then
 
@@ -575,25 +763,19 @@ void
   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))
       {
@@ -606,30 +788,28 @@ if [ x$parallel != xno ] ; then
 #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
 
@@ -637,10 +817,6 @@ ${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)*/);
 }
@@ -651,7 +827,7 @@ EOF
 
 fi # -fast
 
-fi # -scache
+fi # -scache && parallel
 
 ##########################################################################
 
@@ -768,10 +944,12 @@ cat << EOF
        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;
       }
 
-      /* 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
@@ -818,16 +996,16 @@ INLINE SEM_PC
 }
 
 /* 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)
 {
-  ARGBUF *abuf;
+  SEM_PC *new_vpc_ptr;
 
   PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg);
 
@@ -844,7 +1022,7 @@ INLINE SEM_PC
 
   /* 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);
@@ -852,22 +1030,25 @@ INLINE SEM_PC
 
   /* 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
@@ -958,19 +1139,21 @@ void
   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 != xno ] ; 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.
@@ -986,10 +1169,14 @@ cat << 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.  */
@@ -1044,19 +1231,21 @@ void
   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 != xno ] ; 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.
@@ -1072,10 +1261,14 @@ cat << 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.  */
This page took 0.030035 seconds and 4 git commands to generate.