* Make-common.in (CGEN_INCLUDE_DEPS): Add cgen-defs.h, cgen-engine.h.
authorDoug Evans <dje@google.com>
Wed, 6 Jan 1999 00:42:34 +0000 (00:42 +0000)
committerDoug Evans <dje@google.com>
Wed, 6 Jan 1999 00:42:34 +0000 (00:42 +0000)
(CGEN_MAIN_SCM): Add rtx-funcs.scm.
(cgen-arch): Pass $(mach) to cgen.sh.
* cgen-engine.h (SEM_BRANCH_FINI): New arg pcvar, all uses updated.
(SEM_BRANCH_INIT_EXTRACT): New macro.
(SEM_BRANCH_INIT): Add taken_p.
(TARGET_SEM_BRANCH_FINI): Provide default definition.
(SEM_BRANCH_FINI): Use it.
(SEM_INSN): Update.
* cgen-run.c (sim_resume): Handle tracing of last insn.
* cgen-scache.h (WITH_SCACHE): Define as 0 if not defined.
* cgen-trace.c (current_abuf): New static global.
(trace_insn_init): Initialize it.
(trace_insn_fini): Use it.
(trace_insn): Set it.
* cgen.sh (arch case): Pass -m ${mach} to cgen.
* genmloop.sh (@cpu@_emit_before): Only define if WITH_SCACHE_PBB.
(@cpu@_emit_after): Ditto.
(simple @cpu@_engine_run_full): New local `pc'.  Initialize semantic
labels if WITH_SEM_SWITCH_FULL.
* sim-model.c: Include bfd.h.
(sim_model_init): New function.
(sim_model_install): Record init fn.
* sim-model.h (MACH): New member bfd_name.
* sim-module.c (modules): Initialize model before scache.

sim/common/ChangeLog
sim/common/cgen-engine.h
sim/common/cgen-scache.h
sim/common/cgen-trace.c
sim/common/genmloop.sh
sim/common/sim-model.c [new file with mode: 0644]
sim/common/sim-model.h [new file with mode: 0644]
sim/common/sim-module.c

index 9809189..b8b68ab 100644 (file)
@@ -1,3 +1,31 @@
+1999-01-05  Doug Evans  <devans@casey.cygnus.com>
+
+       * Make-common.in (CGEN_INCLUDE_DEPS): Add cgen-defs.h, cgen-engine.h.
+       (CGEN_MAIN_SCM): Add rtx-funcs.scm.
+       (cgen-arch): Pass $(mach) to cgen.sh.
+       * cgen-engine.h (SEM_BRANCH_FINI): New arg pcvar, all uses updated.
+       (SEM_BRANCH_INIT_EXTRACT): New macro.
+       (SEM_BRANCH_INIT): Add taken_p.
+       (TARGET_SEM_BRANCH_FINI): Provide default definition.
+       (SEM_BRANCH_FINI): Use it.
+       (SEM_INSN): Update.
+       * cgen-run.c (sim_resume): Handle tracing of last insn.
+       * cgen-scache.h (WITH_SCACHE): Define as 0 if not defined.
+       * cgen-trace.c (current_abuf): New static global.
+       (trace_insn_init): Initialize it.
+       (trace_insn_fini): Use it.
+       (trace_insn): Set it.
+       * cgen.sh (arch case): Pass -m ${mach} to cgen.
+       * genmloop.sh (@cpu@_emit_before): Only define if WITH_SCACHE_PBB.
+       (@cpu@_emit_after): Ditto.
+       (simple @cpu@_engine_run_full): New local `pc'.  Initialize semantic
+       labels if WITH_SEM_SWITCH_FULL.
+       * sim-model.c: Include bfd.h.
+       (sim_model_init): New function.
+       (sim_model_install): Record init fn.
+       * sim-model.h (MACH): New member bfd_name.
+       * sim-module.c (modules): Initialize model before scache.
+
 1998-12-24  Frank Ch. Eigler  <fche@cygnus.com>
 
        * dv-sockser.c (DEFAULT_TIMEOUT): Increase to 1 ms.
index 91b7766..5c64e6b 100644 (file)
@@ -1,4 +1,4 @@
-/* Simulator header for the cgen engine.
+/* Engine header for Cpu tools GENerated simulators.
    Copyright (C) 1998 Free Software Foundation, Inc.
    Contributed by Cygnus Support.
 
@@ -18,10 +18,7 @@ You should have received a copy of the GNU General Public License along
 with this program; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-/* This file must be included after eng.h and ${cpu}.h have been included.  */
-
-#ifndef CGEN_ENGINE_H
-#define CGEN_ENGINE_H
+/* This file must be included after eng.h and before ${cpu}.h.  */
 
 /* Semantic functions come in six versions on two axes:
    fast/full-featured, and using one of the simple/scache/compilation engines.
@@ -32,6 +29,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 /* FIXME: --enable-sim-fast not implemented yet.  */
 /* FIXME: undecided how to handle WITH_SCACHE_PBB.  */
 
+#ifndef CGEN_ENGINE_H
+#define CGEN_ENGINE_H
+
+/* Instruction field support macros.  */
+
+#define EXTRACT_MSB0_INT(val, total, start, length) \
+(((INT) (val) << ((sizeof (INT) * 8) - (total) + (start))) \
+ >> ((sizeof (INT) * 8) - (length)))
+#define EXTRACT_MSB0_UINT(val, total, start, length) \
+(((UINT) (val) << ((sizeof (UINT) * 8) - (total) + (start))) \
+ >> ((sizeof (UINT) * 8) - (length)))
+
+#define EXTRACT_LSB0_INT(val, total, start, length) \
+(((INT) (val) << ((sizeof (INT) * 8) - (start) - (length))) \
+ >> ((sizeof (INT) * 8) - (length)))
+#define EXTRACT_LSB0_UINT(val, total, start, length) \
+(((UINT) (val) << ((sizeof (UINT) * 8) - (start) - (length))) \
+ >> ((sizeof (UINT) * 8) - (length)))
+
+#if CGEN_INSN_LSB0_P
+
+#define EXTRACT_INT(val, total, start, length) \
+  EXTRACT_LSB0_INT ((val), (total), (start), (length))
+#define EXTRACT_UINT(val, total, start, length) \
+  EXTRACT_LSB0_UINT ((val), (total), (start), (length))
+
+#else
+
+#define EXTRACT_INT(val, total, start, length) \
+  EXTRACT_MSB0_INT ((val), (total), (start), (length))
+#define EXTRACT_UINT(val, total, start, length) \
+  EXTRACT_MSB0_UINT ((val), (total), (start), (length))
+
+#endif
+\f
+/* union sem */
+
 /* Types of the machine generated extract and semantic fns.  */
 typedef void (EXTRACT_FN) (SIM_CPU *, PCADDR, insn_t, ARGBUF *);
 #if HAVE_PARALLEL_INSNS
