18 changed files with 6603 additions and 0 deletions
@ -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. |
|||
@ -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 |
|||
@ -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 |
|||
@ -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 |
|||
File diff suppressed because it is too large
@ -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 |
|||
@ -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 () {} |
|||
@ -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 */ |
|||
@ -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 |
|||
@ -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 */ |
|||
@ -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); |
|||
} |
|||
@ -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 */ |
|||
@ -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 */ |
|||
@ -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 |
|||
} |
|||
@ -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 ()); |
|||
} |
|||
@ -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 */ |
|||
@ -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; |
|||
} |
|||
@ -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 */ |
|||
Loading…
Reference in new issue