sparc cgen port

This commit is contained in:
Doug Evans
1999-02-02 19:38:43 +00:00
parent 27a9a44af7
commit cd6245ce70
18 changed files with 6603 additions and 0 deletions

86
sim/sparc/.Sanitize Normal file
View File

@ -0,0 +1,86 @@
# Sanitize.in for sim/sparc
# Each directory to survive it's way into a release will need a file
# like this one called "./.Sanitize". All keyword lines must exist,
# and must exist in the order specified by this file. Each directory
# in the tree will be processed, top down, in the following order.
# Hash started lines like this one are comments and will be deleted
# before anything else is done. Blank lines will also be squashed
# out.
# The lines between the "Do-first:" line and the "Things-to-keep:"
# line are executed as a /bin/sh shell script before anything else is
# done in this
Do-first:
# All files listed between the "Things-to-keep:" line and the
# "Files-to-sed:" line will be kept. All other files will be removed.
# Directories listed in this section will have their own Sanitize
# called. Directories not listed will be removed in their entirety
# with rm -rf.
Things-to-keep:
ChangeLog
Makefile.in
acconfig.h
arch.c
arch.h
config.in
configure
configure.in
cpu32.c
cpu32.h
cpuall.h
decode32.c
decode32.h
dev32.c
dev32.h
mloop32.in
model32.c
regs32.h
sem32.c
sim-if.c
sim-main.h
sparc-sim.h
sparc.c
sparc32.c
tconfig.in
trap32.c
trap32.h
Things-to-lose:
Do-last:
cygnus_files="ChangeLog Makefile.in"
if ( echo $* | grep keep\-cygnus > /dev/null ) ; then
for i in $cygnus_files ; do
if test ! -d $i && (grep sanitize-cygnus $i > /dev/null) ; then
if [ -n "${verbose}" ] ; then
echo Keeping cygnus stuff in $i
fi
fi
done
else
for i in $cygnus_files ; do
if test ! -d $i && (grep sanitize-cygnus $i > /dev/null) ; then
if [ -n "${verbose}" ] ; then
echo Removing traces of \"cygnus\" from $i...
fi
cp $i new
sed '/start\-sanitize\-cygnus/,/end-\sanitize\-cygnus/d' < $i > new
if [ -n "${safe}" -a ! -f .Recover/$i ] ; then
if [ -n "${verbose}" ] ; then
echo Caching $i in .Recover...
fi
mv $i .Recover
fi
mv new $i
fi
done
fi
# End of file.

135
sim/sparc/Makefile.in Normal file
View File

@ -0,0 +1,135 @@
# Makefile template for Configure for the sparc simulator
# Copyright (C) 1999 Cygnus Solutions.
## COMMON_PRE_CONFIG_FRAG
SPARC32_OBJS = sparc32.o trap32.o dev32.o cpu32.o decode32.o model32.o mloop32.o sem32.o
SPARC64_OBJS = sparc64.o trap64.o cpu64.o decode64.o model64.o mloop64.o sem64.o
SIM_OBJS = \
$(SIM_NEW_COMMON_OBJS) \
sim-cpu.o \
sim-hload.o \
sim-hrw.o \
sim-model.o \
sim-reg.o \
cgen-utils.o cgen-trace.o cgen-scache.o \
cgen-run.o sim-reason.o sim-engine.o sim-stop.o \
sim-if.o sparc.o arch.o \
$(SPARC32_OBJS)
# Extra headers included by sim-main.h.
# This plus sim_main_headers is used by Make-common.in for files in common.
SIM_EXTRA_DEPS = \
$(CGEN_INCLUDE_DEPS) \
arch.h cpuall.h cpu-opc.h
# sparc-sim.h kept out for now (too much unnecessary recompilation)
SIM_EXTRA_CFLAGS =
SIM_RUN_OBJS = nrun.o
SIM_EXTRA_CLEAN = sparc-clean
# This selects the sparc newlib/libgloss syscall definitions.
NL_TARGET = -DNL_TARGET_sparc
## COMMON_POST_CONFIG_FRAG
arch = sparc
sim-if.o: sim-if.c $(SIM_MAIN_DEPS) $(srcdir)/../common/sim-core.h dev32.h
sparc.o: sparc.c $(SIM_MAIN_DEPS) \
$(srcdir)/../common/cgen-mem.h \
$(srcdir)/../common/cgen-ops.h
arch.o: arch.c $(SIM_MAIN_DEPS)
# sparc32 objs
SPARC32_INCLUDE_DEPS = \
$(CGEN_MAIN_CPU_DEPS) \
cpu32.h decode32.h eng32.h \
regs32.h trap32.h
sparc32.o: sparc32.c $(SPARC32_INCLUDE_DEPS)
trap32.o: trap32.c $(SPARC32_INCLUDE_DEPS)
dev32.o: dev32.c $(SPARC32_INCLUDE_DEPS) dev32.h
# FIXME: Use of `mono' is wip.
# FIXME: Add -fast when switching from -simple to -pbb.
# FIXME: Add -switch sem32-switch.c at same time.
mloop32.c eng32.h: stamp-mloop32
stamp-mloop32: $(srcdir)/../common/genmloop.sh mloop32.in Makefile
$(SHELL) $(srccom)/genmloop.sh \
-mono -simple \
-cpu sparc32 -infile $(srcdir)/mloop32.in
$(SHELL) $(srcroot)/move-if-change eng.hin eng32.h
$(SHELL) $(srcroot)/move-if-change mloop.cin mloop32.c
touch stamp-mloop32
mloop32.o: mloop32.c sem32-switch.c $(SPARC32_INCLUDE_DEPS)
cpu32.o: cpu32.c $(SPARC32_INCLUDE_DEPS)
decode32.o: decode32.c $(SPARC32_INCLUDE_DEPS)
model32.o: model32.c $(SPARC32_INCLUDE_DEPS)
sem32.o: sem32.c $(SPARC32_INCLUDE_DEPS)
# sparc64 objs
SPARC64_INCLUDE_DEPS = \
$(CGEN_MAIN_CPU_DEPS) \
cpu64.h decode64.h eng64.h \
regs64.h trap64.h
sparc64.o: sparc64.c $(SPARC64_INCLUDE_DEPS)
trap64.o: trap64.c $(SPARC64_INCLUDE_DEPS)
# FIXME: Use of `mono' is wip.
mloop64.c eng64.h: stamp-mloop64
stamp-mloop64: $(srcdir)/../common/genmloop.sh mloop64.in Makefile
$(SHELL) $(srccom)/genmloop.sh \
-mono -fast -pbb -switch sem64-switch.c \
-cpu sparc64 -infile $(srcdir)/mloop64.in
$(SHELL) $(srcroot)/move-if-change eng.hin eng64.h
$(SHELL) $(srcroot)/move-if-change mloop.cin mloop64.c
touch stamp-mloop64
mloop64.o: mloop64.c sem64-switch.c $(SPARC64_INCLUDE_DEPS)
cpu64.o: cpu64.c $(SPARC64_INCLUDE_DEPS)
decode64.o: decode64.c $(SPARC64_INCLUDE_DEPS)
model64.o: model64.c $(SPARC64_INCLUDE_DEPS)
sparc-clean:
rm -f mloop32.c eng32.h mloop64.c eng64.h stamp-mloop32 stamp-mloop64
rm -f stamp-arch stamp-cpu32 stamp-cpu64
rm -f tmp-*
# cgen support
stamp-arch: $(CGEN_MAIN_SCM) $(CGEN_ARCH_SCM) \
$(srccgen)/sparc.cpu $(srccgen)/sparccom.cpu \
$(srccgen)/sparc32.cpu $(srccgen)/sparc64.cpu
$(MAKE) cgen-arch $(CGEN_FLAGS_TO_PASS) mach=sparc-v8,sparclite
touch stamp-arch
arch.h arch.c cpuall.h: $(CGEN_MAIN) stamp-arch
@true
# Add with-scache to FLAGS when switching to -pbb.
stamp-cpu32: $(CGEN_MAIN_SCM) $(CGEN_CPU_SCM) $(CGEN_DECODE_SCM) \
$(srccgen)/sparc.cpu $(srccgen)/sparccom.cpu $(srccgen)/sparc32.cpu
$(MAKE) cgen-cpu-decode $(CGEN_FLAGS_TO_PASS) \
cpu=sparc32 mach=sparc-v8,sparclite SUFFIX=32 \
FLAGS="with-profile fn" \
EXTRAFILES="$(CGEN_CPU_SEM)"
touch stamp-cpu32
cpu32.h decode32.h decode32.c model32.c sem32.c sem32-switch.c: $(CGEN_MAINT) stamp-cpu32
@true
# Add with-scache to FLAGS when switching to -pbb.
stamp-cpu64: $(CGEN_MAIN_SCM) $(CGEN_CPU_SCM) $(CGEN_DECODE_SCM) \
$(srccgen)/sparc.cpu $(srccgen)/sparccom.cpu $(srccgen)/sparc64.cpu
$(MAKE) cgen-cpu-decode $(CGEN_FLAGS_TO_PASS) \
cpu=sparc64 mach=sparc-v9,sparc-v9a SUFFIX=64 \
FLAGS="with-profile fn" \
EXTRAFILES="$(CGEN_CPU_SEM)"
touch stamp-cpu64
cpu64.h decode64.h decode64.c model64.c sem64.c sem64-switch.c: $(CGEN_MAINT) stamp-cpu64
@true

15
sim/sparc/acconfig.h Normal file
View File

@ -0,0 +1,15 @@
/* Define to 1 if NLS is requested. */
#undef ENABLE_NLS
/* Define as 1 if you have catgets and don't want to use GNU gettext. */
#undef HAVE_CATGETS
/* Define as 1 if you have gettext and don't want to use GNU gettext. */
#undef HAVE_GETTEXT
/* Define as 1 if you have the stpcpy function. */
#undef HAVE_STPCPY
/* Define if your locale.h file contains LC_MESSAGES. */
#undef HAVE_LC_MESSAGES