@@ -91,7 +125,7 @@ do { \
   else \
     SEM_SET_FULL_CODE ((abuf), (idesc)); \
 } while (0)
-
+\f
 #define IDESC_CTI_P(idesc) \
      ((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->opcode)) \
        & (CGEN_ATTR_MASK (CGEN_INSN_COND_CTI) \
@@ -104,8 +138,6 @@ do { \
 
 /* These are used so that we can compile two copies of the semantic code,
    one with full feature support and one without that runs fast(er).  */
-/* FIXME: Eventually delete extraction if not using scache.  */
-#define EX_FN_NAME(cpu,fn) XCONCAT3 (cpu,_ex_,fn)
 #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn)
 #define SEMF_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn)
 
@@ -116,10 +148,15 @@ do { \
 /* semantics.c support */
 #define SEM_ARGBUF(sem_arg) (& (sem_arg) -> argbuf)
 #define SEM_INSN(sem_arg) shouldnt_be_used
-#define SEM_NEXT_VPC(sc, len) ((sc) + 1)
 
 #if WITH_SCACHE_PBB
 
+/* Return the scache pointer of the current insn.  */
+#define SEM_SEM_ARG(vpc, sc) (vpc)
+/* Return the virtual pc of the next insn to execute
+   (assuming this isn't a cti).  */
+#define SEM_NEXT_VPC(sem_arg, pc, len) ((sem_arg) + 1)
+
 /* Update the instruction counter.  */
 #define PBB_UPDATE_INSN_COUNT(cpu,sc) \
   (CPU_INSN_COUNT (cpu) += SEM_ARGBUF (sc) -> fields.chain.insn_count)
@@ -130,8 +167,7 @@ do { \
    address (e.g. j reg).  */
 #define SEM_BRANCH_UNCACHEABLE ((SEM_PC *) 1)
 
-/* ??? Only necessary if SEM_BRANCH_VIA_CACHE will be used,
-   but for simplicity it's done this way.  */
+/* Initialize next-pbb link for SEM_BRANCH_VIA_CACHE.  */
 #define SEM_BRANCH_INIT_EXTRACT(abuf) \
 do { (abuf)->fields.cti.addr_cache = 0; } while (0)
 
@@ -144,21 +180,17 @@ do { (abuf)->fields.cti.addr_cache = 0; } while (0)
    generated by genmloop.sh.  It exists so generated semantic code needn't
    care whether it's being put in a switch or in a function.  */
 #ifdef SEM_IN_SWITCH
-/* Do not append a `;' to invocations of this.
-   ??? Unnecessary here, but for consistency with ..._INIT.  */
-#define SEM_BRANCH_FINI \
-{ \
+#define SEM_BRANCH_FINI(pcvar) \
+do { \
   pbb_br_npc = npc; \
   pbb_br_npc_ptr = npc_ptr; \
-}
+} while (0)
 #else /* 1 semantic function per instruction */
-/* Do not append a `;' to invocations of this.
-   ??? Unnecessary here, but for consistency with ..._INIT.  */
-#define SEM_BRANCH_FINI \
-{ \
+#define SEM_BRANCH_FINI(pcvar) \
+do { \
   CPU_PBB_BR_NPC (current_cpu) = npc; \
   CPU_PBB_BR_NPC_PTR (current_cpu) = npc_ptr; \
-}
+} while (0)
 #endif
 
 /* Return address of cached branch address value.  */
@@ -177,50 +209,83 @@ do { \
 
 #else /* ! WITH_SCACHE_PBB */
 
-#define SEM_BRANCH_INIT
-#define SEM_BRANCH_FINI
+#define SEM_SEM_ARG(vpc, sc) (sc)
+#define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len))
+
+#define SEM_BRANCH_INIT_EXTRACT(abuf) do { } while (0)
+
+#define SEM_BRANCH_INIT \
+  int taken_p = 0;
+#ifndef TARGET_SEM_BRANCH_FINI(pcvar, taken_p)
+#define TARGET_SEM_BRANCH_FINI(pcvar, taken_p)
+#endif
+#define SEM_BRANCH_FINI(pcvar) \
+  do { TARGET_SEM_BRANCH_FINI (pcvar, taken_p); } while (0)
 
 #define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used
 #define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar, cachevar) \
 do { \
   (pcvar) = (newval); \
+  taken_p = 1; \
 } while (0)
 #define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \
 do { \
   (pcvar) = (newval); \
+  taken_p = 1; \
 } while (0)
 
 #endif /* ! WITH_SCACHE_PBB */
 
-/* Return address a branch insn will branch to.
-   This is only used during tracing.  */
-#define SEM_NEW_PC_ADDR(new_pc) (new_pc)
-
 #else /* ! WITH_SCACHE */
 
 #define CIA_ADDR(cia) (cia)
 
 /* semantics.c support */
 #define SEM_ARGBUF(sem_arg) (sem_arg)
-#define SEM_INSN(sem_arg) (SEM_ARGBUF (sem_arg) -> insn)
-/* FIXME:wip */
-#define SEM_NEXT_VPC(abuf, len) ((abuf) -> addr + (abuf) -> length)
+#define SEM_INSN(sem_arg) (SEM_ARGBUF (sem_arg) -> base_insn)
 
-#define SEM_BRANCH_INIT
-#define SEM_BRANCH_FINI
+#define SEM_SEM_ARG(vpc, sc) (sc)
+#define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len))
+
+#define SEM_BRANCH_INIT \
+  int taken_p = 0;
+#ifndef TARGET_SEM_BRANCH_FINI
+#define TARGET_SEM_BRANCH_FINI(pcvar, taken_p)
+#endif
+#define SEM_BRANCH_FINI(pcvar) \
+  do { TARGET_SEM_BRANCH_FINI (pcvar, taken_p); } while (0)
 
 #define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used
 #define SEM_BRANCH_VIA_CACHE(cpu, abuf, newval, pcvar, cachevar) \
 do { \
   (pcvar) = (newval); \
+  taken_p = 1; \
 } while (0)
 #define SEM_BRANCH_VIA_ADDR(cpu, abuf, newval, pcvar) \
 do { \
   (pcvar) = (newval); \
+  taken_p = 1; \
 } while (0)
 
-#define SEM_NEW_PC_ADDR(new_pc) (new_pc)
-
 #endif /* ! WITH_SCACHE */
+\f
+/* Tracing/profiling.  */
+
+/* Return non-zero if a before/after handler is needed.
+   When tracing/profiling a selected range there's no need to slow
+   down simulation of the other insns (except to get more accurate data!).
+
+   ??? May wish to profile all insns if doing insn tracing, or to
+   get more accurate cycle data.
+
+   First test ANY_P so we avoid a potentially expensive HIT_P call
+   [if there are lots of address ranges].  */
+
+#define PC_IN_TRACE_RANGE_P(cpu, pc) \
+  (TRACE_ANY_P (cpu) \
+   && ADDR_RANGE_HIT_P (TRACE_RANGE (CPU_TRACE_DATA (cpu)), (pc)))
+#define PC_IN_PROFILE_RANGE_P(cpu, pc) \
+  (PROFILE_ANY_P (cpu) \
+   && ADDR_RANGE_HIT_P (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), (pc)))
 
 #endif /* CGEN_ENGINE_H */
index 9cb2a5f..e422859 100644 (file)
@@ -1,6 +1,6 @@
-/* Simulator cache definitions for CGEN simulators (and maybe others).
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
-   Contributed by Cygnus Support.
+/* Simulator header for cgen scache support.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions.
 
 This file is part of GDB, the GNU debugger.
 
@@ -18,62 +18,94 @@ You should have received a copy of the GNU General Public License along
 with this program; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#ifndef SCACHE_H
-#define SCACHE_H
+#ifndef CGEN_SCACHE_H
+#define CGEN_SCACHE_H
 
-/* A cached insn.  */
-typedef struct scache {
-  IADDR next;
-  union {
-#ifdef USE_SEM_SWITCH
-#ifdef __GNUC__
-    void *sem_case;
-#else
-    int sem_case;
-#endif
+#ifndef WITH_SCACHE
+#define WITH_SCACHE 0
 #endif
-    SEMANTIC_CACHE_FN *sem_fn;
-  } semantic;
-  ARGBUF argbuf;
-} SCACHE;
 
-/* Scache data for each cpu.  */
+/* When caching bb's, instructions are extracted into "chains".
+   SCACHE_MAP is a hash table into these chains.  */
+
+typedef struct {
+  PCADDR pc;
+  SCACHE *sc;
+} SCACHE_MAP;
 
 typedef struct cpu_scache {
-  /* Simulator cache size.  */
-  int size;
-#define CPU_SCACHE_SIZE(cpu) ((cpu)->cgen_cpu.scache.size)
-  /* Cache.  */
+  /* Simulator cache size.  Must be a power of 2.
+     This is the number of elements in the `cache' member.  */
+  unsigned int size;
+#define CPU_SCACHE_SIZE(cpu) ((cpu) -> cgen_cpu.scache.size)
+  /* The cache.  */
   SCACHE *cache;
-#define CPU_SCACHE_CACHE(cpu) ((cpu)->cgen_cpu.scache.cache)
-#if 0 /* FIXME: wip */
-  /* Free list.  */
-  SCACHE *free;
-#define CPU_SCACHE_FREE(cpu) ((cpu)->cgen_cpu.scache.free)
-  /* Hash table.  */
-  SCACHE **hash_table;
-#define CPU_SCACHE_HASH_TABLE(cpu) ((cpu)->cgen_cpu.scache.hash_table)
-#endif
+#define CPU_SCACHE_CACHE(cpu) ((cpu) -> cgen_cpu.scache.cache)
+
+#if WITH_SCACHE_PBB
+  /* Number of hash chains.  Must be a power of 2.  */
+  unsigned int num_hash_chains;
+#define CPU_SCACHE_NUM_HASH_CHAINS(cpu) ((cpu) -> cgen_cpu.scache.num_hash_chains)
+  /* Number of entries in each hash chain.
+     The hash table is a statically allocated NxM array where
+     N = num_hash_chains
+     M = num_hash_chain_entries.  */
+  unsigned int num_hash_chain_entries;
+#define CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES(cpu) ((cpu) -> cgen_cpu.scache.num_hash_chain_entries)
+  /* Maximum number of instructions in a chain.
+     ??? This just let's us set a static size of chain_lengths table.
+     In a simulation that handles more than just the cpu, this might also be
+     used to keep too many instructions from being executed before checking
+     for events (or some such).  */
+  unsigned int max_chain_length;
+#define CPU_SCACHE_MAX_CHAIN_LENGTH(cpu) ((cpu) -> cgen_cpu.scache.max_chain_length)
+  /* Special scache entry for (re)starting bb extraction.  */
+  SCACHE *pbb_begin;
+#define CPU_SCACHE_PBB_BEGIN(cpu) ((cpu) -> cgen_cpu.scache.pbb_begin)
+  /* Hash table into cached chains.  */
+  SCACHE_MAP *hash_table;
+#define CPU_SCACHE_HASH_TABLE(cpu) ((cpu) -> cgen_cpu.scache.hash_table)
+  /* Next free entry in cache.  */
+  SCACHE *next_free;
+#define CPU_SCACHE_NEXT_FREE(cpu) ((cpu) -> cgen_cpu.scache.next_free)
+
+  /* Address of cti-chain insn, only used by functional semantics,
+     not switch form.  */
+  SCACHE **pbb_br_npc_ptr;
+#define CPU_PBB_BR_NPC_PTR(cpu) ((cpu) -> cgen_cpu.scache.pbb_br_npc_ptr)
+  /* Target's branch address.  */
+  PCADDR pbb_br_npc;
+#define CPU_PBB_BR_NPC(cpu) ((cpu) -> cgen_cpu.scache.pbb_br_npc)
+#endif /* WITH_SCACHE_PBB */
 
 #if WITH_PROFILE_SCACHE_P
   /* Cache hits, misses.  */
   unsigned long hits, misses;
-#define CPU_SCACHE_HITS(cpu) ((cpu)->cgen_cpu.scache.hits)
-#define CPU_SCACHE_MISSES(cpu) ((cpu)->cgen_cpu.scache.misses)
+#define CPU_SCACHE_HITS(cpu) ((cpu) -> cgen_cpu.scache.hits)
+#define CPU_SCACHE_MISSES(cpu) ((cpu) -> cgen_cpu.scache.misses)
+
+#if WITH_SCACHE_PBB
+  /* Chain length counts.
+     Each element is a count of the number of chains created with that
+     length.  */
+  unsigned long *chain_lengths;
+#define CPU_SCACHE_CHAIN_LENGTHS(cpu) ((cpu) -> cgen_cpu.scache.chain_lengths)
+  /* Number of times cache was flushed due to its being full.  */
+  unsigned long full_flushes;
+#define CPU_SCACHE_FULL_FLUSHES(cpu) ((cpu) -> cgen_cpu.scache.full_flushes)
 #endif
-} CPU_SCACHE;
-
-/* Default number of cached blocks.  */
-#ifdef CONFIG_SIM_CACHE_SIZE
-#define SCACHE_DEFAULT_CACHE_SIZE CONFIG_SIM_CACHE_SIZE
-#else
-#define SCACHE_DEFAULT_CACHE_SIZE 1024
 #endif
+} CPU_SCACHE;
 
-/* Hash a PC value.  */
-/* FIXME: cpu specific */
-#define SCACHE_HASH_PC(state, pc) \
-(((pc) >> 1) & (STATE_SCACHE_SIZE (sd) - 1))
+/* Hash a PC value.
+   This is split into two parts to help with moving as much of the
+   computation out of the main loop.  */
+#define CPU_SCACHE_HASH_MASK(cpu) (CPU_SCACHE_SIZE (cpu) - 1)
+#define SCACHE_HASH_PC(pc, mask) \
+((CGEN_MIN_INSN_SIZE == 2 ? ((pc) >> 1) \
+  : CGEN_MIN_INSN_SIZE == 4 ? ((pc) >> 2) \
+  : (pc)) \
+ & (mask))
 
 /* Non-zero if cache is in use.  */
 #define USING_SCACHE_P(sd) (STATE_SCACHE_SIZE (sd) > 0)
@@ -81,15 +113,22 @@ typedef struct cpu_scache {
 /* Install the simulator cache into the simulator.  */
 MODULE_INSTALL_FN scache_install;
 
-/* Flush all cpu's caches.  */
-void scache_flush (SIM_DESC);
+/* Lookup a PC value in the scache [compilation only].  */
+extern SCACHE * scache_lookup (SIM_CPU *, PCADDR);
+/* Return a pointer to at least N buffers.  */
+extern SCACHE *scache_lookup_or_alloc (SIM_CPU *, PCADDR, int, SCACHE **);
+/* Flush all cpu's scaches.  */
+extern void scache_flush (SIM_DESC);
+/* Flush a cpu's scache.  */
+extern void scache_flush_cpu (SIM_CPU *);
 \f
-/* Profiling support.  */
+/* Scache profiling support.  */
 
 /* Print summary scache usage information.  */
-void scache_print_profile (SIM_DESC sd, int verbose);
+extern void scache_print_profile (SIM_CPU *cpu, int verbose);
 
 #if WITH_PROFILE_SCACHE_P
+
 #define PROFILE_COUNT_SCACHE_HIT(cpu) \
 do { \
   if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
@@ -100,9 +139,24 @@ do { \
   if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
     ++ CPU_SCACHE_MISSES (cpu); \
 } while (0)
+#define PROFILE_COUNT_SCACHE_CHAIN_LENGTH(cpu,length) \
+do { \
+  if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
+    ++ CPU_SCACHE_CHAIN_LENGTHS (cpu) [length]; \
+} while (0)
+#define PROFILE_COUNT_SCACHE_FULL_FLUSH(cpu) \
+do { \
+  if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
+    ++ CPU_SCACHE_FULL_FLUSHES (cpu); \
+} while (0)
+
 #else
+
 #define PROFILE_COUNT_SCACHE_HIT(cpu)
 #define PROFILE_COUNT_SCACHE_MISS(cpu)
+#define PROFILE_COUNT_SCACHE_CHAIN_LENGTH(cpu,length)
+#define PROFILE_COUNT_SCACHE_FULL_FLUSH(cpu)
+
 #endif
 
-#endif /* SCACHE_H */
+#endif /* CGEN_SCACHE_H */
index c389014..f95f837 100644 (file)
@@ -1,5 +1,5 @@
 /* Tracing support for CGEN-based simulators.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    Contributed by Cygnus Support.
 
 This file is part of GDB, the GNU debugger.
@@ -46,118 +46,136 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define SIZE_TOTAL_CYCLE_COUNT 9
 #endif
 
+#ifndef SIZE_TRACE_BUF
+#define SIZE_TRACE_BUF 256
+#endif
+
 /* Text is queued in TRACE_BUF because we want to output the insn's cycle
-   count first but that isn't known until after the insn has executed.  */
-static char trace_buf[1024];
+   count first but that isn't known until after the insn has executed.
+   This also handles the queueing of trace results, TRACE_RESULT may be
+   called multiple times for one insn.  */
+static char trace_buf[SIZE_TRACE_BUF];
 /* If NULL, output to stdout directly.  */
 static char *bufptr;
 
-/* For computing an instruction's cycle count.
-   FIXME: Need to move into cpu struct for smp case.  */
-static unsigned long last_cycle_count;
+/* Non-zero if this is the first insn in a set of parallel insns.  */
+static int first_insn_p;
+
+/* For communication between trace_insn and trace_result.  */
+static int printed_result_p;
+
+/* Insn and its extracted fields.
+   Set by trace_insn, used by trace_insn_fini.
+   ??? Move to SIM_CPU to support heterogeneous multi-cpu case.  */
+static const struct cgen_insn *current_insn;
+static CGEN_FIELDS insn_fields;
+static const struct argbuf *current_abuf;
 
 void
 trace_insn_init (SIM_CPU *cpu, int first_p)
 {
   bufptr = trace_buf;
   *bufptr = 0;
+  first_insn_p = first_p;
+
+  /* Set to NULL so trace_insn_fini can know if trace_insn was called.  */
+  current_insn = NULL;
+  current_abuf = NULL;
 }
 
 void
-trace_insn_fini (SIM_CPU *cpu, int last_p)
+trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
 {
-  if (CPU_PROFILE_FLAGS (cpu) [PROFILE_MODEL_IDX])
-    {
-      unsigned long total = PROFILE_TOTAL_CYCLE_COUNT (CPU_PROFILE_DATA (cpu));
-      trace_printf (CPU_STATE (cpu), cpu, "%-*ld %-*ld ",
-                   SIZE_CYCLE_COUNT, total - last_cycle_count,
-                   SIZE_TOTAL_CYCLE_COUNT, total);
-      last_cycle_count = total;
-    }
+  SIM_DESC sd = CPU_STATE (cpu);
 
-  trace_printf (CPU_STATE (cpu), cpu, "%s\n", trace_buf);
-}
+  /* Was insn traced?  It might not be if trace ranges are in effect.  */
+  if (current_insn == NULL)
+    return;
 
-/* For communication between trace_insn and trace_result.  */
-static int printed_result_p;
+  /* The first thing printed is current and total cycle counts.  */
 
-void
-trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
-           const struct argbuf *abuf, PCADDR pc)
-{
-  const char *filename;
-  const char *functionname;
-  unsigned int linenumber;
-  char *p, buf[256], disasm_buf[50];
-
-  if (! TRACE_P (cpu, TRACE_LINENUM_IDX))
+  if (PROFILE_MODEL_P (cpu)
+      && ARGBUF_PROFILE_P (current_abuf))
     {
-      cgen_trace_printf (cpu, "0x%.*x %-*s ",
-                        SIZE_PC, (unsigned) pc,
-                        SIZE_INSTRUCTION,
-                        CGEN_INSN_MNEMONIC (opcode));
-      printed_result_p = 0;
-      return;
-    }
+      unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu));
+      unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu));
 
-  buf[0] = 0;
-  
-  if (STATE_TEXT_SECTION (CPU_STATE (cpu))
-      && pc >= STATE_TEXT_START (CPU_STATE (cpu))
-      && pc < STATE_TEXT_END (CPU_STATE (cpu)))
-    {
-      filename = (const char *) 0;
-      functionname = (const char *) 0;
-      linenumber = 0;
-      if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)),
-                                STATE_TEXT_SECTION (CPU_STATE (cpu)),
-                                (struct symbol_cache_entry **) 0,
-                                pc - STATE_TEXT_START (CPU_STATE (cpu)),
-                                &filename, &functionname, &linenumber))
+      if (last_p)
+       {
+         trace_printf (sd, cpu, "%-*ld %-*ld ",
+                       SIZE_CYCLE_COUNT, this_insn,
+                       SIZE_TOTAL_CYCLE_COUNT, total);
+       }
+      else
        {
-         p = buf;
-         if (linenumber)
-           {
-             sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, linenumber);
-             p += strlen (p);
-           }
-         else
-           {
-             sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---");
-             p += SIZE_LINE_NUMBER+2;
-           }
-
-         if (functionname)
-           {
-             sprintf (p, "%s ", functionname);
-             p += strlen (p);
-           }
-         else if (filename)
-           {
-             char *q = (char *) strrchr (filename, '/');
-             sprintf (p, "%s ", (q) ? q+1 : filename);
-             p += strlen (p);
-           }
-
-         if (*p == ' ')
-           *p = '\0';
+         trace_printf (sd, cpu, "%-*ld %-*s ",
+                       SIZE_CYCLE_COUNT, this_insn,
+                       SIZE_TOTAL_CYCLE_COUNT, "---");
        }
     }
 
