mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-19 17:18:24 +08:00
sparc cgen port
This commit is contained in:
86
sim/sparc/.Sanitize
Normal file
86
sim/sparc/.Sanitize
Normal 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
135
sim/sparc/Makefile.in
Normal 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
15
sim/sparc/acconfig.h
Normal 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
49
sim/sparc/config.in
Normal 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
4255
sim/sparc/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
21
sim/sparc/configure.in
Normal file
21
sim/sparc/configure.in
Normal 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
98
sim/sparc/dev32.c
Normal 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
21
sim/sparc/dev32.h
Normal 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
133
sim/sparc/mloop32.in
Normal 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
91
sim/sparc/regs32.h
Normal 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
245
sim/sparc/sim-if.c
Normal 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
135
sim/sparc/sim-main.h
Normal 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
258
sim/sparc/sparc-sim.h
Normal 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
62
sim/sparc/sparc.c
Normal 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
568
sim/sparc/sparc32.c
Normal 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
49
sim/sparc/tconfig.in
Normal 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
308
sim/sparc/trap32.c
Normal 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
74
sim/sparc/trap32.h
Normal 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 */
|
Reference in New Issue
Block a user