49
sim/sparc/config.in Normal file
View File

@ -0,0 +1,49 @@
/* config.in. Generated automatically from configure.in by autoheader. */
/* Define if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if you have the <alloca.h> header file. */
#undef HAVE_ALLOCA_H
/* Define if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define if you have the <sys/time.h> header file.
This is needed by sys/resource.h. */
#undef HAVE_SYS_TIME_H
/* Define if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define if you have the getrusage function. */
#undef HAVE_GETRUSAGE
/* Define if you have the time function. */
#undef HAVE_TIME
/* Define as the return type of signal handlers (int or void). */
#undef RETSIGTYPE
/* Define if your processor stores words with the most significant
byte first (like Motorola and SPARC, unlike Intel and VAX). */
#undef WORDS_BIGENDIAN
/* Change autoconf's value into ours. */
#ifdef WORDS_BIGENDIAN
#define HOST_BIG_ENDIAN 1
#else
#define HOST_BIG_ENDIAN 0
#endif
/* Defined if --enable-sim-cache provided. */
#undef CONFIG_SIM_CACHE_SIZE

4255
sim/sparc/configure vendored Executable file

File diff suppressed because it is too large Load Diff

21
sim/sparc/configure.in Normal file
View File

@ -0,0 +1,21 @@
dnl Process this file with autoconf to produce a configure script.
sinclude(../common/aclocal.m4)
AC_PREREQ(2.5)dnl
AC_INIT(Makefile.in)
SIM_AC_COMMON
sim_link_files="${sim_link_files} sparc-sim.h ../../opcodes/sprc-opc.h"
sim_link_links="${sim_link_links} cpu-sim.h cpu-opc.h"
SIM_AC_OPTION_ENDIAN(BIG_ENDIAN)
SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT)
SIM_AC_OPTION_HOSTENDIAN
SIM_AC_OPTION_WARNINGS
dnl SIM_AC_OPTION_SCACHE(16384)
SIM_AC_OPTION_DEFAULT_MODEL(sparc32-def)
SIM_AC_OPTION_ENVIRONMENT
SIM_AC_OPTION_INLINE()
SIM_AC_OPTION_CGEN_MAINT()
SIM_AC_OUTPUT

98
sim/sparc/dev32.c Normal file
View File

@ -0,0 +1,98 @@
/* sparc device support
Copyright (C) 1999 Cygnus Solutions. */
#include "sim-main.h"
#include "dev32.h"
#ifdef HAVE_DV_SOCKSER
#include "dv-sockser.h"
#endif
/* ??? At present this is to match erc32 so outbyte works. */
device sparc_devices;
int
device_io_read_buffer (device *me, void *source, int space,
address_word addr, unsigned nr_bytes,
SIM_CPU *cpu, sim_cia cia)
{
SIM_DESC sd = CPU_STATE (cpu);
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
return nr_bytes;
#ifdef HAVE_DV_SOCKSER
if (addr == UART_INCHAR_ADDR)
{
int c = dv_sockser_read (sd);
if (c == -1)
return 0;
*(char *) source = c;
return 1;
}
if (addr == UART_STATUS_ADDR)
{
int status = dv_sockser_status (sd);
unsigned char *p = source;
p[0] = 0;
p[1] = (((status & DV_SOCKSER_INPUT_EMPTY)
#ifdef UART_INPUT_READY0
? UART_INPUT_READY : 0)
#else
? 0 : UART_INPUT_READY)
#endif
+ ((status & DV_SOCKSER_OUTPUT_EMPTY) ? UART_OUTPUT_READY : 0));
return 2;
}
#endif
/* erc32 compatibility */
if (addr == RXSTAT)
{
int Ucontrol = 0;
unsigned char *p = source;
Ucontrol |= 1;
Ucontrol |= 0x00060006;
SETTSI (p, Ucontrol);
}
return nr_bytes;
}
int
device_io_write_buffer (device *me, const void *source, int space,
address_word addr, unsigned nr_bytes,
SIM_CPU *cpu, sim_cia cia)
{
SIM_DESC sd = CPU_STATE (cpu);
#if 0 && WITH_SCACHE
if (addr == MCCR_ADDR)
{
if ((*(const char *) source & MCCR_CP) != 0)
scache_flush (sd);
return nr_bytes;
}
#endif
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
return nr_bytes;
#ifdef HAVE_DV_SOCKSER
if (addr == UART_OUTCHAR_ADDR)
{
int rc = dv_sockser_write (sd, *(char *) source);
return rc == 1;
}
#endif
if (addr == RXADATA)
{
sim_io_printf (sd, "%c", GETTSI (source));
}
return nr_bytes;
}
void device_error () {}

21
sim/sparc/dev32.h Normal file
View File

@ -0,0 +1,21 @@
/* sparc device support
Copyright (C) 1999 Cygnus Solutions. */
#ifndef DEVICES_H
#define DEVICES_H
/* From libgloss/sparc/erc32-io.c. */
#define ERC32_DEVICE_ADDR 0x1f80000
#define ERC32_DEVICE_LEN (0x2000000 - 0x1f80000)
#define RXADATA 0x01F800E0
#define RXBDATA 0x01F800E4
#define RXSTAT 0x01F800E8
extern device sparc_devices;
/* FIXME: Temporary, until device support ready. */
struct _device { int foo; };
#endif /* DEVICES_H */

133
sim/sparc/mloop32.in Normal file
View File

@ -0,0 +1,133 @@
# Simulator main loop for sparc. -*- C -*-
# Copyright (C) 1999 Cygnus Solutions.
# Syntax:
# /bin/sh mainloop.in command
#
# Command is one of:
#
# init
# support
# extract-{simple,scache,pbb}
# {full,fast}-exec-{simple,scache,pbb}
#
# A target need only provide a "full" version of one of simple,scache,pbb.
# If the target wants it can also provide a fast version of same, or if
# the slow (full featured) version is `simple', then the fast version can be
# one of scache/pbb.
# A target can't provide more than this.
# ??? After a few more ports are done, revisit.
# Will eventually need to machine generate a lot of this.
case "x$1" in
xsupport)
cat <<EOF
static INLINE void
execute (SIM_CPU *current_cpu, SCACHE *sc)
{
ARGBUF *abuf = &sc->argbuf;
IADDR pc = GET_H_PC ();
USI insn = GETIMEMUSI (current_cpu, pc);
int fast_p = STATE_RUN_FAST_P (CPU_STATE (current_cpu));
if (fast_p)
{
const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
@cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
(*id->sem_full) (current_cpu, sc, insn);
}
else
{
const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
const CGEN_INSN *opcode = id->opcode;
int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
@cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
@cpu@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p);
/* FIXME: call x-before */
if (ARGBUF_PROFILE_P (abuf))
PROFILE_COUNT_INSN (current_cpu, pc, id->num);
/* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
if (PROFILE_MODEL_P (current_cpu)
&& ARGBUF_PROFILE_P (abuf))
@cpu@_model_insn_before (current_cpu, 1 /*first_p*/);
TRACE_INSN_INIT (current_cpu, abuf, 1);
TRACE_INSN (current_cpu, opcode, abuf, pc);
(*id->sem_full) (current_cpu, sc, insn);
/* FIXME: call x-after */
if (PROFILE_MODEL_P (current_cpu)
&& ARGBUF_PROFILE_P (abuf))
{
int cycles;
cycles = (*id->timing->model_fn) (current_cpu, sc);
@cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
}
TRACE_INSN_FINI (current_cpu, abuf, 1);
}
}
static INLINE void
do_annul (SIM_CPU *current_cpu)
{
IADDR npc = GET_H_NPC ();
/* ??? log profiling data */
/* ??? anything else */
SET_H_PC (npc);
SET_H_NPC (npc + 4);
}
EOF
;;
xinit)
# Nothing needed.
;;
xfull-exec-simple)
# Inputs: current_cpu, sc, FAST_P
# Outputs: none, instruction is fetched and executed
# Recorded PC is updated after every insn.
# ??? Use of `sc' is a bit of a hack as we don't use the scache.
# We do however use ARGBUF so for consistency with the other engine flavours
# sc is used.
cat <<EOF
{
if (GET_H_ANNUL_P ())
{
do_annul (current_cpu);
SET_H_ANNUL_P (0);
}
else
{
execute (current_cpu, sc);
}
}
EOF
;;
*)
echo "Invalid argument to mainloop.in: $1" >&2
exit 1
;;
esac

91
sim/sparc/regs32.h Normal file
View File