-  sim_disassemble_insn (cpu, opcode, abuf, pc, disasm_buf);
+  /* Print the disassembled insn.  */
+
+  trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu)));
 
-  cgen_trace_printf (cpu, "0x%.*x %-*.*s %-*s ",
-                    SIZE_PC, (unsigned) pc,
-                    SIZE_LOCATION, SIZE_LOCATION, buf,
-                    SIZE_INSTRUCTION,
 #if 0
-                    CGEN_INSN_NAME (opcode)
-#else
-                    disasm_buf
+  /* Print insn results.  */
+  {
+    const CGEN_OPERAND_INSTANCE *opinst = CGEN_INSN_OPERANDS (current_insn);
+
+    if (opinst)
+      {
+       int i;
+       int indices[MAX_OPERAND_INSTANCES];
+
+       /* Fetch the operands used by the insn.  */
+       /* FIXME: Add fn ptr to CGEN_OPCODE_DESC.  */
+       CGEN_SYM (get_insn_operands) (STATE_OPCODE_TABLE (sd), current_insn,
+                                     0, CGEN_FIELDS_BITSIZE (&insn_fields),
+                                     indices);
+
+       for (i = 0;
+            CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END;
+            ++i, ++opinst)
+         {
+           if (CGEN_OPERAND_INSTANCE_TYPE (opinst) == CGEN_OPERAND_INSTANCE_OUTPUT)
+             trace_result (cpu, current_insn, opinst, indices[i]);
+         }
+      }
+  }
 #endif
-               );
+
+  /* Print anything else requested.  */
+
+  if (*trace_buf)
+    trace_printf (sd, cpu, " %s\n", trace_buf);
+  else
+    trace_printf (sd, cpu, "\n");
+}
+
+void
+trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
+           const struct argbuf *abuf, PCADDR pc)
+{
+  char disasm_buf[50];
 
   printed_result_p = 0;
+  current_insn = opcode;
+  current_abuf = abuf;
+
+  if (CGEN_INSN_VIRTUAL_P (opcode))
+    {
+      trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, (address_word) 0, 0,
+                   NULL, 0, CGEN_INSN_NAME (opcode));
+      return;
+    }
+
+  sim_disassemble_insn (cpu, opcode, abuf, pc, disasm_buf, &insn_fields);
+  trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
+               NULL, 0,
+               "%s%-*s",
+               first_insn_p ? " " : "|",
+               SIZE_INSTRUCTION, disasm_buf);
 }
 
 void
