Initial creation of sourceware repository

This commit is contained in:
Stan Shebs
1999-04-16 01:35:26 +00:00
parent cd946cff9e
commit c906108c21
2470 changed files with 976797 additions and 0 deletions

461
sim/ChangeLog Normal file
View File

@@ -0,0 +1,461 @@
1999-03-14 Stan Shebs <shebs@andros.cygnus.com>
* Makefile.in (FLAGS_TO_PASS, TARGET_FLAGS_TO_PASS): Remove
RUNTEST instead of commenting out, fixes portability problem.
1999-02-10 Doug Evans <devans@casey.cygnus.com>
* configure.in (sparc*): Configure sparc subdir if --with-cgen or
--with-cgen-sim.
* configure: Rebuild.
1999-02-08 Nick Clifton <nickc@cygnus.com>
* configure.in: Add support for StrongARM target.
* configure: Regenerate.
1999-02-02 Doug Evans <devans@casey.cygnus.com>
* configure.in (sparc*): Configure sparc subdir if --with-cgen.
* configure: Rebuild.
1999-01-04 Jason Molenda (jsm@bugshack.cygnus.com)
* configure.in: Require autoconf 2.12.1 or higher.
1998-12-08 James E Wilson <wilson@wilson-pc.cygnus.com>
* configure.in (i960-*-*): Add.
* configure: Rebuild.
Wed Nov 4 19:11:43 1998 Dave Brolley <brolley@cygnus.com>
* configure.in: Added case for fr30-*-*.
* configure: Regenerated.
Fri Sep 25 10:12:19 1998 Christopher Faylor <cgf@cygnus.com>
* ppc/Makefile.in: Add EXEEXT to installed powerpc-eabi-run program
to allow successful operation on Windows.
Thu May 28 14:59:46 1998 Jillian Ye <jillian@cygnus.com>
* Makefile.in: Take RUNTEST out of FLAG_TO_PASS
so that make check can be invoked recursively.
Wed Apr 29 12:38:53 1998 Mark Alexander <marka@cygnus.com>
* configure.in: Build simulator on sparclite and sparc86x targets.
* configure: Regenerate.
Sun Apr 26 15:21:01 1998 Tom Tromey <tromey@cygnus.com>
* Makefile.in (autoconf-common autoheader-common): Don't pass -l
to autoconf and autoheader.
Fri Apr 24 11:14:13 1998 Tom Tromey <tromey@cygnus.com>
* Makefile.in (autoconf-common autoheader-common): Pass `-l
../common' to autoconf and autoheader. Unconditionally run
autoconf in every subdir.
(autoconf-changelog autoheader-changelog): Unconditionally run
commands in every subdir.
(autoconf-install autoheader-install): Likewise.
Tue Mar 24 17:12:43 1998 Stu Grossman <grossman@bhuna.cygnus.co.uk>
* Makefile.in: Get SHELL from configure.
* (FLAGS_TO_PASS): Pass down SHELL.
* configure: Regenerate with autoconf 2.12.1 to fix shell issues for
NT native builds.
Tue Mar 24 11::18:00 1998 Joyce Janczyn <janczyn@cygnus.com>
* configure.in (extra_subdirs): Enable igen for mn10300.
* configure: Re-generate.
Tue Dec 2 10:10:42 1997 Nick Clifton <nickc@cygnus.com>
* configure.in (extra_subdirs): Add support for thumb target.
* configure (extra_subdirs): Add support for thumb target.
Wed Oct 8 12:38:48 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure.in (extra_subdirs): Add IGEN directory when MIPS
target.
* configure: Regenerate.
Fri Sep 12 13:10:31 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure.in (extra_subdirs): v850ea needs igen.
* configure: Re-generate.
Mon Sep 1 16:48:23 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure.in (testdir): When a testsuite directory, add that to
the list of confdirs.
Tue Aug 19 11:17:46 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure.in (extra_subdirs): Enable igen ready for V850.
Tue Aug 26 15:14:48 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure.in (w65-*-*, only_if_enabled): Set.
* configure: Re-generate.
Mon Aug 25 16:26:53 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure.in (sparc*-*-*, only_if_enabled): Set
only_if_enabled=yes. Check only_if_enabled before enabling a
simulator.
* configure: Regenerate.
Mon Aug 18 10:56:59 1997 Nick Clifton <nickc@cygnus.com>
* configure.in (extra_subdirs): Add v850e target.
Mon Aug 18 10:56:59 1997 Nick Clifton <nickc@cygnus.com>
* configure.in (extra_subdirs): Add v850ea target.
Fri Jul 25 11:40:47 1997 Doug Evans <dje@canuck.cygnus.com>
* configure.in (sparc*-*-*): Don't build erc32.
* configure: Regenerate.
Thu Apr 24 00:47:20 1997 Doug Evans <dje@canuck.cygnus.com>
* configure.in (m32r-*-*): New target.
* configure: Regenerate.
* Makefile.in (autoconf-common, autoconf-changelog): Change $* to $@.
Mon Apr 21 22:57:55 1997 Andrew Cagney <cagney@b1.cygnus.com>
* Makefile.in (.NOEXPORT, MAKEOVERRIDES): Moved to end, BSD make
thought that .NOEXPORT was the default target.
Fri Apr 11 17:18:07 1997 Ian Lance Taylor <ian@cygnus.com>
* Makefile.in (clean mostlyclean): Restore targets accidentally
deleted in earlier change.
Thu Apr 3 12:20:32 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* Makefile.in (autoheader-common, autoheader-changelog,
autoheader-install): Perform autoheader in addition to autoconf.
Wed Apr 2 15:09:05 1997 Doug Evans <dje@canuck.cygnus.com>
* Makefile.in (autoconf-install): New target.
(autoconf-changelog): Try different way to obtain user name.
Wed Apr 2 14:25:52 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* Makefile.in (autoconf-changelog): New target, update
ChangeLog for all subdirectories - normally used after
autoconf-common target.
Wed Mar 19 14:26:21 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* configure.in (extra_subdirs): Include testsuite for d30v.
* configure: Regenerate.
* Makefile.in (RUNTEST, RUNTESTFLAGS): Borrow test rules from
../gdb/Makefile.in
(check): New rules - drive the testsuite.
Mon Mar 3 13:01:00 1997 Jeffrey A Law (law@cygnus.com)
* configure.in: Add mn10200 configure lines accidentally
removed.
* configure: Regenerated.
Wed Feb 19 10:34:20 1997 Andrew Cagney <cagney@critters.cygnus.com>
* configure.in (extra_subdirs): Generalize common sub directory
into a list.
(extra_subdirs): For d30v add igen to the list to be built.
Sun Feb 16 16:37:47 1997 Andrew Cagney <cagney@critters.cygnus.com>
* configure.in (d30v): New target.
* configure: Regenerated.
Wed Feb 19 23:17:13 1997 Jeffrey A Law (law@cygnus.com)
* configure.in: Don't require GCC to build the mn10200
simulator anymore.
* configure: Rebuilt.
Wed Feb 5 13:28:13 1997 Doug Evans <dje@canuck.cygnus.com>
* configure.in: Don't configure any subdirs if no simulator
is being built. Don't use erc32 for sparc64.
* configure: Regenerated.
Tue Feb 4 13:19:39 1997 Doug Evans <dje@canuck.cygnus.com>
* Makefile.in (autoconf-common): New target.
* configure.in: Do configure common.
* configure: Regenerated.
Thu Jan 23 13:59:52 1997 Stu Grossman (grossman@critters.cygnus.com)
* configure configure.in: Don't configure common anymore. Files
from common are now built in the individual simualtor directories.
This fixes problems with the WinGDB build procedure.
Mon Jan 13 13:16:42 1997 Jeffrey A Law (law@cygnus.com)
* configure: Enable the mn10200 simulator.
Wed Nov 20 01:00:36 1996 Doug Evans <dje@canuck.cygnus.com>
* configure.in (configdirs): Add common.
* configure: Regenerated.
Fri Nov 1 08:03:30 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* configure.in (powerpc*-*-linux*): Treat like the other powerpc
system V based targets.
* configure: Regenerate.
Thu Oct 17 12:50:08 1996 Doug Evans <dje@canuck.cygnus.com>
* configure.in (--enable-sim-powerpc): Delete.
(--enable-sim): Add.
* configure: Regenerated.
Fri Oct 11 21:13:43 1996 Jeffrey A Law (law@cygnus.com)
* configure.in: Only build the V850 simulator if
we are using gcc.
* configure: Rebuild.
Sun Sep 8 17:22:50 1996 Ian Lance Taylor <ian@cygnus.com>
* configure.in: Do build erc32 for DOS and Windows hosts.
* configure: Rebuild.
Wed Sep 4 18:11:27 1996 Stu Grossman (grossman@critters.cygnus.com)
* Makefile.in erc32/Makefile.in: Don't set srcroot. This should
be inherited from the parent. Remove INSTALL_XFORM and
INSTALL_XFORM1. Make INSTALL be set from configure.
Wed Sep 4 15:49:16 1996 Ian Lance Taylor <ian@cygnus.com>
* configure.in: Only build the MIPS simulator if we are using
gcc.
* configure: Rebuild.
Wed Aug 28 19:05:23 1996 Jeffrey A Law (law@cygnus.com)
* configure.in (v850-*-*): Added V850 simulator.
Thu Aug 1 17:08:41 1996 Martin M. Hunt <hunt@pizza.cygnus.com>
* configure.in (d10v-*-*): Added D10V simulator.
Wed Jun 26 12:33:57 1996 Jason Molenda (crash@godzilla.cygnus.co.jp)
* Makefile.in (bindir, libdir, datadir, mandir, infodir, includedir,
INSTALL_PROGRAM, INSTALL_DATA): Use autoconf-set values.
(docdir): Removed.
* configure.in (AC_PREREQ): autoconf 2.5 or higher.
(AC_PROG_INSTALL): Added.
* configure: Rebuilt.
Mon Jun 24 14:18:26 1996 Ian Lance Taylor <ian@cygnus.com>
* configure.in: Only configure erc32 if using gcc.
* configure: Rebuild.
Tue Jun 4 09:24:21 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* configure.in (sim_target): Build PowerPC simulator for powerpc
System V.4, Solaris, and Elf targets.
* configure: Regenerate with autoconf 2.10.
Wed May 22 12:10:49 1996 Rob Savoye <rob@chinadoll>
* configure.in: Only built erc32 simulator on Unix hosts as it
uses pseudo ttys.
* configure: Regenerated with autoconf 2.8.
Sun May 19 20:20:40 1996 Rob Savoye <rob@chinadoll.cygnus.com>
* erc32: Sparc simulator from the ESA.
Sun Apr 7 21:00:09 1996 Fred Fish <fnf@cygnus.com>
From: Miles Bader <miles@gnu.ai.mit.edu>
* configure.in: Use AC_CHECK_TOOL to find AR & RANLIB.
* configure: Regenerate using autoconf.
Thu Feb 22 11:31:50 1996 Michael Meissner <meissner@tiktok.cygnus.com>
* Makefile.in (install): Fix typo.
Wed Feb 21 11:59:57 1996 Ian Lance Taylor <ian@cygnus.com>
* configure: Regenerate with autoconf 2.7.
* Makefile.in (all): Simplify.
(clean, mostlyclean): SUBDIRS may contain whitespace; fix the loop
as in the all target.
(distclean, maintainer-clean, realclean): Likewise.
(install): Likewise.
Thu Feb 15 18:37:00 1996 Fred Fish <fnf@cygnus.com>
* Makefile.in (all): Remove extra '\' char from shell script.
Wed Feb 14 16:43:59 1996 Mike Meissner <meissner@tiktok.cygnus.com>
* Makefile.in (all): Avoid a for loop with zero elements, even if
the loop will not be executed because of an if statement.
Wed Jan 31 21:48:34 1996 Fred Fish <fnf@cygnus.com>
* Makefile.in (install): Add missing semicolon in "fi \".
Thu Nov 9 16:10:56 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* Makefile.in (AR, CC, CFLAGS, CC_FOR_BUILD, RANLIB): Pick up
defaults from configure.
* configure.in: Pick up AR, CC, CFLAGS, CC_FOR_BUILD, RANLIB using
configure defaults.
(powerpc*-*-eabi*): Build simulator for all powerpc eabi targets
if either --enable-sim-powerpc is used, or the host compiler is
GCC.
Wed Nov 8 15:46:49 1995 James G. Smith <jsmith@pasanda.cygnus.co.uk>
* configure.in (mips*-*-*): Added "mips" simulator target.
* configure: Re-generated.
Tue Oct 10 11:08:20 1995 Fred Fish <fnf@cygnus.com>
* Makefile.in (BISON): Remove macro.
(FLAGS_TO_PASS): Remove BISON.
Sun Oct 8 04:26:27 1995 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
* configure.in: Explicitly `exit 0' for broken shells.
* configure: Rebuilt.
Fri Oct 6 12:03:27 1995 Jim Wilson <wilson@chestnut.cygnus.com>
* common/run.c (main): Initialize the callbacks.
Wed Sep 20 13:34:50 1995 Ian Lance Taylor <ian@cygnus.com>
* Makefile.in (maintainer-clean): New synonym for realclean.
Fri Aug 25 11:53:43 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* configure.in (powerpc*-*-eabisim*): Only build the simulator if
the target is powerpc*-*-eabisim*, since it requires GCC to build.
Mon Aug 21 17:53:48 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* configure.in (powerpc{,le}-*-*): Add psim from Andrew Cagney
<cagney@highland.com.au>.
* configure: Regnerate from configure.in.
Thu Aug 3 10:45:37 1995 Fred Fish <fnf@cygnus.com>
* Update all FSF addresses except those in COPYING* files.
Thu Jul 20 15:17:29 1995 Fred Fish <fnf@cygnus.com>
* Makefile.in (CC_FOR_BUILD): Define default and arrange to pass
submakes either default or passed in value.
Wed Jul 5 14:32:54 1995 J.T. Conklin <jtc@rtl.cygnus.com>
* Makefile.in (all, clean, distclean, mostlyclean, realclean,
install): Changed targets so that they descend all
subdirectories in $(SUBDIRS).
(*-all, *-clean, *-install): Removed targets.
* configure.in: Don't bother with target makefile fragments, they
are no longer needed.
* configure: regenerated.
* Makefile.in, configure.in: converted to autoconf.
* configure: New file, generated with autconf 2.4.
Wed May 24 14:48:46 1995 Steve Chamberlain <sac@slash.cygnus.com>
* Makefile.in: Support ARM.
* configure.in: Ditto.
Sun Jan 15 16:53:47 1995 Steve Chamberlain <sac@splat>
* Makefile.in: Support W65.
* configure.in: Ditto.
Sun Mar 13 09:27:50 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
* Makefile.in: Add TAGS target.
Mon Sep 13 12:47:15 1993 K. Richard Pixley (rich@sendai.cygnus.com)
* Makefile.in (all-z8k, install-z8k, clean-z8k, all-h8300,
install-h8300, clean-h8300, all-h8500, install-h8500,
clean-h8500, all-sh, install-sh, clean-sh): do not echo
recursion lines.
Wed Jun 30 14:12:05 1993 david d `zoo' zuhn (zoo at poseidon.cygnus.com)
* Makefile.in: remove endian.h trace from h8500
Sun Jun 13 13:08:58 1993 Jim Kingdon (kingdon@cygnus.com)
* Makefile.in: Add distclean, realclean, and mostlyclean targets.
Fri May 21 11:21:16 1993 david d `zoo' zuhn (zoo at cirdan.cygnus.com)
* Makefile.in: make all of the all-* target (except all-nothing)
depend on endian.h, so that if we're not building a simulator, we
don't built endian
Fri May 21 10:55:06 1993 Ian Lance Taylor (ian@cygnus.com)
* Makefile.in (check, installcheck): Added dummy targets.
Mon May 3 21:39:43 1993 Fred Fish (fnf@cygnus.com)
* Makefile.in (endian): Find endian.c in $(srcdir), and also
explicitly make it, since some makes apparently don't work with
VPATH and .c to executable rules (SunOS make for example).
Mon May 3 08:29:01 1993 Steve Chamberlain (sac@thepub.cygnus.com)
* Makefile.in (endian): Add explicit rule for broken makes.
Mon Mar 15 15:47:53 1993 Ian Lance Taylor (ian@cygnus.com)
* Makefile.in (info, install-info): New targets.
(DO_INSTALL): Renamed from INSTALL, which is overridden by the top
level Makefile.
Wed Feb 10 20:12:27 1993 K. Richard Pixley (rich@ok.cygnus.com)
* Makefile.in (endian.h): build endian.h via a temporary file so
that we don't leave an incomplete file lying around on
interrupted builds.
(clean): remove endian, e.h, and endian.h.
Mon Feb 8 11:46:06 1993 Steve Chamberlain (sac@thepub.cygnus.com)
* Makefile.in, configure.in: if target isn't supported, build a
harmless makefile.

254
sim/Makefile.in Normal file
View File

@@ -0,0 +1,254 @@
# Makefile template for Configure for the sim library.
# Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
# Written by Cygnus Support.
#
# This file is part of BFD, the Binary File Descriptor library.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
VPATH = @srcdir@
srcdir = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
target_alias = @target_alias@
program_transform_name = @program_transform_name@
bindir = @bindir@
libdir = @libdir@
tooldir = $(libdir)/$(target_alias)
datadir = @datadir@
mandir = @mandir@
man1dir = $(mandir)/man1
man2dir = $(mandir)/man2
man3dir = $(mandir)/man3
man4dir = $(mandir)/man4
man5dir = $(mandir)/man5
man6dir = $(mandir)/man6
man7dir = $(mandir)/man7
man8dir = $(mandir)/man8
man9dir = $(mandir)/man9
infodir = @infodir@
includedir = @includedir@
SHELL = @SHELL@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
AR = @AR@
AR_FLAGS = rc
CC = @CC@
CFLAGS = @CFLAGS@
CC_FOR_BUILD = @CC_FOR_BUILD@
MAKEINFO = makeinfo
RANLIB = @RANLIB@
SUBDIRS = @subdirs@
INCDIR = $(srcdir)/../include
CSEARCH = -I. -I$(srcdir) -I$(INCDIR)
DEP = mkdep
# compilers to use to create programs which must be run in the build
# environment.
CC_FOR_BUILD = $(CC)
#### Makefile fragments come in here.
# @target_makefile_frag@
###
RUNTEST = `if [ -f $${srcdir}/../dejagnu/runtest ] ; then \
echo $${srcdir}/../dejagnu/runtest ; else echo runtest; \
fi`
RUNTESTFLAGS=
FLAGS_TO_PASS = \
"prefix=$(prefix)" \
"exec_prefix=$(exec_prefix)" \
"against=$(against)" \
"AR=$(AR)" \
"AR_FLAGS=$(AR_FLAGS)" \
"CC=$(CC)" \
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
"CFLAGS=$(CFLAGS)" \
"RANLIB=$(RANLIB)" \
"MAKEINFO=$(MAKEINFO)" \
"INSTALL=$(INSTALL)" \
"INSTALL_DATA=$(INSTALL_DATA)" \
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
"SHELL=$(SHELL)"
# The use of $$(x_FOR_TARGET) reduces the command line length by not
# duplicating the lengthy definition.
TARGET_FLAGS_TO_PASS = \
"prefix=$(prefix)" \
"exec_prefix=$(exec_prefix)" \
"against=$(against)" \
'CC=$$(CC_FOR_TARGET)' \
"CC_FOR_TARGET=$(CC_FOR_TARGET)" \
"CFLAGS=$(CFLAGS)" \
"CHILLFLAGS=$(CHILLFLAGS)" \
'CHILL=$$(CHILL_FOR_TARGET)' \
"CHILL_FOR_TARGET=$(CHILL_FOR_TARGET)" \
"CHILL_LIB=$(CHILL_LIB)" \
'CXX=$$(CXX_FOR_TARGET)' \
"CXX_FOR_TARGET=$(CXX_FOR_TARGET)" \
"CXXFLAGS=$(CXXFLAGS)" \
"INSTALL=$(INSTALL)" \
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
"INSTALL_DATA=$(INSTALL_DATA)" \
"MAKEINFO=$(MAKEINFO)" \
"RUNTESTFLAGS=$(RUNTESTFLAGS)"
all:
@rootme=`pwd` ; export rootme ; \
for dir in . `echo ${SUBDIRS} | sed 's/testsuite//'` ; do \
if [ "$$dir" = "." ]; then \
true; \
elif [ -d $$dir ]; then \
(cd $$dir; $(MAKE) $(FLAGS_TO_PASS)); \
else true; fi; \
done
clean mostlyclean:
@rootme=`pwd` ; export rootme ; \
for dir in . ${SUBDIRS}; do \
if [ "$$dir" = "." ]; then \
true; \
elif [ -d $$dir ]; then \
(cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@); \
else true; fi; \
done
distclean maintainer-clean realclean:
@rootme=`pwd` ; export rootme ; \
for dir in . ${SUBDIRS}; do \
if [ "$$dir" = "." ]; then \
true; \
elif [ -d $$dir ]; then \
(cd $$dir; $(MAKE) $(FLAGS_TO_PASS) $@); \
else true; fi; \
done
rm -f Makefile config.cache config.log config.status
install:
@rootme=`pwd` ; export rootme ; \
for dir in . ${SUBDIRS}; do \
if [ "$$dir" = "." ]; then \
true; \
elif [ -d $$dir ]; then \
(cd $$dir; $(MAKE) $(FLAGS_TO_PASS) install); \
else true; fi; \
done
installcheck:
@echo No installcheck target is available yet for the GNU simulators.
installcheck:
# The check target can not use subdir_do, because subdir_do does not
# use TARGET_FLAGS_TO_PASS.
check: force
@if [ -f testsuite/Makefile ]; then \
rootme=`pwd`; export rootme; \
rootsrc=`cd $(srcdir); pwd`; export rootsrc; \
cd testsuite; \
$(MAKE) $(TARGET_FLAGS_TO_PASS) check; \
else true; fi
info:
install-info:
dvi:
###
###
.NOEXPORT:
MAKEOVERRIDES=
.PHONY: check installcheck
check:
installcheck:
TAGS:
force:
Makefile: Makefile.in config.status
$(SHELL) ./config.status
config.status: configure
$(SHELL) ./config.status --recheck
# Utility to run autoconf in each directory that uses the common framework.
# This is intended to be invoked in $srcdir as
# "make -f Makefile.in autoconf-common".
.PHONY: autoconf-common
autoconf-common autoheader-common:
for d in * ; \
do \
if [ -d $$d -a -f $$d/configure.in ] ; \
then \
echo "Running autoconf in $$d ..." ; \
(cd $$d && autoconf) ; \
if [ $@ = autoheader-common ] ; \
then \
echo "Running autoheader in $$d ..." ; \
(cd $$d && autoheader) ; \
fi ; \
fi ; \
done
autoconf-changelog autoheader-changelog:
id="`id | sed -e 's/^[^(]*(\([^)]*\).*$$/\1/'`" ; \
name=`grep "^$$id:" /etc/passwd | cut -f 5 -d ':'` ; \
host="`hostname`" ; \
date="`date | sed 's/ [^ ]* \([0-9]*\)$$/ \1/'`" ; \
echo "$$date $$name $$id@$$host" ; \
for d in * ; \
do \
if [ -d $$d -a -f $$d/configure.in ] ; \
then \
echo "Creating new-ChangeLog in $$d ..." ; \
( echo "$$date $$name <$$id@$$host>" ; \
echo "" ; \
echo " * configure: Regenerated to track ../common/aclocal.m4 changes." ; \
if [ $@ = autoheader-changelog ] ; \
then \
echo " * config.in: Ditto." ; \
fi ; \
echo "" ; \
cat $$d/ChangeLog \
) > $$d/new-ChangeLog ; \
fi ; \
done
autoconf-install autoheader-install:
for d in * ; \
do \
if [ -d $$d -a -f $$d/configure.in ] ; \
then \
echo "Moving $$d/new-ChangeLog to $$d/ChangeLog ..." ; \
mv $$d/new-ChangeLog $$d/ChangeLog ; \
fi ; \
done

254
sim/README-HACKING Normal file
View File

@@ -0,0 +1,254 @@
This is a loose collection of notes for people hacking on simulators.
If this document gets big enough it can be prettied up then.
Contents
- The "common" directory
- Common Makefile Support
- TAGS support
- Generating "configure" files
- tconfig.in
- C Language Assumptions
- "dump" commands under gdb
The "common" directory
======================
The common directory contains:
- common documentation files (e.g. run.1, and maybe in time .texi files)
- common source files (e.g. run.c)
- common Makefile fragment and configury (e.g. Make-common.in, aclocal.m4).
In addition "common" contains portions of the system call support
(e.g. callback.c, nltvals.def).
Even though no files are built in this directory, it is still configured
so support for regenerating nltvals.def is present.
Common Makefile Support
=======================
A common configuration framework is available for simulators that want
to use it. The common framework exists to remove a lot of duplication
in configure.in and Makefile.in, and it also provides a foundation for
enhancing the simulators uniformly (e.g. the more they share in common
the easier a feature added to one is added to all).
The configure.in of a simulator using the common framework should look like:
--- snip ---
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
... target specific additions ...
SIM_AC_OUTPUT
--- snip ---
SIM_AC_COMMON:
- invokes the autoconf macros most often used by the simulators
- defines --enable/--with options usable by all simulators
- initializes sim_link_files/sim_link_links as the set of symbolic links
to set up
SIM_AC_OUTPUT:
- creates the symbolic links defined in sim_link_{files,links}
- creates config.h
- creates the Makefile
The Makefile.in of a simulator using the common framework should look like:
--- snip ---
# Makefile for blah ...
# Copyright blah ...
## COMMON_PRE_CONFIG_FRAG
# These variables are given default values in COMMON_PRE_CONFIG_FRAG.
# We override the ones we need to here.
# Not all of these need to be mentioned, only the necessary ones.
# In fact it is better to *not* mention ones if the value is the default.
# List of object files, less common parts.
SIM_OBJS =
# List of extra dependencies.
# Generally this consists of simulator specific files included by sim-main.h.
SIM_EXTRA_DEPS =
# List of flags to always pass to $(CC).
SIM_EXTRA_CFLAGS =
# List of extra libraries to link with.
SIM_EXTRA_LIBS =
# List of extra program dependencies.
SIM_EXTRA_LIBDEPS =
# List of main object files for `run'.
SIM_RUN_OBJS = run.o
# Dependency of `all' to build any extra files.
SIM_EXTRA_ALL =
# Dependency of `install' to install any extra files.
SIM_EXTRA_INSTALL =
# Dependency of `clean' to clean any extra files.
SIM_EXTRA_CLEAN =
## COMMON_POST_CONFIG_FRAG
# Rules need to build $(SIM_OBJS), plus whatever else the target wants.
... target specific rules ...
--- snip ---
COMMON_{PRE,POST}_CONFIG_FRAG are markers for SIM_AC_OUTPUT to tell it
where to insert the two pieces of common/Make-common.in.
The resulting Makefile is created by doing autoconf substitions on
both the target's Makefile.in and Make-common.in, and inserting
the two pieces of Make-common.in into the target's Makefile.in at
COMMON_{PRE,POST}_CONFIG_FRAG.
Note that SIM_EXTRA_{INSTALL,CLEAN} could be removed and "::" targets
could be used instead. However, it's not clear yet whether "::" targets
are portable enough.
TAGS support
============
Many files generate program symbols at compile time.
Such symbols can't be found with grep nor do they normally appear in
the TAGS file. To get around this, source files can add the comment
/* TAGS: foo1 foo2 */
where foo1, foo2 are program symbols. Symbols found in such comments
are greppable and appear in the TAGS file.
Generating "configure" files
============================
For targets using the common framework, "configure" can be generated
by running `autoconf'.
To regenerate the configure files for all targets using the common framework:
$ cd devo/sim
$ make -f Makefile.in SHELL=/bin/sh autoconf-common
To add a change-log entry to the ChangeLog file for each updated
directory (WARNING - check the modified new-ChangeLog files before
renaming):
$ make -f Makefile.in SHELL=/bin/sh autoconf-changelog
$ more */new-ChangeLog
$ make -f Makefile.in SHELL=/bin/sh autoconf-install
In a similar vein, both the configure and config.in files can be
updated using the sequence:
$ cd devo/sim
$ make -f Makefile.in SHELL=/bin/sh autoheader-common
$ make -f Makefile.in SHELL=/bin/sh autoheader-changelog
$ more */new-ChangeLog
$ make -f Makefile.in SHELL=/bin/sh autoheader-install
tconfig.in
==========
File tconfig.in defines one or more target configuration macros
(e.g. a tm.h file). There are very few that need defining.
For a list of all of them, see common/tconfig.in.
It contains them all, commented out.
The intent is that a new port can just copy this file and
define the ones it needs.
C Language Assumptions
======================
The programmer may assume that the simulator is being built using an
ANSI C compiler that supports a 64 bit data type. Consequently:
o prototypes can be used (although using
PARAMS() and K&R declarations wouldn't
go astray).
o If sim-types.h is included, the two
types signed64 and unsigned64 are
available.
o The type `unsigned' is valid.
However, the user should be aware of the following:
o GCC's `<number>LL' is NOT acceptable.
Microsoft-C doesn't reconize it.
o MSC's `<number>i64' is NOT acceptable.
GCC doesn't reconize it.
o GCC's `long long' MSC's `_int64' can
NOT be used to define 64 bit integer data
types.
o An empty array (eg int a[0]) is not valid.
When building with GCC it is effectivly a requirement that
--enable-build-warnings=,-Werror be specified during configuration.
"dump" commands under gdb
=========================
gdbinit.in contains the following
define dump
set sim_debug_dump ()
end
Simulators that define the sim_debug_dump function can then have their
internal state pretty printed from gdb.
FIXME: This can obviously be made more elaborate. As needed it will be.
Rebuilding nltvals.def
======================
Checkout a copy of the SIM and LIBGLOSS modules (Unless you've already
got one to hand):
$ mkdir /tmp/$$
$ cd /tmp/$$
$ cvs checkout sim-no-testsuite libgloss-no-testsuite newlib-no-testsuite
Configure things for an arbitrary simulator target (I've d10v for
convenience):
$ mkdir /tmp/$$/build
$ cd /tmp/$$/build
$ /tmp/$$/devo/configure --target=d10v-elf
In the sim/common directory rebuild the headers:
$ cd sim/common
$ make headers
To add a new target:
devo/sim/common/gennltvals.sh
Add your new processor target (you'll need to grub
around to find where your syscall.h lives).
devo/sim/<processor>/Makefile.in
Add the definition:
``NL_TARGET = -DNL_TARGET_d10v''
just before the line COMMON_POST_CONFIG_FRAG.
devo/sim/<processor>/*.[ch]
Include targ-vals.h instead of syscall.h.

340
sim/arm/COPYING Normal file
View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

426
sim/arm/ChangeLog Normal file
View File

@@ -0,0 +1,426 @@
Mon Sep 14 09:00:05 1998 Nick Clifton <nickc@cygnus.com>
* wrapper.c (sim_open): Set endianness according to BFD or command
line switch.
* tconfig.in: Define SIM_HAVE_BIENDIAN.
Thu Aug 27 11:00:05 1998 Nick Clifton <nickc@cygnus.com>
* armemu.c (Multiply64): Test for Rm (rather than Rs) not being
the same as either RdHi or RdLo.
Thu Jul 2 10:24:35 1998 Nick Clifton <nickc@cygnus.com>
* armos.c (ARMul_OSHandleSWI: AngelSWI_Reason_ReportException):
Set Reg[0] based on reason for for the exception.
Thu Jun 4 15:22:03 1998 Jason Molenda (crash@bugshack.cygnus.com)
* armos.c (SWIwrite0): New function.
(WriteCommandLineTo): New function.
(SWIopen): New function.
(SWIread): New function.
(SWIwrite): New function.
(SWIflen): New function.
(ARMul_OSHandleSWI): Call new functions instead of handling
these here.
(ARMul_OSHandleSWI): Handle Angel SWIs correctly.
(*): Reformat spacing to be a bit more GNUly.
Most code taken from a patch by Anthony Thompson
(athompso@cambridge.arm.com)
Tue Jun 2 15:22:22 1998 Nick Clifton <nickc@cygnus.com>
* armos.h: Add Angel SWI and its reason codes.
* armos.c (ARMul_OSHandleSWI): Ignore Angel SWIs (for now).
Mon Jun 1 17:14:19 1998 Anthony Thompson (athompso@cambridge.arm.com)
* armos.c (ARMul_OSHandleSWI::SWI_Open): Handle special case
of ":tt" to catch stdin in addition to stdout.
(ARMul_OSHandleSWI::SWI_Seek): Return 0 or 1 to indicate failure
or success of lseek().
Wed May 20 17:36:25 1998 Nick Clifton <nickc@cygnus.com>
* armos.c (ARMul_OSHandleSWI): Special case code to catch attempts
to open stdout.
Wed Apr 29 15:29:55 1998 Jeff Johnston <jjohnstn@cygnus.com>
* armos.c (ARMul_OSHandleSWI): Added code for SWI_Clock,
SWI_Flen, and SWI_Time. Also fixed SWI_Seek code to only
seek from offset 0 and not to use R2 for whence since it is
not passed as part of the SWI call.
Tue Apr 28 18:33:31 1998 Geoffrey Noer <noer@cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Sun Apr 26 15:31:55 1998 Tom Tromey <tromey@creche>
* configure: Regenerated to track ../common/aclocal.m4 changes.
* config.in: Ditto.
Sun Apr 26 15:20:26 1998 Tom Tromey <tromey@cygnus.com>
* acconfig.h: New file.
* configure.in: Reverted change of Apr 24; use sinclude again.
Fri Apr 24 14:16:40 1998 Tom Tromey <tromey@creche>
* configure: Regenerated to track ../common/aclocal.m4 changes.
* config.in: Ditto.
Fri Apr 24 11:20:19 1998 Tom Tromey <tromey@cygnus.com>
* configure.in: Don't call sinclude.
Sat Apr 4 20:36:25 1998 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Fri Mar 27 16:15:52 1998 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Wed Mar 25 12:35:29 1998 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Wed Mar 18 12:38:12 1998 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Tue Mar 10 09:26:38 1998 Nick Clifton <nickc@cygnus.com>
* armopts.h: Remove definition of LITTLEND - it is not used.
Tue Feb 17 12:35:54 1998 Andrew Cagney <cagney@b1.cygnus.com>
* wrapper.c (sim_store_register, sim_fetch_register): Pass in
length parameter. Return -1.
Sun Feb 1 16:47:51 1998 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Sat Jan 31 18:15:41 1998 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Mon Jan 19 22:26:29 1998 Doug Evans <devans@seba>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Mon Dec 15 23:17:11 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
* config.in: Ditto.
Tue Dec 9 11:30:48 1997 Nick Clifton <nickc@cygnus.com>
* Makefile.in: Updated with changes from branch.
* armdefs.h: ditto
* armemu.c: ditto these changes
* armemu.h: ditto add support for
* armos.c: ditto the Thumb instruction
* armsupp.c: ditto set and the new v4
* armvirt.c: ditto architecture.
* wrapper.c: ditto
* thumbemu.c: New file from branch.
Thu Dec 4 09:21:05 1997 Doug Evans <devans@canuck.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Thu Oct 30 13:54:06 1997 Nick Clifton <nickc@cygnus.com>
* armos.c (ARMul_OSHandleSWI): Add support for GetEnv SWI. Patch
from Tony Thompson at ARM: athompso@arm.com
* wrapper.c (sim_create_inferior): Add code to create an execution
environment. Patch from Tony Thompson at ARM: athompso@arm.com
Wed Oct 22 14:43:00 1997 Andrew Cagney <cagney@b1.cygnus.com>
* wrapper.c (sim_load): Pass lma_p and sim_write args to
sim_load_file.
Fri Oct 3 09:28:00 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Wed Sep 24 17:38:57 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Tue Sep 23 11:04:38 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Mon Sep 22 11:46:20 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Fri Sep 19 17:45:25 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Mon Sep 15 17:36:15 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Thu Sep 4 17:21:23 1997 Doug Evans <dje@seba>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Wed Aug 27 18:13:22 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
* config.in: Ditto.
Tue Aug 26 10:37:27 1997 Andrew Cagney <cagney@b1.cygnus.com>
* wrapper.c (sim_kill): Delete.
(sim_create_inferior): Add ABFD argument.
(sim_load): Move setting of PC from here.
(sim_create_inferior): To here.
Mon Aug 25 17:50:22 1997 Andrew Cagney <cagney@b1.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
* config.in: Ditto.
Mon Aug 25 15:35:45 1997 Andrew Cagney <cagney@b1.cygnus.com>
* wrapper.c (sim_open): Add ABFD argument.
Tue May 20 10:13:26 1997 Andrew Cagney <cagney@b1.cygnus.com>
* wrapper.c (sim_open): Add callback argument.
(sim_set_callbacks): Drop SIM_DESC argument.
Thu Apr 24 00:39:51 1997 Doug Evans <dje@canuck.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Fri Apr 18 13:32:23 1997 Andrew Cagney <cagney@b1.cygnus.com>
* wrapper.c (sim_stop): Stub sim_stop function.
Thu Apr 17 18:33:01 1997 Fred Fish <fnf@cygnus.com>
* arminit.c (ARMul_NewState): Preinitialize the state to
all zero/NULL.
Thu Apr 17 02:39:02 1997 Doug Evans <dje@canuck.cygnus.com>
* Makefile.in (SIM_OBJS): Add sim-load.o.
* wrapper.c (sim_kind,myname): New static locals.
(sim_open): Set sim_kind, myname.
(sim_load): Call sim_load_file to do work. Set start address from bfd.
(sim_create_inferior): Return SIM_RC. Delete start_address arg.
Thu Apr 17 11:48:25 1997 Andrew Cagney <cagney@b1.cygnus.com>
* wrapper.c (sim_trace): Update so that it matches prototype.
Mon Apr 7 15:45:02 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
* config.in: Ditto.
Mon Apr 7 12:01:17 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* Makefile.in (armemu32.o): Replace $< with autoconf recommended
$(srcdir)/....
(armemu26.o): Ditto.
Wed Apr 2 15:06:28 1997 Doug Evans <dje@canuck.cygnus.com>
* wrapper.c (sim_open): New arg `kind'.
* configure: Regenerated to track ../common/aclocal.m4 changes.
Wed Apr 2 14:50:44 1997 Ian Lance Taylor <ian@cygnus.com>
* COPYING: Update FSF address.
Wed Apr 2 14:34:19 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Wed Mar 19 01:14:00 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* configure: Regenerated to track ../common/aclocal.m4 changes.
Mon Mar 17 15:10:07 1997 Andrew Cagney <cagney@kremvax.cygnus.com>
* configure: Re-generate.
Fri Mar 14 10:34:11 1997 Michael Meissner <meissner@cygnus.com>
* configure: Regenerate to track ../common/aclocal.m4 changes.
Thu Mar 13 12:38:56 1997 Doug Evans <dje@canuck.cygnus.com>
* wrapper.c (sim_open): Has result now.
(sim_*): New SIM_DESC argument.
Tue Feb 4 13:22:21 1997 Doug Evans <dje@canuck.cygnus.com>
* Makefile.in (@COMMON_MAKEFILE_FRAG@): Use
COMMON_{PRE,POST}_CONFIG_FRAG instead.
* configure.in: sinclude ../common/aclocal.m4.
* configure: Regenerated.
Thu Jan 23 11:46:23 1997 Stu Grossman (grossman@critters.cygnus.com)
* configure configure.in Makefile.in: Update to new configure
scheme which is more compatible with WinGDB builds.
* configure.in: Improve comment on how to run autoconf.
* configure: Re-run autoconf to get new ../common/aclocal.m4.
* Makefile.in: Use autoconf substitution to install common
makefile fragment.
Wed Nov 20 01:05:10 1996 Doug Evans <dje@canuck.cygnus.com>
* run.c: Deleted, use one in ../common now.
* Makefile.in: Delete everything that's been moved to
../common/Make-common.in.
(SIM_OBJS): Define.
* configure.in: Simplify using macros in ../common/aclocal.m4.
* configure: Regenerated.
* config.in: New file.
* armos.c: #include config.h.
* wrapper.c (mem_size): Value is in bytes now.
(sim_callback): New global.
(arm_sim_set_profile{,_size}): Delete.
(arm_sim_set_mem_size): Rename to sim_size.
(sim_do_command): Call printf_filtered via callback.
(sim_set_callbacks): Record callback.
Thu Oct 3 16:10:27 1996 Jason Molenda (crash@godzilla.cygnus.co.jp)
* Makefile.in (mostlyclean): Remove config.log.
Wed Jun 26 12:17:24 1996 Jason Molenda (crash@godzilla.cygnus.co.jp)
* Makefile.in (bindir, libdir, datadir, mandir, infodir, includedir,
INSTALL_PROGRAM, INSTALL_DATA): Use autoconf-set values.
(docdir): Removed.
* configure.in (AC_PREREQ): autoconf 2.5 or higher.
(AC_PROG_INSTALL): Added.
* configure: Rebuilt.
Wed Feb 21 12:14:31 1996 Ian Lance Taylor <ian@cygnus.com>
* configure: Regenerate with autoconf 2.7.
Fri Dec 15 16:27:30 1995 Ian Lance Taylor <ian@cygnus.com>
* run.c (main): Use new bfd_big_endian macro.
Mon Nov 20 17:40:38 1995 Doug Evans <dje@canuck.cygnus.com>
* run.c: Include "getopt.h".
(verbose): Delete.
(usage): Make static.
(main): Call arm_sim_set_verbosity.
Only load sections marked SEC_LOAD.
* wrapper.c (mem_size, verbosity): New static global.
(arm_sim_set_mem_size): Renamed from sim_size. Callers updated.
(arm_sim_set_profile{,_size}): Renamed from sim_foo. Callers updated.
Fri Nov 17 19:35:11 1995 Doug Evans <dje@canuck.cygnus.com>
* armdefs.h (ARMul_State): New member `verbose'.
* armrdi.c (ARMul_ConsolePrint): Add missing va_end.
* run.c (verbose): Make global.
* wrapper.c (init): Set state->verbose.
(ARMul_ConsolePrint): Don't print anything if !verbose.
Fri Oct 13 15:30:30 1995 Doug Evans <dje@canuck.cygnus.com>
* armos.c: #include dbg_rdi.h.
(ARMul_OSHandleSWI): Handle SWI_Breakpoint.
* armos.h (SWI_Breakpoint): Define.
* wrapper.c: #include armemu.h, dbg_rdi.h.
(rc): Delete.
(sim_resume): Use state->EndCondition to record stop state.
Call FLUSHPIPE before returning.
(sim_stop_reason): Determine reason from state->EndCondition.
Fri Oct 13 15:04:05 1995 steve chamberlain <sac@slash.cygnus.com>
* wrapper.c (sim_set_callbacks): New.
Thu Sep 28 19:45:56 1995 Doug Evans <dje@deneb.cygnus.com>
* armos.c (ARMul_OSHandleSWI): Result of read/write calls is
number of bytes not read/written (or -1).
Wed Sep 20 13:35:54 1995 Ian Lance Taylor <ian@cygnus.com>
* Makefile.in (maintainer-clean): New synonym for realclean.
Fri Sep 8 14:27:20 1995 Ian Lance Taylor <ian@cygnus.com>
* configure.in: Remove AC_PROG_INSTALL.
* configure: Rebuild.
* Makefile.in (INSTALL): Revert to using install.sh.
(INSTALL_PROGRAM, INSTALL_DATA): Set to $(INSTALL).
(INSTALL_XFORM, INSTALL_XFORM1): Restore.
(mostlyclean): Make the same as clean, not distclean.
(clean): Remove config.log.
(install): Don't install in $(tooldir).
Thu Sep 7 12:00:17 1995 Doug Evans <dje@canuck.cygnus.com>
(Try to) Update to new bfd autoconf scheme.
* run.c: Don't include sysdep.h.
* Makefile.in (INSTALL{,_PROGRAM,_DATA}): Use autoconf computed value.
(CC, CFLAGS, AR, RANLIB): Likewise.
(HDEFINES, TDEFINES): Define.
(CC_FOR_BUILD): Delete.
(host_makefile_frag): Delete.
(Makefile): Don't depend on frags.
* configure.in (sysdep.h): Don't create symlink.
(host_makefile_frag, frags): Deleted.
(CC, CFLAGS, AR, RANLIB, INSTALL): Compute values.
* configure: Regenerated.
Thu Aug 3 10:45:37 1995 Fred Fish <fnf@cygnus.com>
* Update all FSF addresses except those in COPYING* files.
Wed Jul 5 16:15:54 1995 J.T. Conklin <jtc@rtl.cygnus.com>
* Makefile.in (clean): Remove run, libsim.a.
* Makefile.in, configure.in: converted to autoconf.
* configure: New file, generated with autconf 2.4.
* arm.mt: Removed.
Fri Jun 30 16:49:47 1995 Stan Shebs <shebs@andros.cygnus.com>
* wrapper.c (sim_do_command): New function.
Tue Jun 13 10:57:32 1995 Steve Chamberlain <sac@slash.cygnus.com>
* armos.c (ARMul_OSHandleSWI): New version to work with
newlib simply.
Thu Jun 8 14:37:14 1995 Steve Chamberlain <sac@slash.cygnus.com>
* run.c (main): Grab return value from right register.
Wed May 24 14:37:31 1995 Steve Chamberlain <sac@slash.cygnus.com>
* New.

48
sim/arm/Makefile.in Normal file
View File

@@ -0,0 +1,48 @@
# Makefile template for Configure for the arm sim library.
# Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
# Written by Cygnus Support.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
## COMMON_PRE_CONFIG_FRAG
SIM_EXTRA_CFLAGS = -DMODET
SIM_OBJS = armcopro.o armemu26.o armemu32.o arminit.o armos.o armsupp.o \
armvirt.o bag.o thumbemu.o wrapper.o sim-load.o
## COMMON_POST_CONFIG_FRAG
armos.o: armos.c armdefs.h armos.h armfpe.h
armcopro.o: armcopro.c armdefs.h
armemu26.o: armemu.c armdefs.h armemu.h
$(CC) -c $< -o armemu26.o $(ALL_CFLAGS)
armemu32.o: armemu.c armdefs.h armemu.h
$(CC) -c $< -o armemu32.o -DMODE32 $(ALL_CFLAGS)
arminit.o: arminit.c armdefs.h armemu.h
armrdi.o: armrdi.c armdefs.h armemu.h armos.h dbg_cp.h dbg_conf.h dbg_rdi.h \
dbg_hif.h communicate.h
armsupp.o: armsupp.c armdefs.h armemu.h
thumbemu.o: thumbemu.c armdefs.h armemu.h
bag.o: bag.c bag.h

27
sim/arm/README.Cygnus Normal file
View File

@@ -0,0 +1,27 @@
This directory contains the standard release of the ARMulator from
Advanced RISC Machines, and was ftp'd from.
ftp.cl.cam.ac.uk:/arm/gnu
It likes to use TCP/IP between the simulator and the host, which is
nice, but is a pain to use under anything non-unix.
I've added created a new Makefile.in (the original in Makefile.orig)
to build a version of the simulator without the TCP/IP stuff, and a
wrapper.c to link directly into gdb and the run command.
It should be possible (barring major changes in the layout of
the armulator) to upgrade the simulator by copying all the files
out of a release into this directory and renaming the Makefile.
(Except that I changed armos.c to work more simply with our
simulator rigs)
Steve
sac@cygnus.com
Mon May 15 12:03:28 PDT 1995

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

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

357
sim/arm/armcopro.c Normal file
View File

@@ -0,0 +1,357 @@
/* armcopro.c -- co-processor interface: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "armdefs.h"
extern unsigned ARMul_CoProInit(ARMul_State *state) ;
extern void ARMul_CoProExit(ARMul_State *state) ;
extern void ARMul_CoProAttach(ARMul_State *state, unsigned number,
ARMul_CPInits *init, ARMul_CPExits *exit,
ARMul_LDCs *ldc, ARMul_STCs *stc,
ARMul_MRCs *mrc, ARMul_MCRs *mcr,
ARMul_CDPs *cdp,
ARMul_CPReads *read, ARMul_CPWrites *write) ;
extern void ARMul_CoProDetach(ARMul_State *state, unsigned number) ;
/***************************************************************************\
* Dummy Co-processors *
\***************************************************************************/
static unsigned NoCoPro3R(ARMul_State *state,unsigned,ARMword) ;
static unsigned NoCoPro4R(ARMul_State *state,unsigned,ARMword,ARMword) ;
static unsigned NoCoPro4W(ARMul_State *state,unsigned,ARMword,ARMword *) ;
/***************************************************************************\
* Define Co-Processor instruction handlers here *
\***************************************************************************/
/* Here's ARMulator's MMU definition. A few things to note:
1) it has eight registers, but only two are defined.
2) you can only access its registers with MCR and MRC.
3) MMU Register 0 (ID) returns 0x41440110
4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4
controls 32/26 bit program space, bit 5 controls 32/26 bit data space,
bit 6 controls late abort timimg and bit 7 controls big/little endian.
*/
static ARMword MMUReg[8] ;
static unsigned MMUInit(ARMul_State *state)
{MMUReg[1] = state->prog32Sig << 4 |
state->data32Sig << 5 |
state->lateabtSig << 6 |
state->bigendSig << 7 ;
ARMul_ConsolePrint (state, ", MMU present") ;
return(TRUE) ;
}
static unsigned MMUMRC(ARMul_State *state, unsigned type, ARMword instr,ARMword *value)
{int reg = BITS(16,19) & 7 ;
if (reg == 0)
*value = 0x41440110 ;
else
*value = MMUReg[reg] ;
return(ARMul_DONE) ;
}
static unsigned MMUMCR(ARMul_State *state, unsigned type, ARMword instr, ARMword value)
{int reg = BITS(16,19) & 7 ;
MMUReg[reg] = value ;
if (reg == 1) {
state->prog32Sig = value >> 4 & 1 ;
state->data32Sig = value >> 5 & 1 ;
state->lateabtSig = value >> 6 & 1 ;
state->bigendSig = value >> 7 & 1 ;
state->Emulate = TRUE ; /* force ARMulator to notice these now !*/
}
return(ARMul_DONE) ;
}
static unsigned MMURead(ARMul_State *state, unsigned reg, ARMword *value)
{if (reg == 0)
*value = 0x41440110 ;
else if (reg < 8)
*value = MMUReg[reg] ;
return(TRUE) ;
}
static unsigned MMUWrite(ARMul_State *state, unsigned reg, ARMword value)
{if (reg < 8)
MMUReg[reg] = value ;
if (reg == 1) {
state->prog32Sig = value >> 4 & 1 ;
state->data32Sig = value >> 5 & 1 ;
state->lateabtSig = value >> 6 & 1 ;
state->bigendSig = value >> 7 & 1 ;
state->Emulate = TRUE ; /* force ARMulator to notice these now !*/
}
return(TRUE) ;
}
/* What follows is the Validation Suite Coprocessor. It uses two
co-processor numbers (4 and 5) and has the follwing functionality.
Sixteen registers. Both co-processor nuimbers can be used in an MCR and
MRC to access these registers. CP 4 can LDC and STC to and from the
registers. CP 4 and CP 5 CDP 0 will busy wait for the number of cycles
specified by a CP register. CP 5 CDP 1 issues a FIQ after a number of
cycles (specified in a CP register), CDP 2 issues an IRQW in the same
way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5 stores a 32
bit time value in a CP register (actually it's the total number of N, S,
I, C and F cyles) */
static ARMword ValReg[16] ;
static unsigned ValLDC(ARMul_State *state, unsigned type,
ARMword instr, ARMword data)
{static unsigned words ;
if (type != ARMul_DATA) {
words = 0 ;
return(ARMul_DONE) ;
}
if (BIT(22)) { /* it's a long access, get two words */
ValReg[BITS(12,15)] = data ;
if (words++ == 4)
return(ARMul_DONE) ;
else
return(ARMul_INC) ;
}
else { /* get just one word */
ValReg[BITS(12,15)] = data ;
return(ARMul_DONE) ;
}
}
static unsigned ValSTC(ARMul_State *state, unsigned type,
ARMword instr, ARMword *data)
{static unsigned words ;
if (type != ARMul_DATA) {
words = 0 ;
return(ARMul_DONE) ;
}
if (BIT(22)) { /* it's a long access, get two words */
*data = ValReg[BITS(12,15)] ;
if (words++ == 4)
return(ARMul_DONE) ;
else
return(ARMul_INC) ;
}
else { /* get just one word */
*data = ValReg[BITS(12,15)] ;
return(ARMul_DONE) ;
}
}
static unsigned ValMRC(ARMul_State *state, unsigned type, ARMword instr,ARMword *value)
{
*value = ValReg[BITS(16,19)] ;
return(ARMul_DONE) ;
}
static unsigned ValMCR(ARMul_State *state, unsigned type, ARMword instr, ARMword value)
{
ValReg[BITS(16,19)] = value ;
return(ARMul_DONE) ;
}
static unsigned ValCDP(ARMul_State *state, unsigned type, ARMword instr)
{
static unsigned long finish = 0 ;
ARMword howlong ;
howlong = ValReg[BITS(0,3)] ;
if (BITS(20,23)==0) {
if (type == ARMul_FIRST) { /* First cycle of a busy wait */
finish = ARMul_Time(state) + howlong ;
if (howlong == 0)
return(ARMul_DONE) ;
else
return(ARMul_BUSY) ;
}
else if (type == ARMul_BUSY) {
if (ARMul_Time(state) >= finish)
return(ARMul_DONE) ;
else
return(ARMul_BUSY) ;
}
}
return(ARMul_CANT) ;
}
static unsigned DoAFIQ(ARMul_State *state)
{state->NfiqSig = LOW ;
state->Exception++ ;
return(0) ;
}
static unsigned DoAIRQ(ARMul_State *state)
{state->NirqSig = LOW ;
state->Exception++ ;
return(0) ;
}
static unsigned IntCDP(ARMul_State *state, unsigned type, ARMword instr)
{static unsigned long finish ;
ARMword howlong ;
howlong = ValReg[BITS(0,3)] ;
switch((int)BITS(20,23)) {
case 0 : if (type == ARMul_FIRST) { /* First cycle of a busy wait */
finish = ARMul_Time(state) + howlong ;
if (howlong == 0)
return(ARMul_DONE) ;
else
return(ARMul_BUSY) ;
}
else if (type == ARMul_BUSY) {
if (ARMul_Time(state) >= finish)
return(ARMul_DONE) ;
else
return(ARMul_BUSY) ;
}
return(ARMul_DONE) ;
case 1 : if (howlong == 0)
ARMul_Abort(state,ARMul_FIQV) ;
else
ARMul_ScheduleEvent(state,howlong,DoAFIQ) ;
return(ARMul_DONE) ;
case 2 : if (howlong == 0)
ARMul_Abort(state,ARMul_IRQV) ;
else
ARMul_ScheduleEvent(state,howlong,DoAIRQ) ;
return(ARMul_DONE) ;
case 3 : state->NfiqSig = HIGH ;
state->Exception-- ;
return(ARMul_DONE) ;
case 4 : state->NirqSig = HIGH ;
state->Exception-- ;
return(ARMul_DONE) ;
case 5 : ValReg[BITS(0,3)] = ARMul_Time(state) ;
return(ARMul_DONE) ;
}
return(ARMul_CANT) ;
}
/***************************************************************************\
* Install co-processor instruction handlers in this routine *
\***************************************************************************/
unsigned ARMul_CoProInit(ARMul_State *state)
{register unsigned i ;
for (i = 0 ; i < 16 ; i++) /* initialise tham all first */
ARMul_CoProDetach(state, i) ;
/* Install CoPro Instruction handlers here
The format is
ARMul_CoProAttach(state, CP Number, Init routine, Exit routine
LDC routine, STC routine, MRC routine, MCR routine,
CDP routine, Read Reg routine, Write Reg routine) ;
*/
ARMul_CoProAttach(state, 4, NULL, NULL,
ValLDC, ValSTC, ValMRC, ValMCR,
ValCDP, NULL, NULL) ;
ARMul_CoProAttach(state, 5, NULL, NULL,
NULL, NULL, ValMRC, ValMCR,
IntCDP, NULL, NULL) ;
ARMul_CoProAttach(state, 15, MMUInit, NULL,
NULL, NULL, MMUMRC, MMUMCR,
NULL, MMURead, MMUWrite) ;
/* No handlers below here */
for (i = 0 ; i < 16 ; i++) /* Call all the initialisation routines */
if (state->CPInit[i])
(state->CPInit[i])(state) ;
return(TRUE) ;
}
/***************************************************************************\
* Install co-processor finalisation routines in this routine *
\***************************************************************************/
void ARMul_CoProExit(ARMul_State *state)
{register unsigned i ;
for (i = 0 ; i < 16 ; i++)
if (state->CPExit[i])
(state->CPExit[i])(state) ;
for (i = 0 ; i < 16 ; i++) /* Detach all handlers */
ARMul_CoProDetach(state, i) ;
}
/***************************************************************************\
* Routines to hook Co-processors into ARMulator *
\***************************************************************************/
void ARMul_CoProAttach(ARMul_State *state, unsigned number,
ARMul_CPInits *init, ARMul_CPExits *exit,
ARMul_LDCs *ldc, ARMul_STCs *stc,
ARMul_MRCs *mrc, ARMul_MCRs *mcr, ARMul_CDPs *cdp,
ARMul_CPReads *read, ARMul_CPWrites *write)
{if (init != NULL)
state->CPInit[number] = init ;
if (exit != NULL)
state->CPExit[number] = exit ;
if (ldc != NULL)
state->LDC[number] = ldc ;
if (stc != NULL)
state->STC[number] = stc ;
if (mrc != NULL)
state->MRC[number] = mrc ;
if (mcr != NULL)
state->MCR[number] = mcr ;
if (cdp != NULL)
state->CDP[number] = cdp ;
if (read != NULL)
state->CPRead[number] = read ;
if (write != NULL)
state->CPWrite[number] = write ;
}
void ARMul_CoProDetach(ARMul_State *state, unsigned number)
{ARMul_CoProAttach(state, number, NULL, NULL,
NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
NoCoPro3R, NULL, NULL) ;
state->CPInit[number] = NULL ;
state->CPExit[number] = NULL ;
state->CPRead[number] = NULL ;
state->CPWrite[number] = NULL ;
}
/***************************************************************************\
* There is no CoPro around, so Undefined Instruction trap *
\***************************************************************************/
static unsigned NoCoPro3R(ARMul_State *state,unsigned a,ARMword b)
{return(ARMul_CANT) ;}
static unsigned NoCoPro4R(ARMul_State *state, unsigned a,ARMword b,ARMword c)
{return(ARMul_CANT) ;}
static unsigned NoCoPro4W(ARMul_State *state, unsigned a,ARMword b,ARMword *c)
{return(ARMul_CANT) ;}

353
sim/arm/armdefs.h Normal file
View File

@@ -0,0 +1,353 @@
/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include <stdlib.h>
#define FALSE 0
#define TRUE 1
#define LOW 0
#define HIGH 1
#define LOWHIGH 1
#define HIGHLOW 2
#ifndef __STDC__
typedef char * VoidStar ;
#endif
typedef unsigned long ARMword ; /* must be 32 bits wide */
typedef struct ARMul_State ARMul_State ;
typedef unsigned ARMul_CPInits(ARMul_State *state) ;
typedef unsigned ARMul_CPExits(ARMul_State *state) ;
typedef unsigned ARMul_LDCs(ARMul_State *state,unsigned type,ARMword instr,ARMword value) ;
typedef unsigned ARMul_STCs(ARMul_State *state,unsigned type,ARMword instr,ARMword *value) ;
typedef unsigned ARMul_MRCs(ARMul_State *state,unsigned type,ARMword instr,ARMword *value) ;
typedef unsigned ARMul_MCRs(ARMul_State *state,unsigned type,ARMword instr,ARMword value) ;
typedef unsigned ARMul_CDPs(ARMul_State *state,unsigned type,ARMword instr) ;
typedef unsigned ARMul_CPReads(ARMul_State *state,unsigned reg,ARMword *value) ;
typedef unsigned ARMul_CPWrites(ARMul_State *state,unsigned reg,ARMword value) ;
struct ARMul_State {
ARMword Emulate ; /* to start and stop emulation */
unsigned EndCondition ; /* reason for stopping */
unsigned ErrorCode ; /* type of illegal instruction */
ARMword Reg[16] ; /* the current register file */
ARMword RegBank[7][16] ; /* all the registers */
ARMword Cpsr ; /* the current psr */
ARMword Spsr[7] ; /* the exception psr's */
ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags ; /* dummy flags for speed */
#ifdef MODET
ARMword TFlag ; /* Thumb state */
#endif
ARMword Bank ; /* the current register bank */
ARMword Mode ; /* the current mode */
ARMword instr, pc, temp ; /* saved register state */
ARMword loaded, decoded ; /* saved pipeline state */
unsigned long NumScycles,
NumNcycles,
NumIcycles,
NumCcycles,
NumFcycles ; /* emulated cycles used */
unsigned long NumInstrs ; /* the number of instructions executed */
unsigned NextInstr ;
unsigned VectorCatch ; /* caught exception mask */
unsigned CallDebug ; /* set to call the debugger */
unsigned CanWatch ; /* set by memory interface if its willing to suffer the
overhead of checking for watchpoints on each memory
access */
unsigned MemReadDebug, MemWriteDebug ;
unsigned long StopHandle ;
unsigned char *MemDataPtr ; /* admin data */
unsigned char *MemInPtr ; /* the Data In bus */
unsigned char *MemOutPtr ; /* the Data Out bus (which you may not need */
unsigned char *MemSparePtr ; /* extra space */
ARMword MemSize ;
unsigned char *OSptr ; /* OS Handle */
char *CommandLine ; /* Command Line from ARMsd */
ARMul_CPInits *CPInit[16] ; /* coprocessor initialisers */
ARMul_CPExits *CPExit[16] ; /* coprocessor finalisers */
ARMul_LDCs *LDC[16] ; /* LDC instruction */
ARMul_STCs *STC[16] ; /* STC instruction */
ARMul_MRCs *MRC[16] ; /* MRC instruction */
ARMul_MCRs *MCR[16] ; /* MCR instruction */
ARMul_CDPs *CDP[16] ; /* CDP instruction */
ARMul_CPReads *CPRead[16] ; /* Read CP register */
ARMul_CPWrites *CPWrite[16] ; /* Write CP register */
unsigned char *CPData[16] ; /* Coprocessor data */
unsigned char const *CPRegWords[16] ; /* map of coprocessor register sizes */
unsigned EventSet ; /* the number of events in the queue */
unsigned long Now ; /* time to the nearest cycle */
struct EventNode **EventPtr ; /* the event list */
unsigned Exception ; /* enable the next four values */
unsigned Debug ; /* show instructions as they are executed */
unsigned NresetSig ; /* reset the processor */
unsigned NfiqSig ;
unsigned NirqSig ;
unsigned abortSig ;
unsigned NtransSig ;
unsigned bigendSig ;
unsigned prog32Sig ;
unsigned data32Sig ;
unsigned lateabtSig ;
ARMword Vector ; /* synthesize aborts in cycle modes */
ARMword Aborted ; /* sticky flag for aborts */
ARMword Reseted ; /* sticky flag for Reset */
ARMword Inted, LastInted ; /* sticky flags for interrupts */
ARMword Base ; /* extra hand for base writeback */
ARMword AbortAddr ; /* to keep track of Prefetch aborts */
const struct Dbg_HostosInterface *hostif;
int verbose; /* non-zero means print various messages like the banner */
} ;
#define ResetPin NresetSig
#define FIQPin NfiqSig
#define IRQPin NirqSig
#define AbortPin abortSig
#define TransPin NtransSig
#define BigEndPin bigendSig
#define Prog32Pin prog32Sig
#define Data32Pin data32Sig
#define LateAbortPin lateabtSig
/***************************************************************************\
* Types of ARM we know about *
\***************************************************************************/
/* The bitflags */
#define ARM_Fix26_Prop 0x01
#define ARM_Nexec_Prop 0x02
#define ARM_Debug_Prop 0x10
#define ARM_Isync_Prop ARM_Debug_Prop
#define ARM_Lock_Prop 0x20
/* ARM2 family */
#define ARM2 (ARM_Fix26_Prop)
#define ARM2as ARM2
#define ARM61 ARM2
#define ARM3 ARM2
#ifdef ARM60 /* previous definition in armopts.h */
#undef ARM60
#endif
/* ARM6 family */
#define ARM6 (ARM_Lock_Prop)
#define ARM60 ARM6
#define ARM600 ARM6
#define ARM610 ARM6
#define ARM620 ARM6
/***************************************************************************\
* Macros to extract instruction fields *
\***************************************************************************/
#define BIT(n) ( (ARMword)(instr>>(n))&1) /* bit n of instruction */
#define BITS(m,n) ( (ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) ) /* bits m to n of instr */
#define TOPBITS(n) (instr >> (n)) /* bits 31 to n of instr */
/***************************************************************************\
* The hardware vector addresses *
\***************************************************************************/
#define ARMResetV 0L
#define ARMUndefinedInstrV 4L
#define ARMSWIV 8L
#define ARMPrefetchAbortV 12L
#define ARMDataAbortV 16L
#define ARMAddrExceptnV 20L
#define ARMIRQV 24L
#define ARMFIQV 28L
#define ARMErrorV 32L /* This is an offset, not an address ! */
#define ARMul_ResetV ARMResetV
#define ARMul_UndefinedInstrV ARMUndefinedInstrV
#define ARMul_SWIV ARMSWIV
#define ARMul_PrefetchAbortV ARMPrefetchAbortV
#define ARMul_DataAbortV ARMDataAbortV
#define ARMul_AddrExceptnV ARMAddrExceptnV
#define ARMul_IRQV ARMIRQV
#define ARMul_FIQV ARMFIQV
/***************************************************************************\
* Mode and Bank Constants *
\***************************************************************************/
#define USER26MODE 0L
#define FIQ26MODE 1L
#define IRQ26MODE 2L
#define SVC26MODE 3L
#define USER32MODE 16L
#define FIQ32MODE 17L
#define IRQ32MODE 18L
#define SVC32MODE 19L
#define ABORT32MODE 23L
#define UNDEF32MODE 27L
#define ARM32BITMODE (state->Mode > 3)
#define ARM26BITMODE (state->Mode <= 3)
#define ARMMODE (state->Mode)
#define ARMul_MODEBITS 0x1fL
#define ARMul_MODE32BIT ARM32BITMODE
#define ARMul_MODE26BIT ARM26BITMODE
#define USERBANK 0
#define FIQBANK 1
#define IRQBANK 2
#define SVCBANK 3
#define ABORTBANK 4
#define UNDEFBANK 5
#define DUMMYBANK 6
/***************************************************************************\
* Definitons of things in the emulator *
\***************************************************************************/
extern void ARMul_EmulateInit(void) ;
extern ARMul_State *ARMul_NewState(void) ;
extern void ARMul_Reset(ARMul_State *state) ;
extern ARMword ARMul_DoProg(ARMul_State *state) ;
extern ARMword ARMul_DoInstr(ARMul_State *state) ;
/***************************************************************************\
* Definitons of things for event handling *
\***************************************************************************/
extern void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay, unsigned (*func)() ) ;
extern void ARMul_EnvokeEvent(ARMul_State *state) ;
extern unsigned long ARMul_Time(ARMul_State *state) ;
/***************************************************************************\
* Useful support routines *
\***************************************************************************/
extern ARMword ARMul_GetReg(ARMul_State *state, unsigned mode, unsigned reg) ;
extern void ARMul_SetReg(ARMul_State *state, unsigned mode, unsigned reg, ARMword value) ;
extern ARMword ARMul_GetPC(ARMul_State *state) ;
extern ARMword ARMul_GetNextPC(ARMul_State *state) ;
extern void ARMul_SetPC(ARMul_State *state, ARMword value) ;
extern ARMword ARMul_GetR15(ARMul_State *state) ;
extern void ARMul_SetR15(ARMul_State *state, ARMword value) ;
extern ARMword ARMul_GetCPSR(ARMul_State *state) ;
extern void ARMul_SetCPSR(ARMul_State *state, ARMword value) ;
extern ARMword ARMul_GetSPSR(ARMul_State *state, ARMword mode) ;
extern void ARMul_SetSPSR(ARMul_State *state, ARMword mode, ARMword value) ;
/***************************************************************************\
* Definitons of things to handle aborts *
\***************************************************************************/
extern void ARMul_Abort(ARMul_State *state, ARMword address) ;
#define ARMul_ABORTWORD 0xefffffff /* SWI -1 */
#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \
state->AbortAddr = (address & ~3L)
#define ARMul_DATAABORT(address) state->abortSig = HIGH ; \
state->Aborted = ARMul_DataAbortV ;
#define ARMul_CLEARABORT state->abortSig = LOW
/***************************************************************************\
* Definitons of things in the memory interface *
\***************************************************************************/
extern unsigned ARMul_MemoryInit(ARMul_State *state,unsigned long initmemsize) ;
extern void ARMul_MemoryExit(ARMul_State *state) ;
extern ARMword ARMul_LoadInstrS(ARMul_State *state,ARMword address,ARMword isize) ;
extern ARMword ARMul_LoadInstrN(ARMul_State *state,ARMword address,ARMword isize) ;
extern ARMword ARMul_ReLoadInstr(ARMul_State *state,ARMword address,ARMword isize) ;
extern ARMword ARMul_LoadWordS(ARMul_State *state,ARMword address) ;
extern ARMword ARMul_LoadWordN(ARMul_State *state,ARMword address) ;
extern ARMword ARMul_LoadHalfWord(ARMul_State *state,ARMword address) ;
extern ARMword ARMul_LoadByte(ARMul_State *state,ARMword address) ;
extern void ARMul_StoreWordS(ARMul_State *state,ARMword address, ARMword data) ;
extern void ARMul_StoreWordN(ARMul_State *state,ARMword address, ARMword data) ;
extern void ARMul_StoreHalfWord(ARMul_State *state,ARMword address, ARMword data) ;
extern void ARMul_StoreByte(ARMul_State *state,ARMword address, ARMword data) ;
extern ARMword ARMul_SwapWord(ARMul_State *state,ARMword address, ARMword data) ;
extern ARMword ARMul_SwapByte(ARMul_State *state,ARMword address, ARMword data) ;
extern void ARMul_Icycles(ARMul_State *state,unsigned number, ARMword address) ;
extern void ARMul_Ccycles(ARMul_State *state,unsigned number, ARMword address) ;
extern ARMword ARMul_ReadWord(ARMul_State *state,ARMword address) ;
extern ARMword ARMul_ReadByte(ARMul_State *state,ARMword address) ;
extern void ARMul_WriteWord(ARMul_State *state,ARMword address, ARMword data) ;
extern void ARMul_WriteByte(ARMul_State *state,ARMword address, ARMword data) ;
extern ARMword ARMul_MemAccess(ARMul_State *state,ARMword,ARMword,ARMword,
ARMword,ARMword,ARMword,ARMword,ARMword,ARMword,ARMword) ;
/***************************************************************************\
* Definitons of things in the co-processor interface *
\***************************************************************************/
#define ARMul_FIRST 0
#define ARMul_TRANSFER 1
#define ARMul_BUSY 2
#define ARMul_DATA 3
#define ARMul_INTERRUPT 4
#define ARMul_DONE 0
#define ARMul_CANT 1
#define ARMul_INC 3
extern unsigned ARMul_CoProInit(ARMul_State *state) ;
extern void ARMul_CoProExit(ARMul_State *state) ;
extern void ARMul_CoProAttach(ARMul_State *state, unsigned number,
ARMul_CPInits *init, ARMul_CPExits *exit,
ARMul_LDCs *ldc, ARMul_STCs *stc,
ARMul_MRCs *mrc, ARMul_MCRs *mcr,
ARMul_CDPs *cdp,
ARMul_CPReads *read, ARMul_CPWrites *write) ;
extern void ARMul_CoProDetach(ARMul_State *state, unsigned number) ;
/***************************************************************************\
* Definitons of things in the host environment *
\***************************************************************************/
extern unsigned ARMul_OSInit(ARMul_State *state) ;
extern void ARMul_OSExit(ARMul_State *state) ;
extern unsigned ARMul_OSHandleSWI(ARMul_State *state,ARMword number) ;
extern ARMword ARMul_OSLastErrorP(ARMul_State *state) ;
extern ARMword ARMul_Debug(ARMul_State *state, ARMword pc, ARMword instr) ;
extern unsigned ARMul_OSException(ARMul_State *state, ARMword vector, ARMword pc) ;
extern int rdi_log ;
/***************************************************************************\
* Host-dependent stuff *
\***************************************************************************/
#ifdef macintosh
pascal void SpinCursor(short increment); /* copied from CursorCtl.h */
# define HOURGLASS SpinCursor( 1 )
# define HOURGLASS_RATE 1023 /* 2^n - 1 */
#endif

3454
sim/arm/armemu.c Normal file

File diff suppressed because it is too large Load Diff

425
sim/arm/armemu.h Normal file
View File

@@ -0,0 +1,425 @@
/* armemu.h -- ARMulator emulation macros: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
extern ARMword isize;
/***************************************************************************\
* Condition code values *
\***************************************************************************/
#define EQ 0
#define NE 1
#define CS 2
#define CC 3
#define MI 4
#define PL 5
#define VS 6
#define VC 7
#define HI 8
#define LS 9
#define GE 10
#define LT 11
#define GT 12
#define LE 13
#define AL 14
#define NV 15
/***************************************************************************\
* Shift Opcodes *
\***************************************************************************/
#define LSL 0
#define LSR 1
#define ASR 2
#define ROR 3
/***************************************************************************\
* Macros to twiddle the status flags and mode *
\***************************************************************************/
#define NBIT ((unsigned)1L << 31)
#define ZBIT (1L << 30)
#define CBIT (1L << 29)
#define VBIT (1L << 28)
#define IBIT (1L << 7)
#define FBIT (1L << 6)
#define IFBITS (3L << 6)
#define R15IBIT (1L << 27)
#define R15FBIT (1L << 26)
#define R15IFBITS (3L << 26)
#define POS(i) ( (~(i)) >> 31 )
#define NEG(i) ( (i) >> 31 )
#ifdef MODET /* Thumb support */
/* ??? This bit is actually in the low order bit of the PC in the hardware.
It isn't clear if the simulator needs to model that or not. */
#define TBIT (1L << 5)
#define TFLAG state->TFlag
#define SETT state->TFlag = 1
#define CLEART state->TFlag = 0
#define ASSIGNT(res) state->TFlag = res
#endif
#define NFLAG state->NFlag
#define SETN state->NFlag = 1
#define CLEARN state->NFlag = 0
#define ASSIGNN(res) state->NFlag = res
#define ZFLAG state->ZFlag
#define SETZ state->ZFlag = 1
#define CLEARZ state->ZFlag = 0
#define ASSIGNZ(res) state->ZFlag = res
#define CFLAG state->CFlag
#define SETC state->CFlag = 1
#define CLEARC state->CFlag = 0
#define ASSIGNC(res) state->CFlag = res
#define VFLAG state->VFlag
#define SETV state->VFlag = 1
#define CLEARV state->VFlag = 0
#define ASSIGNV(res) state->VFlag = res
#define IFLAG (state->IFFlags >> 1)
#define FFLAG (state->IFFlags & 1)
#define IFFLAGS state->IFFlags
#define ASSIGNINT(res) state->IFFlags = (((res) >> 6) & 3)
#define ASSIGNR15INT(res) state->IFFlags = (((res) >> 26) & 3) ;
#define CCBITS (0xf0000000L)
#define INTBITS (0xc0L)
#if defined MODET && defined MODE32
#define PCBITS (0xffffffffL)
#else
#define PCBITS (0xfffffffcL)
#endif
#define MODEBITS (0x1fL)
#define R15INTBITS (3L << 26)
#if defined MODET && defined MODE32
#define R15PCBITS (0x03ffffffL)
#else
#define R15PCBITS (0x03fffffcL)
#endif
#define R15PCMODEBITS (0x03ffffffL)
#define R15MODEBITS (0x3L)
#ifdef MODE32
#define PCMASK PCBITS
#define PCWRAP(pc) (pc)
#else
#define PCMASK R15PCBITS
#define PCWRAP(pc) ((pc) & R15PCBITS)
#endif
#define PC (state->Reg[15] & PCMASK)
#define R15CCINTMODE (state->Reg[15] & (CCBITS | R15INTBITS | R15MODEBITS))
#define R15INT (state->Reg[15] & R15INTBITS)
#define R15INTPC (state->Reg[15] & (R15INTBITS | R15PCBITS))
#define R15INTPCMODE (state->Reg[15] & (R15INTBITS | R15PCBITS | R15MODEBITS))
#define R15INTMODE (state->Reg[15] & (R15INTBITS | R15MODEBITS))
#define R15PC (state->Reg[15] & R15PCBITS)
#define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS))
#define R15MODE (state->Reg[15] & R15MODEBITS)
#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28))
#define EINT (IFFLAGS << 6)
#define ER15INT (IFFLAGS << 26)
#define EMODE (state->Mode)
#ifdef MODET
#define CPSR (ECC | EINT | EMODE | (TFLAG << 5))
#else
#define CPSR (ECC | EINT | EMODE)
#endif
#ifdef MODE32
#define PATCHR15
#else
#define PATCHR15 state->Reg[15] = ECC | ER15INT | EMODE | R15PC
#endif
#define GETSPSR(bank) bank>0?state->Spsr[bank]:ECC | EINT | EMODE ;
#define SETPSR(d,s) d = (s) & (ARMword)(CCBITS | INTBITS | MODEBITS)
#define SETINTMODE(d,s) d = ((d) & CCBITS) | ((s) & (INTBITS | MODEBITS))
#define SETCC(d,s) d = ((d) & (INTBITS | MODEBITS)) | ((s) & CCBITS)
#define SETR15PSR(s) if (state->Mode == USER26MODE) { \
state->Reg[15] = ((s) & CCBITS) | R15PC | ER15INT | EMODE ; \
ASSIGNN((state->Reg[15] & NBIT) != 0) ; \
ASSIGNZ((state->Reg[15] & ZBIT) != 0) ; \
ASSIGNC((state->Reg[15] & CBIT) != 0) ; \
ASSIGNV((state->Reg[15] & VBIT) != 0) ; \
} \
else { \
state->Reg[15] = R15PC | (s) & (CCBITS | R15INTBITS | R15MODEBITS) ; \
ARMul_R15Altered(state) ; \
}
#define SETABORT(i,m) state->Cpsr = ECC | EINT | (i) | (m)
#ifndef MODE32
#define VECTORS 0x20
#define LEGALADDR 0x03ffffff
#define VECTORACCESS(address) (address < VECTORS && ARMul_MODE26BIT && state->prog32Sig)
#define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig)
#endif
#define INTERNALABORT(address) if (address < VECTORS) \
state->Aborted = ARMul_DataAbortV ; \
else \
state->Aborted = ARMul_AddrExceptnV ;
#ifdef MODE32
#define TAKEABORT ARMul_Abort(state,ARMul_DataAbortV)
#else
#define TAKEABORT if (state->Aborted == ARMul_AddrExceptnV) \
ARMul_Abort(state,ARMul_AddrExceptnV) ; \
else \
ARMul_Abort(state,ARMul_DataAbortV)
#endif
#define CPTAKEABORT if (!state->Aborted) \
ARMul_Abort(state,ARMul_UndefinedInstrV) ; \
else if (state->Aborted == ARMul_AddrExceptnV) \
ARMul_Abort(state,ARMul_AddrExceptnV) ; \
else \
ARMul_Abort(state,ARMul_DataAbortV)
/***************************************************************************\
* Different ways to start the next instruction *
\***************************************************************************/
#define SEQ 0
#define NONSEQ 1
#define PCINCEDSEQ 2
#define PCINCEDNONSEQ 3
#define PRIMEPIPE 4
#define RESUME 8
#define NORMALCYCLE state->NextInstr = 0
#define BUSUSEDN state->NextInstr |= 1 /* the next fetch will be an N cycle */
#define BUSUSEDINCPCS state->Reg[15] += isize ; /* a standard PC inc and an S cycle */ \
state->NextInstr = (state->NextInstr & 0xff) | 2
#define BUSUSEDINCPCN state->Reg[15] += isize ; /* a standard PC inc and an N cycle */ \
state->NextInstr |= 3
#define INCPC state->Reg[15] += isize ; /* a standard PC inc */ \
state->NextInstr |= 2
#define FLUSHPIPE state->NextInstr |= PRIMEPIPE
/***************************************************************************\
* Cycle based emulation *
\***************************************************************************/
#define OUTPUTCP(i,a,b)
#define NCYCLE
#define SCYCLE
#define ICYCLE
#define CCYCLE
#define NEXTCYCLE(c)
/***************************************************************************\
* States of the cycle based state machine *
\***************************************************************************/
/***************************************************************************\
* Macros to extract parts of instructions *
\***************************************************************************/
#define DESTReg (BITS(12,15))
#define LHSReg (BITS(16,19))
#define RHSReg (BITS(0,3))
#define DEST (state->Reg[DESTReg])
#ifdef MODE32
#ifdef MODET
#define LHS ((LHSReg == 15) ? (state->Reg[15] & 0xFFFFFFFC): (state->Reg[LHSReg]))
#else
#define LHS (state->Reg[LHSReg])
#endif
#else
#define LHS ((LHSReg == 15) ? R15PC : (state->Reg[LHSReg]) )
#endif
#define MULDESTReg (BITS(16,19))
#define MULLHSReg (BITS(0,3))
#define MULRHSReg (BITS(8,11))
#define MULACCReg (BITS(12,15))
#define DPImmRHS (ARMul_ImmedTable[BITS(0,11)])
#define DPSImmRHS temp = BITS(0,11) ; \
rhs = ARMul_ImmedTable[temp] ; \
if (temp > 255) /* there was a shift */ \
ASSIGNC(rhs >> 31) ;
#ifdef MODE32
#define DPRegRHS ((BITS(4,11)==0) ? state->Reg[RHSReg] \
: GetDPRegRHS(state, instr))
#define DPSRegRHS ((BITS(4,11)==0) ? state->Reg[RHSReg] \
: GetDPSRegRHS(state, instr))
#else
#define DPRegRHS ((BITS(0,11)<15) ? state->Reg[RHSReg] \
: GetDPRegRHS(state, instr))
#define DPSRegRHS ((BITS(0,11)<15) ? state->Reg[RHSReg] \
: GetDPSRegRHS(state, instr))
#endif
#define LSBase state->Reg[LHSReg]
#define LSImmRHS (BITS(0,11))
#ifdef MODE32
#define LSRegRHS ((BITS(4,11)==0) ? state->Reg[RHSReg] \
: GetLSRegRHS(state, instr))
#else
#define LSRegRHS ((BITS(0,11)<15) ? state->Reg[RHSReg] \
: GetLSRegRHS(state, instr))
#endif
#define LSMNumRegs ((ARMword)ARMul_BitList[BITS(0,7)] + \
(ARMword)ARMul_BitList[BITS(8,15)] )
#define LSMBaseFirst ((LHSReg == 0 && BIT(0)) || \
(BIT(LHSReg) && BITS(0,LHSReg-1) == 0))
#define SWAPSRC (state->Reg[RHSReg])
#define LSCOff (BITS(0,7) << 2)
#define CPNum BITS(8,11)
/***************************************************************************\
* Macro to rotate n right by b bits *
\***************************************************************************/
#define ROTATER(n,b) (((n)>>(b))|((n)<<(32-(b))))
/***************************************************************************\
* Macros to store results of instructions *
\***************************************************************************/
#define WRITEDEST(d) if (DESTReg==15) \
WriteR15(state, d) ; \
else \
DEST = d
#define WRITESDEST(d) if (DESTReg == 15) \
WriteSR15(state, d) ; \
else { \
DEST = d ; \
ARMul_NegZero(state, d) ; \
}
#define BYTETOBUS(data) ((data & 0xff) | \
((data & 0xff) << 8) | \
((data & 0xff) << 16) | \
((data & 0xff) << 24))
#define BUSTOBYTE(address,data) \
if (state->bigendSig) \
temp = (data >> (((address ^ 3) & 3) << 3)) & 0xff ; \
else \
temp = (data >> ((address & 3) << 3)) & 0xff
#define LOADMULT(instr,address,wb) LoadMult(state,instr,address,wb)
#define LOADSMULT(instr,address,wb) LoadSMult(state,instr,address,wb)
#define STOREMULT(instr,address,wb) StoreMult(state,instr,address,wb)
#define STORESMULT(instr,address,wb) StoreSMult(state,instr,address,wb)
#define POSBRANCH ((instr & 0x7fffff) << 2)
#define NEGBRANCH (0xff000000 | ((instr & 0xffffff) << 2))
/***************************************************************************\
* Values for Emulate *
\***************************************************************************/
#define STOP 0 /* stop */
#define CHANGEMODE 1 /* change mode */
#define ONCE 2 /* execute just one interation */
#define RUN 3 /* continuous execution */
/***************************************************************************\
* Stuff that is shared across modes *
\***************************************************************************/
extern ARMword ARMul_Emulate26(ARMul_State *state) ;
extern ARMword ARMul_Emulate32(ARMul_State *state) ;
extern unsigned ARMul_MultTable[] ; /* Number of I cycles for a mult */
extern ARMword ARMul_ImmedTable[] ; /* immediate DP LHS values */
extern char ARMul_BitList[] ; /* number of bits in a byte table */
extern void ARMul_Abort26(ARMul_State *state, ARMword) ;
extern void ARMul_Abort32(ARMul_State *state, ARMword) ;
extern unsigned ARMul_NthReg(ARMword instr,unsigned number) ;
extern void ARMul_MSRCpsr(ARMul_State *state, ARMword instr, ARMword rhs) ;
extern void ARMul_NegZero(ARMul_State *state, ARMword result) ;
extern void ARMul_AddCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
extern void ARMul_AddOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
extern void ARMul_SubCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
extern void ARMul_SubOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
extern void ARMul_CPSRAltered(ARMul_State *state) ;
extern void ARMul_R15Altered(ARMul_State *state) ;
extern ARMword ARMul_SwitchMode(ARMul_State *state,ARMword oldmode, ARMword newmode) ;
extern unsigned ARMul_NthReg(ARMword instr, unsigned number) ;
extern void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address) ;
extern void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address) ;
extern void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source) ;
extern ARMword ARMul_MRC(ARMul_State *state,ARMword instr) ;
extern void ARMul_CDP(ARMul_State *state,ARMword instr) ;
extern unsigned IntPending(ARMul_State *state) ;
extern ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data) ;
#define EVENTLISTSIZE 1024L
/* Thumb support: */
typedef enum {
t_undefined, /* undefined Thumb instruction */
t_decoded, /* instruction decoded to ARM equivalent */
t_branch /* Thumb branch (already processed) */
} tdstate;
extern tdstate ARMul_ThumbDecode(ARMul_State *state,ARMword pc,ARMword tinstr, ARMword *ainstr);
/***************************************************************************\
* Macros to scrutinize instructions *
\***************************************************************************/
#define UNDEF_Test
#define UNDEF_Shift
#define UNDEF_MSRPC
#define UNDEF_MRSPC
#define UNDEF_MULPCDest
#define UNDEF_MULDestEQOp1
#define UNDEF_LSRBPC
#define UNDEF_LSRBaseEQOffWb
#define UNDEF_LSRBaseEQDestWb
#define UNDEF_LSRPCBaseWb
#define UNDEF_LSRPCOffWb
#define UNDEF_LSMNoRegs
#define UNDEF_LSMPCBase
#define UNDEF_LSMUserBankWb
#define UNDEF_LSMBaseInListWb
#define UNDEF_SWPPC
#define UNDEF_CoProHS
#define UNDEF_MCRPC
#define UNDEF_LSCPCBaseWb
#define UNDEF_UndefNotBounced
#define UNDEF_ShortInt
#define UNDEF_IllegalMode
#define UNDEF_Prog32SigChange
#define UNDEF_Data32SigChange

1351
sim/arm/armfpe.h Normal file

File diff suppressed because it is too large Load Diff

294
sim/arm/arminit.c Normal file
View File

@@ -0,0 +1,294 @@
/* arminit.c -- ARMulator initialization: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "armdefs.h"
#include "armemu.h"
/***************************************************************************\
* Definitions for the emulator architecture *
\***************************************************************************/
void ARMul_EmulateInit(void) ;
ARMul_State *ARMul_NewState(void) ;
void ARMul_Reset(ARMul_State *state) ;
ARMword ARMul_DoCycle(ARMul_State *state) ;
unsigned ARMul_DoCoPro(ARMul_State *state) ;
ARMword ARMul_DoProg(ARMul_State *state) ;
ARMword ARMul_DoInstr(ARMul_State *state) ;
void ARMul_Abort(ARMul_State *state, ARMword address) ;
unsigned ARMul_MultTable[32] = {1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,
10,10,11,11,12,12,13,13,14,14,15,15,16,16,16} ;
ARMword ARMul_ImmedTable[4096] ; /* immediate DP LHS values */
char ARMul_BitList[256] ; /* number of bits in a byte table */
/***************************************************************************\
* Call this routine once to set up the emulator's tables. *
\***************************************************************************/
void ARMul_EmulateInit(void)
{unsigned long i, j ;
for (i = 0 ; i < 4096 ; i++) { /* the values of 12 bit dp rhs's */
ARMul_ImmedTable[i] = ROTATER(i & 0xffL,(i >> 7L) & 0x1eL) ;
}
for (i = 0 ; i < 256 ; ARMul_BitList[i++] = 0 ) ; /* how many bits in LSM */
for (j = 1 ; j < 256 ; j <<= 1)
for (i = 0 ; i < 256 ; i++)
if ((i & j) > 0 )
ARMul_BitList[i]++ ;
for (i = 0 ; i < 256 ; i++)
ARMul_BitList[i] *= 4 ; /* you always need 4 times these values */
}
/***************************************************************************\
* Returns a new instantiation of the ARMulator's state *
\***************************************************************************/
ARMul_State *ARMul_NewState(void)
{ARMul_State *state ;
unsigned i, j ;
state = (ARMul_State *)malloc(sizeof(ARMul_State)) ;
memset (state, 0, sizeof (ARMul_State));
state->Emulate = RUN ;
for (i = 0 ; i < 16 ; i++) {
state->Reg[i] = 0 ;
for (j = 0 ; j < 7 ; j++)
state->RegBank[j][i] = 0 ;
}
for (i = 0 ; i < 7 ; i++)
state->Spsr[i] = 0 ;
state->Mode = 0 ;
state->CallDebug = FALSE ;
state->Debug = FALSE ;
state->VectorCatch = 0 ;
state->Aborted = FALSE ;
state->Reseted = FALSE ;
state->Inted = 3 ;
state->LastInted = 3 ;
state->MemDataPtr = NULL ;
state->MemInPtr = NULL ;
state->MemOutPtr = NULL ;
state->MemSparePtr = NULL ;
state->MemSize = 0 ;
state->OSptr = NULL ;
state->CommandLine = NULL ;
state->EventSet = 0 ;
state->Now = 0 ;
state->EventPtr = (struct EventNode **)malloc((unsigned)EVENTLISTSIZE *
sizeof(struct EventNode *)) ;
for (i = 0 ; i < EVENTLISTSIZE ; i++)
*(state->EventPtr + i) = NULL ;
#ifdef ARM61
state->prog32Sig = LOW ;
state->data32Sig = LOW ;
#else
state->prog32Sig = HIGH ;
state->data32Sig = HIGH ;
#endif
state->lateabtSig = LOW ;
state->bigendSig = LOW ;
ARMul_Reset(state) ;
return(state) ;
}
/***************************************************************************\
* Call this routine to set ARMulator to model a certain processor *
\***************************************************************************/
void ARMul_SelectProcessor(ARMul_State *state, unsigned processor) {
if (processor & ARM_Fix26_Prop) {
state->prog32Sig = LOW;
state->data32Sig = LOW;
}else{
state->prog32Sig = HIGH;
state->data32Sig = HIGH;
}
state->lateabtSig = LOW;
}
/***************************************************************************\
* Call this routine to set up the initial machine state (or perform a RESET *
\***************************************************************************/
void ARMul_Reset(ARMul_State *state)
{state->NextInstr = 0 ;
if (state->prog32Sig) {
state->Reg[15] = 0 ;
state->Cpsr = INTBITS | SVC32MODE ;
}
else {
state->Reg[15] = R15INTBITS | SVC26MODE ;
state->Cpsr = INTBITS | SVC26MODE ;
}
ARMul_CPSRAltered(state) ;
state->Bank = SVCBANK ;
FLUSHPIPE ;
state->EndCondition = 0 ;
state->ErrorCode = 0 ;
state->Exception = FALSE ;
state->NresetSig = HIGH ;
state->NfiqSig = HIGH ;
state->NirqSig = HIGH ;
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
state->abortSig = LOW ;
state->AbortAddr = 1 ;
state->NumInstrs = 0 ;
state->NumNcycles = 0 ;
state->NumScycles = 0 ;
state->NumIcycles = 0 ;
state->NumCcycles = 0 ;
state->NumFcycles = 0 ;
#ifdef ASIM
(void)ARMul_MemoryInit() ;
ARMul_OSInit(state) ;
#endif
}
/***************************************************************************\
* Emulate the execution of an entire program. Start the correct emulator *
* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the *
* address of the last instruction that is executed. *
\***************************************************************************/
ARMword ARMul_DoProg(ARMul_State *state)
{ARMword pc = 0 ;
state->Emulate = RUN ;
while (state->Emulate != STOP) {
state->Emulate = RUN ;
if (state->prog32Sig && ARMul_MODE32BIT)
pc = ARMul_Emulate32(state) ;
else
pc = ARMul_Emulate26(state) ;
}
return(pc) ;
}
/***************************************************************************\
* Emulate the execution of one instruction. Start the correct emulator *
* (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the *
* address of the instruction that is executed. *
\***************************************************************************/
ARMword ARMul_DoInstr(ARMul_State *state)
{ARMword pc = 0 ;
state->Emulate = ONCE ;
if (state->prog32Sig && ARMul_MODE32BIT)
pc = ARMul_Emulate32(state) ;
else
pc = ARMul_Emulate26(state) ;
return(pc) ;
}
/***************************************************************************\
* This routine causes an Abort to occur, including selecting the correct *
* mode, register bank, and the saving of registers. Call with the *
* appropriate vector's memory address (0,4,8 ....) *
\***************************************************************************/
void ARMul_Abort(ARMul_State *state, ARMword vector)
{ARMword temp ;
state->Aborted = FALSE ;
if (ARMul_OSException(state,vector,ARMul_GetPC(state)))
return ;
if (state->prog32Sig)
if (ARMul_MODE26BIT)
temp = R15PC ;
else
temp = state->Reg[15] ;
else
temp = R15PC | ECC | ER15INT | EMODE ;
switch (vector) {
case ARMul_ResetV : /* RESET */
state->Spsr[SVCBANK] = CPSR ;
SETABORT(INTBITS,state->prog32Sig?SVC32MODE:SVC26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp ;
break ;
case ARMul_UndefinedInstrV : /* Undefined Instruction */
state->Spsr[state->prog32Sig?UNDEFBANK:SVCBANK] = CPSR ;
SETABORT(IBIT,state->prog32Sig?UNDEF32MODE:SVC26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp - 4 ;
break ;
case ARMul_SWIV : /* Software Interrupt */
state->Spsr[SVCBANK] = CPSR ;
SETABORT(IBIT,state->prog32Sig?SVC32MODE:SVC26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp - 4 ;
break ;
case ARMul_PrefetchAbortV : /* Prefetch Abort */
state->AbortAddr = 1 ;
state->Spsr[state->prog32Sig?ABORTBANK:SVCBANK] = CPSR ;
SETABORT(IBIT,state->prog32Sig?ABORT32MODE:SVC26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp - 4 ;
break ;
case ARMul_DataAbortV : /* Data Abort */
state->Spsr[state->prog32Sig?ABORTBANK:SVCBANK] = CPSR ;
SETABORT(IBIT,state->prog32Sig?ABORT32MODE:SVC26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp - 4 ; /* the PC must have been incremented */
break ;
case ARMul_AddrExceptnV : /* Address Exception */
state->Spsr[SVCBANK] = CPSR ;
SETABORT(IBIT,SVC26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp - 4 ;
break ;
case ARMul_IRQV : /* IRQ */
state->Spsr[IRQBANK] = CPSR ;
SETABORT(IBIT,state->prog32Sig?IRQ32MODE:IRQ26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp - 4 ;
break ;
case ARMul_FIQV : /* FIQ */
state->Spsr[FIQBANK] = CPSR ;
SETABORT(INTBITS,state->prog32Sig?FIQ32MODE:FIQ26MODE) ;
ARMul_CPSRAltered(state) ;
state->Reg[14] = temp - 4 ;
break ;
}
if (ARMul_MODE32BIT)
ARMul_SetR15(state,vector) ;
else
ARMul_SetR15(state,R15CCINTMODE | vector) ;
}

23
sim/arm/armopts.h Normal file
View File

@@ -0,0 +1,23 @@
/* armopts.h -- ARMulator configuration options: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Define one of ARM60 or ARM61 */
#ifndef ARM60
#ifndef ARM61
#define ARM60
#endif
#endif

1136
sim/arm/armos.c Normal file

File diff suppressed because it is too large Load Diff

95
sim/arm/armos.h Normal file
View File

@@ -0,0 +1,95 @@
/* armos.h -- ARMulator OS definitions: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/***************************************************************************\
* Define the initial layout of memory *
\***************************************************************************/
#define ADDRSUPERSTACK 0x800L /* supervisor stack space */
#define ADDRUSERSTACK 0x80000L /* default user stack start */
#define ADDRSOFTVECTORS 0x840L /* soft vectors are here */
#define ADDRCMDLINE 0xf00L /* command line is here after a SWI GetEnv */
#define ADDRSOFHANDLERS 0xad0L /* address and workspace for installed handlers */
#define SOFTVECTORCODE 0xb80L /* default handlers */
/***************************************************************************\
* SWI numbers *
\***************************************************************************/
#define SWI_WriteC 0x0
#define SWI_Write0 0x2
#define SWI_ReadC 0x4
#define SWI_CLI 0x5
#define SWI_GetEnv 0x10
#define SWI_Exit 0x11
#define SWI_EnterOS 0x16
#define SWI_GetErrno 0x60
#define SWI_Clock 0x61
#define SWI_Time 0x63
#define SWI_Remove 0x64
#define SWI_Rename 0x65
#define SWI_Open 0x66
#define SWI_Close 0x68
#define SWI_Write 0x69
#define SWI_Read 0x6a
#define SWI_Seek 0x6b
#define SWI_Flen 0x6c
#define SWI_IsTTY 0x6e
#define SWI_TmpNam 0x6f
#define SWI_InstallHandler 0x70
#define SWI_GenerateError 0x71
#define SWI_Breakpoint 0x180000 /* see gdb's tm-arm.h */
#define AngelSWI_ARM 0x123456
#define AngelSWI_Thumb 0xAB
/* The reason codes: */
#define AngelSWI_Reason_Open (0x01)
#define AngelSWI_Reason_Close (0x02)
#define AngelSWI_Reason_WriteC (0x03)
#define AngelSWI_Reason_Write0 (0x04)
#define AngelSWI_Reason_Write (0x05)
#define AngelSWI_Reason_Read (0x06)
#define AngelSWI_Reason_ReadC (0x07)
#define AngelSWI_Reason_IsTTY (0x09)
#define AngelSWI_Reason_Seek (0x0A)
#define AngelSWI_Reason_FLen (0x0C)
#define AngelSWI_Reason_TmpNam (0x0D)
#define AngelSWI_Reason_Remove (0x0E)
#define AngelSWI_Reason_Rename (0x0F)
#define AngelSWI_Reason_Clock (0x10)
#define AngelSWI_Reason_Time (0x11)
#define AngelSWI_Reason_System (0x12)
#define AngelSWI_Reason_Errno (0x13)
#define AngelSWI_Reason_GetCmdLine (0x15)
#define AngelSWI_Reason_HeapInfo (0x16)
#define AngelSWI_Reason_EnterSVC (0x17)
#define AngelSWI_Reason_ReportException (0x18)
#define ADP_Stopped_ApplicationExit ((2 << 16) + 38)
#define ADP_Stopped_RunTimeError ((2 << 16) + 34)
#define FPESTART 0x2000L
#define FPEEND 0x8000L
#define FPEOLDVECT FPESTART + 0x100L + 8L * 16L + 4L /* stack + 8 regs + fpsr */
#define FPENEWVECT(addr) 0xea000000L + ((addr) >> 2) - 3L /* branch from 4 to 0x2400 */
extern unsigned long fpecode[] ;
extern unsigned long fpesize ;

1044
sim/arm/armrdi.c Normal file

File diff suppressed because it is too large Load Diff

712
sim/arm/armsupp.c Normal file
View File

@@ -0,0 +1,712 @@
/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "armdefs.h"
#include "armemu.h"
/***************************************************************************\
* Definitions for the support routines *
\***************************************************************************/
ARMword ARMul_GetReg(ARMul_State *state, unsigned mode, unsigned reg) ;
void ARMul_SetReg(ARMul_State *state, unsigned mode, unsigned reg, ARMword value) ;
ARMword ARMul_GetPC(ARMul_State *state) ;
ARMword ARMul_GetNextPC(ARMul_State *state) ;
void ARMul_SetPC(ARMul_State *state, ARMword value) ;
ARMword ARMul_GetR15(ARMul_State *state) ;
void ARMul_SetR15(ARMul_State *state, ARMword value) ;
ARMword ARMul_GetCPSR(ARMul_State *state) ;
void ARMul_SetCPSR(ARMul_State *state, ARMword value) ;
void ARMul_FixCPSR(ARMul_State *state, ARMword instr, ARMword rhs) ;
ARMword ARMul_GetSPSR(ARMul_State *state, ARMword mode) ;
void ARMul_SetSPSR(ARMul_State *state, ARMword mode, ARMword value) ;
void ARMul_FixSPSR(ARMul_State *state, ARMword instr, ARMword rhs) ;
void ARMul_CPSRAltered(ARMul_State *state) ;
void ARMul_R15Altered(ARMul_State *state) ;
ARMword ARMul_SwitchMode(ARMul_State *state,ARMword oldmode, ARMword newmode) ;
static ARMword ModeToBank(ARMul_State *state,ARMword mode) ;
unsigned ARMul_NthReg(ARMword instr, unsigned number) ;
void ARMul_NegZero(ARMul_State *state, ARMword result) ;
void ARMul_AddCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
void ARMul_AddOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
void ARMul_SubCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
void ARMul_SubOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address) ;
void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address) ;
void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source) ;
ARMword ARMul_MRC(ARMul_State *state,ARMword instr) ;
void ARMul_CDP(ARMul_State *state,ARMword instr) ;
void ARMul_UndefInstr(ARMul_State *state,ARMword instr) ;
unsigned IntPending(ARMul_State *state) ;
ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data) ;
void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay,
unsigned (*what)()) ;
void ARMul_EnvokeEvent(ARMul_State *state) ;
unsigned long ARMul_Time(ARMul_State *state) ;
static void EnvokeList(ARMul_State *state, unsigned long from, unsigned long to) ;
struct EventNode { /* An event list node */
unsigned (*func)() ; /* The function to call */
struct EventNode *next ;
} ;
/***************************************************************************\
* This routine returns the value of a register from a mode. *
\***************************************************************************/
ARMword ARMul_GetReg(ARMul_State *state, unsigned mode, unsigned reg)
{mode &= MODEBITS ;
if (mode != state->Mode)
return(state->RegBank[ModeToBank(state,(ARMword)mode)][reg]) ;
else
return(state->Reg[reg]) ;
}
/***************************************************************************\
* This routine sets the value of a register for a mode. *
\***************************************************************************/
void ARMul_SetReg(ARMul_State *state, unsigned mode, unsigned reg, ARMword value)
{mode &= MODEBITS ;
if (mode != state->Mode)
state->RegBank[ModeToBank(state,(ARMword)mode)][reg] = value ;
else
state->Reg[reg] = value ;
}
/***************************************************************************\
* This routine returns the value of the PC, mode independently. *
\***************************************************************************/
ARMword ARMul_GetPC(ARMul_State *state)
{if (state->Mode > SVC26MODE)
return(state->Reg[15]) ;
else
return(R15PC) ;
}
/***************************************************************************\
* This routine returns the value of the PC, mode independently. *
\***************************************************************************/
ARMword ARMul_GetNextPC(ARMul_State *state)
{if (state->Mode > SVC26MODE)
return(state->Reg[15] + isize) ;
else
return((state->Reg[15] + isize) & R15PCBITS) ;
}
/***************************************************************************\
* This routine sets the value of the PC. *
\***************************************************************************/
void ARMul_SetPC(ARMul_State *state, ARMword value)
{if (ARMul_MODE32BIT)
state->Reg[15] = value & PCBITS ;
else
state->Reg[15] = R15CCINTMODE | (value & R15PCBITS) ;
FLUSHPIPE ;
}
/***************************************************************************\
* This routine returns the value of register 15, mode independently. *
\***************************************************************************/
ARMword ARMul_GetR15(ARMul_State *state)
{if (state->Mode > SVC26MODE)
return(state->Reg[15]) ;
else
return(R15PC | ECC | ER15INT | EMODE) ;
}
/***************************************************************************\
* This routine sets the value of Register 15. *
\***************************************************************************/
void ARMul_SetR15(ARMul_State *state, ARMword value)
{
if (ARMul_MODE32BIT)
state->Reg[15] = value & PCBITS ;
else {
state->Reg[15] = value ;
ARMul_R15Altered(state) ;
}
FLUSHPIPE ;
}
/***************************************************************************\
* This routine returns the value of the CPSR *
\***************************************************************************/
ARMword ARMul_GetCPSR(ARMul_State *state)
{
return(CPSR) ;
}
/***************************************************************************\
* This routine sets the value of the CPSR *
\***************************************************************************/
void ARMul_SetCPSR(ARMul_State *state, ARMword value)
{state->Cpsr = CPSR ;
SETPSR(state->Cpsr,value) ;
ARMul_CPSRAltered(state) ;
}
/***************************************************************************\
* This routine does all the nasty bits involved in a write to the CPSR, *
* including updating the register bank, given a MSR instruction. *
\***************************************************************************/
void ARMul_FixCPSR(ARMul_State *state, ARMword instr, ARMword rhs)
{state->Cpsr = CPSR ;
if (state->Bank==USERBANK) { /* Only write flags in user mode */
if (BIT(19)) {
SETCC(state->Cpsr,rhs) ;
}
}
else { /* Not a user mode */
if (BITS(16,19)==9) SETPSR(state->Cpsr,rhs) ;
else if (BIT(16)) SETINTMODE(state->Cpsr,rhs) ;
else if (BIT(19)) SETCC(state->Cpsr,rhs) ;
}
ARMul_CPSRAltered(state) ;
}
/***************************************************************************\
* Get an SPSR from the specified mode *
\***************************************************************************/
ARMword ARMul_GetSPSR(ARMul_State *state, ARMword mode)
{ARMword bank = ModeToBank(state,mode & MODEBITS) ;
if (bank == USERBANK || bank == DUMMYBANK)
return(CPSR) ;
else
return(state->Spsr[bank]) ;
}
/***************************************************************************\
* This routine does a write to an SPSR *
\***************************************************************************/
void ARMul_SetSPSR(ARMul_State *state, ARMword mode, ARMword value)
{ARMword bank = ModeToBank(state,mode & MODEBITS) ;
if (bank != USERBANK && bank !=DUMMYBANK)
state->Spsr[bank] = value ;
}
/***************************************************************************\
* This routine does a write to the current SPSR, given an MSR instruction *
\***************************************************************************/
void ARMul_FixSPSR(ARMul_State *state, ARMword instr, ARMword rhs)
{if (state->Bank != USERBANK && state->Bank !=DUMMYBANK) {
if (BITS(16,19)==9) SETPSR(state->Spsr[state->Bank],rhs) ;
else if (BIT(16)) SETINTMODE(state->Spsr[state->Bank],rhs) ;
else if (BIT(19)) SETCC(state->Spsr[state->Bank],rhs) ;
}
}
/***************************************************************************\
* This routine updates the state of the emulator after the Cpsr has been *
* changed. Both the processor flags and register bank are updated. *
\***************************************************************************/
void ARMul_CPSRAltered(ARMul_State *state)
{ARMword oldmode ;
if (state->prog32Sig == LOW)
state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS) ;
oldmode = state->Mode ;
if (state->Mode != (state->Cpsr & MODEBITS)) {
state->Mode = ARMul_SwitchMode(state,state->Mode,state->Cpsr & MODEBITS) ;
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
}
ASSIGNINT(state->Cpsr & INTBITS) ;
ASSIGNN((state->Cpsr & NBIT) != 0) ;
ASSIGNZ((state->Cpsr & ZBIT) != 0) ;
ASSIGNC((state->Cpsr & CBIT) != 0) ;
ASSIGNV((state->Cpsr & VBIT) != 0) ;
#ifdef MODET
ASSIGNT((state->Cpsr & TBIT) != 0);
#endif
if (oldmode > SVC26MODE) {
if (state->Mode <= SVC26MODE) {
state->Emulate = CHANGEMODE ;
state->Reg[15] = ECC | ER15INT | EMODE | R15PC ;
}
}
else {
if (state->Mode > SVC26MODE) {
state->Emulate = CHANGEMODE ;
state->Reg[15] = R15PC ;
}
else
state->Reg[15] = ECC | ER15INT | EMODE | R15PC ;
}
}
/***************************************************************************\
* This routine updates the state of the emulator after register 15 has *
* been changed. Both the processor flags and register bank are updated. *
* This routine should only be called from a 26 bit mode. *
\***************************************************************************/
void ARMul_R15Altered(ARMul_State *state)
{
if (state->Mode != R15MODE) {
state->Mode = ARMul_SwitchMode(state,state->Mode,R15MODE) ;
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
}
if (state->Mode > SVC26MODE)
state->Emulate = CHANGEMODE ;
ASSIGNR15INT(R15INT) ;
ASSIGNN((state->Reg[15] & NBIT) != 0) ;
ASSIGNZ((state->Reg[15] & ZBIT) != 0) ;
ASSIGNC((state->Reg[15] & CBIT) != 0) ;
ASSIGNV((state->Reg[15] & VBIT) != 0) ;
}
/***************************************************************************\
* This routine controls the saving and restoring of registers across mode *
* changes. The regbank matrix is largely unused, only rows 13 and 14 are *
* used across all modes, 8 to 14 are used for FIQ, all others use the USER *
* column. It's easier this way. old and new parameter are modes numbers. *
* Notice the side effect of changing the Bank variable. *
\***************************************************************************/
ARMword ARMul_SwitchMode(ARMul_State *state,ARMword oldmode, ARMword newmode)
{unsigned i ;
oldmode = ModeToBank(state,oldmode) ;
state->Bank = ModeToBank(state,newmode) ;
if (oldmode != state->Bank) { /* really need to do it */
switch (oldmode) { /* save away the old registers */
case USERBANK :
case IRQBANK :
case SVCBANK :
case ABORTBANK :
case UNDEFBANK : if (state->Bank == FIQBANK)
for (i = 8 ; i < 13 ; i++)
state->RegBank[USERBANK][i] = state->Reg[i] ;
state->RegBank[oldmode][13] = state->Reg[13] ;
state->RegBank[oldmode][14] = state->Reg[14] ;
break ;
case FIQBANK : for (i = 8 ; i < 15 ; i++)
state->RegBank[FIQBANK][i] = state->Reg[i] ;
break ;
case DUMMYBANK : for (i = 8 ; i < 15 ; i++)
state->RegBank[DUMMYBANK][i] = 0 ;
break ;
}
switch (state->Bank) { /* restore the new registers */
case USERBANK :
case IRQBANK :
case SVCBANK :
case ABORTBANK :
case UNDEFBANK : if (oldmode == FIQBANK)
for (i = 8 ; i < 13 ; i++)
state->Reg[i] = state->RegBank[USERBANK][i] ;
state->Reg[13] = state->RegBank[state->Bank][13] ;
state->Reg[14] = state->RegBank[state->Bank][14] ;
break ;
case FIQBANK : for (i = 8 ; i < 15 ; i++)
state->Reg[i] = state->RegBank[FIQBANK][i] ;
break ;
case DUMMYBANK : for (i = 8 ; i < 15 ; i++)
state->Reg[i] = 0 ;
break ;
} /* switch */
} /* if */
return(newmode) ;
}
/***************************************************************************\
* Given a processor mode, this routine returns the register bank that *
* will be accessed in that mode. *
\***************************************************************************/
static ARMword ModeToBank(ARMul_State *state, ARMword mode)
{static ARMword bankofmode[] = {USERBANK, FIQBANK, IRQBANK, SVCBANK,
DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
USERBANK, FIQBANK, IRQBANK, SVCBANK,
DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK
} ;
if (mode > UNDEF32MODE)
return(DUMMYBANK) ;
else
return(bankofmode[mode]) ;
}
/***************************************************************************\
* Returns the register number of the nth register in a reg list. *
\***************************************************************************/
unsigned ARMul_NthReg(ARMword instr, unsigned number)
{unsigned bit, upto ;
for (bit = 0, upto = 0 ; upto <= number ; bit++)
if (BIT(bit)) upto++ ;
return(bit - 1) ;
}
/***************************************************************************\
* Assigns the N and Z flags depending on the value of result *
\***************************************************************************/
void ARMul_NegZero(ARMul_State *state, ARMword result)
{
if (NEG(result)) { SETN ; CLEARZ ; }
else if (result == 0) { CLEARN ; SETZ ; }
else { CLEARN ; CLEARZ ; } ;
}
/***************************************************************************\
* Assigns the C flag after an addition of a and b to give result *
\***************************************************************************/
void ARMul_AddCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result)
{
ASSIGNC( (NEG(a) && NEG(b)) ||
(NEG(a) && POS(result)) ||
(NEG(b) && POS(result)) ) ;
}
/***************************************************************************\
* Assigns the V flag after an addition of a and b to give result *
\***************************************************************************/
void ARMul_AddOverflow(ARMul_State *state, ARMword a,ARMword b,ARMword result)
{
ASSIGNV( (NEG(a) && NEG(b) && POS(result)) ||
(POS(a) && POS(b) && NEG(result)) ) ;
}
/***************************************************************************\
* Assigns the C flag after an subtraction of a and b to give result *
\***************************************************************************/
void ARMul_SubCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result)
{
ASSIGNC( (NEG(a) && POS(b)) ||
(NEG(a) && POS(result)) ||
(POS(b) && POS(result)) ) ;
}
/***************************************************************************\
* Assigns the V flag after an subtraction of a and b to give result *
\***************************************************************************/
void ARMul_SubOverflow(ARMul_State *state,ARMword a,ARMword b,ARMword result)
{
ASSIGNV( (NEG(a) && POS(b) && POS(result)) ||
(POS(a) && NEG(b) && NEG(result)) ) ;
}
/***************************************************************************\
* This function does the work of generating the addresses used in an *
* LDC instruction. The code here is always post-indexed, it's up to the *
* caller to get the input address correct and to handle base register *
* modification. It also handles the Busy-Waiting. *
\***************************************************************************/
void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address)
{unsigned cpab ;
ARMword data ;
UNDEF_LSCPCBaseWb ;
if (ADDREXCEPT(address)) {
INTERNALABORT(address) ;
}
cpab = (state->LDC[CPNum])(state,ARMul_FIRST,instr,0) ;
while (cpab == ARMul_BUSY) {
ARMul_Icycles(state,1,0) ;
if (IntPending(state)) {
cpab = (state->LDC[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
return ;
}
else
cpab = (state->LDC[CPNum])(state,ARMul_BUSY,instr,0) ;
}
if (cpab == ARMul_CANT) {
CPTAKEABORT ;
return ;
}
cpab = (state->LDC[CPNum])(state,ARMul_TRANSFER,instr,0) ;
data = ARMul_LoadWordN(state,address) ;
BUSUSEDINCPCN ;
if (BIT(21))
LSBase = state->Base ;
cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ;
while (cpab == ARMul_INC) {
address += 4 ;
data = ARMul_LoadWordN(state,address) ;
cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ;
}
if (state->abortSig || state->Aborted) {
TAKEABORT ;
}
}
/***************************************************************************\
* This function does the work of generating the addresses used in an *
* STC instruction. The code here is always post-indexed, it's up to the *
* caller to get the input address correct and to handle base register *
* modification. It also handles the Busy-Waiting. *
\***************************************************************************/
void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address)
{unsigned cpab ;
ARMword data ;
UNDEF_LSCPCBaseWb ;
if (ADDREXCEPT(address) || VECTORACCESS(address)) {
INTERNALABORT(address) ;
}
cpab = (state->STC[CPNum])(state,ARMul_FIRST,instr,&data) ;
while (cpab == ARMul_BUSY) {
ARMul_Icycles(state,1,0) ;
if (IntPending(state)) {
cpab = (state->STC[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
return ;
}
else
cpab = (state->STC[CPNum])(state,ARMul_BUSY,instr,&data) ;
}
if (cpab == ARMul_CANT) {
CPTAKEABORT ;
return ;
}
#ifndef MODE32
if (ADDREXCEPT(address) || VECTORACCESS(address)) {
INTERNALABORT(address) ;
}
#endif
BUSUSEDINCPCN ;
if (BIT(21))
LSBase = state->Base ;
cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ;
ARMul_StoreWordN(state,address,data) ;
while (cpab == ARMul_INC) {
address += 4 ;
cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ;
ARMul_StoreWordN(state,address,data) ;
}
if (state->abortSig || state->Aborted) {
TAKEABORT ;
}
}
/***************************************************************************\
* This function does the Busy-Waiting for an MCR instruction. *
\***************************************************************************/
void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source)
{unsigned cpab ;
cpab = (state->MCR[CPNum])(state,ARMul_FIRST,instr,source) ;
while (cpab == ARMul_BUSY) {
ARMul_Icycles(state,1,0) ;
if (IntPending(state)) {
cpab = (state->MCR[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
return ;
}
else
cpab = (state->MCR[CPNum])(state,ARMul_BUSY,instr,source) ;
}
if (cpab == ARMul_CANT)
ARMul_Abort(state,ARMul_UndefinedInstrV) ;
else {
BUSUSEDINCPCN ;
ARMul_Ccycles(state,1,0) ;
}
}
/***************************************************************************\
* This function does the Busy-Waiting for an MRC instruction. *
\***************************************************************************/
ARMword ARMul_MRC(ARMul_State *state,ARMword instr)
{unsigned cpab ;
ARMword result = 0 ;
cpab = (state->MRC[CPNum])(state,ARMul_FIRST,instr,&result) ;
while (cpab == ARMul_BUSY) {
ARMul_Icycles(state,1,0) ;
if (IntPending(state)) {
cpab = (state->MRC[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
return(0) ;
}
else
cpab = (state->MRC[CPNum])(state,ARMul_BUSY,instr,&result) ;
}
if (cpab == ARMul_CANT) {
ARMul_Abort(state,ARMul_UndefinedInstrV) ;
result = ECC ; /* Parent will destroy the flags otherwise */
}
else {
BUSUSEDINCPCN ;
ARMul_Ccycles(state,1,0) ;
ARMul_Icycles(state,1,0) ;
}
return(result) ;
}
/***************************************************************************\
* This function does the Busy-Waiting for an CDP instruction. *
\***************************************************************************/
void ARMul_CDP(ARMul_State *state,ARMword instr)
{unsigned cpab ;
cpab = (state->CDP[CPNum])(state,ARMul_FIRST,instr) ;
while (cpab == ARMul_BUSY) {
ARMul_Icycles(state,1,0) ;
if (IntPending(state)) {
cpab = (state->CDP[CPNum])(state,ARMul_INTERRUPT,instr) ;
return ;
}
else
cpab = (state->CDP[CPNum])(state,ARMul_BUSY,instr) ;
}
if (cpab == ARMul_CANT)
ARMul_Abort(state,ARMul_UndefinedInstrV) ;
else
BUSUSEDN ;
}
/***************************************************************************\
* This function handles Undefined instructions, as CP isntruction *
\***************************************************************************/
void ARMul_UndefInstr(ARMul_State *state,ARMword instr)
{
ARMul_Abort(state,ARMul_UndefinedInstrV) ;
}
/***************************************************************************\
* Return TRUE if an interrupt is pending, FALSE otherwise. *
\***************************************************************************/
unsigned IntPending(ARMul_State *state)
{
if (state->Exception) { /* Any exceptions */
if (state->NresetSig == LOW) {
ARMul_Abort(state,ARMul_ResetV) ;
return(TRUE) ;
}
else if (!state->NfiqSig && !FFLAG) {
ARMul_Abort(state,ARMul_FIQV) ;
return(TRUE) ;
}
else if (!state->NirqSig && !IFLAG) {
ARMul_Abort(state,ARMul_IRQV) ;
return(TRUE) ;
}
}
return(FALSE) ;
}
/***************************************************************************\
* Align a word access to a non word boundary *
\***************************************************************************/
ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data)
{/* this code assumes the address is really unaligned,
as a shift by 32 is undefined in C */
address = (address & 3) << 3 ; /* get the word address */
return( ( data >> address) | (data << (32 - address)) ) ; /* rot right */
}
/***************************************************************************\
* This routine is used to call another routine after a certain number of *
* cycles have been executed. The first parameter is the number of cycles *
* delay before the function is called, the second argument is a pointer *
* to the function. A delay of zero doesn't work, just call the function. *
\***************************************************************************/
void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay, unsigned (*what)())
{unsigned long when ;
struct EventNode *event ;
if (state->EventSet++ == 0)
state->Now = ARMul_Time(state) ;
when = (state->Now + delay) % EVENTLISTSIZE ;
event = (struct EventNode *)malloc(sizeof(struct EventNode)) ;
event->func = what ;
event->next = *(state->EventPtr + when) ;
*(state->EventPtr + when) = event ;
}
/***************************************************************************\
* This routine is called at the beginning of every cycle, to envoke *
* scheduled events. *
\***************************************************************************/
void ARMul_EnvokeEvent(ARMul_State *state)
{static unsigned long then ;
then = state->Now ;
state->Now = ARMul_Time(state) % EVENTLISTSIZE ;
if (then < state->Now) /* schedule events */
EnvokeList(state,then,state->Now) ;
else if (then > state->Now) { /* need to wrap around the list */
EnvokeList(state,then,EVENTLISTSIZE-1L) ;
EnvokeList(state,0L,state->Now) ;
}
}
static void EnvokeList(ARMul_State *state, unsigned long from, unsigned long to)
/* envokes all the entries in a range */
{struct EventNode *anevent ;
for (; from <= to ; from++) {
anevent = *(state->EventPtr + from) ;
while (anevent) {
(anevent->func)(state) ;
state->EventSet-- ;
anevent = anevent->next ;
}
*(state->EventPtr + from) = NULL ;
}
}
/***************************************************************************\
* This routine is returns the number of clock ticks since the last reset. *
\***************************************************************************/
unsigned long ARMul_Time(ARMul_State *state)
{return(state->NumScycles + state->NumNcycles +
state->NumIcycles + state->NumCcycles + state->NumFcycles) ;
}

491
sim/arm/armvirt.c Normal file
View File

@@ -0,0 +1,491 @@
/* armvirt.c -- ARMulator virtual memory interace: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file contains a complete ARMulator memory model, modelling a
"virtual memory" system. A much simpler model can be found in armfast.c,
and that model goes faster too, but has a fixed amount of memory. This
model's memory has 64K pages, allocated on demand from a 64K entry page
table. The routines PutWord and GetWord implement this. Pages are never
freed as they might be needed again. A single area of memory may be
defined to generate aborts. */
#include "armopts.h"
#include "armdefs.h"
#ifdef VALIDATE /* for running the validate suite */
#define TUBE 48 * 1024 * 1024 /* write a char on the screen */
#define ABORTS 1
#endif
#define ABORTS
#ifdef ABORTS /* the memory system will abort */
/* For the old test suite Abort between 32 Kbytes and 32 Mbytes
For the new test suite Abort between 8 Mbytes and 26 Mbytes */
/* #define LOWABORT 32 * 1024
#define HIGHABORT 32 * 1024 * 1024 */
#define LOWABORT 8 * 1024 * 1024
#define HIGHABORT 26 * 1024 * 1024
#endif
#define NUMPAGES 64 * 1024
#define PAGESIZE 64 * 1024
#define PAGEBITS 16
#define OFFSETBITS 0xffff
/***************************************************************************\
* Get a Word from Virtual Memory, maybe allocating the page *
\***************************************************************************/
static ARMword
GetWord (ARMul_State * state, ARMword address)
{
ARMword page;
ARMword offset;
ARMword ** pagetable;
ARMword * pageptr;
page = address >> PAGEBITS;
offset = (address & OFFSETBITS) >> 2;
pagetable = (ARMword **) state->MemDataPtr;
pageptr = *(pagetable + page);
if (pageptr == NULL)
{
pageptr = (ARMword *) malloc (PAGESIZE);
if (pageptr == NULL)
{
perror ("ARMulator can't allocate VM page");
exit (12);
}
*(pagetable + page) = pageptr;
}
return *(pageptr + offset);
}
/***************************************************************************\
* Put a Word into Virtual Memory, maybe allocating the page *
\***************************************************************************/
static void
PutWord (ARMul_State * state, ARMword address, ARMword data)
{
ARMword page;
ARMword offset;
ARMword ** pagetable;
ARMword * pageptr;
page = address >> PAGEBITS;
offset = (address & OFFSETBITS) >> 2;
pagetable = (ARMword **)state->MemDataPtr;
pageptr = *(pagetable + page);
if (pageptr == NULL)
{
pageptr = (ARMword *) malloc (PAGESIZE);
if (pageptr == NULL)
{
perror ("ARMulator can't allocate VM page");
exit(13);
}
*(pagetable + page) = pageptr;
}
*(pageptr + offset) = data;
}
/***************************************************************************\
* Initialise the memory interface *
\***************************************************************************/
unsigned
ARMul_MemoryInit (ARMul_State * state, unsigned long initmemsize)
{
ARMword ** pagetable;
unsigned page;
if (initmemsize)
state->MemSize = initmemsize;
pagetable = (ARMword **) malloc (sizeof (ARMword) * NUMPAGES);
if (pagetable == NULL)
return FALSE;
for (page = 0 ; page < NUMPAGES ; page++)
*(pagetable + page) = NULL;
state->MemDataPtr = (unsigned char *)pagetable;
ARMul_ConsolePrint (state, ", 4 Gb memory");
return TRUE;
}
/***************************************************************************\
* Remove the memory interface *
\***************************************************************************/
void
ARMul_MemoryExit (ARMul_State * state)
{
ARMword page;
ARMword ** pagetable;
ARMword * pageptr;
pagetable = (ARMword **)state->MemDataPtr;
for (page = 0 ; page < NUMPAGES ; page++)
{
pageptr = *(pagetable + page);
if (pageptr != NULL)
free ((char *)pageptr);
}
free ((char *)pagetable);
return;
}
/***************************************************************************\
* ReLoad Instruction *
\***************************************************************************/
ARMword
ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize)
{
#ifdef ABORTS
if (address >= LOWABORT && address < HIGHABORT)
{
ARMul_PREFETCHABORT (address);
return ARMul_ABORTWORD;
}
else
{
ARMul_CLEARABORT;
}
#endif
if ((isize == 2) && (address & 0x2))
{
/* We return the next two halfwords: */
ARMword lo = GetWord (state, address);
ARMword hi = GetWord (state, address + 4);
if (state->bigendSig == HIGH)
return (lo << 16) | (hi >> 16);
else
return ((hi & 0xFFFF) << 16) | (lo >> 16);
}
return GetWord (state, address);
}
/***************************************************************************\
* Load Instruction, Sequential Cycle *
\***************************************************************************/
ARMword
ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize)
{
state->NumScycles ++;
#ifdef HOURGLASS
if (( state->NumScycles & HOURGLASS_RATE ) == 0)
{
HOURGLASS;
}
#endif
return ARMul_ReLoadInstr (state, address, isize);
}
/***************************************************************************\
* Load Instruction, Non Sequential Cycle *
\***************************************************************************/
ARMword
ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize)
{
state->NumNcycles ++;
return ARMul_ReLoadInstr (state, address, isize);
}
/***************************************************************************\
* Read Word (but don't tell anyone!) *
\***************************************************************************/
ARMword
ARMul_ReadWord (ARMul_State * state, ARMword address)
{
#ifdef ABORTS
if (address >= LOWABORT && address < HIGHABORT)
{
ARMul_DATAABORT (address);
return ARMul_ABORTWORD;
}
else
{
ARMul_CLEARABORT;
}
#endif
return GetWord (state, address);
}
/***************************************************************************\
* Load Word, Sequential Cycle *
\***************************************************************************/
ARMword
ARMul_LoadWordS (ARMul_State * state, ARMword address)
{
state->NumScycles ++;
return ARMul_ReadWord (state, address);
}
/***************************************************************************\
* Load Word, Non Sequential Cycle *
\***************************************************************************/
ARMword
ARMul_LoadWordN (ARMul_State * state, ARMword address)
{
state->NumNcycles ++;
return ARMul_ReadWord (state, address);
}
/***************************************************************************\
* Load Halfword, (Non Sequential Cycle) *
\***************************************************************************/
ARMword
ARMul_LoadHalfWord (ARMul_State * state, ARMword address)
{
ARMword temp, offset;
state->NumNcycles ++;
temp = ARMul_ReadWord (state, address);
offset = (((ARMword)state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */
return (temp >> offset) & 0xffff;
}
/***************************************************************************\
* Read Byte (but don't tell anyone!) *
\***************************************************************************/
ARMword
ARMul_ReadByte (ARMul_State * state, ARMword address)
{
ARMword temp, offset;
temp = ARMul_ReadWord (state, address);
offset = (((ARMword)state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */
return (temp >> offset & 0xffL);
}
/***************************************************************************\
* Load Byte, (Non Sequential Cycle) *
\***************************************************************************/
ARMword
ARMul_LoadByte (ARMul_State * state, ARMword address)
{
state->NumNcycles ++;
return ARMul_ReadByte (state, address);
}
/***************************************************************************\
* Write Word (but don't tell anyone!) *
\***************************************************************************/
void
ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data)
{
#ifdef ABORTS
if (address >= LOWABORT && address < HIGHABORT)
{
ARMul_DATAABORT (address);
return;
}
else
{
ARMul_CLEARABORT;
}
#endif
PutWord (state, address, data);
}
/***************************************************************************\
* Store Word, Sequential Cycle *
\***************************************************************************/
void
ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data)
{
state->NumScycles ++;
ARMul_WriteWord (state, address, data);
}
/***************************************************************************\
* Store Word, Non Sequential Cycle *
\***************************************************************************/
void
ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data)
{
state->NumNcycles ++;
ARMul_WriteWord (state, address, data);
}
/***************************************************************************\
* Store HalfWord, (Non Sequential Cycle) *
\***************************************************************************/
void
ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data)
{
ARMword temp, offset;
state->NumNcycles ++;
#ifdef VALIDATE
if (address == TUBE)
{
if (data == 4)
state->Emulate = FALSE;
else
(void) putc ((char)data, stderr); /* Write Char */
return;
}
#endif
temp = ARMul_ReadWord (state, address);
offset = (((ARMword)state->bigendSig * 2) ^ (address & 2)) << 3; /* bit offset into the word */
PutWord (state, address, (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << offset));
}
/***************************************************************************\
* Write Byte (but don't tell anyone!) *
\***************************************************************************/
void
ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data)
{
ARMword temp, offset;
temp = ARMul_ReadWord (state, address);
offset = (((ARMword)state->bigendSig * 3) ^ (address & 3)) << 3; /* bit offset into the word */
PutWord (state, address, (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset));
}
/***************************************************************************\
* Store Byte, (Non Sequential Cycle) *
\***************************************************************************/
void
ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data)
{
state->NumNcycles ++;
#ifdef VALIDATE
if (address == TUBE)
{
if (data == 4)
state->Emulate = FALSE;
else
(void) putc ((char)data,stderr); /* Write Char */
return;
}
#endif
ARMul_WriteByte (state, address, data);
}
/***************************************************************************\
* Swap Word, (Two Non Sequential Cycles) *
\***************************************************************************/
ARMword
ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data)
{
ARMword temp;
state->NumNcycles ++;
temp = ARMul_ReadWord (state, address);
state->NumNcycles ++;
PutWord (state, address, data);
return temp;
}
/***************************************************************************\
* Swap Byte, (Two Non Sequential Cycles) *
\***************************************************************************/
ARMword
ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data)
{
ARMword temp;
temp = ARMul_LoadByte (state, address);
ARMul_StoreByte (state, address, data);
return temp;
}
/***************************************************************************\
* Count I Cycles *
\***************************************************************************/
void
ARMul_Icycles (ARMul_State * state, unsigned number, ARMword address)
{
state->NumIcycles += number;
ARMul_CLEARABORT;
}
/***************************************************************************\
* Count C Cycles *
\***************************************************************************/
void
ARMul_Ccycles (ARMul_State * state, unsigned number, ARMword address)
{
state->NumCcycles += number;
ARMul_CLEARABORT;
}

141
sim/arm/bag.c Normal file
View File

@@ -0,0 +1,141 @@
/* bag.c -- ARMulator support code: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/********************************************************************/
/* bag.c: */
/* Offers a data structure for storing and getting pairs of number. */
/* The numbers are stored together, put one can be looked up by */
/* quoting the other. If a new pair is entered and one of the */
/* numbers is a repeat of a previous pair, then the previos pair */
/* is deleted. */
/********************************************************************/
#include "bag.h"
#define HASH_TABLE_SIZE 256
#define hash(x) (((x)&0xff)^(((x)>>8)&0xff)^(((x)>>16)&0xff)^(((x)>>24)&0xff))
typedef struct hashentry {
struct hashentry *next;
int first;
int second;
} Hashentry;
Hashentry *lookupbyfirst[HASH_TABLE_SIZE];
Hashentry *lookupbysecond[HASH_TABLE_SIZE];
void addtolist(Hashentry **add, long first, long second) {
while (*add) add = &((*add)->next);
/* Malloc will never fail? :o( */
(*add) = (Hashentry *) malloc(sizeof(Hashentry));
(*add)->next = (Hashentry *) 0;
(*add)->first = first;
(*add)->second = second;
}
void killwholelist(Hashentry *p) {
Hashentry *q;
while (p) {
q = p;
p = p->next;
free(q);
}
}
void removefromlist(Hashentry **p, long first, long second) {
Hashentry *q;
while (*p) {
if ((*p)->first == first) {
q = (*p)->next;
free(*p);
*p = q;
return;
}
p = &((*p)->next);
}
}
void BAG_putpair(long first, long second) {
long junk;
if (BAG_getfirst(&junk, second) != NO_SUCH_PAIR)
BAG_killpair_bysecond(second);
addtolist(&lookupbyfirst[hash(first)], first, second);
addtolist(&lookupbysecond[hash(second)], first, second);
}
Bag_error BAG_getfirst(long *first, long second) {
Hashentry *look;
look = lookupbysecond[hash(second)];
while(look) if (look->second == second) {
*first = look->first;
return NO_ERROR;
}
return NO_SUCH_PAIR;
}
Bag_error BAG_getsecond(long first, long *second) {
Hashentry *look;
look = lookupbyfirst[hash(first)];
while(look) {
if (look->first == first) {
*second = look->second;
return NO_ERROR;
}
look = look->next;
}
return NO_SUCH_PAIR;
}
Bag_error BAG_killpair_byfirst(long first) {
long second;
if (BAG_getsecond(first, &second) == NO_SUCH_PAIR)
return NO_SUCH_PAIR;
removefromlist(&lookupbyfirst[hash(first)], first, second);
removefromlist(&lookupbysecond[hash(second)], first, second);
return NO_ERROR;
}
Bag_error BAG_killpair_bysecond(long second) {
long first;
if (BAG_getfirst(&first, second) == NO_SUCH_PAIR)
return NO_SUCH_PAIR;
removefromlist(&lookupbyfirst[hash(first)], first, second);
removefromlist(&lookupbysecond[hash(second)], first, second);
return NO_ERROR;
}
void BAG_newbag() {
int i;
for (i = 0; i < 256; i++) {
killwholelist(lookupbyfirst[i]);
killwholelist(lookupbysecond[i]);
lookupbyfirst[i] = lookupbysecond[i] = (Hashentry *) 0;
}
}

42
sim/arm/bag.h Normal file
View File

@@ -0,0 +1,42 @@
/* bag.h -- ARMulator support code: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/********************************************************************/
/* bag.h: */
/* Header file for bag.c */
/* Offers a data structure for storing and getting pairs of number. */
/* The numbers are stored together, put one can be looked up by */
/* quoting the other. If a new pair is entered and one of the */
/* numbers is a repeat of a previous pair, then the previos pair */
/* is deleted. */
/********************************************************************/
typedef enum {
NO_ERROR,
DELETED_OLD_PAIR,
NO_SUCH_PAIR,
} Bag_error;
void BAG_putpair(long first, long second);
void BAG_newbag(void);
Bag_error BAG_killpair_byfirst(long first);
Bag_error BAG_killpair_bysecond(long second);
Bag_error BAG_getfirst(long *first, long second);
Bag_error BAG_getsecond(long first, long *second);

221
sim/arm/communicate.c Normal file
View File

@@ -0,0 +1,221 @@
/* communicate.c -- ARMulator RDP comms code: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/**************************************************************************/
/* Functions to read and write characters or groups of characters */
/* down sockets or pipes. Those that return a value return -1 on failure */
/* and 0 on success. */
/**************************************************************************/
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "armdefs.h"
/* The socket to the debugger */
int debugsock;
/* The maximum number of file descriptors */
extern int nfds;
/* The socket handle */
extern int sockethandle;
/* Read and Write routines down a pipe or socket */
/****************************************************************/
/* Read an individual character. */
/* All other read functions rely on this one. */
/* It waits 15 seconds until there is a character available: if */
/* no character is available, then it timeouts and returns -1. */
/****************************************************************/
int MYread_char(int sock, unsigned char *c) {
int i;
fd_set readfds;
struct timeval timeout= {15, 0};
struct sockaddr_in isa;
retry:
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
i = select(nfds, &readfds,
(fd_set *) 0,
(fd_set *) 0,
&timeout);
if (i < 0) {
perror("select");
exit(1);
}
if (!i) {
fprintf(stderr, "read: Timeout\n");
return -1;
}
if ((i = read(sock, c, 1)) < 1) {
if (!i && sock == debugsock) {
fprintf(stderr, "Connection with debugger severed.\n");
/* This shouldn't be necessary for a detached armulator, but
the armulator cannot be cold started a second time, so
this is probably preferable to locking up. */
return -1;
fprintf(stderr, "Waiting for connection from debugger...");
debugsock = accept(sockethandle, &isa, &i);
if (debugsock < 0) { /* Now we are in serious trouble... */
perror("accept");
return -1;
}
fprintf(stderr, " done.\nConnection Established.\n");
sock = debugsock;
goto retry;
}
perror("read");
return -1;
}
#ifdef DEBUG
if (sock == debugsock) fprintf(stderr, "<%02x ", *c);
#endif
return 0;
}
/****************************************************************/
/* Read an individual character. */
/* It waits until there is a character available. Returns -1 if */
/* an error occurs. */
/****************************************************************/
int MYread_charwait(int sock, unsigned char *c) {
int i;
fd_set readfds;
struct sockaddr_in isa;
retry:
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
i = select(nfds, &readfds,
(fd_set *) 0,
(fd_set *) 0,
(struct timeval *) 0);
if (i < 0) {
perror("select");
exit(-1);
}
if ((i = read(sock, c, 1)) < 1) {
if (!i && sock == debugsock) {
fprintf(stderr, "Connection with debugger severed.\n");
return -1;
fprintf(stderr, "Waiting for connection from debugger...");
debugsock = accept(sockethandle, &isa, &i);
if (debugsock < 0) { /* Now we are in serious trouble... */
perror("accept");
return -1;
}
fprintf(stderr, " done.\nConnection Established.\n");
sock = debugsock;
goto retry;
}
perror("read");
return -1;
}
#ifdef DEBUG
if (sock == debugsock) fprintf(stderr, "<%02x ", *c);
#endif
return 0;
}
void MYwrite_char(int sock, unsigned char c) {
if (write(sock, &c, 1) < 1)
perror("write");
#ifdef DEBUG
if (sock == debugsock) fprintf(stderr, ">%02x ", c);
#endif
}
int MYread_word(int sock, ARMword *here) {
unsigned char a, b, c, d;
if (MYread_char(sock, &a) < 0) return -1;
if (MYread_char(sock, &b) < 0) return -1;
if (MYread_char(sock, &c) < 0) return -1;
if (MYread_char(sock, &d) < 0) return -1;
*here = a | b << 8 | c << 16 | d << 24;
return 0;
}
void MYwrite_word(int sock, ARMword i) {
MYwrite_char(sock, i & 0xff);
MYwrite_char(sock, (i & 0xff00) >> 8);
MYwrite_char(sock, (i & 0xff0000) >> 16);
MYwrite_char(sock, (i & 0xff000000) >> 24);
}
void MYwrite_string(int sock, char *s) {
int i;
for (i = 0; MYwrite_char(sock, s[i]), s[i]; i++);
}
int MYread_FPword(int sock, char *putinhere) {
int i;
for (i = 0; i < 16; i++)
if (MYread_char(sock, &putinhere[i]) < 0) return -1;
return 0;
}
void MYwrite_FPword(int sock, char *fromhere) {
int i;
for (i = 0; i < 16; i++)
MYwrite_char(sock, fromhere[i]);
}
/* Takes n bytes from source and those n bytes */
/* down to dest */
int passon(int source, int dest, int n) {
char *p;
int i;
p = (char *) malloc(n);
if (!p) {
perror("Out of memory\n");
exit(1);
}
if (n) {
for (i = 0; i < n; i++)
if (MYread_char(source, &p[i]) < 0) return -1;
#ifdef DEBUG
if (dest == debugsock)
for (i = 0; i < n; i++) fprintf(stderr, ")%02x ", (unsigned char) p[i]);
#endif
write(dest, p, n);
}
free(p);
return 0;
}

37
sim/arm/communicate.h Normal file
View File

@@ -0,0 +1,37 @@
/* communicate.h -- ARMulator comms support defns: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
int MYread_char(int sock, unsigned char *c);
void MYwrite_char(int sock, unsigned char c);
int MYread_word(int sock, ARMword *here);
void MYwrite_word(int sock, ARMword i);
void MYwrite_string(int sock, char *s);
int MYread_FPword(int sock, char *putinhere);
void MYwrite_FPword(int sock, char *fromhere);
int passon(int source, int dest, int n);
int wait_for_osreply(ARMword *reply); /* from kid.c */
#define OS_SendNothing 0x0
#define OS_SendChar 0x1
#define OS_SendWord 0x2
#define OS_SendString 0x3
/* The pipes between the two processes */
extern int mumkid[2];
extern int kidmum[2];

158
sim/arm/config.in Normal file
View File

@@ -0,0 +1,158 @@
/* config.in. Generated automatically from configure.in by autoheader. */
/* Define if using alloca.c. */
#undef C_ALLOCA
/* Define to empty if the keyword does not work. */
#undef const
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
This function is required for alloca.c support on those systems. */
#undef CRAY_STACKSEG_END
/* Define if you have alloca, as a function or macro. */
#undef HAVE_ALLOCA
/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
#undef HAVE_ALLOCA_H
/* Define if you have a working `mmap' system call. */
#undef HAVE_MMAP
/* Define as __inline if that's what the C compiler calls it. */
#undef inline
/* Define to `long' if <sys/types.h> doesn't define. */
#undef off_t
/* Define if you need to in order for stat and other things to work. */
#undef _POSIX_SOURCE
/* Define as the return type of signal handlers (int or void). */
#undef RETSIGTYPE
/* Define to `unsigned' if <sys/types.h> doesn't define. */
#undef size_t
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown
*/
#undef STACK_DIRECTION
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if NLS is requested. */
#undef ENABLE_NLS
/* 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
/* Define if you have the __argz_count function. */
#undef HAVE___ARGZ_COUNT
/* Define if you have the __argz_next function. */
#undef HAVE___ARGZ_NEXT
/* Define if you have the __argz_stringify function. */
#undef HAVE___ARGZ_STRINGIFY
/* Define if you have the __setfpucw function. */
#undef HAVE___SETFPUCW
/* Define if you have the dcgettext function. */
#undef HAVE_DCGETTEXT
/* Define if you have the getcwd function. */
#undef HAVE_GETCWD
/* Define if you have the getpagesize function. */
#undef HAVE_GETPAGESIZE
/* Define if you have the getrusage function. */
#undef HAVE_GETRUSAGE
/* Define if you have the munmap function. */
#undef HAVE_MUNMAP
/* Define if you have the putenv function. */
#undef HAVE_PUTENV
/* Define if you have the setenv function. */
#undef HAVE_SETENV
/* Define if you have the setlocale function. */
#undef HAVE_SETLOCALE
/* Define if you have the sigaction function. */
#undef HAVE_SIGACTION
/* Define if you have the stpcpy function. */
#undef HAVE_STPCPY
/* Define if you have the strcasecmp function. */
#undef HAVE_STRCASECMP
/* Define if you have the strchr function. */
#undef HAVE_STRCHR
/* Define if you have the time function. */
#undef HAVE_TIME
/* Define if you have the <argz.h> header file. */
#undef HAVE_ARGZ_H
/* Define if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define if you have the <fpu_control.h> header file. */
#undef HAVE_FPU_CONTROL_H
/* Define if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define if you have the <malloc.h> header file. */
#undef HAVE_MALLOC_H
/* Define if you have the <nl_types.h> header file. */
#undef HAVE_NL_TYPES_H
/* 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 <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if you have the <values.h> header file. */
#undef HAVE_VALUES_H

3892
sim/arm/configure vendored Executable file

File diff suppressed because it is too large Load Diff

10
sim/arm/configure.in Normal file
View File

@@ -0,0 +1,10 @@
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
AC_CHECK_HEADERS(unistd.h)
SIM_AC_OUTPUT

48
sim/arm/dbg_conf.h Normal file
View File

@@ -0,0 +1,48 @@
/* dbg_conf.h -- ARMulator debug interface: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef Dbg_Conf__h
#define Dbg_Conf__h
typedef struct Dbg_ConfigBlock {
int bytesex;
long memorysize;
int serialport; /*) remote connection parameters */
int seriallinespeed; /*) (serial connection) */
int parallelport; /*) ditto */
int parallellinespeed; /*) (parallel connection) */
int processor; /* processor the armulator is to emulate (eg ARM60) */
int rditype; /* armulator / remote processor */
int drivertype; /* parallel / serial / etc */
char const *configtoload;
int flags;
} Dbg_ConfigBlock;
#define Dbg_ConfigFlag_Reset 1
typedef struct Dbg_HostosInterface Dbg_HostosInterface;
/* This structure allows access by the (host-independent) C-library support
module of armulator or pisd (armos.c) to host-dependent functions for
which there is no host-independent interface. Its contents are unknown
to the debugger toolbox.
The assumption is that, in a windowed system, fputc(stderr) for example
may not achieve the desired effect of the character appearing in some
window.
*/
#endif

62
sim/arm/dbg_cp.h Normal file
View File

@@ -0,0 +1,62 @@
/* dbg_cp.h -- ARMulator debug interface: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef Dbg_CP__h
#define Dbg_CP__h
#define Dbg_Access_Readable 1
#define Dbg_Access_Writable 2
#define Dbg_Access_CPDT 4 /* else CPRT */
typedef struct {
unsigned short rmin, rmax;
/* a single description can be used for a range of registers with
the same properties *accessed via CPDT instructions*
*/
unsigned char nbytes; /* size of register */
unsigned char access; /* see above (Access_xxx) */
union {
struct { /* CPDT instructions do not allow the coprocessor much freedom:
only bit 22 ('N') and 12-15 ('CRd') are free for the
coprocessor to use as it sees fit.
*/
unsigned char nbit;
unsigned char rdbits;
} cpdt;
struct { /* CPRT instructions have much more latitude. The bits fixed
by the ARM are 24..31 (condition mask & opcode)
20 (direction)
8..15 (cpnum, arm register)
4 (CPRT not CPDO)
leaving 14 bits free to the coprocessor (fortunately
falling within two bytes).
*/
unsigned char read_b0, read_b1,
write_b0, write_b1;
} cprt;
} accessinst;
} Dbg_CoProRegDesc;
struct Dbg_CoProDesc {
int entries;
Dbg_CoProRegDesc regdesc[1/* really nentries */];
};
#define Dbg_CoProDesc_Size(n) (sizeof(struct Dbg_CoProDesc) + (n-1)*sizeof(Dbg_CoProRegDesc))
#endif

47
sim/arm/dbg_hif.h Normal file
View File

@@ -0,0 +1,47 @@
/* dbg_hif.h -- ARMulator debug interface: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifdef __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
typedef void Hif_DbgPrint(void *arg, const char *format, va_list ap);
typedef void Hif_DbgPause(void *arg);
typedef void Hif_WriteC(void *arg, int c);
typedef int Hif_ReadC(void *arg);
typedef int Hif_Write(void *arg, char const *buffer, int len);
typedef char *Hif_GetS(void *arg, char *buffer, int len);
typedef void Hif_RDIResetProc(void *arg);
struct Dbg_HostosInterface {
Hif_DbgPrint *dbgprint;
Hif_DbgPause *dbgpause;
void *dbgarg;
Hif_WriteC *writec;
Hif_ReadC *readc;
Hif_Write *write;
Hif_GetS *gets;
void *hostosarg;
Hif_RDIResetProc *reset;
void *resetarg;
};

323
sim/arm/dbg_rdi.h Normal file
View File

@@ -0,0 +1,323 @@
/* dbg_rdi.h -- ARMulator RDI interface: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef dbg_rdi__h
#define dbg_rdi__h
/***************************************************************************\
* Error Codes *
\***************************************************************************/
#define RDIError_NoError 0
#define RDIError_Reset 1
#define RDIError_UndefinedInstruction 2
#define RDIError_SoftwareInterrupt 3
#define RDIError_PrefetchAbort 4
#define RDIError_DataAbort 5
#define RDIError_AddressException 6
#define RDIError_IRQ 7
#define RDIError_FIQ 8
#define RDIError_Error 9
#define RDIError_BranchThrough0 10
#define RDIError_NotInitialised 128
#define RDIError_UnableToInitialise 129
#define RDIError_WrongByteSex 130
#define RDIError_UnableToTerminate 131
#define RDIError_BadInstruction 132
#define RDIError_IllegalInstruction 133
#define RDIError_BadCPUStateSetting 134
#define RDIError_UnknownCoPro 135
#define RDIError_UnknownCoProState 136
#define RDIError_BadCoProState 137
#define RDIError_BadPointType 138
#define RDIError_UnimplementedType 139
#define RDIError_BadPointSize 140
#define RDIError_UnimplementedSize 141
#define RDIError_NoMorePoints 142
#define RDIError_BreakpointReached 143
#define RDIError_WatchpointAccessed 144
#define RDIError_NoSuchPoint 145
#define RDIError_ProgramFinishedInStep 146
#define RDIError_UserInterrupt 147
#define RDIError_CantSetPoint 148
#define RDIError_IncompatibleRDILevels 149
#define RDIError_CantLoadConfig 150
#define RDIError_BadConfigData 151
#define RDIError_NoSuchConfig 152
#define RDIError_BufferFull 153
#define RDIError_OutOfStore 154
#define RDIError_NotInDownload 155
#define RDIError_PointInUse 156
#define RDIError_BadImageFormat 157
#define RDIError_TargetRunning 158
#define RDIError_LittleEndian 240
#define RDIError_BigEndian 241
#define RDIError_SoftInitialiseError 242
#define RDIError_InsufficientPrivilege 253
#define RDIError_UnimplementedMessage 254
#define RDIError_UndefinedMessage 255
/***************************************************************************\
* RDP Message Numbers *
\***************************************************************************/
#define RDP_Start (unsigned char)0x0
#define RDP_End (unsigned char)0x1
#define RDP_Read (unsigned char)0x2
#define RDP_Write (unsigned char)0x3
#define RDP_CPUread (unsigned char)0x4
#define RDP_CPUwrite (unsigned char)0x5
#define RDP_CPread (unsigned char)0x6
#define RDP_CPwrite (unsigned char)0x7
#define RDP_SetBreak (unsigned char)0xa
#define RDP_ClearBreak (unsigned char)0xb
#define RDP_SetWatch (unsigned char)0xc
#define RDP_ClearWatch (unsigned char)0xd
#define RDP_Execute (unsigned char)0x10
#define RDP_Step (unsigned char)0x11
#define RDP_Info (unsigned char)0x12
#define RDP_OSOpReply (unsigned char)0x13
#define RDP_AddConfig (unsigned char)0x14
#define RDP_LoadConfigData (unsigned char)0x15
#define RDP_SelectConfig (unsigned char)0x16
#define RDP_LoadAgent (unsigned char)0x17
#define RDP_Stopped (unsigned char)0x20
#define RDP_OSOp (unsigned char)0x21
#define RDP_Fatal (unsigned char)0x5e
#define RDP_Return (unsigned char)0x5f
#define RDP_Reset (unsigned char)0x7f
/***************************************************************************\
* Other RDI values *
\***************************************************************************/
#define RDISex_Little 0 /* the byte sex of the debuggee */
#define RDISex_Big 1
#define RDISex_DontCare 2
#define RDIPoint_EQ 0 /* the different types of break/watchpoints */
#define RDIPoint_GT 1
#define RDIPoint_GE 2
#define RDIPoint_LT 3
#define RDIPoint_LE 4
#define RDIPoint_IN 5
#define RDIPoint_OUT 6
#define RDIPoint_MASK 7
#define RDIPoint_Inquiry 64 /* ORRed with point type in extended RDP */
#define RDIPoint_Handle 128 /* messages */
#define RDIWatch_ByteRead 1 /* types of data accesses to watch for */
#define RDIWatch_HalfRead 2
#define RDIWatch_WordRead 4
#define RDIWatch_ByteWrite 8
#define RDIWatch_HalfWrite 16
#define RDIWatch_WordWrite 32
#define RDIReg_R15 (1L << 15) /* mask values for CPU */
#define RDIReg_PC (1L << 16)
#define RDIReg_CPSR (1L << 17)
#define RDIReg_SPSR (1L << 18)
#define RDINumCPURegs 19
#define RDINumCPRegs 10 /* current maximum */
#define RDIMode_Curr 255
/* Bits set in return value from RDIInfo_Target */
#define RDITarget_LogSpeed 0x0f
#define RDITarget_HW 0x10 /* else emulator */
#define RDITarget_AgentMaxLevel 0xe0
#define RDITarget_AgentLevelShift 5
#define RDITarget_DebuggerMinLevel 0x700
#define RDITarget_DebuggerLevelShift 8
#define RDITarget_CanReloadAgent 0x800
#define RDITarget_CanInquireLoadSize 0x1000
/* Bits set in return value from RDIInfo_Step */
#define RDIStep_Multiple 1
#define RDIStep_PCChange 2
#define RDIStep_Single 4
/* Bits set in return value from RDIInfo_Points */
#define RDIPointCapability_Comparison 1
#define RDIPointCapability_Range 2
/* 4 to 128 are RDIWatch_xx{Read,Write} left-shifted by two */
#define RDIPointCapability_Mask 256
#define RDIPointCapability_Status 512 /* Point status enquiries available */
/* RDI_Info subcodes */
#define RDIInfo_Target 0
#define RDIInfo_Points 1
#define RDIInfo_Step 2
#define RDIInfo_MMU 3
#define RDIInfo_DownLoad 4 /* Inquires whether configuration download
and selection is available.
*/
#define RDIInfo_SemiHosting 5 /* Inquires whether RDISemiHosting_* RDI_Info
calls are available.
*/
#define RDIInfo_CoPro 6 /* Inquires whether CoPro RDI_Info calls are
available.
*/
#define RDIInfo_Icebreaker 7
/* The next two are only to be used if the value returned by RDIInfo_Points */
/* has RDIPointCapability_Status set. */
#define RDIPointStatus_Watch 0x80
#define RDIPointStatus_Break 0x81
#define RDISignal_Stop 0x100
#define RDIVector_Catch 0x180
/* The next four are only to be used if RDIInfo_Semihosting returned no error */
#define RDISemiHosting_SetState 0x181
#define RDISemiHosting_GetState 0x182
#define RDISemiHosting_SetVector 0x183
#define RDISemiHosting_GetVector 0x184
/* The next two are only to be used if RDIInfo_Icebreaker returned no error */
#define RDIIcebreaker_GetLocks 0x185
#define RDIIcebreaker_SetLocks 0x186
/* Only if RDIInfo_Target returned RDITarget_CanInquireLoadSize */
#define RDIInfo_GetLoadSize 0x187
#define RDICycles 0x200
#define RDICycles_Size 48
#define RDIErrorP 0x201
#define RDISet_Cmdline 0x300
#define RDISet_RDILevel 0x301
#define RDISet_Thread 0x302
/* The next two are only to be used if RDIInfo_CoPro returned no error */
#define RDIInfo_DescribeCoPro 0x400
#define RDIInfo_RequestCoProDesc 0x401
#define RDIInfo_Log 0x800
#define RDIInfo_SetLog 0x801
typedef unsigned long PointHandle;
typedef unsigned long ThreadHandle;
#define RDINoPointHandle ((PointHandle)-1L)
#define RDINoHandle ((ThreadHandle)-1L)
struct Dbg_ConfigBlock;
struct Dbg_HostosInterface;
struct Dbg_MCState;
typedef int rdi_open_proc(unsigned type, struct Dbg_ConfigBlock const *config,
struct Dbg_HostosInterface const *i,
struct Dbg_MCState *dbg_state);
typedef int rdi_close_proc(void);
typedef int rdi_read_proc(ARMword source, void *dest, unsigned *nbytes);
typedef int rdi_write_proc(const void *source, ARMword dest, unsigned *nbytes);
typedef int rdi_CPUread_proc(unsigned mode, unsigned long mask, ARMword *state);
typedef int rdi_CPUwrite_proc(unsigned mode, unsigned long mask, ARMword const *state);
typedef int rdi_CPread_proc(unsigned CPnum, unsigned long mask, ARMword *state);
typedef int rdi_CPwrite_proc(unsigned CPnum, unsigned long mask, ARMword const *state);
typedef int rdi_setbreak_proc(ARMword address, unsigned type, ARMword bound,
PointHandle *handle);
typedef int rdi_clearbreak_proc(PointHandle handle);
typedef int rdi_setwatch_proc(ARMword address, unsigned type, unsigned datatype,
ARMword bound, PointHandle *handle);
typedef int rdi_clearwatch_proc(PointHandle handle);
typedef int rdi_execute_proc(PointHandle *handle);
typedef int rdi_step_proc(unsigned ninstr, PointHandle *handle);
typedef int rdi_info_proc(unsigned type, ARMword *arg1, ARMword *arg2);
typedef int rdi_pointinq_proc(ARMword *address, unsigned type,
unsigned datatype, ARMword *bound);
typedef enum {
RDI_ConfigCPU,
RDI_ConfigSystem
} RDI_ConfigAspect;
typedef enum {
RDI_MatchAny,
RDI_MatchExactly,
RDI_MatchNoEarlier
} RDI_ConfigMatchType;
typedef int rdi_addconfig_proc(unsigned long nbytes);
typedef int rdi_loadconfigdata_proc(unsigned long nbytes, char const *data);
typedef int rdi_selectconfig_proc(RDI_ConfigAspect aspect, char const *name,
RDI_ConfigMatchType matchtype, unsigned versionreq,
unsigned *versionp);
typedef char *getbufferproc(void *getbarg, unsigned long *sizep);
typedef int rdi_loadagentproc(ARMword dest, unsigned long size, getbufferproc *getb, void *getbarg);
typedef struct {
int itemmax;
char const * const *names;
} RDI_NameList;
typedef RDI_NameList const *rdi_namelistproc(void);
typedef int rdi_errmessproc(char *buf, int buflen, int errno);
struct RDIProcVec {
char rditypename[12];
rdi_open_proc *open;
rdi_close_proc *close;
rdi_read_proc *read;
rdi_write_proc *write;
rdi_CPUread_proc *CPUread;
rdi_CPUwrite_proc *CPUwrite;
rdi_CPread_proc *CPread;
rdi_CPwrite_proc *CPwrite;
rdi_setbreak_proc *setbreak;
rdi_clearbreak_proc *clearbreak;
rdi_setwatch_proc *setwatch;
rdi_clearwatch_proc *clearwatch;
rdi_execute_proc *execute;
rdi_step_proc *step;
rdi_info_proc *info;
/* V2 RDI */
rdi_pointinq_proc *pointinquiry;
/* These three useable only if RDIInfo_DownLoad returns no error */
rdi_addconfig_proc *addconfig;
rdi_loadconfigdata_proc *loadconfigdata;
rdi_selectconfig_proc *selectconfig;
rdi_namelistproc *drivernames;
rdi_namelistproc *cpunames;
rdi_errmessproc *errmess;
/* Only if RDIInfo_Target returns a value with RDITarget_LoadAgent set */
rdi_loadagentproc *loadagent;
};
#endif

107
sim/arm/gdbhost.c Normal file
View File

@@ -0,0 +1,107 @@
/* gdbhost.c -- ARMulator RDP to gdb comms code: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/***********************************************************/
/* Functions that communicate info back to the debugger... */
/***********************************************************/
#include <stdio.h>
#include <stdarg.h>
#include "armdefs.h"
#include "communicate.h"
#include "dbg_rdi.h"
#include "armos.h"
#define OS_SendNothing 0x0
#define OS_SendChar 0x1
#define OS_SendWord 0x2
#define OS_SendString 0x3
/* Defined in kid.c */
extern int wait_for_osreply(ARMword *reply);
/* A pipe for handling SWI return values that goes straight from the */
/* parent to the ARMulator host interface, bypassing the childs RDP */
/* to RDI interpreter */
int DebuggerARMul[2];
/* The pipes between the two processes */
int mumkid[2];
int kidmum[2];
void myprint (void *arg, const char *format, va_list ap)
{
#ifdef DEBUG
fprintf (stderr, "Host: myprint\n");
#endif
vfprintf (stderr, format, ap);
}
/* Waits for a keypress on the debuggers' keyboard */
void mypause (void *arg)
{
#ifdef DEBUG
fprintf (stderr, "Host: mypause\n");
#endif
} /* I do love exciting functions */
void mywritec(void *arg, int c)
{
#ifdef DEBUG
fprintf(stderr, "Mywrite : %c\n", c);
#endif
MYwrite_char(kidmum[1], RDP_OSOp); /* OS Operation Request Message */
MYwrite_word(kidmum[1], SWI_WriteC); /* Print... */
MYwrite_char(kidmum[1], OS_SendChar); /* ...a single character */
MYwrite_char(kidmum[1], (unsigned char) c);
wait_for_osreply((ARMword *) 0);
}
int myreadc(void *arg)
{
char c;
ARMword x;
#ifdef DEBUG
fprintf(stderr, "Host: myreadc\n");
#endif
MYwrite_char(kidmum[1], RDP_OSOp); /* OS Operation Request Message */
MYwrite_word(kidmum[1], SWI_ReadC); /* Read... */
MYwrite_char(kidmum[1], OS_SendNothing);
c = wait_for_osreply(&x);
return (x);
}
int mywrite(void *arg, char const *buffer, int len)
{
#ifdef DEBUG
fprintf(stderr, "Host: mywrite\n");
#endif
return 0;
}
char *mygets(void *arg, char *buffer, int len)
{
#ifdef DEBUG
fprintf(stderr, "Host: mygets\n");
#endif
return buffer;
}

23
sim/arm/gdbhost.h Normal file
View File

@@ -0,0 +1,23 @@
/* gdbhost.h -- ARMulator to gdb interface: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
void myprint(void *arg, const char *format, va_list ap);
void mypause(void *arg);
void mywritec(void *arg, int c);
int myreadc(void *arg);
int mywrite(void *arg, char const *buffer, int len);
char *mygets(void *arg, char *buffer, int len);

510
sim/arm/kid.c Normal file
View File

@@ -0,0 +1,510 @@
/* kid.c -- ARMulator RDP/RDI interface: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*****************************************************************/
/* The child process continues here... */
/* It waits on a pipe from the parent and translates the RDP */
/* messages into RDI calls to the ARMulator passing RDP replies */
/* back up a pipe to the parent. */
/*****************************************************************/
#include <sys/types.h>
#include <signal.h>
#include "armdefs.h"
#include "dbg_conf.h"
#include "dbg_hif.h"
#include "dbg_rdi.h"
#include "gdbhost.h"
#include "communicate.h"
/* The pipes between the two processes */
extern int mumkid[2];
extern int kidmum[2];
/* The maximum number of file descriptors */
extern int nfds;
/* The machine name */
#define MAXHOSTNAMELENGTH 64
extern char localhost[MAXHOSTNAMELENGTH + 1];
/* The socket number */
extern unsigned int socketnumber;
/* RDI interface */
extern const struct RDIProcVec armul_rdi;
static int MYrdp_level = 0;
static int rdi_state = 0;
/**************************************************************/
/* Signal handler that terminates excecution in the ARMulator */
/**************************************************************/
void kid_handlesignal(int sig) {
#ifdef DEBUG
fprintf(stderr, "Terminate ARMulator excecution\n");
#endif
if (sig != SIGUSR1) {
fprintf(stderr, "Unsupported signal.\n");
return;
}
armul_rdi.info(RDISignal_Stop, (unsigned long *) 0, (unsigned long *) 0);
}
/********************************************************************/
/* Waits on a pipe from the socket demon for RDP and */
/* acts as an RDP to RDI interpreter on the front of the ARMulator. */
/********************************************************************/
void kid() {
char *p, *q;
int i, j, k;
long outofthebag;
unsigned char c, d, message;
ARMword x, y, z;
struct sigaction action;
PointHandle point;
Dbg_ConfigBlock config;
Dbg_HostosInterface hostif;
struct Dbg_MCState *MCState;
char command_line[256];
struct fd_set readfds;
/* Setup a signal handler for SIGUSR1 */
action.sa_handler = kid_handlesignal;
action.sa_mask = 0;
action.sa_flags = 0;
sigaction(SIGUSR1, &action, (struct sigaction *) 0);
while (1)
{
/* Wait for ever */
FD_ZERO(&readfds);
FD_SET(mumkid[0], &readfds);
i = select(nfds, &readfds,
(fd_set *) 0,
(fd_set *) 0,
(struct timeval *) 0);
if (i < 0) {
perror("select");
}
if (read(mumkid[0], &message, 1) < 1) {
perror("read");
}
switch (message) {
case RDP_Start :
/* Open and/or Initialise */
BAG_newbag();
MYread_char(mumkid[0], &c); /* type */
MYread_word(mumkid[0], &x); /* memorysize */
if (c & 0x2) MYread_char(mumkid[0], &d); /* speed */
config.processor = 0;
config.memorysize = x;
config.bytesex = (c & 0x4) ? RDISex_Big : RDISex_Little;
if (c & 0x8) config.bytesex = RDISex_DontCare;
hostif.dbgprint = myprint;
hostif.dbgpause = mypause;
hostif.dbgarg = stdout;
hostif.writec = mywritec;
hostif.readc = myreadc;
hostif.write = mywrite;
hostif.gets = mygets;
hostif.reset = mypause; /* do nothing */
hostif.resetarg = "Do I love resetting or what!\n";
if (rdi_state)
{
/* we have restarted, so kill off the existing run. */
/* armul_rdi.close(); */
}
i = armul_rdi.open(c & 0x3, &config, &hostif, MCState);
rdi_state = 1;
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
x = ~0x4;
armul_rdi.info(RDIVector_Catch, &x, 0);
break;
case RDP_End :
/* Close and Finalise */
i = armul_rdi.close();
rdi_state = 0;
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_Read :
/* Read Memory Address */
MYread_word(mumkid[0], &x); /* address */
MYread_word(mumkid[0], &y); /* nbytes */
p = (char *) malloc(y);
i = armul_rdi.read(x, p, (unsigned *) &y);
MYwrite_char(kidmum[1], RDP_Return);
for (k = 0; k < y; k++)
MYwrite_char(kidmum[1], p[k]);
free(p);
MYwrite_char(kidmum[1], (unsigned char) i);
if (i)
MYwrite_word(kidmum[1], y); /* number of bytes sent without error */
break;
case RDP_Write :
/* Write Memory Address */
MYread_word(mumkid[0], &x); /* address */
MYread_word(mumkid[0], &y); /* nbytes */
p = (char *) malloc(y);
for (k = 0; k < y; k++)
MYread_char(mumkid[0], &p[k]);
i = armul_rdi.write(p, x, (unsigned *) &y);
free(p);
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
if (i)
MYwrite_word(kidmum[1], y); /* number of bytes sent without error */
break;
case RDP_CPUread :
/* Read CPU State */
MYread_char(mumkid[0], &c); /* mode */
MYread_word(mumkid[0], &x); /* mask */
p = (char *) malloc(4 * RDINumCPURegs);
i = armul_rdi.CPUread(c, x, (ARMword *) p);
MYwrite_char(kidmum[1], RDP_Return);
for (k = 1, j = 0; k != 0x80000000; k *= 2)
if (k & x) MYwrite_word(kidmum[1], ((ARMword *) p)[j++]);
free(p);
if (i) MYwrite_char(kidmum[1], (unsigned char) j);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_CPUwrite :
/* Write CPU State */
MYread_char(mumkid[0], &c); /* mode */
MYread_word(mumkid[0], &x); /* mask */
p = (char *) malloc(4 * RDINumCPURegs);
for (k = 1, j = 0; k != 0x80000000; k *= 2)
if (k & x) MYread_word(mumkid[0], &(((ARMword *) p)[j++]));
i = armul_rdi.CPUwrite(c, x, (ARMword *) p);
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
free(p);
break;
case RDP_CPread :
/* Read Co-Processor State */
MYread_char(mumkid[0], &c); /* CPnum */
MYread_word(mumkid[0], &x); /* mask */
p = q = (char *) malloc(16 * RDINumCPRegs);
i = armul_rdi.CPread(c, x, (ARMword *) p);
MYwrite_char(kidmum[1], RDP_Return);
for (k = 1, j = 0; k != 0x80000000; k *= 2, j++)
if (k & x) {
if ((c == 1 || c == 2) && k <= 128) {
MYwrite_FPword(kidmum[1], q);
q += 16;
}
else {
MYwrite_word(kidmum[1], *q);
q += 4;
}
}
free(p);
if (i) MYwrite_char(kidmum[1], (unsigned char) j);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_CPwrite :
/* Write Co-Processor State */
MYread_char(mumkid[0], &c); /* CPnum */
MYread_word(mumkid[0], &x); /* mask */
p = q = (char *) malloc(16 * RDINumCPURegs);
for (k = 1, j = 0; k != 0x80000000; k *= 2, j++)
if (k & x) {
if ((c == 1 || c == 2) && k <= 128) {
MYread_FPword(kidmum[1], q);
q += 16;
}
else {
MYread_word(mumkid[0], (ARMword *) q);
q += 4;
}
}
i = armul_rdi.CPwrite(c, x, (ARMword *) p);
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
free(p);
break;
case RDP_SetBreak :
/* Set Breakpoint */
MYread_word(mumkid[0], &x); /* address */
MYread_char(mumkid[0], &c); /* type */
if ((c & 0xf) >= 5) MYread_word(mumkid[0], &y); /* bound */
i = armul_rdi.setbreak(x, c, y, &point);
if (!MYrdp_level) BAG_putpair((long) x, (long) point);
MYwrite_char(kidmum[1], RDP_Return);
if (MYrdp_level) MYwrite_word(kidmum[1], point);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_ClearBreak :
/* Clear Breakpoint */
MYread_word(mumkid[0], &point); /* PointHandle */
if (!MYrdp_level) {
BAG_getsecond((long) point, &outofthebag); /* swap pointhandle for address */
BAG_killpair_byfirst(outofthebag);
point = outofthebag;
}
i = armul_rdi.clearbreak(point);
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_SetWatch :
/* Set Watchpoint */
MYread_word(mumkid[0], &x); /* address */
MYread_char(mumkid[0], &c); /* type */
MYread_char(mumkid[0], &d); /* datatype */
if ((c & 0xf) >= 5) MYread_word(mumkid[0], &y); /* bound */
i = armul_rdi.setwatch(x, c, d, y, &point);
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_word(kidmum[1], point);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_ClearWatch :
/* Clear Watchpoint */
MYread_word(mumkid[0], &point); /* PointHandle */
i = armul_rdi.clearwatch(point);
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_Execute :
/* Excecute */
MYread_char(mumkid[0], &c); /* return */
#ifdef DEBUG
fprintf(stderr, "Starting execution\n");
#endif
i = armul_rdi.execute(&point);
#ifdef DEBUG
fprintf(stderr, "Completed execution\n");
#endif
MYwrite_char(kidmum[1], RDP_Return);
if (c & 0x80) MYwrite_word(kidmum[1], point);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_Step :
/* Step */
MYread_char(mumkid[0], &c); /* return */
MYread_word(mumkid[0], &x); /* ninstr */
point = 0x87654321;
i = armul_rdi.step(x, &point);
MYwrite_char(kidmum[1], RDP_Return);
if (c & 0x80) MYwrite_word(kidmum[1], point);
MYwrite_char(kidmum[1], (unsigned char) i);
break;
case RDP_Info:
/* Info */
MYread_word (mumkid[0], &x);
switch (x)
{
case RDIInfo_Target:
i = armul_rdi.info (RDIInfo_Target, &y, &z);
MYwrite_char (kidmum[1], RDP_Return);
MYwrite_word (kidmum[1], y); /* Loads of info... */
MYwrite_word (kidmum[1], z); /* Model */
MYwrite_char (kidmum[1], (unsigned char) i);
break;
case RDISet_RDILevel:
MYread_word (mumkid[0], &x); /* arg1, debug level */
i = armul_rdi.info (RDISet_RDILevel, &x, 0);
if (i == RDIError_NoError)
MYrdp_level = x;
MYwrite_char (kidmum[1], RDP_Return);
MYwrite_char (kidmum[1], (unsigned char) i);
break;
case RDISet_Cmdline:
for (p = command_line; MYread_char (mumkid[0], p), *p; p++)
; /* String */
i = armul_rdi.info (RDISet_Cmdline,
(unsigned long *) command_line, 0);
MYwrite_char (kidmum[1], RDP_Return);
MYwrite_char (kidmum[1], (unsigned char) i);
break;
case RDIInfo_Step:
i = armul_rdi.info (RDIInfo_Step, &x, 0);
MYwrite_char (kidmum[1], RDP_Return);
MYwrite_word (kidmum[1], x);
MYwrite_char (kidmum[1], (unsigned char) i);
break;
case RDIVector_Catch:
MYread_word (mumkid[0], &x);
i = armul_rdi.info (RDIVector_Catch, &x, 0);
MYwrite_char (kidmum[1], RDP_Return);
MYwrite_char (kidmum[1], i);
break;
case RDIInfo_Points:
i = armul_rdi.info (RDIInfo_Points, &x, 0);
MYwrite_char (kidmum[1], RDP_Return);
MYwrite_word (kidmum[1], x);
MYwrite_char (kidmum[1], (unsigned char) i);
break;
default:
fprintf (stderr, "Unsupported info code %d\n", x);
break;
}
break;
case RDP_OSOpReply:
/* OS Operation Reply */
MYwrite_char (kidmum[1], RDP_Fatal);
break;
case RDP_Reset:
/* Reset */
for (i = 0; i < 50; i++)
MYwrite_char(kidmum[1], RDP_Reset);
p = (char *) malloc(MAXHOSTNAMELENGTH + 5 + 20);
sprintf(p, "Running on %s:%d\n", localhost, socketnumber);
MYwrite_string(kidmum[1], p);
free(p);
break;
default:
fprintf (stderr, "Oh dear: Something is seriously wrong :-(\n");
/* Hmm.. bad RDP operation */
break;
}
}
}
/* Handles memory read operations until an OS Operation Reply Message is */
/* encounterd. It then returns the byte info value (0, 1, or 2) and fills */
/* in 'putinr0' with the data if appropriate. */
int wait_for_osreply(ARMword *reply)
{
char *p, *q;
int i, j, k;
unsigned char c, d, message;
ARMword x, y, z;
struct sigaction action;
PointHandle point;
Dbg_ConfigBlock config;
Dbg_HostosInterface hostif;
struct Dbg_MCState *MCState;
char command_line[256];
struct fd_set readfds;
#ifdef DEBUG
fprintf(stderr, "wait_for_osreply ().\n");
#endif
/* Setup a signal handler for SIGUSR1 */
action.sa_handler = kid_handlesignal;
action.sa_mask = 0;
action.sa_flags = 0;
sigaction(SIGUSR1, &action, (struct sigaction *) 0);
while (1)
{
/* Wait for ever */
FD_ZERO(&readfds);
FD_SET(mumkid[0], &readfds);
i = select(nfds, &readfds,
(fd_set *) 0,
(fd_set *) 0,
(struct timeval *) 0);
if (i < 0) {
perror("select");
}
if (read(mumkid[0], &message, 1) < 1) {
perror("read");
}
switch (message) {
case RDP_Read :
/* Read Memory Address */
MYread_word(mumkid[0], &x); /* address */
MYread_word(mumkid[0], &y); /* nbytes */
p = (char *) malloc(y);
i = armul_rdi.read(x, p, (unsigned *) &y);
MYwrite_char(kidmum[1], RDP_Return);
for (k = 0; k < y; k++)
MYwrite_char(kidmum[1], p[k]);
free(p);
MYwrite_char(kidmum[1], (unsigned char) i);
if (i)
MYwrite_word(kidmum[1], y); /* number of bytes sent without error */
break;
case RDP_Write :
/* Write Memory Address */
MYread_word(mumkid[0], &x); /* address */
MYread_word(mumkid[0], &y); /* nbytes */
p = (char *) malloc(y);
for (k = 0; k < y; k++)
MYread_char(mumkid[0], &p[k]);
i = armul_rdi.write(p, x, (unsigned *) &y);
free(p);
MYwrite_char(kidmum[1], RDP_Return);
MYwrite_char(kidmum[1], (unsigned char) i);
if (i)
MYwrite_word(kidmum[1], y); /* number of bytes sent without error */
break;
case RDP_OSOpReply :
/* OS Operation Reply */
MYread_char(mumkid[0], &c);
if (c == 1) MYread_char(mumkid[0], (char *) reply);
if (c == 2) MYread_word(mumkid[0], reply);
return c;
break;
default :
fprintf(stderr, "HELP! Unaccounted-for message during OS request. \n");
MYwrite_char(kidmum[1], RDP_Fatal);
}
}
}

183
sim/arm/main.c Normal file
View File

@@ -0,0 +1,183 @@
/* main.c -- top level of ARMulator: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/**********************************************************************/
/* Forks the ARMulator and hangs on a socket passing on RDP messages */
/* down a pipe to the ARMulator which translates them into RDI calls. */
/**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <netdb.h>
#include <unistd.h>
#include "armdefs.h"
#include "dbg_rdi.h"
#include "dbg_conf.h"
#define MAXHOSTNAMELENGTH 64
/* Read and write routines down sockets and pipes */
void MYread_chars(int sock, void *p, int n);
unsigned char MYread_char(int sock);
ARMword MYread_word(int sock);
void MYread_FPword(int sock, char *putinhere);
void MYwrite_word(int sock, ARMword i);
void MYwrite_string(int sock, char *s);
void MYwrite_FPword(int sock, char *fromhere);
void MYwrite_char(int sock, unsigned char c);
void passon(int source, int dest, int n);
/* Mother and child processes */
void parent (void);
void kid(void);
/* The child process id. */
pid_t child;
/* The socket to the debugger */
int debugsock;
/* The pipes between the two processes */
int mumkid[2];
int kidmum[2];
/* A pipe for handling SWI return values that goes straight from the */
/* parent to the ARMulator host interface, bypassing the childs RDP */
/* to RDI interpreter */
int DebuggerARMul[2];
/* The maximum number of file descriptors */
int nfds;
/* The socket handle */
int sockethandle;
/* The machine name */
char localhost[MAXHOSTNAMELENGTH + 1];
/* The socket number */
unsigned int socketnumber;
/**************************************************************/
/* Takes one argument: the socket number. */
/* Opens a socket to the debugger, and once opened spawns the */
/* ARMulator and sets up a couple of pipes. */
/**************************************************************/
int main(int argc, char *argv[]) {
int i;
struct sockaddr_in devil, isa;
struct hostent *hp;
if (argc == 1) {
fprintf(stderr, "No socket number\n");
return 1;
}
sscanf(argv[1], "%d", &socketnumber);
if (!socketnumber || socketnumber > 0xffff) {
fprintf(stderr, "Invalid socket number: %d\n", socketnumber);
return 1;
}
gethostname(localhost, MAXHOSTNAMELENGTH);
hp = gethostbyname(localhost);
if (!hp) {
fprintf(stderr, "Cannot get local host info\n");
return 1;
}
/* Open a socket */
sockethandle = socket(hp->h_addrtype, SOCK_STREAM, 0);
if (sockethandle < 0) {
perror("socket");
return 1;
}
devil.sin_family = hp->h_addrtype;
devil.sin_port = htons(socketnumber);
devil.sin_addr.s_addr = 0;
for(i = 0; i < sizeof(devil.sin_zero); i++) devil.sin_zero[i] = '\000';
memcpy(&devil.sin_addr, hp->h_addr_list[0], hp->h_length);
if (bind(sockethandle, &devil, sizeof(devil)) < 0) {
perror("bind");
return 1;
}
/* May only accept one debugger at once */
if (listen(sockethandle, 0)) {
perror("listen");
return 1;
}
fprintf(stderr, "Waiting for connection from debugger...");
debugsock = accept(sockethandle, &isa, &i);
if (debugsock < 0) {
perror("accept");
return 1;
}
fprintf(stderr, " done.\nConnection Established.\n");
nfds = getdtablesize();
if (pipe(mumkid)) {
perror("pipe");
return 1;
}
if (pipe(kidmum)) {
perror("pipe");
return 1;
}
if (pipe(DebuggerARMul)) {
perror("pipe");
return 1;
}
#ifdef DEBUG
fprintf(stderr, "Created pipes ok\n");
#endif
child = fork();
#ifdef DEBUG
fprintf(stderr, "fork() ok\n");
#endif
if (child == 0) kid ();
if (child != -1) parent ();
perror("fork");
return 1;
}

483
sim/arm/parent.c Normal file
View File

@@ -0,0 +1,483 @@
/* parent.c -- ARMulator RDP comms code: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*****************************************************************/
/* The Parent process continues here... */
/* It waits on the socket and passes on RDP messages down a pipe */
/* to the ARMulator RDP to RDI interpreter. */
/*****************************************************************/
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include "time.h"
#include "armdefs.h"
#include "dbg_rdi.h"
#include "communicate.h"
/* The socket to the debugger */
extern int debugsock;
/* The pipes between the two processes */
extern int mumkid[2];
extern int kidmum[2];
/* A pipe for handling SWI return values that goes straight from the */
/* parent to the ARMulator host interface, bypassing the child's RDP */
/* to RDI interpreter */
extern int DebuggerARMul[2];
/* The maximum number of file descriptors */
extern int nfds;
/* The child process id. */
extern pid_t child;
void
parent ()
{
int i, j, k;
unsigned char message, CPnum, exreturn;
ARMword mask, nbytes, messagetype;
unsigned char c, d;
ARMword x, y;
int virgin = 1;
struct fd_set readfds;
#ifdef DEBUG
fprintf (stderr, "parent ()...\n");
#endif
panic_error:
if (!virgin)
{
#ifdef DEBUG
fprintf(stderr, "Arghh! What is going on?\n");
#endif
kill (child, SIGHUP);
MYwrite_char(debugsock, RDP_Reset);
}
virgin = 0;
while (1)
{
/* Wait either for the ARMulator or the debugger */
FD_ZERO (&readfds);
FD_SET (kidmum[0], &readfds); /* Wait for messages from ARMulator */
FD_SET (debugsock, &readfds); /* Wait for messages from debugger */
#ifdef DEBUG
fprintf (stderr, "Waiting for ARMulator or debugger... ");
#endif
while ((i = select (nfds, &readfds, (fd_set *) 0, (fd_set *) 0, 0)) < 0)
{
perror ("select");
}
#ifdef DEBUG
fprintf(stderr, "(%d/2)", i);
#endif
if (FD_ISSET (debugsock, &readfds)) {
#ifdef DEBUG
fprintf (stderr, "->debugger\n");
#endif
/* Inside this rather large if statement with simply pass on a complete
message to the ARMulator. The reason we need to pass messages on one
at a time is that we have to know whether the message is an OSOpReply
or an info(stop), so that we can take different action in those
cases. */
if (MYread_char (debugsock, &message))
goto panic_error;
switch (message)
{
case RDP_Start:
/* Open and/or Initialise */
#ifdef DEBUG
fprintf (stderr, "RDP Open\n");
#endif
if (MYread_char(debugsock, &c)) /* type */
goto panic_error;
if (MYread_word(debugsock, &x)) /* memory size */
goto panic_error;
MYwrite_char (mumkid[1], message);
MYwrite_char (mumkid[1], c);
MYwrite_word (mumkid[1], x);
if (c & 0x2)
{
passon (debugsock, mumkid[1], 1); /* speed */
}
break;
case RDP_End:
/* Close and Finalise */
#ifdef DEBUG
fprintf(stderr, "RDP Close\n");
#endif
MYwrite_char (mumkid[1], message);
break;
case RDP_Read:
/* Read Memory Address */
#ifdef DEBUG
fprintf (stderr, "RDP Read Memory\n");
#endif
MYwrite_char (mumkid[1], message);
if (passon (debugsock, mumkid[1], 4))
goto panic_error; /* address */
if (MYread_word(debugsock, &nbytes))
goto panic_error; /* nbytes */
MYwrite_word (mumkid[1], nbytes);
break;
case RDP_Write :
/* Write Memory Address */
#ifdef DEBUG
fprintf (stderr, "RDP Write Memory\n");
#endif
if (MYread_word (debugsock, &x))
goto panic_error; /* address */
if (MYread_word (debugsock, &y))
goto panic_error; /* nbytes */
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], x);
MYwrite_word (mumkid[1], y);
passon (debugsock, mumkid[1], y); /* actual data */
break;
case RDP_CPUread:
/* Read CPU State */
#ifdef DEBUG
fprintf (stderr, "RDP Read CPU\n");
#endif
if (MYread_char(debugsock, &c))
goto panic_error; /* mode */
if (MYread_word (debugsock, &mask))
goto panic_error; /* mask */
MYwrite_char (mumkid[1], message);
MYwrite_char (mumkid[1], c);
MYwrite_word (mumkid[1], mask);
break;
case RDP_CPUwrite :
/* Write CPU State */
#ifdef DEBUG
fprintf (stderr, "RDP Write CPU\n");
#endif
if (MYread_char (debugsock, &c))
goto panic_error; /* mode */
if (MYread_word (debugsock, &x))
goto panic_error; /* mask */
MYwrite_char (mumkid[1], message);
MYwrite_char (mumkid[1], c);
MYwrite_word (mumkid[1], x);
for (k = 1, j = 0; k != 0x80000000; k *= 2, j++)
if ((k & x)
&& passon(debugsock, mumkid[1], 4))
goto panic_error;
break;
case RDP_CPread:
/* Read Co-Processor State */
#ifdef DEBUG
fprintf (stderr, "RDP Read CP state\n");
#endif
if (MYread_char (debugsock, &CPnum))
goto panic_error;
if (MYread_word (debugsock, &mask))
goto panic_error;
MYwrite_char (mumkid[1], message);
MYwrite_char (mumkid[1], CPnum);
MYwrite_word (mumkid[1], mask);
break;
case RDP_CPwrite:
/* Write Co-Processor State */
#ifdef DEBUG
fprintf(stderr, "RDP Write CP state\n");
#endif
if (MYread_char (debugsock, &CPnum))
goto panic_error;
if (MYread_word (debugsock, &mask))
goto panic_error;
MYwrite_char (mumkid[1], message);
MYwrite_char (mumkid[1], c);
MYwrite_char (mumkid[1], x);
for (k = 1, j = 0; k != 0x80000000; k *= 2, j++)
if (k & x)
{
if ((c == 1 || c == 2) && k <= 128)
{
/* FP register = 12 bytes + 4 bytes format */
if (passon(debugsock, mumkid[1], 16))
goto panic_error;
}
else
{
/* Normal register = 4 bytes */
if (passon(debugsock, mumkid[1], 4))
goto panic_error;
}
}
break;
case RDP_SetBreak:
/* Set Breakpoint */
#ifdef DEBUG
fprintf (stderr, "RDP Set Breakpoint\n");
#endif
if (MYread_word (debugsock, &x))
goto panic_error; /* address */
if (MYread_char (debugsock, &c))
goto panic_error; /* type */
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], x);
MYwrite_char (mumkid[1], c);
if (((c & 0xf) >= 5)
&& passon(debugsock, mumkid[1], 4))
goto panic_error; /* bound */
break;
case RDP_ClearBreak:
/* Clear Breakpoint */
#ifdef DEBUG
fprintf (stderr, "RDP Clear Breakpoint\n");
#endif
MYwrite_char (mumkid[1], message);
if (passon (debugsock, mumkid[1], 4))
goto panic_error; /* point */
break;
case RDP_SetWatch:
/* Set Watchpoint */
#ifdef DEBUG
fprintf (stderr, "RDP Set Watchpoint\n");
#endif
if (MYread_word (debugsock, &x))
goto panic_error; /* address */
if (MYread_char(debugsock, &c))
goto panic_error; /* type */
if (MYread_char (debugsock, &d))
goto panic_error; /* datatype */
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], x);
MYwrite_char (mumkid[1], c);
MYwrite_char (mumkid[1], d);
if (((c & 0xf) >= 5)
&& passon(debugsock, mumkid[1], 4))
goto panic_error; /* bound */
break;
case RDP_ClearWatch:
/* Clear Watchpoint */
#ifdef DEBUG
fprintf (stderr, "RDP Clear Watchpoint\n");
#endif
MYwrite_char (mumkid[1], message);
if (passon (debugsock, mumkid[1], 4))
goto panic_error; /* point */
break;
case RDP_Execute:
/* Excecute */
#ifdef DEBUG
fprintf (stderr, "RDP Execute\n");
#endif
/* LEAVE THIS ONE 'TIL LATER... */
/* NEED TO WORK THINGS OUT */
/* NO ASCYNCHROUS RUNNING */
if (MYread_char(debugsock, &c))
goto panic_error; /* return */
/* Remember incase bit 7 is set and we have to send back a word */
exreturn = c;
MYwrite_char(mumkid[1], message);
MYwrite_char(mumkid[1], c);
break;
case RDP_Step:
/* Step */
#ifdef DEBUG
fprintf (stderr, "RDP Step\n");
#endif
if (MYread_char(debugsock, &c))
goto panic_error; /* return */
if (MYread_word(debugsock, &x))
goto panic_error; /* ninstr */
MYwrite_char (mumkid[1], message);
MYwrite_char (mumkid[1], c);
MYwrite_word (mumkid[1], x);
break;
case RDP_Info:
/* Info */
#ifdef DEBUG
fprintf (stderr, "RDP Info\n");
#endif
/* INFO TARGET, SET RDI LEVEL */
if (MYread_word (debugsock, &messagetype))
goto panic_error; /* info */
switch (messagetype)
{
case RDIInfo_Target:
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], messagetype);
break;
case RDISet_RDILevel:
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], messagetype);
if (passon (debugsock, mumkid[1], 1))
goto panic_error; /* argument */
break;
case RDISet_Cmdline:
/* Got to pass on a string argument */
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], messagetype);
do
{
if (MYread_char (debugsock, &c))
goto panic_error;
MYwrite_char (mumkid[1], c);
} while (c);
break;
case RDISignal_Stop:
kill (child, SIGUSR1);
MYwrite_char (debugsock, RDP_Return);
MYwrite_char (debugsock, RDIError_UserInterrupt);
break;
case RDIVector_Catch:
MYread_word (debugsock, &x);
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], messagetype);
MYwrite_word (mumkid[1], x);
break;
case RDIInfo_Step:
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], messagetype);
break;
case RDIInfo_Points:
MYwrite_char (mumkid[1], message);
MYwrite_word (mumkid[1], messagetype);
break;
default:
fprintf (stderr, "Unrecognized RDIInfo request %d\n",
messagetype);
goto panic_error;
}
break;
case RDP_OSOpReply:
/* OS Operation Reply */
#ifdef DEBUG
fprintf (stderr, "RDP OS Reply\n");
#endif
MYwrite_char (mumkid[1], message);
if (MYread_char (debugsock, &message))
goto panic_error;
MYwrite_char (mumkid[1], message);
switch(message)
{
case 0: /* return value i.e. nothing else.*/
break;
case 1: /* returns a byte... */
if (MYread_char(debugsock, &c))
goto panic_error;
MYwrite_char (mumkid[1], c);
break;
case 2: /* returns a word... */
if (MYread_word(debugsock, &x))
goto panic_error;
MYwrite_word (mumkid[1], x);
break;
}
break;
case RDP_Reset:
/* Reset */
#ifdef DEBUG
fprintf (stderr, "RDP Reset\n");
#endif
MYwrite_char (mumkid[1], message);
break;
default:
/* Hmm.. bad RDP operation */
fprintf (stderr, "RDP Bad RDP request (%d)\n", message);
MYwrite_char (debugsock, RDP_Return);
MYwrite_char (debugsock, RDIError_UnimplementedMessage);
break;
}
}
if (FD_ISSET (kidmum[0], &readfds))
{
#ifdef DEBUG
fprintf (stderr, "->ARMulator\n");
#endif
/* Anything we get from the ARMulator has to go to the debugger... */
/* It is that simple! */
passon (kidmum[0], debugsock, 1);
}
}
}

17
sim/arm/tconfig.in Normal file
View File

@@ -0,0 +1,17 @@
/* ARM target configuration file. */
/* Define this if the simulator supports profiling.
See the mips simulator for an example.
This enables the `-p foo' and `-s bar' options.
The target is required to provide sim_set_profile{,_size}. */
/* #define SIM_HAVE_PROFILE */
/* Define this if the simulator uses an instruction cache.
See the h8/300 simulator for an example.
This enables the `-c size' option to set the size of the cache.
The target is required to provide sim_set_simcache_size. */
/* #define SIM_HAVE_SIMCACHE */
/* Define this if the target cpu is bi-endian
and the simulator supports it. */
#define SIM_HAVE_BIENDIAN

455
sim/arm/thumbemu.c Normal file
View File

@@ -0,0 +1,455 @@
/* thumbemu.c -- Thumb instruction emulation.
Copyright (C) 1996, Cygnus Software Technologies Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* We can provide simple Thumb simulation by decoding the Thumb
instruction into its corresponding ARM instruction, and using the
existing ARM simulator. */
#ifndef MODET /* required for the Thumb instruction support */
#if 1
#error "MODET needs to be defined for the Thumb world to work"
#else
#define MODET (1)
#endif
#endif
#include "armdefs.h"
#include "armemu.h"
/* Decode a 16bit Thumb instruction. The instruction is in the low
16-bits of the tinstr field, with the following Thumb instruction
held in the high 16-bits. Passing in two Thumb instructions allows
easier simulation of the special dual BL instruction. */
tdstate
ARMul_ThumbDecode (state,pc,tinstr,ainstr)
ARMul_State *state;
ARMword pc;
ARMword tinstr;
ARMword *ainstr;
{
tdstate valid = t_decoded; /* default assumes a valid instruction */
ARMword next_instr;
if (state->bigendSig)
{
next_instr = tinstr & 0xFFFF;
tinstr >>= 16;
}
else
{
next_instr = tinstr >> 16;
tinstr &= 0xFFFF;
}
#if 1 /* debugging to catch non updates */
*ainstr = 0xDEADC0DE;
#endif
switch ((tinstr & 0xF800) >> 11)
{
case 0: /* LSL */
case 1: /* LSR */
case 2: /* ASR */
/* Format 1 */
*ainstr = 0xE1B00000 /* base opcode */
| ((tinstr & 0x1800) >> (11 - 5)) /* shift type */
| ((tinstr & 0x07C0) << (7 - 6)) /* imm5 */
| ((tinstr & 0x0038) >> 3) /* Rs */
| ((tinstr & 0x0007) << 12); /* Rd */
break;
case 3: /* ADD/SUB */
/* Format 2 */
{
ARMword subset[4] = {
0xE0900000, /* ADDS Rd,Rs,Rn */
0xE0500000, /* SUBS Rd,Rs,Rn */
0xE2900000, /* ADDS Rd,Rs,#imm3 */
0xE2500000 /* SUBS Rd,Rs,#imm3 */
};
/* It is quicker indexing into a table, than performing switch
or conditionals: */
*ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */
| ((tinstr & 0x01C0) >> 6) /* Rn or imm3 */
| ((tinstr & 0x0038) << (16 - 3)) /* Rs */
| ((tinstr & 0x0007) << (12 - 0)); /* Rd */
}
break;
case 4: /* MOV */
case 5: /* CMP */
case 6: /* ADD */
case 7: /* SUB */
/* Format 3 */
{
ARMword subset[4] = {
0xE3B00000, /* MOVS Rd,#imm8 */
0xE3500000, /* CMP Rd,#imm8 */
0xE2900000, /* ADDS Rd,Rd,#imm8 */
0xE2500000, /* SUBS Rd,Rd,#imm8 */
};
*ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */
| ((tinstr & 0x00FF) >> 0) /* imm8 */
| ((tinstr & 0x0700) << (16 - 8)) /* Rn */
| ((tinstr & 0x0700) << (12 - 8)); /* Rd */
}
break ;
case 8: /* Arithmetic and high register transfers */
/* TODO: Since the subsets for both Format 4 and Format 5
instructions are made up of different ARM encodings, we could
save the following conditional, and just have one large
subset. */
if ((tinstr & (1 << 10)) == 0)
{
/* Format 4 */
struct {
ARMword opcode;
enum {t_norm,t_shift,t_neg,t_mul} otype;
} subset[16] = {
{0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */
{0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */
{0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */
{0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */
{0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */
{0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */
{0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */
{0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */
{0xE1100000, t_norm}, /* TST Rd,Rs */
{0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */
{0xE1500000, t_norm}, /* CMP Rd,Rs */
{0xE1700000, t_norm}, /* CMN Rd,Rs */
{0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */
{0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */
{0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */
{0xE1F00000, t_norm} /* MVNS Rd,Rs */
};
*ainstr = subset[(tinstr & 0x03C0)>>6].opcode; /* base */
switch (subset[(tinstr & 0x03C0)>>6].otype)
{
case t_norm:
*ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
| ((tinstr & 0x0007) << 12) /* Rd */
| ((tinstr & 0x0038) >> 3); /* Rs */
break;
case t_shift:
*ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
| ((tinstr & 0x0007) >> 0) /* Rm */
| ((tinstr & 0x0038) << (8 - 3)); /* Rs */
break;
case t_neg:
*ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
| ((tinstr & 0x0038) << (16 - 3)); /* Rn */
break;
case t_mul:
*ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
| ((tinstr & 0x0007) << 8) /* Rs */
| ((tinstr & 0x0038) >> 3); /* Rm */
break;
}
}
else
{
/* Format 5 */
ARMword Rd = ((tinstr & 0x0007) >> 0);
ARMword Rs = ((tinstr & 0x0038) >> 3);
if (tinstr & (1 << 7))
Rd += 8;
if (tinstr & (1 << 6))
Rs += 8;
switch ((tinstr & 0x03C0) >> 6)
{
case 0x1: /* ADD Rd,Rd,Hs */
case 0x2: /* ADD Hd,Hd,Rs */
case 0x3: /* ADD Hd,Hd,Hs */
*ainstr = 0xE0800000 /* base */
| (Rd << 16) /* Rn */
| (Rd << 12) /* Rd */
| (Rs << 0); /* Rm */
break;
case 0x5: /* CMP Rd,Hs */
case 0x6: /* CMP Hd,Rs */
case 0x7: /* CMP Hd,Hs */
*ainstr = 0xE1500000 /* base */
| (Rd << 16) /* Rn */
| (Rd << 12) /* Rd */
| (Rs << 0); /* Rm */
break;
case 0x9: /* MOV Rd,Hs */
case 0xA: /* MOV Hd,Rs */
case 0xB: /* MOV Hd,Hs */
*ainstr = 0xE1A00000 /* base */
| (Rd << 16) /* Rn */
| (Rd << 12) /* Rd */
| (Rs << 0); /* Rm */
break;
case 0xC: /* BX Rs */
case 0xD: /* BX Hs */
*ainstr = 0xE12FFF10 /* base */
| ((tinstr & 0x0078) >> 3); /* Rd */
break;
case 0x0: /* UNDEFINED */
case 0x4: /* UNDEFINED */
case 0x8: /* UNDEFINED */
case 0xE: /* UNDEFINED */
case 0xF: /* UNDEFINED */
valid = t_undefined;
break;
}
}
break;
case 9: /* LDR Rd,[PC,#imm8] */
/* Format 6 */
*ainstr = 0xE59F0000 /* base */
| ((tinstr & 0x0700) << (12 - 8)) /* Rd */
| ((tinstr & 0x00FF) << (2 - 0)); /* off8 */
break;
case 10:
case 11:
/* TODO: Format 7 and Format 8 perform the same ARM encoding, so
the following could be merged into a single subset, saving on
the following boolean: */
if ((tinstr & (1 << 9)) == 0)
{
/* Format 7 */
ARMword subset[4] = {
0xE7800000, /* STR Rd,[Rb,Ro] */
0xE7C00000, /* STRB Rd,[Rb,Ro] */
0xE7900000, /* LDR Rd,[Rb,Ro] */
0xE7D00000 /* LDRB Rd,[Rb,Ro] */
};
*ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
| ((tinstr & 0x0007) << (12 - 0)) /* Rd */
| ((tinstr & 0x0038) << (16 - 3)) /* Rb */
| ((tinstr & 0x01C0) >> 6); /* Ro */
}
else
{
/* Format 8 */
ARMword subset[4] = {
0xE18000B0, /* STRH Rd,[Rb,Ro] */
0xE19000D0, /* LDRSB Rd,[Rb,Ro] */
0xE19000B0, /* LDRH Rd,[Rb,Ro] */
0xE19000F0 /* LDRSH Rd,[Rb,Ro] */
};
*ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
| ((tinstr & 0x0007) << (12 - 0)) /* Rd */
| ((tinstr & 0x0038) << (16 - 3)) /* Rb */
| ((tinstr & 0x01C0) >> 6); /* Ro */
}
break;
case 12: /* STR Rd,[Rb,#imm5] */
case 13: /* LDR Rd,[Rb,#imm5] */
case 14: /* STRB Rd,[Rb,#imm5] */
case 15: /* LDRB Rd,[Rb,#imm5] */
/* Format 9 */
{
ARMword subset[4] = {
0xE5800000, /* STR Rd,[Rb,#imm5] */
0xE5900000, /* LDR Rd,[Rb,#imm5] */
0xE5C00000, /* STRB Rd,[Rb,#imm5] */
0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
};
/* The offset range defends on whether we are transferring a
byte or word value: */
*ainstr = subset[(tinstr & 0x1800) >> 11] /* base */
| ((tinstr & 0x0007) << (12 - 0)) /* Rd */
| ((tinstr & 0x0038) << (16 - 3)) /* Rb */
| ((tinstr & 0x07C0) >>
(6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */
}
break;
case 16: /* STRH Rd,[Rb,#imm5] */
case 17: /* LDRH Rd,[Rb,#imm5] */
/* Format 10 */
*ainstr = ((tinstr & (1 << 11)) /* base */
? 0xE1D000B0 /* LDRH */
: 0xE1C000B0) /* STRH */
| ((tinstr & 0x0007) << (12 - 0)) /* Rd */
| ((tinstr & 0x0038) << (16 - 3)) /* Rb */
| ((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */
| ((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */
break;
case 18: /* STR Rd,[SP,#imm8] */
case 19: /* LDR Rd,[SP,#imm8] */
/* Format 11 */
*ainstr = ((tinstr & (1 << 11)) /* base */
? 0xE59D0000 /* LDR */
: 0xE58D0000) /* STR */
| ((tinstr & 0x0700) << (12 - 8)) /* Rd */
| ((tinstr & 0x00FF) << 2); /* off8 */
break;
case 20: /* ADD Rd,PC,#imm8 */
case 21: /* ADD Rd,SP,#imm8 */
/* Format 12 */
if ((tinstr & (1 << 11)) == 0)
{
/* NOTE: The PC value used here should by word aligned */
/* We encode shift-left-by-2 in the rotate immediate field,
so no shift of off8 is needed. */
*ainstr = 0xE28F0F00 /* base */
| ((tinstr & 0x0700) << (12 - 8)) /* Rd */
| (tinstr & 0x00FF); /* off8 */
}
else
{
/* We encode shift-left-by-2 in the rotate immediate field,
so no shift of off8 is needed. */
*ainstr = 0xE28D0F00 /* base */
| ((tinstr & 0x0700) << (12 - 8)) /* Rd */
| (tinstr & 0x00FF); /* off8 */
}
break;
case 22:
case 23:
if ((tinstr & 0x0F00) == 0x0000)
{
/* Format 13 */
/* NOTE: The instruction contains a shift left of 2
equivalent (implemented as ROR #30): */
*ainstr = ((tinstr & (1 << 7)) /* base */
? 0xE24DDF00 /* SUB */
: 0xE28DDF00) /* ADD */
| (tinstr & 0x007F); /* off7 */
}
else
{
/* Format 14 */
ARMword subset[4] = {
0xE92D0000, /* STMDB sp!,{rlist} */
0xE92D4000, /* STMDB sp!,{rlist,lr} */
0xE8BD0000, /* LDMIA sp!,{rlist} */
0xE8BD8000 /* LDMIA sp!,{rlist,pc} */
};
*ainstr = subset[((tinstr & (1 << 11)) >> 10)
| ((tinstr & (1 << 8)) >> 8)] /* base */
| (tinstr & 0x00FF); /* mask8 */
}
break;
case 24: /* STMIA */
case 25: /* LDMIA */
/* Format 15 */
*ainstr = ((tinstr & (1 << 11)) /* base */
? 0xE8B00000 /* LDMIA */
: 0xE8A00000) /* STMIA */
| ((tinstr & 0x0700) << (16 - 8)) /* Rb */
| (tinstr & 0x00FF); /* mask8 */
break;
case 26: /* Bcc */
case 27: /* Bcc/SWI */
if ((tinstr & 0x0F00) == 0x0F00)
{
/* Format 17 : SWI */
*ainstr = 0xEF000000;
/* Breakpoint must be handled specially. */
if ((tinstr & 0x00FF) == 0x18)
*ainstr |= ((tinstr & 0x00FF) << 16);
else
*ainstr |= (tinstr & 0x00FF);
}
else if ((tinstr & 0x0F00) != 0x0E00)
{
/* Format 16 */
int doit = FALSE;
/* TODO: Since we are doing a switch here, we could just add
the SWI and undefined instruction checks into this
switch to same on a couple of conditionals: */
switch ((tinstr & 0x0F00) >> 8) {
case EQ : doit=ZFLAG ;
break ;
case NE : doit=!ZFLAG ;
break ;
case VS : doit=VFLAG ;
break ;
case VC : doit=!VFLAG ;
break ;
case MI : doit=NFLAG ;
break ;
case PL : doit=!NFLAG ;
break ;
case CS : doit=CFLAG ;
break ;
case CC : doit=!CFLAG ;
break ;
case HI : doit=(CFLAG && !ZFLAG) ;
break ;
case LS : doit=(!CFLAG || ZFLAG) ;
break ;
case GE : doit=((!NFLAG && !VFLAG) || (NFLAG && VFLAG)) ;
break ;
case LT : doit=((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) ;
break ;
case GT : doit=((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG)) ;
break ;
case LE : doit=((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG ;
break ;
}
if (doit) {
state->Reg[15] = pc + 4
+ (((tinstr & 0x7F) << 1)
| ((tinstr & (1 << 7)) ? 0xFFFFFF00 : 0));
FLUSHPIPE;
}
valid = t_branch;
}
else /* UNDEFINED : cc=1110(AL) uses different format */
valid = t_undefined;
break;
case 28: /* B */
/* Format 18 */
state->Reg[15] = pc + 4
+ (((tinstr & 0x3FF) << 1)
| ((tinstr & (1 << 10)) ? 0xFFFFF800 : 0));
FLUSHPIPE;
valid = t_branch;
break;
case 29: /* UNDEFINED */
valid = t_undefined;
break;
case 30: /* BL instruction 1 */
/* Format 19 */
/* There is no single ARM instruction equivalent for this Thumb
instruction. To keep the simulation simple (from the user
perspective) we check if the following instruction is the
second half of this BL, and if it is we simulate it
immediately. */
state->Reg[14] = state->Reg[15] \
+ (((tinstr & 0x07FF) << 12) \
| ((tinstr & (1 << 10)) ? 0xFF800000 : 0));
valid = t_branch; /* in-case we don't have the 2nd half */
tinstr = next_instr; /* move the instruction down */
if (((tinstr & 0xF800) >> 11) != 31)
break; /* exit, since not correct instruction */
/* else we fall through to process the second half of the BL */
pc += 2; /* point the pc at the 2nd half */
case 31: /* BL instruction 2 */
/* Format 19 */
/* There is no single ARM instruction equivalent for this
instruction. Also, it should only ever be matched with the
fmt19 "BL instruction 1" instruction. However, we do allow
the simulation of it on its own, with undefined results if
r14 is not suitably initialised.*/
{
ARMword tmp = (pc + 2);
state->Reg[15] = (state->Reg[14] + ((tinstr & 0x07FF) << 1));
state->Reg[14] = (tmp | 1);
valid = t_branch;
FLUSHPIPE;
}
break;
}
return valid;
}

467
sim/arm/wrapper.c Normal file
View File

@@ -0,0 +1,467 @@
/* run front end support for arm
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of ARM SIM.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file provides the interface between the simulator and run.c and gdb
(when the simulator is linked with gdb).
All simulator interaction should go through this file. */
#include <stdio.h>
#include <stdarg.h>
#include <bfd.h>
#include <signal.h>
#include "callback.h"
#include "remote-sim.h"
#include "armdefs.h"
#include "armemu.h"
#include "dbg_rdi.h"
host_callback *sim_callback;
static struct ARMul_State *state;
/* Who is using the simulator. */
static SIM_OPEN_KIND sim_kind;
/* argv[0] */
static char *myname;
/* Memory size in bytes. */
static int mem_size = (1 << 21);
/* Non-zero to display start up banner, and maybe other things. */
static int verbosity;
/* Non-zero to set big endian mode. */
static int big_endian;
static void
init ()
{
static int done;
if (!done)
{
ARMul_EmulateInit();
state = ARMul_NewState ();
state->bigendSig = (big_endian ? HIGH : LOW);
ARMul_MemoryInit(state, mem_size);
ARMul_OSInit(state);
ARMul_CoProInit(state);
state->verbose = verbosity;
done = 1;
}
}
/* Set verbosity level of simulator.
This is not intended to produce detailed tracing or debugging information.
Just summaries. */
/* FIXME: common/run.c doesn't do this yet. */
void
sim_set_verbose (v)
int v;
{
verbosity = v;
}
/* Set the memory size to SIZE bytes.
Must be called before initializing simulator. */
/* FIXME: Rename to sim_set_mem_size. */
void
sim_size (size)
int size;
{
mem_size = size;
}
void
ARMul_ConsolePrint (ARMul_State * state, const char *format,...)
{
va_list ap;
if (state->verbose)
{
va_start (ap, format);
vprintf (format, ap);
va_end (ap);
}
}
ARMword
ARMul_Debug (ARMul_State * state, ARMword pc, ARMword instr)
{
}
int
sim_write (sd, addr, buffer, size)
SIM_DESC sd;
SIM_ADDR addr;
unsigned char *buffer;
int size;
{
int i;
init ();
for (i = 0; i < size; i++)
{
ARMul_WriteByte (state, addr+i, buffer[i]);
}
return size;
}
int
sim_read (sd, addr, buffer, size)
SIM_DESC sd;
SIM_ADDR addr;
unsigned char *buffer;
int size;
{
int i;
init ();
for (i = 0; i < size; i++)
{
buffer[i] = ARMul_ReadByte (state, addr + i);
}
return size;
}
int
sim_trace (sd)
SIM_DESC sd;
{
(*sim_callback->printf_filtered) (sim_callback, "This simulator does not support tracing\n");
return 1;
}
int
sim_stop (sd)
SIM_DESC sd;
{
return 0;
}
void
sim_resume (sd, step, siggnal)
SIM_DESC sd;
int step, siggnal;
{
state->EndCondition = 0;
if (step)
{
state->Reg[15] = ARMul_DoInstr (state);
if (state->EndCondition == 0)
state->EndCondition = RDIError_BreakpointReached;
}
else
{
#if 1 /* JGS */
state->NextInstr = RESUME; /* treat as PC change */
#endif
state->Reg[15] = ARMul_DoProg (state);
}
FLUSHPIPE;
}
SIM_RC
sim_create_inferior (sd, abfd, argv, env)
SIM_DESC sd;
struct _bfd *abfd;
char **argv;
char **env;
{
int argvlen=0;
char **arg;
if (abfd != NULL)
ARMul_SetPC (state, bfd_get_start_address (abfd));
else
ARMul_SetPC (state, 0); /* ??? */
#if 1 /* JGS */
/* We explicitly select a processor capable of supporting the ARM
32bit mode, and then we force the simulated CPU into the 32bit
User mode: */
ARMul_SelectProcessor(state, ARM600);
ARMul_SetCPSR(state, USER32MODE);
#endif
if (argv != NULL)
{
/*
** Set up the command line (by laboriously stringing together the
** environment carefully picked apart by our caller...)
*/
/* Free any old stuff */
if (state->CommandLine != NULL)
{
free(state->CommandLine);
state->CommandLine = NULL;
}
/* See how much we need */
for (arg = argv; *arg != NULL; arg++)
argvlen += strlen(*arg)+1;
/* allocate it... */
state->CommandLine = malloc(argvlen+1);
if (state->CommandLine != NULL)
{
arg = argv;
state->CommandLine[0]='\0';
for (arg = argv; *arg != NULL; arg++)
{
strcat(state->CommandLine, *arg);
strcat(state->CommandLine, " ");
}
}
}
if (env != NULL)
{
/* Now see if there's a MEMSIZE spec in the environment */
while (*env)
{
if (strncmp(*env, "MEMSIZE=", sizeof("MEMSIZE=")-1)==0)
{
unsigned long top_of_memory;
char *end_of_num;
/* Set up memory limit */
state->MemSize = strtoul(*env + sizeof("MEMSIZE=")-1, &end_of_num, 0);
}
env++;
}
}
return SIM_RC_OK;
}
void
sim_info (sd, verbose)
SIM_DESC sd;
int verbose;
{
}
static int
frommem (state, memory)
struct ARMul_State *state;
unsigned char *memory;
{
if (state->bigendSig == HIGH)
{
return (memory[0] << 24)
| (memory[1] << 16)
| (memory[2] << 8)
| (memory[3] << 0);
}
else
{
return (memory[3] << 24)
| (memory[2] << 16)
| (memory[1] << 8)
| (memory[0] << 0);
}
}
static void
tomem (state, memory, val)
struct ARMul_State *state;
unsigned char *memory;
int val;
{
if (state->bigendSig == HIGH)
{
memory[0] = val >> 24;
memory[1] = val >> 16;
memory[2] = val >> 8;
memory[3] = val >> 0;
}
else
{
memory[3] = val >> 24;
memory[2] = val >> 16;
memory[1] = val >> 8;
memory[0] = val >> 0;
}
}
int
sim_store_register (sd, rn, memory, length)
SIM_DESC sd;
int rn;
unsigned char *memory;
int length;
{
init ();
ARMul_SetReg(state, state->Mode, rn, frommem (state, memory));
return -1;
}
int
sim_fetch_register (sd, rn, memory, length)
SIM_DESC sd;
int rn;
unsigned char *memory;
int length;
{
ARMword regval;
init ();
if (rn < 16)
regval = ARMul_GetReg(state, state->Mode, rn);
else if (rn == 25) /* FIXME: use PS_REGNUM from gdb/config/arm/tm-arm.h */
regval = ARMul_GetCPSR(state);
else
regval = 0; /* FIXME: should report an error */
tomem (state, memory, regval);
return -1;
}
SIM_DESC
sim_open (kind, ptr, abfd, argv)
SIM_OPEN_KIND kind;
host_callback *ptr;
struct _bfd *abfd;
char **argv;
{
sim_kind = kind;
myname = argv[0];
sim_callback = ptr;
/* Decide upon the endian-ness of the processor.
If we can, get the information from the bfd itself.
Otherwise look to see if we have been given a command
line switch that tells us. Otherwise default to little endian. */
if (abfd != NULL)
big_endian = bfd_big_endian (abfd);
else if (argv[1] != NULL)
{
int i;
/* Scan for endian-ness switch. */
for (i = 0; (argv[i] != NULL) && (argv[i][0] != 0); i++)
if (argv[i][0] == '-' && argv[i][1] == 'E')
{
char c;
if ((c = argv[i][2]) == 0)
{
++i;
c = argv[i][0];
}
switch (c)
{
case 0:
sim_callback->printf_filtered
(sim_callback, "No argument to -E option provided\n");
break;
case 'b':
case 'B':
big_endian = 1;
break;
case 'l':
case 'L':
big_endian = 0;
break;
default:
sim_callback->printf_filtered
(sim_callback, "Unrecognised argument to -E option\n");
break;
}
}
}
return (SIM_DESC) 1;
}
void
sim_close (sd, quitting)
SIM_DESC sd;
int quitting;
{
/* nothing to do */
}
SIM_RC
sim_load (sd, prog, abfd, from_tty)
SIM_DESC sd;
char *prog;
bfd *abfd;
int from_tty;
{
extern bfd *sim_load_file (); /* ??? Don't know where this should live. */
bfd *prog_bfd;
prog_bfd = sim_load_file (sd, myname, sim_callback, prog, abfd,
sim_kind == SIM_OPEN_DEBUG,
0, sim_write);
if (prog_bfd == NULL)
return SIM_RC_FAIL;
ARMul_SetPC (state, bfd_get_start_address (prog_bfd));
if (abfd == NULL)
bfd_close (prog_bfd);
return SIM_RC_OK;
}
void
sim_stop_reason (sd, reason, sigrc)
SIM_DESC sd;
enum sim_stop *reason;
int *sigrc;
{
if (state->EndCondition == 0)
{
*reason = sim_exited;
*sigrc = state->Reg[0] & 255;
}
else
{
*reason = sim_stopped;
if (state->EndCondition == RDIError_BreakpointReached)
*sigrc = SIGTRAP;
else
*sigrc = 0;
}
}
void
sim_do_command (sd, cmd)
SIM_DESC sd;
char *cmd;
{
(*sim_callback->printf_filtered) (sim_callback, "This simulator does not accept any commands.\n");
}
void
sim_set_callbacks (ptr)
host_callback *ptr;
{
sim_callback = ptr;
}

4005
sim/common/ChangeLog Normal file

File diff suppressed because it is too large Load Diff

642
sim/common/Make-common.in Normal file
View File

@@ -0,0 +1,642 @@
# Makefile fragment for common parts of all simulators.
# Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
# Contributed by Cygnus Support.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# This Makefile fragment consists of two separate parts.
# They are merged into the final Makefile at points denoted by
# "## COMMON_PRE_CONFIG_FRAG" and "## COMMON_POST_CONFIG_FRAG".
#
# The target Makefile should look like:
#
#># Copyright blah blah
#>
#>## COMMON_PRE_CONFIG_FRAG
#>
#># Any overrides necessary for the SIM_FOO config vars.
#>SIM_FOO = ...
#>
#>## COMMON_POST_CONFIG_FRAG
#>
#># Rules to build target specific .o's.
## COMMON_PRE_CONFIG_FRAG
VPATH = @srcdir@
srcdir = @srcdir@
srccom = $(srcdir)/../common
srcroot = $(srcdir)/../..
prefix = @prefix@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
target_alias = @target_alias@
program_transform_name = @program_transform_name@
bindir = @bindir@
libdir = @libdir@
tooldir = $(libdir)/$(target_alias)
datadir = @datadir@
mandir = @mandir@
man1dir = $(mandir)/man1
infodir = @infodir@
includedir = @includedir@
# This can be referenced by the gettext configuration code.
top_builddir = ..
EXEEXT = @EXEEXT@
SHELL = @SHELL@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CC = @CC@
CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
SIM_BSWAP = @sim_bswap@
SIM_CFLAGS = @sim_cflags@
SIM_DEBUG = @sim_debug@
SIM_TRACE = @sim_trace@
SIM_PROFILE = @sim_profile@
SIM_ASSERT = @sim_assert@
SIM_ALIGNMENT = @sim_alignment@
SIM_BITSIZE = @sim_bitsize@
SIM_DEFAULT_MODEL = @sim_default_model@
SIM_ENDIAN = @sim_endian@
SIM_ENVIRONMENT = @sim_environment@
SIM_FLOAT = @sim_float@
SIM_HW_CFLAGS = @sim_hw_cflags@
SIM_HW_OBJS = @sim_hw_objs@
SIM_HW = @sim_hw@
SIM_HOSTENDIAN = @sim_hostendian@
SIM_INLINE = @sim_inline@
SIM_PACKAGES = @sim_packages@
SIM_REGPARM = @sim_regparm@
SIM_RESERVED_BITS = @sim_reserved_bits@
SIM_SCACHE = @sim_scache@
SIM_SMP = @sim_smp@
SIM_STDCALL = @sim_stdcall@
SIM_WARNINGS = @build_warnings@
SIM_XOR_ENDIAN = @sim_xor_endian@
HDEFINES = @HDEFINES@
TDEFINES =
AR = @AR@
AR_FLAGS = rc
RANLIB = @RANLIB@
MAKEINFO = makeinfo
DEP = $(srcroot)/mkdep
# Each simulator's Makefile.in defines one or more of these variables
# to override our settings as necessary. There is no need to define these
# in the simulator's Makefile.in if one is using the default value. In fact
# it's preferable not to.
# List of object files, less common parts.
SIM_OBJS =
# List of extra dependencies.
# Generally this consists of simulator specific files included by sim-main.h.
SIM_EXTRA_DEPS =
# List of flags to always pass to $(CC).
SIM_EXTRA_CFLAGS =
# List of extra libraries to link with.
SIM_EXTRA_LIBS =
# List of extra program dependencies.
SIM_EXTRA_LIBDEPS =
# List of main object files for `run'.
SIM_RUN_OBJS = run.o
# Dependency of `all' to build any extra files.
SIM_EXTRA_ALL =
# Dependency of `install' to install any extra files.
SIM_EXTRA_INSTALL =
# Dependency of `clean' to clean any extra files.
SIM_EXTRA_CLEAN =
# Every time a new general purpose source file was added every target's
# Makefile.in needed to be updated to include the file in SIM_OBJS.
# This doesn't scale.
# This variable specifies all the generic stuff common to the newer simulators.
# Things like sim-reason.o can't go here as the cpu may provide its own
# (though hopefully in time that won't be so). Things like sim-bits.o can go
# here. Some files are used by all simulators (e.g. callback.o).
# Those files are specified in LIB_OBJS below.
SIM_COMMON_HW_OBJS = \
hw-alloc.o \
hw-base.o \
hw-device.o \
hw-events.o \
hw-handles.o \
hw-instances.o \
hw-ports.o \
hw-properties.o \
hw-tree.o \
sim-hw.o \
SIM_NEW_COMMON_OBJS = \
sim-arange.o \
sim-bits.o \
sim-break.o \
sim-config.o \
sim-core.o \
sim-endian.o \
sim-events.o \
sim-fpu.o \
sim-io.o \
sim-info.o \
sim-load.o \
sim-memopt.o \
sim-module.o \
sim-options.o \
sim-profile.o \
sim-signal.o \
sim-trace.o \
sim-utils.o \
sim-watch.o \
\
$(SIM_HW_OBJS) \
# Add this to SIM_EXTRA_DEPS.
CGEN_INCLUDE_DEPS = \
$(srccom)/cgen-cpu.h \
$(srccom)/cgen-defs.h \
$(srccom)/cgen-engine.h \
$(srccom)/cgen-scache.h \
$(srccom)/cgen-sim.h \
$(srccom)/cgen-trace.h \
$(srccom)/cgen-types.h \
$(srcdir)/../../include/opcode/cgen.h
## End COMMON_PRE_CONFIG_FRAG
## COMMON_POST_CONFIG_FRAG
CONFIG_CFLAGS = \
@DEFS@ \
$(SIM_CFLAGS) \
$(SIM_DEBUG) \
$(SIM_DEFAULT_MODEL) \
$(SIM_TRACE) \
$(SIM_PROFILE) \
$(SIM_BSWAP) \
$(SIM_ASSERT) \
$(SIM_ALIGNMENT) \
$(SIM_BITSIZE) \
$(SIM_ENDIAN) \
$(SIM_ENVIRONMENT) \
$(SIM_FLOAT) \
$(SIM_HW_CFLAGS) \
$(SIM_HOSTENDIAN) \
$(SIM_INLINE) \
$(SIM_PACKAGES) \
$(SIM_REGPARM) \
$(SIM_RESERVED_BITS) \
$(SIM_SCACHE) \
$(SIM_SMP) \
$(SIM_STDCALL) \
$(SIM_WARNINGS) \
$(SIM_XOR_ENDIAN) \
$(SIM_HARDWARE) \
$(SIM_EXTRA_CFLAGS) \
$(HDEFINES) $(TDEFINES)
CSEARCH = -I. -I$(srcdir) -I../common -I$(srccom) \
-I../../include -I$(srcroot)/include \
-I../../bfd -I$(srcroot)/bfd \
-I../../opcodes -I$(srcroot)/opcodes \
-I../../intl -I$(srcroot)/intl
ALL_CFLAGS = $(CONFIG_CFLAGS) $(CSEARCH) $(CFLAGS)
BUILD_CFLAGS = -g -O $(CSEARCH)
COMMON_DEP_CFLAGS = $(CONFIG_CFLAGS) $(CSEARCH)
LIBIBERTY_LIB = ../../libiberty/libiberty.a
BFD_LIB = ../../bfd/libbfd.a
OPCODES_LIB = ../../opcodes/libopcodes.a
INTLLIBS = @INTLLIBS@
INTLDEPS = @INTLDEPS@
CONFIG_LIBS = @LIBS@
LIBDEPS = $(BFD_LIB) $(OPCODES_LIB) $(INTLLIBS) $(LIBIBERTY_LIB) \
$(SIM_EXTRA_LIBDEPS)
EXTRA_LIBS = $(BFD_LIB) $(OPCODES_LIB) $(INTLLIBS) $(LIBIBERTY_LIB) \
$(CONFIG_LIBS) $(SIM_EXTRA_LIBS)
LIB_OBJS = callback.o syscall.o targ-map.o $(SIM_OBJS)
RUNTESTFLAGS =
all: $(SIM_EXTRA_ALL) libsim.a run .gdbinit
libsim.a: $(LIB_OBJS)
rm -f libsim.a
$(AR) $(AR_FLAGS) libsim.a $(LIB_OBJS)
$(RANLIB) libsim.a
run: $(SIM_RUN_OBJS) libsim.a $(LIBDEPS)
$(CC) $(ALL_CFLAGS) -o run$(EXEEXT) \
$(SIM_RUN_OBJS) libsim.a $(EXTRA_LIBS)
run.o: $(srccom)/run.c config.h tconfig.h \
$(srcroot)/include/remote-sim.h $(srcroot)/include/callback.h
$(CC) -c $(srccom)/run.c $(ALL_CFLAGS)
# FIXME: Ideally, callback.o and friends live in a library outside of
# both the gdb and simulator source trees (e.g. devo/remote. Not
# devo/libremote because this directory would contain more than just
# a library).
callback.o: $(srccom)/callback.c config.h tconfig.h \
$(srcroot)/include/callback.h targ-vals.h
$(CC) -c $(srccom)/callback.c $(ALL_CFLAGS)
syscall.o: $(srccom)/syscall.c config.h tconfig.h \
$(srcroot)/include/callback.h targ-vals.h
$(CC) -c $(srccom)/syscall.c $(ALL_CFLAGS)
targ-map.o: targ-map.c targ-vals.h
gentmap: Makefile $(srccom)/gentmap.c targ-vals.def
$(CC_FOR_BUILD) $(srccom)/gentmap.c -o gentmap $(BUILD_CFLAGS) $(NL_TARGET)
targ-vals.h targ-map.c: stamp-tvals
stamp-tvals: gentmap
rm -f tmp-tvals.h tmp-tmap.c
./gentmap -h >tmp-tvals.h
$(SHELL) $(srcroot)/move-if-change tmp-tvals.h targ-vals.h
./gentmap -c >tmp-tmap.c
$(SHELL) $(srcroot)/move-if-change tmp-tmap.c targ-map.c
touch stamp-tvals
#
# Rules for building sim-* components. Triggered by listing the corresponding
# .o file in the list of simulator targets.
#
sim_main_headers = \
sim-main.h \
$(srccom)/sim-assert.h \
$(srccom)/sim-base.h \
$(srccom)/sim-basics.h \
$(srccom)/sim-config.h \
$(srccom)/sim-cpu.h \
$(srccom)/sim-engine.h \
$(srccom)/sim-events.h \
$(srccom)/sim-inline.h \
$(srccom)/sim-memopt.h \
$(srccom)/sim-model.h \
$(srccom)/sim-module.h \
$(srccom)/sim-profile.h \
$(srccom)/sim-signal.h \
$(srccom)/sim-trace.h \
$(srccom)/sim-watch.h \
tconfig.h \
$(SIM_EXTRA_DEPS)
# Exported version of sim_main_headers.
SIM_MAIN_DEPS = \
$(sim_main_headers)
sim-assert_h = $(srccom)/sim-assert.h
sim-endian_h = $(srccom)/sim-endian.h
sim-n-endian_h = $(srccom)/sim-n-endian.h
sim-arange_h = $(srccom)/sim-arange.h
sim-bits_h = $(srccom)/sim-bits.h
sim-config_h = $(srccom)/sim-config.h
sim-n-bits_h = $(srccom)/sim-n-bits.h
sim-core_h = $(srccom)/sim-core.h
sim-n-core_h = $(srccom)/sim-n-core.h
sim-engine_h = $(srccom)/sim-engine.h
sim-events_h = $(srccom)/sim-events.h
sim-fpu_h = $(srccom)/sim-fpu.h
sim-io_h = $(srccom)/sim-io.h
sim-options_h = $(srccom)/sim-options.h
sim-break_h = $(srccom)/sim-break.h
sim-signal_h = $(srccom)/sim-signal.h
hw-alloc_h = $(srccom)/hw-alloc.h
hw-base_h = $(srccom)/hw-base.h
hw-device_h = $(srccom)/hw-device.h
hw-events_h = $(srccom)/hw-events.h
hw-handles_h = $(srccom)/hw-handles.h
hw-instances_h = $(srccom)/hw-instances.h
hw-ports_h = $(srccom)/hw-ports.h
hw-properties_h = $(srccom)/hw-properties.h
hw-tree_h = $(srccom)/hw-tree.h
hw_main_headers = \
$(srccom)/hw-main.h \
$(hw-alloc_h) \
$(hw-base_h) \
$(hw-device_h) \
$(hw-events_h) \
$(hw-instances_h) \
$(hw-handles_h) \
$(hw-ports_h) \
$(hw-properties_h) \
# FIXME: If this complicated way of building .o files from ../common is
# necessary, the reason should be documented here.
BUILT_SRC_FROM_COMMON= \
sim-inline.c
sim-abort.o: $(srccom)/sim-abort.c \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-abort.c $(ALL_CFLAGS)
sim-arange.o: $(srccom)/sim-arange.c $(sim-arange_h) $(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-arange.c $(ALL_CFLAGS)
sim-bits.o: $(srccom)/sim-bits.c $(sim-bits_h) $(sim-n-bits_h) \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-bits.c $(ALL_CFLAGS)
sim-config.o: $(srccom)/sim-config.c $(sim-config_h) \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-config.c $(ALL_CFLAGS)
sim-core.o: $(srccom)/sim-core.c $(sim_main_headers) \
$(sim-core_h) $(sim-n-core_h)
$(CC) -c $(srccom)/sim-core.c $(ALL_CFLAGS)
sim-cpu.o: $(srccom)/sim-cpu.c $(sim_main_headers)
$(CC) -c $(srccom)/sim-cpu.c $(ALL_CFLAGS)
sim-endian.o: $(srccom)/sim-endian.c $(sim-endian_h) $(sim-n-endian_h)
$(CC) -c $(srccom)/sim-endian.c $(ALL_CFLAGS)
sim-engine.o: $(srccom)/sim-engine.c $(sim_main_headers) $(sim-engine_h)
$(CC) -c $(srccom)/sim-engine.c $(ALL_CFLAGS)
sim-events.o: $(srccom)/sim-events.c $(sim-events_h) \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-events.c $(ALL_CFLAGS)
sim-fpu.o: $(srccom)/sim-fpu.c $(sim-fpu_h) \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-fpu.c $(ALL_CFLAGS)
sim-hload.o: $(srccom)/sim-hload.c $(sim-assert_h) \
$(srcroot)/include/remote-sim.h \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-hload.c $(ALL_CFLAGS)
sim-hrw.o: $(srccom)/sim-hrw.c $(sim-assert_h) $(sim_core_h) \
$(srcroot)/include/remote-sim.h \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-hrw.c $(ALL_CFLAGS)
sim-hw.o: $(srccom)/sim-hw.c $(sim_main_headers)
$(CC) -c $(srccom)/sim-hw.c $(ALL_CFLAGS)
sim-info.o: $(srccom)/sim-info.c $(sim-assert_h) \
$(srcroot)/include/remote-sim.h \
$(SIM_EXTRA_DEPS)
$(CC) -c $(srccom)/sim-info.c $(ALL_CFLAGS)
sim-inline.c: $(srccom)/sim-inline.c
rm -f $@ tmp-$@
echo "# 1 \"$(srccom)/$@\"" > tmp-$@
cat $(srccom)/$@ >> tmp-$@
$(SHELL) $(srcdir)/../../move-if-change tmp-$@ $@
sim-io.o: $(srccom)/sim-io.c $(sim_main_headers) $(sim-io_h) \
$(srcroot)/include/remote-sim.h
$(CC) -c $(srccom)/sim-io.c $(ALL_CFLAGS)
sim-memopt.o: $(srccom)/sim-memopt.c $(sim_main_headers) \
$(sim-io_h)
$(CC) -c $(srccom)/sim-memopt.c $(ALL_CFLAGS)
sim-module.o: $(srccom)/sim-module.c $(sim_main_headers) \
$(sim-io_h)
$(CC) -c $(srccom)/sim-module.c $(ALL_CFLAGS)
sim-options.o: $(srccom)/sim-options.c $(sim_main_headers) \
$(sim-options_h) $(sim-io_h)
$(CC) -c $(srccom)/sim-options.c $(ALL_CFLAGS)
sim-reason.o: $(srccom)/sim-reason.c $(sim_main_headers) \
$(srcroot)/include/remote-sim.h
$(CC) -c $(srccom)/sim-reason.c $(ALL_CFLAGS)
sim-reg.o: $(srccom)/sim-reg.c $(sim_main_headers) \
$(srcroot)/include/remote-sim.h
$(CC) -c $(srccom)/sim-reg.c $(ALL_CFLAGS)
sim-resume.o: $(srccom)/sim-resume.c $(sim_main_headers) \
$(srcroot)/include/remote-sim.h
$(CC) -c $(srccom)/sim-resume.c $(ALL_CFLAGS)
sim-run.o: $(srccom)/sim-run.c $(sim_main_headers)
$(CC) -c $(srccom)/sim-run.c $(ALL_CFLAGS)
sim-signal.o: $(srccom)/sim-signal.c $(sim_main_headers) $(sim-signal_h)
$(CC) -c $(srccom)/sim-signal.c $(ALL_CFLAGS)
sim-stop.o: $(srccom)/sim-stop.c $(sim_main_headers)
$(CC) -c $(srccom)/sim-stop.c $(ALL_CFLAGS)
sim-trace.o: $(srccom)/sim-trace.c $(sim_main_headers) \
$(sim-options_h) $(sim-io_h)
$(CC) -c $(srccom)/sim-trace.c $(ALL_CFLAGS)
sim-profile.o: $(srccom)/sim-profile.c $(sim_main_headers) \
$(sim-options_h) $(sim-io_h)
$(CC) -c $(srccom)/sim-profile.c $(ALL_CFLAGS)
sim-model.o: $(srccom)/sim-model.c $(sim_main_headers) \
$(sim-io_h)
$(CC) -c $(srccom)/sim-model.c $(ALL_CFLAGS)
sim-utils.o: $(srccom)/sim-utils.c $(sim_main_headers)
$(CC) -c $(srccom)/sim-utils.c $(ALL_CFLAGS)
sim-watch.o: $(srccom)/sim-watch.c $(sim_main_headers)
$(CC) -c $(srccom)/sim-watch.c $(ALL_CFLAGS)
sim-load.o: $(srccom)/sim-load.c $(srcroot)/include/callback.h
$(CC) -c $(srccom)/sim-load.c $(ALL_CFLAGS)
sim-break.o: $(srccom)/sim-break.c $(sim_main_headers) \
$(sim_break_h)
$(CC) -c $(srccom)/sim-break.c $(ALL_CFLAGS)
# FIXME This is one very simple-minded way of generating the file hw-config.h
hw-config.h: Makefile.in $(srccom)/Make-common.in config.status Makefile
rm -f tmp-hw.h
echo "/* generated by Makefile */" > tmp-hw.h
for hw in $(SIM_HW) ; do \
echo "extern const struct hw_descriptor dv_$${hw}_descriptor[];" ; \
done >> tmp-hw.h
echo "const struct hw_descriptor *hw_descriptors[] = {" >> tmp-hw.h
for hw in $(SIM_HW) ; do \
echo " dv_$${hw}_descriptor," ; \
done >> tmp-hw.h
echo " NULL," >> tmp-hw.h
echo "};" >> tmp-hw.h
mv tmp-hw.h hw-config.h
hw-alloc.o: $(srccom)/hw-alloc.c $(hw_main_headers)
$(CC) -c $(srccom)/hw-alloc.c $(ALL_CFLAGS)
hw-base.o: $(srccom)/hw-base.c $(hw_main_headers) hw-config.h
$(CC) -c $(srccom)/hw-base.c $(ALL_CFLAGS)
hw-device.o: $(srccom)/hw-device.c $(hw_main_headers)
$(CC) -c $(srccom)/hw-device.c $(ALL_CFLAGS)
hw-events.o: $(srccom)/hw-events.c $(hw_main_headers) $(sim_main_headers)
$(CC) -c $(srccom)/hw-events.c $(ALL_CFLAGS)
test-hw-events: $(srccom)/hw-events.c libsim.a
$(CC) $(ALL_CFLAGS) -DMAIN -o test-hw-events$(EXEEXT) \
$(srccom)/hw-events.c libsim.a $(EXTRA_LIBS)
hw-instances.o: $(srccom)/hw-instances.c $(hw_main_headers)
$(CC) -c $(srccom)/hw-instances.c $(ALL_CFLAGS)
hw-handles.o: $(srccom)/hw-handles.c $(hw_main_headers)
$(CC) -c $(srccom)/hw-handles.c $(ALL_CFLAGS)
hw-ports.o: $(srccom)/hw-ports.c $(hw_main_headers)
$(CC) -c $(srccom)/hw-ports.c $(ALL_CFLAGS)
hw-properties.o: $(srccom)/hw-properties.c $(hw_main_headers)
$(CC) -c $(srccom)/hw-properties.c $(ALL_CFLAGS)
hw-tree.o: $(srccom)/hw-tree.c $(hw_main_headers) $(hw-tree_h)
$(CC) -c $(srccom)/hw-tree.c $(ALL_CFLAGS)
# Devices.
dv-core.o: $(srccom)/dv-core.c $(hw_main_headers) $(sim_main_headers)
$(CC) -c $(srccom)/dv-core.c $(ALL_CFLAGS)
dv-glue.o: $(srccom)/dv-glue.c $(hw_main_headers) $(sim_main_headers)
$(CC) -c $(srccom)/dv-glue.c $(ALL_CFLAGS)
dv-pal.o: $(srccom)/dv-pal.c $(hw_main_headers) $(sim_main_headers)
$(CC) -c $(srccom)/dv-pal.c $(ALL_CFLAGS)
dv-sockser.o: $(srccom)/dv-sockser.h $(sim_main_headers)
$(CC) -c $(srccom)/dv-sockser.c $(ALL_CFLAGS)
nrun.o: $(srccom)/nrun.c config.h tconfig.h \
$(srcroot)/include/remote-sim.h $(srcroot)/include/callback.h \
$(sim_main_headers)
$(CC) -c $(srccom)/nrun.c $(ALL_CFLAGS)
# CGEN support.
# For use in Makefile.in for cpu-specific files.
CGEN_MAIN_CPU_DEPS = \
$(SIM_MAIN_DEPS) \
$(CGEN_INCLUDE_DEPS) \
$(srccom)/cgen-ops.h \
$(srccom)/cgen-mem.h
cgen-run.o: $(srccom)/cgen-run.c $(sim_main_headers)
$(CC) -c $(srccom)/cgen-run.c $(ALL_CFLAGS)
cgen-scache.o: $(srccom)/cgen-scache.c $(sim_main_headers)
$(CC) -c $(srccom)/cgen-scache.c $(ALL_CFLAGS)
cgen-trace.o: $(srccom)/cgen-trace.c $(sim_main_headers)
$(CC) -c $(srccom)/cgen-trace.c $(ALL_CFLAGS)
cgen-utils.o: $(srccom)/cgen-utils.c $(sim_main_headers) \
$(srccom)/cgen-mem.h $(srccom)/cgen-ops.h $(srccom)/cgen-engine.h
$(CC) -c $(srccom)/cgen-utils.c $(ALL_CFLAGS)
# Support targets.
install: install-common $(SIM_EXTRA_INSTALL)
install-common: installdirs
n=`echo run | sed '$(program_transform_name)'`; \
$(INSTALL_PROGRAM) run$(EXEEXT) $(bindir)/$$n$(EXEEXT)
n=`echo libsim.a | sed s/libsim.a/lib$(target_alias)-sim.a/`; \
$(INSTALL_DATA) libsim.a $(libdir)/$$n ; \
( cd $(libdir) ; $(RANLIB) $$n )
installdirs:
$(SHELL) $(srcdir)/../../mkinstalldirs $(bindir)
check:
cd ../testsuite && $(MAKE) check RUNTESTFLAGS="$(RUNTESTFLAGS)"
info:
clean-info:
install-info:
.NOEXPORT:
MAKEOVERRIDES=
tags etags: TAGS
# Macros like EXTERN_SIM_CORE confuse tags.
# And the sim-n-foo.h files create functions that can't be found either.
TAGS: force
cd $(srcdir) && \
etags --regex '/^\([a-z_]+\) (/\1/' --regex '/^\/[*] TAGS: .*/' \
*.[ch] ../common/*.[ch]
clean: $(SIM_EXTRA_CLEAN)
rm -f *.[oa] *~ core
rm -f run libsim.a
rm -f gentmap targ-map.c targ-vals.h stamp-tvals
if [ ! -f Make-common.in ] ; then \
rm -f $(BUILT_SRC_FROM_COMMON) ; \
fi
rm -f tmp-mloop.hin tmp-mloop.h tmp-mloop.cin tmp-mloop.c
distclean mostlyclean maintainer-clean realclean: clean
rm -f TAGS
rm -f Makefile config.cache config.log config.status .gdbinit
rm -f tconfig.h config.h stamp-h
rm -f targ-vals.def
.c.o:
$(CC) -c $(ALL_CFLAGS) $<
# Dummy target to force execution of dependent targets.
force:
Makefile: Makefile.in $(srccom)/Make-common.in config.status
CONFIG_HEADERS= $(SHELL) ./config.status
config.status: configure
$(SHELL) ./config.status --recheck
config.h: stamp-h ; @true
stamp-h: config.in config.status
CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status
.gdbinit: # config.status $(srccom)/gdbinit.in
CONFIG_FILES=$@:../common/gdbinit.in CONFIG_HEADERS= $(SHELL) ./config.status
## End COMMON_POST_CONFIG_FRAG

139
sim/common/Makefile.in Normal file
View File

@@ -0,0 +1,139 @@
# Makefile template for Configure for simulator common directory
# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
default: all
VPATH = @srcdir@
srcdir = @srcdir@
srcroot = $(srcdir)/../..
prefix = @prefix@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
target_alias = @target_alias@
program_transform_name = @program_transform_name@
bindir = @bindir@
libdir = @libdir@
tooldir = $(libdir)/$(target_alias)
datadir = @datadir@
mandir = @mandir@
man1dir = $(mandir)/man1
infodir = @infodir@
includedir = @includedir@
SHELL = /bin/sh
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CC = @CC@
CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
SIM_CFLAGS = @sim_cflags@
# These are used to rebuild nltvals.def.
CPP_FOR_TARGET = @CPP_FOR_TARGET@
TARGET_SUBDIR = @TARGET_SUBDIR@
HDEFINES = @HDEFINES@
TDEFINES =
CONFIG_CFLAGS = @DEFS@ $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES)
CSEARCH = -I. -I$(srcdir) -I$(srcroot)/include
ALL_CFLAGS = $(CFLAGS) $(CONFIG_CFLAGS) $(CSEARCH)
BUILD_CFLAGS = -g -O $(CSEARCH)
AR = @AR@
AR_FLAGS = rc
RANLIB = @RANLIB@
MAKEINFO = makeinfo
.NOEXPORT:
MAKEOVERRIDES=
all:
# Generate TARG_VALS_H for newlib/libgloss using devo and build tree.
# This file is shipped with distributions so we build in the source dir.
# This is built in srcdir so putting dependencies here is risky.
# Use `make headers' to rebuild.
headers: nltvals.def
.PHONY: headers
# Note: If gdb releases begin to contain target header files, generate
# targ-vals.def at build time.
nltvals.def: Makefile gennltvals.sh gentvals.sh
rootme=`pwd` ; \
cd $(srcdir) ; \
rm -f nltvals.new ; \
$(SHELL) $(srcdir)/gennltvals.sh $(SHELL) $(srcroot) "$(CPP_FOR_TARGET)" > nltvals.new ; \
$(SHELL) $(srcroot)/move-if-change nltvals.new nltvals.def
.c.o:
$(CC) -c $< $(ALL_CFLAGS)
check:
info:
clean-info:
install-info:
tags etags: TAGS
# Macros like EXTERN_SIM_CORE confuse tags.
# And the sim-n-foo.h files create functions that can't be found either.
TAGS: force
cd $(srcdir) && \
etags --regex '/^\([a-z_]+\) (/\1/' --regex '/^\/[*] TAGS: .*/' \
*.[ch]
clean:
rm -f *.[oa] *~ core
rm -f $(ALL)
distclean mostlyclean maintainer-clean realclean: clean
rm -f TAGS
rm -f Makefile config.cache config.log config.status
rm -f config.h stamp-h
# Dummy target to force execution of dependent targets.
force:
# Copy the files into directories where they will be run.
install:
install-man: installdirs
n=`echo run | sed '$(program_transform_name)'`; \
$(INSTALL_DATA) $(srcdir)/run.1 $(man1dir)/$$n.1
installdirs:
$(SHELL) $(srcdir)/../../mkinstalldirs $(man1dir)
Makefile: Makefile.in config.status
$(SHELL) ./config.status
config.status: configure
$(SHELL) ./config.status --recheck
config.h: stamp-h ; @true
stamp-h: config.in config.status
CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status

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

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

1259
sim/common/aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

810
sim/common/callback.c Normal file
View File

@@ -0,0 +1,810 @@
/* Remote target callback routines.
Copyright 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file provides a standard way for targets to talk to the host OS
level. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ansidecl.h"
#ifdef ANSI_PROTOTYPES
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "callback.h"
#include "targ-vals.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/* ??? sim_cb_printf should be cb_printf, but until the callback support is
broken out of the simulator directory, these are here to not require
sim-utils.h. */
void sim_cb_printf PARAMS ((host_callback *, const char *, ...));
void sim_cb_eprintf PARAMS ((host_callback *, const char *, ...));
extern CB_TARGET_DEFS_MAP cb_init_syscall_map[];
extern CB_TARGET_DEFS_MAP cb_init_errno_map[];
extern CB_TARGET_DEFS_MAP cb_init_open_map[];
extern int system PARAMS ((const char *));
static int os_init PARAMS ((host_callback *));
static int os_shutdown PARAMS ((host_callback *));
static int os_unlink PARAMS ((host_callback *, const char *));
static long os_time PARAMS ((host_callback *, long *));
static int os_system PARAMS ((host_callback *, const char *));
static int os_rename PARAMS ((host_callback *, const char *, const char *));
static int os_write_stdout PARAMS ((host_callback *, const char *, int));
static void os_flush_stdout PARAMS ((host_callback *));
static int os_write_stderr PARAMS ((host_callback *, const char *, int));
static void os_flush_stderr PARAMS ((host_callback *));
static int os_write PARAMS ((host_callback *, int, const char *, int));
static int os_read_stdin PARAMS ((host_callback *, char *, int));
static int os_read PARAMS ((host_callback *, int, char *, int));
static int os_open PARAMS ((host_callback *, const char *, int));
static int os_lseek PARAMS ((host_callback *, int, long, int));
static int os_isatty PARAMS ((host_callback *, int));
static int os_get_errno PARAMS ((host_callback *));
static int os_close PARAMS ((host_callback *, int));
static void os_vprintf_filtered PARAMS ((host_callback *, const char *, va_list));
static void os_evprintf_filtered PARAMS ((host_callback *, const char *, va_list));
static void os_error PARAMS ((host_callback *, const char *, ...));
static int fdmap PARAMS ((host_callback *, int));
static int fdbad PARAMS ((host_callback *, int));
static int wrap PARAMS ((host_callback *, int));
/* Set the callback copy of errno from what we see now. */
static int
wrap (p, val)
host_callback *p;
int val;
{
p->last_errno = errno;
return val;
}
/* Make sure the FD provided is ok. If not, return non-zero
and set errno. */
static int
fdbad (p, fd)
host_callback *p;
int fd;
{
if (fd < 0 || fd > MAX_CALLBACK_FDS || !p->fdopen[fd])
{
p->last_errno = EINVAL;
return -1;
}
return 0;
}
static int
fdmap (p, fd)
host_callback *p;
int fd;
{
return p->fdmap[fd];
}
static int
os_close (p, fd)
host_callback *p;
int fd;
{
int result;
result = fdbad (p, fd);
if (result)
return result;
result = wrap (p, close (fdmap (p, fd)));
if (result == 0 && !p->alwaysopen[fd])
p->fdopen[fd] = 0;
return result;
}
/* taken from gdb/util.c:notice_quit() - should be in a library */
#if defined(__GO32__) || defined (_MSC_VER)
static int
os_poll_quit (p)
host_callback *p;
{
#if defined(__GO32__)
int kbhit ();
int getkey ();
if (kbhit ())
{
int k = getkey ();
if (k == 1)
{
return 1;
}
else if (k == 2)
{
return 1;
}
else
{
sim_cb_eprintf (p, "CTRL-A to quit, CTRL-B to quit harder\n");
}
}
#endif
#if defined (_MSC_VER)
/* NB - this will not compile! */
int k = win32pollquit();
if (k == 1)
return 1;
else if (k == 2)
return 1;
#endif
return 0;
}
#else
#define os_poll_quit 0
#endif /* defined(__GO32__) || defined(_MSC_VER) */
static int
os_get_errno (p)
host_callback *p;
{
return cb_host_to_target_errno (p, p->last_errno);
}
static int
os_isatty (p, fd)
host_callback *p;
int fd;
{
int result;
result = fdbad (p, fd);
if (result)
return result;
result = wrap (p, isatty (fdmap (p, fd)));
return result;
}
static int
os_lseek (p, fd, off, way)
host_callback *p;
int fd;
long off;
int way;
{
int result;
result = fdbad (p, fd);
if (result)
return result;
result = lseek (fdmap (p, fd), off, way);
return result;
}
static int
os_open (p, name, flags)
host_callback *p;
const char *name;
int flags;
{
int i;
for (i = 0; i < MAX_CALLBACK_FDS; i++)
{
if (!p->fdopen[i])
{
int f = open (name, cb_target_to_host_open (p, flags), 0644);
if (f < 0)
{
p->last_errno = errno;
return f;
}
p->fdopen[i] = 1;
p->fdmap[i] = f;
return i;
}
}
p->last_errno = EMFILE;
return -1;
}
static int
os_read (p, fd, buf, len)
host_callback *p;
int fd;
char *buf;
int len;
{
int result;
result = fdbad (p, fd);
if (result)
return result;
result = wrap (p, read (fdmap (p, fd), buf, len));
return result;
}
static int
os_read_stdin (p, buf, len)
host_callback *p;
char *buf;
int len;
{
return wrap (p, read (0, buf, len));
}
static int
os_write (p, fd, buf, len)
host_callback *p;
int fd;
const char *buf;
int len;
{
int result;
int real_fd;
result = fdbad (p, fd);
if (result)
return result;
real_fd = fdmap (p, fd);
switch (real_fd)
{
default:
result = wrap (p, write (real_fd, buf, len));
break;
case 1:
result = p->write_stdout (p, buf, len);
break;
case 2:
result = p->write_stderr (p, buf, len);
break;
}
return result;
}
static int
os_write_stdout (p, buf, len)
host_callback *p;
const char *buf;
int len;
{
return fwrite (buf, 1, len, stdout);
}
static void
os_flush_stdout (p)
host_callback *p;
{
fflush (stdout);
}
static int
os_write_stderr (p, buf, len)
host_callback *p;
const char *buf;
int len;
{
return fwrite (buf, 1, len, stderr);
}
static void
os_flush_stderr (p)
host_callback *p;
{
fflush (stderr);
}
static int
os_rename (p, f1, f2)
host_callback *p;
const char *f1;
const char *f2;
{
return wrap (p, rename (f1, f2));
}
static int
os_system (p, s)
host_callback *p;
const char *s;
{
return wrap (p, system (s));
}
static long
os_time (p, t)
host_callback *p;
long *t;
{
return wrap (p, time (t));
}
static int
os_unlink (p, f1)
host_callback *p;
const char *f1;
{
return wrap (p, unlink (f1));
}
static int
os_stat (p, file, buf)
host_callback *p;
const char *file;
struct stat *buf;
{
/* ??? There is an issue of when to translate to the target layout.
One could do that inside this function, or one could have the
caller do it. It's more flexible to let the caller do it, though
I'm not sure the flexibility will ever be useful. */
return wrap (p, stat (file, buf));
}
static int
os_fstat (p, fd, buf)
host_callback *p;
int fd;
struct stat *buf;
{
if (fdbad (p, fd))
return -1;
/* ??? There is an issue of when to translate to the target layout.
One could do that inside this function, or one could have the
caller do it. It's more flexible to let the caller do it, though
I'm not sure the flexibility will ever be useful. */
return wrap (p, fstat (fdmap (p, fd), buf));
}
static int
os_shutdown (p)
host_callback *p;
{
int i;
for (i = 0; i < MAX_CALLBACK_FDS; i++)
{
if (p->fdopen[i] && !p->alwaysopen[i]) {
close (p->fdmap[i]);
p->fdopen[i] = 0;
}
}
return 1;
}
static int
os_init (p)
host_callback *p;
{
int i;
os_shutdown (p);
for (i = 0; i < 3; i++)
{
p->fdmap[i] = i;
p->fdopen[i] = 1;
p->alwaysopen[i] = 1;
}
p->syscall_map = cb_init_syscall_map;
p->errno_map = cb_init_errno_map;
p->open_map = cb_init_open_map;
return 1;
}
/* DEPRECIATED */
/* VARARGS */
static void
#ifdef ANSI_PROTOTYPES
os_printf_filtered (host_callback *p, const char *format, ...)
#else
os_printf_filtered (p, va_alist)
host_callback *p;
va_dcl
#endif
{
va_list args;
#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
char *format;
va_start (args);
format = va_arg (args, char *);
#endif
vfprintf (stdout, format, args);
va_end (args);
}
/* VARARGS */
static void
#ifdef ANSI_PROTOTYPES
os_vprintf_filtered (host_callback *p, const char *format, va_list args)
#else
os_vprintf_filtered (p, format, args)
host_callback *p;
const char *format;
va_list args;
#endif
{
vprintf (format, args);
}
/* VARARGS */
static void
#ifdef ANSI_PROTOTYPES
os_evprintf_filtered (host_callback *p, const char *format, va_list args)
#else
os_evprintf_filtered (p, format, args)
host_callback *p;
const char *format;
va_list args;
#endif
{
vfprintf (stderr, format, args);
}
/* VARARGS */
static void
#ifdef ANSI_PROTOTYPES
os_error (host_callback *p, const char *format, ...)
#else
os_error (p, va_alist)
host_callback *p;
va_dcl
#endif
{
va_list args;
#ifdef ANSI_PROTOTYPES
va_start (args, format);
#else
char *format;
va_start (args);
format = va_arg (args, char *);
#endif
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
va_end (args);
exit (1);
}
host_callback default_callback =
{
os_close,
os_get_errno,
os_isatty,
os_lseek,
os_open,
os_read,
os_read_stdin,
os_rename,
os_system,
os_time,
os_unlink,
os_write,
os_write_stdout,
os_flush_stdout,
os_write_stderr,
os_flush_stderr,
os_stat,
os_fstat,
os_poll_quit,
os_shutdown,
os_init,
os_printf_filtered, /* deprecated */
os_vprintf_filtered,
os_evprintf_filtered,
os_error,
0, /* last errno */
{ 0, }, /* fdmap */
{ 0, }, /* fdopen */
{ 0, }, /* alwaysopen */
0, /* syscall_map */
0, /* errno_map */
0, /* open_map */
0, /* signal_map */
0, /* stat_map */
HOST_CALLBACK_MAGIC,
};
/* Read in a file describing the target's system call values.
E.g. maybe someone will want to use something other than newlib.
This assumes that the basic system call recognition and value passing/
returning is supported. So maybe some coding/recompilation will be
necessary, but not as much.
If an error occurs, the existing mapping is not changed. */
CB_RC
cb_read_target_syscall_maps (cb, file)
host_callback *cb;
const char *file;
{
CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map;
const char *stat_map;
FILE *f;
if ((f = fopen (file, "r")) == NULL)
return CB_RC_ACCESS;
/* ... read in and parse file ... */
fclose (f);
return CB_RC_NO_MEM; /* FIXME:wip */
/* Free storage allocated for any existing maps. */
if (cb->syscall_map)
free (cb->syscall_map);
if (cb->errno_map)
free (cb->errno_map);
if (cb->open_map)
free (cb->open_map);
if (cb->signal_map)
free (cb->signal_map);
if (cb->stat_map)
free ((PTR) cb->stat_map);
cb->syscall_map = syscall_map;
cb->errno_map = errno_map;
cb->open_map = open_map;
cb->signal_map = signal_map;
cb->stat_map = stat_map;
return CB_RC_OK;
}
/* Translate the target's version of a syscall number to the host's.
This isn't actually the host's version, rather a canonical form.
??? Perhaps this should be renamed to ..._canon_syscall. */
int
cb_target_to_host_syscall (cb, target_val)
host_callback *cb;
int target_val;
{
CB_TARGET_DEFS_MAP *m;
for (m = &cb->syscall_map[0]; m->target_val != -1; ++m)
if (m->target_val == target_val)
return m->host_val;
return -1;
}
/* FIXME: sort tables if large.
Alternatively, an obvious improvement for errno conversion is
to machine generate a function with a large switch(). */
/* Translate the host's version of errno to the target's. */
int
cb_host_to_target_errno (cb, host_val)
host_callback *cb;
int host_val;
{
CB_TARGET_DEFS_MAP *m;
for (m = &cb->errno_map[0]; m->host_val; ++m)
if (m->host_val == host_val)
return m->target_val;
/* ??? Which error to return in this case is up for grabs.
Note that some missing values may have standard alternatives.
For now return 0 and require caller to deal with it. */
return 0;
}
/* Given a set of target bitmasks for the open system call,
return the host equivalent.
Mapping open flag values is best done by looping so there's no need
to machine generate this function. */
int
cb_target_to_host_open (cb, target_val)
host_callback *cb;
int target_val;
{
int host_val = 0;
CB_TARGET_DEFS_MAP *m;
for (m = &cb->open_map[0]; m->host_val != -1; ++m)
{
switch (m->target_val)
{
/* O_RDONLY can be (and usually is) 0 which needs to be treated
specially. */
case TARGET_O_RDONLY :
case TARGET_O_WRONLY :
case TARGET_O_RDWR :
if ((target_val & (TARGET_O_RDONLY | TARGET_O_WRONLY | TARGET_O_RDWR))
== m->target_val)
host_val |= m->host_val;
/* Handle the host/target differentiating between binary and
text mode. Only one case is of importance */
#if ! defined (TARGET_O_BINARY) && defined (O_BINARY)
host_val |= O_BINARY;
#endif
break;
default :
if ((m->target_val & target_val) == m->target_val)
host_val |= m->host_val;
break;
}
}
return host_val;
}
/* Utility for cb_host_to_target_stat to store values in the target's
stat struct. */
static void
store (p, size, val, big_p)
char *p;
int size;
long val; /* ??? must be as big as target word size */
int big_p;
{
if (big_p)
{
p += size;
while (size-- > 0)
{
*--p = val;
val >>= 8;
}
}
else
{
while (size-- > 0)
{
*p++ = val;
val >>= 8;
}
}
}
/* Translate a host's stat struct into a target's.
If HS is NULL, just compute the length of the buffer required,
TS is ignored.
The result is the size of the target's stat struct,
or zero if an error occured during the translation. */
int
cb_host_to_target_stat (cb, hs, ts)
host_callback *cb;
const struct stat *hs;
PTR ts;
{
const char *m = cb->stat_map;
char *p;
int big_p = 0;
if (hs == NULL)
ts = NULL;
p = ts;
while (m)
{
char *q = strchr (m, ',');
int size;
/* FIXME: Use sscanf? */
if (q == NULL)
{
/* FIXME: print error message */
return 0;
}
size = atoi (q + 1);
if (size == 0)
{
/* FIXME: print error message */
return 0;
}
if (hs != NULL)
{
if (strncmp (m, "st_dev", q - m) == 0)
store (p, size, hs->st_dev, big_p);
else if (strncmp (m, "st_ino", q - m) == 0)
store (p, size, hs->st_ino, big_p);
/* FIXME:wip */
else
store (p, size, 0, big_p); /* unsupported field, store 0 */
}
p += size;
m = strchr (q, ':');
if (m)
++m;
}
return p - (char *) ts;
}
/* Cover functions to the vfprintf callbacks.
??? If one thinks of the callbacks as a subsystem onto itself [or part of
a larger "remote target subsystem"] with a well defined interface, then
one would think that the subsystem would provide these. However, until
one is allowed to create such a subsystem (with its own source tree
independent of any particular user), such a critter can't exist. Thus
these functions are here for the time being. */
void
sim_cb_printf (host_callback *p, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
p->vprintf_filtered (p, fmt, ap);
va_end (ap);
}
void
sim_cb_eprintf (host_callback *p, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
p->evprintf_filtered (p, fmt, ap);
va_end (ap);
}

98
sim/common/cgen-cpu.h Normal file
View File

@@ -0,0 +1,98 @@
/* Simulator header for cgen cpus.
Copyright (C) 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef CGEN_CPU_H
#define CGEN_CPU_H
/* Type of function that is ultimately called by sim_resume. */
typedef void (ENGINE_FN) (SIM_CPU *);
/* Type of function to do disassembly. */
typedef void (CGEN_DISASSEMBLER) (SIM_CPU *, const CGEN_INSN *,
const ARGBUF *, IADDR pc_, char *buf_);
/* Additional non-machine generated per-cpu data to go in SIM_CPU.
The member's name must be `cgen_cpu'. */
typedef struct {
/* Non-zero while cpu simulation is running. */
int running_p;
#define CPU_RUNNING_P(cpu) ((cpu)->cgen_cpu.running_p)
/* Instruction count. This is maintained even in fast mode to keep track
of simulator speed. */
unsigned long insn_count;
#define CPU_INSN_COUNT(cpu) ((cpu)->cgen_cpu.insn_count)
/* sim_resume handlers */
ENGINE_FN *fast_engine_fn;
#define CPU_FAST_ENGINE_FN(cpu) ((cpu)->cgen_cpu.fast_engine_fn)
ENGINE_FN *full_engine_fn;
#define CPU_FULL_ENGINE_FN(cpu) ((cpu)->cgen_cpu.full_engine_fn)
/* Maximum number of instructions per time slice.
When single stepping this is 1. If using the pbb model, this can be
more than 1. 0 means "as long as you want". */
unsigned int max_slice_insns;
#define CPU_MAX_SLICE_INSNS(cpu) ((cpu)->cgen_cpu.max_slice_insns)
/* Simulator's execution cache.
Allocate space for this even if not used as some simulators may have
one machine variant that uses the scache and another that doesn't and
we don't want members in this struct to move about. */
CPU_SCACHE scache;
/* Instruction descriptor table. */
IDESC *idesc;
#define CPU_IDESC(cpu) ((cpu)->cgen_cpu.idesc)
/* Whether the read,write,semantic entries (computed goto labels) have been
initialized or not. */
int idesc_read_init_p;
#define CPU_IDESC_READ_INIT_P(cpu) ((cpu)->cgen_cpu.idesc_read_init_p)
int idesc_write_init_p;
#define CPU_IDESC_WRITE_INIT_P(cpu) ((cpu)->cgen_cpu.idesc_write_init_p)
int idesc_sem_init_p;
#define CPU_IDESC_SEM_INIT_P(cpu) ((cpu)->cgen_cpu.idesc_sem_init_p)
/* Cpu descriptor table.
This is a CGEN created entity that contains the description file
turned into C code and tables for our use. */
CGEN_CPU_DESC cpu_desc;
#define CPU_CPU_DESC(cpu) ((cpu)->cgen_cpu.cpu_desc)
/* Function to fetch the insn data entry in the IDESC. */
const CGEN_INSN * (*get_idata) (SIM_CPU *, int);
#define CPU_GET_IDATA(cpu) ((cpu)->cgen_cpu.get_idata)
/* Disassembler. */
CGEN_DISASSEMBLER *disassembler;
#define CPU_DISASSEMBLER(cpu) ((cpu)->cgen_cpu.disassembler)
/* Allow slop in size calcs for case where multiple cpu types are supported
and space for the specified cpu is malloc'd at run time. */
double slop;
} CGEN_CPU;
/* Shorthand macro for fetching registers.
CPU_CGEN_HW is defined in cpu.h. */
#define CPU(x) (CPU_CGEN_HW (current_cpu)->x)
#endif /* CGEN_CPU_H */

174
sim/common/cgen-defs.h Normal file
View File

@@ -0,0 +1,174 @@
/* General Cpu tools GENerated simulator support.
Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef CGEN_DEFS_H
#define CGEN_DEFS_H
/* Compute number of longs required to hold N bits. */
#define HOST_LONGS_FOR_BITS(n) \
(((n) + sizeof (long) * 8 - 1) / sizeof (long) * 8)
/* Forward decls. Defined in the machine generated files. */
/* This holds the contents of the extracted insn.
There are a few common entries (e.g. pc address), and then one big
union with an entry for each of the instruction formats. */
typedef struct argbuf ARGBUF;
/* ARGBUF accessors. */
#define ARGBUF_ADDR(abuf) ((abuf)->addr)
#define ARGBUF_IDESC(abuf) ((abuf)->idesc)
#define ARGBUF_TRACE_P(abuf) ((abuf)->trace_p)
#define ARGBUF_PROFILE_P(abuf) ((abuf)->profile_p)
/* This is one ARGBUF plus whatever else is needed for WITH_SCACHE support.
At present there is nothing else, but it also provides a level of
abstraction. */
typedef struct scache SCACHE;
/* This is a union with one entry for each instruction format.
Each entry contains all of the non-constant inputs of the instruction
in the case of read-before-exec support, or all outputs of the instruction
in the case of write-after-exec support. */
typedef struct parexec PAREXEC;
/* An "Instruction DESCriptor".
This is the main handle on an instruction for the simulator. */
typedef struct idesc IDESC;
/* Engine support.
??? This is here because it's needed before eng.h (built by genmloop.sh)
which is needed before cgen-engine.h and cpu.h.
??? This depends on a cpu family specific type, IADDR, but no machine
generated headers will have been included yet. sim/common currently
requires the typedef of sim_cia in sim-main.h between the inclusion of
sim-basics.h and sim-base.h so this is no different. */
/* SEM_ARG is intended to hide whether or not the scache is in use from the
semantic routines. In reality for the with-extraction case it is always
an SCACHE * even when not using the SCACHE since there's no current win to
making it something else ("not using the SCACHE" is like having a cache
size of 1).
The without-extraction case still uses an ARGBUF:
- consistency with scache version
- still need to record which operands are written
This wouldn't be needed if modeling was done in the semantic routines
but this isn't as general as handling it outside of the semantic routines.
For example Shade allows calling user-supplied code before/after each
instruction and this is something that is being planned.
??? There is still some clumsiness in how much of ARGBUF to use. */
typedef SCACHE *SEM_ARG;
/* instruction address
??? This was intended to be a struct of two elements in the WITH_SCACHE_PBB
case. The first element is the IADDR, the second element is the SCACHE *.
Haven't found the time yet to make this work, but it seemed a nicer approach
than the current br_cache stuff. */
typedef IADDR PCADDR;
/* Current instruction address, used by common. */
typedef IADDR CIA;
/* Semantic routines' version of the PC. */
#if WITH_SCACHE_PBB
typedef SCACHE *SEM_PC;
#else
typedef IADDR SEM_PC;
#endif
/* Virtual insn support. */
/* Opcode table for virtual insns (only used by the simulator). */
extern const CGEN_INSN cgen_virtual_insn_table[];
/* -ve of indices of virtual insns in cgen_virtual_insn_table. */
typedef enum {
VIRTUAL_INSN_X_INVALID = 0,
VIRTUAL_INSN_X_BEFORE = -1, VIRTUAL_INSN_X_AFTER = -2,
VIRTUAL_INSN_X_BEGIN = -3,
VIRTUAL_INSN_X_CHAIN= -4, VIRTUAL_INSN_X_CTI_CHAIN = -5
} CGEN_INSN_VIRTUAL_TYPE;
/* Return non-zero if OPCODE is a virtual insn. */
#define CGEN_INSN_VIRTUAL_P(insn) \
CGEN_INSN_ATTR_VALUE ((insn), CGEN_INSN_VIRTUAL)
/* GNU C's "computed goto" facility is used to speed things up where
possible. These macros provide a portable way to use them.
Nesting of these switch statements is done by providing an extra argument
that distinguishes them. `N' can be a number or symbol.
Variable `labels_##N' must be initialized with the labels of each case. */
#ifdef __GNUC__
#define SWITCH(N, X) goto *X;
#define CASE(N, X) case_##N##_##X
#define BREAK(N) goto end_switch_##N
#define DEFAULT(N) default_##N
#define ENDSWITCH(N) end_switch_##N:
#else
#define SWITCH(N, X) switch (X)
#define CASE(N, X) case X /* FIXME: old sem-switch had (@arch@_,X) here */
#define BREAK(N) break
#define DEFAULT(N) default
#define ENDSWITCH(N)
#endif
/* Simulator state. */
/* Records simulator descriptor so utilities like @cpu@_dump_regs can be
called from gdb. */
extern SIM_DESC current_state;
/* Simulator state. */
/* CGEN_STATE contains additional state information not present in
sim_state_base. */
typedef struct cgen_state {
/* FIXME: Moved to sim_state_base. */
/* argv, env */
char **argv;
#define STATE_ARGV(s) ((s) -> cgen_state.argv)
/* FIXME: Move to sim_state_base. */
char **envp;
#define STATE_ENVP(s) ((s) -> cgen_state.envp)
/* Non-zero if no tracing or profiling is selected. */
int run_fast_p;
#define STATE_RUN_FAST_P(sd) ((sd) -> cgen_state.run_fast_p)
} CGEN_STATE;
/* Various utilities. */
/* Called after sim_post_argv_init to do any cgen initialization. */
extern void cgen_init (SIM_DESC);
/* Return the name of an insn. */
extern CPU_INSN_NAME_FN cgen_insn_name;
/* Return the maximum number of extra bytes required for a sim_cpu struct. */
/* ??? Ok, yes, this is less pretty than it should be. Give me a better
language [or suggest a better way]. */
extern int cgen_cpu_max_extra_bytes (void);
/* Called to process an invalid instruction. */
extern void sim_engine_invalid_insn (SIM_CPU *, IADDR);
#endif /* CGEN_DEFS_H */

473
sim/common/cgen-engine.h Normal file
View File

@@ -0,0 +1,473 @@
/* Engine header for Cpu tools GENerated simulators.
Copyright (C) 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file must be included after eng.h and before ${cpu}.h. */
/* Semantic functions come in six versions on two axes:
fast/full-featured, and using one of the simple/scache/compilation engines.
A full featured simulator is always provided. --enable-sim-fast includes
support for fast execution by duplicating the semantic code but leaving
out all features like tracing and profiling.
Using the scache is selected with --enable-sim-scache. */
/* FIXME: --enable-sim-fast not implemented yet. */
/* FIXME: undecided how to handle WITH_SCACHE_PBB. */
/* There are several styles of engines, all generally supported by the
same code:
WITH_SCACHE && WITH_SCACHE_PBB - pseudo-basic-block scaching
WITH_SCACHE && !WITH_SCACHE_PBB - scaching on an insn by insn basis
!WITH_SCACHE - simple engine: fetch an insn, execute an insn
The !WITH_SCACHE case can also be broken up into two flavours:
extract the fields of the insn into an ARGBUF struct, or defer the
extraction to the semantic handler. The former can be viewed as the
WITH_SCACHE case with a cache size of 1 (thus there's no need for a
WITH_EXTRACTION macro). The WITH_SCACHE case always extracts the fields
into an ARGBUF struct. */
#ifndef CGEN_ENGINE_H
#define CGEN_ENGINE_H
/* Instruction field support macros. */
#define EXTRACT_MSB0_INT(val, total, start, length) \
(((INT) (val) << ((sizeof (INT) * 8) - (total) + (start))) \
>> ((sizeof (INT) * 8) - (length)))
#define EXTRACT_MSB0_UINT(val, total, start, length) \
(((UINT) (val) << ((sizeof (UINT) * 8) - (total) + (start))) \
>> ((sizeof (UINT) * 8) - (length)))
#define EXTRACT_LSB0_INT(val, total, start, length) \
(((INT) (val) << ((sizeof (INT) * 8) - (start) - 1)) \
>> ((sizeof (INT) * 8) - (length)))
#define EXTRACT_LSB0_UINT(val, total, start, length) \
(((UINT) (val) << ((sizeof (UINT) * 8) - (start) - 1)) \
>> ((sizeof (UINT) * 8) - (length)))
#if CGEN_INSN_LSB0_P
#define EXTRACT_INT(val, total, start, length) \
EXTRACT_LSB0_INT ((val), (total), (start), (length))
#define EXTRACT_UINT(val, total, start, length) \
EXTRACT_LSB0_UINT ((val), (total), (start), (length))
#else
#define EXTRACT_INT(val, total, start, length) \
EXTRACT_MSB0_INT ((val), (total), (start), (length))
#define EXTRACT_UINT(val, total, start, length) \
EXTRACT_MSB0_UINT ((val), (total), (start), (length))
#endif
/* Semantic routines. */
/* Type of the machine generated extraction fns. */
/* ??? No longer used. */
typedef void (EXTRACT_FN) (SIM_CPU *, IADDR, CGEN_INSN_INT, ARGBUF *);
/* Type of the machine generated semantic fns. */
#if WITH_SCACHE
/* Instruction fields are extracted into ARGBUF before calling the
semantic routine. */
#if HAVE_PARALLEL_INSNS
typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *);
#else
typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG);
#endif
#else
/* Result of semantic routines is a status indicator (wip). */
typedef unsigned int SEM_STATUS;
/* Instruction fields are extracted by the semantic routine.
??? TODO: multi word insns. */
#if HAVE_PARALLEL_INSNS
typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *, CGEN_INSN_INT);
#else
typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, CGEN_INSN_INT);
#endif
#endif
/* In the ARGBUF struct, a pointer to the semantic routine for the insn. */
union sem {
#if ! WITH_SEM_SWITCH_FULL
SEMANTIC_FN *sem_full;
#endif
#if ! WITH_SEM_SWITCH_FAST
SEMANTIC_FN *sem_fast;
#endif
#if WITH_SEM_SWITCH_FULL || WITH_SEM_SWITCH_FAST
#ifdef __GNUC__
void *sem_case;
#else
int sem_case;
#endif
#endif
};
/* Set the appropriate semantic handler in ABUF. */
#if WITH_SEM_SWITCH_FULL
#ifdef __GNUC__
#define SEM_SET_FULL_CODE(abuf, idesc) \
do { (abuf)->semantic.sem_case = (idesc)->sem_full_lab; } while (0)
#else
#define SEM_SET_FULL_CODE(abuf, idesc) \
do { (abuf)->semantic.sem_case = (idesc)->num; } while (0)
#endif
#else
#define SEM_SET_FULL_CODE(abuf, idesc) \
do { (abuf)->semantic.sem_full = (idesc)->sem_full; } while (0)
#endif
#if WITH_SEM_SWITCH_FAST
#ifdef __GNUC__
#define SEM_SET_FAST_CODE(abuf, idesc) \
do { (abuf)->semantic.sem_case = (idesc)->sem_fast_lab; } while (0)
#else
#define SEM_SET_FAST_CODE(abuf, idesc) \
do { (abuf)->semantic.sem_case = (idesc)->num; } while (0)
#endif
#else
#define SEM_SET_FAST_CODE(abuf, idesc) \
do { (abuf)->semantic.sem_fast = (idesc)->sem_fast; } while (0)
#endif
#define SEM_SET_CODE(abuf, idesc, fast_p) \
do { \
if (fast_p) \
SEM_SET_FAST_CODE ((abuf), (idesc)); \
else \
SEM_SET_FULL_CODE ((abuf), (idesc)); \
} while (0)
/* Return non-zero if IDESC is a conditional or unconditional CTI. */
#define IDESC_CTI_P(idesc) \
((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \
& (CGEN_ATTR_MASK (CGEN_INSN_COND_CTI) \
| CGEN_ATTR_MASK (CGEN_INSN_UNCOND_CTI))) \
!= 0)
/* Return non-zero if IDESC is a skip insn. */
#define IDESC_SKIP_P(idesc) \
((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \
& CGEN_ATTR_MASK (CGEN_INSN_SKIP_CTI)) \
!= 0)
/* These are used so that we can compile two copies of the semantic code,
one with full feature support and one without that runs fast(er). */
#define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn)
#define SEMF_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn)
/* Return pointer to ARGBUF given ptr to SCACHE. */
#define SEM_ARGBUF(sem_arg) (& (sem_arg) -> argbuf)
/* There are several styles of engines, all generally supported by the
same code:
WITH_SCACHE && WITH_SCACHE_PBB - pseudo-basic-block scaching
WITH_SCACHE && !WITH_SCACHE_PBB - scaching on an insn by insn basis
!WITH_SCACHE - simple engine: fetch an insn, execute an insn
??? The !WITH_SCACHE case can also be broken up into two flavours:
extract the fields of the insn into an ARGBUF struct, or defer the
extraction to the semantic handler. The WITH_SCACHE case always
extracts the fields into an ARGBUF struct. */
#if WITH_SCACHE
#define CIA_ADDR(cia) (cia)
#if WITH_SCACHE_PBB
/* Return the scache pointer of the current insn. */
#define SEM_SEM_ARG(vpc, sc) (vpc)
/* Return the virtual pc of the next insn to execute
(assuming this isn't a cti or the branch isn't taken). */
#define SEM_NEXT_VPC(sem_arg, pc, len) ((sem_arg) + 1)
/* Update the instruction counter. */
#define PBB_UPDATE_INSN_COUNT(cpu,sc) \
(CPU_INSN_COUNT (cpu) += SEM_ARGBUF (sc) -> fields.chain.insn_count)
/* Value for br_addr_ptr indicating branch wasn't taken. */
#define SEM_BRANCH_UNTAKEN ((SEM_PC *) 0)
/* Value for br_addr_ptr indicating branch was taken to uncacheable
address (e.g. j reg). */
#define SEM_BRANCH_UNCACHEABLE ((SEM_PC *) 1)
/* Initialize next-pbb link for SEM_BRANCH_VIA_CACHE. */
#define SEM_BRANCH_INIT_EXTRACT(abuf) \
do { (abuf)->fields.cti.addr_cache = 0; } while (0)
/* Do not append a `;' to invocations of this.
npc,npc_ptr are for communication between the cti insn and cti-chain. */
#define SEM_BRANCH_INIT \
IADDR npc = 0; /* assign a value for -Wall */ \
SEM_PC *npc_ptr = SEM_BRANCH_UNTAKEN;
/* SEM_IN_SWITCH is defined at the top of the mainloop.c files
generated by genmloop.sh. It exists so generated semantic code needn't
care whether it's being put in a switch or in a function. */
#ifdef SEM_IN_SWITCH
#define SEM_BRANCH_FINI(pcvar) \
do { \
pbb_br_npc = npc; \
pbb_br_npc_ptr = npc_ptr; \
} while (0)
#else /* 1 semantic function per instruction */
#define SEM_BRANCH_FINI(pcvar) \
do { \
CPU_PBB_BR_NPC (current_cpu) = npc; \
CPU_PBB_BR_NPC_PTR (current_cpu) = npc_ptr; \
} while (0)
#endif
/* Return address of cached branch address value. */
#define SEM_BRANCH_ADDR_CACHE(sem_arg) \
(& SEM_ARGBUF (sem_arg)->fields.cti.addr_cache)
#define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar, cachevarptr) \
do { \
npc = (newval); \
npc_ptr = (cachevarptr); \
} while (0)
#define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \
do { \
npc = (newval); \
npc_ptr = SEM_BRANCH_UNCACHEABLE; \
} while (0)
#else /* ! WITH_SCACHE_PBB */
#define SEM_SEM_ARG(vpc, sc) (sc)
#define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len))
#define SEM_BRANCH_INIT_EXTRACT(abuf) do { } while (0)
/* ??? May wish to move taken_p out of here and make it explicit. */
#define SEM_BRANCH_INIT \
int taken_p = 0;
#ifndef TARGET_SEM_BRANCH_FINI(pcvar, taken_p)
#define TARGET_SEM_BRANCH_FINI(pcvar, taken_p)
#endif
#define SEM_BRANCH_FINI(pcvar) \
do { TARGET_SEM_BRANCH_FINI (pcvar, taken_p); } while (0)
#define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used
#define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar, cachevar) \
do { \
(pcvar) = (newval); \
taken_p = 1; \
} while (0)
#define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \
do { \
(pcvar) = (newval); \
taken_p = 1; \
} while (0)
#endif /* ! WITH_SCACHE_PBB */
#else /* ! WITH_SCACHE */
/* This is the "simple" engine case. */
#define CIA_ADDR(cia) (cia)
#define SEM_SEM_ARG(vpc, sc) (sc)
#define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len))
#define SEM_BRANCH_INIT \
int taken_p = 0;
#define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used
#define SEM_BRANCH_VIA_CACHE(cpu, abuf, newval, pcvar, cachevar) \
do { \
(pcvar) = (newval); \
taken_p = 1; \
} while (0)
#define SEM_BRANCH_VIA_ADDR(cpu, abuf, newval, pcvar) \
do { \
(pcvar) = (newval); \
taken_p = 1; \
} while (0)
/* Finish off branch insns.
The target must define TARGET_SEM_BRANCH_FINI.
??? This can probably go away when define-execute is finished. */
#define SEM_BRANCH_FINI(pcvar, bool_attrs) \
do { TARGET_SEM_BRANCH_FINI ((pcvar), (bool_attrs), taken_p); } while (0)
/* Finish off non-branch insns.
The target must define TARGET_SEM_NBRANCH_FINI.
??? This can probably go away when define-execute is finished. */
#define SEM_NBRANCH_FINI(pcvar, bool_attrs) \
do { TARGET_SEM_NBRANCH_FINI ((pcvar), (bool_attrs)); } while (0)
#endif /* ! WITH_SCACHE */
/* Instruction information. */
/* Compile time computable instruction data.
??? May wish to move parallel execution support into its own struct.
It's a fair bit of "clutter" for the "normal" case. */
struct insn_sem {
/* The instruction type (a number that identifies each insn over the
entire architecture). */
CGEN_INSN_TYPE type;
/* Index in IDESC table. */
int index;
/* Sanity check, at most one of these may be true. */
#if WITH_PARALLEL_READ && WITH_PARALLEL_WRITE
#error "Both WITH_PARALLEL_READ && WITH_PARALLEL_WRITE can't be true."
#endif
#if WITH_PARALLEL_READ || WITH_PARALLEL_WRITE
/* Index in IDESC table of parallel handler. */
int par_index;
#endif
#if WITH_PARALLEL_READ
#ifndef __GNUC__
/* Semantic format number of pre-read handler.
Only used by chips that support parallel execution of several insns.
It is always implemented as a `switch'. In the case of GNUC we use
computed gotos. When not GNUC, this is the argument to `switch'. */
int fmt;
#endif
#endif
#if WITH_PARALLEL_WRITE
/* Index in IDESC table of writeback handler.
Only used by chips that support parallel execution of several insns. */
int write_index;
#endif
/* Routines to execute the insn.
The full version has all features (profiling,tracing) compiled in.
The fast version has none of that. */
#if ! WITH_SEM_SWITCH_FULL
SEMANTIC_FN *sem_full;
#endif
#if WITH_FAST && ! WITH_SEM_SWITCH_FAST
SEMANTIC_FN *sem_fast;
#endif
};
/* Run-time computed instruction descriptor. */
struct idesc {
/* Parallel read-before-exec support. */
#if WITH_PARALLEL_READ
struct idesc *par_idesc;
#ifdef __GNUC__
void *read;
#else
int fmt;
#endif
#endif
/* Parallel write-after-exec support. */
#if WITH_PARALLEL_WRITE
/* Pointer to parallel handler if serial insn.
Pointer to writeback handler if parallel insn. */
struct idesc *par_idesc;
#endif
#if WITH_SEM_SWITCH_FULL
#ifdef __GNUC__
void *sem_full_lab;
#else
/* nothing needed, switch's on `num' member */
#endif
#else
SEMANTIC_FN *sem_full;
#endif
#if WITH_SEM_SWITCH_FAST
#ifdef __GNUC__
void *sem_fast_lab;
#else
/* nothing needed, switch's on `num' member */
#endif
#else
SEMANTIC_FN *sem_fast;
#endif
/* Instruction number (index in IDESC table, profile table).
Also used to switch on in non-gcc semantic switches. */
int num;
/* instruction data (name, attributes, size, etc.) */
const CGEN_INSN *idata;
/* instruction attributes, copied from `idata' for speed */
const CGEN_INSN_ATTR_TYPE *attrs;
/* instruction length in bytes, copied from `idata' for speed */
int length;
/* profiling/modelling support */
const INSN_TIMING *timing;
};
/* Tracing/profiling. */
/* Return non-zero if a before/after handler is needed.
When tracing/profiling a selected range there's no need to slow
down simulation of the other insns (except to get more accurate data!).
??? May wish to profile all insns if doing insn tracing, or to
get more accurate cycle data.
First test ANY_P so we avoid a potentially expensive HIT_P call
[if there are lots of address ranges]. */
#define PC_IN_TRACE_RANGE_P(cpu, pc) \
(TRACE_ANY_P (cpu) \
&& ADDR_RANGE_HIT_P (TRACE_RANGE (CPU_TRACE_DATA (cpu)), (pc)))
#define PC_IN_PROFILE_RANGE_P(cpu, pc) \
(PROFILE_ANY_P (cpu) \
&& ADDR_RANGE_HIT_P (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), (pc)))
#endif /* CGEN_ENGINE_H */

203
sim/common/cgen-mem.h Normal file
View File

@@ -0,0 +1,203 @@
/* Memory ops header for CGEN-based simulators.
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of the GNU Simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef CGEN_MEM_H
#define CGEN_MEM_H
#ifdef MEMOPS_DEFINE_INLINE
#define MEMOPS_INLINE
#else
#define MEMOPS_INLINE extern inline
#endif
/* Memory read support. */
#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE)
#define DECLARE_GETMEM(mode, size) \
MEMOPS_INLINE mode \
XCONCAT2 (GETMEM,mode) (SIM_CPU *cpu, IADDR pc, ADDR a) \
{ \
PROFILE_COUNT_READ (cpu, a, XCONCAT2 (MODE_,mode)); \
/* Don't read anything into "unaligned" here. Bad name choice. */\
return XCONCAT2 (sim_core_read_unaligned_,size) (cpu, pc, read_map, a); \
}
#else
#define DECLARE_GETMEM(mode, size) \
extern mode XCONCAT2 (GETMEM,mode) (SIM_CPU *, IADDR, ADDR);
#endif
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
#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE)
#define DECLARE_GETMEM(mode, size) \
MEMOPS_INLINE mode \
XCONCAT2 (GETMEM,mode) (SIM_CPU *cpu, IADDR pc, ADDR a) \
{ \
PROFILE_COUNT_READ (cpu, a, XCONCAT2 (MODE_,mode)); \
/* Don't read anything into "unaligned" here. Bad name choice. */\
return XCONCAT2 (sim_core_read_unaligned_,size) (cpu, pc, read_map, a); \
}
#else
#define DECLARE_GETMEM(mode, size) \
extern mode XCONCAT2 (GETMEM,mode) (SIM_CPU *, IADDR, ADDR);
#endif
DECLARE_GETMEM (SF, 4)
DECLARE_GETMEM (DF, 8)
/*DECLARE_GETMEM (TF, 16)*/
#undef DECLARE_GETMEM
/* Memory write support. */
#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE)
#define DECLARE_SETMEM(mode, size) \
MEMOPS_INLINE void \
XCONCAT2 (SETMEM,mode) (SIM_CPU *cpu, IADDR pc, ADDR a, mode val) \
{ \
PROFILE_COUNT_WRITE (cpu, a, XCONCAT2 (MODE_,mode)); \
/* Don't read anything into "unaligned" here. Bad name choice. */ \
XCONCAT2 (sim_core_write_unaligned_,size) (cpu, pc, write_map, a, val); \
}
#else
#define DECLARE_SETMEM(mode, size) \
extern void XCONCAT2 (SETMEM,mode) (SIM_CPU *, IADDR, ADDR, mode);
#endif
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)
/*
DECLARE_SETMEM (SF, 4)
DECLARE_SETMEM (DF, 8)
DECLARE_SETMEM (TF, 16)
*/
#undef DECLARE_SETMEM
/* Instruction read support. */
#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE)
#define DECLARE_GETIMEM(mode, size) \
MEMOPS_INLINE mode \
XCONCAT2 (GETIMEM,mode) (SIM_CPU *cpu, IADDR a) \
{ \
/*PROFILE_COUNT_READ (cpu, a, XCONCAT2 (MODE_,mode));*/ \
/* Don't read anything into "unaligned" here. Bad name choice. */\
return XCONCAT2 (sim_core_read_unaligned_,size) (cpu, a, exec_map, a); \
}
#else
#define DECLARE_GETIMEM(mode, size) \
extern mode XCONCAT2 (GETIMEM,mode) (SIM_CPU *, ADDR);
#endif
DECLARE_GETIMEM (UQI, 1)
DECLARE_GETIMEM (UHI, 2)
DECLARE_GETIMEM (USI, 4)
DECLARE_GETIMEM (UDI, 8)
#undef DECLARE_GETIMEM
/* GETT<mode>: translate target value at P to host value.
This needn't be very efficient (i.e. can call memcpy) as this is
only used when interfacing with the outside world (e.g. gdb). */
#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE)
#define DECLARE_GETT(mode, size) \
MEMOPS_INLINE mode \
XCONCAT2 (GETT,mode) (unsigned char *p) \
{ \
mode tmp; \
memcpy (&tmp, p, sizeof (mode)); \
return XCONCAT2 (T2H_,size) (tmp); \
}
#else
#define DECLARE_GETT(mode, size) \
extern mode XCONCAT2 (GETT,mode) (unsigned char *);
#endif
DECLARE_GETT (QI, 1)
DECLARE_GETT (UQI, 1)
DECLARE_GETT (HI, 2)
DECLARE_GETT (UHI, 2)
DECLARE_GETT (SI, 4)
DECLARE_GETT (USI, 4)
DECLARE_GETT (DI, 8)
DECLARE_GETT (UDI, 8)
/*
DECLARE_GETT (SF, 4)
DECLARE_GETT (DF, 8)
DECLARE_GETT (TF, 16)
*/
#undef DECLARE_GETT
/* SETT<mode>: translate host value to target value and store at P.
This needn't be very efficient (i.e. can call memcpy) as this is
only used when interfacing with the outside world (e.g. gdb). */
#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE)
#define DECLARE_SETT(mode, size) \
MEMOPS_INLINE void \
XCONCAT2 (SETT,mode) (unsigned char *buf, mode val) \
{ \
mode tmp; \
tmp = XCONCAT2 (H2T_,size) (val); \
memcpy (buf, &tmp, sizeof (mode)); \
}
#else
#define DECLARE_SETT(mode, size) \
extern mode XCONCAT2 (GETT,mode) (unsigned char *, mode);
#endif
DECLARE_SETT (QI, 1)
DECLARE_SETT (UQI, 1)
DECLARE_SETT (HI, 2)
DECLARE_SETT (UHI, 2)
DECLARE_SETT (SI, 4)
DECLARE_SETT (USI, 4)
DECLARE_SETT (DI, 8)
DECLARE_SETT (UDI, 8)
/*
DECLARE_SETT (SF, 4)
DECLARE_SETT (DF, 8)
DECLARE_SETT (TF, 16)
*/
#undef DECLARE_SETT
#endif /* CGEN_MEM_H */

897
sim/common/cgen-ops.h Normal file
View File

@@ -0,0 +1,897 @@
/* Semantics ops support for CGEN-based simulators.
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of the GNU Simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef CGEN_SEM_OPS_H
#define CGEN_SEM_OPS_H
/* Semantic operations.
At one point this file was machine generated. Maybe it will be again. */
/* These don't really have a mode. */
#define ANDIF(x, y) ((x) && (y))
#define ORIF(x, y) ((x) || (y))
#define ANDBI(x, y) ((x) & (y))
#define ORBI(x, y) ((x) | (y))
#define XORBI(x, y) ((x) ^ (y))
#define NEGBI(x) (- (x))
#define NOTBI(x) (! (BI) (x))
#define INVBI(x) (~ (x))
#define EQBI(x, y) ((BI) (x) == (BI) (y))
#define NEBI(x, y) ((BI) (x) != (BI) (y))
#define LTBI(x, y) ((BI) (x) < (BI) (y))
#define LEBI(x, y) ((BI) (x) <= (BI) (y))
#define GTBI(x, y) ((BI) (x) > (BI) (y))
#define GEBI(x, y) ((BI) (x) >= (BI) (y))
#define LTUBI(x, y) ((BI) (x) < (BI) (y))
#define LEUBI(x, y) ((BI) (x) <= (BI) (y))
#define GTUBI(x, y) ((BI) (x) > (BI) (y))
#define GEUBI(x, y) ((BI) (x) >= (BI) (y))
#define ADDQI(x, y) ((x) + (y))
#define SUBQI(x, y) ((x) - (y))
#define MULQI(x, y) ((x) * (y))
#define DIVQI(x, y) ((QI) (x) / (QI) (y))
#define UDIVQI(x, y) ((UQI) (x) / (UQI) (y))
#define MODQI(x, y) ((QI) (x) % (QI) (y))
#define UMODQI(x, y) ((UQI) (x) % (UQI) (y))
#define SRAQI(x, y) ((QI) (x) >> (y))
#define SRLQI(x, y) ((UQI) (x) >> (y))
#define SLLQI(x, y) ((UQI) (x) << (y))
extern QI RORQI PARAMS ((QI, int));
extern QI ROLQI PARAMS ((QI, int));
#define ANDQI(x, y) ((x) & (y))
#define ORQI(x, y) ((x) | (y))
#define XORQI(x, y) ((x) ^ (y))
#define NEGQI(x) (- (x))
#define NOTQI(x) (! (QI) (x))
#define INVQI(x) (~ (x))
#define EQQI(x, y) ((QI) (x) == (QI) (y))
#define NEQI(x, y) ((QI) (x) != (QI) (y))
#define LTQI(x, y) ((QI) (x) < (QI) (y))
#define LEQI(x, y) ((QI) (x) <= (QI) (y))
#define GTQI(x, y) ((QI) (x) > (QI) (y))
#define GEQI(x, y) ((QI) (x) >= (QI) (y))
#define LTUQI(x, y) ((UQI) (x) < (UQI) (y))
#define LEUQI(x, y) ((UQI) (x) <= (UQI) (y))
#define GTUQI(x, y) ((UQI) (x) > (UQI) (y))
#define GEUQI(x, y) ((UQI) (x) >= (UQI) (y))
#define ADDHI(x, y) ((x) + (y))
#define SUBHI(x, y) ((x) - (y))
#define MULHI(x, y) ((x) * (y))
#define DIVHI(x, y) ((HI) (x) / (HI) (y))
#define UDIVHI(x, y) ((UHI) (x) / (UHI) (y))
#define MODHI(x, y) ((HI) (x) % (HI) (y))
#define UMODHI(x, y) ((UHI) (x) % (UHI) (y))
#define SRAHI(x, y) ((HI) (x) >> (y))
#define SRLHI(x, y) ((UHI) (x) >> (y))
#define SLLHI(x, y) ((UHI) (x) << (y))
extern HI RORHI PARAMS ((HI, int));
extern HI ROLHI PARAMS ((HI, int));
#define ANDHI(x, y) ((x) & (y))
#define ORHI(x, y) ((x) | (y))
#define XORHI(x, y) ((x) ^ (y))
#define NEGHI(x) (- (x))
#define NOTHI(x) (! (HI) (x))
#define INVHI(x) (~ (x))
#define EQHI(x, y) ((HI) (x) == (HI) (y))
#define NEHI(x, y) ((HI) (x) != (HI) (y))
#define LTHI(x, y) ((HI) (x) < (HI) (y))
#define LEHI(x, y) ((HI) (x) <= (HI) (y))
#define GTHI(x, y) ((HI) (x) > (HI) (y))
#define GEHI(x, y) ((HI) (x) >= (HI) (y))
#define LTUHI(x, y) ((UHI) (x) < (UHI) (y))
#define LEUHI(x, y) ((UHI) (x) <= (UHI) (y))
#define GTUHI(x, y) ((UHI) (x) > (UHI) (y))
#define GEUHI(x, y) ((UHI) (x) >= (UHI) (y))
#define ADDSI(x, y) ((x) + (y))
#define SUBSI(x, y) ((x) - (y))
#define MULSI(x, y) ((x) * (y))
#define DIVSI(x, y) ((SI) (x) / (SI) (y))
#define UDIVSI(x, y) ((USI) (x) / (USI) (y))
#define MODSI(x, y) ((SI) (x) % (SI) (y))
#define UMODSI(x, y) ((USI) (x) % (USI) (y))
#define SRASI(x, y) ((SI) (x) >> (y))
#define SRLSI(x, y) ((USI) (x) >> (y))
#define SLLSI(x, y) ((USI) (x) << (y))
extern SI RORSI PARAMS ((SI, int));
extern SI ROLSI PARAMS ((SI, int));
#define ANDSI(x, y) ((x) & (y))
#define ORSI(x, y) ((x) | (y))
#define XORSI(x, y) ((x) ^ (y))
#define NEGSI(x) (- (x))
#define NOTSI(x) (! (SI) (x))
#define INVSI(x) (~ (x))
#define EQSI(x, y) ((SI) (x) == (SI) (y))
#define NESI(x, y) ((SI) (x) != (SI) (y))
#define LTSI(x, y) ((SI) (x) < (SI) (y))
#define LESI(x, y) ((SI) (x) <= (SI) (y))
#define GTSI(x, y) ((SI) (x) > (SI) (y))
#define GESI(x, y) ((SI) (x) >= (SI) (y))
#define LTUSI(x, y) ((USI) (x) < (USI) (y))
#define LEUSI(x, y) ((USI) (x) <= (USI) (y))
#define GTUSI(x, y) ((USI) (x) > (USI) (y))
#define GEUSI(x, y) ((USI) (x) >= (USI) (y))
#ifdef DI_FN_SUPPORT
extern DI ADDDI PARAMS ((DI, DI));
extern DI SUBDI PARAMS ((DI, DI));
extern DI MULDI PARAMS ((DI, DI));
extern DI DIVDI PARAMS ((DI, DI));
extern DI UDIVDI PARAMS ((DI, DI));
extern DI MODDI PARAMS ((DI, DI));
extern DI UMODDI PARAMS ((DI, DI));
extern DI SRADI PARAMS ((DI, int));
extern UDI SRLDI PARAMS ((UDI, int));
extern UDI SLLDI PARAMS ((UDI, int));
extern DI RORDI PARAMS ((DI, int));
extern DI ROLDI PARAMS ((DI, int));
extern DI ANDDI PARAMS ((DI, DI));
extern DI ORDI PARAMS ((DI, DI));
extern DI XORDI PARAMS ((DI, DI));
extern DI NEGDI PARAMS ((DI));
extern int NOTDI PARAMS ((DI));
extern DI INVDI PARAMS ((DI));
extern int EQDI PARAMS ((DI, DI));
extern int NEDI PARAMS ((DI, DI));
extern int LTDI PARAMS ((DI, DI));
extern int LEDI PARAMS ((DI, DI));
extern int GTDI PARAMS ((DI, DI));
extern int GEDI PARAMS ((DI, DI));
extern int LTUDI PARAMS ((UDI, UDI));
extern int LEUDI PARAMS ((UDI, UDI));
extern int GTUDI PARAMS ((UDI, UDI));
extern int GEUDI PARAMS ((UDI, UDI));
#else /* ! DI_FN_SUPPORT */
#define ADDDI(x, y) ((x) + (y))
#define SUBDI(x, y) ((x) - (y))
#define MULDI(x, y) ((x) * (y))
#define DIVDI(x, y) ((DI) (x) / (DI) (y))
#define UDIVDI(x, y) ((UDI) (x) / (UDI) (y))
#define MODDI(x, y) ((DI) (x) % (DI) (y))
#define UMODDI(x, y) ((UDI) (x) % (UDI) (y))
#define SRADI(x, y) ((DI) (x) >> (y))
#define SRLDI(x, y) ((UDI) (x) >> (y))
#define SLLDI(x, y) ((UDI) (x) << (y))
extern DI RORDI PARAMS ((DI, int));
extern DI ROLDI PARAMS ((DI, int));
#define ANDDI(x, y) ((x) & (y))
#define ORDI(x, y) ((x) | (y))
#define XORDI(x, y) ((x) ^ (y))
#define NEGDI(x) (- (x))
#define NOTDI(x) (! (DI) (x))
#define INVDI(x) (~ (x))
#define EQDI(x, y) ((DI) (x) == (DI) (y))
#define NEDI(x, y) ((DI) (x) != (DI) (y))
#define LTDI(x, y) ((DI) (x) < (DI) (y))
#define LEDI(x, y) ((DI) (x) <= (DI) (y))
#define GTDI(x, y) ((DI) (x) > (DI) (y))
#define GEDI(x, y) ((DI) (x) >= (DI) (y))
#define LTUDI(x, y) ((UDI) (x) < (UDI) (y))
#define LEUDI(x, y) ((UDI) (x) <= (UDI) (y))
#define GTUDI(x, y) ((UDI) (x) > (UDI) (y))
#define GEUDI(x, y) ((UDI) (x) >= (UDI) (y))
#endif /* DI_FN_SUPPORT */
#ifdef SF_FN_SUPPORT
extern SF ADDSF PARAMS ((SF, SF));
extern SF SUBSF PARAMS ((SF, SF));
extern SF NEGSF PARAMS ((SF));
extern SF MULSF PARAMS ((SF, SF));
extern SF DIVSF PARAMS ((SF, SF));
extern int EQSF PARAMS ((SF, SF));
extern int NESF PARAMS ((SF, SF));
extern int LTSF PARAMS ((SF, SF));
extern int LESF PARAMS ((SF, SF));
extern int GTSF PARAMS ((SF, SF));
extern int GESF PARAMS ((SF, SF));
extern SF ABSSF PARAMS ((SF));
extern SF SQRTSF PARAMS ((SF));
extern SF COSSF PARAMS ((SF));
extern SF SINSF PARAMS ((SF));
#else /* ! SF_FN_SUPPORT */
#define ADDSF(x, y) ((x) + (y))
#define SUBSF(x, y) ((x) - (y))
#define NEGSF(x) (- (x))
#define MULSF(x, y) ((x) * (y))
#define DIVSF(x, y) ((x) / (y))
#define EQSF(x, y) ((SF) (x) == (SF) (y))
#define NESF(x, y) ((SF) (x) != (SF) (y))
#define LTSF(x, y) ((SF) (x) < (SF) (y))
#define LESF(x, y) ((SF) (x) <= (SF) (y))
#define GTSF(x, y) ((SF) (x) > (SF) (y))
#define GESF(x, y) ((SF) (x) >= (SF) (y))
extern SF ABSSF PARAMS ((SF));
extern SF SQRTSF PARAMS ((SF));
extern SF COSSF PARAMS ((SF));
extern SF SINSF PARAMS ((SF));
#endif /* SF_FN_SUPPORT */
#ifdef DF_FN_SUPPORT
extern DF ADDDF PARAMS ((DF, DF));
extern DF SUBDF PARAMS ((DF, DF));
extern DF NEGDF PARAMS ((DF));
extern DF MULDF PARAMS ((DF, DF));
extern DF DIVDF PARAMS ((DF, DF));
extern int EQDF PARAMS ((DF, DF));
extern int NEDF PARAMS ((DF, DF));
extern int LTDF PARAMS ((DF, DF));
extern int LEDF PARAMS ((DF, DF));
extern int GTDF PARAMS ((DF, DF));
extern int GEDF PARAMS ((DF, DF));
extern DF ABSDF PARAMS ((DF));
extern DF SQRTDF PARAMS ((DF));
extern DF COSDF PARAMS ((DF));
extern DF SINDF PARAMS ((DF));
#else /* ! DF_FN_SUPPORT */
#define ADDDF(x, y) ((x) + (y))
#define SUBDF(x, y) ((x) - (y))
#define NEGDF(x) (- (x))
#define MULDF(x, y) ((x) * (y))
#define DIVDF(x, y) ((x) / (y))
#define EQDF(x, y) ((DF) (x) == (DF) (y))
#define NEDF(x, y) ((DF) (x) != (DF) (y))
#define LTDF(x, y) ((DF) (x) < (DF) (y))
#define LEDF(x, y) ((DF) (x) <= (DF) (y))
#define GTDF(x, y) ((DF) (x) > (DF) (y))
#define GEDF(x, y) ((DF) (x) >= (DF) (y))
extern DF ABSDF PARAMS ((DF));
extern DF SQRTDF PARAMS ((DF));
extern DF COSDF PARAMS ((DF));
extern DF SINDF PARAMS ((DF));
#endif /* DF_FN_SUPPORT */
#ifdef XF_FN_SUPPORT
extern XF ADDXF PARAMS ((XF, XF));
extern XF SUBXF PARAMS ((XF, XF));
extern XF NEGXF PARAMS ((XF));
extern XF MULXF PARAMS ((XF, XF));
extern XF DIVXF PARAMS ((XF, XF));
extern int EQXF PARAMS ((XF, XF));
extern int NEXF PARAMS ((XF, XF));
extern int LTXF PARAMS ((XF, XF));
extern int LEXF PARAMS ((XF, XF));
extern int GTXF PARAMS ((XF, XF));
extern int GEXF PARAMS ((XF, XF));
extern XF ABSXF PARAMS ((XF));
extern XF SQRTXF PARAMS ((XF));
extern XF COSXF PARAMS ((XF));
extern XF SINXF PARAMS ((XF));
#else /* ! XF_FN_SUPPORT */
#define ADDXF(x, y) ((x) + (y))
#define SUBXF(x, y) ((x) - (y))
#define NEGXF(x) (- (x))
#define MULXF(x, y) ((x) * (y))
#define DIVXF(x, y) ((x) / (y))
#define EQXF(x, y) ((XF) (x) == (XF) (y))
#define NEXF(x, y) ((XF) (x) != (XF) (y))
#define LTXF(x, y) ((XF) (x) < (XF) (y))
#define LEXF(x, y) ((XF) (x) <= (XF) (y))
#define GTXF(x, y) ((XF) (x) > (XF) (y))
#define GEXF(x, y) ((XF) (x) >= (XF) (y))
extern XF ABSXF PARAMS ((XF));
extern XF SQRTXF PARAMS ((XF));
extern XF COSXF PARAMS ((XF));
extern XF SINXF PARAMS ((XF));
#endif /* XF_FN_SUPPORT */
#ifdef TF_FN_SUPPORT
extern TF ADDTF PARAMS ((TF, TF));
extern TF SUBTF PARAMS ((TF, TF));
extern TF NEGTF PARAMS ((TF));
extern TF MULTF PARAMS ((TF, TF));
extern TF DIVTF PARAMS ((TF, TF));
extern int EQTF PARAMS ((TF, TF));
extern int NETF PARAMS ((TF, TF));
extern int LTTF PARAMS ((TF, TF));
extern int LETF PARAMS ((TF, TF));
extern int GTTF PARAMS ((TF, TF));
extern int GETF PARAMS ((TF, TF));
extern TF ABSTF PARAMS ((TF));
extern TF SQRTTF PARAMS ((TF));
extern TF COSTF PARAMS ((TF));
extern TF SINTF PARAMS ((TF));
#else /* ! TF_FN_SUPPORT */
#define ADDTF(x, y) ((x) + (y))
#define SUBTF(x, y) ((x) - (y))
#define NEGTF(x) (- (x))
#define MULTF(x, y) ((x) * (y))
#define DIVTF(x, y) ((x) / (y))
#define EQTF(x, y) ((TF) (x) == (TF) (y))
#define NETF(x, y) ((TF) (x) != (TF) (y))
#define LTTF(x, y) ((TF) (x) < (TF) (y))
#define LETF(x, y) ((TF) (x) <= (TF) (y))
#define GTTF(x, y) ((TF) (x) > (TF) (y))
#define GETF(x, y) ((TF) (x) >= (TF) (y))
extern TF ABSTF PARAMS ((TF));
extern TF SQRTTF PARAMS ((TF));
extern TF COSTF PARAMS ((TF));
extern TF SINTF PARAMS ((TF));
#endif /* TF_FN_SUPPORT */
#define EXTBIQI(x) ((QI) (BI) (x))
#define EXTBIHI(x) ((HI) (BI) (x))
#define EXTBISI(x) ((SI) (BI) (x))
#if defined (DI_FN_SUPPORT)
extern DI EXTBIDI PARAMS ((BI));
#else
#define EXTBIDI(x) ((DI) (BI) (x))
#endif
#define EXTQIHI(x) ((HI) (QI) (x))
#define EXTQISI(x) ((SI) (QI) (x))
#if defined (DI_FN_SUPPORT)
extern DI EXTQIDI PARAMS ((QI));
#else
#define EXTQIDI(x) ((DI) (QI) (x))
#endif
#define EXTHISI(x) ((SI) (HI) (x))
#if defined (DI_FN_SUPPORT)
extern DI EXTHIDI PARAMS ((HI));
#else
#define EXTHIDI(x) ((DI) (HI) (x))
#endif
#if defined (DI_FN_SUPPORT)
extern DI EXTSIDI PARAMS ((SI));
#else
#define EXTSIDI(x) ((DI) (SI) (x))
#endif
#if defined (SF_FN_SUPPORT) || defined (DF_FN_SUPPORT)
extern DF EXTSFDF PARAMS ((SF));
#else
#define EXTSFDF(x) ((DF) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT) || defined (XF_FN_SUPPORT)
extern XF EXTSFXF PARAMS ((SF));
#else
#define EXTSFXF(x) ((XF) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT) || defined (TF_FN_SUPPORT)
extern TF EXTSFTF PARAMS ((SF));
#else
#define EXTSFTF(x) ((TF) (SF) (x))
#endif
#if defined (DF_FN_SUPPORT) || defined (XF_FN_SUPPORT)
extern XF EXTDFXF PARAMS ((DF));
#else
#define EXTDFXF(x) ((XF) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT) || defined (TF_FN_SUPPORT)
extern TF EXTDFTF PARAMS ((DF));
#else
#define EXTDFTF(x) ((TF) (DF) (x))
#endif
#if defined (XF_FN_SUPPORT) || defined (TF_FN_SUPPORT)
extern TF EXTXFTF PARAMS ((XF));
#else
#define EXTXFTF(x) ((TF) (XF) (x))
#endif
#define ZEXTBIQI(x) ((QI) (BI) (x))
#define ZEXTBIHI(x) ((HI) (BI) (x))
#define ZEXTBISI(x) ((SI) (BI) (x))
#if defined (DI_FN_SUPPORT)
extern DI ZEXTBIDI PARAMS ((BI));
#else
#define ZEXTBIDI(x) ((DI) (BI) (x))
#endif
#define ZEXTQIHI(x) ((HI) (UQI) (x))
#define ZEXTQISI(x) ((SI) (UQI) (x))
#if defined (DI_FN_SUPPORT)
extern DI ZEXTQIDI PARAMS ((QI));
#else
#define ZEXTQIDI(x) ((DI) (UQI) (x))
#endif
#define ZEXTHISI(x) ((SI) (UHI) (x))
#if defined (DI_FN_SUPPORT)
extern DI ZEXTHIDI PARAMS ((HI));
#else
#define ZEXTHIDI(x) ((DI) (UHI) (x))
#endif
#if defined (DI_FN_SUPPORT)
extern DI ZEXTSIDI PARAMS ((SI));
#else
#define ZEXTSIDI(x) ((DI) (USI) (x))
#endif
#define TRUNCQIBI(x) ((BI) (QI) (x))
#define TRUNCHIBI(x) ((BI) (HI) (x))
#define TRUNCHIQI(x) ((QI) (HI) (x))
#define TRUNCSIBI(x) ((BI) (SI) (x))
#define TRUNCSIQI(x) ((QI) (SI) (x))
#define TRUNCSIHI(x) ((HI) (SI) (x))
#if defined (DI_FN_SUPPORT)
extern BI TRUNCDIBI PARAMS ((DI));
#else
#define TRUNCDIBI(x) ((BI) (DI) (x))
#endif
#if defined (DI_FN_SUPPORT)
extern QI TRUNCDIQI PARAMS ((DI));
#else
#define TRUNCDIQI(x) ((QI) (DI) (x))
#endif
#if defined (DI_FN_SUPPORT)
extern HI TRUNCDIHI PARAMS ((DI));
#else
#define TRUNCDIHI(x) ((HI) (DI) (x))
#endif
#if defined (DI_FN_SUPPORT)
extern SI TRUNCDISI PARAMS ((DI));
#else
#define TRUNCDISI(x) ((SI) (DI) (x))
#endif
#if defined (DF_FN_SUPPORT) || defined (SF_FN_SUPPORT)
extern SF TRUNCDFSF PARAMS ((DF));
#else
#define TRUNCDFSF(x) ((SF) (DF) (x))
#endif
#if defined (XF_FN_SUPPORT) || defined (SF_FN_SUPPORT)
extern SF TRUNCXFSF PARAMS ((XF));
#else
#define TRUNCXFSF(x) ((SF) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT) || defined (DF_FN_SUPPORT)
extern DF TRUNCXFDF PARAMS ((XF));
#else
#define TRUNCXFDF(x) ((DF) (XF) (x))
#endif
#if defined (TF_FN_SUPPORT) || defined (SF_FN_SUPPORT)
extern SF TRUNCTFSF PARAMS ((TF));
#else
#define TRUNCTFSF(x) ((SF) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT) || defined (DF_FN_SUPPORT)
extern DF TRUNCTFDF PARAMS ((TF));
#else
#define TRUNCTFDF(x) ((DF) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT) || defined (XF_FN_SUPPORT)
extern XF TRUNCTFXF PARAMS ((TF));
#else
#define TRUNCTFXF(x) ((XF) (TF) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SF FLOATQISF PARAMS ((QI));
#else
#define FLOATQISF(x) ((SF) (QI) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern DF FLOATQIDF PARAMS ((QI));
#else
#define FLOATQIDF(x) ((DF) (QI) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern XF FLOATQIXF PARAMS ((QI));
#else
#define FLOATQIXF(x) ((XF) (QI) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern TF FLOATQITF PARAMS ((QI));
#else
#define FLOATQITF(x) ((TF) (QI) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SF FLOATHISF PARAMS ((HI));
#else
#define FLOATHISF(x) ((SF) (HI) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern DF FLOATHIDF PARAMS ((HI));
#else
#define FLOATHIDF(x) ((DF) (HI) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern XF FLOATHIXF PARAMS ((HI));
#else
#define FLOATHIXF(x) ((XF) (HI) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern TF FLOATHITF PARAMS ((HI));
#else
#define FLOATHITF(x) ((TF) (HI) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SF FLOATSISF PARAMS ((SI));
#else
#define FLOATSISF(x) ((SF) (SI) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern DF FLOATSIDF PARAMS ((SI));
#else
#define FLOATSIDF(x) ((DF) (SI) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern XF FLOATSIXF PARAMS ((SI));
#else
#define FLOATSIXF(x) ((XF) (SI) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern TF FLOATSITF PARAMS ((SI));
#else
#define FLOATSITF(x) ((TF) (SI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (SF_FN_SUPPORT)
extern SF FLOATDISF PARAMS ((DI));
#else
#define FLOATDISF(x) ((SF) (DI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (DF_FN_SUPPORT)
extern DF FLOATDIDF PARAMS ((DI));
#else
#define FLOATDIDF(x) ((DF) (DI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (XF_FN_SUPPORT)
extern XF FLOATDIXF PARAMS ((DI));
#else
#define FLOATDIXF(x) ((XF) (DI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (TF_FN_SUPPORT)
extern TF FLOATDITF PARAMS ((DI));
#else
#define FLOATDITF(x) ((TF) (DI) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SF UFLOATQISF PARAMS ((QI));
#else
#define UFLOATQISF(x) ((SF) (UQI) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern DF UFLOATQIDF PARAMS ((QI));
#else
#define UFLOATQIDF(x) ((DF) (UQI) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern XF UFLOATQIXF PARAMS ((QI));
#else
#define UFLOATQIXF(x) ((XF) (UQI) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern TF UFLOATQITF PARAMS ((QI));
#else
#define UFLOATQITF(x) ((TF) (UQI) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SF UFLOATHISF PARAMS ((HI));
#else
#define UFLOATHISF(x) ((SF) (UHI) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern DF UFLOATHIDF PARAMS ((HI));
#else
#define UFLOATHIDF(x) ((DF) (UHI) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern XF UFLOATHIXF PARAMS ((HI));
#else
#define UFLOATHIXF(x) ((XF) (UHI) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern TF UFLOATHITF PARAMS ((HI));
#else
#define UFLOATHITF(x) ((TF) (UHI) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SF UFLOATSISF PARAMS ((SI));
#else
#define UFLOATSISF(x) ((SF) (USI) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern DF UFLOATSIDF PARAMS ((SI));
#else
#define UFLOATSIDF(x) ((DF) (USI) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern XF UFLOATSIXF PARAMS ((SI));
#else
#define UFLOATSIXF(x) ((XF) (USI) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern TF UFLOATSITF PARAMS ((SI));
#else
#define UFLOATSITF(x) ((TF) (USI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (SF_FN_SUPPORT)
extern SF UFLOATDISF PARAMS ((DI));
#else
#define UFLOATDISF(x) ((SF) (UDI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (DF_FN_SUPPORT)
extern DF UFLOATDIDF PARAMS ((DI));
#else
#define UFLOATDIDF(x) ((DF) (UDI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (XF_FN_SUPPORT)
extern XF UFLOATDIXF PARAMS ((DI));
#else
#define UFLOATDIXF(x) ((XF) (UDI) (x))
#endif
#if defined (DI_FN_SUPPORT) || defined (TF_FN_SUPPORT)
extern TF UFLOATDITF PARAMS ((DI));
#else
#define UFLOATDITF(x) ((TF) (UDI) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern BI FIXSFBI PARAMS ((SF));
#else
#define FIXSFBI(x) ((BI) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern QI FIXSFQI PARAMS ((SF));
#else
#define FIXSFQI(x) ((QI) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern HI FIXSFHI PARAMS ((SF));
#else
#define FIXSFHI(x) ((HI) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SI FIXSFSI PARAMS ((SF));
#else
#define FIXSFSI(x) ((SI) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI FIXSFDI PARAMS ((SF));
#else
#define FIXSFDI(x) ((DI) (SF) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern BI FIXDFBI PARAMS ((DF));
#else
#define FIXDFBI(x) ((BI) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern QI FIXDFQI PARAMS ((DF));
#else
#define FIXDFQI(x) ((QI) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern HI FIXDFHI PARAMS ((DF));
#else
#define FIXDFHI(x) ((HI) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern SI FIXDFSI PARAMS ((DF));
#else
#define FIXDFSI(x) ((SI) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI FIXDFDI PARAMS ((DF));
#else
#define FIXDFDI(x) ((DI) (DF) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern BI FIXXFBI PARAMS ((XF));
#else
#define FIXXFBI(x) ((BI) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern QI FIXXFQI PARAMS ((XF));
#else
#define FIXXFQI(x) ((QI) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern HI FIXXFHI PARAMS ((XF));
#else
#define FIXXFHI(x) ((HI) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern SI FIXXFSI PARAMS ((XF));
#else
#define FIXXFSI(x) ((SI) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI FIXXFDI PARAMS ((XF));
#else
#define FIXXFDI(x) ((DI) (XF) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern BI FIXTFBI PARAMS ((TF));
#else
#define FIXTFBI(x) ((BI) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern QI FIXTFQI PARAMS ((TF));
#else
#define FIXTFQI(x) ((QI) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern HI FIXTFHI PARAMS ((TF));
#else
#define FIXTFHI(x) ((HI) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern SI FIXTFSI PARAMS ((TF));
#else
#define FIXTFSI(x) ((SI) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI FIXTFDI PARAMS ((TF));
#else
#define FIXTFDI(x) ((DI) (TF) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern QI UFIXSFQI PARAMS ((SF));
#else
#define UFIXSFQI(x) ((UQI) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern HI UFIXSFHI PARAMS ((SF));
#else
#define UFIXSFHI(x) ((UHI) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT)
extern SI UFIXSFSI PARAMS ((SF));
#else
#define UFIXSFSI(x) ((USI) (SF) (x))
#endif
#if defined (SF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI UFIXSFDI PARAMS ((SF));
#else
#define UFIXSFDI(x) ((UDI) (SF) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern QI UFIXDFQI PARAMS ((DF));
#else
#define UFIXDFQI(x) ((UQI) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern HI UFIXDFHI PARAMS ((DF));
#else
#define UFIXDFHI(x) ((UHI) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT)
extern SI UFIXDFSI PARAMS ((DF));
#else
#define UFIXDFSI(x) ((USI) (DF) (x))
#endif
#if defined (DF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI UFIXDFDI PARAMS ((DF));
#else
#define UFIXDFDI(x) ((UDI) (DF) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern QI UFIXXFQI PARAMS ((XF));
#else
#define UFIXXFQI(x) ((UQI) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern HI UFIXXFHI PARAMS ((XF));
#else
#define UFIXXFHI(x) ((UHI) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT)
extern SI UFIXXFSI PARAMS ((XF));
#else
#define UFIXXFSI(x) ((USI) (XF) (x))
#endif
#if defined (XF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI UFIXXFDI PARAMS ((XF));
#else
#define UFIXXFDI(x) ((UDI) (XF) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern QI UFIXTFQI PARAMS ((TF));
#else
#define UFIXTFQI(x) ((UQI) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern HI UFIXTFHI PARAMS ((TF));
#else
#define UFIXTFHI(x) ((UHI) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT)
extern SI UFIXTFSI PARAMS ((TF));
#else
#define UFIXTFSI(x) ((USI) (TF) (x))
#endif
#if defined (TF_FN_SUPPORT) || defined (DI_FN_SUPPORT)
extern DI UFIXTFDI PARAMS ((TF));
#else
#define UFIXTFDI(x) ((UDI) (TF) (x))
#endif
/* Semantic support utilities. */
#ifdef __GNUC__
#ifdef SEMOPS_DEFINE_INLINE
#define SEMOPS_INLINE
#else
#define SEMOPS_INLINE extern inline
#endif
SEMOPS_INLINE SI
ADDCSI (SI a, SI b, BI c)
{
SI res = ADDSI (a, ADDSI (b, c));
return res;
}
SEMOPS_INLINE BI
ADDCFSI (SI a, SI b, BI c)
{
SI tmp = ADDSI (a, ADDSI (b, c));
BI res = ((USI) tmp < (USI) a) || (c && tmp == a);
return res;
}
SEMOPS_INLINE BI
ADDOFSI (SI a, SI b, BI c)
{
SI tmp = ADDSI (a, ADDSI (b, c));
BI res = (((a < 0) == (b < 0))
&& ((a < 0) != (tmp < 0)));
return res;
}
SEMOPS_INLINE SI
SUBCSI (SI a, SI b, BI c)
{
SI res = SUBSI (a, ADDSI (b, c));
return res;
}
SEMOPS_INLINE BI
SUBCFSI (SI a, SI b, BI c)
{
BI res = ((USI) a < (USI) b) || (c && a == b);
return res;
}
SEMOPS_INLINE BI
SUBOFSI (SI a, SI b, BI c)
{
SI tmp = SUBSI (a, ADDSI (b, c));
BI res = (((a < 0) != (b < 0))
&& ((a < 0) != (tmp < 0)));
return res;
}
#else
SI ADDCSI (SI, SI, BI);
UBI ADDCFSI (SI, SI, BI);
UBI ADDOFSI (SI, SI, BI);
SI SUBCSI (SI, SI, BI);
UBI SUBCFSI (SI, SI, BI);
UBI SUBOFSI (SI, SI, BI);
#endif
/* DI mode support if "long long" doesn't exist.
At one point CGEN supported K&R C compilers, and ANSI C compilers without
"long long". One can argue the various merits of keeping this in or
throwing it out. I went to the trouble of adding it so for the time being
I'm leaving it in. */
#ifdef DI_FN_SUPPORT
DI make_struct_di (SI, SI);
/* FIXME: needed? */
DI CONVHIDI (HI);
DI CONVSIDI (SI);
SI CONVDISI (DI);
#endif /* DI_FN_SUPPORT */
#endif /* CGEN_SEM_OPS_H */

233
sim/common/cgen-run.c Normal file
View File

@@ -0,0 +1,233 @@
/* Main simulator loop for CGEN-based simulators.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* ??? These are old notes, kept around for now.
Collecting profile data and tracing slow us down so we don't do them in
"fast mode".
There are 6 possibilities on 2 axes:
- no-scaching, insn-scaching, basic-block-scaching
- run with full features or run fast
Supporting all six possibilities in one executable is a bit much but
supporting full/fast seems reasonable.
If the scache is configured in it is always used.
If pbb-scaching is configured in it is always used.
??? Sometimes supporting more than one set of semantic functions will make
the simulator too large - this should be configurable. Blah blah blah.
??? Supporting full/fast can be more modular, blah blah blah.
When the framework is more modular, this can be.
*/
#include "sim-main.h"
#include "sim-assert.h"
#ifndef SIM_ENGINE_PREFIX_HOOK
#define SIM_ENGINE_PREFIX_HOOK(sd)
#endif
#ifndef SIM_ENGINE_POSTFIX_HOOK
#define SIM_ENGINE_POSTFIX_HOOK(sd)
#endif
static sim_event_handler has_stepped;
static void prime_cpu (SIM_CPU *, int);
static void engine_run_1 (SIM_DESC, int, int);
static void engine_run_n (SIM_DESC, int, int, int, int);
/* sim_resume for cgen */
void
sim_resume (SIM_DESC sd, int step, int siggnal)
{
sim_engine *engine = STATE_ENGINE (sd);
jmp_buf buf;
int jmpval;
ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
/* we only want to be single stepping the simulator once */
if (engine->stepper != NULL)
{
sim_events_deschedule (sd, engine->stepper);
engine->stepper = NULL;
}
if (step)
engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd);
sim_module_resume (sd);
#if WITH_SCACHE
if (USING_SCACHE_P (sd))
scache_flush (sd);
#endif
/* run/resume the simulator */
sim_engine_set_run_state (sd, sim_running, 0);
engine->jmpbuf = &buf;
jmpval = setjmp (buf);
if (jmpval == sim_engine_start_jmpval
|| jmpval == sim_engine_restart_jmpval)
{
int last_cpu_nr = sim_engine_last_cpu_nr (sd);
int next_cpu_nr = sim_engine_next_cpu_nr (sd);
int nr_cpus = sim_engine_nr_cpus (sd);
/* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is
useful if all one wants to do is run a benchmark. Need some better
way to identify this case. */
int max_insns = (step
? 1
: (nr_cpus == 1 /*&& wip:no-events*/)
? 0
: 4); /*FIXME: magic number*/
int fast_p = STATE_RUN_FAST_P (sd);
sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus);
if (next_cpu_nr >= nr_cpus)
next_cpu_nr = 0;
if (nr_cpus == 1)
engine_run_1 (sd, max_insns, fast_p);
else
engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p);
}
#if 1 /*wip*/
else
{
/* Account for the last insn executed. */
SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd));
++ CPU_INSN_COUNT (cpu);
TRACE_INSN_FINI (cpu, NULL, 1);
}
#endif
engine->jmpbuf = NULL;
{
int i;
int nr_cpus = sim_engine_nr_cpus (sd);
#if 0 /*wip,ignore*/
/* If the loop exits, either we single-stepped or @cpu@_engine_stop
was called. */
if (step)
sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP);
else
sim_engine_set_run_state (sd, pending_reason, pending_sigrc);
#endif
for (i = 0; i < nr_cpus; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu);
}
}
sim_module_suspend (sd);
}
/* Halt the simulator after just one instruction. */
static void
has_stepped (SIM_DESC sd, void *data)
{
ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP);
}
/* Prepare a cpu for running.
MAX_INSNS is the number of insns to execute per time slice.
If 0 it means the cpu can run as long as it wants (e.g. until the
program completes).
??? Perhaps this should be an argument to the engine_fn. */
static void
prime_cpu (SIM_CPU *cpu, int max_insns)
{
CPU_MAX_SLICE_INSNS (cpu) = max_insns;
CPU_INSN_COUNT (cpu) = 0;
/* Initialize the insn descriptor table.
This has to be done after all initialization so we just defer it to
here. */
if (MACH_PREPARE_RUN (CPU_MACH (cpu)))
(* MACH_PREPARE_RUN (CPU_MACH (cpu))) (cpu);
}
/* Main loop, for 1 cpu. */
static void
engine_run_1 (SIM_DESC sd, int max_insns, int fast_p)
{
sim_cpu *cpu = STATE_CPU (sd, 0);
ENGINE_FN *fn = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu);
prime_cpu (cpu, max_insns);
while (1)
{
SIM_ENGINE_PREFIX_HOOK (sd);
(*fn) (cpu);
SIM_ENGINE_POSTFIX_HOOK (sd);
/* process any events */
if (sim_events_tick (sd))
sim_events_process (sd);
}
}
/* Main loop, for multiple cpus. */
static void
engine_run_n (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int max_insns, int fast_p)
{
int i;
ENGINE_FN *engine_fns[MAX_NR_PROCESSORS];
for (i = 0; i < nr_cpus; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
engine_fns[i] = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu);
prime_cpu (cpu, max_insns);
}
while (1)
{
SIM_ENGINE_PREFIX_HOOK (sd);
/* FIXME: proper cycling of all of them, blah blah blah. */
while (next_cpu_nr != nr_cpus)
{
SIM_CPU *cpu = STATE_CPU (sd, next_cpu_nr);
(* engine_fns[next_cpu_nr]) (cpu);
++next_cpu_nr;
}
SIM_ENGINE_POSTFIX_HOOK (sd);
/* process any events */
if (sim_events_tick (sd))
sim_events_process (sd);
}
}

471
sim/common/cgen-scache.c Normal file
View File

@@ -0,0 +1,471 @@
/* Simulator cache routines for CGEN simulators (and maybe others).
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define SCACHE_DEFINE_INLINE
#include "sim-main.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "libiberty.h"
#include "sim-options.h"
#include "sim-io.h"
#define MAX(a,b) ((a) > (b) ? (a) : (b))
/* Unused address. */
#define UNUSED_ADDR 0xffffffff
/* Scache configuration parameters.
??? Experiments to determine reasonable values is wip.
These are just guesses. */
/* Default number of scache elements.
The size of an element is typically 32-64 bytes, so the size of the
default scache will be between 512K and 1M bytes. */
#ifdef CONFIG_SIM_CACHE_SIZE
#define SCACHE_DEFAULT_CACHE_SIZE CONFIG_SIM_CACHE_SIZE
#else
#define SCACHE_DEFAULT_CACHE_SIZE 16384
#endif
/* Minimum cache size.
The m32r port assumes a cache size of at least 2 so it can decode both 16
bit insns. When compiling we need an extra for the chain entry. And this
must be a multiple of 2. Hence 4 is the minimum (though, for those with
featuritis or itchy pedantic bits, we could make this conditional on
WITH_SCACHE_PBB). */
#define MIN_SCACHE_SIZE 4
/* Ratio of size of text section to size of scache.
When compiling, we don't want to flush the scache more than we have to
but we also don't want it to be exorbitantly(sp?) large. So we pick a high
default value, then reduce it by the size of the program being simulated,
but we don't override any value specified on the command line.
If not specified on the command line, the size to use is computed as
max (MIN_SCACHE_SIZE,
min (DEFAULT_SCACHE_SIZE,
text_size / (base_insn_size * INSN_SCACHE_RATIO))). */
/* ??? Interesting idea but not currently used. */
#define INSN_SCACHE_RATIO 4
/* Default maximum insn chain length.
The only reason for a maximum is so we can place a maximum size on the
profiling table. Chain lengths are determined by cti's.
32 is a more reasonable number, but when profiling, the before/after
handlers take up that much more space. The scache is filled from front to
back so all this determines is when the scache needs to be flushed. */
#define MAX_CHAIN_LENGTH 64
/* Default maximum hash list length. */
#define MAX_HASH_CHAIN_LENGTH 4
/* Minimum hash table size. */
#define MIN_HASH_CHAINS 32
/* Ratio of number of scache elements to number of hash lists.
Since the user can only specify the size of the scache, we compute the
size of the hash table as
max (MIN_HASH_CHAINS, scache_size / SCACHE_HASH_RATIO). */
#define SCACHE_HASH_RATIO 8
/* Hash a PC value.
FIXME: May wish to make the hashing architecture specific.
FIXME: revisit */
#define HASH_PC(pc) (((pc) >> 2) + ((pc) >> 5))
static MODULE_INIT_FN scache_init;
static MODULE_UNINSTALL_FN scache_uninstall;
static DECLARE_OPTION_HANDLER (scache_option_handler);
#define OPTION_PROFILE_SCACHE (OPTION_START + 0)
static const OPTION scache_options[] = {
{ {"scache-size", optional_argument, NULL, 'c'},
'c', "[SIZE]", "Specify size of simulator execution cache",
scache_option_handler },
#if WITH_SCACHE_PBB
/* ??? It might be nice to allow the user to specify the size of the hash
table, the maximum hash list length, and the maximum chain length, but
for now that might be more akin to featuritis. */
#endif
{ {"profile-scache", optional_argument, NULL, OPTION_PROFILE_SCACHE},
'\0', "on|off", "Perform simulator execution cache profiling",
scache_option_handler },
{ {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
};
static SIM_RC
scache_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
char *arg, int is_command)
{
int n;
switch (opt)
{
case 'c' :
if (WITH_SCACHE)
{
if (arg != NULL)
{
int n = strtol (arg, NULL, 0);
if (n < MIN_SCACHE_SIZE)
{
sim_io_eprintf (sd, "invalid scache size `%d', must be at least 4", n);
return SIM_RC_FAIL;
}
/* Ensure it's a multiple of 2. */
if ((n & (n - 1)) != 0)
{
sim_io_eprintf (sd, "scache size `%d' not a multiple of 2\n", n);
{
/* round up to nearest multiple of 2 */
int i;
for (i = 1; i < n; i <<= 1)
continue;
n = i;
}
sim_io_eprintf (sd, "rounding scache size up to %d\n", n);
}
if (cpu == NULL)
STATE_SCACHE_SIZE (sd) = n;
else
CPU_SCACHE_SIZE (cpu) = n;
}
else
{
if (cpu == NULL)
STATE_SCACHE_SIZE (sd) = SCACHE_DEFAULT_CACHE_SIZE;
else
CPU_SCACHE_SIZE (cpu) = SCACHE_DEFAULT_CACHE_SIZE;
}
}
else
sim_io_eprintf (sd, "Simulator execution cache not enabled, `--scache-size' ignored\n");
break;
case OPTION_PROFILE_SCACHE :
if (WITH_SCACHE && WITH_PROFILE_SCACHE_P)
{
/* FIXME: handle cpu != NULL. */
return sim_profile_set_option (sd, "-scache", PROFILE_SCACHE_IDX,
arg);
}
else
sim_io_eprintf (sd, "Simulator cache profiling not compiled in, `--profile-scache' ignored\n");
break;
}
return SIM_RC_OK;
}
SIM_RC
scache_install (SIM_DESC sd)
{
sim_add_option_table (sd, NULL, scache_options);
sim_module_add_init_fn (sd, scache_init);
sim_module_add_uninstall_fn (sd, scache_uninstall);
/* This is the default, it may be overridden on the command line. */
STATE_SCACHE_SIZE (sd) = WITH_SCACHE;
return SIM_RC_OK;
}
static SIM_RC
scache_init (SIM_DESC sd)
{
int c;
for (c = 0; c < MAX_NR_PROCESSORS; ++c)
{
SIM_CPU *cpu = STATE_CPU (sd, c);
int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu)));
/* elm_size is 0 if the cpu doesn't not have scache support */
if (elm_size == 0)
{
CPU_SCACHE_SIZE (cpu) = 0;
CPU_SCACHE_CACHE (cpu) = NULL;
}
else
{
if (CPU_SCACHE_SIZE (cpu) == 0)
CPU_SCACHE_SIZE (cpu) = STATE_SCACHE_SIZE (sd);
CPU_SCACHE_CACHE (cpu) =
(SCACHE *) xmalloc (CPU_SCACHE_SIZE (cpu) * elm_size);
#if WITH_SCACHE_PBB
CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) = MAX_CHAIN_LENGTH;
CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu) = MAX_HASH_CHAIN_LENGTH;
CPU_SCACHE_NUM_HASH_CHAINS (cpu) = MAX (MIN_HASH_CHAINS,
CPU_SCACHE_SIZE (cpu)
/ SCACHE_HASH_RATIO);
CPU_SCACHE_HASH_TABLE (cpu) =
(SCACHE_MAP *) xmalloc (CPU_SCACHE_NUM_HASH_CHAINS (cpu)
* CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu)
* sizeof (SCACHE_MAP));
CPU_SCACHE_PBB_BEGIN (cpu) = (SCACHE *) zalloc (elm_size);
CPU_SCACHE_CHAIN_LENGTHS (cpu) =
(unsigned long *) zalloc ((CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) + 1)
* sizeof (long));
#endif
}
}
scache_flush (sd);
return SIM_RC_OK;
}
static void
scache_uninstall (SIM_DESC sd)
{
int c;
for (c = 0; c < MAX_NR_PROCESSORS; ++c)
{
SIM_CPU *cpu = STATE_CPU (sd, c);
if (CPU_SCACHE_CACHE (cpu) != NULL)
free (CPU_SCACHE_CACHE (cpu));
#if WITH_SCACHE_PBB
if (CPU_SCACHE_HASH_TABLE (cpu) != NULL)
free (CPU_SCACHE_HASH_TABLE (cpu));
if (CPU_SCACHE_PBB_BEGIN (cpu) != NULL)
free (CPU_SCACHE_PBB_BEGIN (cpu));
if (CPU_SCACHE_CHAIN_LENGTHS (cpu) != NULL)
free (CPU_SCACHE_CHAIN_LENGTHS (cpu));
#endif
}
}
void
scache_flush (SIM_DESC sd)
{
int c;
for (c = 0; c < MAX_NR_PROCESSORS; ++c)
{
SIM_CPU *cpu = STATE_CPU (sd, c);
scache_flush_cpu (cpu);
}
}
void
scache_flush_cpu (SIM_CPU *cpu)
{
int i,n;
/* Don't bother if cache not in use. */
if (CPU_SCACHE_SIZE (cpu) == 0)
return;
#if WITH_SCACHE_PBB
/* It's important that this be reasonably fast as this can be done when
the simulation is running. */
CPU_SCACHE_NEXT_FREE (cpu) = CPU_SCACHE_CACHE (cpu);
n = CPU_SCACHE_NUM_HASH_CHAINS (cpu) * CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu);
/* ??? Might be faster to just set the first entry, then update the
"last entry" marker during allocation. */
for (i = 0; i < n; ++i)
CPU_SCACHE_HASH_TABLE (cpu) [i] . pc = UNUSED_ADDR;
#else
{
int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu)));
SCACHE *sc;
/* Technically, this may not be necessary, but it helps debugging. */
memset (CPU_SCACHE_CACHE (cpu), 0,
CPU_SCACHE_SIZE (cpu) * elm_size);
for (i = 0, sc = CPU_SCACHE_CACHE (cpu); i < CPU_SCACHE_SIZE (cpu);
++i, sc = (SCACHE *) ((char *) sc + elm_size))
{
sc->argbuf.addr = UNUSED_ADDR;
}
}
#endif
}
#if WITH_SCACHE_PBB
/* Look up PC in the hash table of scache entry points.
Returns the entry or NULL if not found. */
SCACHE *
scache_lookup (SIM_CPU *cpu, IADDR pc)
{
unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1);
int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu);
SCACHE_MAP *scm;
/* We don't update hit/miss statistics as this is only used when recording
branch target addresses. */
scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot];
for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm)
{
if (scm->pc == pc)
return scm->sc;
}
return 0;
}
/* Look up PC and if not found create an entry for it.
If found the result is a pointer to the SCACHE entry.
If not found the result is NULL, and the address of a buffer of at least
N entries is stored in BUFP.
It's done this way so the caller can still distinguish found/not-found.
If the table is full, it is emptied to make room.
If the maximum length of a hash list is reached a random entry is thrown out
to make room.
??? One might want to try to make this smarter, but let's see some
measurable benefit first. */
SCACHE *
scache_lookup_or_alloc (SIM_CPU *cpu, IADDR pc, int n, SCACHE **bufp)
{
unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1);
int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu);
SCACHE_MAP *scm;
SCACHE *sc;
scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot];
for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm)
{
if (scm->pc == pc)
{
PROFILE_COUNT_SCACHE_HIT (cpu);
return scm->sc;
}
}
PROFILE_COUNT_SCACHE_MISS (cpu);
/* The address we want isn't cached. Bummer.
If the hash chain we have for this address is full, throw out an entry
to make room. */
if (i == max_i)
{
/* Rather than do something sophisticated like LRU, we just throw out
a semi-random entry. Let someone else have the joy of saying how
wrong this is. NEXT_FREE is the entry to throw out and cycles
through all possibilities. */
static int next_free = 0;
scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot];
for (i = 0; i < next_free; ++i, ++scm)
continue;
++next_free;
if (next_free == CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu))
next_free = 0;
}
/* At this point SCM points to the hash table entry to use.
Now make sure there's room in the cache. */
{
int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu)));
int elms_used = (((char *) CPU_SCACHE_NEXT_FREE (cpu)
- (char *) CPU_SCACHE_CACHE (cpu))
/ elm_size);
int elms_left = CPU_SCACHE_SIZE (cpu) - elms_used;
if (elms_left < n)
{
PROFILE_COUNT_SCACHE_FULL_FLUSH (cpu);
scache_flush_cpu (cpu);
}
}
sc = CPU_SCACHE_NEXT_FREE (cpu);
scm->pc = pc;
scm->sc = sc;
*bufp = sc;
return NULL;
}
#endif /* WITH_SCACHE_PBB */
/* Print cache access statics for CPU. */
void
scache_print_profile (SIM_CPU *cpu, int verbose)
{
SIM_DESC sd = CPU_STATE (cpu);
unsigned long hits = CPU_SCACHE_HITS (cpu);
unsigned long misses = CPU_SCACHE_MISSES (cpu);
char buf[20];
unsigned long max_val;
unsigned long *lengths;
int i;
if (CPU_SCACHE_SIZE (cpu) == 0)
return;
sim_io_printf (sd, "Simulator Cache Statistics\n\n");
/* One could use PROFILE_LABEL_WIDTH here. I chose not to. */
sim_io_printf (sd, " Cache size: %s\n",
sim_add_commas (buf, sizeof (buf), CPU_SCACHE_SIZE (cpu)));
sim_io_printf (sd, " Hits: %s\n",
sim_add_commas (buf, sizeof (buf), hits));
sim_io_printf (sd, " Misses: %s\n",
sim_add_commas (buf, sizeof (buf), misses));
if (hits + misses != 0)
sim_io_printf (sd, " Hit rate: %.2f%%\n",
((double) hits / ((double) hits + (double) misses)) * 100);
#if WITH_SCACHE_PBB
sim_io_printf (sd, "\n");
sim_io_printf (sd, " Hash table size: %s\n",
sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAINS (cpu)));
sim_io_printf (sd, " Max hash list length: %s\n",
sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu)));
sim_io_printf (sd, " Max insn chain length: %s\n",
sim_add_commas (buf, sizeof (buf), CPU_SCACHE_MAX_CHAIN_LENGTH (cpu)));
sim_io_printf (sd, " Cache full flushes: %s\n",
sim_add_commas (buf, sizeof (buf), CPU_SCACHE_FULL_FLUSHES (cpu)));
sim_io_printf (sd, "\n");
if (verbose)
{
sim_io_printf (sd, " Insn chain lengths:\n\n");
max_val = 0;
lengths = CPU_SCACHE_CHAIN_LENGTHS (cpu);
for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i)
if (lengths[i] > max_val)
max_val = lengths[i];
for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i)
{
sim_io_printf (sd, " %2d: %*s: ",
i,
max_val < 10000 ? 5 : 10,
sim_add_commas (buf, sizeof (buf), lengths[i]));
sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
lengths[i], max_val);
sim_io_printf (sd, "\n");
}
sim_io_printf (sd, "\n");
}
#endif /* WITH_SCACHE_PBB */
}

162
sim/common/cgen-scache.h Normal file
View File

@@ -0,0 +1,162 @@
/* Simulator header for cgen scache support.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef CGEN_SCACHE_H
#define CGEN_SCACHE_H
#ifndef WITH_SCACHE
#define WITH_SCACHE 0
#endif
/* When caching bb's, instructions are extracted into "chains".
SCACHE_MAP is a hash table into these chains. */
typedef struct {
IADDR pc;
SCACHE *sc;
} SCACHE_MAP;
typedef struct cpu_scache {
/* Simulator cache size. Must be a power of 2.
This is the number of elements in the `cache' member. */
unsigned int size;
#define CPU_SCACHE_SIZE(cpu) ((cpu) -> cgen_cpu.scache.size)
/* The cache. */
SCACHE *cache;
#define CPU_SCACHE_CACHE(cpu) ((cpu) -> cgen_cpu.scache.cache)
#if WITH_SCACHE_PBB
/* Number of hash chains. Must be a power of 2. */
unsigned int num_hash_chains;
#define CPU_SCACHE_NUM_HASH_CHAINS(cpu) ((cpu) -> cgen_cpu.scache.num_hash_chains)
/* Number of entries in each hash chain.
The hash table is a statically allocated NxM array where
N = num_hash_chains
M = num_hash_chain_entries. */
unsigned int num_hash_chain_entries;
#define CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES(cpu) ((cpu) -> cgen_cpu.scache.num_hash_chain_entries)
/* Maximum number of instructions in a chain.
??? This just let's us set a static size of chain_lengths table.
In a simulation that handles more than just the cpu, this might also be
used to keep too many instructions from being executed before checking
for events (or some such). */
unsigned int max_chain_length;
#define CPU_SCACHE_MAX_CHAIN_LENGTH(cpu) ((cpu) -> cgen_cpu.scache.max_chain_length)
/* Special scache entry for (re)starting bb extraction. */
SCACHE *pbb_begin;
#define CPU_SCACHE_PBB_BEGIN(cpu) ((cpu) -> cgen_cpu.scache.pbb_begin)
/* Hash table into cached chains. */
SCACHE_MAP *hash_table;
#define CPU_SCACHE_HASH_TABLE(cpu) ((cpu) -> cgen_cpu.scache.hash_table)
/* Next free entry in cache. */
SCACHE *next_free;
#define CPU_SCACHE_NEXT_FREE(cpu) ((cpu) -> cgen_cpu.scache.next_free)
/* Address of cti-chain insn, only used by functional semantics,
not switch form. */
SCACHE **pbb_br_npc_ptr;
#define CPU_PBB_BR_NPC_PTR(cpu) ((cpu) -> cgen_cpu.scache.pbb_br_npc_ptr)
/* Target's branch address. */
IADDR pbb_br_npc;
#define CPU_PBB_BR_NPC(cpu) ((cpu) -> cgen_cpu.scache.pbb_br_npc)
#endif /* WITH_SCACHE_PBB */
#if WITH_PROFILE_SCACHE_P
/* Cache hits, misses. */
unsigned long hits, misses;
#define CPU_SCACHE_HITS(cpu) ((cpu) -> cgen_cpu.scache.hits)
#define CPU_SCACHE_MISSES(cpu) ((cpu) -> cgen_cpu.scache.misses)
#if WITH_SCACHE_PBB
/* Chain length counts.
Each element is a count of the number of chains created with that
length. */
unsigned long *chain_lengths;
#define CPU_SCACHE_CHAIN_LENGTHS(cpu) ((cpu) -> cgen_cpu.scache.chain_lengths)
/* Number of times cache was flushed due to its being full. */
unsigned long full_flushes;
#define CPU_SCACHE_FULL_FLUSHES(cpu) ((cpu) -> cgen_cpu.scache.full_flushes)
#endif
#endif
} CPU_SCACHE;
/* Hash a PC value.
This is split into two parts to help with moving as much of the
computation out of the main loop. */
#define CPU_SCACHE_HASH_MASK(cpu) (CPU_SCACHE_SIZE (cpu) - 1)
#define SCACHE_HASH_PC(pc, mask) \
((CGEN_MIN_INSN_SIZE == 2 ? ((pc) >> 1) \
: CGEN_MIN_INSN_SIZE == 4 ? ((pc) >> 2) \
: (pc)) \
& (mask))
/* Non-zero if cache is in use. */
#define USING_SCACHE_P(sd) (STATE_SCACHE_SIZE (sd) > 0)
/* Install the simulator cache into the simulator. */
MODULE_INSTALL_FN scache_install;
/* Lookup a PC value in the scache [compilation only]. */
extern SCACHE * scache_lookup (SIM_CPU *, IADDR);
/* Return a pointer to at least N buffers. */
extern SCACHE *scache_lookup_or_alloc (SIM_CPU *, IADDR, int, SCACHE **);
/* Flush all cpu's scaches. */
extern void scache_flush (SIM_DESC);
/* Flush a cpu's scache. */
extern void scache_flush_cpu (SIM_CPU *);
/* Scache profiling support. */
/* Print summary scache usage information. */
extern void scache_print_profile (SIM_CPU *cpu, int verbose);
#if WITH_PROFILE_SCACHE_P
#define PROFILE_COUNT_SCACHE_HIT(cpu) \
do { \
if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
++ CPU_SCACHE_HITS (cpu); \
} while (0)
#define PROFILE_COUNT_SCACHE_MISS(cpu) \
do { \
if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
++ CPU_SCACHE_MISSES (cpu); \
} while (0)
#define PROFILE_COUNT_SCACHE_CHAIN_LENGTH(cpu,length) \
do { \
if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
++ CPU_SCACHE_CHAIN_LENGTHS (cpu) [length]; \
} while (0)
#define PROFILE_COUNT_SCACHE_FULL_FLUSH(cpu) \
do { \
if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \
++ CPU_SCACHE_FULL_FLUSHES (cpu); \
} while (0)
#else
#define PROFILE_COUNT_SCACHE_HIT(cpu)
#define PROFILE_COUNT_SCACHE_MISS(cpu)
#define PROFILE_COUNT_SCACHE_CHAIN_LENGTH(cpu,length)
#define PROFILE_COUNT_SCACHE_FULL_FLUSH(cpu)
#endif
#endif /* CGEN_SCACHE_H */

34
sim/common/cgen-sim.h Normal file
View File

@@ -0,0 +1,34 @@
/* Main header file for Cpu tools GENerated simulators.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file must be included after sim-base.h. */
#ifndef CGEN_SIM_H
#define CGEN_SIM_H
#include "cgen-defs.h"
#include "cgen-scache.h"
#include "cgen-cpu.h"
#include "cgen-trace.h"
/* This is a machine generated file. */
#include "cpuall.h"
#endif /* CGEN_SIM_H */

414
sim/common/cgen-trace.c Normal file
View File

@@ -0,0 +1,414 @@
/* Tracing support for CGEN-based simulators.
Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <errno.h>
#include "dis-asm.h"
#include "bfd.h"
#include "sim-main.h"
#undef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#ifndef SIZE_INSTRUCTION
#define SIZE_INSTRUCTION 16
#endif
#ifndef SIZE_LOCATION
#define SIZE_LOCATION 20
#endif
#ifndef SIZE_PC
#define SIZE_PC 6
#endif
#ifndef SIZE_LINE_NUMBER
#define SIZE_LINE_NUMBER 4
#endif
#ifndef SIZE_CYCLE_COUNT
#define SIZE_CYCLE_COUNT 2
#endif
#ifndef SIZE_TOTAL_CYCLE_COUNT
#define SIZE_TOTAL_CYCLE_COUNT 9
#endif
#ifndef SIZE_TRACE_BUF
#define SIZE_TRACE_BUF 256
#endif
static void
disassemble_insn (SIM_CPU *, const CGEN_INSN *,
const struct argbuf *, IADDR, char *);
/* Text is queued in TRACE_BUF because we want to output the insn's cycle
count first but that isn't known until after the insn has executed.
This also handles the queueing of trace results, TRACE_RESULT may be
called multiple times for one insn. */
static char trace_buf[SIZE_TRACE_BUF];
/* If NULL, output to stdout directly. */
static char *bufptr;
/* Non-zero if this is the first insn in a set of parallel insns. */
static int first_insn_p;
/* For communication between trace_insn and trace_result. */
static int printed_result_p;
/* Insn and its extracted fields.
Set by trace_insn, used by trace_insn_fini.
??? Move to SIM_CPU to support heterogeneous multi-cpu case. */
static const struct cgen_insn *current_insn;
static const struct argbuf *current_abuf;
void
trace_insn_init (SIM_CPU *cpu, int first_p)
{
bufptr = trace_buf;
*bufptr = 0;
first_insn_p = first_p;
/* Set to NULL so trace_insn_fini can know if trace_insn was called. */
current_insn = NULL;
current_abuf = NULL;
}
void
trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p)
{
SIM_DESC sd = CPU_STATE (cpu);
/* Was insn traced? It might not be if trace ranges are in effect. */
if (current_insn == NULL)
return;
/* The first thing printed is current and total cycle counts. */
if (PROFILE_MODEL_P (cpu)
&& ARGBUF_PROFILE_P (current_abuf))
{
unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu));
unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu));
if (last_p)
{
trace_printf (sd, cpu, "%-*ld %-*ld ",
SIZE_CYCLE_COUNT, this_insn,
SIZE_TOTAL_CYCLE_COUNT, total);
}
else
{
trace_printf (sd, cpu, "%-*ld %-*s ",
SIZE_CYCLE_COUNT, this_insn,
SIZE_TOTAL_CYCLE_COUNT, "---");
}
}
/* Print the disassembled insn. */
trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu)));
#if 0
/* Print insn results. */
{
const CGEN_OPINST *opinst = CGEN_INSN_OPERANDS (current_insn);
if (opinst)
{
int i;
int indices[MAX_OPERAND_INSTANCES];
/* Fetch the operands used by the insn. */
/* FIXME: Add fn ptr to CGEN_CPU_DESC. */
CGEN_SYM (get_insn_operands) (CPU_CPU_DESC (cpu), current_insn,
0, CGEN_FIELDS_BITSIZE (&insn_fields),
indices);
for (i = 0;
CGEN_OPINST_TYPE (opinst) != CGEN_OPINST_END;
++i, ++opinst)
{
if (CGEN_OPINST_TYPE (opinst) == CGEN_OPINST_OUTPUT)
trace_result (cpu, current_insn, opinst, indices[i]);
}
}
}
#endif
/* Print anything else requested. */
if (*trace_buf)
trace_printf (sd, cpu, " %s\n", trace_buf);
else
trace_printf (sd, cpu, "\n");
}
void
trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode,
const struct argbuf *abuf, IADDR pc)
{
char disasm_buf[50];
printed_result_p = 0;
current_insn = opcode;
current_abuf = abuf;
if (CGEN_INSN_VIRTUAL_P (opcode))
{
trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, 0,
NULL, 0, CGEN_INSN_NAME (opcode));
return;
}
CPU_DISASSEMBLER (cpu) (cpu, opcode, abuf, pc, disasm_buf);
trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
NULL, 0,
"%s%-*s",
first_insn_p ? " " : "|",
SIZE_INSTRUCTION, disasm_buf);
}
void
trace_extract (SIM_CPU *cpu, IADDR pc, char *name, ...)
{
va_list args;
int printed_one_p = 0;
char *fmt;
va_start (args, name);
trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ",
SIZE_PC, pc, name);
do {
int type,ival;
fmt = va_arg (args, char *);
if (fmt)
{
if (printed_one_p)
trace_printf (CPU_STATE (cpu), cpu, ", ");
printed_one_p = 1;
type = va_arg (args, int);
switch (type)
{
case 'x' :
ival = va_arg (args, int);
trace_printf (CPU_STATE (cpu), cpu, fmt, ival);
break;
default :
abort ();
}
}
} while (fmt);
va_end (args);
trace_printf (CPU_STATE (cpu), cpu, "\n");
}
void
trace_result (SIM_CPU *cpu, char *name, int type, ...)
{
va_list args;
va_start (args, type);
if (printed_result_p)
cgen_trace_printf (cpu, ", ");
switch (type)
{
case 'x' :
default :
cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int));
break;
case 'D' :
{
DI di;
/* this is separated from previous line for sunos cc */
di = va_arg (args, DI);
cgen_trace_printf (cpu, "%s <- 0x%x%08x", name,
GETHIDI(di), GETLODI (di));
break;
}
}
printed_result_p = 1;
va_end (args);
}
/* Print trace output to BUFPTR if active, otherwise print normally.
This is only for tracing semantic code. */
void
cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...)
{
va_list args;
va_start (args, fmt);
if (bufptr == NULL)
{
if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL)
(* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered)
(STATE_CALLBACK (CPU_STATE (cpu)), fmt, args);
else
vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args);
}
else
{
vsprintf (bufptr, fmt, args);
bufptr += strlen (bufptr);
/* ??? Need version of SIM_ASSERT that is always enabled. */
if (bufptr - trace_buf > SIZE_TRACE_BUF)
abort ();
}
va_end (args);
}
/* Disassembly support. */
/* sprintf to a "stream" */
int
sim_disasm_sprintf VPARAMS ((SFILE *f, const char *format, ...))
{
#ifndef __STDC__
SFILE *f;
const char *format;
#endif
int n;
va_list args;
VA_START (args, format);
#ifndef __STDC__
f = va_arg (args, SFILE *);
format = va_arg (args, char *);
#endif
vsprintf (f->current, format, args);
f->current += n = strlen (f->current);
va_end (args);
return n;
}
/* Memory read support for an opcodes disassembler. */
int
sim_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info)
{
SIM_CPU *cpu = (SIM_CPU *) info->application_data;
SIM_DESC sd = CPU_STATE (cpu);
int length_read;
length_read = sim_core_read_buffer (sd, cpu, read_map, myaddr, memaddr,
length);
if (length_read != length)
return EIO;
return 0;
}
/* Memory error support for an opcodes disassembler. */
void
sim_disasm_perror_memory (int status, bfd_vma memaddr,
struct disassemble_info *info)
{
if (status != EIO)
/* Can't happen. */
info->fprintf_func (info->stream, "Unknown error %d.", status);
else
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
info->fprintf_func (info->stream,
"Address 0x%x is out of bounds.",
(int) memaddr);
}
/* Disassemble using the CGEN opcode table.
??? While executing an instruction, the insn has been decoded and all its
fields have been extracted. It is certainly possible to do the disassembly
with that data. This seems simpler, but maybe in the future the already
extracted fields will be used. */
void
sim_cgen_disassemble_insn (SIM_CPU *cpu, const CGEN_INSN *insn,
const ARGBUF *abuf, IADDR pc, char *buf)
{
unsigned int length;
unsigned long insn_value;
struct disassemble_info disasm_info;
SFILE sfile;
union {
unsigned8 bytes[CGEN_MAX_INSN_SIZE];
unsigned16 shorts[8];
unsigned32 words[4];
} insn_buf;
SIM_DESC sd = CPU_STATE (cpu);
CGEN_CPU_DESC cd = CPU_CPU_DESC (cpu);
CGEN_EXTRACT_INFO ex_info;
CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
int insn_bit_length = CGEN_INSN_BITSIZE (insn);
int insn_length = insn_bit_length / 8;
sfile.buffer = sfile.current = buf;
INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile,
(fprintf_ftype) sim_disasm_sprintf);
disasm_info.endian =
(bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG
: bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE
: BFD_ENDIAN_UNKNOWN);
length = sim_core_read_buffer (sd, cpu, read_map, &insn_buf, pc,
insn_length);
switch (min (CGEN_BASE_INSN_SIZE, insn_length))
{
case 0 : return; /* fake insn, typically "compile" (aka "invalid") */
case 1 : insn_value = insn_buf.bytes[0]; break;
case 2 : insn_value = T2H_2 (insn_buf.shorts[0]); break;
case 4 : insn_value = T2H_4 (insn_buf.words[0]); break;
default: abort ();
}
disasm_info.buffer_vma = pc;
disasm_info.buffer = insn_buf.bytes;
disasm_info.buffer_length = length;
ex_info.dis_info = (PTR) &disasm_info;
ex_info.valid = (1 << length) - 1;
ex_info.insn_bytes = insn_buf.bytes;
length = (*CGEN_EXTRACT_FN (cd, insn)) (cd, insn, &ex_info, insn_value, fields, pc);
/* Result of extract fn is in bits. */
/* ??? This assumes that each instruction has a fixed length (and thus
for insns with multiple versions of variable lengths they would each
have their own table entry). */
if (length == insn_bit_length)
{
(*CGEN_PRINT_FN (cd, insn)) (cd, &disasm_info, insn, fields, pc, length);
}
else
{
/* This shouldn't happen, but aborting is too drastic. */
strcpy (buf, "***unknown***");
}
}

91
sim/common/cgen-trace.h Normal file
View File

@@ -0,0 +1,91 @@
/* Simulator tracing support for Cpu tools GENerated simulators.
Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef CGEN_TRACE_H
#define CGEN_TRACE_H
void trace_insn_init (SIM_CPU *, int);
void trace_insn_fini (SIM_CPU *, const struct argbuf *, int);
void trace_insn (SIM_CPU *, const struct cgen_insn *,
const struct argbuf *, IADDR);
void trace_extract (SIM_CPU *, IADDR, char *, ...);
void trace_result (SIM_CPU *, char *, int, ...);
void cgen_trace_printf (SIM_CPU *, char *fmt, ...);
/* Trace instruction results. */
#define TRACE_RESULT_P(cpu, abuf) (TRACE_INSN_P (cpu) && ARGBUF_TRACE_P (abuf))
#define TRACE_INSN_INIT(cpu, abuf, first_p) \
do { \
if (TRACE_INSN_P (cpu)) \
trace_insn_init ((cpu), (first_p)); \
} while (0)
#define TRACE_INSN_FINI(cpu, abuf, last_p) \
do { \
if (TRACE_INSN_P (cpu)) \
trace_insn_fini ((cpu), (abuf), (last_p)); \
} while (0)
#define TRACE_PRINTF(cpu, what, args) \
do { \
if (TRACE_P ((cpu), (what))) \
cgen_trace_printf args ; \
} while (0)
#define TRACE_INSN(cpu, insn, abuf, pc) \
do { \
if (TRACE_INSN_P (cpu) && ARGBUF_TRACE_P (abuf)) \
trace_insn ((cpu), (insn), (abuf), (pc)) ; \
} while (0)
#define TRACE_EXTRACT(cpu, abuf, args) \
do { \
if (TRACE_EXTRACT_P (cpu)) \
trace_extract args ; \
} while (0)
#define TRACE_RESULT(cpu, abuf, name, type, val) \
do { \
if (TRACE_RESULT_P ((cpu), (abuf))) \
trace_result ((cpu), (name), (type), (val)) ; \
} while (0)
/* Disassembly support. */
/* Function to use for cgen-based disassemblers. */
extern CGEN_DISASSEMBLER sim_cgen_disassemble_insn;
/* Pseudo FILE object for strings. */
typedef struct {
char *buffer;
char *current;
} SFILE;
/* String printer for the disassembler. */
extern int sim_disasm_sprintf (SFILE *, const char *, ...);
/* For opcodes based disassemblers. */
#ifdef BFD_VERSION
struct disassemble_info;
extern int
sim_disasm_read_memory (bfd_vma memaddr_, bfd_byte *myaddr_, int length_,
struct disassemble_info *info_);
extern void
sim_disasm_perror_memory (int status_, bfd_vma memaddr_,
struct disassemble_info *info_);
#endif
#endif /* CGEN_TRACE_H */

116
sim/common/cgen-types.h Normal file
View File

@@ -0,0 +1,116 @@
/* Types for Cpu tools GENerated simulators.
Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file is not included with cgen-sim.h as it defines types
needed by sim-base.h. */
#ifndef CGEN_TYPES_H
#define CGEN_TYPES_H
/* Miscellaneous cgen configury defined here as this file gets
included soon enough. */
/* Indicate we support --profile-model. */
#undef SIM_HAVE_MODEL
#define SIM_HAVE_MODEL
/* Indicate we support --{profile,trace}-{range,function}. */
#undef SIM_HAVE_ADDR_RANGE
#define SIM_HAVE_ADDR_RANGE
#ifdef __GNUC__
#define HAVE_LONGLONG
#undef DI_FN_SUPPORT
#else
#undef HAVE_LONGLONG
#define DI_FN_SUPPORT
#endif
/* Mode support. */
/* Common mode types. */
/* ??? Target specific modes. */
typedef enum mode_type {
MODE_VM, MODE_BI,
MODE_QI, MODE_HI, MODE_SI, MODE_DI,
MODE_UQI, MODE_UHI, MODE_USI, MODE_UDI,
MODE_SF, MODE_DF, MODE_XF, MODE_TF,
MODE_TARGET_MAX /* = MODE_TF? */,
/* These are host modes. */
MODE_INT, MODE_UINT, MODE_PTR, /*??? MODE_ADDR, MODE_IADDR,*/
MODE_MAX
} MODE_TYPE;
#define MAX_TARGET_MODES ((int) MODE_TARGET_MAX)
#define MAX_MODES ((int) MODE_MAX)
extern const char *mode_names[];
#define MODE_NAME(m) (mode_names[m])
typedef unsigned char BI;
typedef signed8 QI;
typedef signed16 HI;
typedef signed32 SI;
typedef unsigned8 UQI;
typedef unsigned16 UHI;
typedef unsigned32 USI;
#ifdef HAVE_LONGLONG
typedef signed64 DI;
typedef unsigned64 UDI;
#define GETLODI(di) ((SI) (di))
#define GETHIDI(di) ((SI) ((UDI) (di) >> 32))
#define SETLODI(di, val) ((di) = (((di) & 0xffffffff00000000LL) | (val)))
#define SETHIDI(di, val) ((di) = (((di) & 0xffffffffLL) | (((DI) (val)) << 32)))
#define SETDI(di, hi, lo) ((di) = MAKEDI (hi, lo))
#define MAKEDI(hi, lo) ((((DI) (SI) (hi)) << 32) | ((UDI) (USI) (lo)))
#else
/* DI mode support if "long long" doesn't exist.
At one point CGEN supported K&R C compilers, and ANSI C compilers without
"long long". One can argue the various merits of keeping this in or
throwing it out. I went to the trouble of adding it so for the time being
I'm leaving it in. */
typedef struct { SI hi,lo; } DI;
typedef DI UDI;
#define GETLODI(di) ((di).lo)
#define GETHIDI(di) ((di).hi)
#define SETLODI(di, val) ((di).lo = (val))
#define SETHIDI(di, val) ((di).hi = (val))
#define SETDI(di, hi, lo) ((di) = MAKEDI (hi, lo))
extern DI make_struct_di (SI, SI);
#define MAKEDI(hi, lo) (make_struct_di ((hi), (lo)))
#endif
/* FIXME: Need to provide libraries if these aren't appropriate for target,
or user's needs. */
typedef float SF;
typedef double DF;
typedef double XF; /* FIXME: configure, provide library */
typedef double TF; /* FIXME: configure, provide library */
/* These are used to record extracted raw data from an instruction, among other
things. It must be a host data type, and not a target one. */
typedef int INT;
typedef unsigned int UINT;
typedef unsigned_address ADDR; /* FIXME: wip*/
typedef unsigned_address IADDR; /* FIXME: wip*/
#endif /* CGEN_TYPES_H */

328
sim/common/cgen-utils.c Normal file
View File

@@ -0,0 +1,328 @@
/* Support code for various pieces of CGEN simulators.
Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sim-main.h"
#include "dis-asm.h"
#define MEMOPS_DEFINE_INLINE
#include "cgen-mem.h"
#define SEMOPS_DEFINE_INLINE
#include "cgen-ops.h"
#undef min
#define min(a,b) ((a) < (b) ? (a) : (b))
const char *mode_names[] = {
"VM",
"BI",
"QI",
"HI",
"SI",
"DI",
"UQI",
"UHI",
"USI",
"UDI",
"SF",
"DF",
"XF",
"TF",
0, /* MODE_TARGET_MAX */
"INT",
"UINT",
"PTR"
};
/* Opcode table for virtual insns used by the simulator. */
#define V CGEN_ATTR_MASK (CGEN_INSN_VIRTUAL)
static const CGEN_IBASE virtual_insn_entries[] =
{
{
VIRTUAL_INSN_X_INVALID, "--invalid--", NULL, 0,
{ CGEN_INSN_NBOOL_ATTRS, V, { 0 } }
},
{
VIRTUAL_INSN_X_BEFORE, "--before--", NULL, 0,
{ CGEN_INSN_NBOOL_ATTRS, V, { 0 } }
},
{
VIRTUAL_INSN_X_AFTER, "--after--", NULL, 0,
{ CGEN_INSN_NBOOL_ATTRS, V, { 0 } }
},
{
VIRTUAL_INSN_X_BEGIN, "--begin--", NULL, 0,
{ CGEN_INSN_NBOOL_ATTRS, V, { 0 } }
},
{
VIRTUAL_INSN_X_CHAIN, "--chain--", NULL, 0,
{ CGEN_INSN_NBOOL_ATTRS, V, { 0 } }
},
{
VIRTUAL_INSN_X_CTI_CHAIN, "--cti-chain--", NULL, 0,
{ CGEN_INSN_NBOOL_ATTRS, V, { 0 } }
}
};
#undef V
const CGEN_INSN cgen_virtual_insn_table[] =
{
{ & virtual_insn_entries[0] },
{ & virtual_insn_entries[1] },
{ & virtual_insn_entries[2] },
{ & virtual_insn_entries[3] },
{ & virtual_insn_entries[4] },
{ & virtual_insn_entries[5] }
};
/* Initialize cgen things.
This is called after sim_post_argv_init. */
void
cgen_init (SIM_DESC sd)
{
int i, c;
/* If no profiling or tracing has been enabled, run in fast mode. */
{
int run_fast_p = 1;
for (c = 0; c < MAX_NR_PROCESSORS; ++c)
{
SIM_CPU *cpu = STATE_CPU (sd, c);
for (i = 0; i < MAX_PROFILE_VALUES; ++i)
if (CPU_PROFILE_FLAGS (cpu) [i])
{
run_fast_p = 0;
break;
}
for (i = 0; i < MAX_TRACE_VALUES; ++i)
if (CPU_TRACE_FLAGS (cpu) [i])
{
run_fast_p = 0;
break;
}
if (! run_fast_p)
break;
}
STATE_RUN_FAST_P (sd) = run_fast_p;
}
}
/* Return the name of insn number I. */
const char *
cgen_insn_name (SIM_CPU *cpu, int i)
{
return CGEN_INSN_NAME ((* CPU_GET_IDATA (cpu)) ((cpu), (i)));
}
/* Return the maximum number of extra bytes required for a SIM_CPU struct. */
int
cgen_cpu_max_extra_bytes (void)
{
int i;
int extra = 0;
for (i = 0; sim_machs[i] != 0; ++i)
{
int size = IMP_PROPS_SIM_CPU_SIZE (MACH_IMP_PROPS (sim_machs[i]));
if (size > extra)
extra = size;
}
return extra;
}
#ifdef DI_FN_SUPPORT
DI
make_struct_di (hi, lo)
SI hi, lo;
{
DI result;
result.hi = hi;
result.lo = lo;
return result;
}
DI
ANDDI (a, b)
DI a, b;
{
SI ahi = GETHIDI (a);
SI alo = GETLODI (a);
SI bhi = GETHIDI (b);
SI blo = GETLODI (b);
return MAKEDI (ahi & bhi, alo & blo);
}
DI
ORDI (a, b)
DI a, b;
{
SI ahi = GETHIDI (a);
SI alo = GETLODI (a);
SI bhi = GETHIDI (b);
SI blo = GETLODI (b);
return MAKEDI (ahi | bhi, alo | blo);
}
DI
ADDDI (a, b)
DI a, b;
{
USI ahi = GETHIDI (a);
USI alo = GETLODI (a);
USI bhi = GETHIDI (b);
USI blo = GETLODI (b);
USI x = alo + blo;
return MAKEDI (ahi + bhi + (x < alo), x);
}
DI
MULDI (a, b)
DI a, b;
{
USI ahi = GETHIDI (a);
USI alo = GETLODI (a);
USI bhi = GETHIDI (b);
USI blo = GETLODI (b);
USI rhi,rlo;
USI x0, x1, x2, x3;
x0 = alo * blo;
x1 = alo * bhi;
x2 = ahi * blo;
x3 = ahi * bhi;
#define SI_TYPE_SIZE 32
#define BITS4 (SI_TYPE_SIZE / 4)
#define ll_B (1L << (SI_TYPE_SIZE / 2))
#define ll_lowpart(t) ((USI) (t) % ll_B)
#define ll_highpart(t) ((USI) (t) / ll_B)
x1 += ll_highpart (x0); /* this can't give carry */
x1 += x2; /* but this indeed can */
if (x1 < x2) /* did we get it? */
x3 += ll_B; /* yes, add it in the proper pos. */
rhi = x3 + ll_highpart (x1);
rlo = ll_lowpart (x1) * ll_B + ll_lowpart (x0);
return MAKEDI (rhi + (alo * bhi) + (ahi * blo), rlo);
}
DI
SHLDI (val, shift)
DI val;
SI shift;
{
USI hi = GETHIDI (val);
USI lo = GETLODI (val);
/* FIXME: Need to worry about shift < 0 || shift >= 32. */
return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift);
}
DI
SLADI (val, shift)
DI val;
SI shift;
{
SI hi = GETHIDI (val);
USI lo = GETLODI (val);
/* FIXME: Need to worry about shift < 0 || shift >= 32. */
return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift);
}
DI
SRADI (val, shift)
DI val;
SI shift;
{
SI hi = GETHIDI (val);
USI lo = GETLODI (val);
/* We use SRASI because the result is implementation defined if hi < 0. */
/* FIXME: Need to worry about shift < 0 || shift >= 32. */
return MAKEDI (SRASI (hi, shift), (hi << (32 - shift)) | (lo >> shift));
}
int
GEDI (a, b)
DI a, b;
{
SI ahi = GETHIDI (a);
USI alo = GETLODI (a);
SI bhi = GETHIDI (b);
USI blo = GETLODI (b);
if (ahi > bhi)
return 1;
if (ahi == bhi)
return alo >= blo;
return 0;
}
int
LEDI (a, b)
DI a, b;
{
SI ahi = GETHIDI (a);
USI alo = GETLODI (a);
SI bhi = GETHIDI (b);
USI blo = GETLODI (b);
if (ahi < bhi)
return 1;
if (ahi == bhi)
return alo <= blo;
return 0;
}
DI
CONVHIDI (val)
HI val;
{
if (val < 0)
return MAKEDI (-1, val);
else
return MAKEDI (0, val);
}
DI
CONVSIDI (val)
SI val;
{
if (val < 0)
return MAKEDI (-1, val);
else
return MAKEDI (0, val);
}
SI
CONVDISI (val)
DI val;
{
return GETLODI (val);
}
#endif /* DI_FN_SUPPORT */

167
sim/common/config.in Normal file
View File

@@ -0,0 +1,167 @@
/* config.in. Generated automatically from configure.in by autoheader. */
/* Define if using alloca.c. */
#undef C_ALLOCA
/* Define to empty if the keyword does not work. */
#undef const
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
This function is required for alloca.c support on those systems. */
#undef CRAY_STACKSEG_END
/* Define if you have alloca, as a function or macro. */
#undef HAVE_ALLOCA
/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
#undef HAVE_ALLOCA_H
/* Define if you have a working `mmap' system call. */
#undef HAVE_MMAP
/* Define as __inline if that's what the C compiler calls it. */
#undef inline
/* Define to `long' if <sys/types.h> doesn't define. */
#undef off_t
/* Define if you need to in order for stat and other things to work. */
#undef _POSIX_SOURCE
/* Define as the return type of signal handlers (int or void). */
#undef RETSIGTYPE
/* Define to `unsigned' if <sys/types.h> doesn't define. */
#undef size_t
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown
*/
#undef STACK_DIRECTION
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if NLS is requested. */
#undef ENABLE_NLS
/* 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
/* Define if you have the __argz_count function. */
#undef HAVE___ARGZ_COUNT
/* Define if you have the __argz_next function. */
#undef HAVE___ARGZ_NEXT
/* Define if you have the __argz_stringify function. */
#undef HAVE___ARGZ_STRINGIFY
/* Define if you have the __setfpucw function. */
#undef HAVE___SETFPUCW
/* Define if you have the dcgettext function. */
#undef HAVE_DCGETTEXT
/* Define if you have the getcwd function. */
#undef HAVE_GETCWD
/* Define if you have the getpagesize function. */
#undef HAVE_GETPAGESIZE
/* Define if you have the getrusage function. */
#undef HAVE_GETRUSAGE
/* Define if you have the munmap function. */
#undef HAVE_MUNMAP
/* Define if you have the putenv function. */
#undef HAVE_PUTENV
/* Define if you have the setenv function. */
#undef HAVE_SETENV
/* Define if you have the setlocale function. */
#undef HAVE_SETLOCALE
/* Define if you have the sigaction function. */
#undef HAVE_SIGACTION
/* Define if you have the stpcpy function. */
#undef HAVE_STPCPY
/* Define if you have the strcasecmp function. */
#undef HAVE_STRCASECMP
/* Define if you have the strchr function. */
#undef HAVE_STRCHR
/* Define if you have the time function. */
#undef HAVE_TIME
/* Define if you have the <argz.h> header file. */
#undef HAVE_ARGZ_H
/* Define if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
/* Define if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define if you have the <fpu_control.h> header file. */
#undef HAVE_FPU_CONTROL_H
/* Define if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
/* Define if you have the <malloc.h> header file. */
#undef HAVE_MALLOC_H
/* Define if you have the <nl_types.h> header file. */
#undef HAVE_NL_TYPES_H
/* 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 <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define if you have the <sys/times.h> header file. */
#undef HAVE_SYS_TIMES_H
/* Define if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if you have the <values.h> header file. */
#undef HAVE_VALUES_H

3902
sim/common/configure vendored Executable file

File diff suppressed because it is too large Load Diff

40
sim/common/configure.in Normal file
View File

@@ -0,0 +1,40 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.5)dnl
AC_INIT(Makefile.in)
# This is intended for use by the target specific directories, and by us.
SIM_AC_COMMON(cconfig.h)
# Put a useful copy of CPP_FOR_TARGET in Makefile.
# This is only used to build the target values header files. These files are
# shipped with distributions so CPP_FOR_TARGET only needs to work in
# developer's trees. This value is borrowed from ../../Makefile.in.
CPP_FOR_TARGET="\` \
if test -f \$\${rootme}/../../gcc/Makefile ; then \
if test -f \$\${rootme}/../../\$(TARGET_SUBDIR)/newlib/Makefile ; then \
echo \$\${rootme}/../../gcc/xgcc -B\$\${rootme}/../../gcc/ -idirafter \$\${rootme}/../../\$(TARGET_SUBDIR)/newlib/targ-include -idirafter \$(srcroot)/newlib/libc/include -nostdinc; \
else \
echo \$\${rootme}/../../gcc/xgcc -B\$\${rootme}/../../gcc/; \
fi; \
else \
if test '\$(host_canonical)' = '\$(target_canonical)' ; then \
echo \$(CC); \
else \
t='\$(program_transform_name)'; echo gcc | sed -e 's/x/x/' \$\$t; \
fi; \
fi\` -E"
AC_SUBST(CPP_FOR_TARGET)
# Set TARGET_SUBDIR, needed by CPP_FOR_TARGET.
if test x"${host}" = x"${target}" ; then
TARGET_SUBDIR="."
else
TARGET_SUBDIR=${target_alias}
fi
AC_SUBST(TARGET_SUBDIR)
# These aren't all needed yet, but will be eventually.
AC_CHECK_HEADERS(stdlib.h string.h strings.h time.h sys/times.h)
AC_OUTPUT(Makefile,
[case x$CONFIG_HEADERS in xcconfig.h:config.in) echo > stamp-h ;; esac])

118
sim/common/dv-core.c Normal file
View File

@@ -0,0 +1,118 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sim-main.h"
#include "hw-main.h"
/* DEVICE
core - root of the device tree
DESCRIPTION
The core device, positioned at the root of the device tree appears
to its child devices as a normal device just like every other
device in the tree.
Internally it is implemented using a core object. Requests to
attach (or detach) address spaces are passed to that core object.
Requests to transfer (DMA) data are reflected back down the device
tree using the core_map data transfer methods.
PROPERTIES
None.
*/
static void
dv_core_attach_address_callback (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client)
{
HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%ld, client=%s",
level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
/* NOTE: At preset the space is assumed to be zero. Perhaphs the
space should be mapped onto something for instance: space0 -
unified memory; space1 - IO memory; ... */
if (space != 0)
hw_abort (me, "Hey! Unknown space %d", space);
sim_core_attach (hw_system (me),
NULL, /*cpu*/
level,
access_read_write_exec,
space, addr,
nr_bytes,
0, /* modulo */
client,
NULL);
}
static unsigned
dv_core_dma_read_buffer_callback (struct hw *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
return sim_core_read_buffer (hw_system (me),
NULL, /*CPU*/
space, /*???*/
dest,
addr,
nr_bytes);
}
static unsigned
dv_core_dma_write_buffer_callback (struct hw *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
return sim_core_write_buffer (hw_system (me),
NULL, /*cpu*/
space, /*???*/
source,
addr,
nr_bytes);
}
static void
dv_core_finish (struct hw *me)
{
set_hw_attach_address (me, dv_core_attach_address_callback);
set_hw_dma_write_buffer (me, dv_core_dma_write_buffer_callback);
set_hw_dma_read_buffer (me, dv_core_dma_read_buffer_callback);
}
const struct hw_descriptor dv_core_descriptor[] = {
{ "core", dv_core_finish, },
{ NULL },
};

373
sim/common/dv-glue.c Normal file
View File

@@ -0,0 +1,373 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996,1998 Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hw-main.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
/* DEVICE
glue - glue to interconnect and test hardware ports
DESCRIPTION
The glue device provides two functions. Firstly, it provides a
mechanism for inspecting and driving the port network. Secondly,
it provides a set of boolean primitives that can be used to apply
combinatorial operations to the port network.
Glue devices have a variable number of big endian <<output>>
registers. Each register is target-word sized. The registers can
be read and written.
Writing to an output register results in an event being driven
(level determined by the value written) on the devices
corresponding output port.
Reading an <<output>> register returns either the last value
written or the most recently computed value (for that register) as
a result of an event ariving on that port (which ever was computed
last).
At present the following sub device types are available:
<<glue>>: In addition to driving its output interrupt port with any
value written to an interrupt input port is stored in the
corresponding <<output>> register. Such input interrupts, however,
are not propogated to an output interrupt port.
<<glue-and>>: The bit-wise AND of the interrupt inputs is computed
and then both stored in <<output>> register zero and propogated to
output interrupt output port zero.
PROPERTIES
reg = <address> <size> (required)
Specify the address (within the parent bus) that this device is to
live. The address must be 2048 * sizeof (word) (8k in a 32bit
simulation) aligned.
interrupt-ranges = <int-number> <range> (optional)
If present, this specifies the number of valid interrupt inputs (up
to the maximum of 2048). By default, <<int-number>> is zero and
range is determined by the <<reg>> size.
PORTS
int[0..] (input, output)
Both an input and an output port.
EXAMPLES
Enable tracing of the device:
| -t glue-device \
Create source, bitwize-and, and sink glue devices. Since the
device at address <<0x10000>> is of size <<8>> it will have two
output interrupt ports.
| -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \
| -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \
| -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \
| -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \
Wire the two source interrupts to the AND device:
| -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
| -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
Wire the AND device up to the sink so that the and's output is not
left open.
| -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
With the above configuration. The client program is able to
compute a two bit AND. For instance the <<C>> stub below prints 1
AND 0.
| unsigned *input = (void*)0xf0010000;
| unsigned *output = (void*)0xf0030000;
| unsigned ans;
| input[0] = htonl(1);
| input[1] = htonl(0);
| ans = ntohl(*output);
| write_string("AND is ");
| write_int(ans);
| write_line();
BUGS
A future implementation of this device may support multiple
interrupt ranges.
Some of the devices listed may not yet be fully implemented.
Additional devices such as a D flip-flop (DFF), an inverter (INV)
or a latch (LAT) may prove useful.
*/
enum {
max_nr_ports = 2048,
};
enum hw_glue_type {
glue_undefined = 0,
glue_io,
glue_and,
glue_nand,
glue_or,
glue_xor,
glue_nor,
glue_not,
};
struct hw_glue {
enum hw_glue_type type;
int int_number;
int *input;
int nr_inputs;
unsigned sizeof_input;
/* our output registers */
int space;
unsigned_word address;
unsigned sizeof_output;
int *output;
int nr_outputs;
};
static hw_io_read_buffer_method hw_glue_io_read_buffer;
static hw_io_write_buffer_method hw_glue_io_write_buffer;
static hw_port_event_method hw_glue_port_event;
const static struct hw_port_descriptor hw_glue_ports[];
static void
hw_glue_finish (struct hw *me)
{
struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
/* establish our own methods */
set_hw_data (me, glue);
set_hw_io_read_buffer (me, hw_glue_io_read_buffer);
set_hw_io_write_buffer (me, hw_glue_io_write_buffer);
set_hw_ports (me, hw_glue_ports);
set_hw_port_event (me, hw_glue_port_event);
/* attach to our parent bus */
do_hw_attach_regs (me);
/* establish the output registers */
{
reg_property_spec unit;
int reg_nr;
/* find a relevant reg entry */
reg_nr = 0;
while (hw_find_reg_array_property (me, "reg", reg_nr, &unit)
&& !hw_unit_size_to_attach_size (hw_parent (me),
&unit.size,
&glue->sizeof_output,
me))
reg_nr++;
/* check out the size */
if (glue->sizeof_output == 0)
hw_abort (me, "at least one reg property size must be nonzero");
if (glue->sizeof_output % sizeof (unsigned_word) != 0)
hw_abort (me, "reg property size must be %d aligned",
sizeof (unsigned_word));
/* and the address */
hw_unit_address_to_attach_address (hw_parent (me),
&unit.address,
&glue->space,
&glue->address,
me);
if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0)
hw_abort (me, "reg property address must be %d aligned",
sizeof (unsigned_word) * max_nr_ports);
glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word);
glue->output = hw_zalloc (me, glue->sizeof_output);
}
/* establish the input ports */
{
const struct hw_property *ranges;
ranges = hw_find_property (me, "interrupt-ranges");
if (ranges == NULL)
{
glue->int_number = 0;
glue->nr_inputs = glue->nr_outputs;
}
else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2)
{
hw_abort (me, "invalid interrupt-ranges property (incorrect size)");
}
else
{
const unsigned_cell *int_range = ranges->array;
glue->int_number = BE2H_cell (int_range[0]);
glue->nr_inputs = BE2H_cell (int_range[1]);
}
glue->sizeof_input = glue->nr_inputs * sizeof (unsigned);
glue->input = hw_zalloc (me, glue->sizeof_input);
}
/* determine our type */
{
const char *name = hw_name(me);
if (strcmp (name, "glue") == 0)
glue->type = glue_io;
else if (strcmp (name, "glue-and") == 0)
glue->type = glue_and;
else
hw_abort (me, "unimplemented glue type");
}
HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d",
glue->int_number, glue->nr_inputs, glue->nr_outputs));
}
static unsigned
hw_glue_io_read_buffer (struct hw *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
struct hw_glue *glue = (struct hw_glue *) hw_data (me);
int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs;
if (nr_bytes != sizeof (unsigned_word)
|| (addr % sizeof (unsigned_word)) != 0)
hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported",
space, (unsigned long)addr, nr_bytes);
*(unsigned_word*)dest = H2BE_4(glue->output[reg]);
HW_TRACE ((me, "read - port %d (0x%lx), level %d",
reg, (unsigned long) addr, glue->output[reg]));
return nr_bytes;
}
static unsigned
hw_glue_io_write_buffer (struct hw *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
struct hw_glue *glue = (struct hw_glue *) hw_data (me);
int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports;
if (nr_bytes != sizeof (unsigned_word)
|| (addr % sizeof (unsigned_word)) != 0)
hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported",
space, (unsigned long) addr, nr_bytes);
glue->output[reg] = H2BE_4 (*(unsigned_word*)source);
HW_TRACE ((me, "write - port %d (0x%lx), level %d",
reg, (unsigned long) addr, glue->output[reg]));
hw_port_event (me, reg, glue->output[reg]);
return nr_bytes;
}
static void
hw_glue_port_event (struct hw *me,
int my_port,
struct hw *source,
int source_port,
int level)
{
struct hw_glue *glue = (struct hw_glue *) hw_data (me);
int i;
if (my_port < glue->int_number
|| my_port >= glue->int_number + glue->nr_inputs)
hw_abort (me, "port %d outside of valid range", my_port);
glue->input[my_port - glue->int_number] = level;
switch (glue->type)
{
case glue_io:
{
int port = my_port % glue->nr_outputs;
glue->output[port] = level;
HW_TRACE ((me, "input - port %d (0x%lx), level %d",
my_port,
(unsigned long) glue->address + port * sizeof (unsigned_word),
level));
break;
}
case glue_and:
{
glue->output[0] = glue->input[0];
for (i = 1; i < glue->nr_inputs; i++)
glue->output[0] &= glue->input[i];
HW_TRACE ((me, "and - port %d, level %d arrived - output %d",
my_port, level, glue->output[0]));
hw_port_event (me, 0, glue->output[0]);
break;
}
default:
{
hw_abort (me, "operator not implemented");
break;
}
}
}
static const struct hw_port_descriptor hw_glue_ports[] = {
{ "int", 0, max_nr_ports },
{ NULL }
};
const struct hw_descriptor dv_glue_descriptor[] = {
{ "glue", hw_glue_finish, },
{ "glue-and", hw_glue_finish, },
{ "glue-nand", hw_glue_finish, },
{ "glue-or", hw_glue_finish, },
{ "glue-xor", hw_glue_finish, },
{ "glue-nor", hw_glue_finish, },
{ "glue-not", hw_glue_finish, },
{ NULL },
};

605
sim/common/dv-pal.c Normal file
View File

@@ -0,0 +1,605 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996,1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hw-main.h"
#include "sim-io.h"
/* NOTE: pal is naughty and grubs around looking at things outside of
its immediate domain */
#include "hw-tree.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* DEVICE
pal - glue logic device containing assorted junk
DESCRIPTION
Typical hardware dependant hack. This device allows the firmware
to gain access to all the things the firmware needs (but the OS
doesn't).
The pal contains the following registers:
|0 reset register (write, 8bit)
|4 processor id register (read, 8bit)
|8 interrupt register (8 - port, 9 - level) (write, 16bit)
|12 processor count register (read, 8bit)
|16 tty input fifo register (read, 8bit)
|20 tty input status register (read, 8bit)
|24 tty output fifo register (write, 8bit)
|28 tty output status register (read, 8bit)
|32 countdown register (read/write, 32bit, big-endian)
|36 countdown value register (read, 32bit, big-endian)
|40 timer register (read/write, 32bit, big-endian)
|44 timer value register (read, 32bit, big-endian)
RESET (write): halts the simulator. The value written to the
register is used as an exit status.
PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of
the processor performing the read.
INTERRUPT (write): This register must be written using a two byte
store. The low byte specifies a port and the upper byte specifies
the a level. LEVEL is driven on the specified port. By
convention, the pal's interrupt ports (int0, int1, ...) are wired
up to the corresponding processor's level sensative external
interrupt pin. Eg: A two byte write to address 8 of 0x0102
(big-endian) will result in processor 2's external interrupt pin
being asserted.
PROCESSOR COUNT (read): returns the total number of processors
active in the current simulation.
TTY INPUT FIFO (read): if the TTY input status register indicates a
character is available by being nonzero, returns the next available
character from the pal's tty input port.
TTY OUTPUT FIFO (write): if the TTY output status register
indicates the output fifo is not full by being nonzero, outputs the
character written to the tty's output port.
COUNDOWN (read/write): The countdown registers provide a
non-repeating timed interrupt source. Writing a 32 bit big-endian
zero value to this register clears the countdown timer. Writing a
non-zero 32 bit big-endian value to this register sets the
countdown timer to expire in VALUE ticks (ticks is target
dependant). Reading the countdown register returns the last value
writen.
COUNTDOWN VALUE (read): Reading this 32 bit big-endian register
returns the number of ticks remaining until the countdown timer
expires.
TIMER (read/write): The timer registers provide a periodic timed
interrupt source. Writing a 32 bit big-endian zero value to this
register clears the periodic timer. Writing a 32 bit non-zero
value to this register sets the periodic timer to triger every
VALUE ticks (ticks is target dependant). Reading the timer
register returns the last value written.
TIMER VALUE (read): Reading this 32 bit big-endian register returns
the number of ticks until the next periodic interrupt.
PROPERTIES
reg = <address> <size> (required)
Specify the address (within the parent bus) that this device is to
be located.
poll? = <boolean>
If present and true, indicates that the device should poll its
input.
PORTS
int[0..NR_PROCESSORS] (output)
Driven as a result of a write to the interrupt-port /
interrupt-level register pair.
countdown
Driven whenever the countdown counter reaches zero.
timer
Driven whenever the timer counter reaches zero.
BUGS
At present the common simulator framework does not support input
polling.
*/
enum {
hw_pal_reset_register = 0x0,
hw_pal_cpu_nr_register = 0x4,
hw_pal_int_register = 0x8,
hw_pal_nr_cpu_register = 0xa,
hw_pal_read_fifo = 0x10,
hw_pal_read_status = 0x14,
hw_pal_write_fifo = 0x18,
hw_pal_write_status = 0x1a,
hw_pal_countdown = 0x20,
hw_pal_countdown_value = 0x24,
hw_pal_timer = 0x28,
hw_pal_timer_value = 0x2c,
hw_pal_address_mask = 0x3f,
};
typedef struct _hw_pal_console_buffer {
char buffer;
int status;
} hw_pal_console_buffer;
typedef struct _hw_pal_counter {
struct hw_event *handler;
signed64 start;
unsigned32 delta;
int periodic_p;
} hw_pal_counter;
typedef struct _hw_pal_device {
hw_pal_console_buffer input;
hw_pal_console_buffer output;
hw_pal_counter countdown;
hw_pal_counter timer;
struct hw *disk;
do_hw_poll_read_method *reader;
} hw_pal_device;
enum {
COUNTDOWN_PORT,
TIMER_PORT,
INT_PORT,
};
static const struct hw_port_descriptor hw_pal_ports[] = {
{ "countdown", COUNTDOWN_PORT, 0, output_port, },
{ "timer", TIMER_PORT, 0, output_port, },
{ "int", INT_PORT, MAX_NR_PROCESSORS, output_port, },
{ NULL }
};
/* countdown and simple timer */
static void
do_counter_event (struct hw *me,
void *data)
{
hw_pal_counter *counter = (hw_pal_counter *) data;
if (counter->periodic_p)
{
HW_TRACE ((me, "timer expired"));
counter->start = hw_event_queue_time (me);
hw_port_event (me, TIMER_PORT, 1);
hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
}
else
{
HW_TRACE ((me, "countdown expired"));
counter->delta = 0;
hw_port_event (me, COUNTDOWN_PORT, 1);
}
}
static void
do_counter_read (struct hw *me,
hw_pal_device *pal,
const char *reg,
hw_pal_counter *counter,
unsigned32 *word,
unsigned nr_bytes)
{
unsigned32 val;
if (nr_bytes != 4)
hw_abort (me, "%s - bad read size must be 4 bytes", reg);
val = counter->delta;
HW_TRACE ((me, "read - %s %ld", reg, (long) val));
*word = H2BE_4 (val);
}
static void
do_counter_value (struct hw *me,
hw_pal_device *pal,
const char *reg,
hw_pal_counter *counter,
unsigned32 *word,
unsigned nr_bytes)
{
unsigned32 val;
if (nr_bytes != 4)
hw_abort (me, "%s - bad read size must be 4 bytes", reg);
if (counter->delta != 0)
val = (counter->start + counter->delta
- hw_event_queue_time (me));
else
val = 0;
HW_TRACE ((me, "read - %s %ld", reg, (long) val));
*word = H2BE_4 (val);
}
static void
do_counter_write (struct hw *me,
hw_pal_device *pal,
const char *reg,
hw_pal_counter *counter,
const unsigned32 *word,
unsigned nr_bytes)
{
if (nr_bytes != 4)
hw_abort (me, "%s - bad write size must be 4 bytes", reg);
if (counter->handler != NULL)
{
hw_event_queue_deschedule (me, counter->handler);
counter->handler = NULL;
}
counter->delta = BE2H_4 (*word);
counter->start = hw_event_queue_time (me);
HW_TRACE ((me, "write - %s %ld", reg, (long) counter->delta));
if (counter->delta > 0)
hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
}
/* check the console for an available character */
static void
scan_hw_pal (struct hw *me)
{
hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me);
char c;
int count;
count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof(c));
switch (count)
{
case HW_IO_NOT_READY:
case HW_IO_EOF:
hw_pal->input.buffer = 0;
hw_pal->input.status = 0;
break;
default:
hw_pal->input.buffer = c;
hw_pal->input.status = 1;
}
}
/* write the character to the hw_pal */
static void
write_hw_pal (struct hw *me,
char val)
{
hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
sim_io_write_stdout (hw_system (me), &val, 1);
hw_pal->output.buffer = val;
hw_pal->output.status = 1;
}
/* Reads/writes */
static unsigned
hw_pal_io_read_buffer (struct hw *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
unsigned_1 *byte = (unsigned_1 *) dest;
memset (dest, 0, nr_bytes);
switch (addr & hw_pal_address_mask)
{
case hw_pal_cpu_nr_register:
#ifdef CPU_INDEX
*byte = CPU_INDEX (hw_system_cpu (me));
#else
*byte = 0;
#endif
HW_TRACE ((me, "read - cpu-nr %d\n", *byte));
break;
case hw_pal_nr_cpu_register:
if (hw_tree_find_property (me, "/openprom/options/smp") == NULL)
{
*byte = 1;
HW_TRACE ((me, "read - nr-cpu %d (not defined)\n", *byte));
}
else
{
*byte = hw_tree_find_integer_property (me, "/openprom/options/smp");
HW_TRACE ((me, "read - nr-cpu %d\n", *byte));
}
break;
case hw_pal_read_fifo:
*byte = hw_pal->input.buffer;
HW_TRACE ((me, "read - input-fifo %d\n", *byte));
break;
case hw_pal_read_status:
scan_hw_pal (me);
*byte = hw_pal->input.status;
HW_TRACE ((me, "read - input-status %d\n", *byte));
break;
case hw_pal_write_fifo:
*byte = hw_pal->output.buffer;
HW_TRACE ((me, "read - output-fifo %d\n", *byte));
break;
case hw_pal_write_status:
*byte = hw_pal->output.status;
HW_TRACE ((me, "read - output-status %d\n", *byte));
break;
case hw_pal_countdown:
do_counter_read (me, hw_pal, "countdown",
&hw_pal->countdown, dest, nr_bytes);
break;
case hw_pal_countdown_value:
do_counter_value (me, hw_pal, "countdown-value",
&hw_pal->countdown, dest, nr_bytes);
break;
case hw_pal_timer:
do_counter_read (me, hw_pal, "timer",
&hw_pal->timer, dest, nr_bytes);
break;
case hw_pal_timer_value:
do_counter_value (me, hw_pal, "timer-value",
&hw_pal->timer, dest, nr_bytes);
break;
default:
HW_TRACE ((me, "read - ???\n"));
break;
}
return nr_bytes;
}
static unsigned
hw_pal_io_write_buffer (struct hw *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me);
unsigned_1 *byte = (unsigned_1 *) source;
switch (addr & hw_pal_address_mask)
{
case hw_pal_reset_register:
hw_halt (me, sim_exited, byte[0]);
break;
case hw_pal_int_register:
hw_port_event (me,
INT_PORT + byte[0], /*port*/
(nr_bytes > 1 ? byte[1] : 0)); /* val */
break;
case hw_pal_read_fifo:
hw_pal->input.buffer = byte[0];
HW_TRACE ((me, "write - input-fifo %d\n", byte[0]));
break;
case hw_pal_read_status:
hw_pal->input.status = byte[0];
HW_TRACE ((me, "write - input-status %d\n", byte[0]));
break;
case hw_pal_write_fifo:
write_hw_pal (me, byte[0]);
HW_TRACE ((me, "write - output-fifo %d\n", byte[0]));
break;
case hw_pal_write_status:
hw_pal->output.status = byte[0];
HW_TRACE ((me, "write - output-status %d\n", byte[0]));
break;
case hw_pal_countdown:
do_counter_write (me, hw_pal, "countdown",
&hw_pal->countdown, source, nr_bytes);
break;
case hw_pal_timer:
do_counter_write (me, hw_pal, "timer",
&hw_pal->timer, source, nr_bytes);
break;
}
return nr_bytes;
}
/* instances of the hw_pal struct hw */
#if NOT_YET
static void
hw_pal_instance_delete_callback(hw_instance *instance)
{
/* nothing to delete, the hw_pal is attached to the struct hw */
return;
}
#endif
#if NOT_YET
static int
hw_pal_instance_read_callback (hw_instance *instance,
void *buf,
unsigned_word len)
{
DITRACE (pal, ("read - %s (%ld)", (const char*) buf, (long int) len));
return sim_io_read_stdin (buf, len);
}
#endif
#if NOT_YET
static int
hw_pal_instance_write_callback (hw_instance *instance,
const void *buf,
unsigned_word len)
{
int i;
const char *chp = buf;
hw_pal_device *hw_pal = hw_instance_data (instance);
DITRACE (pal, ("write - %s (%ld)", (const char*) buf, (long int) len));
for (i = 0; i < len; i++)
write_hw_pal (hw_pal, chp[i]);
sim_io_flush_stdoutput ();
return i;
}
#endif
#if NOT_YET
static const hw_instance_callbacks hw_pal_instance_callbacks = {
hw_pal_instance_delete_callback,
hw_pal_instance_read_callback,
hw_pal_instance_write_callback,
};
#endif
#if 0
static hw_instance *
hw_pal_create_instance (struct hw *me,
const char *path,
const char *args)
{
return hw_create_instance_from (me, NULL,
hw_data (me),
path, args,
&hw_pal_instance_callbacks);
}
#endif
static void
hw_pal_attach_address (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client)
{
hw_pal_device *pal = (hw_pal_device*) hw_data (me);
pal->disk = client;
}
#if 0
static hw_callbacks const hw_pal_callbacks = {
{ generic_hw_init_address, },
{ hw_pal_attach_address, }, /* address */
{ hw_pal_io_read_buffer_callback,
hw_pal_io_write_buffer_callback, },
{ NULL, }, /* DMA */
{ NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
{ generic_hw_unit_decode,
generic_hw_unit_encode,
generic_hw_address_to_attach_address,
generic_hw_size_to_attach_size },
hw_pal_create_instance,
};
#endif
static void
hw_pal_finish (struct hw *hw)
{
/* create the descriptor */
hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device);
hw_pal->output.status = 1;
hw_pal->output.buffer = '\0';
hw_pal->input.status = 0;
hw_pal->input.buffer = '\0';
set_hw_data (hw, hw_pal);
set_hw_attach_address (hw, hw_pal_attach_address);
set_hw_io_read_buffer (hw, hw_pal_io_read_buffer);
set_hw_io_write_buffer (hw, hw_pal_io_write_buffer);
set_hw_ports (hw, hw_pal_ports);
/* attach ourselves */
do_hw_attach_regs (hw);
/* If so configured, enable polled input */
if (hw_find_property (hw, "poll?") != NULL
&& hw_find_boolean_property (hw, "poll?"))
{
hw_pal->reader = sim_io_poll_read;
}
else
{
hw_pal->reader = sim_io_read;
}
/* tag the periodic timer */
hw_pal->timer.periodic_p = 1;
}
const struct hw_descriptor dv_pal_descriptor[] = {
{ "pal", hw_pal_finish, },
{ NULL },
};

386
sim/common/dv-sockser.c Normal file
View File

@@ -0,0 +1,386 @@
/* Serial port emulation using sockets.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* FIXME: will obviously need to evolve.
- connectionless sockets might be more appropriate. */
#include "sim-main.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include <signal.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#ifndef __CYGWIN32__
#include <netinet/tcp.h>
#endif
#include "sim-assert.h"
#include "sim-options.h"
#include "dv-sockser.h"
/* Get definitions for both O_NONBLOCK and O_NDELAY. */
#ifndef O_NDELAY
#ifdef FNDELAY
#define O_NDELAY FNDELAY
#else /* ! defined (FNDELAY) */
#define O_NDELAY 0
#endif /* ! defined (FNDELAY) */
#endif /* ! defined (O_NDELAY) */
#ifndef O_NONBLOCK
#ifdef FNBLOCK
#define O_NONBLOCK FNBLOCK
#else /* ! defined (FNBLOCK) */
#define O_NONBLOCK 0
#endif /* ! defined (FNBLOCK) */
#endif /* ! defined (O_NONBLOCK) */
#define MIN(a,b) ((a) < (b) ? (a) : (b))
/* Compromise between eating cpu and properly busy-waiting.
One could have an option to set this but for now that seems
like featuritis. */
#define DEFAULT_TIMEOUT 1000 /* microseconds */
/* FIXME: These should allocated at run time and kept with other simulator
state (duh...). Later. */
const char * sockser_addr = NULL;
/* Timeout in microseconds during status flag computation.
Setting this to zero achieves proper busy wait semantics but eats cpu. */
static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
static int sockser_listen_fd = -1;
static int sockser_fd = -1;
/* FIXME: use tree properties when they're ready. */
typedef enum {
OPTION_ADDR = OPTION_START
} SOCKSER_OPTIONS;
static DECLARE_OPTION_HANDLER (sockser_option_handler);
static const OPTION sockser_options[] =
{
{ { "sockser-addr", required_argument, NULL, OPTION_ADDR },
'\0', "SOCKET ADDRESS", "Set serial emulation socket address",
sockser_option_handler },
{ { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL }
};
static SIM_RC
sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
char *arg, int is_command)
{
switch (opt)
{
case OPTION_ADDR :
sockser_addr = arg;
break;
}
return SIM_RC_OK;
}
static SIM_RC
dv_sockser_init (SIM_DESC sd)
{
struct hostent *hostent;
struct sockaddr_in sockaddr;
char hostname[100];
const char *port_str;
int tmp,port;
if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
|| sockser_addr == NULL)
return SIM_RC_OK;
if (*sockser_addr == '/')
{
/* support for these can come later */
sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
sockser_addr);
return SIM_RC_FAIL;
}
port_str = strchr (sockser_addr, ':');
if (!port_str)
{
sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
sockser_addr);
return SIM_RC_FAIL;
}
tmp = MIN (port_str - sockser_addr, (int) sizeof hostname - 1);
strncpy (hostname, sockser_addr, tmp);
hostname[tmp] = '\000';
port = atoi (port_str + 1);
hostent = gethostbyname (hostname);
if (! hostent)
{
sim_io_eprintf (sd, "sockser init: unknown host: %s\n",
hostname);
return SIM_RC_FAIL;
}
sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0);
if (sockser_listen_fd < 0)
{
sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n",
strerror (errno));
return SIM_RC_FAIL;
}
sockaddr.sin_family = PF_INET;
sockaddr.sin_port = htons(port);
memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
sizeof (struct in_addr));
tmp = 1;
if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof(tmp)) < 0)
{
sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n",
strerror (errno));
}
if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
{
sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n",
strerror (errno));
close (sockser_listen_fd);
sockser_listen_fd = -1;
return SIM_RC_FAIL;
}
if (listen (sockser_listen_fd, 1) < 0)
{
sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n",
strerror (errno));
close (sockser_listen_fd);
sockser_listen_fd = -1;
return SIM_RC_OK;
}
/* Handle writes to missing client -> SIGPIPE.
??? Need a central signal management module. */
{
RETSIGTYPE (*orig) ();
orig = signal (SIGPIPE, SIG_IGN);
/* If a handler is already set up, don't mess with it. */
if (orig != SIG_DFL && orig != SIG_IGN)
signal (SIGPIPE, orig);
}
return SIM_RC_OK;
}
static void
dv_sockser_uninstall (SIM_DESC sd)
{
if (sockser_listen_fd != -1)
{
close (sockser_listen_fd);
sockser_listen_fd = -1;
}
if (sockser_fd != -1)
{
close (sockser_fd);
sockser_fd = -1;
}
}
SIM_RC
dv_sockser_install (SIM_DESC sd)
{
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK)
return SIM_RC_FAIL;
sim_module_add_init_fn (sd, dv_sockser_init);
sim_module_add_uninstall_fn (sd, dv_sockser_uninstall);
return SIM_RC_OK;
}
static int
connected_p (SIM_DESC sd)
{
int numfds,flags;
struct timeval tv;
fd_set readfds;
struct sockaddr sockaddr;
int addrlen;
if (sockser_listen_fd == -1)
return 0;
if (sockser_fd >= 0)
{
/* FIXME: has client gone away? */
return 1;
}
/* Not connected. Connect with a client if there is one. */
FD_ZERO (&readfds);
FD_SET (sockser_listen_fd, &readfds);
/* ??? One can certainly argue this should be done differently,
but for now this is sufficient. */
tv.tv_sec = 0;
tv.tv_usec = sockser_timeout;
numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv);
if (numfds <= 0)
return 0;
sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
if (sockser_fd < 0)
return 0;
/* Set non-blocking i/o. */
flags = fcntl (sockser_fd, F_GETFL);
flags |= O_NONBLOCK | O_NDELAY;
if (fcntl (sockser_fd, F_SETFL, flags) == -1)
{
sim_io_eprintf (sd, "unable to set nonblocking i/o");
close (sockser_fd);
sockser_fd = -1;
return 0;
}
return 1;
}
int
dv_sockser_status (SIM_DESC sd)
{
int numrfds,numwfds,status;
struct timeval tv;
fd_set readfds,writefds;
/* status to return if the socket isn't set up, or select fails */
status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY;
if (! connected_p (sd))
return status;
FD_ZERO (&readfds);
FD_ZERO (&writefds);
FD_SET (sockser_fd, &readfds);
FD_SET (sockser_fd, &writefds);
/* ??? One can certainly argue this should be done differently,
but for now this is sufficient. The read is done separately
from the write to enforce the delay which we heuristically set to
once every SOCKSER_TIMEOUT_FREQ tries.
No, this isn't great for SMP situations, blah blah blah. */
{
static int n;
#define SOCKSER_TIMEOUT_FREQ 42
if (++n == SOCKSER_TIMEOUT_FREQ)
n = 0;
if (n == 0)
{
tv.tv_sec = 0;
tv.tv_usec = sockser_timeout;
numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
tv.tv_sec = 0;
tv.tv_usec = 0;
numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
}
else /* do both selects at once */
{
tv.tv_sec = 0;
tv.tv_usec = 0;
numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
}
}
status = 0;
if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds))
status |= DV_SOCKSER_INPUT_EMPTY;
if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds))
status |= DV_SOCKSER_OUTPUT_EMPTY;
return status;
}
int
dv_sockser_write (SIM_DESC sd, unsigned char c)
{
int n;
if (! connected_p (sd))
return -1;
n = write (sockser_fd, &c, 1);
if (n == -1)
{
if (errno == EPIPE)
{
close (sockser_fd);
sockser_fd = -1;
}
return -1;
}
if (n != 1)
return -1;
return 1;
}
int
dv_sockser_read (SIM_DESC sd)
{
unsigned char c;
int n;
if (! connected_p (sd))
return -1;
n = read (sockser_fd, &c, 1);
/* ??? We're assuming semantics that may not be correct for all hosts.
In particular (from cvssrc/src/server.c), this assumes that we are using
BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
there is nothing to read. */
if (n == 0)
{
close (sockser_fd);
sockser_fd = -1;
return -1;
}
if (n != 1)
return -1;
return c;
}

32
sim/common/dv-sockser.h Normal file
View File

@@ -0,0 +1,32 @@
/* Serial port emulation via sockets.
Copyright (C) 1998, Free Software Foundation, Inc.
This file is part of the GNU simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef DV_SOCKSER_H
#define DV_SOCKSER_H
/* bits in result of dev_sockser_status */
#define DV_SOCKSER_INPUT_EMPTY 1
#define DV_SOCKSER_OUTPUT_EMPTY 2
/* FIXME: later add a device ptr arg */
extern int dv_sockser_status (SIM_DESC);
int dv_sockser_write (SIM_DESC, unsigned char);
int dv_sockser_read (SIM_DESC);
#endif /* DV_SOCKSER_H */

10
sim/common/gdbinit.in Normal file
View File

@@ -0,0 +1,10 @@
break sim_io_error
define dump
set sim_debug_dump ()
end
document dump
Dump cpu and simulator registers for debugging the simulator.
Requires the simulator to provide function sim_debug_dump.
end

1122
sim/common/genmloop.sh Normal file

File diff suppressed because it is too large Load Diff

67
sim/common/gennltvals.sh Normal file
View File

@@ -0,0 +1,67 @@
#! /bin/sh
# Generate nltvals.def, a file that describes various newlib/libgloss
# target values used by the host/target interface.
#
# Syntax: /bin/sh gennltvals.sh shell srcroot cpp
shell=$1
srcroot=$2
cpp=$3
srccom=$srcroot/sim/common
echo '/* Newlib/libgloss macro values needed by remote target support. */'
echo '/* This file is machine generated by gennltvals.sh. */'
$shell ${srccom}/gentvals.sh "" errno ${srcroot}/newlib/libc/include \
"errno.h sys/errno.h" 'E[A-Z0-9]*' "${cpp}"
$shell ${srccom}/gentvals.sh "" signal ${srcroot}/newlib/libc/include \
"signal.h sys/signal.h" 'SIG[A-Z0-9]*' "${cpp}"
$shell ${srccom}/gentvals.sh "" open ${srcroot}/newlib/libc/include \
"fcntl.h sys/fcntl.h" 'O_[A-Z0-9]*' "${cpp}"
# Unfortunately, each newlib/libgloss port has seen fit to define their own
# syscall.h file. This means that system call numbers can vary for each port.
# Support for all this crud is kept here, rather than trying to get too fancy.
# If you want to try to improve this, please do, but don't break anything.
# Note that there is a standard syscall.h file (libgloss/syscall.h) now which
# hopefully more targets can use.
dir=newlib/libc/sys/d10v/sys target=d10v
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss target=d30v
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss target=fr30
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss/i960 target=i960
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss target=m32r
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss target=mn10200
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss target=mn10300
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss target=sparc
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"
dir=libgloss/v850/sys target=v850
$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
"syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}"

125
sim/common/gentmap.c Normal file
View File

@@ -0,0 +1,125 @@
/* Generate targ-vals.h and targ-map.c. */
#include <stdio.h>
struct tdefs {
char *symbol;
int value;
};
static struct tdefs sys_tdefs[] = {
#define sys_defs
#include "targ-vals.def"
#undef sys_defs
{ 0, 0 }
};
static struct tdefs errno_tdefs[] = {
#define errno_defs
#include "targ-vals.def"
#undef errno_defs
{ 0, 0 }
};
static struct tdefs open_tdefs[] = {
#define open_defs
#include "targ-vals.def"
#undef open_defs
{ 0, 0 }
};
static void
gen_targ_vals_h ()
{
struct tdefs *t;
printf ("/* Target header values needed by the simulator and gdb. */\n");
printf ("/* This file is machine generated by gentmap.c. */\n\n");
printf ("#ifndef TARG_VALS_H\n");
printf ("#define TARG_VALS_H\n\n");
printf ("/* syscall values */\n");
for (t = &sys_tdefs[0]; t->symbol; ++t)
printf ("#define TARGET_%s %d\n", t->symbol, t->value);
printf ("\n");
printf ("/* errno values */\n");
for (t = &errno_tdefs[0]; t->symbol; ++t)
printf ("#define TARGET_%s %d\n", t->symbol, t->value);
printf ("\n");
printf ("/* open flag values */\n");
for (t = &open_tdefs[0]; t->symbol; ++t)
printf ("#define TARGET_%s 0x%x\n", t->symbol, t->value);
printf ("\n");
printf ("#endif /* TARG_VALS_H */\n");
}
static void
gen_targ_map_c ()
{
struct tdefs *t;
printf ("/* Target value mapping utilities needed by the simulator and gdb. */\n");
printf ("/* This file is machine generated by gentmap.c. */\n\n");
printf ("#include <errno.h>\n");
printf ("#include <fcntl.h>\n");
printf ("#include \"ansidecl.h\"\n");
printf ("#include \"callback.h\"\n");
printf ("#include \"targ-vals.h\"\n");
printf ("\n");
printf ("/* syscall mapping table */\n");
printf ("CB_TARGET_DEFS_MAP cb_init_syscall_map[] = {\n");
for (t = &sys_tdefs[0]; t->symbol; ++t)
{
printf ("#ifdef CB_%s\n", t->symbol);
printf (" { CB_%s, TARGET_%s },\n", t->symbol, t->symbol);
printf ("#endif\n");
}
printf (" { -1, -1 }\n");
printf ("};\n\n");
printf ("/* errno mapping table */\n");
printf ("CB_TARGET_DEFS_MAP cb_init_errno_map[] = {\n");
for (t = &errno_tdefs[0]; t->symbol; ++t)
{
printf ("#ifdef %s\n", t->symbol);
printf (" { %s, TARGET_%s },\n", t->symbol, t->symbol);
printf ("#endif\n");
}
printf (" { 0, 0 }\n");
printf ("};\n\n");
printf ("/* open flags mapping table */\n");
printf ("CB_TARGET_DEFS_MAP cb_init_open_map[] = {\n");
for (t = &open_tdefs[0]; t->symbol; ++t)
{
printf ("#ifdef %s\n", t->symbol);
printf (" { %s, TARGET_%s },\n", t->symbol, t->symbol);
printf ("#endif\n");
}
printf (" { -1, -1 }\n");
printf ("};\n\n");
}
int
main (argc, argv)
int argc;
char *argv[];
{
if (argc != 2)
abort ();
if (strcmp (argv[1], "-h") == 0)
gen_targ_vals_h ();
else if (strcmp (argv[1], "-c") == 0)
gen_targ_map_c ();
else
abort ();
exit (0);
}

74
sim/common/gentvals.sh Normal file
View File

@@ -0,0 +1,74 @@
#!/bin/sh
# Usage: gentvals.sh target type dir files pattern cpp
target=$1
type=$2
dir=$3
# FIXME: Would be nice to process #include's in these files.
files=$4
pattern=$5
cpp=$6
# FIXME: need trap to remove tmp files.
rm -f tmpvals.list tmpvals.uniq
for f in $files
do
if test -f $dir/$f ; then
grep "#define[ ]$pattern" $dir/$f | sed -e "s/^.*#define[ ]\($pattern\)[ ]*\([^ ][^ ]*\).*$/\1/" >> tmpvals.list
fi
done
sort <tmpvals.list | uniq >tmpvals.uniq
rm -f tmpvals.h
for f in $files
do
if test -f $dir/$f ; then
echo "#include <$f>" >>tmpvals.h
fi
done
cat tmpvals.uniq |
while read sym
do
echo "#ifdef $sym" >>tmpvals.h
echo 'DEFVAL { "'$sym'", '$sym ' },' >>tmpvals.h
echo "#endif" >>tmpvals.h
done
if test -z "$target"
then
echo "#ifdef ${type}_defs"
else
echo "#ifdef NL_TARGET_$target"
echo "#ifdef ${type}_defs"
fi
for f in $files
do
if test -f $dir/$f ; then
echo "/* from $f */"
fi
done
if test -z "$target"
then
echo "/* begin $type target macros */"
else
echo "/* begin $target $type target macros */"
fi
$cpp -I$dir tmpvals.h | grep DEFVAL | sed -e 's/DEFVAL//' -e 's/ / /'
if test -z "$target"
then
echo "/* end $type target macros */"
echo "#endif"
else
echo "/* end $target $type target macros */"
echo "#endif"
echo "#endif"
fi
rm -f tmpvals.list tmpvals.uniq tmpvals.h

99
sim/common/hw-alloc.c Normal file
View File

@@ -0,0 +1,99 @@
/* Hardware memory allocator.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "hw-main.h"
#include "hw-base.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
struct hw_alloc_data {
void *alloc;
int zalloc_p;
struct hw_alloc_data *next;
};
void
create_hw_alloc_data (struct hw *me)
{
/* NULL */
}
void
delete_hw_alloc_data (struct hw *me)
{
if (me->alloc_of_hw != NULL)
hw_abort (me, "hw-alloc botch");
while (me->alloc_of_hw != NULL)
{
hw_free (me, me->alloc_of_hw->alloc);
}
}
void *
hw_zalloc (struct hw *me, unsigned long size)
{
struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data);
memory->alloc = zalloc (size);
memory->zalloc_p = 1;
memory->next = me->alloc_of_hw;
me->alloc_of_hw = memory;
return memory->alloc;
}
void *
hw_malloc (struct hw *me, unsigned long size)
{
struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data);
memory->alloc = zalloc (size);
memory->zalloc_p = 0;
memory->next = me->alloc_of_hw;
me->alloc_of_hw = memory;
return memory->alloc;
}
void
hw_free (struct hw *me,
void *alloc)
{
struct hw_alloc_data **memory;
for (memory = &me->alloc_of_hw;
*memory != NULL;
memory = &(*memory)->next)
{
if ((*memory)->alloc == alloc)
{
struct hw_alloc_data *die = (*memory);
(*memory) = die->next;
if (die->zalloc_p)
zfree (die->alloc);
else
free (die->alloc);
zfree (die);
return;
}
}
hw_abort (me, "free of memory not belonging to a device");
}

49
sim/common/hw-alloc.h Normal file
View File

@@ -0,0 +1,49 @@
/* Hardware memory allocator.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef HW_ALLOC_H
#define HW_ALLOC_H
/* Mechanism for associating memory allocated by a device to that
device.
When a device is deleted any remaining memory regions associated to
it are reclaimed.
FIXME: Perhaphs this can be generalized. Perhaphs it should not
be. */
#define HW_ZALLOC(me,type) (type*) hw_zalloc (me, sizeof (type))
#define HW_MALLOC(me,type) (type*) hw_malloc (me, sizeof (type))
#define HW_NZALLOC(ME,TYPE,N) (TYPE*) hw_zalloc (me, sizeof (TYPE) * (N))
extern void *hw_zalloc (struct hw *me, unsigned long size);
extern void *hw_malloc (struct hw *me, unsigned long size);
extern void hw_free (struct hw *me, void *);
/* Duplicate a string allocating memory using the per-device heap */
extern char *hw_strdup (struct hw *me, const char *str);
#endif

571
sim/common/hw-base.c Normal file
View File

@@ -0,0 +1,571 @@
/* This file is part of the program psim.
Copyright (C) 1994-1996, 1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hw-main.h"
#include "hw-base.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <ctype.h>
#include "hw-config.h"
struct hw_base_data {
int finished_p;
const struct hw_descriptor *descriptor;
hw_delete_callback *to_delete;
};
static int
generic_hw_unit_decode (struct hw *bus,
const char *unit,
hw_unit *phys)
{
memset (phys, 0, sizeof (*phys));
if (unit == NULL)
return 0;
else
{
int nr_cells = 0;
const int max_nr_cells = hw_unit_nr_address_cells (bus);
while (1)
{
char *end = NULL;
unsigned long val;
val = strtoul (unit, &end, 0);
/* parse error? */
if (unit == end)
return -1;
/* two many cells? */
if (nr_cells >= max_nr_cells)
return -1;
/* save it */
phys->cells[nr_cells] = val;
nr_cells++;
unit = end;
/* more to follow? */
if (isspace (*unit) || *unit == '\0')
break;
if (*unit != ',')
return -1;
unit++;
}
if (nr_cells < max_nr_cells) {
/* shift everything to correct position */
int i;
for (i = 1; i <= nr_cells; i++)
phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i];
for (i = 0; i < (max_nr_cells - nr_cells); i++)
phys->cells[i] = 0;
}
phys->nr_cells = max_nr_cells;
return max_nr_cells;
}
}
static int
generic_hw_unit_encode (struct hw *bus,
const hw_unit *phys,
char *buf,
int sizeof_buf)
{
int i;
int len;
char *pos = buf;
/* skip leading zero's */
for (i = 0; i < phys->nr_cells; i++)
{
if (phys->cells[i] != 0)
break;
}
/* don't output anything if empty */
if (phys->nr_cells == 0)
{
strcpy(pos, "");
len = 0;
}
else if (i == phys->nr_cells)
{
/* all zero */
strcpy(pos, "0");
len = 1;
}
else
{
for (; i < phys->nr_cells; i++)
{
if (pos != buf) {
strcat(pos, ",");
pos = strchr(pos, '\0');
}
if (phys->cells[i] < 10)
sprintf (pos, "%ld", (unsigned long)phys->cells[i]);
else
sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]);
pos = strchr(pos, '\0');
}
len = pos - buf;
}
if (len >= sizeof_buf)
hw_abort (NULL, "generic_unit_encode - buffer overflow\n");
return len;
}
static int
generic_hw_unit_address_to_attach_address (struct hw *me,
const hw_unit *address,
int *attach_space,
unsigned_word *attach_address,
struct hw *client)
{
int i;
for (i = 0; i < address->nr_cells - 2; i++)
{
if (address->cells[i] != 0)
hw_abort (me, "Only 32bit addresses supported");
}
if (address->nr_cells >= 2)
*attach_space = address->cells[address->nr_cells - 2];
else
*attach_space = 0;
*attach_address = address->cells[address->nr_cells - 1];
return 1;
}
static int
generic_hw_unit_size_to_attach_size (struct hw *me,
const hw_unit *size,
unsigned *nr_bytes,
struct hw *client)
{
int i;
for (i = 0; i < size->nr_cells - 1; i++)
{
if (size->cells[i] != 0)
hw_abort (me, "Only 32bit sizes supported");
}
*nr_bytes = size->cells[0];
return *nr_bytes;
}
/* ignore/passthrough versions of each function */
static void
passthrough_hw_attach_address (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client) /*callback/default*/
{
if (hw_parent (me) == NULL)
hw_abort (client, "hw_attach_address: no parent attach method");
hw_attach_address (hw_parent (me), level,
space, addr, nr_bytes,
client);
}
static void
passthrough_hw_detach_address (struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client) /*callback/default*/
{
if (hw_parent (me) == NULL)
hw_abort (client, "hw_attach_address: no parent attach method");
hw_detach_address (hw_parent (me), level,
space, addr, nr_bytes,
client);
}
static unsigned
panic_hw_io_read_buffer (struct hw *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
hw_abort (me, "no io-read method");
return 0;
}
static unsigned
panic_hw_io_write_buffer (struct hw *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
hw_abort (me, "no io-write method");
return 0;
}
static unsigned
passthrough_hw_dma_read_buffer (struct hw *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes)
{
if (hw_parent (me) == NULL)
hw_abort (me, "no parent dma-read method");
return hw_dma_read_buffer (hw_parent (me), dest,
space, addr, nr_bytes);
}
static unsigned
passthrough_hw_dma_write_buffer (struct hw *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section)
{
if (hw_parent (me) == NULL)
hw_abort (me, "no parent dma-write method");
return hw_dma_write_buffer (hw_parent (me), source,
space, addr,
nr_bytes,
violate_read_only_section);
}
static void
ignore_hw_delete (struct hw *me)
{
/* NOP */
}
static const char *
full_name_of_hw (struct hw *leaf,
char *buf,
unsigned sizeof_buf)
{
/* get a buffer */
char full_name[1024];
if (buf == (char*)0)
{
buf = full_name;
sizeof_buf = sizeof (full_name);
}
/* use head recursion to construct the path */
if (hw_parent (leaf) == NULL)
/* root */
{
if (sizeof_buf < 1)
hw_abort (leaf, "buffer overflow");
*buf = '\0';
}
else
/* sub node */
{
char unit[1024];
full_name_of_hw (hw_parent (leaf), buf, sizeof_buf);
if (hw_unit_encode (hw_parent (leaf),
hw_unit_address (leaf),
unit + 1,
sizeof (unit) - 1)
> 0)
unit[0] = '@';
else
unit[0] = '\0';
if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit)
>= sizeof_buf)
hw_abort (leaf, "buffer overflow");
strcat (buf, "/");
strcat (buf, hw_name (leaf));
strcat (buf, unit);
}
/* return it usefully */
if (buf == full_name)
buf = hw_strdup (leaf, full_name);
return buf;
}
struct hw *
hw_create (struct sim_state *sd,
struct hw *parent,
const char *family,
const char *name,
const char *unit,
const char *args)
{
/* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */
struct hw *hw = ZALLOC (struct hw);
/* our identity */
hw->family_of_hw = hw_strdup (hw, family);
hw->name_of_hw = hw_strdup (hw, name);
hw->args_of_hw = hw_strdup (hw, args);
/* a hook into the system */
if (sd != NULL)
hw->system_of_hw = sd;
else if (parent != NULL)
hw->system_of_hw = hw_system (parent);
else
hw_abort (parent, "No system found");
/* in a tree */
if (parent != NULL)
{
struct hw **sibling = &parent->child_of_hw;
while ((*sibling) != NULL)
sibling = &(*sibling)->sibling_of_hw;
*sibling = hw;
hw->parent_of_hw = parent;
}
/* top of tree */
if (parent != NULL)
{
struct hw *root = parent;
while (root->parent_of_hw != NULL)
root = root->parent_of_hw;
hw->root_of_hw = root;
}
/* a unique identifier for the device on the parents bus */
if (parent != NULL)
{
hw_unit_decode (parent, unit, &hw->unit_address_of_hw);
}
/* Determine our path */
if (parent != NULL)
hw->path_of_hw = full_name_of_hw (hw, NULL, 0);
else
hw->path_of_hw = "/";
/* create our base type */
hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data);
hw->base_of_hw->finished_p = 0;
/* our callbacks */
set_hw_io_read_buffer (hw, panic_hw_io_read_buffer);
set_hw_io_write_buffer (hw, panic_hw_io_write_buffer);
set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer);
set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer);
set_hw_unit_decode (hw, generic_hw_unit_decode);
set_hw_unit_encode (hw, generic_hw_unit_encode);
set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address);
set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size);
set_hw_attach_address (hw, passthrough_hw_attach_address);
set_hw_detach_address (hw, passthrough_hw_detach_address);
set_hw_delete (hw, ignore_hw_delete);
/* locate a descriptor */
{
const struct hw_descriptor **table;
for (table = hw_descriptors;
*table != NULL;
table++)
{
const struct hw_descriptor *entry;
for (entry = *table;
entry->family != NULL;
entry++)
{
if (strcmp (family, entry->family) == 0)
{
hw->base_of_hw->descriptor = entry;
break;
}
}
}
if (hw->base_of_hw->descriptor == NULL)
{
hw_abort (parent, "Unknown device `%s'", family);
}
}
/* Attach dummy ports */
create_hw_alloc_data (hw);
create_hw_property_data (hw);
create_hw_port_data (hw);
create_hw_event_data (hw);
create_hw_handle_data (hw);
create_hw_instance_data (hw);
return hw;
}
int
hw_finished_p (struct hw *me)
{
return (me->base_of_hw->finished_p);
}
void
hw_finish (struct hw *me)
{
if (hw_finished_p (me))
hw_abort (me, "Attempt to finish finished device");
/* Fill in the (hopefully) defined address/size cells values */
if (hw_find_property (me, "#address-cells") != NULL)
me->nr_address_cells_of_hw_unit =
hw_find_integer_property (me, "#address-cells");
else
me->nr_address_cells_of_hw_unit = 2;
if (hw_find_property (me, "#size-cells") != NULL)
me->nr_size_cells_of_hw_unit =
hw_find_integer_property (me, "#size-cells");
else
me->nr_size_cells_of_hw_unit = 1;
/* Fill in the (hopefully) defined trace variable */
if (hw_find_property (me, "trace?") != NULL)
me->trace_of_hw_p = hw_find_boolean_property (me, "trace?");
/* allow global variable to define default tracing */
else if (! hw_trace_p (me)
&& hw_find_property (hw_root (me), "global-trace?") != NULL
&& hw_find_boolean_property (hw_root (me), "global-trace?"))
me->trace_of_hw_p = 1;
/* Allow the real device to override any methods */
me->base_of_hw->descriptor->to_finish (me);
me->base_of_hw->finished_p = 1;
}
void
hw_delete (struct hw *me)
{
/* give the object a chance to tidy up */
me->base_of_hw->to_delete (me);
delete_hw_instance_data (me);
delete_hw_handle_data (me);
delete_hw_event_data (me);
delete_hw_port_data (me);
delete_hw_property_data (me);
/* now unlink us from the tree */
if (hw_parent (me))
{
struct hw **sibling = &hw_parent (me)->child_of_hw;
while (*sibling != NULL)
{
if (*sibling == me)
{
*sibling = me->sibling_of_hw;
me->sibling_of_hw = NULL;
me->parent_of_hw = NULL;
break;
}
}
}
/* some sanity checks */
if (hw_child (me) != NULL)
{
hw_abort (me, "attempt to delete device with children");
}
if (hw_sibling (me) != NULL)
{
hw_abort (me, "attempt to delete device with siblings");
}
/* blow away all memory belonging to the device */
delete_hw_alloc_data (me);
/* finally */
zfree (me->base_of_hw);
zfree (me);
}
/* Go through the devices various reg properties for those that
specify attach addresses */
void
do_hw_attach_regs (struct hw *hw)
{
static const char *(reg_property_names[]) = {
"attach-addresses",
"assigned-addresses",
"reg",
"alternate-reg" ,
NULL
};
const char **reg_property_name;
int nr_valid_reg_properties = 0;
for (reg_property_name = reg_property_names;
*reg_property_name != NULL;
reg_property_name++)
{
if (hw_find_property (hw, *reg_property_name) != NULL)
{
reg_property_spec reg;
int reg_entry;
for (reg_entry = 0;
hw_find_reg_array_property (hw, *reg_property_name, reg_entry,
&reg);
reg_entry++)
{
unsigned_word attach_address;
int attach_space;
unsigned attach_size;
if (!hw_unit_address_to_attach_address (hw_parent (hw),
&reg.address,
&attach_space,
&attach_address,
hw))
continue;
if (!hw_unit_size_to_attach_size (hw_parent (hw),
&reg.size,
&attach_size, hw))
continue;
hw_attach_address (hw_parent (hw),
0,
attach_space, attach_address, attach_size,
hw);
nr_valid_reg_properties++;
}
/* if first option matches don't try for any others */
if (reg_property_name == reg_property_names)
break;
}
}
}

109
sim/common/hw-base.h Normal file
View File

@@ -0,0 +1,109 @@
/* This file is part of the program psim.
Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef HW_BASE
#define HW_BASE
/* Create a primative device */
struct hw *hw_create
(struct sim_state *sd,
struct hw *parent,
const char *family,
const char *name,
const char *unit,
const char *args);
/* Complete the creation of that device (finish overrides methods
using the set_hw_* operations below) */
void hw_finish
(struct hw *me);
int hw_finished_p
(struct hw *me);
/* Delete the entire device */
void hw_delete
(struct hw *me);
/* Override device methods */
typedef void (hw_delete_callback)
(struct hw *me);
#define set_hw_delete(hw, method) \
((hw)->base_of_hw->to_delete = (method))
/* ALLOC */
extern void create_hw_alloc_data
(struct hw *hw);
extern void delete_hw_alloc_data
(struct hw *hw);
/* PORTS */
extern void create_hw_port_data
(struct hw *hw);
extern void delete_hw_port_data
(struct hw *hw);
/* PROPERTIES */
extern void create_hw_property_data
(struct hw *hw);
extern void delete_hw_property_data
(struct hw *hw);
/* EVENTS */
extern void create_hw_event_data
(struct hw *hw);
extern void delete_hw_event_data
(struct hw *hw);
/* HANDLES */
extern void create_hw_handle_data
(struct hw *hw);
extern void delete_hw_handle_data
(struct hw *hw);
/* INSTANCES */
extern void create_hw_instance_data
(struct hw *hw);
extern void delete_hw_instance_data
(struct hw *hw);
#endif

66
sim/common/hw-device.c Normal file
View File

@@ -0,0 +1,66 @@
/* This file is part of the program psim.
Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hw-main.h"
#include "hw-base.h"
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* Address methods */
const hw_unit *
hw_unit_address (struct hw *me)
{
return &me->unit_address_of_hw;
}
/* IOCTL: */
int
hw_ioctl (struct hw *me,
hw_ioctl_request request,
...)
{
int status;
va_list ap;
va_start(ap, request);
status = me->to_ioctl (me, request, ap);
va_end(ap);
return status;
}
char *
hw_strdup (struct hw *me, const char *str)
{
if (str != NULL)
{
char *dup = hw_zalloc (me, strlen (str) + 1);
strcpy (dup, str);
return dup;
}
else
{
return NULL;
}
}

535
sim/common/hw-device.h Normal file
View File

@@ -0,0 +1,535 @@
/* This file is part of the program psim.
Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef HW_DEVICE_H
#define HW_DEVICE_H
/* declared in sim-basics.h, this object is used everywhere */
/* typedef struct _device device; */
/* Introduction:
As explained in earlier sections, the device, device instance,
property and ports lie at the heart of PSIM's device model.
In the below a synopsis of the device object and the operations it
supports are given.
*/
/* Creation:
The devices are created using a sequence of steps. In particular:
o A tree framework is created.
At this point, properties can be modified and extra
devices inserted (or removed?).
#if LATER
Any properties that have a run-time value (eg ihandle
or device instance pointer properties) are entered
into the device tree using a named reference to the
corresponding runtime object that is to be created.
#endif
o Real devices are created for all the dummy devices.
A device can assume that all of its parents have been
initialized.
A device can assume that all non run-time properties
have been initialized.
As part of being created, the device normally attaches
itself to its parent bus.
#if LATER
Device instance data is initialized.
#endif
#if LATER
o Any run-time properties are created.
#endif
#if MUCH_MUCH_LATER
o Some devices, as part of their initialization
might want to refer to ihandle properties
in the device tree.
#endif
NOTES:
o It is important to separate the creation
of an actual device from the creation
of the tree. The alternative creating
the device in two stages: As a separate
entity and then as a part of the tree.
#if LATER
o Run-time properties can not be created
until after the devices in the tree
have been created. Hence an extra pass
for handling them.
#endif
*/
/* Relationships:
A device is able to determine its relationship to other devices
within the tree. Operations include querying for a devices parent,
sibling, child, name, and path (from the root).
*/
#define hw_parent(hw) ((hw)->parent_of_hw + 0)
#define hw_sibling(hw) ((hw)->sibling_of_hw + 0)
#define hw_child(hw) ((hw)->child_of_hw + 0)
/* Herritage:
*/
#define hw_family(hw) ((hw)->family_of_hw + 0)
#define hw_name(hw) ((hw)->name_of_hw + 0)
#define hw_args(hw) ((hw)->args_of_hw + 0)
#define hw_path(hw) ((hw)->path_of_hw + 0)
/* Short cut to the root node of the tree */
#define hw_root(hw) ((hw)->root_of_hw + 0)
/* Short cut back to the simulator object */
#define hw_system(hw) ((hw)->system_of_hw)
/* For requests initiated by a CPU the cpu that initiated the request */
struct _sim_cpu *hw_system_cpu (struct hw *hw);
/* Device private data */
#define hw_data(hw) ((hw)->data_of_hw)
#define set_hw_data(hw, value) \
((hw)->data_of_hw = (value))
/* Perform a soft reset of the device */
typedef unsigned (hw_reset_method)
(struct hw *me);
#define hw_reset(hw) ((hw)->to_reset (hw))
#define set_hw_reset(hw, method) \
((hw)->to_reset = method)
/* Hardware operations:
Connecting a parent to its children is a common bus. The parent
node is described as the bus owner and is responisble for
co-ordinating bus operations. On the bus, a SPACE:ADDR pair is used
to specify an address. A device that is both a bus owner (parent)
and bus client (child) are refered to as a bridging device.
A child performing a data (DMA) transfer will pass its request to
the bus owner (the devices parent). The bus owner will then either
reflect the request to one of the other devices attached to the bus
(a child of the bus owner) or bridge the request up the tree to the
next bus. */
/* Children attached to a bus can register (attach) themselves to
specific addresses on their attached bus.
(A device may also be implicitly attached to certain bus
addresses).
The SPACE:ADDR pair specify an address on the common bus that
connects the parent and child devices. */
typedef void (hw_attach_address_method)
(struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client); /*callback/default*/
#define hw_attach_address(me, level, space, addr, nr_bytes, client) \
((me)->to_attach_address (me, level, space, addr, nr_bytes, client))
#define set_hw_attach_address(hw, method) \
((hw)->to_attach_address = (method))
typedef void (hw_detach_address_method)
(struct hw *me,
int level,
int space,
address_word addr,
address_word nr_bytes,
struct hw *client); /*callback/default*/
#define hw_detach_address(me, level, space, addr, nr_bytes, client) \
((me)->to_detach_address (me, level, space, addr, nr_bytes, client))
#define set_hw_detach_address(hw, method) \
((hw)->to_detach_address = (method))
/* An IO operation from a parent to a child via the conecting bus.
The SPACE:ADDR pair specify an address on the bus shared between
the parent and child devices. */
typedef unsigned (hw_io_read_buffer_method)
(struct hw *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes);
#define hw_io_read_buffer(hw, dest, space, addr, nr_bytes) \
((hw)->to_io_read_buffer (hw, dest, space, addr, nr_bytes))
#define set_hw_io_read_buffer(hw, method) \
((hw)->to_io_read_buffer = (method))
typedef unsigned (hw_io_write_buffer_method)
(struct hw *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes);
#define hw_io_write_buffer(hw, src, space, addr, nr_bytes) \
((hw)->to_io_write_buffer (hw, src, space, addr, nr_bytes))
#define set_hw_io_write_buffer(hw, method) \
((hw)->to_io_write_buffer = (method))
/* Conversly, the device pci1000,1@1 may need to perform a dma transfer
into the cpu/memory core. Just as I/O moves towards the leaves,
dma transfers move towards the core via the initiating devices
parent nodes. The root device (special) converts the DMA transfer
into reads/writes to memory.
The SPACE:ADDR pair specify an address on the common bus connecting
the parent and child devices. */
typedef unsigned (hw_dma_read_buffer_method)
(struct hw *bus,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes);
#define hw_dma_read_buffer(bus, dest, space, addr, nr_bytes) \
((bus)->to_dma_read_buffer (bus, dest, space, addr, nr_bytes))
#define set_hw_dma_read_buffer(me, method) \
((me)->to_dma_read_buffer = (method))
typedef unsigned (hw_dma_write_buffer_method)
(struct hw *bus,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section);
#define hw_dma_write_buffer(bus, src, space, addr, nr_bytes, violate_ro) \
((bus)->to_dma_write_buffer (bus, src, space, addr, nr_bytes, violate_ro))
#define set_hw_dma_write_buffer(me, method) \
((me)->to_dma_write_buffer = (method))
/* Address/size specs for devices are encoded following a convention
similar to that used by OpenFirmware. In particular, an
address/size is packed into a sequence of up to four cell words.
The number of words determined by the number of {address,size}
cells attributes of the device. */
typedef struct _hw_unit {
int nr_cells;
unsigned_cell cells[4]; /* unused cells are zero */
} hw_unit;
/* For the given bus, the number of address and size cells used in a
hw_unit. */
#define hw_unit_nr_address_cells(bus) ((bus)->nr_address_cells_of_hw_unit + 0)
#define hw_unit_nr_size_cells(bus) ((bus)->nr_size_cells_of_hw_unit + 0)
/* For the given device, its identifying hw_unit address.
Each device has an identifying hw_unit address. That address is
used when identifying one of a number of identical devices on a
common controller bus. ex fd0&fd1. */
const hw_unit *hw_unit_address
(struct hw *me);
/* Convert between a textual and the internal representation of a
hw_unit address/size.
NOTE: A device asks its parent to translate between a hw_unit and
textual representation. This is because the textual address of a
device is specified using the parent busses notation. */
typedef int (hw_unit_decode_method)
(struct hw *bus,
const char *encoded,
hw_unit *unit);
#define hw_unit_decode(bus, encoded, unit) \
((bus)->to_unit_decode (bus, encoded, unit))
#define set_hw_unit_decode(hw, method) \
((hw)->to_unit_decode = (method))
typedef int (hw_unit_encode_method)
(struct hw *bus,
const hw_unit *unit,
char *encoded,
int sizeof_buf);
#define hw_unit_encode(bus, unit, encoded, sizeof_encoded) \
((bus)->to_unit_encode (bus, unit, encoded, sizeof_encoded))
#define set_hw_unit_encode(hw, method) \
((hw)->to_unit_encode = (method))
/* As the bus that the device is attached too, to translate a devices
hw_unit address/size into a form suitable for an attach address
call.
Return a zero result if the address should be ignored when looking
for attach addresses. */
typedef int (hw_unit_address_to_attach_address_method)
(struct hw *bus,
const hw_unit *unit_addr,
int *attach_space,
unsigned_word *attach_addr,
struct hw *client);
#define hw_unit_address_to_attach_address(bus, unit_addr, attach_space, attach_addr, client) \
((bus)->to_unit_address_to_attach_address (bus, unit_addr, attach_space, attach_addr, client))
#define set_hw_unit_address_to_attach_address(hw, method) \
((hw)->to_unit_address_to_attach_address = (method))
typedef int (hw_unit_size_to_attach_size_method)
(struct hw *bus,
const hw_unit *unit_size,
unsigned *attach_size,
struct hw *client);
#define hw_unit_size_to_attach_size(bus, unit_size, attach_size, client) \
((bus)->to_unit_size_to_attach_size (bus, unit_size, attach_size, client))
#define set_hw_unit_size_to_attach_size(hw, method) \
((hw)->to_unit_size_to_attach_size = (method))
extern char *hw_strdup (struct hw *me, const char *str);
/* Utilities:
*/
/* IOCTL::
Often devices require `out of band' operations to be performed.
For instance a pal device may need to notify a PCI bridge device
that an interrupt ack cycle needs to be performed on the PCI bus.
Within PSIM such operations are performed by using the generic
ioctl call <<hw_ioctl()>>.
*/
typedef enum {
hw_ioctl_break, /* unsigned_word requested_break */
hw_ioctl_set_trace, /* void */
hw_ioctl_create_stack, /* unsigned_word *sp, char **argv, char **envp */
hw_ioctl_change_media, /* const char *new_image (possibly NULL) */
nr_hw_ioctl_requests,
} hw_ioctl_request;
typedef int (hw_ioctl_method)
(struct hw *me,
hw_ioctl_request request,
va_list ap);
int hw_ioctl
(struct hw *me,
hw_ioctl_request request,
...);
/* Error reporting::
So that errors originating from devices appear in a consistent
format, the <<hw_abort()>> function can be used. Formats and
outputs the error message before aborting the simulation
Devices should use this function to abort the simulation except
when the abort reason leaves the simulation in a hazardous
condition (for instance a failed malloc).
*/
void hw_abort
(struct hw *me,
const char *fmt,
...) __attribute__ ((format (printf, 2, 3)));
void hw_vabort
(struct hw *me,
const char *fmt,
va_list ap);
void hw_halt
(struct hw *me,
int reason,
int status);
#define hw_trace_p(hw) ((hw)->trace_of_hw_p + 0)
void hw_trace
(struct hw *me,
const char *fmt,
...) __attribute__ ((format (printf, 2, 3)));
#define HW_TRACE(ARGS) \
do { \
if (hw_trace_p (me)) \
{ \
hw_trace ARGS; \
} \
} while (0)
/* Some of the related functions require specific types */
struct hw_property_data;
struct hw_port_data;
struct hw_base_data;
struct hw_alloc_data;
struct hw_event_data;
struct hw_handle_data;
struct hw_instance_data;
/* Finally the hardware device - keep your grubby little mits off of
these internals! :-) */
struct hw {
/* our relatives */
struct hw *parent_of_hw;
struct hw *sibling_of_hw;
struct hw *child_of_hw;
/* our identity */
const char *name_of_hw;
const char *family_of_hw;
const char *args_of_hw;
const char *path_of_hw;
/* our data */
void *data_of_hw;
/* hot links */
struct hw *root_of_hw;
struct sim_state *system_of_hw;
/* identifying data */
hw_unit unit_address_of_hw;
int nr_address_cells_of_hw_unit;
int nr_size_cells_of_hw_unit;
/* Soft reset */
hw_reset_method *to_reset;
/* Basic callbacks */
hw_io_read_buffer_method *to_io_read_buffer;
hw_io_write_buffer_method *to_io_write_buffer;
hw_dma_read_buffer_method *to_dma_read_buffer;
hw_dma_write_buffer_method *to_dma_write_buffer;
hw_attach_address_method *to_attach_address;
hw_detach_address_method *to_detach_address;
/* More complicated callbacks */
hw_ioctl_method *to_ioctl;
int trace_of_hw_p;
/* address callbacks */
hw_unit_decode_method *to_unit_decode;
hw_unit_encode_method *to_unit_encode;
hw_unit_address_to_attach_address_method *to_unit_address_to_attach_address;
hw_unit_size_to_attach_size_method *to_unit_size_to_attach_size;
/* related data */
struct hw_property_data *properties_of_hw;
struct hw_port_data *ports_of_hw;
struct hw_base_data *base_of_hw;
struct hw_alloc_data *alloc_of_hw;
struct hw_event_data *events_of_hw;
struct hw_handle_data *handles_of_hw;
struct hw_instance_data *instances_of_hw;
};
#endif

263
sim/common/hw-events.c Normal file
View File

@@ -0,0 +1,263 @@
/* Hardware event manager.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "hw-main.h"
#include "hw-base.h"
#include "sim-events.h"
/* The hw-events object is implemented using sim-events */
struct hw_event {
void *data;
struct hw *me;
hw_event_callback *callback;
sim_event *real;
struct hw_event_data *entry;
};
struct hw_event_data {
struct hw_event event;
struct hw_event_data *next;
};
void
create_hw_event_data (struct hw *me)
{
if (me->events_of_hw != NULL)
hw_abort (me, "stray events");
/* NOP */
}
void
delete_hw_event_data (struct hw *me)
{
if (me->events_of_hw != NULL)
hw_abort (me, "stray events");
}
/* Pass the H/W event onto the real callback */
static void
bounce_hw_event (SIM_DESC sd,
void *data)
{
/* save the data */
struct hw_event_data *entry = (struct hw_event_data *) data;
struct hw *me = entry->event.me;
void *event_data = entry->event.data;
hw_event_callback *callback = entry->event.callback;
struct hw_event_data **prev = &me->events_of_hw;
while ((*prev) != entry)
prev = &(*prev)->next;
(*prev) = entry->next;
hw_free (me, entry);
callback (me, event_data); /* may not return */
}
/* Map onto the event functions */
struct hw_event *
hw_event_queue_schedule (struct hw *me,
signed64 delta_time,
hw_event_callback *callback,
void *data)
{
struct hw_event *event;
va_list dummy;
event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data,
NULL, dummy);
return event;
}
struct hw_event *
hw_event_queue_schedule_tracef (struct hw *me,
signed64 delta_time,
hw_event_callback *callback,
void *data,
const char *fmt,
...)
{
struct hw_event *event;
va_list ap;
va_start (ap, fmt);
event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, fmt, ap);
va_end (ap);
return event;
}
struct hw_event *
hw_event_queue_schedule_vtracef (struct hw *me,
signed64 delta_time,
hw_event_callback *callback,
void *data,
const char *fmt,
va_list ap)
{
struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data);
entry->next = me->events_of_hw;
me->events_of_hw = entry;
/* fill it in */
entry->event.entry = entry;
entry->event.data = data;
entry->event.callback = callback;
entry->event.me = me;
entry->event.real = sim_events_schedule_vtracef (hw_system (me),
delta_time,
bounce_hw_event,
entry,
fmt, ap);
return &entry->event;
}
void
hw_event_queue_deschedule (struct hw *me,
struct hw_event *event_to_remove)
{
/* ZAP the event but only if it is still in the event queue. Note
that event_to_remove is only de-referenced after its validity has
been confirmed. */
struct hw_event_data **prev;
for (prev = &me->events_of_hw;
(*prev) != NULL;
prev = &(*prev)->next)
{
struct hw_event_data *entry = (*prev);
if (&entry->event == event_to_remove)
{
sim_events_deschedule (hw_system (me),
entry->event.real);
(*prev) = entry->next;
hw_free (me, entry);
return;
}
}
}
signed64
hw_event_queue_time (struct hw *me)
{
return sim_events_time (hw_system (me));
}
/* Only worry about this compling on ANSI systems.
Build with `make test-hw-events' in sim/<cpu> directory*/
#if defined (MAIN)
#include "sim-main.h"
#include <string.h>
#include <stdio.h>
static void
test_handler (struct hw *me,
void *data)
{
int *n = data;
if (*n != hw_event_queue_time (me))
abort ();
*n = -(*n);
}
int
main (int argc,
char **argv)
{
host_callback *cb = ZALLOC (host_callback);
struct sim_state *sd = sim_state_alloc (0, cb);
struct hw *me = ZALLOC (struct hw);
sim_pre_argv_init (sd, "test-hw-events");
sim_post_argv_init (sd);
me->system_of_hw = sd;
printf ("Create hw-event-data\n");
{
create_hw_alloc_data (me);
create_hw_event_data (me);
delete_hw_event_data (me);
delete_hw_alloc_data (me);
}
printf ("Create hw-events\n");
{
struct hw_event *a;
struct hw_event *b;
struct hw_event *c;
struct hw_event *d;
create_hw_alloc_data (me);
create_hw_event_data (me);
a = hw_event_queue_schedule (me, 0, NULL, NULL);
b = hw_event_queue_schedule (me, 1, NULL, NULL);
c = hw_event_queue_schedule (me, 2, NULL, NULL);
d = hw_event_queue_schedule (me, 1, NULL, NULL);
hw_event_queue_deschedule (me, c);
hw_event_queue_deschedule (me, b);
hw_event_queue_deschedule (me, a);
hw_event_queue_deschedule (me, d);
c = HW_ZALLOC (me, struct hw_event);
hw_event_queue_deschedule (me, b); /* OOPS! */
hw_free (me, c);
delete_hw_event_data (me);
delete_hw_alloc_data (me);
}
printf ("Schedule hw-events\n");
{
struct hw_event **e;
int *n;
int i;
int nr = 4;
e = HW_NZALLOC (me, struct hw_event *, nr);
n = HW_NZALLOC (me, int, nr);
create_hw_alloc_data (me);
create_hw_event_data (me);
for (i = 0; i < nr; i++)
{
n[i] = i;
e[i] = hw_event_queue_schedule (me, i, test_handler, &n[i]);
}
sim_events_preprocess (sd, 1, 1);
for (i = 0; i < nr; i++)
{
if (sim_events_tick (sd))
sim_events_process (sd);
}
for (i = 0; i < nr; i++)
{
if (n[i] != -i)
abort ();
hw_event_queue_deschedule (me, e[i]);
}
hw_free (me, n);
hw_free (me, e);
delete_hw_event_data (me);
delete_hw_alloc_data (me);
}
return 0;
}
#endif

61
sim/common/hw-events.h Normal file
View File

@@ -0,0 +1,61 @@
/* Hardware event manager.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef HW_EVENTS_H
#define HW_EVENTS_H
/* Event manager customized for hardware models.
This interface is discussed further in sim-events.h. */
struct hw_event;
typedef void (hw_event_callback) (struct hw *me, void *data);
struct hw_event *hw_event_queue_schedule
(struct hw *me,
signed64 delta_time,
hw_event_callback *handler,
void *data);
struct hw_event *hw_event_queue_schedule_tracef
(struct hw *me,
signed64 delta_time,
hw_event_callback *handler,
void *data,
const char *fmt,
...) __attribute__ ((format (printf, 5, 6)));
struct hw_event *hw_event_queue_schedule_vtracef
(struct hw *me,
signed64 delta_time,
hw_event_callback *handler,
void *data,
const char *fmt,
va_list ap);
void hw_event_queue_deschedule
(struct hw *me,
struct hw_event *event_to_remove);
signed64 hw_event_queue_time
(struct hw *me);
#endif

237
sim/common/hw-handles.c Normal file
View File

@@ -0,0 +1,237 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995,1997-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hw-main.h"
#include "hw-base.h"
struct hw_handle_mapping {
cell_word external;
struct hw *phandle;
struct hw_instance *ihandle;
struct hw_handle_mapping *next;
};
struct hw_handle_data {
int nr_mappings;
struct hw_handle_mapping *mappings;
};
void
create_hw_handle_data (struct hw *hw)
{
if (hw_parent (hw) == NULL)
{
hw->handles_of_hw = HW_ZALLOC (hw, struct hw_handle_data);
}
else
{
hw->handles_of_hw = hw_root (hw)->handles_of_hw;
}
}
void
delete_hw_handle_data (struct hw *hw)
{
/* NULL */
}
#if 0
void
hw_handle_init (struct hw *hw)
{
struct hw_handle_mapping *current_map = db->mappings;
if (current_map != NULL)
{
db->nr_mappings = db->mappings->external;
/* verify that the mappings that were not removed are in
sequence down to nr 1 */
while (current_map->next != NULL)
{
if (current_map->external != current_map->next->external + 1)
error ("hw_handle: hw_handle database possibly corrupt");
current_map = current_map->next;
}
ASSERT (current_map->next == NULL);
if (current_map->external != 1)
error ("hw_handle: hw_handle database possibly corrupt");
}
else
{
db->nr_mappings = 0;
}
}
#endif
struct hw_instance *
hw_handle_ihandle2 (struct hw *hw,
cell_word external)
{
struct hw_handle_data *db = hw->handles_of_hw;
struct hw_handle_mapping *current_map = db->mappings;
while (current_map != NULL)
{
if (current_map->external == external)
return current_map->ihandle;
current_map = current_map->next;
}
return (void*)0;
}
struct hw *
hw_handle_phandle2 (struct hw *hw,
cell_word external)
{
struct hw_handle_data *db = hw->handles_of_hw;
struct hw_handle_mapping *current_map = db->mappings;
while (current_map != NULL)
{
if (current_map->external == external)
return current_map->phandle;
current_map = current_map->next;
}
return (void*)0;
}
cell_word
hw_handle_2ihandle (struct hw *hw,
struct hw_instance *internal)
{
struct hw_handle_data *db = hw->handles_of_hw;
struct hw_handle_mapping *current_map = db->mappings;
while (current_map != NULL)
{
if (current_map->ihandle == internal)
return current_map->external;
current_map = current_map->next;
}
return 0;
}
cell_word
hw_handle_2phandle (struct hw *hw,
struct hw *internal)
{
struct hw_handle_data *db = hw->handles_of_hw;
struct hw_handle_mapping *current_map = db->mappings;
while (current_map != NULL)
{
if (current_map->phandle == internal)
return current_map->external;
current_map = current_map->next;
}
return 0;
}
void
hw_handle_add_ihandle (struct hw *hw,
struct hw_instance *internal)
{
struct hw_handle_data *db = hw->handles_of_hw;
if (hw_handle_2ihandle (hw, internal) != 0)
{
hw_abort (hw, "attempting to add an ihandle already in the data base");
}
else
{
/* insert at the front making things in decending order */
struct hw_handle_mapping *new_map = ZALLOC (struct hw_handle_mapping);
new_map->next = db->mappings;
new_map->ihandle = internal;
db->nr_mappings += 1;
new_map->external = db->nr_mappings;
db->mappings = new_map;
}
}
void
hw_handle_add_phandle (struct hw *hw,
struct hw *internal)
{
struct hw_handle_data *db = hw->handles_of_hw;
if (hw_handle_2phandle (hw, internal) != 0)
{
hw_abort (hw, "attempting to add a phandle already in the data base");
}
else
{
/* insert at the front making things in decending order */
struct hw_handle_mapping *new_map = ZALLOC (struct hw_handle_mapping);
new_map->next = db->mappings;
new_map->phandle = internal;
db->nr_mappings += 1;
new_map->external = db->nr_mappings;
db->mappings = new_map;
}
}
void
hw_handle_remove_ihandle (struct hw *hw,
struct hw_instance *internal)
{
struct hw_handle_data *db = hw->handles_of_hw;
struct hw_handle_mapping **current_map = &db->mappings;
while (*current_map != NULL)
{
if ((*current_map)->ihandle == internal)
{
struct hw_handle_mapping *delete = *current_map;
*current_map = delete->next;
zfree (delete);
return;
}
current_map = &(*current_map)->next;
}
hw_abort (hw, "attempt to remove nonexistant ihandle");
}
void
hw_handle_remove_phandle (struct hw *hw,
struct hw *internal)
{
struct hw_handle_data *db = hw->handles_of_hw;
struct hw_handle_mapping **current_map = &db->mappings;
while (*current_map != NULL)
{
if ((*current_map)->phandle == internal)
{
struct hw_handle_mapping *delete = *current_map;
*current_map = delete->next;
zfree (delete);
return;
}
current_map = &(*current_map)->next;
}
hw_abort (hw, "attempt to remove nonexistant phandle");
}

63
sim/common/hw-handles.h Normal file
View File

@@ -0,0 +1,63 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995,1997-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef HW_HANDLES_H
#define HW_HANDLES_H
/* Export a capability (handle) data base that maps between internal
data values and those given to a simulation. */
cell_word hw_handle_2ihandle
(struct hw *db,
struct hw_instance *instance);
struct hw_instance *hw_handle_ihandle2
(struct hw *db,
cell_word external);
void hw_handle_add_ihandle
(struct hw *db,
struct hw_instance *instance);
void hw_handle_remove_ihandle
(struct hw *db,
struct hw_instance *instance);
cell_word hw_handle_2phandle
(struct hw *db,
struct hw *hw);
struct hw *hw_handle_phandle2
(struct hw *db,
cell_word external);
void hw_handle_add_phandle
(struct hw *db,
struct hw *hw);
void hw_handle_remove_phandle
(struct hw *db,
struct hw *hw);
#endif

285
sim/common/hw-instances.c Normal file
View File

@@ -0,0 +1,285 @@
/* This file is part of the program psim.
Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hw-main.h"
#include "hw-base.h"
#include "sim-assert.h"
struct hw_instance_data {
hw_finish_instance_method *to_finish;
struct hw_instance *instances;
};
static hw_finish_instance_method abort_hw_finish_instance;
void
create_hw_instance_data (struct hw *me)
{
me->instances_of_hw = HW_ZALLOC (me, struct hw_instance_data);
set_hw_finish_instance (me, abort_hw_finish_instance);
}
void
delete_hw_instance_data (struct hw *me)
{
/* NOP */
}
static void
abort_hw_finish_instance (struct hw *hw,
struct hw_instance *instance)
{
hw_abort (hw, "no instance finish method");
}
void
set_hw_finish_instance (struct hw *me,
hw_finish_instance_method *finish)
{
me->instances_of_hw->to_finish = finish;
}
#if 0
void
clean_hw_instances (struct hw *me)
{
struct hw_instance **instance = &me->instances;
while (*instance != NULL)
{
struct hw_instance *old_instance = *instance;
hw_instance_delete (old_instance);
instance = &me->instances;
}
}
#endif
void
hw_instance_delete (struct hw_instance *instance)
{
#if 1
hw_abort (hw_instance_hw (instance), "not implemented");
#else
struct hw *me = hw_instance_hw (instance);
if (instance->to_instance_delete == NULL)
hw_abort (me, "no delete method");
instance->method->delete(instance);
if (instance->args != NULL)
zfree (instance->args);
if (instance->path != NULL)
zfree (instance->path);
if (instance->child == NULL)
{
/* only remove leaf nodes */
struct hw_instance **curr = &me->instances;
while (*curr != instance)
{
ASSERT (*curr != NULL);
curr = &(*curr)->next;
}
*curr = instance->next;
}
else
{
/* check it isn't in the instance list */
struct hw_instance *curr = me->instances;
while (curr != NULL)
{
ASSERT(curr != instance);
curr = curr->next;
}
/* unlink the child */
ASSERT (instance->child->parent == instance);
instance->child->parent = NULL;
}
cap_remove (me->ihandles, instance);
zfree (instance);
#endif
}
static int
panic_hw_instance_read (struct hw_instance *instance,
void *addr,
unsigned_word len)
{
hw_abort (hw_instance_hw (instance), "no read method");
return -1;
}
static int
panic_hw_instance_write (struct hw_instance *instance,
const void *addr,
unsigned_word len)
{
hw_abort (hw_instance_hw (instance), "no write method");
return -1;
}
static int
panic_hw_instance_seek (struct hw_instance *instance,
unsigned_word pos_hi,
unsigned_word pos_lo)
{
hw_abort (hw_instance_hw (instance), "no seek method");
return -1;
}
int
hw_instance_call_method (struct hw_instance *instance,
const char *method_name,
int n_stack_args,
unsigned_cell stack_args[/*n_stack_args*/],
int n_stack_returns,
unsigned_cell stack_returns[/*n_stack_args*/])
{
#if 1
hw_abort (hw_instance_hw (instance), "not implemented");
return -1;
#else
struct hw *me = instance->owner;
const hw_instance_methods *method = instance->method->methods;
if (method == NULL)
{
hw_abort (me, "no methods (want %s)", method_name);
}
while (method->name != NULL)
{
if (strcmp(method->name, method_name) == 0)
{
return method->method (instance,
n_stack_args, stack_args,
n_stack_returns, stack_returns);
}
method++;
}
hw_abort (me, "no %s method", method_name);
return 0;
#endif
}
#define set_hw_instance_read(instance, method)\
((instance)->to_instance_read = (method))
#define set_hw_instance_write(instance, method)\
((instance)->to_instance_write = (method))
#define set_hw_instance_seek(instance, method)\
((instance)->to_instance_seek = (method))
#if 0
static void
set_hw_instance_finish (struct hw *me,
hw_instance_finish_method *method)
{
if (me->instances_of_hw == NULL)
me->instances_of_hw = HW_ZALLOC (me, struct hw_instance_data);
me->instances_of_hw->to_finish = method;
}
#endif
struct hw_instance *
hw_instance_create (struct hw *me,
struct hw_instance *parent,
const char *path,
const char *args)
{
struct hw_instance *instance = ZALLOC (struct hw_instance);
/*instance->unit*/
/* link this instance into the devices list */
instance->hw_of_instance = me;
instance->parent_of_instance = NULL;
/* link this instance into the front of the devices instance list */
instance->sibling_of_instance = me->instances_of_hw->instances;
me->instances_of_hw->instances = instance;
if (parent != NULL)
{
ASSERT (parent->child_of_instance == NULL);
parent->child_of_instance = instance;
instance->parent_of_instance = parent;
}
instance->args_of_instance = hw_strdup (me, args);
instance->path_of_instance = hw_strdup (me, path);
set_hw_instance_read (instance, panic_hw_instance_read);
set_hw_instance_write (instance, panic_hw_instance_write);
set_hw_instance_seek (instance, panic_hw_instance_seek);
hw_handle_add_ihandle (me, instance);
me->instances_of_hw->to_finish (me, instance);
return instance;
}
struct hw_instance *
hw_instance_interceed (struct hw_instance *parent,
const char *path,
const char *args)
{
#if 1
return NULL;
#else
struct hw_instance *instance = ZALLOC (struct hw_instance);
/*instance->unit*/
/* link this instance into the devices list */
if (me != NULL)
{
ASSERT (parent == NULL);
instance->hw_of_instance = me;
instance->parent_of_instance = NULL;
/* link this instance into the front of the devices instance list */
instance->sibling_of_instance = me->instances_of_hw->instances;
me->instances_of_hw->instances = instance;
}
if (parent != NULL)
{
struct hw_instance **previous;
ASSERT (parent->child_of_instance == NULL);
parent->child_of_instance = instance;
instance->owner = parent->owner;
instance->parent_of_instance = parent;
/* in the devices instance list replace the parent instance with
this one */
instance->next = parent->next;
/* replace parent with this new node */
previous = &instance->owner->instances;
while (*previous != parent)
{
ASSERT (*previous != NULL);
previous = &(*previous)->next;
}
*previous = instance;
}
instance->data = data;
instance->args = (args == NULL ? NULL : (char *) strdup(args));
instance->path = (path == NULL ? NULL : (char *) strdup(path));
cap_add (instance->owner->ihandles, instance);
return instance;
#endif
}

157
sim/common/hw-instances.h Normal file
View File

@@ -0,0 +1,157 @@
/* This file is part of the program psim.
Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef HW_INSTANCES_H
#define HW_INSTANCES_H
/* Instances:
As with IEEE1275, a device can be opened, creating an instance.
Instances provide more abstract interfaces to the underlying
hardware. For example, the instance methods for a disk may include
code that is able to interpret file systems found on disks. Such
methods would there for allow the manipulation of files on the
disks file system. The operations would be implemented using the
basic block I/O model provided by the disk.
This model includes methods that faciliate the creation of device
instance and (should a given device support it) standard operations
on those instances.
*/
struct hw_instance;
typedef void (hw_finish_instance_method)
(struct hw *hw,
struct hw_instance *);
extern void set_hw_finish_instance
(struct hw *hw,
hw_finish_instance_method *method);
/* construct an instance of the hardware */
struct hw_instance *hw_instance_create
(struct hw *hw,
struct hw_instance *parent,
const char *path,
const char *args);
struct hw_instance *hw_instance_interceed
(struct hw_instance *parent,
const char *path,
const char *args);
void hw_instance_delete
(struct hw_instance *instance);
/* methods applied to an instance of the hw */
typedef int (hw_instance_read_method)
(struct hw_instance *instance,
void *addr,
unsigned_cell len);
#define hw_instance_read(instance, addr, len) \
((instance)->to_instance_read ((instance), (addr), (len)))
#define set_hw_instance_read(instance, method) \
((instance)->to_instance_read = (method))
typedef int (hw_instance_write_method)
(struct hw_instance *instance,
const void *addr,
unsigned_cell len);
#define hw_instance_write(instance, addr, len) \
((instance)->to_instance_write ((instance), (addr), (len)))
#define set_hw_instance_write(instance, method) \
((instance)->to_instance_write = (method))
typedef int (hw_instance_seek_method)
(struct hw_instance *instance,
unsigned_cell pos_hi,
unsigned_cell pos_lo);
#define hw_instance_seek(instance, pos_hi, pos_lo) \
((instance)->to_instance_seek ((instance), (pos_hi), (pos_lo)));
#define set_hw_instance_seek(instance, method) \
((instance)->to_instance_seek = (method))
int hw_instance_call_method
(struct hw_instance *instance,
const char *method,
int n_stack_args,
unsigned_cell stack_args[/*n_stack_args + 1(NULL)*/],
int n_stack_returns,
unsigned_cell stack_returns[/*n_stack_returns + 1(NULL)*/]);
/* the definition of the instance */
#define hw_instance_hw(instance) ((instance)->hw_of_instance + 0)
#define hw_instance_path(instance) ((instance)->path_of_instance + 0)
#define hw_instance_args(instance) ((instance)->args_of_instance)
#define hw_instance_data(instance) ((instance)->data_of_instance)
#define hw_instance_system(instance) (hw_system (hw_instance_hw (instance)))
/* Finally an instance of a hardware device - keep your grubby little
mits off of these internals! :-) */
struct hw_instance {
void *data_of_instance;
char *args_of_instance;
char *path_of_instance;
/* the device that owns the instance */
struct hw *hw_of_instance;
struct hw_instance *sibling_of_instance;
/* interposed instance */
struct hw_instance *parent_of_instance;
struct hw_instance *child_of_instance;
/* methods */
hw_instance_read_method *to_instance_read;
hw_instance_write_method *to_instance_write;
hw_instance_seek_method *to_instance_seek;
};
#endif

73
sim/common/hw-main.h Normal file
View File

@@ -0,0 +1,73 @@
/* Common hardware header file.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Andrew Cagney and Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef HW_MAIN
#define HW_MAIN
/* establish a type system */
#include "sim-basics.h"
/* construct a hw device */
#include "hw-device.h"
#include "hw-properties.h"
#include "hw-events.h"
#include "hw-alloc.h"
#include "hw-instances.h"
#include "hw-handles.h"
#include "hw-ports.h"
/* Description of a hardware device */
typedef void (hw_finish_method)
(struct hw *me);
struct hw_descriptor {
const char *family;
hw_finish_method *to_finish;
};
/* Helper functions to make the implementation of a device easier */
/* Go through the devices reg properties and look for those specifying
an address to attach various registers to */
void do_hw_attach_regs (struct hw *me);
/* Perform a polling read on FD returning either the number of bytes
or a hw_io status code that indicates the reason for the read
failure */
enum {
HW_IO_EOF = -1, HW_IO_NOT_READY = -2, /* See: IEEE 1275 */
};
typedef int (do_hw_poll_read_method)
(SIM_DESC sd, int, char *, int);
int do_hw_poll_read
(struct hw *me,
do_hw_poll_read_method *read,
int sim_io_fd,
void *buf,
unsigned size_of_buf);
#endif

339
sim/common/hw-ports.c Normal file
View File

@@ -0,0 +1,339 @@
/* Hardware ports.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Andrew Cagney and Cygnus Solutions.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "hw-main.h"
#include "hw-base.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include <ctype.h>
#define TRACE(x,y)
struct hw_port_edge {
int my_port;
struct hw *dest;
int dest_port;
struct hw_port_edge *next;
object_disposition disposition;
};
struct hw_port_data {
hw_port_event_method *to_port_event;
const struct hw_port_descriptor *ports;
struct hw_port_edge *edges;
};
const struct hw_port_descriptor empty_hw_ports[] = {
{ NULL, },
};
static void
panic_hw_port_event (struct hw *me,
int my_port,
struct hw *source,
int source_port,
int level)
{
hw_abort (me, "no port method");
}
void
create_hw_port_data (struct hw *me)
{
me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data);
set_hw_port_event (me, panic_hw_port_event);
set_hw_ports (me, empty_hw_ports);
}
void
delete_hw_port_data (struct hw *me)
{
hw_free (me, me->ports_of_hw);
me->ports_of_hw = NULL;
}
void
set_hw_ports (struct hw *me,
const struct hw_port_descriptor ports[])
{
me->ports_of_hw->ports = ports;
}
void
set_hw_port_event (struct hw *me,
hw_port_event_method *port_event)
{
me->ports_of_hw->to_port_event = port_event;
}
static void
attach_hw_port_edge (struct hw *me,
struct hw_port_edge **list,
int my_port,
struct hw *dest,
int dest_port,
object_disposition disposition)
{
struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge);
new_edge->my_port = my_port;
new_edge->dest = dest;
new_edge->dest_port = dest_port;
new_edge->next = *list;
new_edge->disposition = disposition;
*list = new_edge;
}
static void
detach_hw_port_edge (struct hw *me,
struct hw_port_edge **list,
int my_port,
struct hw *dest,
int dest_port)
{
while (*list != NULL)
{
struct hw_port_edge *old_edge = *list;
if (old_edge->dest == dest
&& old_edge->dest_port == dest_port
&& old_edge->my_port == my_port)
{
if (old_edge->disposition == permenant_object)
hw_abort (me, "attempt to delete permenant port edge");
*list = old_edge->next;
hw_free (me, old_edge);
return;
}
}
hw_abort (me, "attempt to delete unattached port");
}
#if 0
static void
clean_hw_port_edges (struct hw_port_edge **list)
{
while (*list != NULL)
{
struct hw_port_edge *old_edge = *list;
switch (old_edge->disposition)
{
case permenant_object:
list = &old_edge->next;
break;
case temporary_object:
*list = old_edge->next;
hw_free (me, old_edge);
break;
}
}
}
#endif
/* Ports: */
void
hw_port_event (struct hw *me,
int my_port,
int level)
{
int found_an_edge = 0;
struct hw_port_edge *edge;
/* device's lines directly connected */
for (edge = me->ports_of_hw->edges;
edge != NULL;
edge = edge->next)
{
if (edge->my_port == my_port)
{
edge->dest->ports_of_hw->to_port_event (edge->dest,
edge->dest_port,
me,
my_port,
level);
found_an_edge = 1;
}
}
if (!found_an_edge)
hw_abort (me, "No edge for port %d", my_port);
}
void
hw_port_attach (struct hw *me,
int my_port,
struct hw *dest,
int dest_port,
object_disposition disposition)
{
attach_hw_port_edge (me,
&me->ports_of_hw->edges,
my_port,
dest,
dest_port,
disposition);
}
void
hw_port_detach (struct hw *me,
int my_port,
struct hw *dest,
int dest_port)
{
detach_hw_port_edge (me,
&me->ports_of_hw->edges,
my_port,
dest,
dest_port);
}
void
hw_port_traverse (struct hw *me,
hw_port_traverse_function *handler,
void *data)
{
struct hw_port_edge *port_edge;
for (port_edge = me->ports_of_hw->edges;
port_edge != NULL;
port_edge = port_edge->next)
{
handler (me, port_edge->my_port,
port_edge->dest, port_edge->dest_port,
data);
}
}
int
hw_port_decode (struct hw *me,
const char *port_name,
port_direction direction)
{
if (port_name == NULL || port_name[0] == '\0')
return 0;
if (isdigit(port_name[0]))
{
return strtoul (port_name, NULL, 0);
}
else
{
const struct hw_port_descriptor *ports =
me->ports_of_hw->ports;
if (ports != NULL)
{
while (ports->name != NULL)
{
if (ports->direction == bidirect_port
|| ports->direction == direction)
{
if (ports->nr_ports > 0)
{
int len = strlen (ports->name);
if (strncmp (port_name, ports->name, len) == 0)
{
if (port_name[len] == '\0')
return ports->number;
else if(isdigit (port_name[len]))
{
int port = (ports->number
+ strtoul (&port_name[len], NULL, 0));
if (port >= ports->number + ports->nr_ports)
hw_abort (me,
"Port %s out of range",
port_name);
return port;
}
}
}
else if (strcmp (port_name, ports->name) == 0)
return ports->number;
}
ports++;
}
}
}
hw_abort (me, "Unreconized port %s", port_name);
return 0;
}
int
hw_port_encode (struct hw *me,
int port_number,
char *buf,
int sizeof_buf,
port_direction direction)
{
const struct hw_port_descriptor *ports = NULL;
ports = me->ports_of_hw->ports;
if (ports != NULL) {
while (ports->name != NULL)
{
if (ports->direction == bidirect_port
|| ports->direction == direction)
{
if (ports->nr_ports > 0)
{
if (port_number >= ports->number
&& port_number < ports->number + ports->nr_ports)
{
strcpy (buf, ports->name);
sprintf (buf + strlen(buf), "%d", port_number - ports->number);
if (strlen (buf) >= sizeof_buf)
hw_abort (me, "hw_port_encode: buffer overflow");
return strlen (buf);
}
}
else
{
if (ports->number == port_number)
{
if (strlen(ports->name) >= sizeof_buf)
hw_abort (me, "hw_port_encode: buffer overflow");
strcpy(buf, ports->name);
return strlen(buf);
}
}
}
ports++;
}
}
sprintf (buf, "%d", port_number);
if (strlen(buf) >= sizeof_buf)
hw_abort (me, "hw_port_encode: buffer overflow");
return strlen(buf);
}

129
sim/common/hw-ports.h Normal file
View File

@@ -0,0 +1,129 @@
/* Hardware ports.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Andrew Cagney and Cygnus Solutions.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef HW_PORTS_H
#define HW_PORTS_H
/* Initialize a port */
struct hw_port_descriptor {
const char *name;
int number;
int nr_ports;
port_direction direction;
};
void set_hw_ports (struct hw *hw, const struct hw_port_descriptor ports[]);
typedef void (hw_port_event_method)
(struct hw *me,
int my_port,
struct hw *source,
int source_port,
int level);
void set_hw_port_event (struct hw *hw, hw_port_event_method *to_port_event);
/* Port source
A device drives its output ports using the call
*/
void hw_port_event
(struct hw *me,
int my_port,
int value);
/* This port event will then be propogated to any attached
destination ports.
Any interpretation of PORT and VALUE is model dependant. As a
guideline the following are recommended: PCI interrupts A-D should
correspond to ports 0-3; level sensative interrupts be requested
with a value of one and withdrawn with a value of 0; edge sensative
interrupts always have a value of 1, the event its self is treated
as the interrupt.
Port destinations
Attached to each port of a device can be zero or more
desitinations. These destinations consist of a device/port pair.
A destination is attached/detached to a device line using the
attach and detach calls. */
void hw_port_attach
(struct hw *me,
int my_port,
struct hw *dest,
int dest_port,
object_disposition disposition);
void hw_port_detach
(struct hw *me,
int my_port,
struct hw *dest,
int dest_port);
/* Iterate over the list of ports attached to a device */
typedef void (hw_port_traverse_function)
(struct hw *me,
int my_port,
struct hw *dest,
int dest_port,
void *data);
void hw_port_traverse
(struct hw *me,
hw_port_traverse_function *handler,
void *data);
/* DESTINATION is attached (detached) to LINE of the device ME
Port conversion
Users refer to port numbers symbolically. For instance a device
may refer to its `INT' signal which is internally represented by
port 3.
To convert to/from the symbolic and internal representation of a
port name/number. The following functions are available. */
int hw_port_decode
(struct hw *me,
const char *symbolic_name,
port_direction direction);
int hw_port_encode
(struct hw *me,
int port_number,
char *buf,
int sizeof_buf,
port_direction direction);
#endif

905
sim/common/hw-properties.c Normal file
View File

@@ -0,0 +1,905 @@
/* This file is part of the program psim.
Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "hw-main.h"
#include "hw-base.h"
#include "sim-assert.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#define TRACE(A,B)
/* property entries */
struct hw_property_data {
struct hw_property_data *next;
struct hw_property *property;
const void *init_array;
unsigned sizeof_init_array;
};
void
create_hw_property_data (struct hw *me)
{
}
void
delete_hw_property_data (struct hw *me)
{
}
/* Device Properties: */
static struct hw_property_data *
find_property_data (struct hw *me,
const char *property)
{
struct hw_property_data *entry;
ASSERT (property != NULL);
entry = me->properties_of_hw;
while (entry != NULL)
{
if (strcmp (entry->property->name, property) == 0)
return entry;
entry = entry->next;
}
return NULL;
}
static void
hw_add_property (struct hw *me,
const char *property,
hw_property_type type,
const void *init_array,
unsigned sizeof_init_array,
const void *array,
unsigned sizeof_array,
const struct hw_property *original,
object_disposition disposition)
{
struct hw_property_data *new_entry = NULL;
struct hw_property *new_value = NULL;
/* find the list end */
struct hw_property_data **insertion_point = &me->properties_of_hw;
while (*insertion_point != NULL)
{
if (strcmp ((*insertion_point)->property->name, property) == 0)
return;
insertion_point = &(*insertion_point)->next;
}
/* create a new value */
new_value = HW_ZALLOC (me, struct hw_property);
new_value->name = (char *) strdup (property);
new_value->type = type;
if (sizeof_array > 0)
{
void *new_array = hw_zalloc (me, sizeof_array);
memcpy (new_array, array, sizeof_array);
new_value->array = new_array;
new_value->sizeof_array = sizeof_array;
}
new_value->owner = me;
new_value->original = original;
new_value->disposition = disposition;
/* insert the value into the list */
new_entry = HW_ZALLOC (me, struct hw_property_data);
*insertion_point = new_entry;
if (sizeof_init_array > 0)
{
void *new_init_array = hw_zalloc (me, sizeof_init_array);
memcpy (new_init_array, init_array, sizeof_init_array);
new_entry->init_array = new_init_array;
new_entry->sizeof_init_array = sizeof_init_array;
}
new_entry->property = new_value;
}
static void
hw_set_property (struct hw *me,
const char *property,
hw_property_type type,
const void *array,
int sizeof_array)
{
/* find the property */
struct hw_property_data *entry = find_property_data (me, property);
if (entry != NULL)
{
/* existing property - update it */
void *new_array = 0;
struct hw_property *value = entry->property;
/* check the type matches */
if (value->type != type)
hw_abort (me, "conflict between type of new and old value for property %s", property);
/* replace its value */
if (value->array != NULL)
hw_free (me, (void*)value->array);
new_array = (sizeof_array > 0
? hw_zalloc (me, sizeof_array)
: (void*)0);
value->array = new_array;
value->sizeof_array = sizeof_array;
if (sizeof_array > 0)
memcpy (new_array, array, sizeof_array);
return;
}
else
{
/* new property - create it */
hw_add_property (me, property, type,
NULL, 0, array, sizeof_array,
NULL, temporary_object);
}
}
#if 0
static void
clean_hw_properties (struct hw *me)
{
struct hw_property_data **delete_point = &me->properties_of_hw;
while (*delete_point != NULL)
{
struct hw_property_data *current = *delete_point;
switch (current->property->disposition)
{
case permenant_object:
/* zap the current value, will be initialized later */
ASSERT (current->init_array != NULL);
if (current->property->array != NULL)
{
hw_free (me, (void*)current->property->array);
current->property->array = NULL;
}
delete_point = &(*delete_point)->next;
break;
case temporary_object:
/* zap the actual property, was created during simulation run */
ASSERT (current->init_array == NULL);
*delete_point = current->next;
if (current->property->array != NULL)
hw_free (me, (void*)current->property->array);
hw_free (me, current->property);
hw_free (me, current);
break;
}
}
}
#endif
#if 0
void
hw_init_static_properties (SIM_DESC sd,
struct hw *me,
void *data)
{
struct hw_property_data *property;
for (property = me->properties_of_hw;
property != NULL;
property = property->next)
{
ASSERT (property->init_array != NULL);
ASSERT (property->property->array == NULL);
ASSERT(property->property->disposition == permenant_object);
switch (property->property->type)
{
case array_property:
case boolean_property:
case range_array_property:
case reg_array_property:
case string_property:
case string_array_property:
case integer_property:
/* delete the property, and replace it with the original */
hw_set_property (me, property->property->name,
property->property->type,
property->init_array,
property->sizeof_init_array);
break;
#if 0
case ihandle_property:
break;
#endif
}
}
}
#endif
#if 0
void
hw_init_runtime_properties (SIM_DESC sd,
struct hw *me,
void *data)
{
struct hw_property_data *property;
for (property = me->properties_of_hw;
property != NULL;
property = property->next)
{
switch (property->property->disposition)
{
case permenant_object:
switch (property->property->type)
{
#if 0
case ihandle_property:
{
struct hw_instance *ihandle;
ihandle_runtime_property_spec spec;
ASSERT (property->init_array != NULL);
ASSERT (property->property->array == NULL);
hw_find_ihandle_runtime_property (me, property->property->name, &spec);
ihandle = tree_instance (me, spec.full_path);
hw_set_ihandle_property (me, property->property->name, ihandle);
break;
}
#endif
case array_property:
case boolean_property:
case range_array_property:
case integer_property:
case reg_array_property:
case string_property:
case string_array_property:
ASSERT (property->init_array != NULL);
ASSERT (property->property->array != NULL);
break;
}
break;
case temporary_object:
ASSERT (property->init_array == NULL);
ASSERT (property->property->array != NULL);
break;
}
}
}
#endif
const struct hw_property *
hw_next_property (const struct hw_property *property)
{
/* find the property in the list */
struct hw *owner = property->owner;
struct hw_property_data *entry = owner->properties_of_hw;
while (entry != NULL && entry->property != property)
entry = entry->next;
/* now return the following property */
ASSERT (entry != NULL); /* must be a member! */
if (entry->next != NULL)
return entry->next->property;
else
return NULL;
}
const struct hw_property *
hw_find_property (struct hw *me,
const char *property)
{
if (me == NULL)
{
return NULL;
}
else if (property == NULL || strcmp (property, "") == 0)
{
if (me->properties_of_hw == NULL)
return NULL;
else
return me->properties_of_hw->property;
}
else
{
struct hw_property_data *entry = find_property_data (me, property);
if (entry != NULL)
return entry->property;
}
return NULL;
}
void
hw_add_array_property (struct hw *me,
const char *property,
const void *array,
int sizeof_array)
{
hw_add_property (me, property, array_property,
array, sizeof_array, array, sizeof_array,
NULL, permenant_object);
}
void
hw_set_array_property (struct hw *me,
const char *property,
const void *array,
int sizeof_array)
{
hw_set_property (me, property, array_property, array, sizeof_array);
}
const struct hw_property *
hw_find_array_property (struct hw *me,
const char *property)
{
const struct hw_property *node;
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != array_property)
hw_abort (me, "property \"%s\" of wrong type (array)", property);
return node;
}
void
hw_add_boolean_property (struct hw *me,
const char *property,
int boolean)
{
signed32 new_boolean = (boolean ? -1 : 0);
hw_add_property (me, property, boolean_property,
&new_boolean, sizeof(new_boolean),
&new_boolean, sizeof(new_boolean),
NULL, permenant_object);
}
int
hw_find_boolean_property (struct hw *me,
const char *property)
{
const struct hw_property *node;
unsigned_cell boolean;
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != boolean_property)
hw_abort (me, "property \"%s\" of wrong type (boolean)", property);
ASSERT (sizeof (boolean) == node->sizeof_array);
memcpy (&boolean, node->array, sizeof (boolean));
return boolean;
}
#if 0
void
hw_add_ihandle_runtime_property (struct hw *me,
const char *property,
const ihandle_runtime_property_spec *ihandle)
{
/* enter the full path as the init array */
hw_add_property (me, property, ihandle_property,
ihandle->full_path, strlen(ihandle->full_path) + 1,
NULL, 0,
NULL, permenant_object);
}
#endif
#if 0
void
hw_find_ihandle_runtime_property (struct hw *me,
const char *property,
ihandle_runtime_property_spec *ihandle)
{
struct hw_property_data *entry = find_property_data (me, property);
TRACE (trace_devices,
("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n",
(long)me, property));
if (entry == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (entry->property->type != ihandle_property
|| entry->property->disposition != permenant_object)
hw_abort (me, "property \"%s\" of wrong type", property);
ASSERT (entry->init_array != NULL);
/* the full path */
ihandle->full_path = entry->init_array;
}
#endif
#if 0
void
hw_set_ihandle_property (struct hw *me,
const char *property,
hw_instance *ihandle)
{
unsigned_cell cells;
cells = H2BE_cell (hw_instance_to_external (ihandle));
hw_set_property (me, property, ihandle_property,
&cells, sizeof (cells));
}
#endif
#if 0
hw_instance *
hw_find_ihandle_property (struct hw *me,
const char *property)
{
const hw_property_data *node;
unsigned_cell ihandle;
hw_instance *instance;
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != ihandle_property)
hw_abort(me, "property \"%s\" of wrong type (ihandle)", property);
if (node->array == NULL)
hw_abort(me, "runtime property \"%s\" not yet initialized", property);
ASSERT (sizeof(ihandle) == node->sizeof_array);
memcpy (&ihandle, node->array, sizeof(ihandle));
instance = external_to_hw_instance (me, BE2H_cell(ihandle));
ASSERT (instance != NULL);
return instance;
}
#endif
void
hw_add_integer_property (struct hw *me,
const char *property,
signed_cell integer)
{
H2BE (integer);
hw_add_property (me, property, integer_property,
&integer, sizeof(integer),
&integer, sizeof(integer),
NULL, permenant_object);
}
signed_cell
hw_find_integer_property (struct hw *me,
const char *property)
{
const struct hw_property *node;
signed_cell integer;
TRACE (trace_devices,
("hw_find_integer(me=0x%lx, property=%s)\n",
(long)me, property));
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != integer_property)
hw_abort (me, "property \"%s\" of wrong type (integer)", property);
ASSERT (sizeof(integer) == node->sizeof_array);
memcpy (&integer, node->array, sizeof (integer));
return BE2H_cell (integer);
}
int
hw_find_integer_array_property (struct hw *me,
const char *property,
unsigned index,
signed_cell *integer)
{
const struct hw_property *node;
int sizeof_integer = sizeof (*integer);
signed_cell *cell;
TRACE (trace_devices,
("hw_find_integer(me=0x%lx, property=%s)\n",
(long)me, property));
/* check things sane */
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != integer_property
&& node->type != array_property)
hw_abort (me, "property \"%s\" of wrong type (integer or array)", property);
if ((node->sizeof_array % sizeof_integer) != 0)
hw_abort (me, "property \"%s\" contains an incomplete number of cells", property);
if (node->sizeof_array <= sizeof_integer * index)
return 0;
/* Find and convert the value */
cell = ((signed_cell*)node->array) + index;
*integer = BE2H_cell (*cell);
return node->sizeof_array / sizeof_integer;
}
static unsigned_cell *
unit_address_to_cells (const hw_unit *unit,
unsigned_cell *cell,
int nr_cells)
{
int i;
ASSERT(nr_cells == unit->nr_cells);
for (i = 0; i < unit->nr_cells; i++)
{
*cell = H2BE_cell (unit->cells[i]);
cell += 1;
}
return cell;
}
static const unsigned_cell *
cells_to_unit_address (const unsigned_cell *cell,
hw_unit *unit,
int nr_cells)
{
int i;
memset(unit, 0, sizeof(*unit));
unit->nr_cells = nr_cells;
for (i = 0; i < unit->nr_cells; i++)
{
unit->cells[i] = BE2H_cell (*cell);
cell += 1;
}
return cell;
}
static unsigned
nr_range_property_cells (struct hw *me,
int nr_ranges)
{
return ((hw_unit_nr_address_cells (me)
+ hw_unit_nr_address_cells (hw_parent (me))
+ hw_unit_nr_size_cells (me))
) * nr_ranges;
}
void
hw_add_range_array_property (struct hw *me,
const char *property,
const range_property_spec *ranges,
unsigned nr_ranges)
{
unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges)
* sizeof (unsigned_cell));
unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
unsigned_cell *cell;
int i;
/* copy the property elements over */
cell = cells;
for (i = 0; i < nr_ranges; i++)
{
const range_property_spec *range = &ranges[i];
/* copy the child address */
cell = unit_address_to_cells (&range->child_address, cell,
hw_unit_nr_address_cells (me));
/* copy the parent address */
cell = unit_address_to_cells (&range->parent_address, cell,
hw_unit_nr_address_cells (hw_parent (me)));
/* copy the size */
cell = unit_address_to_cells (&range->size, cell,
hw_unit_nr_size_cells (me));
}
ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]);
/* add it */
hw_add_property (me, property, range_array_property,
cells, sizeof_cells,
cells, sizeof_cells,
NULL, permenant_object);
hw_free (me, cells);
}
int
hw_find_range_array_property (struct hw *me,
const char *property,
unsigned index,
range_property_spec *range)
{
const struct hw_property *node;
unsigned sizeof_entry = (nr_range_property_cells (me, 1)
* sizeof (unsigned_cell));
const unsigned_cell *cells;
/* locate the property */
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != range_array_property)
hw_abort (me, "property \"%s\" of wrong type (range array)", property);
/* aligned ? */
if ((node->sizeof_array % sizeof_entry) != 0)
hw_abort (me, "property \"%s\" contains an incomplete number of entries",
property);
/* within bounds? */
if (node->sizeof_array < sizeof_entry * (index + 1))
return 0;
/* find the range of interest */
cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
/* copy the child address out - converting as we go */
cells = cells_to_unit_address (cells, &range->child_address,
hw_unit_nr_address_cells (me));
/* copy the parent address out - converting as we go */
cells = cells_to_unit_address (cells, &range->parent_address,
hw_unit_nr_address_cells (hw_parent (me)));
/* copy the size - converting as we go */
cells = cells_to_unit_address (cells, &range->size,
hw_unit_nr_size_cells (me));
return node->sizeof_array / sizeof_entry;
}
static unsigned
nr_reg_property_cells (struct hw *me,
int nr_regs)
{
return (hw_unit_nr_address_cells (hw_parent(me))
+ hw_unit_nr_size_cells (hw_parent(me))
) * nr_regs;
}
void
hw_add_reg_array_property (struct hw *me,
const char *property,
const reg_property_spec *regs,
unsigned nr_regs)
{
unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs)
* sizeof (unsigned_cell));
unsigned_cell *cells = hw_zalloc (me, sizeof_cells);
unsigned_cell *cell;
int i;
/* copy the property elements over */
cell = cells;
for (i = 0; i < nr_regs; i++)
{
const reg_property_spec *reg = &regs[i];
/* copy the address */
cell = unit_address_to_cells (&reg->address, cell,
hw_unit_nr_address_cells (hw_parent (me)));
/* copy the size */
cell = unit_address_to_cells (&reg->size, cell,
hw_unit_nr_size_cells (hw_parent (me)));
}
ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]);
/* add it */
hw_add_property (me, property, reg_array_property,
cells, sizeof_cells,
cells, sizeof_cells,
NULL, permenant_object);
hw_free (me, cells);
}
int
hw_find_reg_array_property (struct hw *me,
const char *property,
unsigned index,
reg_property_spec *reg)
{
const struct hw_property *node;
unsigned sizeof_entry = (nr_reg_property_cells (me, 1)
* sizeof (unsigned_cell));
const unsigned_cell *cells;
/* locate the property */
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != reg_array_property)
hw_abort (me, "property \"%s\" of wrong type (reg array)", property);
/* aligned ? */
if ((node->sizeof_array % sizeof_entry) != 0)
hw_abort (me, "property \"%s\" contains an incomplete number of entries",
property);
/* within bounds? */
if (node->sizeof_array < sizeof_entry * (index + 1))
return 0;
/* find the range of interest */
cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index);
/* copy the address out - converting as we go */
cells = cells_to_unit_address (cells, &reg->address,
hw_unit_nr_address_cells (hw_parent (me)));
/* copy the size out - converting as we go */
cells = cells_to_unit_address (cells, &reg->size,
hw_unit_nr_size_cells (hw_parent (me)));
return node->sizeof_array / sizeof_entry;
}
void
hw_add_string_property (struct hw *me,
const char *property,
const char *string)
{
hw_add_property (me, property, string_property,
string, strlen(string) + 1,
string, strlen(string) + 1,
NULL, permenant_object);
}
const char *
hw_find_string_property (struct hw *me,
const char *property)
{
const struct hw_property *node;
const char *string;
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
if (node->type != string_property)
hw_abort (me, "property \"%s\" of wrong type (string)", property);
string = node->array;
ASSERT (strlen(string) + 1 == node->sizeof_array);
return string;
}
void
hw_add_string_array_property (struct hw *me,
const char *property,
const string_property_spec *strings,
unsigned nr_strings)
{
int sizeof_array;
int string_nr;
char *array;
char *chp;
if (nr_strings == 0)
hw_abort (me, "property \"%s\" must be non-null", property);
/* total up the size of the needed array */
for (sizeof_array = 0, string_nr = 0;
string_nr < nr_strings;
string_nr ++)
{
sizeof_array += strlen (strings[string_nr]) + 1;
}
/* create the array */
array = (char*) hw_zalloc (me, sizeof_array);
chp = array;
for (string_nr = 0;
string_nr < nr_strings;
string_nr++)
{
strcpy (chp, strings[string_nr]);
chp += strlen (chp) + 1;
}
ASSERT (chp == array + sizeof_array);
/* now enter it */
hw_add_property (me, property, string_array_property,
array, sizeof_array,
array, sizeof_array,
NULL, permenant_object);
}
int
hw_find_string_array_property (struct hw *me,
const char *property,
unsigned index,
string_property_spec *string)
{
const struct hw_property *node;
node = hw_find_property (me, property);
if (node == NULL)
hw_abort (me, "property \"%s\" not found", property);
switch (node->type)
{
default:
hw_abort (me, "property \"%s\" of wrong type", property);
break;
case string_property:
if (index == 0)
{
*string = node->array;
ASSERT (strlen(*string) + 1 == node->sizeof_array);
return 1;
}
break;
case array_property:
if (node->sizeof_array == 0
|| ((char*)node->array)[node->sizeof_array - 1] != '\0')
hw_abort (me, "property \"%s\" invalid for string array", property);
/* FALL THROUGH */
case string_array_property:
ASSERT (node->sizeof_array > 0);
ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0');
{
const char *chp = node->array;
int nr_entries = 0;
/* count the number of strings, keeping an eye out for the one
we're looking for */
*string = chp;
do
{
if (*chp == '\0')
{
/* next string */
nr_entries++;
chp++;
if (nr_entries == index)
*string = chp;
}
else
{
chp++;
}
} while (chp < (char*)node->array + node->sizeof_array);
if (index < nr_entries)
return nr_entries;
else
{
*string = NULL;
return 0;
}
}
break;
}
return 0;
}
void
hw_add_duplicate_property (struct hw *me,
const char *property,
const struct hw_property *original)
{
struct hw_property_data *master;
TRACE (trace_devices,
("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n",
(long)me, property));
if (original->disposition != permenant_object)
hw_abort (me, "Can only duplicate permenant objects");
/* find the original's master */
master = original->owner->properties_of_hw;
while (master->property != original)
{
master = master->next;
ASSERT(master != NULL);
}
/* now duplicate it */
hw_add_property (me, property,
original->type,
master->init_array, master->sizeof_init_array,
original->array, original->sizeof_array,
original, permenant_object);
}

244
sim/common/hw-properties.h Normal file
View File

@@ -0,0 +1,244 @@
/* This file is part of the program psim.
Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef HW_PROPERTIES_H
#define HW_PROPERTIES_H
/* The following are valid property types. The property `array' is
for generic untyped data. */
typedef enum {
array_property,
boolean_property,
#if 0
ihandle_property, /*runtime*/
#endif
integer_property,
range_array_property,
reg_array_property,
string_property,
string_array_property,
} hw_property_type;
struct hw_property {
struct hw *owner;
const char *name;
hw_property_type type;
unsigned sizeof_array;
const void *array;
const struct hw_property *original;
object_disposition disposition;
};
#define hw_property_owner(p) ((p)->owner + 0)
#define hw_property_name(p) ((p)->name + 0)
#define hw_property_type(p) ((p)->type + 0)
#define hw_property_array(p) ((p)->array + 0)
#define hw_property_sizeof_array(p) ((p)->sizeof_array + 0)
#define hw_property_original(p) ((p)->original + 0)
#define hw_property_disposition(p) ((p)->disposition + 0)
/* Find/iterate over properites attached to a device.
To iterate over all properties attached to a device, call
hw_find_property (.., NULL) and then hw_property_next. */
const struct hw_property *hw_find_property
(struct hw *me,
const char *property);
const struct hw_property *hw_next_property
(const struct hw_property *previous);
/* Manipulate the properties belonging to a given device.
HW_ADD_* will, if the property is not already present, add a
property to the device. Adding a property to a device after it has
been created is a checked run-time error (use HW_SET_*).
HW_SET_* will always update (or create) the property so that it has
the specified value. Changing the type of a property is a checked
run-time error.
FIND returns the specified properties value. It is a checked
runtime error to either request a nonexistant property or to
request a property using the wrong type. Code locating a property
should first check its type (using hw_find_property above) and then
obtain its value using the below.
Naming convention:
void hw_add_<type>_property(struct hw *, const char *, <type>)
void hw_add_*_array_property(struct hw *, const char *, const <type>*, int)
void hw_set_*_property(struct hw *, const char *, <type>)
void hw_set_*_array_property(struct hw *, const char *, const <type>*, int)
<type> hw_find_*_property(struct hw *, const char *)
int hw_find_*_array_property(struct hw *, const char *, int, <type>*)
*/
void hw_add_array_property
(struct hw *me,
const char *property,
const void *array,
int sizeof_array);
void hw_set_array_property
(struct hw *me,
const char *property,
const void *array,
int sizeof_array);
const struct hw_property *hw_find_array_property
(struct hw *me,
const char *property);
void hw_add_boolean_property
(struct hw *me,
const char *property,
int bool);
int hw_find_boolean_property
(struct hw *me,
const char *property);
#if 0
typedef struct _ihandle_runtime_property_spec {
const char *full_path;
} ihandle_runtime_property_spec;
void hw_add_ihandle_runtime_property
(struct hw *me,
const char *property,
const ihandle_runtime_property_spec *ihandle);
void hw_find_ihandle_runtime_property
(struct hw *me,
const char *property,
ihandle_runtime_property_spec *ihandle);
void hw_set_ihandle_property
(struct hw *me,
const char *property,
hw_instance *ihandle);
hw_instance * hw_find_ihandle_property
(struct hw *me,
const char *property);
#endif
void hw_add_integer_property
(struct hw *me,
const char *property,
signed_cell integer);
signed_cell hw_find_integer_property
(struct hw *me,
const char *property);
int hw_find_integer_array_property
(struct hw *me,
const char *property,
unsigned index,
signed_word *integer);
typedef struct _range_property_spec {
hw_unit child_address;
hw_unit parent_address;
hw_unit size;
} range_property_spec;
void hw_add_range_array_property
(struct hw *me,
const char *property,
const range_property_spec *ranges,
unsigned nr_ranges);
int hw_find_range_array_property
(struct hw *me,
const char *property,
unsigned index,
range_property_spec *range);
typedef struct _reg_property_spec {
hw_unit address;
hw_unit size;
} reg_property_spec;
void hw_add_reg_array_property
(struct hw *me,
const char *property,
const reg_property_spec *reg,
unsigned nr_regs);
int hw_find_reg_array_property
(struct hw *me,
const char *property,
unsigned index,
reg_property_spec *reg);
void hw_add_string_property
(struct hw *me,
const char *property,
const char *string);
const char *hw_find_string_property
(struct hw *me,
const char *property);
typedef const char *string_property_spec;
void hw_add_string_array_property
(struct hw *me,
const char *property,
const string_property_spec *strings,
unsigned nr_strings);
int hw_find_string_array_property
(struct hw *me,
const char *property,
unsigned index,
string_property_spec *string);
void hw_add_duplicate_property
(struct hw *me,
const char *property,
const struct hw_property *original);
#endif

1344
sim/common/hw-tree.c Normal file

File diff suppressed because it is too large Load Diff

119
sim/common/hw-tree.h Normal file
View File

@@ -0,0 +1,119 @@
/* This file is part of the program psim.
Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef HW_TREE
#define HW_TREE
struct hw *hw_tree_create
(SIM_DESC sd,
const char *device);
void hw_tree_delete
(struct hw *root);
struct hw *hw_tree_parse
(struct hw *root,
const char *fmt,
...) __attribute__ ((format (printf, 2, 3)));
struct hw *hw_tree_vparse
(struct hw *root,
const char *fmt,
va_list ap);
void hw_tree_finish
(struct hw *root);
typedef void (hw_tree_print_callback)
(void *,
const char *fmt,
...);
void hw_tree_print
(struct hw *root,
hw_tree_print_callback *print,
void *file);
/* Tree traversal::
The entire device tree can be traversed using the
<<device_tree_traverse()>> function. The traversal can be in
either prefix or postfix order.
*/
typedef void (hw_tree_traverse_function)
(struct hw *device,
void *data);
void hw_tree_traverse
(struct hw *root,
hw_tree_traverse_function *prefix,
hw_tree_traverse_function *postfix,
void *data);
/* Tree lookup::
The function <<hw_tree_find_device()>> will attempt to locate the
specified device within the tree. If the device is not found a
NULL device is returned.
*/
struct hw * hw_tree_find_device
(struct hw *root,
const char *path);
const struct hw_property *hw_tree_find_property
(struct hw *root,
const char *path_to_property);
int hw_tree_find_boolean_property
(struct hw *root,
const char *path_to_property);
signed_cell hw_tree_find_integer_property
(struct hw *root,
const char *path_to_property);
#if NOT_YET
device_instance *hw_tree_find_ihandle_property
(struct hw *root,
const char *path_to_property);
#endif
const char *hw_tree_find_string_property
(struct hw *root,
const char *path_to_property);
/* Perform a soft reset on the created tree. */
void hw_tree_reset
(struct hw *root);
#endif

418
sim/common/nltvals.def Normal file
View File

@@ -0,0 +1,418 @@
/* Newlib/libgloss macro values needed by remote target support. */
/* This file is machine generated by gennltvals.sh. */
#ifdef errno_defs
/* from errno.h */
/* from sys/errno.h */
/* begin errno target macros */
{ "E2BIG", 7 },
{ "EACCES", 13 },
{ "EADDRINUSE", 112 },
{ "EADDRNOTAVAIL", 125 },
{ "EADV", 68 },
{ "EAFNOSUPPORT", 106 },
{ "EAGAIN", 11 },
{ "EALREADY", 120 },
{ "EBADE", 50 },
{ "EBADF", 9 },
{ "EBADFD", 81 },
{ "EBADMSG", 77 },
{ "EBADR", 51 },
{ "EBADRQC", 54 },
{ "EBADSLT", 55 },
{ "EBFONT", 57 },
{ "EBUSY", 16 },
{ "ECHILD", 10 },
{ "ECHRNG", 37 },
{ "ECOMM", 70 },
{ "ECONNABORTED", 113 },
{ "ECONNREFUSED", 111 },
{ "ECONNRESET", 104 },
{ "EDEADLK", 45 },
{ "EDEADLOCK", 56 },
{ "EDESTADDRREQ", 121 },
{ "EDOM", 33 },
{ "EDOTDOT", 76 },
{ "EDQUOT", 132 },
{ "EEXIST", 17 },
{ "EFAULT", 14 },
{ "EFBIG", 27 },
{ "EHOSTDOWN", 117 },
{ "EHOSTUNREACH", 118 },
{ "EIDRM", 36 },
{ "EINPROGRESS", 119 },
{ "EINTR", 4 },
{ "EINVAL", 22 },
{ "EIO", 5 },
{ "EISCONN", 127 },
{ "EISDIR", 21 },
{ "EL2HLT", 44 },
{ "EL2NSYNC", 38 },
{ "EL3HLT", 39 },
{ "EL3RST", 40 },
{ "ELBIN", 75 },
{ "ELIBACC", 83 },
{ "ELIBBAD", 84 },
{ "ELIBEXEC", 87 },
{ "ELIBMAX", 86 },
{ "ELIBSCN", 85 },
{ "ELNRNG", 41 },
{ "ELOOP", 92 },
{ "EMFILE", 24 },
{ "EMLINK", 31 },
{ "EMSGSIZE", 122 },
{ "EMULTIHOP", 74 },
{ "ENAMETOOLONG", 91 },
{ "ENETDOWN", 115 },
{ "ENETRESET", 126 },
{ "ENETUNREACH", 114 },
{ "ENFILE", 23 },
{ "ENMFILE", 89 },
{ "ENOANO", 53 },
{ "ENOBUFS", 105 },
{ "ENOCSI", 43 },
{ "ENODATA", 61 },
{ "ENODEV", 19 },
{ "ENOENT", 2 },
{ "ENOEXEC", 8 },
{ "ENOLCK", 46 },
{ "ENOLINK", 67 },
{ "ENOMEM", 12 },
{ "ENOMSG", 35 },
{ "ENONET", 64 },
{ "ENOPKG", 65 },
{ "ENOPROTOOPT", 109 },
{ "ENOSPC", 28 },
{ "ENOSR", 63 },
{ "ENOSTR", 60 },
{ "ENOSYS", 88 },
{ "ENOTBLK", 15 },
{ "ENOTCONN", 128 },
{ "ENOTDIR", 20 },
{ "ENOTEMPTY", 90 },
{ "ENOTSOCK", 108 },
{ "ENOTSUP", 134 },
{ "ENOTTY", 25 },
{ "ENOTUNIQ", 80 },
{ "ENXIO", 6 },
{ "EOPNOTSUPP", 95 },
{ "EPERM", 1 },
{ "EPFNOSUPPORT", 96 },
{ "EPIPE", 32 },
{ "EPROCLIM", 130 },
{ "EPROTO", 71 },
{ "EPROTONOSUPPORT", 123 },
{ "EPROTOTYPE", 107 },
{ "ERANGE", 34 },
{ "EREMCHG", 82 },
{ "EREMOTE", 66 },
{ "EROFS", 30 },
{ "ESHUTDOWN", 110 },
{ "ESOCKTNOSUPPORT", 124 },
{ "ESPIPE", 29 },
{ "ESRCH", 3 },
{ "ESRMNT", 69 },
{ "ESTALE", 133 },
{ "ETIME", 62 },
{ "ETIMEDOUT", 116 },
{ "ETOOMANYREFS", 129 },
{ "ETXTBSY", 26 },
{ "EUNATCH", 42 },
{ "EUSERS", 131 },
{ "EWOULDBLOCK", 11 },
{ "EXDEV", 18 },
{ "EXFULL", 52 },
/* end errno target macros */
#endif
#ifdef signal_defs
/* from signal.h */
/* from sys/signal.h */
/* begin signal target macros */
{ "SIGABRT", 6 },
{ "SIGALRM", 14 },
{ "SIGBUS", 10 },
{ "SIGCHLD", 20 },
{ "SIGCLD", 20 },
{ "SIGCONT", 19 },
{ "SIGEMT", 7 },
{ "SIGFPE", 8 },
{ "SIGHUP", 1 },
{ "SIGILL", 4 },
{ "SIGINT", 2 },
{ "SIGIO", 23 },
{ "SIGIOT", 6 },
{ "SIGKILL", 9 },
{ "SIGLOST", 29 },
{ "SIGPIPE", 13 },
{ "SIGPOLL", 23 },
{ "SIGPROF", 27 },
{ "SIGQUIT", 3 },
{ "SIGSEGV", 11 },
{ "SIGSTOP", 17 },
{ "SIGSYS", 12 },
{ "SIGTERM", 15 },
{ "SIGTRAP", 5 },
{ "SIGTSTP", 18 },
{ "SIGTTIN", 21 },
{ "SIGTTOU", 22 },
{ "SIGURG", 16 },
{ "SIGUSR1", 30 },
{ "SIGUSR2", 31 },
{ "SIGVTALRM", 26 },
{ "SIGWINCH", 28 },
{ "SIGXCPU", 24 },
{ "SIGXFSZ", 25 },
/* end signal target macros */
#endif
#ifdef open_defs
/* from fcntl.h */
/* from sys/fcntl.h */
/* begin open target macros */
{ "O_ACCMODE", (0 | 1 | 2 ) },
{ "O_APPEND", 0x0008 },
{ "O_CREAT", 0x0200 },
{ "O_EXCL", 0x0800 },
{ "O_NOCTTY", 0x8000 },
{ "O_NONBLOCK", 0x4000 },
{ "O_RDONLY", 0 },
{ "O_RDWR", 2 },
{ "O_SYNC", 0x2000 },
{ "O_TRUNC", 0x0400 },
{ "O_WRONLY", 1 },
/* end open target macros */
#endif
#ifdef NL_TARGET_d10v
#ifdef sys_defs
/* from syscall.h */
/* begin d10v sys target macros */
{ "SYS_ARG", 24 },
{ "SYS_chdir", 12 },
{ "SYS_chmod", 15 },
{ "SYS_chown", 16 },
{ "SYS_close", 6 },
{ "SYS_creat", 8 },
{ "SYS_execv", 11 },
{ "SYS_execve", 59 },
{ "SYS_exit", 1 },
{ "SYS_fork", 2 },
{ "SYS_fstat", 22 },
{ "SYS_getpid", 20 },
{ "SYS_isatty", 21 },
{ "SYS_kill", 60 },
{ "SYS_link", 9 },
{ "SYS_lseek", 19 },
{ "SYS_mknod", 14 },
{ "SYS_open", 5 },
{ "SYS_pipe", 42 },
{ "SYS_read", 3 },
{ "SYS_stat", 38 },
{ "SYS_time", 23 },
{ "SYS_unlink", 10 },
{ "SYS_utime", 201 },
{ "SYS_wait", 202 },
{ "SYS_wait4", 7 },
{ "SYS_write", 4 },
/* end d10v sys target macros */
#endif
#endif
#ifdef NL_TARGET_d30v
#ifdef sys_defs
/* from syscall.h */
/* begin d30v sys target macros */
{ "SYS_argv", 13 },
{ "SYS_argvlen", 12 },
{ "SYS_chdir", 14 },
{ "SYS_chmod", 16 },
{ "SYS_close", 3 },
{ "SYS_exit", 1 },
{ "SYS_fstat", 10 },
{ "SYS_getpid", 8 },
{ "SYS_kill", 9 },
{ "SYS_lseek", 6 },
{ "SYS_open", 2 },
{ "SYS_read", 4 },
{ "SYS_stat", 15 },
{ "SYS_time", 18 },
{ "SYS_unlink", 7 },
{ "SYS_utime", 17 },
{ "SYS_write", 5 },
/* end d30v sys target macros */
#endif
#endif
#ifdef NL_TARGET_fr30
#ifdef sys_defs
/* from syscall.h */
/* begin fr30 sys target macros */
{ "SYS_argv", 13 },
{ "SYS_argvlen", 12 },
{ "SYS_chdir", 14 },
{ "SYS_chmod", 16 },
{ "SYS_close", 3 },
{ "SYS_exit", 1 },
{ "SYS_fstat", 10 },
{ "SYS_getpid", 8 },
{ "SYS_kill", 9 },
{ "SYS_lseek", 6 },
{ "SYS_open", 2 },
{ "SYS_read", 4 },
{ "SYS_stat", 15 },
{ "SYS_time", 18 },
{ "SYS_unlink", 7 },
{ "SYS_utime", 17 },
{ "SYS_write", 5 },
/* end fr30 sys target macros */
#endif
#endif
#ifdef NL_TARGET_i960
#ifdef sys_defs
/* from syscall.h */
/* begin i960 sys target macros */
{ "SYS_argv", 13 },
{ "SYS_argvlen", 12 },
{ "SYS_chdir", 14 },
{ "SYS_chmod", 16 },
{ "SYS_close", 234 },
{ "SYS_exit", 257 },
{ "SYS_fstat", 10 },
{ "SYS_getpid", 8 },
{ "SYS_kill", 9 },
{ "SYS_lseek", 233 },
{ "SYS_open", 230 },
{ "SYS_read", 231 },
{ "SYS_stat", 15 },
{ "SYS_time", 18 },
{ "SYS_unlink", 7 },
{ "SYS_utime", 17 },
{ "SYS_write", 232 },
/* end i960 sys target macros */
#endif
#endif
#ifdef NL_TARGET_m32r
#ifdef sys_defs
/* from syscall.h */
/* begin m32r sys target macros */
{ "SYS_argv", 13 },
{ "SYS_argvlen", 12 },
{ "SYS_chdir", 14 },
{ "SYS_chmod", 16 },
{ "SYS_close", 3 },
{ "SYS_exit", 1 },
{ "SYS_fstat", 10 },
{ "SYS_getpid", 8 },
{ "SYS_kill", 9 },
{ "SYS_lseek", 6 },
{ "SYS_open", 2 },
{ "SYS_read", 4 },
{ "SYS_stat", 15 },
{ "SYS_time", 18 },
{ "SYS_unlink", 7 },
{ "SYS_utime", 17 },
{ "SYS_write", 5 },
/* end m32r sys target macros */
#endif
#endif
#ifdef NL_TARGET_mn10200
#ifdef sys_defs
/* from syscall.h */
/* begin mn10200 sys target macros */
{ "SYS_argv", 13 },
{ "SYS_argvlen", 12 },
{ "SYS_chdir", 14 },
{ "SYS_chmod", 16 },
{ "SYS_close", 3 },
{ "SYS_exit", 1 },
{ "SYS_fstat", 10 },
{ "SYS_getpid", 8 },
{ "SYS_kill", 9 },
{ "SYS_lseek", 6 },
{ "SYS_open", 2 },
{ "SYS_read", 4 },
{ "SYS_stat", 15 },
{ "SYS_time", 18 },
{ "SYS_unlink", 7 },
{ "SYS_utime", 17 },
{ "SYS_write", 5 },
/* end mn10200 sys target macros */
#endif
#endif
#ifdef NL_TARGET_mn10300
#ifdef sys_defs
/* from syscall.h */
/* begin mn10300 sys target macros */
{ "SYS_argv", 13 },
{ "SYS_argvlen", 12 },
{ "SYS_chdir", 14 },
{ "SYS_chmod", 16 },
{ "SYS_close", 3 },
{ "SYS_exit", 1 },
{ "SYS_fstat", 10 },
{ "SYS_getpid", 8 },
{ "SYS_kill", 9 },
{ "SYS_lseek", 6 },
{ "SYS_open", 2 },
{ "SYS_read", 4 },
{ "SYS_stat", 15 },
{ "SYS_time", 18 },
{ "SYS_unlink", 7 },
{ "SYS_utime", 17 },
{ "SYS_write", 5 },
/* end mn10300 sys target macros */
#endif
#endif
#ifdef NL_TARGET_sparc
#ifdef sys_defs
/* from syscall.h */
/* begin sparc sys target macros */
{ "SYS_argv", 13 },
{ "SYS_argvlen", 12 },
{ "SYS_chdir", 14 },
{ "SYS_chmod", 16 },
{ "SYS_close", 3 },
{ "SYS_exit", 1 },
{ "SYS_fstat", 10 },
{ "SYS_getpid", 8 },
{ "SYS_kill", 9 },
{ "SYS_lseek", 6 },
{ "SYS_open", 2 },
{ "SYS_read", 4 },
{ "SYS_stat", 15 },
{ "SYS_time", 18 },
{ "SYS_unlink", 7 },
{ "SYS_utime", 17 },
{ "SYS_write", 5 },
/* end sparc sys target macros */
#endif
#endif
#ifdef NL_TARGET_v850
#ifdef sys_defs
/* from syscall.h */
/* begin v850 sys target macros */
{ "SYS_ARG", 24 },
{ "SYS_chdir", 12 },
{ "SYS_chmod", 15 },
{ "SYS_chown", 16 },
{ "SYS_close", 6 },
{ "SYS_creat", 8 },
{ "SYS_execv", 11 },
{ "SYS_execve", 59 },
{ "SYS_exit", 1 },
{ "SYS_fork", 2 },
{ "SYS_fstat", 22 },
{ "SYS_getpid", 20 },
{ "SYS_gettimeofday", 116 },
{ "SYS_isatty", 21 },
{ "SYS_link", 9 },
{ "SYS_lseek", 19 },
{ "SYS_mknod", 14 },
{ "SYS_open", 5 },
{ "SYS_pipe", 42 },
{ "SYS_read", 3 },
{ "SYS_stat", 38 },
{ "SYS_time", 23 },
{ "SYS_unlink", 10 },
{ "SYS_utime", 201 },
{ "SYS_wait", 202 },
{ "SYS_wait4", 7 },
{ "SYS_write", 4 },
/* end v850 sys target macros */
#endif
#endif

214
sim/common/nrun.c Normal file
View File

@@ -0,0 +1,214 @@
/* New version of run front end support for simulators.
Copyright (C) 1997 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <signal.h>
#include "sim-main.h"
#include "bfd.h"
#ifdef HAVE_ENVIRON
extern char **environ;
#endif
static void usage (void);
extern host_callback default_callback;
static char *myname;
static SIM_DESC sd;
static RETSIGTYPE
cntrl_c (int sig)
{
if (! sim_stop (sd))
{
fprintf (stderr, "Quit!\n");
exit (1);
}
}
int
main (int argc, char **argv)
{
char *name;
char **prog_argv = NULL;
struct _bfd *prog_bfd;
enum sim_stop reason;
int sigrc = 0;
int single_step = 0;
RETSIGTYPE (*prev_sigint) ();
myname = argv[0] + strlen (argv[0]);
while (myname > argv[0] && myname[-1] != '/')
--myname;
/* INTERNAL: When MYNAME is `step', single step the simulator
instead of allowing it to run free. The sole purpose of this
HACK is to allow the sim_resume interface's step argument to be
tested without having to build/run gdb. */
if (strlen (myname) > 4 && strcmp (myname - 4, "step") == 0)
{
single_step = 1;
}
/* Create an instance of the simulator. */
default_callback.init (&default_callback);
sd = sim_open (SIM_OPEN_STANDALONE, &default_callback, NULL, argv);
if (sd == 0)
exit (1);
if (STATE_MAGIC (sd) != SIM_MAGIC_NUMBER)
{
fprintf (stderr, "Internal error - bad magic number in simulator struct\n");
abort ();
}
/* Was there a program to run? */
prog_argv = STATE_PROG_ARGV (sd);
prog_bfd = STATE_PROG_BFD (sd);
if (prog_argv == NULL || *prog_argv == NULL)
usage ();
name = *prog_argv;
/* For simulators that don't open prog during sim_open() */
if (prog_bfd == NULL)
{
prog_bfd = bfd_openr (name, 0);
if (prog_bfd == NULL)
{
fprintf (stderr, "%s: can't open \"%s\": %s\n",
myname, name, bfd_errmsg (bfd_get_error ()));
exit (1);
}
if (!bfd_check_format (prog_bfd, bfd_object))
{
fprintf (stderr, "%s: \"%s\" is not an object file: %s\n",
myname, name, bfd_errmsg (bfd_get_error ()));
exit (1);
}
}
if (STATE_VERBOSE_P (sd))
printf ("%s %s\n", myname, name);
/* Load the program into the simulator. */
if (sim_load (sd, name, prog_bfd, 0) == SIM_RC_FAIL)
exit (1);
/* Prepare the program for execution. */
#ifdef HAVE_ENVIRON
sim_create_inferior (sd, prog_bfd, prog_argv, environ);
#else
sim_create_inferior (sd, prog_bfd, prog_argv, NULL);
#endif
/* Run/Step the program. */
if (single_step)
{
do
{
prev_sigint = signal (SIGINT, cntrl_c);
sim_resume (sd, 1/*step*/, 0);
signal (SIGINT, prev_sigint);
sim_stop_reason (sd, &reason, &sigrc);
if ((reason == sim_stopped) &&
(sigrc == sim_signal_to_host (sd, SIM_SIGINT)))
break; /* exit on control-C */
}
/* remain on breakpoint or signals in oe mode*/
while (((reason == sim_signalled) &&
(sigrc == sim_signal_to_host (sd, SIM_SIGTRAP))) ||
((reason == sim_stopped) &&
(STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)));
}
else do
{
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
struct sigaction sa, osa;
sa.sa_handler = cntrl_c;
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGINT, &sa, &osa);
prev_sigint = osa.sa_handler;
#else
prev_sigint = signal (SIGINT, cntrl_c);
#endif
sim_resume (sd, 0, sigrc);
signal (SIGINT, prev_sigint);
sim_stop_reason (sd, &reason, &sigrc);
if ((reason == sim_stopped) &&
(sigrc == sim_signal_to_host (sd, SIM_SIGINT)))
break; /* exit on control-C */
/* remain on signals in oe mode */
} while ((reason == sim_stopped) &&
(STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT));
/* Print any stats the simulator collected. */
sim_info (sd, 0);
/* Shutdown the simulator. */
sim_close (sd, 0);
/* If reason is sim_exited, then sigrc holds the exit code which we want
to return. If reason is sim_stopped or sim_signalled, then sigrc holds
the signal that the simulator received; we want to return that to
indicate failure. */
#ifdef SIM_H8300 /* FIXME: Ugh. grep for SLEEP in compile.c */
if (sigrc == SIGILL)
abort ();
sigrc = 0;
#else
/* Why did we stop? */
switch (reason)
{
case sim_signalled:
case sim_stopped:
if (sigrc != 0)
fprintf (stderr, "program stopped with signal %d.\n", sigrc);
break;
case sim_exited:
break;
default:
fprintf (stderr, "program in undefined state (%d:%d)\n", reason, sigrc);
break;
}
#endif
return sigrc;
}
static void
usage ()
{
fprintf (stderr, "Usage: %s [options] program [program args]\n", myname);
fprintf (stderr, "Run `%s --help' for full list of options.\n", myname);
exit (1);
}
#ifdef __CYGWIN32__
/* no-op GUI update hook for standalone sim */
void (*ui_loop_hook) PARAMS ((int)) = NULL;
#endif

107
sim/common/run.1 Normal file
View File

@@ -0,0 +1,107 @@
.\" Copyright (c) 1993 Free Software Foundation
.\" See section COPYING for conditions for redistribution
.TH run 1 "13oct1993" "GNU Tools" "GNU Tools"
.de BP
.sp
.ti -.2i
\(**
..
.SH NAME
run\(em\&Simulator front-end
.SH SYNOPSIS
.hy 0
.na
.TP
.B run
.RB "[\|" \-v "\|]"
." .RB "[\|" \-t "\|]"
.RB "[\|" \-p
.IR freq "\|]"
.RB "[\|" \-m
.IR memory "\|]"
.I program
.ad b
.hy 1
.SH DESCRIPTION
Use `\|\c
.BI run " program"\c
\&\|' to execute a binary by interpreting machine instructions on your
host computer.
.B run
is the same emulator used by GDB's `\|\c
.B target sim\c
\&\|' command. You can run it directly by executing
.B run
if you just want to see your program execute, and do not need any
debugger functionality. You can also use
.B run
to generate profiling information for analysis with
.BR gprof .
.SH OPTIONS
.TP
.B \-v
Verbose output. Display the name of the program to run before
execution; after execution, display the number of instructions
executed, the number of machine cycles emulated, the number of
pipeline stalls, the real time taken, the emulated execution time
taken, and a summary of how much profiling information was generated.
."
." .TP
." .B \-t
." `trace', calls a sim_trace routine that does nothing.
.TP
.BI \-p " freq"
Generate profile information (for use with
.B gprof\c
\&).
.I freq
is the profiling frequency. Write the profiling information to a file called
.BR gmon.out .
.TP
.BI \-m " memory"
Set the memory size for the emulated machine to two to the power
.IR memory .
The default value is 19, emulating a board with 524288 bytes of memory.
.PP
.SH "SEE ALSO"
.RB "`\|" gprof "\|'"
entry in
.B info\c
\&;
.RB "`\|" gdb "\|'"
entry in
.B info\c
\&;
.I
Using GDB: A Guide to the GNU Source-Level Debugger\c
, Richard M. Stallman and Roland H. Pesch.
.SH COPYING
Copyright (c) 1993 Free Software Foundation, Inc.
.PP
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
.PP
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the
entire resulting derived work is distributed under the terms of a
permission notice identical to this one.
.PP
Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be included in
translations approved by the Free Software Foundation instead of in
the original English.

308
sim/common/run.c Normal file
View File

@@ -0,0 +1,308 @@
/* run front end support for all the simulators.
Copyright (C) 1992, 93-96, 1997 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Steve Chamberlain sac@cygnus.com,
and others at Cygnus. */
#include "config.h"
#include "tconfig.h"
#include <signal.h>
#include <stdio.h>
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#include "libiberty.h"
#include "bfd.h"
#include "callback.h"
#include "remote-sim.h"
#include "../libiberty/alloca-conf.h"
static void usage PARAMS ((void));
extern int optind;
extern char *optarg;
extern host_callback default_callback;
static char *myname;
/* NOTE: sim_size() and sim_trace() are going away */
extern int sim_trace PARAMS ((SIM_DESC sd));
extern int getopt ();
static SIM_DESC sd;
static RETSIGTYPE
cntrl_c (int sig)
{
if (! sim_stop (sd))
{
fprintf (stderr, "Quit!\n");
exit (1);
}
}
int
main (ac, av)
int ac;
char **av;
{
RETSIGTYPE (*prev_sigint) ();
bfd *abfd;
int i;
int verbose = 0;
int trace = 0;
char *name;
static char *no_args[4];
char **sim_argv = &no_args[0];
char **prog_args;
enum sim_stop reason;
int sigrc;
myname = av[0] + strlen (av[0]);
while (myname > av[0] && myname[-1] != '/')
--myname;
/* The first element of sim_open's argv is the program name. */
no_args[0] = av[0];
#ifdef SIM_HAVE_BIENDIAN
no_args[1] = "-E";
no_args[2] = "set-later";
#endif
/* FIXME: This is currently being migrated into sim_open.
Simulators that use functions such as sim_size() still require
this. */
default_callback.init (&default_callback);
sim_set_callbacks (&default_callback);
/* FIXME: This is currently being rewritten to have each simulator
do all argv processing. */
#ifdef SIM_H8300 /* FIXME: quick hack */
while ((i = getopt (ac, av, "a:c:m:p:s:htv")) != EOF)
#else
while ((i = getopt (ac, av, "a:c:m:p:s:tv")) != EOF)
#endif
switch (i)
{
case 'a':
/* FIXME: Temporary hack. */
{
int len = strlen (av[0]) + strlen (optarg);
char *argbuf = (char *) alloca (len + 2 + 50);
sprintf (argbuf, "%s %s", av[0], optarg);
#ifdef SIM_HAVE_BIENDIAN
/* The desired endianness must be passed to sim_open.
The value for "set-later" is set when we know what it is.
-E support isn't yet part of the published interface. */
strcat (argbuf, " -E set-later");
#endif
sim_argv = buildargv (argbuf);
}
break;
#ifdef SIM_HAVE_SIMCACHE
case 'c':
sim_set_simcache_size (atoi (optarg));
break;
#endif
case 'm':
/* FIXME: Rename to sim_set_mem_size. */
sim_size (atoi (optarg));
break;
#ifdef SIM_HAVE_PROFILE
case 'p':
sim_set_profile (atoi (optarg));
break;
case 's':
sim_set_profile_size (atoi (optarg));
break;
#endif
case 't':
trace = 1;
/* FIXME: need to allow specification of what to trace. */
/* sim_set_trace (1); */
break;
case 'v':
/* Things that are printed with -v are the kinds of things that
gcc -v prints. This is not meant to include detailed tracing
or debugging information, just summaries. */
verbose = 1;
/* sim_set_verbose (1); */
break;
/* FIXME: Quick hack, to be replaced by more general facility. */
#ifdef SIM_H8300
case 'h':
set_h8300h (1);
break;
#endif
default:
usage ();
}
ac -= optind;
av += optind;
if (ac <= 0)
usage ();
name = *av;
prog_args = av;
if (verbose)
{
printf ("%s %s\n", myname, name);
}
abfd = bfd_openr (name, 0);
if (!abfd)
{
fprintf (stderr, "%s: can't open %s: %s\n",
myname, name, bfd_errmsg (bfd_get_error ()));
exit (1);
}
if (!bfd_check_format (abfd, bfd_object))
{
fprintf (stderr, "%s: can't load %s: %s\n",
myname, name, bfd_errmsg (bfd_get_error ()));
exit (1);
}
#ifdef SIM_HAVE_BIENDIAN
/* The endianness must be passed to sim_open because one may wish to
examine/set registers before calling sim_load [which is the other
place where one can determine endianness]. We previously passed the
endianness via global `target_byte_order' but that's not a clean
interface. */
for (i = 1; sim_argv[i + 1] != NULL; ++i)
continue;
if (bfd_big_endian (abfd))
sim_argv[i] = "big";
else
sim_argv[i] = "little";
#endif
/* Ensure that any run-time initialisation that needs to be
performed by the simulator can occur. */
sd = sim_open (SIM_OPEN_STANDALONE, &default_callback, abfd, sim_argv);
if (sd == 0)
exit (1);
if (sim_load (sd, name, abfd, 0) == SIM_RC_FAIL)
exit (1);
if (sim_create_inferior (sd, abfd, prog_args, NULL) == SIM_RC_FAIL)
exit (1);
prev_sigint = signal (SIGINT, cntrl_c);
if (trace)
{
int done = 0;
while (!done)
{
done = sim_trace (sd);
}
}
else
{
sim_resume (sd, 0, 0);
}
signal (SIGINT, prev_sigint);
if (verbose)
sim_info (sd, 0);
sim_stop_reason (sd, &reason, &sigrc);
sim_close (sd, 0);
/* If reason is sim_exited, then sigrc holds the exit code which we want
to return. If reason is sim_stopped or sim_signalled, then sigrc holds
the signal that the simulator received; we want to return that to
indicate failure. */
#ifdef SIM_H8300 /* FIXME: Ugh. grep for SLEEP in compile.c */
if (sigrc == SIGILL)
abort ();
sigrc = 0;
#else
/* Why did we stop? */
switch (reason)
{
case sim_signalled:
case sim_stopped:
if (sigrc != 0)
fprintf (stderr, "program stopped with signal %d.\n", sigrc);
break;
case sim_exited:
break;
case sim_running:
case sim_polling: /* these indicate a serious problem */
abort ();
break;
}
#endif
return sigrc;
}
static void
usage ()
{
fprintf (stderr, "Usage: %s [options] program [program args]\n", myname);
fprintf (stderr, "Options:\n");
fprintf (stderr, "-a args Pass `args' to simulator.\n");
#ifdef SIM_HAVE_SIMCACHE
fprintf (stderr, "-c size Set simulator cache size to `size'.\n");
#endif
#ifdef SIM_H8300
fprintf (stderr, "-h Executable is for h8/300h or h8/300s.\n");
#endif
fprintf (stderr, "-m size Set memory size of simulator, in bytes.\n");
#ifdef SIM_HAVE_PROFILE
fprintf (stderr, "-p freq Set profiling frequency.\n");
fprintf (stderr, "-s size Set profiling size.\n");
#endif
fprintf (stderr, "-t Perform instruction tracing.\n");
fprintf (stderr, " Note: Very few simulators support tracing.\n");
fprintf (stderr, "-v Verbose output.\n");
fprintf (stderr, "\n");
fprintf (stderr, "program args Arguments to pass to simulated program.\n");
fprintf (stderr, " Note: Very few simulators support this.\n");
exit (1);
}

60
sim/common/sim-abort.c Normal file
View File

@@ -0,0 +1,60 @@
/* Generic simulator abort.
Copyright (C) 1997 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include "sim-main.h"
#include "sim-assert.h"
/* This is an implementation of sim_engine_abort that does not use
longjmp, instead it just calls sim_io_error. sim_io_error will
jump right out of the simulator.
It is intended as a holder for simulators that have started to use
sim-core et.al. but are not yet in a position to use sim-engine
(the setjmp/longjmp code). */
void
sim_engine_abort (SIM_DESC sd,
sim_cpu *cpu,
sim_cia cia,
const char *fmt,
...)
{
ASSERT (sd == NULL || STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
if (sd != NULL)
{
va_list ap;
va_start(ap, fmt);
sim_io_evprintf (sd, fmt, ap);
va_end(ap);
sim_io_error (sd, "\n");
}
else
{
va_list ap;
va_start(ap, fmt);
vfprintf (stderr, fmt, ap);
va_end(ap);
fprintf (stderr, "\n");
abort ();
}
}

1047
sim/common/sim-alu.h Normal file

File diff suppressed because it is too large Load Diff

301
sim/common/sim-arange.c Normal file
View File

@@ -0,0 +1,301 @@
/* Address ranges.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of the GNU Simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Tell sim-arange.h it's us. */
#define SIM_ARANGE_C
#include "libiberty.h"
#include "sim-basics.h"
#include "sim-assert.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#define DEFINE_INLINE_P (! defined (SIM_ARANGE_C_INCLUDED))
#define DEFINE_NON_INLINE_P defined (SIM_ARANGE_C_INCLUDED)
#if DEFINE_NON_INLINE_P
/* Insert a range. */
static void
insert_range (ADDR_SUBRANGE **pos, ADDR_SUBRANGE *asr)
{
asr->next = *pos;
*pos = asr;
}
/* Delete a range. */
static void
delete_range (ADDR_SUBRANGE **thisasrp)
{
ADDR_SUBRANGE *thisasr;
thisasr = *thisasrp;
*thisasrp = thisasr->next;
free (thisasr);
}
/* Add or delete an address range.
This code was borrowed from linux's locks.c:posix_lock_file().
??? Todo: Given our simpler needs this could be simplified
(split into two fns). */
static void
frob_range (ADDR_RANGE *ar, address_word start, address_word end, int delete_p)
{
ADDR_SUBRANGE *asr;
ADDR_SUBRANGE *new_asr, *new_asr2;
ADDR_SUBRANGE *left = NULL;
ADDR_SUBRANGE *right = NULL;
ADDR_SUBRANGE **before;
ADDR_SUBRANGE init_caller;
ADDR_SUBRANGE *caller = &init_caller;
int added_p = 0;
memset (caller, 0, sizeof (ADDR_SUBRANGE));
new_asr = ZALLOC (ADDR_SUBRANGE);
new_asr2 = ZALLOC (ADDR_SUBRANGE);
caller->start = start;
caller->end = end;
before = &ar->ranges;
while ((asr = *before) != NULL)
{
if (! delete_p)
{
/* Try next range if current range preceeds new one and not
adjacent or overlapping. */
if (asr->end < caller->start - 1)
goto next_range;
/* Break out if new range preceeds current one and not
adjacent or overlapping. */
if (asr->start > caller->end + 1)
break;
/* If we come here, the new and current ranges are adjacent or
overlapping. Make one range yielding from the lower start address
of both ranges to the higher end address. */
if (asr->start > caller->start)
asr->start = caller->start;
else
caller->start = asr->start;
if (asr->end < caller->end)
asr->end = caller->end;
else
caller->end = asr->end;
if (added_p)
{
delete_range (before);
continue;
}
caller = asr;
added_p = 1;
}
else /* deleting a range */
{
/* Try next range if current range preceeds new one. */
if (asr->end < caller->start)
goto next_range;
/* Break out if new range preceeds current one. */
if (asr->start > caller->end)
break;
added_p = 1;
if (asr->start < caller->start)
left = asr;
/* If the next range in the list has a higher end
address than the new one, insert the new one here. */
if (asr->end > caller->end)
{
right = asr;
break;
}
if (asr->start >= caller->start)
{
/* The new range completely replaces an old
one (This may happen several times). */
if (added_p)
{
delete_range (before);
continue;
}
/* Replace the old range with the new one. */
asr->start = caller->start;
asr->end = caller->end;
caller = asr;
added_p = 1;
}
}
/* Go on to next range. */
next_range:
before = &asr->next;
}
if (!added_p)
{
if (delete_p)
goto out;
new_asr->start = caller->start;
new_asr->end = caller->end;
insert_range (before, new_asr);
new_asr = NULL;
}
if (right)
{
if (left == right)
{
/* The new range breaks the old one in two pieces,
so we have to use the second new range. */
new_asr2->start = right->start;
new_asr2->end = right->end;
left = new_asr2;
insert_range (before, left);
new_asr2 = NULL;
}
right->start = caller->end + 1;
}
if (left)
{
left->end = caller->start - 1;
}
out:
if (new_asr)
free(new_asr);
if (new_asr2)
free(new_asr2);
}
/* Free T and all subtrees. */
static void
free_search_tree (ADDR_RANGE_TREE *t)
{
if (t != NULL)
{
free_search_tree (t->lower);
free_search_tree (t->higher);
free (t);
}
}
/* Subroutine of build_search_tree to recursively build a balanced tree.
??? It's not an optimum tree though. */
static ADDR_RANGE_TREE *
build_tree_1 (ADDR_SUBRANGE **asrtab, unsigned int n)
{
unsigned int mid = n / 2;
ADDR_RANGE_TREE *t;
if (n == 0)
return NULL;
t = (ADDR_RANGE_TREE *) xmalloc (sizeof (ADDR_RANGE_TREE));
t->start = asrtab[mid]->start;
t->end = asrtab[mid]->end;
if (mid != 0)
t->lower = build_tree_1 (asrtab, mid);
else
t->lower = NULL;
if (n > mid + 1)
t->higher = build_tree_1 (asrtab + mid + 1, n - mid - 1);
else
t->higher = NULL;
return t;
}
/* Build a search tree for address range AR. */
static void
build_search_tree (ADDR_RANGE *ar)
{
/* ??? Simple version for now. */
ADDR_SUBRANGE *asr,**asrtab;
unsigned int i, n;
for (n = 0, asr = ar->ranges; asr != NULL; ++n, asr = asr->next)
continue;
asrtab = (ADDR_SUBRANGE **) xmalloc (n * sizeof (ADDR_SUBRANGE *));
for (i = 0, asr = ar->ranges; i < n; ++i, asr = asr->next)
asrtab[i] = asr;
ar->range_tree = build_tree_1 (asrtab, n);
free (asrtab);
}
void
sim_addr_range_add (ADDR_RANGE *ar, address_word start, address_word end)
{
frob_range (ar, start, end, 0);
/* Rebuild the search tree. */
/* ??? Instead of rebuilding it here it could be done in a module resume
handler, say by first checking for a `changed' flag, assuming of course
this would never be done while the simulation is running. */
free_search_tree (ar->range_tree);
build_search_tree (ar);
}
void
sim_addr_range_delete (ADDR_RANGE *ar, address_word start, address_word end)
{
frob_range (ar, start, end, 1);
/* Rebuild the search tree. */
/* ??? Instead of rebuilding it here it could be done in a module resume
handler, say by first checking for a `changed' flag, assuming of course
this would never be done while the simulation is running. */
free_search_tree (ar->range_tree);
build_search_tree (ar);
}
#endif /* DEFINE_NON_INLINE_P */
#if DEFINE_INLINE_P
SIM_ARANGE_INLINE int
sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
{
ADDR_RANGE_TREE *t = ar->range_tree;
while (t != NULL)
{
if (addr < t->start)
t = t->lower;
else if (addr > t->end)
t = t->higher;
else
return 1;
}
return 0;
}
#endif /* DEFINE_INLINE_P */

83
sim/common/sim-arange.h Normal file
View File

@@ -0,0 +1,83 @@
/* Address ranges.
Copyright (C) 1998 Free Software Foundation, Inc.
Contributed by Cygnus Solutions.
This file is part of the GNU Simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file is meant to be included by sim-basics.h. */
#ifndef SIM_ARANGE_H
#define SIM_ARANGE_H
/* A list of address ranges. */
typedef struct _addr_subrange {
struct _addr_subrange *next;
/* Range of addresses to be traced is [start,end]. */
address_word start,end;
} ADDR_SUBRANGE;
/* For speed, searching is done on a tree. */
typedef struct _addr_range_tree {
struct _addr_range_tree *lower;
struct _addr_range_tree *higher;
/* Range of addresses to be traced is [start,end]. */
address_word start,end;
} ADDR_RANGE_TREE;
/* The top level struct. */
typedef struct _addr_range {
ADDR_SUBRANGE *ranges;
#define ADDR_RANGE_RANGES(ar) ((ar)->ranges)
ADDR_RANGE_TREE *range_tree;
#define ADDR_RANGE_TREE(ar) ((ar)->range_tree)
} ADDR_RANGE;
/* Add address range START,END to AR. */
extern void sim_addr_range_add (ADDR_RANGE * /*ar*/,
address_word /*start*/,
address_word /*end*/);
/* Delete address range START,END from AR. */
extern void sim_addr_range_delete (ADDR_RANGE * /*ar*/,
address_word /*start*/,
address_word /*end*/);
/* Return non-zero if ADDR is in range AR, traversing the entire tree.
If no range is specified, that is defined to mean "everything". */
extern INLINE int
sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/);
#define ADDR_RANGE_HIT_P(ar, addr) \
((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr)))
#ifdef HAVE_INLINE
#ifdef SIM_ARANGE_C
#define SIM_ARANGE_INLINE INLINE
#else
#define SIM_ARANGE_INLINE EXTERN_INLINE
#endif
#include "sim-arange.c"
#else
#define SIM_ARANGE_INLINE
#endif
#define SIM_ARANGE_C_INCLUDED
#endif /* SIM_ARANGE_H */

90
sim/common/sim-assert.h Normal file
View File

@@ -0,0 +1,90 @@
/* This file is part of the program GDB.
Copyright (C) 1997, Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _SIM_ASSERT_H_
#define _SIM_ASSERT_H_
#define SIM_FILTER_PATH(FILE, PATH) \
do \
{ \
/* strip leading path */ \
const char *p = (PATH); \
(FILE) = p; \
while (*p != '\0' && *p != ':') \
{ \
if (*p == '/') \
(FILE) = p + 1; \
p++; \
} \
} \
while (0)
/* The subtle difference between SIM_ASSERT and ASSERT is that
SIM_ASSERT passes `sd' to sim_io_error for the SIM_DESC,
ASSERT passes NULL. */
#if !defined (SIM_ASSERT)
#if defined (WITH_ASSERT)
#define SIM_ASSERT(EXPRESSION) \
do \
{ \
if (WITH_ASSERT) \
{ \
if (!(EXPRESSION)) \
{ \
/* report the failure */ \
const char *file; \
SIM_FILTER_PATH(file, __FILE__); \
sim_io_error (sd, "%s:%d: assertion failed - %s", \
file, __LINE__, #EXPRESSION); \
} \
} \
} \
while (0)
#else
#define SIM_ASSERT(EXPRESSION) do { /*nothing*/; } while (0)
#endif
#endif
#if !defined (ASSERT)
#if defined (WITH_ASSERT)
#define ASSERT(EXPRESSION) \
do \
{ \
if (WITH_ASSERT) \
{ \
if (!(EXPRESSION)) \
{ \
/* report the failure */ \
const char *file; \
SIM_FILTER_PATH(file, __FILE__); \
sim_io_error (NULL, "%s:%d: assertion failed - %s", \
file, __LINE__, #EXPRESSION); \
} \
} \
} \
while (0)
#else
#define ASSERT(EXPRESSION) do { /*nothing*/; } while (0)
#endif
#endif
#endif

252
sim/common/sim-base.h Normal file
View File

@@ -0,0 +1,252 @@
/* Simulator pseudo baseclass.
Copyright (C) 1997-1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Simulator state pseudo baseclass.
Each simulator is required to have the file ``sim-main.h''. That
file includes ``sim-basics.h'', defines the base type ``sim_cia''
(the data type that contains complete current instruction address
information), include ``sim-base.h'':
#include "sim-basics.h"
typedef address_word sim_cia;
/-* If `sim_cia' is not an integral value (e.g. a struct), define
CIA_ADDR to return the integral value. *-/
/-* #define CIA_ADDR(cia) (...) *-/
#include "sim-base.h"
finally, two data types `struct _sim_cpu' and `struct sim_state'
are defined:
struct _sim_cpu {
... simulator specific members ...
sim_cpu_base base;
};
struct sim_state {
sim_cpu cpu[MAX_NR_PROCESSORS];
#if (WITH_SMP)
#define STATE_CPU(sd,n) (&(sd)->cpu[n])
#else
#define STATE_CPU(sd,n) (&(sd)->cpu[0])
#endif
... simulator specific members ...
sim_state_base base;
};
Note that `base' appears last. This makes `base.magic' appear last
in the entire struct and helps catch miscompilation errors. */
#ifndef SIM_BASE_H
#define SIM_BASE_H
/* Pre-declare certain types. */
/* typedef <target-dependant> sim_cia; */
#ifndef NULL_CIA
#define NULL_CIA ((sim_cia) 0)
#endif
/* Return the current instruction address as a number.
Some targets treat the current instruction address as a struct
(e.g. for delay slot handling). */
#ifndef CIA_ADDR
#define CIA_ADDR(cia) (cia)
#endif
#ifndef INVALID_INSTRUCTION_ADDRESS
#define INVALID_INSTRUCTION_ADDRESS ((address_word)0 - 1)
#endif
typedef struct _sim_cpu sim_cpu;
#include "sim-module.h"
#include "sim-trace.h"
#include "sim-core.h"
#include "sim-events.h"
#include "sim-profile.h"
#ifdef SIM_HAVE_MODEL
#include "sim-model.h"
#endif
#include "sim-io.h"
#include "sim-engine.h"
#include "sim-watch.h"
#include "sim-memopt.h"
#ifdef SIM_HAVE_BREAKPOINTS
#include "sim-break.h"
#endif
#include "sim-cpu.h"
/* Global pointer to current state while sim_resume is running.
On a machine with lots of registers, it might be possible to reserve
one of them for current_state. However on a machine with few registers
current_state can't permanently live in one and indirecting through it
will be slower [in which case one can have sim_resume set globals from
current_state for faster access].
If CURRENT_STATE_REG is defined, it means current_state is living in
a global register. */
#ifdef CURRENT_STATE_REG
/* FIXME: wip */
#else
extern struct sim_state *current_state;
#endif
/* The simulator may provide different (and faster) definition. */
#ifndef CURRENT_STATE
#define CURRENT_STATE current_state
#endif
typedef struct {
/* Simulator's argv[0]. */
const char *my_name;
#define STATE_MY_NAME(sd) ((sd)->base.my_name)
/* Who opened the simulator. */
SIM_OPEN_KIND open_kind;
#define STATE_OPEN_KIND(sd) ((sd)->base.open_kind)
/* The host callbacks. */
struct host_callback_struct *callback;
#define STATE_CALLBACK(sd) ((sd)->base.callback)
/* The type of simulation environment (user/operating). */
enum sim_environment environment;
#define STATE_ENVIRONMENT(sd) ((sd)->base.environment)
#if 0 /* FIXME: Not ready yet. */
/* Stuff defined in sim-config.h. */
struct sim_config config;
#define STATE_CONFIG(sd) ((sd)->base.config)
#endif
/* List of installed module `init' handlers. */
struct module_list *modules;
#define STATE_MODULES(sd) ((sd)->base.modules)
/* Supported options. */
struct option_list *options;
#define STATE_OPTIONS(sd) ((sd)->base.options)
/* Non-zero if -v specified. */
int verbose_p;
#define STATE_VERBOSE_P(sd) ((sd)->base.verbose_p)
/* Non cpu-specific trace data. See sim-trace.h. */
TRACE_DATA trace_data;
#define STATE_TRACE_DATA(sd) (& (sd)->base.trace_data)
/* If non NULL, the BFD architecture specified on the command line */
const struct bfd_arch_info *architecture;
#define STATE_ARCHITECTURE(sd) ((sd)->base.architecture)
/* If non NULL, the bfd target specified on the command line */
const char *target;
#define STATE_TARGET(sd) ((sd)->base.target)
/* In standalone simulator, this is the program's arguments passed
on the command line. */
char **prog_argv;
#define STATE_PROG_ARGV(sd) ((sd)->base.prog_argv)
/* The program's bfd. */
struct _bfd *prog_bfd;
#define STATE_PROG_BFD(sd) ((sd)->base.prog_bfd)
/* Symbol table for prog_bfd */
struct symbol_cache_entry **prog_syms;
#define STATE_PROG_SYMS(sd) ((sd)->base.prog_syms)
/* The program's text section. */
struct sec *text_section;
/* Starting and ending text section addresses from the bfd. */
SIM_ADDR text_start, text_end;
#define STATE_TEXT_SECTION(sd) ((sd)->base.text_section)
#define STATE_TEXT_START(sd) ((sd)->base.text_start)
#define STATE_TEXT_END(sd) ((sd)->base.text_end)
/* Start address, set when the program is loaded from the bfd. */
SIM_ADDR start_addr;
#define STATE_START_ADDR(sd) ((sd)->base.start_addr)
/* Size of the simulator's cache, if any.
This is not the target's cache. It is the cache the simulator uses
to process instructions. */
unsigned int scache_size;
#define STATE_SCACHE_SIZE(sd) ((sd)->base.scache_size)
/* FIXME: Move to top level sim_state struct (as some struct)? */
#ifdef SIM_HAVE_FLATMEM
unsigned int mem_size;
#define STATE_MEM_SIZE(sd) ((sd)->base.mem_size)
unsigned int mem_base;
#define STATE_MEM_BASE(sd) ((sd)->base.mem_base)
unsigned char *memory;
#define STATE_MEMORY(sd) ((sd)->base.memory)
#endif
/* core memory bus */
#define STATE_CORE(sd) (&(sd)->base.core)
sim_core core;
/* Record of memory sections added via the memory-options interface. */
#define STATE_MEMOPT(sd) ((sd)->base.memopt)
sim_memopt *memopt;
/* event handler */
#define STATE_EVENTS(sd) (&(sd)->base.events)
sim_events events;
/* generic halt/resume engine */
sim_engine engine;
#define STATE_ENGINE(sd) (&(sd)->base.engine)
/* generic watchpoint support */
sim_watchpoints watchpoints;
#define STATE_WATCHPOINTS(sd) (&(sd)->base.watchpoints)
/* Pointer to list of breakpoints */
struct sim_breakpoint *breakpoints;
#define STATE_BREAKPOINTS(sd) ((sd)->base.breakpoints)
#if WITH_HW
struct sim_hw *hw;
#define STATE_HW(sd) ((sd)->base.hw)
#endif
/* Marker for those wanting to do sanity checks.
This should remain the last member of this struct to help catch
miscompilation errors. */
int magic;
#define SIM_MAGIC_NUMBER 0x4242
#define STATE_MAGIC(sd) ((sd)->base.magic)
} sim_state_base;
/* Functions for allocating/freeing a sim_state. */
SIM_DESC sim_state_alloc PARAMS ((SIM_OPEN_KIND kind, host_callback *callback));
void sim_state_free PARAMS ((SIM_DESC));
#endif /* SIM_BASE_H */

Some files were not shown because too many files have changed in this diff Show More