@ -0,0 +1,91 @@
/* sparc32 register definitions
Copyright (C) 1999 Cygnus Solutions. */
#ifndef REG32_H
#define REG32_H
/* PSR bits */
#define PSR_IMPL 0xf0000000
#define PSR_VER 0x0f000000
#define PSR_CC 0x00f00000
#define PSR_N 0x00800000
#define PSR_Z 0x00400000
#define PSR_V 0x00200000
#define PSR_C 0x00100000
#define PSR_EC 0x00002000
#define PSR_EF 0x00001000
#define PSR_PIL 0x00000f00
#define PSR_S 0x00000080
#define PSR_PS 0x00000040
#define PSR_ET 0x00000020
#define PSR_CWP 0x0000001f
/* The PSR is a hodge-podge of various things.
??? The final organization of this is wip. */
extern USI sparc32_get_h_psr_handler (SIM_CPU *);
extern void sparc32_set_h_psr_handler (SIM_CPU *, USI);
#define GET_H_PSR() sparc32_get_h_psr_handler (current_cpu)
#define SET_H_PSR(val) sparc32_set_h_psr_handler (current_cpu, (val))
/* The y reg is a virtual reg as it's actually one of the asr regs.
??? To be replaced in time with get/set specs. */
#if 0
#define sparc32_h_y_get(cpu) (CPU_CGEN_HW (cpu)->h_asr[0])
#define sparc32_h_y_set(cpu,val) (CPU_CGEN_HW (cpu)->h_asr[0] = (val))
#endif
#define GET_H_Y() (CPU (h_asr) [0])
#define SET_H_Y(newval) do { CPU (h_asr) [0] = (newval); } while (0)
/* The Trap Base Register. */
#define GET_H_TBR() CPU (h_tbr)
#define SET_H_TBR(newval) \
do { \
CPU (h_tbr) = (CPU (h_tbr) & 0xff0) | ((newval) & 0xfffff000); \
} while (0)
/* sparc32 register window stuff. */
/* Handle gets/sets of h-cwp.
This handles swapping out the current set of window registers
and swapping in the new. How the "swapping" is done depends on the
register window implementation of the day. */
void sparc32_set_h_cwp_handler (SIM_CPU *, int);
#define GET_H_CWP() CPU (h_cwp)
#define SET_H_CWP(newval) sparc32_set_h_cwp_handler (current_cpu, (newval))
/* WIM accessors. */
/* ??? Yes, mask computation assumes nwindows < 32. */
#define GET_H_WIM() (CPU (h_wim) & ((1 << GET_NWINDOWS ()) - 1))
#define SET_H_WIM(newval) (CPU (h_wim) = (newval))
/* Return non-zero if window WIN is valid in WIM. */
#define WINDOW_VALID_P(win, wim) (((wim) & (1 << (win))) == 0)
void sparc32_alloc_regwins (SIM_CPU *, int);
void sparc32_free_regwins (SIM_CPU *);
void sparc32_swapout_regwin (SIM_CPU *, int);
void sparc32_swapin_regwin (SIM_CPU *, int);
void sparc32_load_regwin (SIM_CPU *, IADDR pc_, int win_);
void sparc32_flush_regwin (SIM_CPU *, IADDR pc_, int win_, int no_errors_p_);
void sparc32_flush_regwins (SIM_CPU *, IADDR pc_, int no_errors_p_);
void sparc32_save_regwin (SIM_CPU *);
void sparc32_restore_regwin (SIM_CPU *);
/* Integer register access macros.
Provides an interface between the cpu description and the register window
implementation of the day. To be solidified in time. */
#define GET_H_GR(r) (current_cpu->current_regs[r])
/* ??? The r != 0 test may not be necessary as sufficient numbers of dni
entries can prevent this from occuring (I think). Even then though doing
this makes things more robust, and a lot of dni's would be needed.
??? The other way to handle %g0 is to always reset it for each insn
[perhaps optimized to only do so when necessary]. */
#define SET_H_GR(r, val) \
((r) != 0 ? (current_cpu->current_regs[r] = (val)) : 0)
#endif /* REG32_H */

245
sim/sparc/sim-if.c Normal file
View File