@@ -169,7 +187,8 @@ trace_extract (SIM_CPU *cpu, PCADDR pc, char *name, ...)
 
   va_start (args, name);
 
-  trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*x: %s ", SIZE_PC, pc, name);
+  trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ",
+               SIZE_PC, pc, name);
 
   do {
     int type,ival;
@@ -206,6 +225,7 @@ trace_result (SIM_CPU *cpu, char *name, int type, ...)
   va_start (args, type);
   if (printed_result_p)
     cgen_trace_printf (cpu, ", ");
+
   switch (type)
     {
     case 'x' :
@@ -222,6 +242,7 @@ trace_result (SIM_CPU *cpu, char *name, int type, ...)
        break;
       }
     }
+
   printed_result_p = 1;
   va_end (args);
 }
@@ -248,6 +269,9 @@ cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...)
     {
       vsprintf (bufptr, fmt, args);
       bufptr += strlen (bufptr);
+      /* ??? Need version of SIM_ASSERT that is always enabled.  */
+      if (bufptr - trace_buf > SIZE_TRACE_BUF)
+       abort ();
     }
 
   va_end (args);
index 52e6004..3a65b0b 100644 (file)
@@ -234,7 +234,7 @@ cat << EOF
 #define SEM_IN_SWITCH
 
 #define WANT_CPU
