(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.
+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.
-/* Simulator header for the cgen engine.
+/* Engine header for Cpu tools GENerated simulators.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
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.
/* 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
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) \
/* 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)
/* 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)
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)
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. */
#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 */
-/* 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.
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)
/* 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]) \
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 */
/* 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.
#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
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;
va_start (args, type);
if (printed_result_p)
cgen_trace_printf (cpu, ", ");
+
switch (type)
{
case 'x' :
break;
}
}
+
printed_result_p = 1;
va_end (args);
}
{
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);
#define SEM_IN_SWITCH
#define WANT_CPU
-#define WANT_CPU_${CPU}
+#define WANT_CPU_@CPU@
#include "sim-main.h"
#include "bfd.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)
+{
+ 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
#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
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 */
#define FAST_P 1
-FIXME
+FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh."
#undef FAST_P
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. */
#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);
{
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
#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);
{
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
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;
}
/* 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. */
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;
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
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_INIT (current_cpu, cur_abuf, first_p);
TRACE_INSN (current_cpu, cur_idesc->opcode, cur_abuf, cur_abuf->addr);
}
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);
/* 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);
/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
#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"
#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
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)
{
CPU_INDEX (STATE_CPU (sd, i)) = i;
}
+ if (sim_module_init (sd) != SIM_RC_OK)
+ return SIM_RC_FAIL;
+
return SIM_RC_OK;
}
\f