* 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.
This commit is contained in:
Doug Evans 1999-01-06 00:42:34 +00:00
parent 5730d39d2c
commit f5cd4d758c
8 changed files with 810 additions and 224 deletions

View 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.

View 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
/* 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 */

View 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;
#ifndef WITH_SCACHE
#define WITH_SCACHE 0
#endif
#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
#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
/* 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 */

View 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])
SIM_DESC sd = CPU_STATE (cpu);
/* Was insn traced? It might not be if trace ranges are in effect. */
if (current_insn == NULL)
return;
/* The first thing printed is current and total cycle counts. */
if (PROFILE_MODEL_P (cpu)
&& ARGBUF_PROFILE_P (current_abuf))
{
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;
unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu));
unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu));
if (last_p)
{
trace_printf (sd, cpu, "%-*ld %-*ld ",
SIZE_CYCLE_COUNT, this_insn,
SIZE_TOTAL_CYCLE_COUNT, total);
}
else
{
trace_printf (sd, cpu, "%-*ld %-*s ",
SIZE_CYCLE_COUNT, this_insn,
SIZE_TOTAL_CYCLE_COUNT, "---");
}
}
trace_printf (CPU_STATE (cpu), cpu, "%s\n", trace_buf);
}
/* Print the disassembled insn. */
/* For communication between trace_insn and trace_result. */
static int printed_result_p;
trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu)));
#if 0
/* 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)
{
const char *filename;
const char *functionname;
unsigned int linenumber;
char *p, buf[256], disasm_buf[50];
char disasm_buf[50];
if (! TRACE_P (cpu, TRACE_LINENUM_IDX))
printed_result_p = 0;
current_insn = opcode;
current_abuf = abuf;
if (CGEN_INSN_VIRTUAL_P (opcode))
{
cgen_trace_printf (cpu, "0x%.*x %-*s ",
SIZE_PC, (unsigned) pc,
SIZE_INSTRUCTION,
CGEN_INSN_MNEMONIC (opcode));
printed_result_p = 0;
trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, (address_word) 0, 0,
NULL, 0, CGEN_INSN_NAME (opcode));
return;
}
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))
{
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';
}
}
sim_disassemble_insn (cpu, opcode, abuf, pc, disasm_buf);
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
#endif
);
printed_result_p = 0;
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);

View 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

192
sim/common/sim-model.c Normal file
View file

@ -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;
}

132
sim/common/sim-model.h Normal file
View file

@ -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 */

View 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;
}