-#define WANT_CPU_${CPU}
+#define WANT_CPU_@CPU@
 
 #include "sim-main.h"
 #include "bfd.h"
@@ -244,6 +244,62 @@ cat << EOF
 #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)
+{
+  SEM_SET_CODE (abuf, idesc, fast_p);
+  ARGBUF_ADDR (abuf) = pc;
+  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
@@ -259,12 +315,13 @@ 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);
   SCACHE cache[MAX_LIW_INSNS];
   SCACHE *sc = &cache[0];
+  IADDR pc;
 
 EOF
 
@@ -300,6 +357,20 @@ fi
 
 cat << EOF
 
+#if WITH_SEM_SWITCH_FULL && defined (__GNUC__)
+  {
+    if (! CPU_IDESC_SEM_INIT_P (current_cpu))
+      {
+/* ??? 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
+
+  pc = GET_H_PC ();
+
   do
     {
 /* begin full-{extract,exec}-simple */
@@ -333,7 +404,7 @@ if [ x$fast = xyes ] ; then
 
 #define FAST_P 1
 
-FIXME
+FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
 
 #undef FAST_P
 
@@ -352,7 +423,7 @@ if [ x$scache = xyes ] ; 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.  */
@@ -389,7 +460,7 @@ cat << EOF
 #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);
@@ -436,7 +507,7 @@ cat << EOF
     {
       SCACHE *sc;
 
-      sc = ${cpu}_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
+      sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
 
 /* begin full-exec-scache */
 EOF
@@ -468,7 +539,7 @@ 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);
@@ -527,7 +598,7 @@ cat << EOF
     {
       SCACHE *sc;
 
-      sc = ${cpu}_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
+      sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
 
 /* begin fast-exec-scache */
 EOF
@@ -565,15 +636,15 @@ if [ x$pbb = xyes ] ; then
     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;
@@ -585,9 +656,10 @@ ${cpu}_pbb_begin (SIM_CPU *current_cpu, int FAST_P)
   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.
@@ -653,18 +725,18 @@ cat << EOF
        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;
       }
@@ -684,7 +756,7 @@ cat << EOF
 /* 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);
 
@@ -693,7 +765,14 @@ ${cpu}_pbb_chain (SIM_CPU *current_cpu, SEM_ARG 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.  */
@@ -715,7 +794,7 @@ ${cpu}_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg)
    NEW_VPC_PTR != SEM_BRANCH_UNTAKEN.  */
 
 INLINE SEM_PC
-${cpu}_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
+@cpu@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
                     SEM_PC *new_vpc_ptr, PCADDR new_pc)
 {
   ARGBUF *abuf;
@@ -723,7 +802,14 @@ ${cpu}_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
   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
@@ -763,7 +849,7 @@ ${cpu}_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg,
    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);
