From: Doug Evans Date: Wed, 6 Jan 1999 00:42:34 +0000 (+0000) Subject: * Make-common.in (CGEN_INCLUDE_DEPS): Add cgen-defs.h, cgen-engine.h. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f5cd4d758c52b6746046da1fafd0e70b41022178;p=binutils-gdb.git * 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. --- diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog index 98091899259..b8b68ab54b1 100644 --- a/sim/common/ChangeLog +++ b/sim/common/ChangeLog @@ -1,3 +1,31 @@ +1999-01-05 Doug Evans + + * 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 * dv-sockser.c (DEFAULT_TIMEOUT): Increase to 1 ms. diff --git a/sim/common/cgen-engine.h b/sim/common/cgen-engine.h index 91b7766a0a4..5c64e6bcf73 100644 --- a/sim/common/cgen-engine.h +++ b/sim/common/cgen-engine.h @@ -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 + +/* 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) - + #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 */ + +/* 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 */ diff --git a/sim/common/cgen-scache.h b/sim/common/cgen-scache.h index 9cb2a5fe44e..e4228591584 100644 --- a/sim/common/cgen-scache.h +++ b/sim/common/cgen-scache.h @@ -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 *); -/* 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 */ diff --git a/sim/common/cgen-trace.c b/sim/common/cgen-trace.c index c38901467b4..f95f837e8b2 100644 --- a/sim/common/cgen-trace.c +++ b/sim/common/cgen-trace.c @@ -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); diff --git a/sim/common/genmloop.sh b/sim/common/genmloop.sh index 52e600401e6..3a65b0bb5e8 100644 --- a/sim/common/genmloop.sh +++ b/sim/common/genmloop.sh @@ -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 index 00000000000..47be9969245 --- /dev/null +++ b/sim/common/sim-model.c @@ -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 index 00000000000..287e4bb4f65 --- /dev/null +++ b/sim/common/sim-model.h @@ -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 */ diff --git a/sim/common/sim-module.c b/sim/common/sim-module.c index 970e7258233..ebdd64e44ae 100644 --- a/sim/common/sim-module.c +++ b/sim/common/sim-module.c @@ -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; }