forked from Imagelibrary/binutils-gdb
Initial creation of sourceware repository
This commit is contained in:
461
sim/ChangeLog
Normal file
461
sim/ChangeLog
Normal 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
254
sim/Makefile.in
Normal 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
254
sim/README-HACKING
Normal 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
340
sim/arm/COPYING
Normal 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
426
sim/arm/ChangeLog
Normal 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
48
sim/arm/Makefile.in
Normal 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
27
sim/arm/README.Cygnus
Normal 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
15
sim/arm/acconfig.h
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
/* Define to 1 if NLS is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define as 1 if you have catgets and don't want to use GNU gettext. */
|
||||
#undef HAVE_CATGETS
|
||||
|
||||
/* Define as 1 if you have gettext and don't want to use GNU gettext. */
|
||||
#undef HAVE_GETTEXT
|
||||
|
||||
/* Define as 1 if you have the stpcpy function. */
|
||||
#undef HAVE_STPCPY
|
||||
|
||||
/* Define if your locale.h file contains LC_MESSAGES. */
|
||||
#undef HAVE_LC_MESSAGES
|
||||
357
sim/arm/armcopro.c
Normal file
357
sim/arm/armcopro.c
Normal 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
353
sim/arm/armdefs.h
Normal 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
3454
sim/arm/armemu.c
Normal file
File diff suppressed because it is too large
Load Diff
425
sim/arm/armemu.h
Normal file
425
sim/arm/armemu.h
Normal 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
1351
sim/arm/armfpe.h
Normal file
File diff suppressed because it is too large
Load Diff
294
sim/arm/arminit.c
Normal file
294
sim/arm/arminit.c
Normal 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
23
sim/arm/armopts.h
Normal 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
1136
sim/arm/armos.c
Normal file
File diff suppressed because it is too large
Load Diff
95
sim/arm/armos.h
Normal file
95
sim/arm/armos.h
Normal 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
1044
sim/arm/armrdi.c
Normal file
File diff suppressed because it is too large
Load Diff
712
sim/arm/armsupp.c
Normal file
712
sim/arm/armsupp.c
Normal 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
491
sim/arm/armvirt.c
Normal 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
141
sim/arm/bag.c
Normal 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
42
sim/arm/bag.h
Normal 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
221
sim/arm/communicate.c
Normal 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
37
sim/arm/communicate.h
Normal 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
158
sim/arm/config.in
Normal 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
3892
sim/arm/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
10
sim/arm/configure.in
Normal file
10
sim/arm/configure.in
Normal 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
48
sim/arm/dbg_conf.h
Normal 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
62
sim/arm/dbg_cp.h
Normal 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
47
sim/arm/dbg_hif.h
Normal 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
323
sim/arm/dbg_rdi.h
Normal 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
107
sim/arm/gdbhost.c
Normal 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
23
sim/arm/gdbhost.h
Normal 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
510
sim/arm/kid.c
Normal 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
183
sim/arm/main.c
Normal 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
483
sim/arm/parent.c
Normal 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
17
sim/arm/tconfig.in
Normal 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
455
sim/arm/thumbemu.c
Normal 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
467
sim/arm/wrapper.c
Normal 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
4005
sim/common/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
642
sim/common/Make-common.in
Normal file
642
sim/common/Make-common.in
Normal 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
139
sim/common/Makefile.in
Normal 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
15
sim/common/acconfig.h
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
/* Define to 1 if NLS is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define as 1 if you have catgets and don't want to use GNU gettext. */
|
||||
#undef HAVE_CATGETS
|
||||
|
||||
/* Define as 1 if you have gettext and don't want to use GNU gettext. */
|
||||
#undef HAVE_GETTEXT
|
||||
|
||||
/* Define as 1 if you have the stpcpy function. */
|
||||
#undef HAVE_STPCPY
|
||||
|
||||
/* Define if your locale.h file contains LC_MESSAGES. */
|
||||
#undef HAVE_LC_MESSAGES
|
||||
1259
sim/common/aclocal.m4
vendored
Normal file
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
810
sim/common/callback.c
Normal 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
98
sim/common/cgen-cpu.h
Normal 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
174
sim/common/cgen-defs.h
Normal 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
473
sim/common/cgen-engine.h
Normal 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
203
sim/common/cgen-mem.h
Normal 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
897
sim/common/cgen-ops.h
Normal 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
233
sim/common/cgen-run.c
Normal 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
471
sim/common/cgen-scache.c
Normal 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
162
sim/common/cgen-scache.h
Normal 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
34
sim/common/cgen-sim.h
Normal 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
414
sim/common/cgen-trace.c
Normal 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
91
sim/common/cgen-trace.h
Normal 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
116
sim/common/cgen-types.h
Normal 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
328
sim/common/cgen-utils.c
Normal 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
167
sim/common/config.in
Normal 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
3902
sim/common/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
40
sim/common/configure.in
Normal file
40
sim/common/configure.in
Normal 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
118
sim/common/dv-core.c
Normal 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
373
sim/common/dv-glue.c
Normal 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
605
sim/common/dv-pal.c
Normal 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
386
sim/common/dv-sockser.c
Normal 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
32
sim/common/dv-sockser.h
Normal 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
10
sim/common/gdbinit.in
Normal 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
1122
sim/common/genmloop.sh
Normal file
File diff suppressed because it is too large
Load Diff
67
sim/common/gennltvals.sh
Normal file
67
sim/common/gennltvals.sh
Normal 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
125
sim/common/gentmap.c
Normal 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
74
sim/common/gentvals.sh
Normal 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
99
sim/common/hw-alloc.c
Normal 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
49
sim/common/hw-alloc.h
Normal 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
571
sim/common/hw-base.c
Normal 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_entry++)
|
||||
{
|
||||
unsigned_word attach_address;
|
||||
int attach_space;
|
||||
unsigned attach_size;
|
||||
if (!hw_unit_address_to_attach_address (hw_parent (hw),
|
||||
®.address,
|
||||
&attach_space,
|
||||
&attach_address,
|
||||
hw))
|
||||
continue;
|
||||
if (!hw_unit_size_to_attach_size (hw_parent (hw),
|
||||
®.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
109
sim/common/hw-base.h
Normal 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
66
sim/common/hw-device.c
Normal 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
535
sim/common/hw-device.h
Normal 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
263
sim/common/hw-events.c
Normal 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
61
sim/common/hw-events.h
Normal 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
237
sim/common/hw-handles.c
Normal 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
63
sim/common/hw-handles.h
Normal 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
285
sim/common/hw-instances.c
Normal 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
157
sim/common/hw-instances.h
Normal 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
73
sim/common/hw-main.h
Normal 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
339
sim/common/hw-ports.c
Normal 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
129
sim/common/hw-ports.h
Normal 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
905
sim/common/hw-properties.c
Normal 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 = ®s[i];
|
||||
/* copy the address */
|
||||
cell = unit_address_to_cells (®->address, cell,
|
||||
hw_unit_nr_address_cells (hw_parent (me)));
|
||||
/* copy the size */
|
||||
cell = unit_address_to_cells (®->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, ®->address,
|
||||
hw_unit_nr_address_cells (hw_parent (me)));
|
||||
|
||||
/* copy the size out - converting as we go */
|
||||
cells = cells_to_unit_address (cells, ®->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
244
sim/common/hw-properties.h
Normal 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
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
119
sim/common/hw-tree.h
Normal 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
418
sim/common/nltvals.def
Normal 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
214
sim/common/nrun.c
Normal 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
107
sim/common/run.1
Normal 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
308
sim/common/run.c
Normal 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
60
sim/common/sim-abort.c
Normal 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
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
301
sim/common/sim-arange.c
Normal 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
83
sim/common/sim-arange.h
Normal 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
90
sim/common/sim-assert.h
Normal 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
252
sim/common/sim-base.h
Normal 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
Reference in New Issue
Block a user