@@ -772,7 +858,8 @@ ${cpu}_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
   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.  */
 
@@ -785,18 +872,23 @@ ${cpu}_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
          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_INIT (current_cpu, cur_abuf, first_p);
   TRACE_INSN (current_cpu, cur_idesc->opcode, cur_abuf, cur_abuf->addr);
 }
 
@@ -805,28 +897,30 @@ ${cpu}_pbb_before (SIM_CPU *current_cpu, SCACHE *sc)
    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);
@@ -871,8 +965,8 @@ cat << EOF
       /* 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;
     }
@@ -882,7 +976,7 @@ cat << EOF
      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
     {
@@ -912,7 +1006,7 @@ 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);
@@ -957,8 +1051,8 @@ cat << EOF
       /* 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;
     }
@@ -968,7 +1062,7 @@ cat << EOF
      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
     {
@@ -990,6 +1084,7 @@ fi # -fast
 
 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
diff --git a/sim/common/sim-model.c b/sim/common/sim-model.c
new file mode 100644 (file)
index 0000000..47be996
--- /dev/null
@@ -0,0 +1,192 @@
+/* Model support.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.
+
+This file is part of GDB, the GNU debugger.
+
+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
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sim-main.h"
+#include "libiberty.h"
+#include "sim-options.h"
+#include "sim-io.h"
+#include "sim-assert.h"
+#include "bfd.h"
+
+static void model_set (SIM_DESC, sim_cpu *, const MODEL *);
+
+static DECLARE_OPTION_HANDLER (model_option_handler);
+
+static MODULE_INIT_FN sim_model_init;
+
+#define OPTION_MODEL (OPTION_START + 0)
+
+static const OPTION model_options[] = {
+  { {"model", required_argument, NULL, OPTION_MODEL},
+      '\0', "MODEL", "Specify model to simulate",
+      model_option_handler },
+  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
+};
+
+static SIM_RC
+model_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
+                     char *arg, int is_command)
+{
+  switch (opt)
+    {
+    case OPTION_MODEL :
+      {
+       const MODEL *model = sim_model_lookup (arg);
+       if (! model)
+         {
+           sim_io_eprintf (sd, "unknown model `%s'", arg);
+           return SIM_RC_FAIL;
+         }
+       sim_model_set (sd, cpu, model);
+       break;
+      }
+    }
+
+  return SIM_RC_OK;
+}
+
+SIM_RC
+sim_model_install (SIM_DESC sd)
+{
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  sim_add_option_table (sd, NULL, model_options);
+  sim_module_add_init_fn (sd, sim_model_init);
+
+  return SIM_RC_OK;
+}
+
+/* Subroutine of sim_model_set to set the model for one cpu.  */
+
+static void
+model_set (SIM_DESC sd, sim_cpu *cpu, const MODEL *model)
+{
+  CPU_MACH (cpu) = MODEL_MACH (model);
+  CPU_MODEL (cpu) = model;
+  (* MACH_INIT_CPU (MODEL_MACH (model))) (cpu);
+  (* MODEL_INIT (model)) (cpu);
+}
+
+/* Set the current model of CPU to MODEL.
+   If CPU is NULL, all cpus are set to MODEL.  */
+
+void
+sim_model_set (SIM_DESC sd, sim_cpu *cpu, const MODEL *model)
+{
+  if (! cpu)
+    {
+      int c;
+
+      for (c = 0; c < MAX_NR_PROCESSORS; ++c)
+       if (STATE_CPU (sd, c))
+         model_set (sd, STATE_CPU (sd, c), model);
+    }
+  else
+    {
+      model_set (sd, cpu, model);
+    }
+}
+
+/* Look up model named NAME.
+   Result is pointer to MODEL entry or NULL if not found.  */
+
+const MODEL *
+sim_model_lookup (const char *name)
+{
+  const MACH **machp;
+  const MODEL *model;
+
+  for (machp = & sim_machs[0]; *machp != NULL; ++machp)
+    {
+      for (model = MACH_MODELS (*machp); MODEL_NAME (model) != NULL; ++model)
+       {
+         if (strcmp (MODEL_NAME (model), name) == 0)
+           return model;
+       }
+    }
+  return NULL;
+}
+
+/* Look up machine named NAME.
+   Result is pointer to MACH entry or NULL if not found.  */
+
+const MACH *
+sim_mach_lookup (const char *name)
+{
+  const MACH **machp;
+
+  for (machp = & sim_machs[0]; *machp != NULL; ++machp)
+    {
+      if (strcmp (MACH_NAME (*machp), name) == 0)
+       return *machp;
+    }
+  return NULL;
+}
+
+/* Initialize model support.  */
+
+static SIM_RC
+sim_model_init (SIM_DESC sd)
+{
+  SIM_CPU *cpu;
+
+  /* If both cpu model and state architecture are set, ensure they're
+     compatible.  If only one is set, set the other.  If neither are set,
+     use the default model.  STATE_ARCHITECTURE is the bfd_arch_info data
+     for the selected "mach" (bfd terminology).  */
+
+  /* Only check cpu 0.  STATE_ARCHITECTURE is for that one only.  */
+  /* ??? At present this only supports homogeneous multiprocessors.  */
+  cpu = STATE_CPU (sd, 0);
+
+  if (! STATE_ARCHITECTURE (sd)
+      && ! CPU_MACH (cpu))
+    {
+      /* Set the default model.  */
+      const MODEL *model = sim_model_lookup (WITH_DEFAULT_MODEL);
+      sim_model_set (sd, NULL, model);
+    }
+
+  if (STATE_ARCHITECTURE (sd)
+      && CPU_MACH (cpu))
+    {
+      if (strcmp (STATE_ARCHITECTURE (sd)->printable_name,
+                 MACH_BFD_NAME (CPU_MACH (cpu))) != 0)
+       {
+         sim_io_eprintf (sd, "invalid model `%s' for `%s'\n",
+                         MODEL_NAME (CPU_MODEL (cpu)),
+                         STATE_ARCHITECTURE (sd)->printable_name);
+         return SIM_RC_FAIL;
+       }
+    }
+  else if (STATE_ARCHITECTURE (sd))
+    {
+      /* Use the default model for the selected machine.
+        The default model is the first one in the list.  */
+      const MACH *mach = sim_mach_lookup (STATE_ARCHITECTURE (sd)->printable_name);
+      sim_model_set (sd, NULL, MACH_MODELS (mach));
+    }
+  else
+    {
+      STATE_ARCHITECTURE (sd) = bfd_scan_arch (MACH_BFD_NAME (CPU_MACH (cpu)));
+    }
+
+  return SIM_RC_OK;
+}
diff --git a/sim/common/sim-model.h b/sim/common/sim-model.h
new file mode 100644 (file)
index 0000000..287e4bb
--- /dev/null
@@ -0,0 +1,132 @@
+/* Architecture, machine, and model support.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.
+
+This file is part of GDB, the GNU debugger.
+
+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
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Nomenclature:
+   architecture = one of sparc, mips, sh, etc.
+   in the sparc architecture, mach = one of v6, v7, v8, sparclite, etc.
+   in the v8 mach, model = one of supersparc, etc.
+*/
+
+/* This file is intended to be included by sim-basics.h.  */
+
+#ifndef SIM_MODEL_H
+#define SIM_MODEL_H
+
+/* Function unit and instruction timing support.
+   ??? This is obviously insufficiently general.
+   It's useful but it needs elaborating upon.  */
+
+typedef struct {
+  unsigned char name; /* actually a UNIT_TYPE enum */
+  unsigned char issue;
+  unsigned char done;
+} UNIT;
+
+#ifndef MAX_UNITS
+#define MAX_UNITS 1
+#endif
+
+typedef int (MODEL_FN) (sim_cpu *, void *);
+
+typedef struct {
+  /* This is an integer that identifies this insn.
+     How this works is up to the target.  */
+  int num;
+
+  /* Function to handle insn-specific profiling.  */
+  MODEL_FN *model_fn;
+
+  /* Array of function units used by this insn.  */
+  UNIT units[MAX_UNITS];
+} INSN_TIMING;
+
+/* Struct to describe various implementation properties of a cpu.
+   When multiple cpu variants are supported, the sizes of some structs
+   can vary.  */
+
+typedef struct {
+  /* The size of the SIM_CPU struct.  */
+  int sim_cpu_size;
+#define IMP_PROPS_SIM_CPU_SIZE(cpu_props) ((cpu_props)->sim_cpu_size)
+  /* An SCACHE element can vary in size, depending on the selected cpu.
+     This is zero if the SCACHE isn't in use for this variant.  */
+  int scache_elm_size;
+#define IMP_PROPS_SCACHE_ELM_SIZE(cpu_props) ((cpu_props)->scache_elm_size)
+} MACH_IMP_PROPERTIES;
+
+/* A machine variant.  */
+
+typedef struct {
+  const char *name;
+#define MACH_NAME(m) ((m)->name)
+  /* This is the argument to bfd_scan_arch.  */
+  const char *bfd_name;
+#define MACH_BFD_NAME(m) ((m)->bfd_name)
+  int word_bitsize;
+#define MACH_WORD_BITSIZE(m) ((m)->word_bitsize)
+  int addr_bitsize;
+#define MACH_ADDR_BITSIZE(m) ((m)->addr_bitsize)
+
+  /* Pointer to null-entry terminated table of models of this mach.
+     The default is the first one.  */
+  const struct model *models;
+#define MACH_MODELS(m) ((m)->models)
+
+  /* Pointer to the implementation properties of this mach.  */
+  const MACH_IMP_PROPERTIES *imp_props;
+#define MACH_IMP_PROPS(m) ((m)->imp_props)
+
+  /* Called by sim_model_set when the model of a cpu is set.  */
+  void (* init_cpu) (sim_cpu *);
+#define MACH_INIT_CPU(m) ((m)->init_cpu)
+} MACH;
+
+/* A model (implementation) of a machine.  */
+
+typedef struct model {
+  const char *name;
+#define MODEL_NAME(m) ((m)->name)
+  const MACH *mach;
+#define MODEL_MACH(m) ((m)->mach)
+  /* An enum that distinguished the model.  */
+  int num;
+#define MODEL_NUM(m) ((m)->num)
+  /* Pointer to timing table for this model.  */
+  const INSN_TIMING *timing;
+#define MODEL_TIMING(m) ((m)->timing)
+  void (* init) (sim_cpu *);
+#define MODEL_INIT(m) ((m)->init)
+} MODEL;
+
+/* Tables of supported machines.  */
+/* ??? In a simulator of multiple architectures, will need multiple copies of
+   this.  Have an `archs' array that contains a pointer to the machs array
+   for each (which in turn has a pointer to the models array for each).  */
+extern const MACH *sim_machs[];
+
+/* Model module handlers.  */
+extern MODULE_INSTALL_FN sim_model_install;
+
+/* Support routines.  */
+extern void sim_model_set (SIM_DESC sd, sim_cpu *cpu, const MODEL *model);
+extern const MODEL * sim_model_lookup (const char *name);
+extern const MACH * sim_mach_lookup (const char *name);
+
+#endif /* SIM_MODEL_H */
index 970e725..ebdd64e 100644 (file)
@@ -23,11 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "sim-options.h"
 #include "sim-assert.h"
 