@ -0,0 +1,245 @@
/* Main simulator entry points for the SPARC.
Copyright (C) 1999 Cygnus Solutions. */
#include "sim-main.h"
#include <signal.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "libiberty.h"
#include "bfd.h"
#include "sim-core.h"
#include "dev32.h"
/* FIXME: Do we *need* to pass state to the semantic routines? */
SIM_DESC current_state;
static MODULE_SUSPEND_FN regwin_suspend;
/* Cover function of sim_state_free to free the cpu buffers as well. */
static void
free_state (SIM_DESC sd)
{
if (STATE_MODULES (sd) != NULL)
sim_module_uninstall (sd);
sim_cpu_free_all (sd);
sim_state_free (sd);
}
/* Create an instance of the simulator. */
SIM_DESC
sim_open (kind, callback, abfd, argv)
SIM_OPEN_KIND kind;
host_callback *callback;
struct _bfd *abfd;
char **argv;
{
char c;
int i;
SIM_DESC sd = sim_state_alloc (kind, callback);
/* The cpu data is kept in a separately allocated chunk of memory. */
if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ()) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
#if 0 /* FIXME: 'twould be nice if we could do this */
/* These options override any module options.
Obviously ambiguity should be avoided, however the caller may wish to
augment the meaning of an option. */
if (extra_options != NULL)
sim_add_option_table (sd, extra_options);
#endif
/* Make the default --environment=operating to be compatible with erc32. */
STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
/* getopt will print the error message so we just have to exit if this fails.
FIXME: Hmmm... in the case of gdb we need getopt to call
print_filtered. */
if (sim_parse_args (sd, argv) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* check for/establish the a reference program image */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd)
: NULL),
abfd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Establish any remaining configuration options. */
if (sim_config (sd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
if (sim_post_argv_init (sd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Initialize various cgen things not done by common framework. */
cgen_init (sd);
/* Open a copy of the opcode table. */
STATE_OPCODE_TABLE (sd) = sparc_cgen_opcode_open (STATE_ARCHITECTURE (sd)->mach,
CGEN_ENDIAN_BIG);
sparc_cgen_init_dis (STATE_OPCODE_TABLE (sd));
/* Allocate a handler for the control registers and other devices
if no memory for that range has been allocated by the user.
All are allocated in one chunk to keep things from being
unnecessarily complicated. */
if (sim_core_read_buffer (sd, NULL, read_map, &c, ERC32_DEVICE_ADDR, 1) == 0)
sim_core_attach (sd, NULL,
0 /*level*/,
access_read_write,
0 /*space ???*/,
ERC32_DEVICE_ADDR, ERC32_DEVICE_LEN /*nr_bytes*/,
0 /*modulo*/,
&sparc_devices,
NULL /*buffer*/);
/* Allocate core managed memory if none specified by user. */
/* Use address 4 here in case the user wanted address 0 unmapped. */
if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
sim_do_commandf (sd, "memory region 0,0x%x", SPARC_DEFAULT_MEM_SIZE);
/* FIXME: magic number */
if (sim_core_read_buffer (sd, NULL, read_map, &c, 0x2000000, 1) == 0)
sim_do_commandf (sd, "memory region 0x%x,0x%x", 0x2000000, 0x200000);
#ifdef HAVE_SPARC32
if (! ARCH64_P (sd))
{
sparc32_alloc_regwins (STATE_CPU (sd, 0), NWINDOWS);
}
#endif
#ifdef HAVE_SPARC64
if (ARCH64_P (sd))
{
sparc64_alloc_regwins (STATE_CPU (sd, 0), NWINDOWS);
}
#endif
sim_module_add_suspend_fn (sd, regwin_suspend);
/* Perform a cold-reset of the cpu(s). */
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
sparc32_cold_reset (STATE_CPU (sd, i), 0);
/* Store in a global so things like sparc32_dump_regs can be invoked
from the gdb command line. */
current_state = sd;
return sd;
}
void
sim_close (sd, quitting)
SIM_DESC sd;
int quitting;
{
#ifdef HAVE_SPARC32
if (! ARCH64_P (sd))
sparc32_free_regwins (STATE_CPU (sd, 0));
#endif
#ifdef HAVE_SPARC64
if (ARCH64_P (sd))
sparc64_free_regwins (STATE_CPU (sd, 0));
#endif
sim_module_uninstall (sd);
}
SIM_RC
sim_create_inferior (sd, abfd, argv, envp)
SIM_DESC sd;
struct _bfd *abfd;
char **argv;
char **envp;
{
SIM_ADDR addr;
if (abfd)
addr = bfd_get_start_address (abfd);
else
addr = 0;
#if 0
STATE_ARGV (sd) = sim_copy_argv (argv);
STATE_ENVP (sd) = sim_copy_argv (envp);
#endif
#ifdef HAVE_SPARC32
if (! ARCH64_P (sd))
{
sparc32_cold_reset (STATE_CPU (sd, 0), 1);
sparc32_init_pc (STATE_CPU (sd, 0), addr, addr + 4);
}
#endif
#ifdef HAVE_SPARC64
if (ARCH64_P (sd))
{
sparc64_cold_reset (STATE_CPU (sd, 0), 1);
sparc64_init_pc (STATE_CPU (sd, 0), addr, addr + 4);
}
#endif
return SIM_RC_OK;
}
/* Flush the register windows when we suspend so we can walk the stack
in gdb.
??? Extremely inefficient in case where gdb is running a program
by stepping it.
??? Also interferes with debugging of --environment=operating. */
static SIM_RC
regwin_suspend (SIM_DESC sd)
{
int c;
for (c = 0; c < MAX_NR_PROCESSORS; ++c)
{
SIM_CPU *cpu = STATE_CPU (sd, c);
#ifdef HAVE_SPARC32
if (ARCH32_P (cpu))
sparc32_flush_regwins (cpu, sim_pc_get (cpu), 1 /* no errors */);
#endif
#ifdef HAVE_SPARC64
if (ARCH64_P (cpu))
sparc64_flush_regwins (cpu, sim_pc_get (cpu), 1 /* no errors */);
#endif
}
return SIM_RC_OK;
}
void
sim_do_command (sd, cmd)
SIM_DESC sd;
char *cmd;
{
if (sim_args_command (sd, cmd) != SIM_RC_OK)
sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
}

135
sim/sparc/sim-main.h Normal file
View File

@ -0,0 +1,135 @@
/* Main header for sparc. */
#ifndef SIM_MAIN_H
#define SIM_MAIN_H
#define USING_SIM_BASE_H /* FIXME: quick hack */
/* FIXME: For now always provide sparc32 support. */
#define HAVE_SPARC32
#undef HAVE_SPARC64 /* FIXME:wip */
/* ??? May eventually want this model (and perhaps runtime) selectable. */
#define NWINDOWS 8
struct _sim_cpu; /* FIXME: should be in sim-basics.h */
typedef struct _sim_cpu SIM_CPU;
#include "symcat.h"
#include "sim-basics.h"
#include "cgen-types.h"
#include "cpu-opc.h"
#include "arch.h"
/* These must be defined before sim-base.h. */
typedef USI sim_cia;
typedef int SEMRES;
#define CIA_GET(cpu) CPU_PC_GET (cpu)
#define CIA_SET(cpu,val) CPU_PC_SET ((cpu), (val))
#define SIM_ENGINE_HALT_HOOK(sd, cpu, cia) \
do { \
if (cpu) /* null if ctrl-c */ \
sim_pc_set ((cpu), (cia)); \
} while (0)
#define SIM_ENGINE_RESTART_HOOK(sd, cpu, cia) \
do { \
sim_pc_set ((cpu), (cia)); \
} while (0)
#include "sim-base.h"
#include "cgen-sim.h"
#ifdef WANT_CPU
#include "cpu-sim.h"
#endif
#if defined (WANT_CPU_SPARC32)
#include "regs32.h"
#include "trap32.h"
#elif defined (WANT_CPU_SPARC64)
#include "regs64.h"
#include "trap64.h"
#endif
/* The sim_cpu struct. */
struct _sim_cpu {
/* sim/common cpu base. */
sim_cpu_base base;
/* Static parts of cgen. */
CGEN_CPU cgen_cpu;
/* CPU specific parts go here.
Note that in files that don't need to access these pieces WANT_CPU_FOO
won't be defined and thus these parts won't appear. This is ok in the
sense that things work. It is a source of bugs though.
One has to of course be careful to not take the size of this
struct and no structure members accessed in non-cpu specific files can
go after here. Oh for a better language. */
#if defined (WANT_CPU_SPARC32)
/* Machine generated registers. */
SPARC32_CPU_DATA cpu_data;
#if 0
/* Working variables for generating profiling information. */
SPARC32_CPU_PROFILE cpu_profile;
#endif
/* Actual values of the window regs. */
SI win_regs[NWINDOWS][16];
/* g0-g7, normal and alternate
??? handling the alternate regs still wip, need REAL_GREGS to dtrt. */
SI global_regs[2][8];
/* Working copies of integer regs, swapped in/out on each window change.
??? Doing things this way means the .cpu file needn't mark these as
virtual. */
SI current_regs[32];
#elif defined (WANT_CPU_SPARC64)
/* Machine generated registers. */
SPARC64_CPU_DATA cpu_data;
#if 0
/* Working variables for generating profiling information. */
SPARC64_CPU_PROFILE cpu_profile;
#endif
/* Actual values of the window regs. */
DI win_regs[NWINDOWS][16];
/* g0-g7, normal and alternate */
DI global_regs[2][8];
/* Working copies of integer regs, swapped in/out on each window change.
??? Doing things this way means .cpu file needn't mark these as
virtual. */
DI current_regs[32];
#endif
};
#define ARCH32_P(cpu) 1 /*FIXME*/
#define ARCH64_P(cpu) (! ARCH32_P (cpu))
/* The sim_state struct. */
struct sim_state {
sim_cpu *cpu;
#define STATE_CPU(sd, n) (/*&*/ (sd)->cpu)
CGEN_STATE cgen_state;
sim_state_base base;
};
/* Misc. */
/* Catch address exceptions. */
extern SIM_CORE_SIGNAL_FN sparc_core_signal;
#define SIM_CORE_SIGNAL(SD,CPU,CIA,MAP,NR_BYTES,ADDR,TRANSFER,ERROR) \
sparc_core_signal ((SD), (CPU), (CIA), (MAP), (NR_BYTES), (ADDR), \
(TRANSFER), (ERROR))
/* Default memory size. */
#define SPARC_DEFAULT_MEM_SIZE 0x800000 /* 8M */
#endif /* SIM_MAIN_H */

258
sim/sparc/sparc-sim.h Normal file
View File

@ -0,0 +1,258 @@
/* collection of junk waiting time to sort out
Copyright (C) 1999 Cygnus Solutions. */
#ifndef SPARC_SIM_H
#define SPARC_SIM_H
/* GDB register numbers, will eventually live in more public place. */
#define SPARC32_PC_REGNUM 68
#define SPARC32_NPC_REGNUM 69
#define SPARC64_PC_REGNUM ?
#define SPARC64_NPC_REGNUM ?
/* Commonly used registers. */
#define REG_O0 8
#define REG_O1 9
#define REG_O2 10
#define REG_O3 11
#define REG_O4 12
#define REG_O5 13
#define REG_SP 14
#define REG_FP 30
#define CURRENT_GREGS(cpu) (& (cpu)->current_regs[0])
#define CURRENT_OREGS(cpu) (& (cpu)->current_regs[8])
#define CURRENT_LREGS(cpu) (& (cpu)->current_regs[16])
#define CURRENT_IREGS(cpu) (& (cpu)->current_regs[24])
/* The register windows are recorded in a seemingly backwards manner.
%i0-7 live at lower addresses in memory than %o0-7 (even though they
have higher register numbers). This is because on v9 the stack grows
upwards in the sense that CWP increases during a "push" (save) operation.
On v8 CWP decreases during a "push" (save) operation. */
#define REAL_GREGS(cpu) \
(& (cpu)->global_regs[0])
#define REAL_IREGS(cpu, win) \
(& (cpu)->win_regs[win][0])
#define REAL_LREGS(cpu, win) \
(& (cpu)->win_regs[win][8])
#ifdef WANT_CPU_SPARC32
#define REAL_OREGS(cpu, win) \
(& (cpu)->win_regs[ROUND_WIN ((win) - 1)][0])
#endif
#ifdef WANT_CPU_SPARC64
#define REAL_OREGS(cpu, win) \
(& (cpu)->win_regs[ROUND_WIN ((win) + 1)][0])
#endif
/* Window state. */
/* Various ways to handle register windows:
- don't, do all index calculations at runtime
- table of lookup tables, one entry for each window
- working copy of registers that is swapped in/out on each
register window change
- table of 32 pointers, one for each regs
- table of 4 pointers, one for each of g,o,l,i regs
- ???
*/
/* FIXME: Hardcodes number of windows. */
#define GET_NWINDOWS() NWINDOWS
/* We take advantage of the fact that NWINDOWS is always a power of two. */
#define ROUND_WIN(x) ((x) & (NWINDOWS - 1))
/* Return the next and previous windows of WIN.
Note that the next window for sparc32 is win-1 whereas the next window
for sparc64 is win+1. */
#ifdef WANT_CPU_SPARC32
#define NEXT_WIN(win) ROUND_WIN ((win) - 1)
#define PREV_WIN(win) ROUND_WIN ((win) + 1)
#endif
#ifdef WANT_CPU_SPARC64
#define NEXT_WIN(win) ROUND_WIN ((win) + 1)
#define PREV_WIN(win) ROUND_WIN ((win) - 1)
#endif
#if 0 /* FIXME: Use GET_H_FOO */
/* These are v9 specific. */
#define GET_CANSAVE(cpu_) (cpu_->cgen_cpu.cpu.h_cansave)
#define GET_CANRESTORE(cpu_) (cpu_->cgen_cpu.cpu.h_canrestore)
#define GET_CLEANWIN(cpu_) (cpu_->cgen_cpu.cpu.h_cleanwin)
#define GET_OTHERWIN(cpu_) (cpu_->cgen_cpu.cpu.h_otherwin)
#define GET_WSTATE(cpu_) (cpu_->cgen_cpu.cpu.h_wstate)
/* These are v9 specific. */
#define SET_CANSAVE(cpu_, x) (cpu_->cgen_cpu.cpu.h_cansave = (x))
#define SET_CANRESTORE(cpu_, x) (cpu_->cgen_cpu.cpu.h_canrestore = (x))
#define SET_CLEANWIN(cpu_, x) (cpu_->cgen_cpu.cpu.h_cleanwin = (x))
#define SET_OTHERWIN(cpu_, x) (cpu_->cgen_cpu.cpu.h_otherwin = (x))
#define SET_WSTATE(cpu_, x) (cpu_->cgen_cpu.cpu.h_wstate = (x))
#endif
#define CPU32_CGEN(cpu) (& (cpu)->sparc_cpu.sparc32.cpu_cgen)
#ifdef WANT_CPU_SPARC32
/*#define ARGBUF SPARC32_ARGBUF*/
#define CPU_PROFILE_STATE(cpu) (& CPU32 (cpu)->cpu_profile)
/* Macro to access heart of cpu: the registers, etc. */
#define CPU_CGEN(cpu) CPU32_CGEN (cpu)
#endif
#define CPU64_CGEN(cpu) (& (cpu)->sparc_cpu.sparc64.cpu_cgen)
#ifdef WANT_CPU_SPARC64
/*#define ARGBUF SPARC64_ARGBUF*/
#define CPU_PROFILE_STATE(cpu) (& CPU64 (cpu)->cpu_profile)
/* Macro to access heart of cpu: the registers, etc. */
#define CPU_CGEN(cpu) CPU64_CGEN (cpu)
#endif
/* ASI accesses. */
#define DECLARE_GETMEM(mode, size) \
extern mode XCONCAT3 (GETMEM,mode,ASI) (SIM_CPU *, IADDR, ADDR, INT);
DECLARE_GETMEM (QI, 1)
DECLARE_GETMEM (UQI, 1)
DECLARE_GETMEM (HI, 2)
DECLARE_GETMEM (UHI, 2)
DECLARE_GETMEM (SI, 4)
DECLARE_GETMEM (USI, 4)
DECLARE_GETMEM (DI, 8)
DECLARE_GETMEM (UDI, 8)
#undef DECLARE_GETMEM
#define DECLARE_SETMEM(mode, size) \
extern void XCONCAT3 (SETMEM,mode,ASI) (SIM_CPU *, IADDR, ADDR, INT, mode);
DECLARE_SETMEM (QI, 1)
DECLARE_SETMEM (UQI, 1)
DECLARE_SETMEM (HI, 2)
DECLARE_SETMEM (UHI, 2)
DECLARE_SETMEM (SI, 4)
DECLARE_SETMEM (USI, 4)
DECLARE_SETMEM (DI, 8)
DECLARE_SETMEM (UDI, 8)
#undef DECLARE_SETMEM
/* Misc. support routines. */
void sparc32_cold_reset (SIM_CPU *, int userland_p_);
SI sparc32_do_restore (SIM_CPU *, IADDR pc_, SI rs1_, SI rs2_simm13_);
SI sparc32_do_save (SIM_CPU *, IADDR pc_, SI rs1_, SI rs2_simm13_);
void sparc32_do_ldstub (SIM_CPU *, IADDR pc_, INT rd_regno_,
SI rs1_, SI rs2_simm13_, INT asi_);
void sparc32_do_swap (SIM_CPU *, IADDR pc_, INT rd_regno_,
SI rs1_, SI rs2_simm13_, INT asi_);
void sparc32_invalid_insn (SIM_CPU *, IADDR pc_);
void sparc32_core_signal (SIM_DESC, SIM_CPU *, sim_cia pc_,
unsigned int map_, int nr_bytes_, address_word addr_,
transfer_type transfer_, sim_core_signals sig_);
/* Profiling support. */
void model_mark_get_h_gr (SIM_CPU *, void *);
void model_mark_set_h_gr (SIM_CPU *, void *);
void model_mark_busy_reg (SIM_CPU *, void *);
void model_mark_unbusy_reg (SIM_CPU *, void *);
/* Called by semantic code to annul the next insn. */
#define SEM_ANNUL_INSN(cpu, pc, yes) \
do { CPU_CGEN_HW (cpu)->h_annul_p = (yes); } while (0)
#if 0 /* old experiment */
/* Macros used by the semantic code generator and cgen-run.c to control
branches. */
/* Value returned for the next PC when a branch has occured. */
#define PC_BRANCH_INSN 3
/* Value of npc when there is no delay slot. */
#define NPC_NO_DELAY_INSN 3
/* CURRENT_CPU isn't used, a variable of same name must exist for SET_H_NPC */
#define BRANCH_NEW_PC(current_cpu, var, addr) \
do { \
SET_H_PC (var); \
SET_H_NPC (addr); \
var = PC_BRANCH_INSN; \
} while (0)
/* Mark the next instruction as being annulled if YES is non-zero.
VAR is the local variable that contains the next PC value.
CURRENT_CPU isn't used, a variable of same name must exist for SET_H_NPC */
#define ANNUL_NEXT_INSN(current_cpu, var, yes) \
do { \
if (yes) \
{ \
SET_H_ANNUL_P (yes); \
var = PC_BRANCH_INSN; \
} \
} while (0)
/* Update the PC.
We also have to watch for delay slots and annulled insns.
current_cpu isn't used, a variable of same name must exist for SET_H_PC */
#define UPDATE_PC(current_cpu, new_pc) \
do { \
if ((new_pc) == PC_BRANCH_INSN) \
{ \
int annul_p = GET_H_ANNUL_P (); \
PCADDR npc = GET_H_NPC (); \
SET_H_ANNUL_P (0); \
if (npc != NPC_NO_DELAY_INSN) \
{ \
if (annul_p) \
{ \
/* FIXME: Could update cycle count. */ \
SET_H_PC (npc); \
SET_H_NPC (NPC_NO_DELAY_INSN) ; \
} \
else \
goto GotoFirstInsn; \
} \
else \
{ \
/* Untaken annulled branch. */ \
/* FIXME: Could update cycle count. */ \
ASSERT (annul_p); \
SET_H_PC (GET_H_PC () + 8); \
} \
} \
else \
SET_H_PC (new_pc); \
} while (0)
/* Return nonzero if in non-annulled delay slot. */
#define EXECUTE_FIRST_INSN_P(current_cpu) \
(GET_H_NPC () != NPC_NO_DELAY_INSN)
/* Called when the first instruction is in non-annulled delay slot. */
#define EXECUTE_FIRST_INSN(current_cpu, sc, fast_p) \
do { \
PCADDR new_pc = execute (current_cpu, sc, fast_p); \
if (new_pc == PC_BRANCH_INSN) \
{ \
abort (); /* FIXME: dcti in delay slot not handled yet */ \
} \
else \
{ \
SET_H_PC (GET_H_NPC ()); \
SET_H_NPC (NPC_NO_DELAY_INSN); \
} \
} while (0)
#endif /* old experiment */
#endif /* SPARC_SIM_H */

62
sim/sparc/sparc.c Normal file
View File

@ -0,0 +1,62 @@
/* sparc simulator support code, generic to all sparcs
Copyright (C) 1999 Cygnus Solutions. */
#include "sim-main.h"
#include "libiberty.h"
#include "bfd.h"
#include "cgen-mem.h"
#include "cgen-ops.h"
#ifdef HAVE_SPARC64
#define WI DI
#else
#define WI SI
#endif
void
sparc_do_unimp (SIM_CPU *current_cpu, IADDR pc, SI imm22)
{
sim_engine_invalid_insn (current_cpu, pc);
}
void
do_ldstub ()
{
}
void
do_swap ()
{
}
/* The semantic code invokes this for invalid (unrecognized) instructions. */
void
sim_engine_invalid_insn (SIM_CPU *cpu, IADDR pc)
{
#ifdef HAVE_SPARC32
if (ARCH32_P (cpu))
sparc32_invalid_insn (cpu, pc);
#endif
#ifdef HAVE_SPARC64
if (ARCH64_P (cpu))
sparc64_invalid_insn (cpu, pc);
#endif
}
/* Process an address exception. */
void
sparc_core_signal (SIM_DESC sd, SIM_CPU *cpu, sim_cia pc,
unsigned int map, int nr_bytes, address_word addr,
transfer_type transfer, sim_core_signals sig)
{
#ifdef HAVE_SPARC32
if (ARCH32_P (cpu))
sparc32_core_signal (sd, cpu, pc, map, nr_bytes, addr, transfer, sig);
#endif
#ifdef HAVE_SPARC64
if (ARCH64_P (cpu))
sparc64_core_signal (sd, cpu, pc, map, nr_bytes, addr, transfer, sig);
#endif
}

568
sim/sparc/sparc32.c Normal file
View File

@ -0,0 +1,568 @@
/* sparc32 simulator support code
Copyright (C) 1999 Cygnus Solutions. */
#define WANT_CPU sparc32
#define WANT_CPU_SPARC32
#include "sim-main.h"
#include <signal.h>
#include "libiberty.h"
#include "bfd.h"
#include "cgen-mem.h"
#include "cgen-ops.h"
#include "targ-vals.h"
static void sparc32_init_regwins (SIM_CPU *current_cpu);
static void sparc32_set_psr_no_cwp (SIM_CPU *current_cpu, USI newval);
/* gdb register access support.
The contents of BUF are in target byte order. */
int
sparc32_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
if (rn < 32)
{
SETTSI (buf, a_sparc_h_gr_get (current_cpu, rn));
}
else
switch (rn)
{
case SPARC32_PC_REGNUM :
SETTSI (buf, a_sparc_h_pc_get (current_cpu));
break;
case SPARC32_NPC_REGNUM :
{
USI npc = a_sparc_h_npc_get (current_cpu);
#if 0 /* experiment */
if (npc == NPC_NO_DELAY_INSN)
npc = a_sparc_h_pc_get (current_cpu) + 4;
#endif
SETTSI (buf, npc);
break;
}
default :
return 0;
}
return -1; /*FIXME*/
}
/* gdb register access support.
The contents of BUF are in target byte order. */
int
sparc32_store_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
if (rn < 32)
{
a_sparc_h_gr_set (current_cpu, rn, GETTSI (buf));
}
else
switch (rn)
{
case SPARC32_PC_REGNUM :
a_sparc_h_pc_set (current_cpu, GETTSI (buf));
break;
case SPARC32_NPC_REGNUM :
a_sparc_h_npc_set (current_cpu, GETTSI (buf));
break;
default :
return 0;
}
return -1; /*FIXME*/
}
/* Initialization. */
/* Initialize the program counter. */
void
sparc32_init_pc (SIM_CPU *current_cpu, SI pc, SI npc)
{
SET_H_PC (pc);
SET_H_NPC (npc);
}
/* Do a pseudo power-on-reset.
USERLAND_P is non-zero to prepare to run a user-land program. */
void
sparc32_cold_reset (SIM_CPU *current_cpu, int userland_p)
{
int i;
/* Initialize the PSR.
This has to be careful as we just want to initialize the CWP, we don't
want to "set" it (which causes the old window to be "swapped out").
??? impl,ver need better values. */
sparc32_set_psr_no_cwp (current_cpu, 0 | PSR_S);
/* Initialize cwp directly (bypassing SET_H_CWP and SET_H_PSR) as we just
want to initialize things, not "swap" the current window out. */
CPU (h_cwp) = 0;
sparc32_init_regwins (current_cpu);
/* Mark the last window as invalid. This creates a distinguishable end
of register window stack. The last window is window 1 (mask 2) as
saves decrement CWP.
Note that the last and first window overlap. */
SET_H_WIM (2);
sparc32_init_pc (current_cpu, 0, 4);
for (i = 0; i < 32; ++i)
SET_H_GR (i, 0);
SET_H_FSR (0);
}
/* Do a warm reset (the reset trap). */
void
sparc32_warm_reset (SIM_CPU *current_cpu)
{
/* FIXME: unimplemented yet */
}
/* Special purpose registers. */
/* The PSR.
??? add ability to specify a register as a set of bitfields. */
USI
sparc32_get_h_psr_handler (SIM_CPU *current_cpu)
{
USI val;
val = CPU (h_psr) & (PSR_IMPL | PSR_VER);
val |= GET_H_ICC_C () ? PSR_C : 0;
val |= GET_H_ICC_N () ? PSR_N : 0;
val |= GET_H_ICC_V () ? PSR_V : 0;
val |= GET_H_ICC_Z () ? PSR_Z : 0;
val |= GET_H_EC () ? PSR_EC : 0;
val |= GET_H_EF () ? PSR_EF : 0;
val |= (GET_H_PIL () & 0xf) << 8;
val |= GET_H_S () ? PSR_S : 0;
val |= GET_H_PS () ? PSR_PS : 0;
val |= GET_H_ET () ? PSR_ET : 0;
val |= GET_H_CWP ();
return val;
}
/* Utility to set everything in the PSR except CWP
(needed by sparc32_cold_reset). */
static void
sparc32_set_psr_no_cwp (SIM_CPU *current_cpu, USI newval)
{
SET_H_ICC_C ((newval & PSR_C) != 0);
SET_H_ICC_N ((newval & PSR_N) != 0);
SET_H_ICC_V ((newval & PSR_V) != 0);
SET_H_ICC_Z ((newval & PSR_Z) != 0);
SET_H_EC ((newval & PSR_EC) != 0);
SET_H_EF ((newval & PSR_EF) != 0);
SET_H_PIL ((newval & PSR_PIL) >> 8);
SET_H_S ((newval & PSR_S) != 0);
SET_H_PS ((newval & PSR_PS) != 0);
SET_H_ET ((newval & PSR_ET) != 0);
}
void
sparc32_set_h_psr_handler (SIM_CPU *current_cpu, USI newval)
{
sparc32_set_psr_no_cwp (current_cpu, newval);
SET_H_CWP (newval & PSR_CWP);
}
/* Register window support. */
/* Allocate space for the register window mechanism.
This version doesn't have much to do.
Other register window implementations have more to do. */
void
sparc32_alloc_regwins (SIM_CPU *current_cpu, int nwindows)
{
/* nothing to do in current window implementation */
}
void
sparc32_free_regwins (SIM_CPU *current_cpu)
{
/* nothing to do in current window implementation */
}
/* Initialize the register window control registers for running
user programs. */
static void
sparc32_init_regwins (SIM_CPU *current_cpu)
{
/* nothing to do in current window implementation */
}
/* Assign a new value to CWP.
SET_H_CWP calls this.
This swaps out the current values of the o/l/i regs from `current_regs'
and swaps in the new values. */
void
sparc32_set_h_cwp_handler (SIM_CPU *current_cpu, int new)
{
int old = GET_H_CWP ();
if (new < 0 || new >= GET_NWINDOWS ())
abort ();
CPU (h_cwp) = new;
/* Swap current values out of `current_regs'.
Do this even if old == new. */
sparc32_swapout_regwin (current_cpu, old);
/* Swap new values into `current_regs'. */
if (old != new)
sparc32_swapin_regwin (current_cpu, new);
}
/* Swap out the values in `current_regs'. */
void
sparc32_swapout_regwin (SIM_CPU *current_cpu, int win)
{
int n = 8 * sizeof (SI);
memcpy (REAL_OREGS (current_cpu, win), CURRENT_OREGS (current_cpu), n);
memcpy (REAL_LREGS (current_cpu, win), CURRENT_LREGS (current_cpu), n);
memcpy (REAL_IREGS (current_cpu, win), CURRENT_IREGS (current_cpu), n);
}
/* Swap int values for `current_regs'. */
void
sparc32_swapin_regwin (SIM_CPU *current_cpu, int win)
{
int n = 8 * sizeof (SI);
memcpy (CURRENT_OREGS (current_cpu), REAL_OREGS (current_cpu, win), n);
memcpy (CURRENT_LREGS (current_cpu), REAL_LREGS (current_cpu, win), n);
memcpy (CURRENT_IREGS (current_cpu), REAL_IREGS (current_cpu, win), n);
}
/* Create a new window. We assume there is room. */
void
sparc32_save_regwin (SIM_CPU *current_cpu)
{
SET_H_CWP (NEXT_WIN (GET_H_CWP ()));
}
/* Pop a window. We assume no traps possible. */
void
sparc32_restore_regwin (SIM_CPU *current_cpu)
{
SET_H_CWP (PREV_WIN (GET_H_CWP ()));
}
/* Flush the register windows to memory.
This is necessary, for example, when we want to walk the stack in gdb.
NO_ERRORS_P is non-zero if memory faults must be avoided. This is important
when returning to gdb, the processor has "stopped".
??? At present we only handle user programs. */
void
sparc32_flush_regwins (SIM_CPU *current_cpu, IADDR pc, int no_errors_p)
{
int i, win;
int count = GET_NWINDOWS ();
/* Flush the current window cache. */
sparc32_swapout_regwin (current_cpu, GET_H_CWP ());
/* For each register window that is marked valid, flush it to memory.
We start at the current window and move upwards on the stack. */
for (i = 0, win = GET_H_CWP (); i < count; i++, win = PREV_WIN (win))
{
/* Don't go passed an invalid window. */
if (! WINDOW_VALID_P (win, GET_H_WIM ()))
break;
sparc32_flush_regwin (current_cpu, pc, win, no_errors_p);
}
}
void
sparc32_flush_regwin (SIM_CPU *cpu, IADDR pc, int win, int no_errors_p)
{
int i;
USI sp,fp,addr;
/* Fetch pointers to lregs and iregs for this frame. */
SI *lregs = REAL_LREGS (cpu, win);
SI *iregs = REAL_IREGS (cpu, win);
SIM_DESC sd = CPU_STATE (cpu);
/* Fetch values of sp,fp for this frame. */
sp = REAL_OREGS (cpu, win) [6];
fp = REAL_IREGS (cpu, win) [6];
/* Exit early if there'd be a memory fault but we can't have any errors. */
if (no_errors_p)
{
/* Check if sp and fp indicate a proper save may not have been done. */
if (fp <= sp
|| fp - sp < 8 * sizeof (SI))
return;
/* sp misaligned? */
if (sp & 3)
return;
}
/* Use sim_core_write_aligned_N here to handle endian conversions. */
addr = sp;
for (i = 0; i < 8; i++)
{
if (no_errors_p)
{
char reg[4];
SETTSI (reg, lregs[i]);
if (sim_core_write_buffer (sd, cpu, write_map, reg, addr, 4) == 0)
return;
}
else
sim_core_write_aligned_4 (cpu, pc, write_map, addr, lregs[i]);
addr += 4;
}
for (i = 0; i < 8; i++)
{
if (no_errors_p)
{
char reg[4];
SETTSI (reg, lregs[i]);
if (sim_core_write_buffer (sd, cpu, write_map, reg, addr, 4) == 0)
return;
}
else
sim_core_write_aligned_4 (cpu, pc, write_map, addr, iregs[i]);
addr += 4;
}
}
void
sparc32_load_regwin (SIM_CPU *cpu, IADDR pc, int win)
{
int i;
/* Fetch value of sp for this frame. */
SI addr = REAL_OREGS (cpu, win) [6];
/* Fetch pointers to lregs and iregs for this frame. */
SI *lregs = REAL_LREGS (cpu, win);
SI *iregs = REAL_IREGS (cpu, win);
/* Use sim_core_read_aligned_N here to handle endian conversions. */
for (i = 0; i < 8; i++)
{
lregs[i] = sim_core_read_aligned_4 (cpu, pc, read_map, addr);
addr += 4;
}
for (i = 0; i < 8; i++)
{
iregs[i] = sim_core_read_aligned_4 (cpu, pc, read_map, addr);
addr += 4;
}
}
/* Save/restore insns. */
/* Handle the save instruction. */
SI
sparc32_do_save (SIM_CPU *current_cpu, IADDR pc, SI rs1, SI rs2_simm13)
{
SI rd;
int oldwin,newwin,wim;
/* FIXME: Watch for stack overflow if user prog. */
/* Determine new window number and see if its bit is set in the
Window Invalid Mask. */
oldwin = GET_H_CWP ();
newwin = NEXT_WIN (oldwin);
wim = GET_H_WIM ();
if (! WINDOW_VALID_P (newwin, wim))
sparc32_window_overflow (current_cpu, pc);
/* `rs1' and `rs2_simm13' are based on the old window (which we want) */
rd = rs1 + rs2_simm13;
/* Switch to the new window. */
sparc32_save_regwin (current_cpu);
if (TRACE_INSN_P (current_cpu)) /* FIXME */
{
trace_result (current_cpu, "sp", 'x', GET_H_GR (H_GR__SP));
trace_result (current_cpu, "fp", 'x', GET_H_GR (H_GR__FP));
trace_result (current_cpu, "cwp", 'x', GET_H_CWP ());
}
/* `rd' will be saved in the new window by the semantic code. */
return rd;
}
/* Handle the restore instruction. */
SI
sparc32_do_restore (SIM_CPU *current_cpu, IADDR pc, SI rs1, SI rs2_simm13)
{
SI rd;
int oldwin,newwin,wim;
/* Determine new window number and see if its bit is set in the
Window Invalid Mask. */
oldwin = GET_H_CWP ();
newwin = PREV_WIN (oldwin);
wim = GET_H_WIM ();
if (! WINDOW_VALID_P (newwin, wim))
sparc32_window_underflow (current_cpu, pc);
/* `rs1' and `rs2_simm13' are based on the old window (which we want) */
rd = rs1 + rs2_simm13;
/* Switch to the previous window. */
sparc32_restore_regwin (current_cpu);
if (TRACE_INSN_P (current_cpu)) /* FIXME */
{
trace_result (current_cpu, "sp", 'x', GET_H_GR (H_GR__SP));
trace_result (current_cpu, "fp", 'x', GET_H_GR (H_GR__FP));
trace_result (current_cpu, "cwp", 'x', GET_H_CWP ());
}
/* `rd' will be saved in the new window by the semantic code. */
return rd;
}
/* ASI accesses. */
#define DEFINE_GETMEM(mode, size) \
mode \
XCONCAT3 (GETMEM,mode,ASI) (SIM_CPU *cpu, IADDR pc, ADDR a, INT asi) \
{ \
return 0; /* FIXME:wip */ \
}
DEFINE_GETMEM (QI, 1)
DEFINE_GETMEM (UQI, 1)
DEFINE_GETMEM (HI, 2)
DEFINE_GETMEM (UHI, 2)
DEFINE_GETMEM (SI, 4)
DEFINE_GETMEM (USI, 4)
DEFINE_GETMEM (DI, 8)
DEFINE_GETMEM (UDI, 8)
#undef DEFINE_GETMEM
#define DEFINE_SETMEM(mode, size) \
void \
XCONCAT3 (SETMEM,mode,ASI) (SIM_CPU *cpu, IADDR pc, ADDR a, INT asi, mode newval) \
{ \
return; /* FIXME:wip */ \
}
DEFINE_SETMEM (QI, 1)
DEFINE_SETMEM (UQI, 1)
DEFINE_SETMEM (HI, 2)
DEFINE_SETMEM (UHI, 2)
DEFINE_SETMEM (SI, 4)
DEFINE_SETMEM (USI, 4)
DEFINE_SETMEM (DI, 8)
DEFINE_SETMEM (UDI, 8)
#undef SETMEM
/* ldstub, swap insns */
void
sparc32_do_ldstub (SIM_CPU *current_cpu, IADDR pc, INT rd_regno,
SI rs1, SI rs2_simm13, INT asi)
{
}
void
sparc32_do_swap (SIM_CPU *current_cpu, IADDR pc, INT rd_regno,
SI rs1, SI rs2_simm13, INT asi)
{
}
/* Profiling support. */
#if WITH_PROFILE_MODEL_P
/* FIXME: Some of these should be inline or macros. Later. */
void
sparc32_model_mark_get_h_gr (SIM_CPU *cpu, ARGBUF *abuf)
{
}
void
sparc32_model_mark_set_h_gr (SIM_CPU *cpu, ARGBUF *abuf)
{
}
void
sparc32_model_mark_busy_reg (SIM_CPU *cpu, ARGBUF *abuf)
{
}
void
sparc32_model_mark_unbusy_reg (SIM_CPU *cpu, ARGBUF *abuf)
{
}
/* Initialize cycle counting for an insn.
FIRST_P is non-zero if this is the first insn in a set of parallel
insns. */
void
sparc32_model_insn_before (SIM_CPU *cpu, int first_p)
{
}
/* Record the cycles computed for an insn.
LAST_P is non-zero if this is the last insn in a set of parallel insns,
and we update the total cycle count.
CYCLES is the cycle count of the insn. */
void
sparc32_model_insn_after (SIM_CPU *cpu, int last_p, int cycles)
{
}
int
sparc32_model_sparc32_def_u_exec (SIM_CPU *cpu, const IDESC *idesc,
int unit_num, int referenced)
{
return idesc->timing->units[unit_num].done;
}
#endif /* WITH_PROFILE_MODEL_P */
/* Debugging stuff. */
/* Pretty print the control and integer registers.
This can be invoked with the user-defined "dump" command in gdb. */
void
sim_debug_dump ()
{
extern SIM_DESC current_state;
host_callback *cb = STATE_CALLBACK (current_state);
SIM_CPU *current_cpu = STATE_CPU (current_state, 0);
sim_cb_printf (cb, "CPU Registers\n");
sim_cb_printf (cb, "CWP:%4d WIM:%4d\n", GET_H_CWP (), GET_H_WIM ());
}

49
sim/sparc/tconfig.in Normal file
View File

@ -0,0 +1,49 @@
/* Sparc target configuration file. -*- C -*- */
#ifndef SPARC_TCONFIG_H
#define SPARC_TCONFIG_H
/* See sim-hload.c. We properly handle LMA. */
#define SIM_HANDLES_LMA 1
/* Device support. FIXME: revisit. */
#define WITH_DEVICES 1
/* This is a global setting. Different cpu families can't mix-n-match -scache
and -pbb. However some cpu families may use -simple while others use
one of -scache/-pbb. */
#define WITH_SCACHE_PBB 0
/* Simple-engine branch support.
Delay slots, annuling, and traps are (currently) handled by using the
simple engine and doing all the work in SEM_{,N}BRANCH_FINI. */
#define TARGET_SEM_BRANCH_FINI(vpc, bool_attrs, taken_p) \
do { \
IADDR npc = GET_H_NPC (); \
if (CGEN_BOOL_ATTR ((bool_attrs), CGEN_INSN_DELAY_SLOT) && taken_p) \
{ \
SET_H_PC (npc); \
SET_H_NPC (vpc); \
} \
else if (CGEN_BOOL_ATTR ((bool_attrs), CGEN_INSN_TRAP) && taken_p) \
{ \
SET_H_PC (vpc); \
SET_H_NPC ((vpc) + 4); \
} \
else \
{ \
SET_H_PC (npc); \
SET_H_NPC (npc + 4); \
} \
} while (0)
#define TARGET_SEM_NBRANCH_FINI(vpc, bool_attrs) \
do { \
IADDR npc = GET_H_NPC (); \
SET_H_PC (npc); \
SET_H_NPC (npc + 4); \
} while (0)
#endif /* SPARC_TCONFIG_H */

308
sim/sparc/trap32.c Normal file
View File

@ -0,0 +1,308 @@
/* sparc32 trap support
Copyright (C) 1999 Cygnus Solutions. */
#define WANT_CPU sparc32
#define WANT_CPU_SPARC32
#include "sim-main.h"
#include "targ-vals.h"
/* Indicate a window overflow has occured. */
void
sparc32_window_overflow (SIM_CPU *cpu, IADDR pc)
{
SIM_DESC sd = CPU_STATE (cpu);
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
sparc32_hw_trap (cpu, pc, TRAP32_WINDOW_OVERFLOW);
else
sparc32_hw_trap (cpu, pc, TRAP32_SIM_SPILL);
}
/* Indicate a window underflow has occured. */
void
sparc32_window_underflow (SIM_CPU *cpu, IADDR pc)
{
SIM_DESC sd = CPU_STATE (cpu);
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
sparc32_hw_trap (cpu, pc, TRAP32_WINDOW_UNDERFLOW);
else
sparc32_hw_trap (cpu, pc, TRAP32_SIM_FILL);
}
void
sparc32_invalid_insn (SIM_CPU * cpu, IADDR pc)
{
sparc32_hw_trap (cpu, pc, TRAP32_ILLEGAL_INSN);
}
void
sparc32_core_signal (SIM_DESC sd, SIM_CPU *cpu, sim_cia pc,
unsigned int map, int nr_bytes, address_word addr,
transfer_type transfer, sim_core_signals sig)
{
sparc32_hw_trap (cpu, pc,
map == exec_map
? TRAP32_INSTRUCTION_ACCESS
: TRAP32_DATA_ACCESS);
}
/* Handle hardware generated traps when --environment=operating. */
static void
sparc32_hw_trap_oper (SIM_CPU *current_cpu, IADDR pc, TRAP32_TYPE trap)
{
SIM_DESC sd = CPU_STATE (current_cpu);
IADDR new_pc = (GET_H_TBR () & 0xfffff000) | (trap << 4);
USI psr = GET_H_PSR ();
psr &= ~PSR_ET;
psr = (psr & ~PSR_PS) | (psr & PSR_S ? PSR_PS : 0);
psr |= PSR_S;
psr = (psr & ~PSR_CWP) | NEXT_WIN (psr & PSR_CWP);
SET_H_PSR (psr);
SET_H_GR (H_GR__L1, GET_H_PC ());
SET_H_GR (H_GR__L2, GET_H_NPC ());
SET_H_ANNUL_P (0);
/* The wrtbr insn doesn't affect the tt part so SET_H_TBR doesn't either
(??? doesn't *have* to be this way though).
Therefore we can't use SET_H_TBR here. */
CPU (h_tbr) = new_pc;
SET_H_PC (new_pc);
SET_H_NPC (new_pc + 4);
sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL, new_pc);
}
/* Handle hardware generated traps when --environment=user. */
static void
sparc32_hw_trap_user (SIM_CPU *current_cpu, IADDR pc, TRAP32_TYPE trap)
{
SIM_DESC sd = CPU_STATE (current_cpu);
switch (trap)
{
case TRAP32_SIM_SPILL :
/* The CWP-1 window is invalid. */
{
int win = NEXT_WIN (GET_H_CWP ());
int next_win = NEXT_WIN (win);
int nwindows = GET_NWINDOWS ();
unsigned int mask = (1 << nwindows) - 1;
unsigned int wim = GET_H_WIM ();
/* There's no need to flush `current_regs' here, `next_win' can't
refer to it. */
sparc32_flush_regwin (current_cpu, pc, next_win, 0 /* error ok (?) */);
/* Rotate WIM right one. */
wim = ((wim & mask) >> 1) | (wim << (nwindows - 1));
SET_H_WIM (wim & mask);
return;
}
case TRAP32_SIM_FILL :
/* The CWP+1 window is invalid. */
{
int win = PREV_WIN (GET_H_CWP ());
int nwindows = GET_NWINDOWS ();
unsigned int mask = (1 << nwindows) - 1;
unsigned int wim = GET_H_WIM ();
/* Load caller's caller's window.
There's no need to flush `current_regs' as `win' can't
refer to it. */
sparc32_load_regwin (current_cpu, pc, win);
/* Rotate WIM left one. */
wim = (wim << 1) | ((wim & mask) >> (nwindows - 1));
SET_H_WIM (wim & mask);
return;
}
}
sim_io_eprintf (sd, "Received trap %d\n", trap);
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGABRT);
}
/* Handle hardware generated traps. */
void
sparc32_hw_trap (SIM_CPU *current_cpu, IADDR pc, TRAP32_TYPE trap)
{
SIM_DESC sd = CPU_STATE (current_cpu);
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
sparc32_hw_trap_oper (current_cpu, pc, trap);
else
sparc32_hw_trap_user (current_cpu, pc, trap);
}
/* Handle the trap insn when --environment=operating. */
static IADDR
sparc32_sw_trap_oper (SIM_CPU *current_cpu, IADDR pc, SI rs1, SI rs2_simm13)
{
SIM_DESC sd = CPU_STATE (current_cpu);
int trap = 128 + ((rs1 + rs2_simm13) & 127);
IADDR new_pc;
/* ??? Quick hack to have breakpoints work with gdb+"target sim" until
other things are working. */
if (trap == TRAP32_BREAKPOINT)
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
if (! GET_H_ET ())
{
/* Enter error mode.
??? wip, need to remain compatible with erc32 for now. */
int i0 = GET_H_GR (H_GR__I0);
int i1 = GET_H_GR (H_GR__I1);
if (i1 == LIBGLOSS_EXIT_MAGIC)
sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, i0);
else
{
sim_io_eprintf (sd, "Unexpected program termination, pc=0x%x\n",
(int) pc);
sim_engine_halt (sd, current_cpu, NULL, pc,
sim_signalled, SIM_SIGABRT);
}
}
SET_H_ET (0);
SET_H_PSR ((GET_H_PSR () & ~(PSR_CWP | PSR_PS))
| PSR_S
| (GET_H_S () ? PSR_PS : 0)
| (NEXT_WIN (GET_H_CWP ())));
SET_H_GR (H_GR__L1, GET_H_PC ());
SET_H_GR (H_GR__L2, GET_H_NPC ());
/* The wrtbr insn doesn't affect the tt part so SET_H_TBR doesn't either
(??? doesn't *have* to be this way though).
Therefore we can't use SET_H_TBR here. */
CPU (h_tbr) = new_pc = ((GET_H_TBR () & 0xfffff000)
| (trap << 4));
return new_pc;
}
/* Subroutine of sparc32_do_trap to read target memory. */
static int
syscall_read_mem (host_callback *cb, CB_SYSCALL *sc,
unsigned long taddr, char *buf, int bytes)
{
SIM_DESC sd = (SIM_DESC) sc->p1;
SIM_CPU *cpu = (SIM_CPU *) sc->p2;
return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
}
/* Subroutine of sparc32_do_trap to write target memory. */
static int
syscall_write_mem (host_callback *cb, CB_SYSCALL *sc,
unsigned long taddr, const char *buf, int bytes)
{
SIM_DESC sd = (SIM_DESC) sc->p1;
SIM_CPU *cpu = (SIM_CPU *) sc->p2;
return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
}
/* Handle the trap insn when --environment=user. */
static IADDR
sparc32_sw_trap_user (SIM_CPU *current_cpu, IADDR pc, SI rs1, SI rs2_simm13)
{
SIM_DESC sd = CPU_STATE (current_cpu);
int trap = 128 + ((rs1 + rs2_simm13) & 127);
IADDR new_pc = pc + 4;
switch (trap)
{
case TRAP32_SYSCALL :
/* FIXME: Later make trap number runtime selectable. */
{
CB_SYSCALL s;
CB_SYSCALL_INIT (&s);
s.func = a_sparc_h_gr_get (current_cpu, 8);
s.arg1 = a_sparc_h_gr_get (current_cpu, 9);
s.arg2 = a_sparc_h_gr_get (current_cpu, 10);
s.arg3 = a_sparc_h_gr_get (current_cpu, 11);
if (s.func == TARGET_SYS_exit)
{
/* Tell sim_resume program called exit(). */
sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, s.arg1);
}
s.p1 = (PTR) sd;
s.p2 = (PTR) current_cpu;
s.read_mem = syscall_read_mem;
s.write_mem = syscall_write_mem;
cb_syscall (STATE_CALLBACK (CPU_STATE (current_cpu)), &s);
a_sparc_h_gr_set (current_cpu, 10, s.errcode);
a_sparc_h_gr_set (current_cpu, 8, s.result);
a_sparc_h_gr_set (current_cpu, 9, s.result2);
break;
}
case TRAP32_BREAKPOINT :
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
case TRAP32_DIVIDE_0 :
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE);
case TRAP32_FLUSH_REGWIN :
sparc32_flush_regwins (current_cpu, pc, 0 /* error ok */);
break;
default :
sim_io_eprintf (sd, "Unsupported trap %d\n", trap);
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
}
return new_pc;
}
/* Called from the semantic code to handle the trap instruction. */
IADDR
sparc32_sw_trap (SIM_CPU *current_cpu, IADDR pc, SI rs1, SI rs2_simm13)
{
SIM_DESC sd = CPU_STATE (current_cpu);
IADDR new_pc;
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
new_pc = sparc32_sw_trap_oper (current_cpu, pc, rs1, rs2_simm13);
else
new_pc = sparc32_sw_trap_user (current_cpu, pc, rs1, rs2_simm13);
return new_pc;
}
/* Handle the rett insn. */
IADDR
sparc32_do_rett (SIM_CPU *current_cpu, IADDR pc, SI rs1, SI rs2_simm13)
{
int psr = GET_H_PSR ();
/* FIXME: check for trap conditions. */
SET_H_PSR ((psr & ~(PSR_S + PSR_CWP))
| ((psr & PSR_PS) ? PSR_S : 0)
| PSR_ET
| PREV_WIN (psr & PSR_CWP));
if (TRACE_INSN_P (current_cpu)) /* FIXME */
{
trace_result (current_cpu, "sp", 'x', GET_H_GR (H_GR__SP));
trace_result (current_cpu, "fp", 'x', GET_H_GR (H_GR__FP));
trace_result (current_cpu, "cwp", 'x', GET_H_CWP ());
}
return rs1 + rs2_simm13;
}

74
sim/sparc/trap32.h Normal file
View File

@ -0,0 +1,74 @@
/* sparc32 trap definitions
Copyright (C) 1999 Cygnus Solutions. */
#ifndef TRAP32_H
#define TRAP32_H
typedef enum
{
/* reset */
TRAP32_RESET = 0,
/* unable to fetch instruction (e.g. bad mapping) */
TRAP32_INSTRUCTION_ACCESS = 1,
/* illegal instruction */
TRAP32_ILLEGAL_INSN = 2,
/* priviledged instruction */
TRAP32_PRIVILEDGED_INSN = 3,
/* FPU disabled */
TRAP32_FP_DIS = 4,
/* window overflow */
TRAP32_WINDOW_OVERFLOW = 5,
/* window underflow */
TRAP32_WINDOW_UNDERFLOW = 6,
/* unaligned memory access */
TRAP32_UNALIGNED_ADDR = 7,
/* unable to access memory (e.g. bad mapping) */
TRAP32_DATA_ACCESS = 9,
/* tag overflow (taddcctv, tsubcctv insns) */
TRAP32_TAG_OVERFLOW = 10,
/* coprocessor disabled */
TRAP32_CP_DIS = 36,
/* Implementation dependent trap types. */
/* ??? Borrowed concept from v9. */
TRAP32_IMPDEP_EXCEPTION_0 = 96, /* n = 0..31 */
/* IMPDEP codes used by the simulator in ENVIRONMENT_USER. */
TRAP32_SIM_UNIMPLEMENTED_OPCODE = 124,
TRAP32_SIM_RESERVED_INSN = 125,
TRAP32_SIM_SPILL = 126,
TRAP32_SIM_FILL = 127,
/* Traps via the "trap" instruction. */
TRAP32_INSTRUCTION = 128, /* n = 0..127 */
/* System calls. */
TRAP32_SYSCALL = 128,
/* The breakpoint trap, "ta 1". */
TRAP32_BREAKPOINT = 129,
/* Divide by zero. */
TRAP32_DIVIDE_0 = 130,
/* Flush register windows, "ta 3". */
TRAP32_FLUSH_REGWIN = 131,
TRAP32_MAX = 0xff
} TRAP32_TYPE;
/* FIXME: revisit */
#define MAX_NUM_TRAPS 256
#define TRAP32_TABLE_SIZE (32 * MAX_NUM_TRAPS) /* in bytes */
/* The libgloss _exit routine sets a magic number in %o1 to tell us its
him. This lets us defer tinkering with libgloss and remain compatible
with erc32. */
#define LIBGLOSS_EXIT_MAGIC 0xdeadd00d
void sparc32_window_overflow (SIM_CPU *, IADDR pc_);
void sparc32_window_underflow (SIM_CPU *, IADDR pc_);
void sparc32_hw_trap (SIM_CPU *, IADDR pc_, TRAP32_TYPE trap_);
IADDR sparc32_sw_trap (SIM_CPU *, IADDR pc_, SI rs1_, SI rs2_simm13_);
IADDR sparc32_do_rett (SIM_CPU *, IADDR pc_, SI rs1_, SI rs2_simm13_);
#endif /* TRAP32_H */