-/* start-sanitize-am30 */
 #if WITH_HW
 #include "sim-hw.h"
 #endif
-/* end-sanitize-am30 */
 
 #include "libiberty.h"
 
@@ -52,20 +50,18 @@ static MODULE_INSTALL_FN * const modules[] = {
 #if WITH_WATCHPOINTS
   sim_watchpoint_install,
 #endif
-#if WITH_SCACHE
-  scache_install,
-#endif
 #ifdef SIM_HAVE_MODEL
   sim_model_install,
 #endif
+#if WITH_SCACHE
+  scache_install,
+#endif
 #ifdef SIM_HAVE_BREAKPOINTS
   sim_break_install,
 #endif
-  /* start-sanitize-am30 */
 #if WITH_HW
   sim_hw_install,
 #endif
-  /* end-sanitize-am30 */
   /* Configured in [simulator specific] additional modules.  */
 #ifdef MODULE_LIST
   MODULE_LIST
@@ -116,9 +112,6 @@ sim_post_argv_init (SIM_DESC sd)
   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
   SIM_ASSERT (STATE_MODULES (sd) != NULL);
 
-  if (sim_module_init (sd) != SIM_RC_OK)
-    return SIM_RC_FAIL;
-
   /* Set the cpu->state backlinks for each cpu.  */
   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
     {
@@ -126,6 +119,9 @@ sim_post_argv_init (SIM_DESC sd)
       CPU_INDEX (STATE_CPU (sd, i)) = i;
     }
 
+  if (sim_module_init (sd) != SIM_RC_OK)
+    return SIM_RC_FAIL;
+
   return SIM_RC_OK;
 }
 \f