Add PowerPC simulator from Andrew Cagney <cagney@highland.com.au>
authorMichael Meissner <gnu@the-meissners.org>
Wed, 23 Aug 1995 21:06:36 +0000 (21:06 +0000)
committerMichael Meissner <gnu@the-meissners.org>
Wed, 23 Aug 1995 21:06:36 +0000 (21:06 +0000)
36 files changed:
sim/.Sanitize
sim/ChangeLog
sim/configure
sim/configure.in
sim/ppc/.Sanitize [new file with mode: 0644]
sim/ppc/COPYING [new file with mode: 0644]
sim/ppc/COPYING.LIB [new file with mode: 0644]
sim/ppc/ChangeLog [new file with mode: 0644]
sim/ppc/Makefile.in [new file with mode: 0644]
sim/ppc/README.psim [new file with mode: 0644]
sim/ppc/bits.h [new file with mode: 0644]
sim/ppc/configure.in [new file with mode: 0644]
sim/ppc/core.c [new file with mode: 0644]
sim/ppc/core.h [new file with mode: 0644]
sim/ppc/device_tree.c [new file with mode: 0644]
sim/ppc/device_tree.h [new file with mode: 0644]
sim/ppc/devices.c [new file with mode: 0644]
sim/ppc/devices.h [new file with mode: 0644]
sim/ppc/double.c [new file with mode: 0644]
sim/ppc/dp-bit.c [new file with mode: 0644]
sim/ppc/events.c [new file with mode: 0644]
sim/ppc/events.h [new file with mode: 0644]
sim/ppc/gen.c [new file with mode: 0644]
sim/ppc/idecode_branch.h [new file with mode: 0644]
sim/ppc/idecode_fields.h [new file with mode: 0644]
sim/ppc/idecode_insn.h [new file with mode: 0644]
sim/ppc/memory_map.c [new file with mode: 0644]
sim/ppc/memory_map.h [new file with mode: 0644]
sim/ppc/ppc-endian.c [new file with mode: 0644]
sim/ppc/ppc-endian.h [new file with mode: 0644]
sim/ppc/ppc.mt [new file with mode: 0644]
sim/ppc/sim_callbacks.h [new file with mode: 0644]
sim/ppc/system.c [new file with mode: 0644]
sim/ppc/system.h [new file with mode: 0644]
sim/ppc/vm.h [new file with mode: 0644]
sim/ppc/words.h [new file with mode: 0644]

index 73c9a377d119fa71c5dadabdcd68802ed7da4c40..747497341f80e26fe66d76679e6c3eb8b6906090 100644 (file)
@@ -30,6 +30,7 @@ configure
 configure.in
 h8300
 h8500
+ppc
 sh
 w65
 z8k
index fcd3f036ac0cfb2b2464ec95ee5b731f7f727490..a094a41d9fe468110c62e8a9478bc11ec22f3209 100644 (file)
@@ -1,5 +1,29 @@
+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.
 
index 4ad651e3d1e844ae587c7bd40b07c9a87eaffa19..a6c0eae517cedb4d3c11b09536b4c0a4177c9852 100755 (executable)
@@ -1,7 +1,7 @@
 #! /bin/sh
 
 # Guess values for system-dependent variables and create Makefiles.
-# Generated automatically using autoconf version 2.4 
+# Generated automatically using autoconf version 2.3 
 # Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
 #
 # This configure script is free software; the Free Software Foundation
@@ -216,7 +216,7 @@ EOF
     verbose=yes ;;
 
   -version | --version | --versio | --versi | --vers)
-    echo "configure generated by autoconf version 2.4"
+    echo "configure generated by autoconf version 2.3"
     exit 0 ;;
 
   -with-* | --with-*)
@@ -401,7 +401,6 @@ fi
 
 ac_aux_dir=
 for ac_dir in `cd $srcdir;pwd`/.. $srcdir/`cd $srcdir;pwd`/..; do
-  ac_dir=`cd $ac_dir; pwd`
   if test -f $ac_dir/install-sh; then
     ac_aux_dir=$ac_dir
     ac_install_sh="$ac_aux_dir/install-sh -c"
@@ -533,6 +532,8 @@ case "${target}" in
   h8300*-*-*)          sim_target=h8300 ;;
   h8500-*-*)           sim_target=h8500 ;;
   sh*-*-*)             sim_target=sh ;; 
+  powerpc-*-*)         sim_target=ppc ;;
+  powerpcle-*-*)       sim_target=ppc ;;
   w65-*-*)             sim_target=w65 ;;
   z8k*-*-*)            sim_target=z8k ;;
   *)                   sim_target=none ;;
@@ -542,19 +543,6 @@ configdirs=${sim_target}
 subdirs="$configdirs"
 
 
-if test ! -f ${srcdir}/${sim_target}/${sim_target}.mt ; then
-       target_makefile_frag=/dev/null
-else
-       target_makefile_frag=${srcdir}/${sim_target}/${sim_target}.mt
-fi
-
-frags=
-if test $target_makefile_frag != /dev/null; then
-       frags="$frags $target_makefile_frag"
-fi
-
-
-
 trap '' 1 2 15
 cat > confcache <<\EOF
 # This file is a shell script that caches the results of configure
@@ -643,7 +631,7 @@ do
     echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
     exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
   -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
-    echo "$CONFIG_STATUS generated by autoconf version 2.4"
+    echo "$CONFIG_STATUS generated by autoconf version 2.3"
     exit 0 ;;
   -help | --help | --hel | --he | --h)
     echo "\$ac_cs_usage"; exit 0 ;;
@@ -685,9 +673,6 @@ s%@build_cpu@%$build_cpu%g
 s%@build_vendor@%$build_vendor%g
 s%@build_os@%$build_os%g
 s%@subdirs@%$subdirs%g
-/@target_makefile_frag@/r $target_makefile_frag
-s%@target_makefile_frag@%%g
-s%@frags@%$frags%g
 
 CEOF
 EOF
index 36209c738a1b1140a0130e7c9fe1cc15a9e67de6..36d6a789b82244a5ee1db693759e31121b130da6 100644 (file)
@@ -16,6 +16,8 @@ case "${target}" in
   h8300*-*-*)          sim_target=h8300 ;;
   h8500-*-*)           sim_target=h8500 ;;
   sh*-*-*)             sim_target=sh ;; 
+  powerpc-*-*)         sim_target=ppc ;;
+  powerpcle-*-*)       sim_target=ppc ;;
   w65-*-*)             sim_target=w65 ;;
   z8k*-*-*)            sim_target=z8k ;;
   *)                   sim_target=none ;;
diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize
new file mode 100644 (file)
index 0000000..625fd36
--- /dev/null
@@ -0,0 +1,85 @@
+# .Sanitize for devo/sim/ppc.
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+COPYING
+COPYING.LIB
+ChangeLog
+Makefile.in
+README.psim
+basics.h
+bits.c
+bits.h
+configure
+configure.in
+core.c
+core.h
+cpu.c
+cpu.h
+debug.c
+debug.h
+device_tree.c
+device_tree.h
+devices.c
+devices.h
+double.c
+dp-bit.c
+events.c
+events.h
+gen.c
+idecode_branch.h
+idecode_expression.h
+idecode_fields.h
+idecode_insn.h
+inline.c
+inline.h
+interrupts.c
+interrupts.h
+main.c
+memory_map.c
+memory_map.h
+ppc-endian.c
+ppc-endian.h
+ppc-instructions
+ppc-spr-table
+ppc.mt
+psim.c
+psim.h
+registers.c
+registers.h
+sim_callbacks.h
+sim_calls.c
+std-config.h
+system.c
+system.h
+vm.c
+vm.h
+words.h
+
+Things-to-lose:
+
+
+Do-last:
+
+# End of file.
diff --git a/sim/ppc/COPYING b/sim/ppc/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, 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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       Appendix: 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., 675 Mass Ave, Cambridge, MA 02139, 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.
diff --git a/sim/ppc/COPYING.LIB b/sim/ppc/COPYING.LIB
new file mode 100644 (file)
index 0000000..eb685a5
--- /dev/null
@@ -0,0 +1,481 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, 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 library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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.
+\f
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  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 library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog
new file mode 100644 (file)
index 0000000..5fc6a07
--- /dev/null
@@ -0,0 +1,81 @@
+Tue Aug 22 09:31:18 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
+
+       * system.c (system_call): Add read support.
+
+       * main.c (main): -t sets trace_device_tree.  Correct usage message
+       to current reality.
+
+       * device_tree.c (update_memory_node_for_section): Make tracing
+       output line up.  If not code or readonly, assume that the section
+       is a data section and has read/write permissions.  Add readonly
+       support.
+
+       * core.c (create_core_from_addresses): Print end address in traces
+       and make tracing output line up.
+
+       * Makefile.in: Rewrite from Makefile to work with the Cygnus
+       environment, and support compiling in a different directory than
+       the sources reside in.
+
+       * ppc-endian.h: Rename from endian.h so that it doesn't get
+       confused with /usr/include/sys/endian.h on Linux.  Add Linux
+       endian support.
+
+       * ppc-endian.c: Rename to be consistant with ppc-endian.h.
+       Include ppc-endian.h, not endian.h.
+
+       * basics.h (sysdep.h): Include sysdep.h that configure makes.
+       Include ppc-endian.h, not endian.h.
+
+       * std-config.h: Rename from ppc-config.  Put #ifndefs around most
+       configuration macros, so they can be overridden via CFLAGS.  By
+       default, turn off tracing.
+
+       * configure.in: Clone from other simulator targets.
+       * configure: Generate via autoconf from configure.in.
+
+Sat Aug 19 09:05:32 1995  Andrew Cagney - aka Noid  <cagney@kremvax>
+
+       * ppc-instructions: fix srawi (was geting XER[CA] real wrong).
+
+       * interrupts.c (data_storage_interrupt): allow stack to grow by
+        upto one MB per increment.
+
+       * ppc-instructions: divw was computing rA / rA not rA / rB
+
+       * main.c (main): really stupid. Wasn't exiting with correct status
+
+Fri Aug 18 00:38:01 1995  Andrew Cagney - aka Noid  <cagney@kremvax>
+
+       * system.c (system_call): add system calls kill(2) and getpid(2).
+
+       * main.c (main): Check/return exit status when simulation
+        finishes.
+
+Thu Aug 17 14:29:18 1995  Andrew Cagney  <cagney@kremvax>
+
+       * device_tree.c (create_option_device_node): Alignment rules (at
+       least for the moment) now are for strict alignment only for LE OEA
+       mode.  (Because of compiler problems).
+
+       * system.c (system_call) SYS_exit: Wasn't exiting with correct status.
+
+Thu Aug 17 01:16:38 1995  Andrew Cagney - aka Noid  <cagney@kremvax>
+
+       * vm.c (DEFINE_VM_DATA_MAP_WRITE_N): For miss aligned transfer
+        forgot to return.
+
+       * system.c (system_call): didn't page align break argument before
+        determining increment break increment.
+
+       * psim/ppc: Re-arange entire directory structure so that
+        everything lives in the one directory.  While a pain for cleaning,
+        makes building across multiple architectures much simpler.
+
+       * devices.c, device_tree.c: Added code that provides a simple
+        illustration of how an interrupt control device could be
+        implemented.
+
+       * devices.c: Added code so that the dumb console device can read
+        (from stdin) as well as write to stdout.
+
diff --git a/sim/ppc/Makefile.in b/sim/ppc/Makefile.in
new file mode 100644 (file)
index 0000000..8c5865e
--- /dev/null
@@ -0,0 +1,297 @@
+#
+#   This file is part of the program psim.
+#
+#   Copyright (C) 1994-1995, 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.
+#
+
+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 = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+tooldir = $(libdir)/$(target_alias)
+
+datadir = $(prefix)/lib
+mandir = $(prefix)/man
+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 = $(prefix)/info
+includedir = $(prefix)/include
+docdir = $(datadir)/doc
+
+SHELL = /bin/sh
+
+# FIXME: use autoconf's AC_PROG_INSTALL
+INSTALL = $(srcroot)/install.sh -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL)
+INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)'
+INSTALL_XFORM1= $(INSTALL_XFORM) -b=.1
+
+AR = ar
+AR_FLAGS = rc
+CFLAGS = -g
+BISON = bison
+MAKEINFO = makeinfo
+RANLIB = ranlib
+
+.NOEXPORT:
+MAKEOVERRIDES=
+
+LIB_INCLUDES   = -I$(srcdir)/../../include
+BFD_INCLUDES   = -I../../bfd -I$(srcdir)/../../bfd
+GDB_INCLUDES   = -I../../gdb -I$(srcdir)/../../gdb  -I$(srcdir)/../../gdb/config -I$(srcdir)/../../mmalloc
+INCLUDES       = -I. -I$(srcdir) $(LIB_INCLUDES) $(BFD_INCLUDES) $(GDB_INCLUDES)
+
+CONFIG_FILE    = std-config.h
+
+LIBIBERTY_LIB  = ../../libiberty/libiberty.a
+BFD_LIB                = ../../bfd/libbfd.a
+
+#### Makefile fragments come in here.
+# @host_makefile_frag@
+###
+
+TARGETLIB = libsim.a
+
+all:   run libsim.a $(GDB_OBJ)
+
+.c.o:
+       $(CC) -c $(CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) $<
+
+
+
+BASICS_H = \
+       sysdep.h \
+       config.h \
+       words.h \
+       ppc-endian.h \
+       debug.h \
+       bits.h \
+       sim_callbacks.h
+
+PSIM_H = \
+       psim.h \
+       $(BASICS_H)
+
+IDECODE_H = \
+       idecode.h \
+       idecode_insn.h \
+       idecode_expression.h \
+       idecode_branch.h \
+       idecode_fields.h \
+       icache.h
+
+REGISTERS_H = \
+       registers.h \
+       spreg.h
+
+CPU_H = \
+       cpu.h \
+       $(BASICS_H) \
+       $(REGISTERS_H) \
+       device_tree.h \
+       memory_map.h \
+       core.h \
+       vm.h \
+       events.h \
+       interrupts.h \
+       psim.h \
+       icache.h
+
+
+INLINE = \
+       inline.h \
+       inline.c
+
+BUILT_SRC = \
+       icache.h \
+       idecode.h idecode.c \
+       semantics.h semantics.c \
+       spreg.h spreg.c \
+       config.h
+
+LIB_SRC = \
+       psim.c \
+       bits.c \
+       ppc-endian.c \
+       debug.c \
+       memory_map.c \
+       vm.c \
+       core.c \
+       events.c \
+       system.c \
+       registers.c \
+       cpu.c \
+       interrupts.c \
+       devices.c \
+       device_tree.c
+
+MAIN_SRC = \
+       main.c \
+       sim_calls.c
+
+
+LIB_OBJ = \
+       debug.o \
+       bits.o \
+       ppc-endian.o \
+       system.o \
+       registers.o \
+       memory_map.o \
+       vm.o \
+       core.o \
+       spreg.o \
+       cpu.o \
+       interrupts.o \
+       events.o \
+       devices.o \
+       device_tree.o \
+       semantics.o \
+       idecode.o \
+       psim.o
+
+
+GDB_OBJ = sim_calls.o 
+
+
+psim: libsim.a main.o $(LIBIBERTY_LIB) $(BFD_LIB) $(LIBS)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o psim main.o libsim.a $(BFD_LIB) $(LIBIBERTY_LIB) $(LIBS)
+
+run: psim
+       rm -f run
+       ln psim run
+
+libsim.a: $(BUILT_SRC) $(LIB_OBJ) $(GDB_OBJ)
+       rm -f $(TARGETLIB)
+       $(AR) $(AR_FLAGS) $(TARGETLIB) $(LIB_OBJ) $(GDB_OBJ)
+       $(RANLIB) $(TARGETLIB)
+
+psim.o: psim.c psim.h $(CPU_H) $(IDECODE_H) $(INLINE)
+
+bits.o: bits.c bits.h
+
+debug.o: debug.c $(BASICS_H)
+
+ppc-endian.o: ppc-endian.c ppc-endian.h \
+       config.h words.h sim_callbacks.h
+
+system.o: system.c system.h $(CPU_H) $(IDECODE_H)
+
+registers.o: registers.c $(REGISTERS_H) $(BASICS_H) 
+
+cpu.o: cpu.c $(CPU_H) $(IDECODE_H)
+
+interrupts.o: interrupts.c $(CPU_H) $(IDECODE_H) system.h
+
+idecode.o: idecode.c $(CPU_H) $(IDECODE_H) semantics.h
+
+memory_map.o: memory_map.c memory_map.h $(BASICS_H) device_tree.h interrupts.h
+
+# double.o: double.c dp-bit.c
+
+vm.o: vm.c vm.h $(BASICS_H) $(REGISTERS_H) \
+       device_tree.h memory_map.h core.h interrupts.h
+
+core.o: core.c core.h $(BASICS_H) \
+       device_tree.h memory_map.h
+
+events.o: events.c events.h $(BASICS_H) 
+
+sim_calls.o: sim_calls.c $(PSIM_H) ../../gdb/tm.h devices.h
+
+spreg.o: spreg.h spreg.c words.h
+
+main.o: main.c $(PSIM_H)
+
+devices.o: devices.c devices.h $(BASICS_H) \
+       device_tree.h events.h
+
+device_tree.o: device_tree.c device_tree.h devices.h $(BASICS_H)
+
+semantics.o: semantics.c semantics.h $(CPU_H) $(IDECODE_H)
+
+
+#
+# Rules to create the built c source code files
+#
+
+config.h: $(CONFIG_FILE)
+       cp $(srcdir)/$(CONFIG_FILE) config.h
+
+
+tmp-gencode: gen ppc-instructions ppc-spr-table $(srcdir)/../../move-if-change
+       ./gen   -r $(srcdir)/ppc-spr-table \
+               -P tmp-spreg.h \
+               -p tmp-spreg.c \
+               -i $(srcdir)/ppc-instructions \
+               -C tmp-icache.h \
+               -S tmp-semantics.h \
+               -s tmp-semantics.c \
+               -D tmp-idecode.h \
+               -d tmp-idecode.c
+       $(srcdir)/../../move-if-change tmp-icache.h icache.h
+       $(srcdir)/../../move-if-change tmp-idecode.h idecode.h
+       $(srcdir)/../../move-if-change tmp-idecode.c idecode.c
+       $(srcdir)/../../move-if-change tmp-semantics.h semantics.h
+       $(srcdir)/../../move-if-change tmp-semantics.c semantics.c
+       $(srcdir)/../../move-if-change tmp-spreg.h spreg.h
+       $(srcdir)/../../move-if-change tmp-spreg.c spreg.c
+       touch tmp-gencode
+
+icache.h idecode.h idecode.c semantics.h semantics.c spreg.h spreg.c: tmp-gencode
+
+gen.o: gen.c config.h
+
+gen: gen.o config.h $(LIBIBERTY_LIB) $(LIBS)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o gen gen.o $(LIBIBERTY_LIB) $(LIBS)
+               
+#
+
+tags etags: TAGS
+
+TAGS: tmp-gencode config.h
+       etags $(srcdir)/*.h $(srcdir)/*.c $(BUILT_SRC)
+
+clean:
+       rm -f tmp-* *.[oas] core psim run gen
+
+distclean mostlyclean realclean: clean
+       rm -f TAGS $(BUILT_SRC) Makefile config.cache config.log config.status
+
+Makefile: Makefile.in config.status @frags@
+       $(SHELL) ./config.status
+
+config.status: configure
+       $(SHELL) ./config.status --recheck
+
+install:
+       echo Install psim ...
diff --git a/sim/ppc/README.psim b/sim/ppc/README.psim
new file mode 100644 (file)
index 0000000..c76c023
--- /dev/null
@@ -0,0 +1,253 @@
+
+                       PSIM
+
+Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+This directory contains the program PSIM that models the PowerPC
+architecture.  It can either be run stand alone (psim) or linked with
+GDB.
+
+
+CONTENTS:
+
+    psim-*.tar:        
+
+       psim-sim-*.tar.gz       simulator source code
+
+       psim-test-*.tar.gz      test directory for simulator
+
+       psim-gdb-*.diff.gz      patches to integrated psim
+                               into gdb
+
+    gnu-*.tar:
+
+       gnu-gdb-*.diff.gz       patches to gdb that may have
+                               already been merged into the
+                               GDB source tree.
+
+       gnu-*-*.diff.gz         Other noise
+
+
+BUILDING:
+
+       o Install flex, bison, gnu-make, native gcc and probably also byacc.
+
+
+       o First you will need a fairly current copy of GDB (try the ftp site
+         ftp.cygnus.com:pub).  I've built it with a beta version of gdb-4.15.
+
+         Unpack gdb vis:
+
+               $ gunzip < gdb-4.15.tar.gz | tar xf -
+
+
+       o Apply any patches that haven't yet been merged into the GDB source
+         tree.
+
+               $ cd gdb-4.15
+               $ gunzip < ../psim-gdb-*.diff.gz | patch -p1
+               $ gunzip < ../gnu-gdb-*.diff.gz | patch -p1
+
+
+       o Unpack the psim source code (and optionally the test directory)
+
+               $ cd gdb-4.15
+               $ gunzip < ../psim-sim-*.tar.gz | tar xvf -
+               $ gunzip < ../psim-test-*.tar.gz | tar xvf -
+
+
+       o Configure gdb as per normal.  I use something along the lines of:
+
+               $ cd gdb-4.15
+               $ CC=gcc ./configure --target=powerpcle-unknown-eabi
+
+
+       o Build your entire gdb tree as per normal.  Something along the
+         lines of:
+
+               $ cd gdb-4.15
+               $ make CC=gcc
+               .
+               .
+               .
+
+
+
+       o Install it it all as per normal.  Something along the lines of:
+
+               $ cd gdb-4.15
+               $ make CC=gcc install
+
+         The program sim/ppc/psim is not installed.
+
+
+RUNNING:
+
+       PSIM can either be run as a stand alone program or as part
+       of gdb.  The psim-test archive contains pre-compiled and
+       linked programs that can be run on PSIM.  The notes below
+       assume that you have unpacked that tar archive.
+
+       To rebuild the archive you will need to obtain a working
+       version of an ELF compiler/linker for the PowerPC.
+       
+       Example of running PSIM:
+
+               Print out the users environment:
+
+                       $ sim/ppc/psim sim/ppc/test/envp
+
+               Print out the arguments:
+
+                       $ sim/ppc/psim sim/ppc/test/argv a b c
+
+               Check the OEA model:
+
+                       $ sim/ppc/psim sim/ppc/test/interrupt
+
+               Check that sbrk works
+
+                       $ sim/ppc/psim sim/ppc/test/break
+
+               Try for speed.  The program count contains a loop
+               of two instructions which is looped <arg> times.
+               See later for how to make PSIM run 10-100 times
+               faster.
+
+                       $ time sim/ppc/sim sim/ppc/test/count 5000000
+                       $ expr 10 \* 1000 \* 1000 / <seconds>
+
+
+       Example of running GDB: 
+
+               The most important thing to be aware of is the fact
+               that before the simulator is used, the user must attach
+               to it (target sim) and than load the executable (load count).
+
+                       $ cd sim/ppc/test
+                       $ powerpc-unknown-eabi-gdb count
+                       (gdb) target sim
+                       (gdb) load count
+                       (gdb) break main
+                       (gdb) run
+                       .
+                       .
+                       .
+
+
+CONFIGURATION: Making it go faster
+
+       See the file sim/ppc/config.h (a.k.a. sim/ppc/data/ppc-config)
+       for notes.
+
+
+KNOWN FEATURES
+
+       SMP, dual-endian, VEA and OEA models, hardware devices
+       (console, icu, reset) ...
+
+
+KNOWN PROBLEMS:
+
+       Configuration could be better.
+
+       HTAB (page) code for OEA model untested.  Some of the vm code
+       instructions unimplemented.
+
+       Doesn't detect/handle changing endian bits.  In fact they are
+       ignored.
+
+       Return from interrupt instruction unimplemented.
+
+       Flush instruction cache instructions do nothing.  Perhaphs they
+       should (if there is an instruction cache) flush it.
+
+       PowerOpen VEA model (a.k.a XCOFF a.k.a AIX) broken.  It was
+       working but that is before I changed the create stack frame
+       code into an ELF version.
+
+       OpenBoot and PR*P interfaces missing.  Open boot could be
+       implemented by putting special instructions at the address
+       of the OpenBoot callback functions.  Those instructions
+       could than emulate OpenBoot behavour.
+
+       VEA memory read/write performance could be improved by merging
+       the data sections.
+
+       When reading in a VEA executable, the binaries text and data
+       sections are not made page aligned.
+
+       Missing or commented out instructions.
+
+       Lack of floating point support.
+       [workaround: build everything using -msoft-float]
+
+       64bit untested.
+
+       Event code for pending events from signal handlers not
+       finished/tested.
+
+       Better and more devices.
+
+       Only two device trees VEA and OEA (clayton) and those hard coded.
+       Should be possible to specify a file containing a device tree
+       description as the program to run.  At present it a device tree
+       file is detected causing psim to abort.
+
+       I wonder if I've got my ppc.instructions copyright
+       notice correct.
+
+
+THANKS:
+
+       Thanks go to the following who each helped in some way.
+
+               Allen Briggs, Bett Koch, David Edelsohn,
+               Michael Meissner, Bob Mercier, Richard Perini,
+               Richard Stallman, Mitchele Walker
+
+
+----------------------------------------------------------------
+
+
+Random notes on performance:
+
+
+$ cd test
+time ../psim count `expr 10000000 / 2`
+time ../psim volatile-count `expr 10000000 / 7`
+
+Where 2 and 7 are the number of instructions in the main loop.
+
+
+       611/729 - baseline
+
+Tests:
+
+       CFLAGS= -c -O2 -m486 -fomit-frame-pointer
+
+       o       different first/second level table/switch combinations
+
+               0 - use a table
+               1 - use a simple switch
+               2 - use an expanded switch
+
+i486DX4/100 - AMD
+
+       1/108/140 - switch=0/0/0,expand=2,inline=2,nia=1,cache=1
+       1/114/140 - switch=0/0/0,expand=2,inline=2,nia=1,cache=1
+       1/137/149 - switch=0/0,expand=2,inline=1,nia=1,cache=1
+       1/144/155 - switch=2/1,expand=2,inline=1,nia=1,cache=1
+       1/153/159 - switch=2/1,expand=0,inline=1,nia=1,cache=1
+       1/185/189 - switch=0/0,expand=0,inline=1,nia=1
+
+i486DX2/66
+
+       1/572/695 - switch=1/1,expand=0,inline=0
+       1/579/729 - switch=0/0,expand=0,inline=0
+       1/570/682 - switch=2/2,expand=0,inline=0
+       1/431/492 - switch=0/0,expand=0,inline=1,nia=0
+       1/271/292 - switch=2/1,expand=0,inline=1,nia=0
+       1/270/316 - switch=2/2,expand=0,inline=1,nia=0
+       1/271/281 - switch=1/1,expand=0,inline=1,nia=1
+       1/267/274 - switch=2/1,expand=0,inline=1,nia=1
diff --git a/sim/ppc/bits.h b/sim/ppc/bits.h
new file mode 100644 (file)
index 0000000..e3889b4
--- /dev/null
@@ -0,0 +1,194 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _BITS_H_
+#define _BITS_H_
+
+/* bit manipulation routines:
+
+   Bit numbering: The bits are numbered according to the PowerPC
+   convention - the left most (or most significant) is bit 0 while the
+   right most (least significant) is bit 1.
+
+   Size convention: Each macro is in three forms - <MACRO>32 which
+   operates in 32bit quantity (bits are numbered 0..31); <MACRO>64
+   which operates using 64bit quantites (and bits are numbered 0..64);
+   and <MACRO> which operates using the bit size of the target
+   architecture (bits are still numbered 0..63), with 32bit
+   architectures ignoring the first 32bits having bit 32 as the most
+   significant.
+
+   BIT*(POS): Quantity with just 1 bit set.
+
+   MASK*(FIRST, LAST): Create a constant bit mask of the specified
+   size with bits [FIRST .. LAST] set.
+
+   MASKED*(VALUE, FIRST, LAST): Masks out all but bits [FIRST
+   .. LAST].
+
+   EXTRACTED*(VALUE, FIRST, LAST): Masks out bits [FIRST .. LAST] but
+   also right shifts the masked value so that bit LAST becomes the
+   least significant (right most).
+
+   SHUFFLE*(VALUE, OLD, NEW): Moves things around so that bit pos OLD
+   is extracted and than moved to bit pos NEW.
+
+   
+
+   IEA_MASKED(SHOULD_MASK, ADDR): Convert the address to the targets
+   natural size.  If in 32bit mode, discard the high 32bits.
+
+   EXTENDED(VALUE): Convert VALUE (32bits of it) to the targets
+   natural size.  If in 64bit mode, sign extend the value.
+
+   */
+
+/* Bit operators */
+#define BIT4(POS)  (1 << _MAKE_SHIFT(4, POS))
+#define BIT5(POS)  (1 << _MAKE_SHIFT(5, POS))
+#define BIT10(POS)  (1 << _MAKE_SHIFT(10, POS))
+#define BIT32(POS) _BITn(32, POS)
+#define BIT64(POS) _BITn(64, POS)
+
+#if (WITH_64BIT_TARGET)
+#define BIT(POS)   BIT64(POS)
+#else
+#define BIT(POS)   (((POS) < 32) ? 0 : _BITn(32, (POS)-32))
+#endif
+
+
+/* multi bit mask */
+
+#define MASK32(START, STOP)   _MASKn(32, START, STOP)
+#define MASK64(START, STOP)   _MASKn(64, START, STOP)
+
+#if (WITH_64BIT_TARGET)
+#define MASK(START, STOP) (((START) <= (STOP)) \
+                          ? _MASKn(64, START, STOP) \
+                          : (_MASKn(64, 0, STOP) \
+                             | _MASKn(64, START, 63)))
+#else
+#define MASK(START, STOP)  (((START) <= (STOP)) \
+                           ? (((STOP) < 32) \
+                              ? 0 \
+                              : _MASKn(32, \
+                                       (START) < 32 ? 0 : (START) - 32, \
+                                       (STOP)-32)) \
+                           : (_MASKn(32, \
+                                     (START) < 32 ? 0 : (START) - 32, \
+                                     31) \
+                              | (((STOP) < 32) \
+                                 ? 0 \
+                                 : _MASKn(32, \
+                                          0, \
+                                          (STOP) - 32))))
+#endif
+
+
+#define MASKED32(WORD, START, STOP)    _MASKEDn(32, WORD, START, STOP)
+#define MASKED64(WORD, START, STOP)    _MASKEDn(64, WORD, START, STOP)
+#define MASKED10(WORD, START, STOP)    _MASKEDn(10, WORD, START, STOP)
+#define EXTRACTED32(WORD, START, STOP) _EXTRACTEDn(32, WORD, START, STOP)
+#define EXTRACTED64(WORD, START, STOP) _EXTRACTEDn(64, WORD, START, STOP)
+#define EXTRACTED10(WORD, START, STOP) _EXTRACTEDn(10, WORD, START, STOP)
+
+#define MASKED(WORD, START, STOP)   ((natural_word)(WORD) & MASK(START, STOP))
+#if (WITH_64BITS_TARGET)
+#define EXTRACTED(WORD, START, STOP)   _EXTRACTEDn(64, WORD, START, STOP)
+#else
+#define EXTRACTED(WORD, START, STOP) (STOP < 32 \
+                                     ? 0 \
+                                     : (((natural_word)WORD \
+                                         >> (63 - (STOP))) \
+                                        && MASK(START+(63-STOP), 63)))
+#endif
+
+
+#define SHUFFLE32(WORD, OLD, NEW) _SHUFFLEn(32, WORD, OLD, NEW)
+#define SHUFFLE64(WORD, OLD, NEW) _SHUFFLEn(64, WORD, OLD, NEW)
+#define SHUFFLE(WORD, OLD, NEW) _SHUFFLEn(_word, WORD, OLD, NEW)
+/* NB: the wierdness (N>O?N-O:0) is to stop a warning from GCC */
+#define _SHUFFLEn(N, WORD, OLD, NEW) \
+((OLD) < (NEW) \
+ ? (((unsigned##N)(WORD) \
+     >> (((NEW) > (OLD)) ? ((NEW) - (OLD)) : 0)) \
+    & MASK32((NEW), (NEW))) \
+ : (((unsigned##N)(WORD) \
+     << (((OLD) > (NEW)) ? ((OLD) - (NEW)) : 0)) \
+    & MASK32((NEW), (NEW))))
+
+
+
+/* depending on MODE return a 64bit or 32bit (sign extended) value */
+#if (WITH_64BIT_TARGET)
+#define EXTENDED(X)     ((signed64)(signed32)(X))
+#else
+#define EXTENDED(X)     (X)
+#endif
+
+
+
+
+/* memory alignment macro's */
+#define _ALIGNa(A,X)  (((X) + ((A)-1)) & ~((A)-1))
+#define ALIGN_8(X)     _ALIGNa(8, X)
+#define ALIGN_16(X)    _ALIGNa(16, X)
+#define ALIGN_PAGE(X)  _ALIGNa(0x1000, X)
+#define FLOOR_PAGE(X)   ((X) & ~(0x1000 - 1))
+
+/* bit bliting macro's */
+#define BLIT32(V, POS, BIT) \
+do { \
+  if (BIT) \
+    V |= BIT32(POS); \
+  else \
+    V &= ~BIT32(POS); \
+} while (0)
+#define MLIT32(V, LO, HI, VAL) \
+do { \
+  (V) = (((V) & ~MASK32((LO), (HI))) \
+        | ((VAL) << _MAKE_SHIFT(32,HI))); \
+} while (0)
+
+
+
+/* Things for creating single bit set values */
+/* MakeBit */
+#define _MAKE_SHIFT(WIDTH, pos) (WIDTH - 1 - (pos))
+#define _BITn(WIDTH, pos) (((natural##WIDTH)(1)) \
+                          << _MAKE_SHIFT(WIDTH, pos))
+/* MakeBitMask */
+#define _MASKn(WIDTH, START, STOP) (((((unsigned##WIDTH)0) - 1) \
+                                    >> (WIDTH - ((STOP) - (START) + 1))) \
+                                   << (WIDTH - 1 - (STOP)))
+
+
+
+/* mask the required bits, leaving them in place */
+#define _MASKEDn(WIDTH, WORD, START, STOP) \
+(((natural##WIDTH)(WORD)) & MASK##WIDTH(START, STOP))
+
+/* extract the required bits aligning them with the lsb */
+#define _EXTRACTEDn(WIDTH, WORD, START, STOP) \
+((((natural##WIDTH)(WORD)) >> (WIDTH - (STOP) - 1)) \
+ & _MASKn(WIDTH, WIDTH-1+(START)-(STOP), WIDTH-1))
+
+#endif /* _BITS_H_ */
diff --git a/sim/ppc/configure.in b/sim/ppc/configure.in
new file mode 100644 (file)
index 0000000..4cd6559
--- /dev/null
@@ -0,0 +1,32 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.3)dnl
+AC_INIT(Makefile.in)
+
+AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..)
+AC_CANONICAL_SYSTEM
+AC_ARG_PROGRAM
+
+. ${srcdir}/../../bfd/configure.host
+
+# Set up to make a link between the host's include file and "sysdep.h".
+files="../../bfd/hosts/${my_host}.h"
+if test ! -f ${srcdir}/${files} ; then
+       files=../../bfd/hosts/std-host.h
+       AC_MSG_WARN(z8k sim has no specific support for host ${host} -- using std-host)
+fi
+AC_LINK_FILES($files, sysdep.h)
+
+if test -f ${srcdir}/../../bfd/config/${my_host}.mh; then
+       host_makefile_frag=../../bfd/config/${my_host}.mh
+else
+       host_makefile_frag=/dev/null
+fi
+
+frags=
+if test $host_makefile_frag != /dev/null; then
+       frags="$frags $host_makefile_frag"
+fi
+AC_SUBST_FILE(host_makefile_frag)
+AC_SUBST(frags)
+
+AC_OUTPUT(Makefile)
diff --git a/sim/ppc/core.c b/sim/ppc/core.c
new file mode 100644 (file)
index 0000000..5e8479f
--- /dev/null
@@ -0,0 +1,356 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _CORE_C_
+#define _CORE_C_
+
+#ifndef STATIC_INLINE_CORE
+#define STATIC_INLINE_CORE STATIC_INLINE
+#endif
+
+#include "basics.h"
+#include "device_tree.h"
+#include "memory_map.h"
+#include "core.h"
+
+
+struct _core {
+  /* attached devices */
+  device_node *device_tree;
+  /* different memory maps */
+  memory_map *readable; /* really everything */
+  memory_map *writeable;
+  memory_map *executable;
+  /* VEA model requires additional memory information */
+  unsigned_word data_upper_bound;
+  unsigned_word data_high_water;
+  unsigned_word stack_upper_bound;
+  unsigned_word stack_lower_bound;
+  unsigned_word stack_low_water;
+  /* misc */
+  int trace;
+};
+
+
+STATIC_INLINE_CORE void
+create_core_from_addresses(device_node *device,
+                          void *data)
+{
+  core *memory = (core*)data;
+  device_address *address;
+  for (address = device->addresses;
+       address != NULL;
+       address = address->next_address) {
+    switch (device->type) {
+    case memory_device:
+      {
+       void *ram = zalloc(address->size);
+       TRACE(trace_core,
+             ("create_core_from_addresses() adding memory at 0x%.8x-0x%.8x, size %8d\n",
+              address->lower_bound, address->lower_bound + address->size - 1, address->size));
+       core_add_raw_memory(memory,
+                           ram,
+                           address->lower_bound,
+                           address->size,
+                           address->access);
+      }
+      break;
+    case sequential_device:
+    case block_device:
+    case bus_device:
+    case other_device:
+      {
+       TRACE(trace_core,
+             ("create_core_from_addresses() adding device at 0x%.8x-0x%.8x, size %8d\n",
+              address->lower_bound, address->lower_bound + address->size - 1, address->size));
+       ASSERT(device->callbacks != NULL);
+       core_add_callback_memory(memory,
+                                device,
+                                device->callbacks->read_callback,
+                                device->callbacks->write_callback,
+                                address->lower_bound,
+                                address->size,
+                                address->access);
+      }
+      break;
+    default:
+      TRACE(trace_core,
+           ("create_core_from_addresses() unknown type %d\n", (int)device->type));
+      break;
+      /* nothing happens here */
+    }
+  }
+}
+
+
+INLINE_CORE core *
+core_create(device_node *root,
+           int trace)
+{
+  core *memory;
+
+  /* Initialize things */
+  memory = ZALLOC(core);
+  memory->trace = trace;
+  memory->device_tree = root;
+
+  /* allocate space for the separate virtual to physical maps */
+  memory->executable = new_memory_map();
+  memory->readable = new_memory_map();
+  memory->writeable = new_memory_map();
+
+  /* initial values for the water marks */
+  memory->data_high_water = 0;
+  memory->stack_low_water = memory->data_high_water - sizeof(unsigned_word);
+
+  /* go over the device tree looking for address ranges to add to
+     memory */
+  device_tree_traverse(root,
+                      create_core_from_addresses,
+                      NULL,
+                      memory);
+
+  /* return the created core object */
+  return memory;
+}
+
+
+STATIC_INLINE_CORE void
+zero_core_from_addresses(device_node *device,
+                        void *data)
+{
+  core *memory = (core*)data;
+  device_address *address;
+
+  /* for memory nodes, copy or zero any data */
+  if (device->type == memory_device) {
+    for (address = device->addresses;
+        address != NULL;
+        address = address->next_address) {
+      if (memory_map_zero(memory->readable,
+                         address->lower_bound,
+                         address->size) != address->size)
+       error("init_core_from_addresses() - zero failed\n");
+      /* adjust high water mark (sbrk) */
+      if (memory->data_upper_bound < address->upper_bound)
+       memory->data_upper_bound = address->upper_bound;
+    }
+  }
+}
+
+STATIC_INLINE_CORE void
+load_core_from_addresses(device_node *device,
+                        void *data)
+{
+  core *memory = (core*)data;
+  device_address *address;
+
+  /* initialize the address range with the value attached to the
+     address.  Even works for devices! */
+  for (address = device->addresses;
+       address != NULL;
+       address = address->next_address) {
+    /* (re)init the address range.  I don't want to think about what
+       this is doing to callback devices! */
+    if (address->init) {
+      if (memory_map_write_buffer(memory->readable,
+                                 address->init,
+                                 address->lower_bound,
+                                 address->size,
+                                 raw_transfer) != address->size)
+       error("init_core_from_addresses() - write failed\n");
+    }
+  }
+}
+
+INLINE_CORE void
+core_init(core *memory)
+{
+  unsigned nr_cleared;
+  unsigned_word clear_base;
+  unsigned_word clear_bound;
+
+  /* for vea, several memory break points */
+  memory->data_upper_bound = 0;
+  memory->stack_upper_bound = device_tree_find_int(memory->device_tree,
+                                                  "/options/stack-pointer");;
+  memory->stack_lower_bound = memory->stack_upper_bound;
+
+  /* (re) clear all of memory that is specified by memory-address
+     entries.  While we're at it determine the upper bound for memory
+     areas */
+  device_tree_traverse(memory->device_tree,
+                      NULL,
+                      zero_core_from_addresses,
+                      memory);
+
+  /* May have grown the data sectioin (vea model), zero that too if
+     present */
+  clear_base = memory->data_upper_bound;
+  clear_bound = memory->data_high_water;
+  if (clear_bound > clear_base) {
+    while ((nr_cleared = memory_map_zero(memory->readable,
+                                        clear_base,
+                                        clear_bound - clear_base)) > 0) {
+      clear_base += nr_cleared;
+    }
+  }
+
+  /* clear any part of the stack that was dynamically allocated */
+  clear_base = memory->stack_low_water;
+  clear_bound = memory->stack_upper_bound;
+  if (clear_bound > clear_base) {
+    while ((nr_cleared = memory_map_zero(memory->readable,
+                                        clear_base,
+                                        clear_bound - clear_base)) > 0) {
+      clear_base += nr_cleared;
+    }
+  }
+
+  /* with everything zero'ed, now (re) load any data sections */
+  device_tree_traverse(memory->device_tree,
+                      NULL,
+                      load_core_from_addresses,
+                      memory);
+
+}
+
+
+
+INLINE_CORE void
+core_add_raw_memory(core *memory,
+                   void *buffer,
+                   unsigned_word base,
+                   unsigned size,
+                   device_access access)
+{
+  if (access & device_is_readable)
+    memory_map_add_raw_memory(memory->readable,
+                             buffer, base, size);
+  if (access & device_is_writeable)
+    memory_map_add_raw_memory(memory->writeable,
+                             buffer, base, size);
+  if (access & device_is_executable)
+    memory_map_add_raw_memory(memory->executable,
+                             buffer, base, size);
+}
+
+
+INLINE_CORE void
+core_add_callback_memory(core *memory,
+                        device_node *device,
+                        device_reader_callback *reader,
+                        device_writer_callback *writer,
+                        unsigned_word base,
+                        unsigned size,
+                        device_access access)
+{
+  if (access & device_is_readable)
+    memory_map_add_callback_memory(memory->readable,
+                                  device, reader, writer,
+                                  base, size);
+  if (access & device_is_writeable)
+    memory_map_add_callback_memory(memory->writeable,
+                                  device, reader, writer,
+                                  base, size);
+  if (access & device_is_executable)
+    memory_map_add_callback_memory(memory->executable,
+                                  device, reader, writer,
+                                  base, size);
+}
+
+
+STATIC_INLINE_CORE void
+malloc_core_memory(core *memory,
+                  unsigned_word base,
+                  unsigned size,
+                  device_access access)
+{
+  void *buffer = (void*)zalloc(size);
+  core_add_raw_memory(memory, buffer, base, size, access);
+}
+
+INLINE_CORE unsigned_word
+core_data_upper_bound(core *memory)
+{
+  return memory->data_upper_bound;
+}
+
+
+INLINE_CORE unsigned_word
+core_stack_lower_bound(core *memory)
+{
+  return memory->stack_lower_bound;
+}
+
+INLINE_CORE unsigned_word
+core_stack_size(core *memory)
+{
+  return (memory->stack_upper_bound - memory->stack_lower_bound);
+}
+
+
+
+INLINE_CORE void 
+core_add_data(core *memory, unsigned_word incr)
+{
+  memory->data_upper_bound += incr;
+  if (memory->data_upper_bound > memory->data_high_water) {
+    malloc_core_memory(memory, memory->data_high_water, incr,
+                    device_is_readable | device_is_writeable);
+    memory->data_high_water = memory->data_upper_bound;
+  }
+}
+
+
+INLINE_CORE void 
+core_add_stack(core *memory, unsigned_word incr)
+{
+  memory->stack_lower_bound -= incr;
+  if (memory->stack_lower_bound < memory->stack_low_water) {
+    malloc_core_memory(memory, memory->stack_lower_bound, incr,
+                      device_is_readable | device_is_writeable);
+    memory->stack_low_water = memory->stack_lower_bound;
+  }
+}
+
+
+INLINE_CORE memory_map *
+core_readable(core *core)
+{
+  return core->readable;
+}
+
+
+INLINE_CORE memory_map *
+core_writeable(core *core)
+{
+  return core->writeable;
+}
+
+
+INLINE_CORE memory_map *
+core_executable(core *core)
+{
+  return core->executable;
+}
+
+#endif /* _CORE_ */
diff --git a/sim/ppc/core.h b/sim/ppc/core.h
new file mode 100644 (file)
index 0000000..5d7837a
--- /dev/null
@@ -0,0 +1,103 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _CORE_H_
+#define _CORE_H_
+
+#ifndef INLINE_CORE
+#define INLINE_CORE
+#endif
+
+/* the base type */
+
+typedef struct _core core;
+
+
+/* create the hardware's core (memory and devices) from the device
+   tree */
+INLINE_CORE core *core_create
+(device_node *root,
+ int trace);
+
+
+/* given a created core object, (re)initialize it from the
+   information provided in it's associated device tree */
+
+INLINE_CORE void core_init
+(core *memory);
+
+
+/* from this core extract out the three different types of memory -
+   executable, readable, writeable */
+
+INLINE_CORE memory_map *core_readable
+(core *memory);
+
+INLINE_CORE memory_map *core_writeable
+(core *memory);
+
+INLINE_CORE memory_map *core_executable
+(core *memory);
+
+
+/* operators to grow memory on the fly */
+
+INLINE_CORE void core_add_raw_memory
+(core *memory,
+ void *buffer,
+ unsigned_word base,
+ unsigned size,
+ device_access access);
+
+INLINE_CORE void core_add_callback_memory
+(core *memory,
+ device_node *device,
+ device_reader_callback *reader,
+ device_writer_callback *writer,
+ unsigned_word base,
+ unsigned size,
+ device_access access);
+
+
+/* In the VEA model, memory grow's after it is created.  Operators
+   below grow memory as required.
+
+   FIXME - should this be inside of vm? */
+
+INLINE_CORE unsigned_word core_data_upper_bound
+(core *memory);
+
+INLINE_CORE unsigned_word core_stack_lower_bound
+(core *memory);
+
+INLINE_CORE unsigned_word core_stack_size
+(core *memory);
+
+INLINE_CORE void core_add_data
+(core *memory,
+ unsigned_word incr);
+
+INLINE_CORE void core_add_stack
+(core *memory,
+ unsigned_word incr);
+
+
+#endif /* _CORE_ */
diff --git a/sim/ppc/device_tree.c b/sim/ppc/device_tree.c
new file mode 100644 (file)
index 0000000..3478320
--- /dev/null
@@ -0,0 +1,506 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _DEVICE_TREE_C_
+#define _DEVICE_TREE_C_
+
+#ifndef STATIC_INLINE_DEVICE_TREE
+#define STATIC_INLINE_DEVICE_TREE STATIC_INLINE
+#endif
+
+#include <string.h>
+
+#include "basics.h"
+#include "device_tree.h"
+#include "devices.h"
+
+#include "bfd.h"
+
+enum { clayton_memory_size = 0x100000 };
+
+/* insert the address into the device_nodes sorted list of addresses */
+INLINE_DEVICE_TREE void
+device_node_add_address(device_node *node,
+                       unsigned_word lower_bound,
+                       unsigned size,
+                       device_access access,
+                       void *init)
+{
+  unsigned_word upper_bound = lower_bound + size;
+  device_address *new_address;
+  device_address **current_address;
+
+  /* find the insertion point */
+  current_address = &node->addresses;
+  while (*current_address != NULL
+        && (*current_address)->upper_bound >= upper_bound) {
+    current_address = &(*current_address)->next_address;
+  }
+
+  /* insert */
+  new_address = ZALLOC(device_address);
+  new_address->lower_bound = lower_bound;
+  new_address->upper_bound = lower_bound + size;
+  new_address->size = size;
+  new_address->access = access;
+  new_address->init = init;
+  new_address->next_address = *current_address;
+  *current_address = new_address;
+}
+
+
+/* create a new device tree optionally making it a child of the parent
+   node */
+
+INLINE_DEVICE_TREE device_node *
+device_node_create(device_node *parent,
+                  char *name,
+                  device_type type,
+                  device_callbacks *callbacks,
+                  void *data)
+{
+  device_node *new_node;
+  new_node = ZALLOC(device_node);
+  new_node->parent = parent;
+  new_node->name = name;
+  new_node->type = type;
+  new_node->callbacks = callbacks;
+  new_node->data = data;
+  if (parent != NULL) {
+    new_node->sibling = parent->children;
+    parent->children = new_node;
+  }
+  return new_node;
+}
+
+
+/* Binary file:
+
+   The specified file is a binary, assume VEA is required, construct a
+   fake device tree based on the addresses of the text / data segments
+   requested by the binary */
+
+
+/* Update the fake device tree so that memory is allocated for this
+   section */
+STATIC_INLINE_DEVICE_TREE void
+update_memory_node_for_section(bfd *abfd,
+                              asection *the_section,
+                              PTR obj)
+{
+  unsigned_word section_vma;
+  unsigned_word section_size;
+  device_access section_access;
+  void *section_init;
+  device_node *memory = (device_node*)obj;
+
+  /* skip the section if no memory to allocate */
+  if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
+    return;
+
+  /* check/ignore any sections of size zero */
+  section_size = bfd_get_section_size_before_reloc(the_section);
+  if (section_size == 0)
+    return;
+
+  /* find where it is to go */
+  section_vma = bfd_get_section_vma(abfd, the_section);
+
+  TRACE(trace_device_tree,
+       ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
+        bfd_get_section_name(abfd, the_section),
+        section_vma, section_size,
+        bfd_get_section_flags(abfd, the_section),
+        bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
+       ));
+
+  if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
+    section_init = zalloc(section_size);
+    if (!bfd_get_section_contents(abfd,
+                                 the_section,
+                                 section_init, 0,
+                                 section_size)) {
+      bfd_perror("core:load_section()");
+      error("load of data failed");
+      return;
+    }
+  }
+  else {
+    section_init = NULL;
+  }
+
+  /* determine the devices access */
+  if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
+    section_access = (device_is_readable | device_is_executable);
+  else if (bfd_get_section_flags(abfd, the_section) & SEC_READONLY)
+    section_access = device_is_readable;
+  else
+    section_access = (device_is_readable | device_is_writeable);
+
+  /* find our memory and add this section to its list of addresses */
+  device_node_add_address(memory,
+                         section_vma,
+                         section_size,
+                         section_access,
+                         section_init);
+}
+
+
+/* construct the device tree from the executable */
+
+STATIC_INLINE_DEVICE_TREE device_node *
+create_option_device_node(device_node *root,
+                         bfd *image)
+{
+  device_node *option_node;
+  
+  /* the option node and than its members */
+  option_node = device_node_create(root, "options", options_device,
+                                  NULL, NULL);
+
+  /* which endian are we ? */
+  device_node_create(option_node,
+                    "little-endian?",
+                    boolean_type_device,
+                    NULL,
+                    (void*)(image->xvec->byteorder_big_p ? 0 : -1));
+
+  /* what is the initial entry point */
+  device_node_create(option_node,
+                    "program-counter",
+                    integer_type_device,
+                    NULL,
+                    (void*)(bfd_get_start_address(image)));
+
+  /* address of top of boot stack */
+  TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
+  device_node_create(option_node,
+                    "stack-pointer",
+                    integer_type_device,
+                    NULL,
+                    (void*)(bfd_get_start_address(image) == 0
+                            ? clayton_memory_size /* OEA */
+                            : (image->xvec->flavour == bfd_target_elf_flavour
+                               ? 0xe0000000 /* elf */
+                               : 0x20000000 /* xcoff */)));
+
+  /* execution environment */
+  device_node_create(option_node,
+                    "vea?",
+                    boolean_type_device,
+                    NULL,
+                    (void*)(bfd_get_start_address(image) == 0
+                            ? 0
+                            : -1));
+
+  /* what type of binary */
+  TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
+  device_node_create(option_node,
+                    "elf?",
+                    boolean_type_device,
+                    NULL,
+                    (void*)(image->xvec->flavour == bfd_target_elf_flavour
+                            ? -1 /* elf binary */
+                            : 0 /* probably aix binary */));
+
+  /* must all memory transfers be naturally aligned? */
+  device_node_create(option_node,
+                    "aligned?",
+                    boolean_type_device,
+                    NULL,
+                    (void*)((WITH_ALIGNMENT == NONSTRICT_ALIGNMENT
+                             || image->xvec->byteorder_big_p
+                             || bfd_get_start_address(image) != 0)
+                            ? 0
+                            : -1));
+
+
+  return option_node;
+}
+
+
+/* clatyon is a simple machine that does not require interrupts or any
+   thing else */
+
+STATIC_INLINE_DEVICE_TREE device_node *
+create_clayton_device_tree(bfd *image)
+{
+  device_node *root;
+  device_node *io_node;
+  device_node *data_node;
+  device_node *memory_node;
+
+  /* the root */
+  root = ZALLOC(device_node);
+
+  /* memory - clayton has 2mb of RAM at location 0 */
+  memory_node = device_node_create(root,
+                                  "memory",
+                                  memory_device,
+                                  NULL,
+                                  NULL);
+  device_node_add_address(memory_node, 0x0, clayton_memory_size,
+                         (device_is_readable
+                          | device_is_writeable
+                          | device_is_executable),
+                         NULL);
+
+  /* io address space */
+  io_node = device_node_create(root, "io", bus_device, NULL, NULL);
+
+  /* and IO devices */
+  find_device_descriptor("console")
+    ->creator(io_node, "console@0x400000,0");
+  find_device_descriptor("halt")
+    ->creator(io_node, "halt@0x500000,0");
+  find_device_descriptor("icu")
+    ->creator(io_node, "icu@0x600000,0");
+
+  /* data to load */
+  data_node = device_node_create(root, "image", data_device, NULL, NULL);
+  bfd_map_over_sections(image,
+                       update_memory_node_for_section,
+                       (PTR)data_node);
+
+  /* options */
+  create_option_device_node(root, image);
+
+  return root;
+}
+
+
+/* user mode executable build up a device tree that reflects this */
+
+STATIC_INLINE_DEVICE_TREE device_node *
+create_vea_device_tree(bfd *image)
+{
+  device_node *root;
+  device_node *memory_node;
+  device_node *option_node;
+
+  /* the root */
+  root = ZALLOC(device_node);
+
+  /* memory */
+  memory_node = device_node_create(root, "memory", memory_device,
+                                  NULL, NULL);
+  bfd_map_over_sections(image,
+                       update_memory_node_for_section,
+                       (PTR)memory_node);
+  /* options - only endian so far */
+  option_node = create_option_device_node(root, image);
+
+  return root;
+}
+
+
+/* create a device tree from the specified file */
+INLINE_DEVICE_TREE device_node *
+device_tree_create(const char *file_name)
+{
+  bfd *image;
+  device_node *tree;
+
+  bfd_init(); /* could be redundant but ... */
+
+  /* open the file */
+  image = bfd_openr(file_name, NULL);
+  if (image == NULL) {
+    bfd_perror("open failed:");
+    error("nothing loaded\n");
+    return NULL;
+  }
+
+  /* check it is valid */
+  if (!bfd_check_format(image, bfd_object)) {
+    printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
+    printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
+    bfd_close(image);
+    image = NULL;
+  }
+
+  /* depending on what was found about the file, load it */
+  if (image != NULL) {
+    if (bfd_get_start_address(image) == 0) {
+      TRACE(trace_device_tree, ("create_device_tree() - clayton image\n"));
+      tree = create_clayton_device_tree(image);
+    }
+    else if (bfd_get_start_address(image) > 0) {
+      TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
+      tree = create_vea_device_tree(image);
+    }
+    bfd_close(image);
+  }
+  else {
+    error("TBD - create_device_tree() text file defining device tree\n");
+    tree = NULL;
+  }
+
+  return tree;
+}
+
+
+/* traverse a device tree applying prefix/postfix functions to it */
+
+INLINE_DEVICE_TREE void
+device_tree_traverse(device_node *root,
+                    device_tree_traverse_function *prefix,
+                    device_tree_traverse_function *postfix,
+                    void *data)
+{
+  device_node *child;
+  if (prefix != NULL)
+    prefix(root, data);
+  for (child = root->children; child != NULL; child = child->sibling) {
+    device_tree_traverse(child, prefix, postfix, data);
+  }
+  if (postfix != NULL)
+    postfix(root, data);
+}
+
+
+/* query the device tree */
+
+INLINE_DEVICE_TREE device_node *
+device_tree_find_node(device_node *root,
+                     const char *path)
+{
+  char *chp;
+  int name_len;
+  device_node *child;
+
+  /* strip off any leading `/', `../' or `./' */
+  while (1) {
+    if (strncmp(path, "/", strlen("/")) == 0) {
+      while (root->parent != NULL)
+       root = root->parent;
+      path += strlen("/");
+    }
+    else if (strncmp(path, "./", strlen("./")) == 0) {
+      root = root;
+      path += strlen("./");
+    }
+    else if (strncmp(path, "../", strlen("../")) == 0) {
+      if (root->parent != NULL)
+       root = root->parent;
+      path += strlen("../");
+    }
+    else {
+      break;
+    }
+  }
+
+  /* find the qualified (with @) and unqualified names in the path */
+  chp = strchr(path, '/');
+  name_len = (chp == NULL
+             ? strlen(path)
+             : chp - path);
+
+  /* search through children for a match */
+  for (child = root->children;
+       child != NULL;
+       child = child->sibling) {
+    if (strncmp(path, child->name, name_len) == 0
+       && (strlen(child->name) == name_len
+           || strchr(child->name, '@') == child->name + name_len)) {
+      if (path[name_len] == '\0')
+       return child;
+      else
+       return device_tree_find_node(child, path + name_len + 1);
+    }
+  }
+  return NULL;
+}
+
+INLINE_DEVICE_TREE device_node *device_tree_find_next_node
+(device_node *root,
+ const char *path,
+ device_node *last);
+
+INLINE_DEVICE_TREE signed_word
+device_tree_find_int(device_node *root,
+                    const char *path)
+{
+  device_node *int_node = device_tree_find_node(root, path);
+  if (int_node == NULL) {
+    error("device_tree_find_int() - node %s does not exist\n", path);
+    return 0;
+  }
+  else if (int_node->type != integer_type_device) {
+    error("device_tree_find_int() - node %s is not an int\n", path);
+    return 0;
+  }
+  else {
+    return (signed_word)(int_node->data);
+  }
+}
+
+
+INLINE_DEVICE_TREE const char *device_tree_find_string
+(device_node *root,
+ const char *path);
+
+INLINE_DEVICE_TREE int
+device_tree_find_boolean(device_node *root,
+                        const char *path)
+{
+  device_node *int_node = device_tree_find_node(root, path);
+  if (int_node == NULL) {
+    error("device_tree_find_boolean() - node %s does not exist\n", path);
+    return 0;
+  }
+  else if (int_node->type != boolean_type_device) {
+    error("device_tree_find_boolean() - node %s is not a boolean\n", path);
+    return 0;
+  }
+  else {
+    return (signed_word)(int_node->data);
+  }
+}
+
+
+INLINE_DEVICE_TREE void *device_tree_find_bytes
+(device_node *root,
+ const char *path);
+
+/* dump out a device node and addresses */
+
+INLINE_DEVICE_TREE void
+device_tree_dump(device_node *device,
+                void *ignore_data_argument)
+{
+  printf_filtered("(device_node@0x%x\n", device);
+  printf_filtered(" (parent 0x%x)\n", device->parent);
+  printf_filtered(" (children 0x%x)\n", device->children);
+  printf_filtered(" (sibling 0x%x)\n", device->sibling);
+  printf_filtered(" (name %s)\n", device->name ? device->name : "(null)");
+  printf_filtered(" (type %d)\n", device->type);
+  printf_filtered(" (handlers 0x%x)\n", device->callbacks);
+  printf_filtered(" (addresses %d)\n", device->addresses);
+  printf_filtered(" (data %d)\n", device->data);
+  printf_filtered(")\n");
+}
+
+#endif /* _DEVICE_TREE_C_ */
diff --git a/sim/ppc/device_tree.h b/sim/ppc/device_tree.h
new file mode 100644 (file)
index 0000000..59d764e
--- /dev/null
@@ -0,0 +1,234 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _DEVICE_TREE_H_
+#define _DEVICE_TREE_H_
+
+#ifndef INLINE_DEVICE_TREE
+#define INLINE_DEVICE_TREE
+#endif
+
+
+/* forward declaration of types */
+
+typedef struct _device_node device_node;
+typedef struct _device_address device_address;
+typedef struct _device_callbacks device_callbacks;
+
+
+/* Device callbacks: */
+
+
+/* Memory operations: transfer data to/from a processor.
+
+   These callbacks pass/return data in *host* byte order.
+
+   Should a memory read/write operation cause an interrupt (external
+   exception) then a device would typically pass an interrupt message
+   to the devices parent.  Hopefully that is an interrupt controler
+   and will know what to do with it.
+
+   Devices normally never either restart a processor or issue an
+   interrupt directly.  The only exception I've thought of could be
+   machine check type event. */
+
+typedef unsigned64 (device_reader_callback)
+     (device_node *device,
+      unsigned_word base,
+      unsigned nr_bytes,
+      cpu *processor,
+      unsigned_word cia);
+
+typedef void (device_writer_callback)
+     (device_node *device,
+      unsigned_word base,
+      unsigned nr_bytes,
+      unsigned64 val,
+      cpu *processor,
+      unsigned_word cia);
+
+/* Interrupts:
+
+   A child device uses the below to pass on to its parent changes in
+   the state of a child devices interrupt lines.
+
+   Typically, the parent being an interrupt control device, would, in
+   responce, schedule an event at the start of the next clock cycle.
+   On this event, the state of any cpu could be changed.  Other
+   devices could either ignore or pass on the interrupt message */
+
+typedef void (device_interrupt_callback)
+     (device_node *me,
+      int interrupt_status,
+      device_node *device,
+      cpu *processor,
+      unsigned_word cia);
+
+/* Create:
+
+   DEVICE_CREATOR is called once, as part of building the device tree.
+   This function gives the device the chance to attach any additional
+   data to this particular device instance.
+
+   DEVICE_INIT_CALLBACK is (re)called when ever the system is
+   (re)initialised. */
+
+typedef device_node *(device_creator)
+     (device_node *parent,
+      char *name);
+
+typedef void (device_init_callback)
+     (device_node *device);
+
+
+
+/* constructs to describe the hardware's tree of devices */
+
+typedef enum _device_type {
+  /* default */
+  unknown_device,
+  /* typical devices */
+  memory_device,
+  sequential_device,
+  block_device,
+  bus_device,
+  other_device,
+  /* atypical devices, these are for data being loaded into ram/rom */
+  data_device,
+  options_device,
+  /* types of primative nodes containing just data */
+  boolean_type_device,
+  integer_type_device,
+  string_type_device,
+  byte_type_device,
+} device_type;
+
+typedef enum _device_access {
+  device_is_readable = 1,
+  device_is_writeable = 2,
+  device_is_read_write = 3,
+  device_is_executable = 4,
+  device_is_read_exec = 5,
+  device_is_write_exec = 6,
+  device_is_read_write_exec = 7,
+} device_access;
+
+struct _device_address {
+  unsigned_word lower_bound;
+  unsigned_word upper_bound;
+  unsigned size; /* host limited */
+  void *init; /* initial data */
+  device_access access;
+  device_address *next_address;
+};
+
+struct _device_callbacks {
+  device_reader_callback *read_callback;
+  device_writer_callback *write_callback;
+  device_interrupt_callback *interrupt_callback;
+  /* device_init_callback *init_callback; */
+  /* device_init_hander *post_init_handler; */
+};
+
+struct _device_node {
+  /* where i am */
+  device_node *parent;
+  device_node *children;
+  device_node *sibling;
+  /* what I am */
+  char *name; /* eg rom@0x1234,0x40 */
+  device_type type;
+  device_callbacks *callbacks;
+  device_address *addresses;
+  void *data;
+};
+
+
+/* given the image to run, return its device tree */
+
+INLINE_DEVICE_TREE device_node *device_tree_create
+(const char *hardware_description);
+
+
+/* traverse the tree eiter pre or post fix */
+
+typedef void (device_tree_traverse_function)
+     (device_node *device,
+      void *data);
+
+INLINE_DEVICE_TREE void device_tree_traverse
+(device_node *root,
+ device_tree_traverse_function *prefix,
+ device_tree_traverse_function *postfix,
+ void *data);
+
+
+/* query the device tree */
+
+INLINE_DEVICE_TREE device_node *device_tree_find_node
+(device_node *root,
+ const char *path);
+
+INLINE_DEVICE_TREE device_node *device_tree_find_next_node
+(device_node *root,
+ const char *path,
+ device_node *last);
+
+INLINE_DEVICE_TREE signed_word device_tree_find_int
+(device_node *root,
+ const char *path);
+
+INLINE_DEVICE_TREE const char *device_tree_find_string
+(device_node *root,
+ const char *path);
+
+INLINE_DEVICE_TREE int device_tree_find_boolean
+(device_node *root,
+ const char *path);
+
+INLINE_DEVICE_TREE void *device_tree_find_bytes
+(device_node *root,
+ const char *path);
+
+/* add to the device tree */
+
+INLINE_DEVICE_TREE device_node *device_node_create
+(device_node *parent,
+ char *name,
+ device_type type,
+ device_callbacks *callbacks,
+ void *data);
+
+INLINE_DEVICE_TREE void device_node_add_address
+(device_node *node,
+ unsigned_word lower_bound,
+ unsigned size,
+ device_access access,
+ void *init);
+
+/* dump a node, pass this to the device_tree_traverse() function to
+   dump the tree */
+
+INLINE_DEVICE_TREE void device_tree_dump
+(device_node *device,
+ void *ignore_data_argument);
+
+#endif /* _DEVICE_TREE_H_ */
diff --git a/sim/ppc/devices.c b/sim/ppc/devices.c
new file mode 100644 (file)
index 0000000..96b8109
--- /dev/null
@@ -0,0 +1,442 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _DEVICES_C_
+#define _DEVICES_C_
+
+#ifndef STATIC_INLINE_DEVICES
+#define STATIC_INLINE_DEVICES STATIC_INLINE
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "basics.h"
+#include "device_tree.h"
+#include "devices.h"
+#include "events.h"
+
+#include "cpu.h" /* drats */
+
+/* Helper functions */
+
+STATIC_INLINE_DEVICES void
+parse_device_address(char *name,
+                    unsigned *base,
+                    unsigned *flags)
+{
+  /* extract the two arguments */
+  name = strchr(name, '@');
+  if (name == NULL)
+    error("missing address for device %s\n", name);
+  name++;
+  *base = strtol(name, &name, 0);
+  *flags = (*name == ','
+           ? strtol(name+1, &name, 0)
+           : 0);
+}
+
+
+/* Simple console device:
+
+   Implements a simple text output device that is attached to stdout
+   of the process running the simulation.  The devices has four
+   word registers:
+
+   0: read
+   4: read-status
+   8: write
+   c: write-status
+
+   Where a nonzero status register indicates that the device is ready
+   (input fifo contains a character or output fifo has space).
+
+   Illustrates: Mapping read/write to device operations onto actual
+   registers.
+
+   */
+
+typedef struct _console_buffer {
+  char buffer;
+  int status;
+  event_entry_tag event_tag;
+} console_buffer;
+
+typedef struct _console_device {
+  unsigned_word my_base_address;
+  int interrupt_delay;
+  console_buffer input;
+  console_buffer output;
+} console_device;
+
+typedef enum {
+  console_read_buffer = 0,
+  console_read_status = 4,
+  console_write_buffer = 8,
+  console_write_status = 12,
+  console_offset_mask = 0xc,
+  console_size = 16,
+} console_offsets;
+
+
+STATIC_INLINE_DEVICES unsigned64
+console_read_callback(device_node *device,
+                     unsigned_word base,
+                     unsigned nr_bytes,
+                     cpu *processor,
+                     unsigned_word cia)
+{
+  console_device *con = (console_device*)device->data;
+  TRACE(trace_console_device,
+       ("device=0x%x, base=0x%x, nr_bytes=%d\n",
+        device, base, nr_bytes));
+
+  /* handle the request */
+
+  switch (base & console_offset_mask) {
+
+  case console_read_buffer:
+    return con->input.buffer;
+
+  case console_read_status:
+    { /* check for input */
+      int flags;
+      int status;
+      /* get the old status */
+      flags = fcntl(0, F_GETFL, 0);
+      if (flags == -1) {
+       perror("console");
+       return 0;
+      }
+      /* temp, disable blocking IO */
+      status = fcntl(0, F_SETFL, flags | O_NDELAY);
+      if (status == -1) {
+       perror("console");
+       return 0;
+      }
+      /* try for input */
+      status = read(0, &con->input.buffer, 1);
+      if (status == 1) {
+       con->input.status = 1;
+      }
+      else {
+       con->input.status = 0;
+      }
+      /* return to regular vewing */
+      fcntl(0, F_SETFL, flags);
+    }
+    return con->input.status;
+
+  case console_write_buffer:
+    return con->output.buffer;
+
+  case console_write_status:
+    return con->output.status;
+
+  default:
+    error("console_read_callback() internal error\n");
+    return 0;
+
+  }
+
+}
+
+STATIC_INLINE_DEVICES void
+console_write_callback(device_node *device,
+                      unsigned_word base,
+                      unsigned nr_bytes,
+                      unsigned64 val,
+                      cpu *processor,
+                      unsigned_word cia)
+{
+  console_device *con = (console_device*)device->data;
+
+  TRACE(trace_console_device,
+       ("device=0x%x, base=0x%x, nr_bytes=%d, val=0x%x\n",
+        device, base, nr_bytes, val));
+
+  /* check for bus error */
+  if (base & 0x3) {
+    error("%s - misaligned base address, base=0x%x, nr_bytes=%d\n",
+         "console_write_callback", base, nr_bytes);
+  }
+
+  switch (base & console_offset_mask) {
+  case console_read_buffer: con->input.buffer = val; break;
+  case console_read_status: con->input.status = val; break;
+  case console_write_buffer:
+    TRACE(trace_console_device,
+         ("<%c:%d>", val, val));
+    printf_filtered("%c", val);
+    con->output.buffer = val;
+    con->output.status = 1;
+    break;
+  case console_write_status:
+    con->output.status = val;
+    break;
+  }
+
+}
+
+static device_callbacks console_callbacks = {
+  console_read_callback,
+  console_write_callback,
+};
+
+STATIC_INLINE_DEVICES device_node *
+console_create(device_node *parent,
+              char *name)
+{
+  device_node *device;
+  unsigned address_base;
+  unsigned address_flags;
+
+  /* create the descriptor */
+  console_device *console = ZALLOC(console_device);
+
+  /* extract the two arguments */
+  parse_device_address(name, &address_base, &address_flags);
+
+  /* fill in the details */
+  console->my_base_address = address_base;
+  console->interrupt_delay = address_flags;
+  console->output.status = 1;
+  console->output.buffer = '\0';
+  console->input.status = 0;
+  console->input.buffer = '\0';
+
+  /* insert into the device tree along with its address info */
+  device = device_node_create(parent, name, sequential_device,
+                             &console_callbacks, console);
+  device_node_add_address(device,
+                         address_base,
+                         console_size,
+                         device_is_read_write_exec,
+                         NULL);
+
+  return device;
+}
+
+static device_descriptor console_descriptor = {
+  "console",
+  console_create,
+};
+
+
+/* ICU device:
+
+   Single 4 byte register.  Read returns processor number.  Write
+   interrupts specified processor.
+
+   Illustrates passing of events to parent device. Passing of
+   interrupts to parent bus.
+
+   NB: For the sake of illustrating the passing of interrupts.  This
+   device doesn't pass interrupt events to its parent.  Instead it
+   passes them back to its self. */
+
+STATIC_INLINE_DEVICES unsigned64
+icu_read_callback(device_node *device,
+                 unsigned_word base,
+                 unsigned nr_bytes,
+                 cpu *processor,
+                 unsigned_word cia)
+{
+  TRACE(trace_icu_device,
+       ("device=0x%x, base=0x%x, nr_bytes=%d\n",
+        device, base, nr_bytes));
+  return cpu_nr(processor);
+}
+
+STATIC_INLINE_DEVICES void
+icu_write_callback(device_node *device,
+                  unsigned_word base,
+                  unsigned nr_bytes,
+                  unsigned64 val,
+                  cpu *processor,
+                  unsigned_word cia)
+{
+  psim *system = cpu_system(processor);
+  device_node *parent = device; /* NB: normally would be device->parent */
+  TRACE(trace_icu_device,
+       ("device=0x%x, base=0x%x, nr_bytes=%d, val=0x%x\n",
+        device, base, nr_bytes, val));
+  /* tell the parent device that the interrupt lines have changed.
+     For this fake ICU.  The interrupt lines just indicate the cpu to
+     interrupt next */
+  parent->callbacks->interrupt_callback(parent, val, device, processor, cia);
+}
+
+STATIC_INLINE_DEVICES void
+icu_do_interrupt(event_queue *queue,
+                void *data)
+{
+  cpu *target = (cpu*)data;
+  /* try to interrupt the processor.  If the attempt fails, try again
+     on the next tick */
+  if (!external_interrupt(target))
+    event_queue_schedule(queue, 1, icu_do_interrupt, target);
+}
+
+STATIC_INLINE_DEVICES void
+icu_interrupt_callback(device_node *me,
+                      int interrupt_status,
+                      device_node *device,
+                      cpu *processor,
+                      unsigned_word cia)
+{
+  /* the interrupt controler can't interrupt a cpu at any time.
+     Rather it must synchronize with the system clock before
+     performing an interrupt on the given processor */
+  psim *system = cpu_system(processor);
+  cpu *target = psim_cpu(system, interrupt_status);
+  if (target != NULL) {
+    event_queue *events = cpu_event_queue(target);
+    event_queue_schedule(events, 1, icu_do_interrupt, target);
+  }
+}
+
+static device_callbacks icu_callbacks = {
+  icu_read_callback,
+  icu_write_callback,
+  icu_interrupt_callback,
+};
+
+STATIC_INLINE_DEVICES device_node *
+icu_create(device_node *parent,
+              char *name)
+{
+  device_node *device;
+  unsigned address_base;
+  unsigned address_flags;
+
+  /* extract the two arguments */
+  parse_device_address(name, &address_base, &address_flags);
+
+  /* insert into the device tree along with its address info */
+  device = device_node_create(parent, name, sequential_device,
+                             &icu_callbacks, 0);
+  device_node_add_address(device,
+                         address_base,
+                         4,
+                         device_is_read_write_exec,
+                         NULL);
+
+  return device;
+}
+
+static device_descriptor icu_descriptor = {
+  "icu",
+  icu_create,
+};
+
+
+
+
+
+/* HALT device:
+
+   With real hardware, the processor operation is normally terminated
+   through a reset.  This device illustrates how a reset device could
+   be attached to an address */
+
+STATIC_INLINE_DEVICES unsigned64
+halt_read_callback(device_node *device,
+                  unsigned_word base,
+                  unsigned nr_bytes,
+                  cpu *processor,
+                  unsigned_word cia)
+{
+  cpu_halt(processor, cia, was_exited, 0);
+  return 0;
+}
+
+STATIC_INLINE_DEVICES void
+halt_write_callback(device_node *device,
+                   unsigned_word base,
+                   unsigned nr_bytes,
+                   unsigned64 val,
+                   cpu *processor,
+                   unsigned_word cia)
+{
+  cpu_halt(processor, cia, was_exited, 0);
+}
+
+
+static device_callbacks halt_callbacks = {
+  halt_read_callback,
+  halt_write_callback,
+};
+
+STATIC_INLINE_DEVICES device_node *
+halt_create(device_node *parent,
+           char *name)
+{
+  device_node *device;
+  unsigned address_base;
+  unsigned address_flags;
+
+  parse_device_address(name, &address_base, &address_flags);
+  device = device_node_create(parent, name, other_device,
+                             &halt_callbacks, NULL);
+  device_node_add_address(device,
+                         address_base,
+                         4,
+                         device_is_read_write_exec,
+                         NULL);
+  return device;
+}
+
+static device_descriptor halt_descriptor = {
+  "halt",
+  halt_create,
+};
+
+
+static device_descriptor *devices[] = {
+  &console_descriptor,
+  &halt_descriptor,
+  &icu_descriptor,
+  NULL,
+};
+
+
+INLINE_DEVICES device_descriptor *
+find_device_descriptor(char *name)
+{
+  device_descriptor **device;
+  int name_len;
+  char *chp;
+  chp = strchr(name, '@');
+  name_len = (chp == NULL ? strlen(name) : chp - name);
+  for (device = devices; *device != NULL; device++) {
+    if (strncmp(name, (*device)->name, name_len) == 0
+       && ((*device)->name[name_len] == '\0'
+           || (*device)->name[name_len] == '@'))
+      return *device;
+  }
+  return NULL;
+}
+
+#endif /* _DEVICES_C_ */
diff --git a/sim/ppc/devices.h b/sim/ppc/devices.h
new file mode 100644 (file)
index 0000000..e115779
--- /dev/null
@@ -0,0 +1,42 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _DEVICES_H_
+#define _DEVICES_H_
+
+#ifndef INLINE_DEVICES
+#define INLINE_DEVICES
+#endif
+
+#include "device_tree.h"
+
+/* table of all the configured devices */
+
+typedef struct _device_descriptor device_descriptor;
+struct _device_descriptor {
+  char *name;
+  device_creator *creator;
+};
+
+
+INLINE_DEVICES device_descriptor *find_device_descriptor(char *name);
+
+#endif /* _DEVICES_H_ */
diff --git a/sim/ppc/double.c b/sim/ppc/double.c
new file mode 100644 (file)
index 0000000..8594301
--- /dev/null
@@ -0,0 +1,42 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _DOUBLE_C_
+#define _DOUBLE_C_
+
+#include "basics.h"
+
+#define SFtype unsigned32
+#define DFtype unsigned64
+
+#define HItype signed16
+#define SItype signed32
+#define DItype signed64
+
+#define UHItype unsigned16
+#define USItype unsigned32
+#define UDItype unsigned64
+
+
+#define US_SOFTWARE_GOFAST
+#include "dp-bit.c"
+
+#endif
diff --git a/sim/ppc/dp-bit.c b/sim/ppc/dp-bit.c
new file mode 100644 (file)
index 0000000..3313132
--- /dev/null
@@ -0,0 +1,1307 @@
+/* This is a software floating point library which can be used instead of
+   the floating point routines in libgcc1.c for targets without hardware
+   floating point.  */
+
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+
+This file 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file 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; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* This implements IEEE 754 format arithmetic, but does not provide a
+   mechanism for setting the rounding mode, or for generating or handling
+   exceptions.
+
+   The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
+   Wilson, all of Cygnus Support.  */
+
+/* The intended way to use this file is to make two copies, add `#define FLOAT'
+   to one copy, then compile both copies and add them to libgcc.a.  */
+
+/* The following macros can be defined to change the behaviour of this file:
+   FLOAT: Implement a `float', aka SFmode, fp library.  If this is not
+     defined, then this file implements a `double', aka DFmode, fp library.
+   FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
+     don't include float->double conversion which requires the double library.
+     This is useful only for machines which can't support doubles, e.g. some
+     8-bit processors.
+   CMPtype: Specify the type that floating point compares should return.
+     This defaults to SItype, aka int.
+   US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
+     US Software goFast library.  If this is not defined, the entry points use
+     the same names as libgcc1.c.
+   _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
+     two integers to the FLO_union_type.  
+   NO_NANS: Disable nan and infinity handling
+   SMALL_MACHINE: Useful when operations on QIs and HIs are faster
+     than on an SI */
+
+#ifndef SFtype
+typedef SFtype __attribute__ ((mode (SF)));
+#endif
+#ifndef DFtype
+typedef DFtype __attribute__ ((mode (DF)));
+#endif
+
+#ifndef HItype
+typedef int HItype __attribute__ ((mode (HI)));
+#endif
+#ifndef SItype
+typedef int SItype __attribute__ ((mode (SI)));
+#endif
+#ifndef DItype
+typedef int DItype __attribute__ ((mode (DI)));
+#endif
+
+/* The type of the result of a fp compare */
+#ifndef CMPtype
+#define CMPtype SItype
+#endif
+
+#ifndef UHItype
+typedef unsigned int UHItype __attribute__ ((mode (HI)));
+#endif
+#ifndef USItype
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+#endif
+#ifndef UDItype
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+#endif
+
+#define MAX_SI_INT   ((SItype) ((unsigned) (~0)>>1))
+#define MAX_USI_INT  ((USItype) ~0)
+
+
+#ifdef FLOAT_ONLY
+#define NO_DI_MODE
+#endif
+
+#ifdef FLOAT
+#      define NGARDS    7L
+#      define GARDROUND 0x3f
+#      define GARDMASK  0x7f
+#      define GARDMSB   0x40
+#      define EXPBITS 8
+#      define EXPBIAS 127
+#      define FRACBITS 23
+#      define EXPMAX (0xff)
+#      define QUIET_NAN 0x100000L
+#      define FRAC_NBITS 32
+#      define FRACHIGH  0x80000000L
+#      define FRACHIGH2 0xc0000000L
+       typedef USItype fractype;
+       typedef UHItype halffractype;
+       typedef SFtype FLO_type;
+       typedef SItype intfrac;
+
+#else
+#      define PREFIXFPDP dp
+#      define PREFIXSFDF df
+#      define NGARDS 8L
+#      define GARDROUND 0x7f
+#      define GARDMASK  0xff
+#      define GARDMSB   0x80
+#      define EXPBITS 11
+#      define EXPBIAS 1023
+#      define FRACBITS 52
+#      define EXPMAX (0x7ff)
+#      define QUIET_NAN 0x8000000000000LL
+#      define FRAC_NBITS 64
+#      define FRACHIGH  0x8000000000000000LL
+#      define FRACHIGH2 0xc000000000000000LL
+       typedef UDItype fractype;
+       typedef USItype halffractype;
+       typedef DFtype FLO_type;
+       typedef DItype intfrac;
+#endif
+
+#ifdef US_SOFTWARE_GOFAST
+#      ifdef FLOAT
+#              define add              fpadd
+#              define sub              fpsub
+#              define multiply         fpmul
+#              define divide           fpdiv
+#              define compare          fpcmp
+#              define si_to_float      sitofp
+#              define float_to_si      fptosi
+#              define float_to_usi     fptoui
+#              define negate           __negsf2
+#              define sf_to_df         fptodp
+#              define dptofp           dptofp
+#else
+#              define add              dpadd
+#              define sub              dpsub
+#              define multiply         dpmul
+#              define divide           dpdiv
+#              define compare          dpcmp
+#              define si_to_float      litodp
+#              define float_to_si      dptoli
+#              define float_to_usi     dptoul
+#              define negate           __negdf2
+#              define df_to_sf         dptofp
+#endif
+#else
+#      ifdef FLOAT
+#              define add              __addsf3
+#              define sub              __subsf3
+#              define multiply         __mulsf3
+#              define divide           __divsf3
+#              define compare          __cmpsf2
+#              define _eq_f2           __eqsf2
+#              define _ne_f2           __nesf2
+#              define _gt_f2           __gtsf2
+#              define _ge_f2           __gesf2
+#              define _lt_f2           __ltsf2
+#              define _le_f2           __lesf2
+#              define si_to_float      __floatsisf
+#              define float_to_si      __fixsfsi
+#              define float_to_usi     __fixunssfsi
+#              define negate           __negsf2
+#              define sf_to_df         __extendsfdf2
+#else
+#              define add              __adddf3
+#              define sub              __subdf3
+#              define multiply         __muldf3
+#              define divide           __divdf3
+#              define compare          __cmpdf2
+#              define _eq_f2           __eqdf2
+#              define _ne_f2           __nedf2
+#              define _gt_f2           __gtdf2
+#              define _ge_f2           __gedf2
+#              define _lt_f2           __ltdf2
+#              define _le_f2           __ledf2
+#              define si_to_float      __floatsidf
+#              define float_to_si      __fixdfsi
+#              define float_to_usi     __fixunsdfsi
+#              define negate           __negdf2
+#              define df_to_sf         __truncdfsf2
+#      endif
+#endif
+
+
+#ifndef INLINE
+#define INLINE __inline__
+#endif
+
+/* Preserve the sticky-bit when shifting fractions to the right.  */
+#define LSHIFT(a) { a = (a & 1) | (a >> 1); }
+
+/* numeric parameters */
+/* F_D_BITOFF is the number of bits offset between the MSB of the mantissa
+   of a float and of a double. Assumes there are only two float types.
+   (double::FRAC_BITS+double::NGARGS-(float::FRAC_BITS-float::NGARDS))
+ */
+#define F_D_BITOFF (52+8-(23+7))
+
+
+#define NORMAL_EXPMIN (-(EXPBIAS)+1)
+#define IMPLICIT_1 (1LL<<(FRACBITS+NGARDS))
+#define IMPLICIT_2 (1LL<<(FRACBITS+1+NGARDS))
+
+/* common types */
+
+typedef enum
+{
+  CLASS_SNAN,
+  CLASS_QNAN,
+  CLASS_ZERO,
+  CLASS_NUMBER,
+  CLASS_INFINITY
+} fp_class_type;
+
+typedef struct
+{
+#ifdef SMALL_MACHINE
+  char class;
+  unsigned char sign;
+  short normal_exp;
+#else
+  fp_class_type class;
+  unsigned int sign;
+  int normal_exp;
+#endif
+
+  union
+    {
+      fractype ll;
+      halffractype l[2];
+    } fraction;
+} fp_number_type;
+
+typedef union
+{
+  FLO_type value;
+#ifdef _DEBUG_BITFLOAT
+  int l[2];
+#endif
+  struct
+    {
+#ifndef FLOAT_BIT_ORDER_MISMATCH
+      unsigned int sign:1 __attribute__ ((packed));
+      unsigned int exp:EXPBITS __attribute__ ((packed));
+      fractype fraction:FRACBITS __attribute__ ((packed));
+#else
+      fractype fraction:FRACBITS __attribute__ ((packed));
+      unsigned int exp:EXPBITS __attribute__ ((packed));
+      unsigned int sign:1 __attribute__ ((packed));
+#endif
+    }
+  bits;
+}
+FLO_union_type;
+
+
+/* end of header */
+
+/* IEEE "special" number predicates */
+
+#ifdef NO_NANS
+
+#define nan() 0
+#define isnan(x) 0
+#define isinf(x) 0
+#else
+
+INLINE
+static fp_number_type *
+nan ()
+{
+  static fp_number_type thenan;
+
+  return &thenan;
+}
+
+INLINE
+static int
+isnan ( fp_number_type *  x)
+{
+  return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
+}
+
+INLINE
+static int
+isinf ( fp_number_type *  x)
+{
+  return x->class == CLASS_INFINITY;
+}
+
+#endif
+
+INLINE
+static int
+iszero ( fp_number_type *  x)
+{
+  return x->class == CLASS_ZERO;
+}
+
+INLINE 
+static void
+flip_sign ( fp_number_type *  x)
+{
+  x->sign = !x->sign;
+}
+
+static FLO_type
+pack_d ( fp_number_type *  src)
+{
+  FLO_union_type dst;
+  fractype fraction = src->fraction.ll;        /* wasn't unsigned before? */
+
+  dst.bits.sign = src->sign;
+
+  if (isnan (src))
+    {
+      dst.bits.exp = EXPMAX;
+      dst.bits.fraction = src->fraction.ll;
+      if (src->class == CLASS_QNAN || 1)
+       {
+         dst.bits.fraction |= QUIET_NAN;
+       }
+    }
+  else if (isinf (src))
+    {
+      dst.bits.exp = EXPMAX;
+      dst.bits.fraction = 0;
+    }
+  else if (iszero (src))
+    {
+      dst.bits.exp = 0;
+      dst.bits.fraction = 0;
+    }
+  else if (fraction == 0)
+    {
+      dst.value = 0;
+    }
+  else
+    {
+      if (src->normal_exp < NORMAL_EXPMIN)
+       {
+         /* This number's exponent is too low to fit into the bits
+            available in the number, so we'll store 0 in the exponent and
+            shift the fraction to the right to make up for it.  */
+
+         int shift = NORMAL_EXPMIN - src->normal_exp;
+
+         dst.bits.exp = 0;
+
+         if (shift > FRAC_NBITS - NGARDS)
+           {
+             /* No point shifting, since it's more that 64 out.  */
+             fraction = 0;
+           }
+         else
+           {
+             /* Shift by the value */
+             fraction >>= shift;
+           }
+         fraction >>= NGARDS;
+         dst.bits.fraction = fraction;
+       }
+      else if (src->normal_exp > EXPBIAS)
+       {
+         dst.bits.exp = EXPMAX;
+         dst.bits.fraction = 0;
+       }
+      else
+       {
+         dst.bits.exp = src->normal_exp + EXPBIAS;
+         /* IF the gard bits are the all zero, but the first, then we're
+            half way between two numbers, choose the one which makes the
+            lsb of the answer 0.  */
+         if ((fraction & GARDMASK) == GARDMSB)
+           {
+             if (fraction & (1 << NGARDS))
+               fraction += GARDROUND + 1;
+           }
+         else
+           {
+             /* Add a one to the guards to round up */
+             fraction += GARDROUND;
+           }
+         if (fraction >= IMPLICIT_2)
+           {
+             fraction >>= 1;
+             dst.bits.exp += 1;
+           }
+         fraction >>= NGARDS;
+         dst.bits.fraction = fraction;
+       }
+    }
+  return dst.value;
+}
+
+static void
+unpack_d (FLO_union_type * src, fp_number_type * dst)
+{
+  fractype fraction = src->bits.fraction;
+
+  dst->sign = src->bits.sign;
+  if (src->bits.exp == 0)
+    {
+      /* Hmm.  Looks like 0 */
+      if (fraction == 0)
+       {
+         /* tastes like zero */
+         dst->class = CLASS_ZERO;
+       }
+      else
+       {
+         /* Zero exponent with non zero fraction - it's denormalized,
+            so there isn't a leading implicit one - we'll shift it so
+            it gets one.  */
+         dst->normal_exp = src->bits.exp - EXPBIAS + 1;
+         fraction <<= NGARDS;
+
+         dst->class = CLASS_NUMBER;
+#if 1
+         while (fraction < IMPLICIT_1)
+           {
+             fraction <<= 1;
+             dst->normal_exp--;
+           }
+#endif
+         dst->fraction.ll = fraction;
+       }
+    }
+  else if (src->bits.exp == EXPMAX)
+    {
+      /* Huge exponent*/
+      if (fraction == 0)
+       {
+         /* Attached to a zero fraction - means infinity */
+         dst->class = CLASS_INFINITY;
+       }
+      else
+       {
+         /* Non zero fraction, means nan */
+         if (dst->sign)
+           {
+             dst->class = CLASS_SNAN;
+           }
+         else
+           {
+             dst->class = CLASS_QNAN;
+           }
+         /* Keep the fraction part as the nan number */
+         dst->fraction.ll = fraction;
+       }
+    }
+  else
+    {
+      /* Nothing strange about this number */
+      dst->normal_exp = src->bits.exp - EXPBIAS;
+      dst->class = CLASS_NUMBER;
+      dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
+    }
+}
+
+static fp_number_type *
+_fpadd_parts (fp_number_type * a,
+             fp_number_type * b,
+             fp_number_type * tmp)
+{
+  intfrac tfraction;
+
+  /* Put commonly used fields in local variables.  */
+  int a_normal_exp;
+  int b_normal_exp;
+  fractype a_fraction;
+  fractype b_fraction;
+
+  if (isnan (a))
+    {
+      return a;
+    }
+  if (isnan (b))
+    {
+      return b;
+    }
+  if (isinf (a))
+    {
+      /* Adding infinities with opposite signs yields a NaN.  */
+      if (isinf (b) && a->sign != b->sign)
+       return nan ();
+      return a;
+    }
+  if (isinf (b))
+    {
+      return b;
+    }
+  if (iszero (b))
+    {
+      return a;
+    }
+  if (iszero (a))
+    {
+      return b;
+    }
+
+  /* Got two numbers. shift the smaller and increment the exponent till
+     they're the same */
+  {
+    int diff;
+
+    a_normal_exp = a->normal_exp;
+    b_normal_exp = b->normal_exp;
+    a_fraction = a->fraction.ll;
+    b_fraction = b->fraction.ll;
+
+    diff = a_normal_exp - b_normal_exp;
+
+    if (diff < 0)
+      diff = -diff;
+    if (diff < FRAC_NBITS)
+      {
+       /* ??? This does shifts one bit at a time.  Optimize.  */
+       while (a_normal_exp > b_normal_exp)
+         {
+           b_normal_exp++;
+           LSHIFT (b_fraction);
+         }
+       while (b_normal_exp > a_normal_exp)
+         {
+           a_normal_exp++;
+           LSHIFT (a_fraction);
+         }
+      }
+    else
+      {
+       /* Somethings's up.. choose the biggest */
+       if (a_normal_exp > b_normal_exp)
+         {
+           b_normal_exp = a_normal_exp;
+           b_fraction = 0;
+         }
+       else
+         {
+           a_normal_exp = b_normal_exp;
+           a_fraction = 0;
+         }
+      }
+  }
+
+  if (a->sign != b->sign)
+    {
+      if (a->sign)
+       {
+         tfraction = -a_fraction + b_fraction;
+       }
+      else
+       {
+         tfraction = a_fraction - b_fraction;
+       }
+      if (tfraction > 0)
+       {
+         tmp->sign = 0;
+         tmp->normal_exp = a_normal_exp;
+         tmp->fraction.ll = tfraction;
+       }
+      else
+       {
+         tmp->sign = 1;
+         tmp->normal_exp = a_normal_exp;
+         tmp->fraction.ll = -tfraction;
+       }
+      /* and renormalize it */
+
+      while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
+       {
+         tmp->fraction.ll <<= 1;
+         tmp->normal_exp--;
+       }
+    }
+  else
+    {
+      tmp->sign = a->sign;
+      tmp->normal_exp = a_normal_exp;
+      tmp->fraction.ll = a_fraction + b_fraction;
+    }
+  tmp->class = CLASS_NUMBER;
+  /* Now the fraction is added, we have to shift down to renormalize the
+     number */
+
+  if (tmp->fraction.ll >= IMPLICIT_2)
+    {
+      LSHIFT (tmp->fraction.ll);
+      tmp->normal_exp++;
+    }
+  return tmp;
+
+}
+
+FLO_type
+add (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+  fp_number_type tmp;
+  fp_number_type *res;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  res = _fpadd_parts (&a, &b, &tmp);
+
+  return pack_d (res);
+}
+
+FLO_type
+sub (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+  fp_number_type tmp;
+  fp_number_type *res;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  b.sign ^= 1;
+
+  res = _fpadd_parts (&a, &b, &tmp);
+
+  return pack_d (res);
+}
+
+static fp_number_type *
+_fpmul_parts ( fp_number_type *  a,
+              fp_number_type *  b,
+              fp_number_type * tmp)
+{
+  fractype low = 0;
+  fractype high = 0;
+
+  if (isnan (a))
+    {
+      a->sign = a->sign != b->sign;
+      return a;
+    }
+  if (isnan (b))
+    {
+      b->sign = a->sign != b->sign;
+      return b;
+    }
+  if (isinf (a))
+    {
+      if (iszero (b))
+       return nan ();
+      a->sign = a->sign != b->sign;
+      return a;
+    }
+  if (isinf (b))
+    {
+      if (iszero (a))
+       {
+         return nan ();
+       }
+      b->sign = a->sign != b->sign;
+      return b;
+    }
+  if (iszero (a))
+    {
+      a->sign = a->sign != b->sign;
+      return a;
+    }
+  if (iszero (b))
+    {
+      b->sign = a->sign != b->sign;
+      return b;
+    }
+
+  /* Calculate the mantissa by multiplying both 64bit numbers to get a
+     128 bit number */
+  {
+    fractype x = a->fraction.ll;
+    fractype ylow = b->fraction.ll;
+    fractype yhigh = 0;
+    int bit;
+
+#if defined(NO_DI_MODE)
+    {
+      /* ??? This does multiplies one bit at a time.  Optimize.  */
+      for (bit = 0; bit < FRAC_NBITS; bit++)
+       {
+         int carry;
+
+         if (x & 1)
+           {
+             carry = (low += ylow) < ylow;
+             high += yhigh + carry;
+           }
+         yhigh <<= 1;
+         if (ylow & FRACHIGH)
+           {
+             yhigh |= 1;
+           }
+         ylow <<= 1;
+         x >>= 1;
+       }
+    }
+#elif defined(FLOAT) 
+    {
+      /* Multiplying two 32 bit numbers to get a 64 bit number  on 
+        a machine with DI, so we're safe */
+
+      DItype answer = (DItype)(a->fraction.ll) * (DItype)(b->fraction.ll);
+      
+      high = answer >> 32;
+      low = answer;
+    }
+#else
+    /* Doing a 64*64 to 128 */
+    {
+      UDItype nl = a->fraction.ll & 0xffffffff;
+      UDItype nh = a->fraction.ll >> 32;
+      UDItype ml = b->fraction.ll & 0xffffffff;
+      UDItype mh = b->fraction.ll >>32;
+      UDItype pp_ll = ml * nl;
+      UDItype pp_hl = mh * nl;
+      UDItype pp_lh = ml * nh;
+      UDItype pp_hh = mh * nh;
+      UDItype res2 = 0;
+      UDItype res0 = 0;
+      UDItype ps_hh__ = pp_hl + pp_lh;
+      if (ps_hh__ < pp_hl)
+       res2 += 0x100000000LL;
+      pp_hl = (ps_hh__ << 32) & 0xffffffff00000000LL;
+      res0 = pp_ll + pp_hl;
+      if (res0 < pp_ll)
+       res2++;
+      res2 += ((ps_hh__ >> 32) & 0xffffffffL) + pp_hh;
+      high = res2;
+      low = res0;
+    }
+#endif
+  }
+
+  tmp->normal_exp = a->normal_exp + b->normal_exp;
+  tmp->sign = a->sign != b->sign;
+#ifdef FLOAT
+  tmp->normal_exp += 2;                /* ??????????????? */
+#else
+  tmp->normal_exp += 4;                /* ??????????????? */
+#endif
+  while (high >= IMPLICIT_2)
+    {
+      tmp->normal_exp++;
+      if (high & 1)
+       {
+         low >>= 1;
+         low |= FRACHIGH;
+       }
+      high >>= 1;
+    }
+  while (high < IMPLICIT_1)
+    {
+      tmp->normal_exp--;
+
+      high <<= 1;
+      if (low & FRACHIGH)
+       high |= 1;
+      low <<= 1;
+    }
+  /* rounding is tricky. if we only round if it won't make us round later. */
+#if 0
+  if (low & FRACHIGH2)
+    {
+      if (((high & GARDMASK) != GARDMSB)
+         && (((high + 1) & GARDMASK) == GARDMSB))
+       {
+         /* don't round, it gets done again later. */
+       }
+      else
+       {
+         high++;
+       }
+    }
+#endif
+  if ((high & GARDMASK) == GARDMSB)
+    {
+      if (high & (1 << NGARDS))
+       {
+         /* half way, so round to even */
+         high += GARDROUND + 1;
+       }
+      else if (low)
+       {
+         /* but we really weren't half way */
+         high += GARDROUND + 1;
+       }
+    }
+  tmp->fraction.ll = high;
+  tmp->class = CLASS_NUMBER;
+  return tmp;
+}
+
+FLO_type
+multiply (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+  fp_number_type tmp;
+  fp_number_type *res;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  res = _fpmul_parts (&a, &b, &tmp);
+
+  return pack_d (res);
+}
+
+static fp_number_type *
+_fpdiv_parts (fp_number_type * a,
+             fp_number_type * b,
+             fp_number_type * tmp)
+{
+  fractype low = 0;
+  fractype high = 0;
+  fractype r0, r1, y0, y1, bit;
+  fractype q;
+  fractype numerator;
+  fractype denominator;
+  fractype quotient;
+  fractype remainder;
+
+  if (isnan (a))
+    {
+      return a;
+    }
+  if (isnan (b))
+    {
+      return b;
+    }
+  if (isinf (a) || iszero (a))
+    {
+      if (a->class == b->class)
+       return nan ();
+      return a;
+    }
+  a->sign = a->sign ^ b->sign;
+
+  if (isinf (b))
+    {
+      a->fraction.ll = 0;
+      a->normal_exp = 0;
+      return a;
+    }
+  if (iszero (b))
+    {
+      a->class = CLASS_INFINITY;
+      return b;
+    }
+
+  /* Calculate the mantissa by multiplying both 64bit numbers to get a
+     128 bit number */
+  {
+    int carry;
+    intfrac d0, d1;            /* weren't unsigned before ??? */
+
+    /* quotient =
+       ( numerator / denominator) * 2^(numerator exponent -  denominator exponent)
+     */
+
+    a->normal_exp = a->normal_exp - b->normal_exp;
+    numerator = a->fraction.ll;
+    denominator = b->fraction.ll;
+
+    if (numerator < denominator)
+      {
+       /* Fraction will be less than 1.0 */
+       numerator *= 2;
+       a->normal_exp--;
+      }
+    bit = IMPLICIT_1;
+    quotient = 0;
+    /* ??? Does divide one bit at a time.  Optimize.  */
+    while (bit)
+      {
+       if (numerator >= denominator)
+         {
+           quotient |= bit;
+           numerator -= denominator;
+         }
+       bit >>= 1;
+       numerator *= 2;
+      }
+
+    if ((quotient & GARDMASK) == GARDMSB)
+      {
+       if (quotient & (1 << NGARDS))
+         {
+           /* half way, so round to even */
+           quotient += GARDROUND + 1;
+         }
+       else if (numerator)
+         {
+           /* but we really weren't half way, more bits exist */
+           quotient += GARDROUND + 1;
+         }
+      }
+
+    a->fraction.ll = quotient;
+    return (a);
+  }
+}
+
+FLO_type
+divide (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+  fp_number_type tmp;
+  fp_number_type *res;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  res = _fpdiv_parts (&a, &b, &tmp);
+
+  return pack_d (res);
+}
+
+/* according to the demo, fpcmp returns a comparison with 0... thus
+   a<b -> -1
+   a==b -> 0
+   a>b -> +1
+ */
+
+static int
+_fpcmp_parts (fp_number_type * a, fp_number_type * b)
+{
+#if 0
+  /* either nan -> unordered. Must be checked outside of this routine. */
+  if (isnan (a) && isnan (b))
+    {
+      return 1;                        /* still unordered! */
+    }
+#endif
+
+  if (isnan (a) || isnan (b))
+    {
+      return 1;                        /* how to indicate unordered compare? */
+    }
+  if (isinf (a) && isinf (b))
+    {
+      /* +inf > -inf, but +inf != +inf */
+      /* b    \a| +inf(0)| -inf(1)
+       ______\+--------+--------
+       +inf(0)| a==b(0)| a<b(-1)
+       -------+--------+--------
+       -inf(1)| a>b(1) | a==b(0)
+       -------+--------+--------
+       So since unordered must be non zero, just line up the columns...
+       */
+      return b->sign - a->sign;
+    }
+  /* but not both... */
+  if (isinf (a))
+    {
+      return a->sign ? -1 : 1;
+    }
+  if (isinf (b))
+    {
+      return b->sign ? 1 : -1;
+    }
+  if (iszero (a) && iszero (b))
+    {
+      return 0;
+    }
+  if (iszero (a))
+    {
+      return b->sign ? 1 : -1;
+    }
+  if (iszero (b))
+    {
+      return a->sign ? -1 : 1;
+    }
+  /* now both are "normal". */
+  if (a->sign != b->sign)
+    {
+      /* opposite signs */
+      return a->sign ? -1 : 1;
+    }
+  /* same sign; exponents? */
+  if (a->normal_exp > b->normal_exp)
+    {
+      return a->sign ? -1 : 1;
+    }
+  if (a->normal_exp < b->normal_exp)
+    {
+      return a->sign ? 1 : -1;
+    }
+  /* same exponents; check size. */
+  if (a->fraction.ll > b->fraction.ll)
+    {
+      return a->sign ? -1 : 1;
+    }
+  if (a->fraction.ll < b->fraction.ll)
+    {
+      return a->sign ? 1 : -1;
+    }
+  /* after all that, they're equal. */
+  return 0;
+}
+
+CMPtype
+compare (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  return _fpcmp_parts (&a, &b);
+}
+
+#ifndef US_SOFTWARE_GOFAST
+
+/* These should be optimized for their specific tasks someday.  */
+
+CMPtype
+_eq_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  if (isnan (&a) || isnan (&b))
+    return 1;                  /* false, truth == 0 */
+
+  return _fpcmp_parts (&a, &b) ;
+}
+
+CMPtype
+_ne_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  if (isnan (&a) || isnan (&b))
+    return 1;                  /* true, truth != 0 */
+
+  return  _fpcmp_parts (&a, &b) ;
+}
+
+CMPtype
+_gt_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  if (isnan (&a) || isnan (&b))
+    return -1;                 /* false, truth > 0 */
+
+  return _fpcmp_parts (&a, &b);
+}
+
+CMPtype
+_ge_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  if (isnan (&a) || isnan (&b))
+    return -1;                 /* false, truth >= 0 */
+  return _fpcmp_parts (&a, &b) ;
+}
+
+CMPtype
+_lt_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  if (isnan (&a) || isnan (&b))
+    return 1;                  /* false, truth < 0 */
+
+  return _fpcmp_parts (&a, &b);
+}
+
+CMPtype
+_le_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+  fp_number_type a;
+  fp_number_type b;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  unpack_d ((FLO_union_type *) & arg_b, &b);
+
+  if (isnan (&a) || isnan (&b))
+    return 1;                  /* false, truth <= 0 */
+
+  return _fpcmp_parts (&a, &b) ;
+}
+
+#endif /* ! US_SOFTWARE_GOFAST */
+
+FLO_type
+si_to_float (SItype arg_a)
+{
+  fp_number_type in;
+
+  in.class = CLASS_NUMBER;
+  in.sign = arg_a < 0;
+  if (!arg_a)
+    {
+      in.class = CLASS_ZERO;
+    }
+  else
+    {
+      in.normal_exp = FRACBITS + NGARDS;
+      if (in.sign) 
+       {
+         /* Special case for minint, since there is no +ve integer
+            representation for it */
+         if (arg_a == 0x80000000)
+           {
+             return -2147483648.0;
+           }
+         in.fraction.ll = (-arg_a);
+       }
+      else
+       in.fraction.ll = arg_a;
+
+      while (in.fraction.ll < (1LL << (FRACBITS + NGARDS)))
+       {
+         in.fraction.ll <<= 1;
+         in.normal_exp -= 1;
+       }
+    }
+  return pack_d (&in);
+}
+
+SItype
+float_to_si (FLO_type arg_a)
+{
+  fp_number_type a;
+  SItype tmp;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  if (iszero (&a))
+    return 0;
+  if (isnan (&a))
+    return 0;
+  /* get reasonable MAX_SI_INT... */
+  if (isinf (&a))
+    return a.sign ? MAX_SI_INT : (-MAX_SI_INT)-1;
+  /* it is a number, but a small one */
+  if (a.normal_exp < 0)
+    return 0;
+  if (a.normal_exp > 30)
+    return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
+  tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
+  return a.sign ? (-tmp) : (tmp);
+}
+
+#ifdef US_SOFTWARE_GOFAST
+/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
+   we also define them for GOFAST because the ones in libgcc2.c have the
+   wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
+   out of libgcc2.c.  We can't define these here if not GOFAST because then
+   there'd be duplicate copies.  */
+
+USItype
+float_to_usi (FLO_type arg_a)
+{
+  fp_number_type a;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  if (iszero (&a))
+    return 0;
+  if (isnan (&a))
+    return 0;
+  /* get reasonable MAX_USI_INT... */
+  if (isinf (&a))
+    return a.sign ? MAX_USI_INT : 0;
+  /* it is a negative number */
+  if (a.sign)
+    return 0;
+  /* it is a number, but a small one */
+  if (a.normal_exp < 0)
+    return 0;
+  if (a.normal_exp > 31)
+    return MAX_USI_INT;
+  else if (a.normal_exp > (FRACBITS + NGARDS))
+    return a.fraction.ll << ((FRACBITS + NGARDS) - a.normal_exp);
+  else
+    return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
+}
+#endif
+
+FLO_type
+negate (FLO_type arg_a)
+{
+  fp_number_type a;
+
+  unpack_d ((FLO_union_type *) & arg_a, &a);
+  flip_sign (&a);
+  return pack_d (&a);
+}
+
+#ifdef FLOAT
+
+SFtype
+__make_fp(fp_class_type class,
+            unsigned int sign,
+            int exp, 
+            USItype frac)
+{
+  fp_number_type in;
+
+  in.class = class;
+  in.sign = sign;
+  in.normal_exp = exp;
+  in.fraction.ll = frac;
+  return pack_d (&in);
+}
+
+#ifndef FLOAT_ONLY
+
+/* This enables one to build an fp library that supports float but not double.
+   Otherwise, we would get an undefined reference to __make_dp.
+   This is needed for some 8-bit ports that can't handle well values that
+   are 8-bytes in size, so we just don't support double for them at all.  */
+
+extern DFtype __make_dp (fp_class_type, unsigned int, int, UDItype frac);
+
+DFtype
+sf_to_df (SFtype arg_a)
+{
+  fp_number_type in;
+
+  unpack_d ((FLO_union_type *) & arg_a, &in);
+  return __make_dp (in.class, in.sign, in.normal_exp,
+                   ((UDItype) in.fraction.ll) << F_D_BITOFF);
+}
+
+#endif
+#endif
+
+#ifndef FLOAT
+
+extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
+
+DFtype
+__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
+{
+  fp_number_type in;
+
+  in.class = class;
+  in.sign = sign;
+  in.normal_exp = exp;
+  in.fraction.ll = frac;
+  return pack_d (&in);
+}
+
+SFtype
+df_to_sf (DFtype arg_a)
+{
+  fp_number_type in;
+
+  unpack_d ((FLO_union_type *) & arg_a, &in);
+  return __make_fp (in.class, in.sign, in.normal_exp,
+                   in.fraction.ll >> F_D_BITOFF);
+}
+
+#endif
diff --git a/sim/ppc/events.c b/sim/ppc/events.c
new file mode 100644 (file)
index 0000000..4b26a6a
--- /dev/null
@@ -0,0 +1,238 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _EVENTS_C_
+#define _EVENTS_C_
+
+#ifndef STATIC_INLINE_EVENTS
+#define STATIC_INLINE_EVENTS STATIC_INLINE
+#endif
+
+
+#include "basics.h"
+#include "events.h"
+
+
+/* The event queue maintains a single absolute time using two
+   variables.
+   
+   TIME_OF_EVENT: this holds the time at which the next event is ment
+   to occure.  If no next event it will hold the time of the last
+   event.  The first event occures at time 0 - system start.
+
+   TIME_FROM_EVENT: The current distance from TIME_OF_EVENT.  If an
+   event is pending, this will be positive.  If no future event is
+   pending this will be negative.  This variable is decremented once
+   for each iteration of a clock cycle.
+
+   Clearly there is a bug in that this code assumes that the absolute
+   time counter will never become greater than 2^62. */
+
+typedef struct _event_entry event_entry;
+struct _event_entry {
+  void *data;
+  event_handler *handler;
+  signed64 time_of_event;  
+  event_entry *next;
+};
+
+struct _event_queue {
+  event_entry *queue;
+  event_entry *volatile held;
+  event_entry *volatile *volatile held_end;
+  signed64 time_of_event;
+  signed64 time_from_event;
+};
+
+
+INLINE_EVENTS event_queue *
+event_queue_create(void)
+{
+  event_queue *new_event_queue = ZALLOC(event_queue);
+
+  new_event_queue->queue = NULL;
+  new_event_queue->held = NULL;
+  new_event_queue->held_end = &new_event_queue->held;
+  /* both times are already zero */
+  return new_event_queue;
+}
+
+
+
+STATIC_INLINE_EVENTS void
+insert_event_entry(event_queue *events,
+                  event_entry *new_event,
+                  signed64 delta)
+{
+  event_entry *curr;
+  event_entry **last;
+  signed64 time_of_event;
+
+  if (delta <= 0)
+    error("can not schedule event for current time\n");
+
+  /* compute when the event should occure */
+  time_of_event = (events->time_of_event
+                  - events->time_from_event
+                  + delta);
+
+  /* find the queue insertion point - things are time ordered */
+  last = &events->queue;
+  curr = events->queue;
+  while (curr != NULL && time_of_event >= curr->time_of_event) {
+    last = &curr->next;
+    curr = curr->next;
+  }
+
+  /* insert it */
+  new_event->next = curr;
+  *last = new_event;
+  new_event->time_of_event = time_of_event;
+
+  /* adjust the time until the first event */
+  events->time_from_event = (events->queue->time_of_event
+                            - (events->time_of_event
+                               - events->time_from_event));
+  events->time_of_event = events->queue->time_of_event;
+}
+
+INLINE_EVENTS event_entry_tag
+event_queue_schedule(event_queue *events,
+                    signed64 delta_time,
+                    event_handler *handler,
+                    void *data)
+{
+  event_entry *new_event = ZALLOC(event_entry);
+  new_event->data = data;
+  new_event->handler = handler;
+  insert_event_entry(events, new_event, delta_time);
+  return new_event;
+}
+
+
+INLINE_EVENTS event_entry_tag
+event_queue_schedule_after_signal(event_queue *events,
+                                 signed64 delta_time,
+                                 event_handler *handler,
+                                 void *data)
+{
+  event_entry *new_event = ZALLOC(event_entry);
+
+  new_event->data = data;
+  new_event->handler = handler;
+  new_event->time_of_event = delta_time; /* work it out later */
+  new_event->next = NULL;
+
+  /*-LOCK-*/
+  if (events->held == NULL) {
+    events->held = new_event;
+  }
+  else {
+    *events->held_end = new_event;
+  }
+  events->held_end = &new_event->next;
+  /*-UNLOCK-*/
+
+  return new_event;
+}
+
+
+INLINE_EVENTS void
+event_queue_deschedule(event_queue *events,
+                      event_entry_tag event_to_remove)
+{
+  if (event_to_remove != NULL) {
+    event_entry *current;
+    event_entry **ptr_to_current;
+    for (ptr_to_current = &events->queue, current = *ptr_to_current;
+        current != NULL && current != event_to_remove;
+        ptr_to_current = &current->next, current = *ptr_to_current);
+    if (current == event_to_remove) {
+      *ptr_to_current = current->next;
+      zfree(current);
+      /* Just forget to recompute the delay to the next event */
+    }
+  }
+}
+
+
+
+
+INLINE_EVENTS int
+event_queue_tick(event_queue *events)
+{
+  /* remove things from the asynchronous event queue onto the real one */
+  if (events->held != NULL) {
+    event_entry *held_events;
+    event_entry *curr_event;
+
+    /*-LOCK-*/
+    held_events = events->held;
+    events->held = NULL;
+    events->held_end = &events->held;
+    /*-UNLOCK-*/
+
+    do {
+      curr_event = held_events;
+      held_events = curr_event->next;
+      insert_event_entry(events, curr_event, curr_event->time_of_event);
+    } while (held_events != NULL);
+  }
+
+  /* advance time, checking to see if we've reached time zero which
+     would indicate the time for the next event has arrived */
+  events->time_from_event -= 1;
+  return events->time_from_event == 0;
+}
+
+INLINE_EVENTS void
+event_queue_process(event_queue *events)
+{
+  if (events->time_from_event == 0) {
+    /* consume all events for this or earlier times */
+    do {
+      event_entry *to_do = events->queue;
+      events->queue = to_do->next;
+      to_do->handler(events,
+                    to_do->data);
+      zfree(to_do);
+    } while (events->queue != NULL
+            && events->queue->time_of_event <= events->time_of_event);
+    /* re-caculate time for new events */
+    if (events->queue != NULL) {
+      events->time_from_event = (events->queue->time_of_event
+                                - events->time_of_event);
+      events->time_of_event = events->queue->time_of_event;
+    }
+    else {
+      /* nothing to do, time_from_event will go negative */
+    }
+  }
+}
+
+INLINE_EVENTS signed64
+event_queue_time(event_queue *queue)
+{
+  return queue->time_of_event - queue->time_from_event;
+}
+
+
+#endif /* _EVENTS_C_ */
diff --git a/sim/ppc/events.h b/sim/ppc/events.h
new file mode 100644 (file)
index 0000000..fc81263
--- /dev/null
@@ -0,0 +1,75 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _EVENTS_H_
+#define _EVENTS_H_
+
+#ifndef INLINE_EVENTS
+#define INLINE_EVENTS
+#endif
+
+
+typedef struct _event_queue event_queue;
+typedef void *event_entry_tag;
+
+typedef void event_handler
+(event_queue *queue,
+ void *data);
+
+INLINE_EVENTS event_queue *event_queue_create
+(void);
+
+
+/* (de)Schedule things to happen in the future. */
+
+INLINE_EVENTS event_entry_tag event_queue_schedule
+(event_queue *queue,
+ signed64 delta_time,
+ event_handler *handler,
+ void *data);
+
+INLINE_EVENTS event_entry_tag event_queue_schedule_after_signal
+(event_queue *queue,
+ signed64 delta_time,
+ event_handler *handler,
+ void *data);
+
+INLINE_EVENTS void event_queue_deschedule
+(event_queue *queue,
+ event_entry_tag event_to_remove);
+
+
+/* progress time.  In to parts so that if something is pending, the
+   caller has a chance to save any cached state */
+
+INLINE_EVENTS int event_queue_tick
+(event_queue *queue);
+
+INLINE_EVENTS void event_queue_process
+(event_queue *events);
+
+
+/* local concept of time */
+
+INLINE_EVENTS signed64 event_queue_time
+(event_queue *queue);
+
+#endif /* _EVENTS_H_ */
diff --git a/sim/ppc/gen.c b/sim/ppc/gen.c
new file mode 100644 (file)
index 0000000..e6e5c16
--- /dev/null
@@ -0,0 +1,3111 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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.
+    */
+
+
+/* BUGS:
+
+   Instead of using/abusing macro's the semantic code should be parsed
+   and each `cachable' expression replaced with the corresponding
+   value.
+
+   If not expanding fields, invalid_insn has call to its self this is
+   a little fatal when semantic_invalid() is being called because an
+   instruction is invalid */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "config.h"
+
+#undef WITH_ASSERT
+#define WITH_ASSERT 1
+
+#include "debug.h"
+
+
+/****************************************************************/
+
+void
+error (char *msg, ...)
+{
+  va_list ap;
+  va_start(ap, msg);
+  vprintf(msg, ap);
+  va_end(ap);
+  exit (1);
+}
+
+void *
+zmalloc(long size)
+{
+  void *memory = malloc(size);
+  if (memory == NULL)
+    error("zmalloc failed\n");
+  bzero(memory, size);
+  return memory;
+}
+
+void
+dumpf (int indent, char *msg, ...)
+{
+  va_list ap;
+  for (; indent > 0; indent--)
+    printf(" ");
+  va_start(ap, msg);
+  vprintf(msg, ap);
+  va_end(ap);
+}
+
+
+/****************************************************************/
+
+int idecode_expand_semantics = WITH_IDECODE_EXPAND_SEMANTICS;
+int idecode_cache = WITH_IDECODE_CACHE;
+int spreg_lookup_table = WITH_SPREG_LOOKUP_TABLE;
+
+/****************************************************************/
+
+typedef struct {
+  int valid;
+  char *old_name;
+  char *new_name;
+  char *type;
+  char *expression;
+} extraction_rules;
+
+extraction_rules cachable_values[] = WITH_IDECODE_CACHE_RULES;
+
+/****************************************************************/
+
+typedef struct _opcode_rules {
+  int valid;
+  int first;
+  int last;
+  int force_first;
+  int force_last;
+  int force_slash;
+  char *force_expansion;
+  int use_switch;
+  unsigned special_mask;
+  unsigned special_value;
+  unsigned special_rule;
+} opcode_rules;
+
+/* FIXME - this should be loaded from a file */
+opcode_rules opcode_table[] = WITH_IDECODE_OPCODE_RULES;
+
+dump_opcode_rule(opcode_rules *rule,
+                int indent)
+{
+  printf("(opcode_rules*)0x%x\n", rule);
+  dumpf(indent, "(valid %d)\n", rule->valid);
+  ASSERT(rule != NULL);
+  if (rule->valid) {
+    dumpf(indent, "(first %d)\n", rule->first);
+    dumpf(indent, "(last %d)\n", rule->last);
+    dumpf(indent, "(force_first %d)\n", rule->force_first);
+    dumpf(indent, "(force_last %d)\n", rule->force_last);
+    dumpf(indent, "(force_slash %d)\n", rule->force_slash);
+    dumpf(indent, "(force_expansion %s)\n", rule->force_expansion);
+  }
+}
+
+
+/****************************************************************/
+
+enum gen_constants {
+  insn_size = 32,
+  nr_of_sprs = 1024
+};
+
+char cache_idecode_formal[] = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia,\n idecode_cache *cache_entry";
+char cache_idecode_actual[] = "processor, instruction, cia, cache_entry";
+char cache_insn_formal[] = "cpu *processor,\n idecode_cache *cache_entry,\n unsigned_word cia";
+char cache_insn_actual[] = "processor, entry, cia";
+
+char insn_formal[] = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia";
+char insn_actual[] = "processor, instruction, cia";
+
+char insn_local[] = "unsigned_word nia = cia + 4;";
+
+
+/****************************************************************/
+
+int
+bin2i(char *bin, int width)
+{
+  int i = 0;
+  while (*bin != '\0' && width != 0) {
+    i = (i << 1) + (*bin - '0');
+    width--;
+    bin++;
+  }
+  return i;
+}
+
+
+int
+it_is(char *flag,
+      char *flags)
+{
+  int flag_len = strlen(flag);
+  while (*flags != '\0') {
+    if (!strncmp(flags, flag, flag_len)
+       && (flags[flag_len] == ',' || flags[flag_len] == '\0'))
+      return 1;
+    while (*flags != ',') {
+      if (*flags == '\0')
+       return 0;
+      flags++;
+    }
+    flags++;
+  }
+  return 0;
+}
+
+
+/****************************************************************/
+
+typedef struct _lf lf;
+struct _lf {
+  FILE *stream;
+  int line_nr; /* nr complete lines written, curr line is line_nr+1 */
+  int indent;
+  int line_blank;
+  char *file_name;
+};
+
+
+lf *
+lf_open(char *name)
+{
+  /* create a file object */
+  lf *new_lf = zmalloc(sizeof(lf));
+  ASSERT(new_lf != NULL);
+  new_lf->file_name = name;
+
+  /* attach to stdout if pipe */
+  if (!strcmp(name, "-")) {
+    new_lf->stream = stdout;
+  }
+  else {
+    /* create a new file */
+    new_lf->stream = fopen(name, "w");
+    ASSERT(new_lf->stream != NULL);
+  }
+  return new_lf;
+}
+
+
+void
+lf_close(lf *file)
+{
+  if (file->stream != stdout) {
+    if (fclose(file->stream)) {
+      perror("lf_close.fclose");
+      exit(1);
+    }
+    free(file);
+  }
+}
+
+
+void
+lf_putchr(lf *file,
+         const char chr)
+{
+  if (chr == '\n') {
+    file->line_nr += 1;
+    file->line_blank = 1;
+  }
+  else if (file->line_blank) {
+    int pad;
+    for (pad = file->indent; pad > 0; pad--)
+      putc(' ', file->stream);
+    file->line_blank = 0;
+  }
+  putc(chr, file->stream);
+}
+
+void
+lf_indent_suppress(lf *file)
+{
+  file->line_blank = 0;
+}
+
+
+void
+lf_putstr(lf *file,
+         const char *string)
+{
+  const char *chp;
+  if (string != NULL) {
+    for (chp = string; *chp != '\0'; chp++) {
+      lf_putchr(file, *chp);
+    }
+  }
+}
+
+void
+do_lf_putunsigned(lf *file,
+             unsigned u)
+{
+  if (u > 0) {
+    do_lf_putunsigned(file, u / 10);
+    lf_putchr(file, (u % 10) + '0');
+  }
+}
+
+
+void
+lf_putint(lf *file,
+         int decimal)
+{
+  if (decimal == 0)
+    lf_putchr(file, '0');
+  else if (decimal < 0) {
+    lf_putchr(file, '-');
+    do_lf_putunsigned(file, -decimal);
+  }
+  else if (decimal > 0) {
+    do_lf_putunsigned(file, decimal);
+  }
+  else
+    ASSERT(0);
+}
+
+void
+lf_printf(lf *file,
+         const char *fmt,
+         ...)
+{
+  char buf[1024];
+  va_list ap;
+  int nr_chars;
+
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  /* FIXME - this is really stuffed but so is vsprintf() on a sun! */
+  ASSERT(strlen(buf) > 0 && strlen(buf) < sizeof(buf));
+  lf_putstr(file, buf);
+  va_end(ap);
+}
+
+void
+lf_print_file_line_nr(lf *file)
+{
+#if WITH_LINE_NUMBERS
+  lf_indent_suppress(file);
+  lf_putstr(file, "#line ");
+  lf_putint(file, file->line_nr+2); /*line_nr == last_line, want next */
+  lf_putstr(file, " \"");
+  lf_putstr(file, file->file_name);
+  lf_putstr(file, "\"\n");
+#endif
+}
+
+lf_indent(lf *file, int delta)
+{
+  file->indent += delta;
+}
+
+
+/****************************************************************/
+
+/* read entries from ppc.instructions */
+
+enum {
+  file_table_max_fields = 6,
+};
+
+typedef struct _file_table file_table;
+struct _file_table {
+  size_t size;
+  char *buffer;
+  char *pos;
+  int line_nr;
+  char *file_name;
+};
+
+typedef struct _file_table_entry file_table_entry;
+struct _file_table_entry {
+  char *fields[file_table_max_fields];
+  int line_nr;
+  char *file_name;
+  char *annex;
+};
+
+
+file_table *
+file_table_open(char *file_name)
+{
+  int fd;
+  struct stat stat_buf;
+  file_table *file;
+
+  /* create a file descriptor */
+  file = (file_table*)zmalloc(sizeof(file_table));
+  ASSERT(file != NULL);
+
+  /* save the file name */
+  file->file_name = (char*)zmalloc(strlen(file_name) + 1);
+  ASSERT(file->file_name != NULL);
+  strcpy(file->file_name, file_name);
+
+  /* open the file */
+  fd = open(file->file_name, O_RDONLY, 0);
+  ASSERT(fd >= 0);
+
+  /* determine the size */
+  if (fstat(fd, &stat_buf) < 0) {
+    perror("file_table_open.fstat");
+    exit(1);
+  }
+  file->size = stat_buf.st_size;
+
+  /* allocate this much memory */
+  file->buffer = (char*)zmalloc(file->size+1);
+  if(file->buffer == NULL) {
+    perror("file_table_open.calloc.file->size+1");
+    exit(1);
+  }
+  file->pos = file->buffer;
+
+  /* read it in */
+  if (read(fd, file->buffer, file->size) < file->size) {
+    perror("file_table_open.read");
+    exit(1);
+  }
+  file->buffer[file->size] = '\0';
+
+  /* done */
+  close(fd);
+  return file;
+}
+
+
+file_table_entry *
+file_table_read(file_table *file)
+{
+  int field;
+  file_table_entry *entry;
+
+  /* skip comments/blanks */
+  while(1) {
+    /* leading white space */
+    while (*file->pos != '\0'
+          && *file->pos != '\n'
+          && isspace(*file->pos))
+      file->pos++;
+    /* comment */
+    if (*file->pos == '#') {
+      do {
+       file->pos++;
+      } while (*file->pos != '\0' && *file->pos != '\n');
+    }
+    /* end of line? */
+    if (*file->pos == '\n') {
+      file->pos++;
+      file->line_nr++;
+    }
+    else
+      break;
+  }
+  if (*file->pos == '\0')
+    return NULL;
+
+  /* create this new entry */
+  entry = (file_table_entry*)zmalloc(sizeof(file_table_entry));
+  ASSERT(entry != NULL);
+  entry->file_name = file->file_name;
+
+  /* break the line into its colon delimitered fields */
+  for (field = 0; field < file_table_max_fields-1; field++) {
+    entry->fields[field] = file->pos;
+    while(*file->pos && *file->pos != ':' && *file->pos != '\n')
+      file->pos++;
+    if (*file->pos == ':') {
+      *file->pos = '\0';
+      file->pos++;
+    }
+  }
+
+  /* any trailing stuff not the last field */
+  ASSERT(field == file_table_max_fields-1);
+  entry->fields[field] = file->pos;
+  while (*file->pos && *file->pos != '\n') {
+    file->pos++;
+  }
+  if (*file->pos == '\n') {
+    *file->pos = '\0';
+    file->pos++;
+  }
+  file->line_nr++;
+  entry->line_nr = file->line_nr;
+
+  /* if following lines tab indented, put in the annex */
+  if (*file->pos == '\t') {
+    entry->annex = file->pos;
+    do {
+      do {
+       file->pos++;
+      } while (*file->pos != '\0' && *file->pos != '\n');
+      if (*file->pos == '\n') {
+       file->pos++;
+       file->line_nr++;
+      }
+    } while (*file->pos != '\0' && *file->pos == '\t');
+    if (file->pos[-1] == '\n')
+      file->pos[-1] = '\0';
+  }
+  else
+    entry->annex = NULL;
+
+  /* return it */
+  return entry;
+
+}
+
+
+void
+dump_file_table_entry(file_table_entry *entry,
+                     int indent)
+{
+  printf("(file_table_entry*)0x%x\n", entry);
+
+  if (entry != NULL) {
+    int field;
+    char sep;
+
+    sep = ' ';
+    dumpf(indent, "(fields");
+    for (field = 0; field < file_table_max_fields; field++) {
+      printf("%c%s", sep, entry->fields[field]);
+      sep = ':';
+    }
+    printf(")\n");
+
+    dumpf(indent, "(line_nr %d)\n", entry->line_nr);
+
+    dumpf(indent, "(file_name %s)\n", entry->file_name);
+
+    dumpf(indent, "(annex\n%s\n", entry->annex);
+    dumpf(indent, " )\n");
+
+  }
+}
+
+
+/****************************************************************/
+
+typedef struct _insn_field insn_field;
+struct _insn_field {
+  int first;
+  int last;
+  int width;
+  int is_int;
+  int is_slash;
+  int is_string;
+  int val_int;
+  char *pos_string;
+  char *val_string;
+  insn_field *next;
+  insn_field *prev;
+};
+
+typedef struct _insn_fields insn_fields;
+struct _insn_fields {
+  insn_field *bits[insn_size];
+  insn_field *first;
+  insn_field *last;
+  unsigned value;
+};
+
+insn_field *
+insn_field_new()
+{
+  insn_field *new_field = (insn_field*)zmalloc(sizeof(insn_field));
+  ASSERT(new_field != NULL);
+  return new_field;
+}
+
+insn_fields *
+insn_fields_new()
+{
+  insn_fields *new_fields = (insn_fields*)zmalloc(sizeof(insn_fields));
+  ASSERT(new_fields != NULL);
+  return new_fields;
+}
+
+
+insn_fields *
+parse_insn_format(file_table_entry *entry,
+                 char *format)
+{
+  char *chp;
+  insn_fields *fields = insn_fields_new();
+
+  /* create a leading sentinal */
+  fields->first = insn_field_new();
+  fields->first->first = -1;
+  fields->first->last = -1;
+  fields->first->width = 0;
+
+  /* and a trailing sentinal */
+  fields->last = insn_field_new();
+  fields->last->first = insn_size;
+  fields->last->last = insn_size;
+  fields->last->width = 0;
+
+  /* link them together */
+  fields->first->next = fields->last;
+  fields->last->prev = fields->first;
+
+  /* now work through the formats */
+  chp = format;
+
+  while (*chp != '\0') {
+    char *start_pos;
+    char *start_val;
+    int strlen_val;
+    int strlen_pos;
+    insn_field *new_field;
+
+    /* sanity check */
+    if (!isdigit(*chp)) {
+      fprintf(stderr, "%s:%d: missing position field at %s\n",
+             entry->file_name, entry->line_nr, chp);
+      break;
+    }
+
+    /* break out the bit position */
+    start_pos = chp;
+    while (isdigit(*chp))
+      chp++;
+    strlen_pos = chp - start_pos;
+    if (*chp == '.' && strlen_pos > 0)
+      chp++;
+    else {
+      fprintf(stderr, "%s:%d: missing field value at %s\n",
+             entry->file_name, entry->line_nr, chp);
+      break;
+    }
+
+    /* break out the value */
+    start_val = chp;
+    while (*start_val == '/' && *chp == '/'
+          || isdigit(*start_val) && isdigit(*chp)
+          || isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))
+      chp++;
+    strlen_val = chp - start_val;
+    if (*chp == ',')
+      chp++;
+    else if (*chp != '\0' || strlen_val == 0) {
+      fprintf(stderr, "%s:%d: missing field terminator at %s\n",
+             entry->file_name, entry->line_nr, chp);
+      break;
+    }
+
+    /* create a new field and insert it */
+    new_field = insn_field_new();
+    new_field->next = fields->last;
+    new_field->prev = fields->last->prev;
+    new_field->next->prev = new_field;
+    new_field->prev->next = new_field;
+
+    /* the value */
+    new_field->val_string = (char*)zmalloc(strlen_val+1);
+    strncpy(new_field->val_string, start_val, strlen_val);
+    if (isdigit(*new_field->val_string)) {
+      new_field->val_int = atoi(new_field->val_string);
+      new_field->is_int = 1;
+    }
+    else if (new_field->val_string[0] == '/') {
+      new_field->is_slash = 1;
+    }
+    else {
+      new_field->is_string = 1;
+    }
+    
+    /* the pos */
+    new_field->pos_string = (char*)zmalloc(strlen_pos+1);
+    strncpy(new_field->pos_string, start_pos, strlen_pos);
+    new_field->first = atoi(new_field->pos_string);
+    new_field->last = new_field->next->first - 1; /* guess */
+    new_field->width = new_field->last - new_field->first + 1; /* guess */
+    new_field->prev->last = new_field->first-1; /*fix*/
+    new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/
+  }
+
+  /* fiddle first/last so that the sentinals `disapear' */
+  ASSERT(fields->first->last < 0);
+  ASSERT(fields->last->first >= insn_size);
+  fields->first = fields->first->next;
+  fields->last = fields->last->prev;
+
+  /* now go over this again, pointing each bit position at a field
+     record */
+  {
+    int i;
+    insn_field *field;
+    field = fields->first;
+    for (i = 0; i < insn_size; i++) {
+      while (field->last < i)
+       field = field->next;
+      fields->bits[i] = field;
+    }
+  }
+
+  /* go over each of the fields, and compute a `value' for the insn */
+  {
+    insn_field *field;
+    fields->value = 0;
+    for (field = fields->first;
+        field->last < insn_size;
+        field = field->next) {
+      fields->value <<= field->width;
+      if (field->is_int)
+       fields->value |= field->val_int;
+    }
+  }
+  return fields;
+}
+
+
+typedef enum {
+  field_constant_int = 1,
+  field_constant_slash = 2,
+  field_constant_string = 3
+} constant_field_types;
+
+
+int
+insn_field_is_constant(insn_field *field,
+                      opcode_rules *rule)
+{
+  /* field is an integer */
+  if (field->is_int)
+    return field_constant_int;
+  /* field is `/' and treating that as a constant */
+  if (field->is_slash && rule->force_slash)
+    return field_constant_slash;
+  /* field, though variable is on the list */
+  if (field->is_string && rule->force_expansion != NULL) {
+    char *forced_fields = rule->force_expansion;
+    while (*forced_fields != '\0') {
+      int field_len;
+      char *end = strchr(forced_fields, ',');
+      if (end == NULL)
+       field_len = strlen(forced_fields);
+      else
+       field_len = end-forced_fields;
+      if (strncmp(forced_fields, field->val_string, field_len) == 0
+         && field->val_string[field_len] == '\0')
+       return field_constant_string;
+      forced_fields += field_len;
+      if (*forced_fields == ',')
+       forced_fields++;
+    }
+  }
+  return 0;
+}
+
+
+void
+dump_insn_field(insn_field *field,
+               int indent)
+{
+
+  printf("(insn_field*)0x%x\n", field);
+
+  dumpf(indent, "(first %d)\n", field->first);
+
+  dumpf(indent, "(last %d)\n", field->last);
+
+  dumpf(indent, "(width %d)\n", field->width);
+
+  if (field->is_int)
+    dumpf(indent, "(is_int %d)\n", field->val_int);
+
+  if (field->is_slash)
+    dumpf(indent, "(is_slash)\n");
+
+  if (field->is_string)
+    dumpf(indent, "(is_string `%s')\n", field->val_string);
+  
+  dumpf(indent, "(next 0x%x)\n", field->next);
+  
+  dumpf(indent, "(prev 0x%x)\n", field->prev);
+  
+
+}
+
+void
+dump_insn_fields(insn_fields *fields,
+                int indent)
+{
+  insn_field *field;
+  int i;
+
+  printf("(insn_fields*)0x%x\n", fields);
+
+  dumpf(indent, "(first 0x%x)\n", fields->first);
+  dumpf(indent, "(last 0x%x)\n", fields->last);
+
+  dumpf(indent, "(value 0x%x)\n", fields->value);
+
+  for (i = 0; i < insn_size; i++) {
+    dumpf(indent, "(bits[%d] ", i, fields->bits[i]);
+    dump_insn_field(fields->bits[i], indent+1);
+    dumpf(indent, " )\n");
+  }
+
+}
+
+
+/****************************************************************/
+
+typedef struct _opcode_field opcode_field;
+struct _opcode_field {
+  int first;
+  int last;
+  int is_boolean;
+  opcode_field *parent;
+};
+
+opcode_field *
+opcode_field_new()
+{
+  opcode_field *new_field = (opcode_field*)zmalloc(sizeof(opcode_field));
+  ASSERT(new_field != NULL);
+  new_field->first = insn_size;
+  new_field->last = -1;
+  return new_field;
+}
+
+void
+dump_opcode_field(opcode_field *field, int indent, int levels)
+{
+  printf("(opcode_field*)0x%x\n", field);
+  if (levels && field != NULL) {
+    dumpf(indent, "(first %d)\n", field->first);
+    dumpf(indent, "(last %d)\n", field->last);
+    dumpf(indent, "(is_boolean %d)\n", field->is_boolean);
+    dumpf(indent, "(parent ");
+    dump_opcode_field(field->parent, indent, levels-1);
+  }
+}
+
+
+/****************************************************************/
+
+typedef struct _insn_bits insn_bits;
+struct _insn_bits {
+  int is_expanded;
+  int value;
+  insn_field *field;
+  opcode_field *opcode;
+  insn_bits *last;
+};
+
+insn_bits *
+insn_bits_new()
+{
+  insn_bits *new_bits = (insn_bits*)zmalloc(sizeof(insn_bits));
+  ASSERT(new_bits);
+  return new_bits;
+}
+
+
+void
+dump_insn_bits(insn_bits *bits, int indent, int levels)
+{
+  printf("(insn_bits*)0x%x\n", bits);
+
+  if (levels && bits != NULL) {
+    dumpf(indent, "(value %d)\n", bits->value);
+    dumpf(indent, "(opcode ");
+    dump_opcode_field(bits->opcode, indent+1, 0);
+    dumpf(indent, " )\n");
+    dumpf(indent, "(field ");
+    dump_insn_field(bits->field, indent+1);
+    dumpf(indent, " )\n");
+    dumpf(indent, "(last ");
+    dump_insn_bits(bits->last, indent+1, levels-1);
+  }
+}
+
+
+/****************************************************************/
+
+
+typedef enum {
+  insn_format,
+  insn_form,
+  insn_flags,
+  insn_nmemonic,
+  insn_name,
+  insn_comment,
+  nr_insn_table_fields = file_table_max_fields
+} insn_table_fields;
+char *insn_field_name[] = {
+  "format", "form", "flags", "nmemonic", "name", "comments"
+};
+
+typedef struct _insn insn;
+struct _insn {
+  file_table_entry *file_entry;
+  insn_fields *fields;
+  insn *next;
+};
+
+typedef struct _insn_table insn_table;
+struct _insn_table {
+  int opcode_nr;
+  insn_bits *expanded_bits;
+  int nr_insn;
+  insn *insns;
+  opcode_rules *opcode_rule;
+  opcode_field *opcode;
+  int nr_entries;
+  insn_table *entries;
+  insn_table *sibling;
+  insn_table *parent;
+};
+
+
+
+insn *
+insn_new()
+{
+  insn *new_entry = ((insn*) zmalloc(sizeof(insn)));
+  ASSERT(new_entry != NULL);
+  return new_entry;
+}
+
+insn_table *
+insn_table_new()
+{
+  insn_table *new_table = (insn_table*)zmalloc(sizeof(insn_table));
+  ASSERT(new_table != NULL);
+  return new_table;
+}
+
+
+void
+insn_table_insert_insn(insn_table *table,
+                      file_table_entry *file_entry,
+                      insn_fields *fields)
+{
+  insn **ptr_to_cur_insn = &table->insns;
+  insn *cur_insn = *ptr_to_cur_insn;
+
+  /* create a new instruction */
+  insn *new_insn = insn_new();
+  new_insn->file_entry = file_entry;
+  new_insn->fields = fields;
+
+  /* insert it according to the order of the fields */
+  while (cur_insn != NULL
+        && new_insn->fields->value >= cur_insn->fields->value) {
+    ptr_to_cur_insn = &cur_insn->next;
+    cur_insn = *ptr_to_cur_insn;
+  }
+
+  new_insn->next = cur_insn;
+  *ptr_to_cur_insn = new_insn;
+
+  table->nr_insn++;
+}
+
+
+opcode_field *
+insn_table_find_opcode_field(insn *insns,
+                            opcode_rules *rule,
+                            int string_only)
+{
+  opcode_field *curr_opcode = opcode_field_new();
+  insn *entry;
+
+  ASSERT(rule->valid);
+
+  for (entry = insns; entry != NULL; entry = entry->next) {
+    insn_fields *fields = entry->fields;
+    opcode_field new_opcode;
+
+    /* find a start point for the opcode field */
+    new_opcode.first = rule->first;
+    while (new_opcode.first <= rule->last
+          && (!string_only
+              || insn_field_is_constant(fields->bits[new_opcode.first],
+                                        rule) != field_constant_string)
+          && (string_only
+              || !insn_field_is_constant(fields->bits[new_opcode.first],
+                                         rule)))
+      new_opcode.first = fields->bits[new_opcode.first]->last + 1;
+    ASSERT(new_opcode.first > rule->last
+          || (string_only
+              && insn_field_is_constant(fields->bits[new_opcode.first],
+                                        rule) == field_constant_string)
+          || (!string_only
+              && insn_field_is_constant(fields->bits[new_opcode.first],
+                                        rule)));
+  
+    /* find the end point for the opcode field */
+    new_opcode.last = rule->last;
+    while (new_opcode.last >= rule->first
+          && (!string_only
+              || insn_field_is_constant(fields->bits[new_opcode.last],
+                                        rule) != field_constant_string)
+          && (string_only
+              || !insn_field_is_constant(fields->bits[new_opcode.last],
+                                         rule)))
+      new_opcode.last = fields->bits[new_opcode.last]->first - 1;
+    ASSERT(new_opcode.last < rule->first
+          || (string_only
+              && insn_field_is_constant(fields->bits[new_opcode.last],
+                                        rule) == field_constant_string)
+          || (!string_only
+              && insn_field_is_constant(fields->bits[new_opcode.last],
+                                        rule)));
+
+    /* now see if our current opcode needs expanding */
+    if (new_opcode.first <= rule->last
+       && curr_opcode->first > new_opcode.first)
+      curr_opcode->first = new_opcode.first;
+    if (new_opcode.last >= rule->first
+       && curr_opcode->last < new_opcode.last)
+      curr_opcode->last = new_opcode.last;
+    
+  }
+
+  /* was any thing interesting found? */
+  if (curr_opcode->first > rule->last) {
+    ASSERT(curr_opcode->last < rule->first);
+    free(curr_opcode);
+    return NULL;
+  }
+  ASSERT(curr_opcode->last >= rule->first);
+  ASSERT(curr_opcode->first <= rule->last);
+
+  /* if something was found, check it includes the forced field range */
+  if (!string_only
+      && curr_opcode->first > rule->force_first) {
+    curr_opcode->first = rule->force_first;
+  }
+  if (!string_only
+      && curr_opcode->last < rule->force_last) {
+    curr_opcode->last = rule->force_last;
+  }
+  /* handle special case elminating any need to do shift after mask */
+  if (string_only
+      && rule->force_last == insn_size-1) {
+    curr_opcode->last = insn_size-1;
+  }
+
+  /* handle any special cases */
+  switch (rule->special_rule) {
+  case 0: /* let the above apply */
+    break;
+  case 1: /* expand a limited nr of bits, ignoring the rest */
+    curr_opcode->first = rule->force_first;
+    curr_opcode->last = rule->force_last;
+    break;
+  case 2: /* boolean field */
+    curr_opcode->is_boolean = 1;
+    break;
+  }
+
+  return curr_opcode;
+}
+
+
+void
+insn_table_insert_expanded(insn_table *table,
+                          insn *old_insn,
+                          int new_opcode_nr,
+                          insn_bits *new_bits)
+{
+  insn_table **ptr_to_cur_entry = &table->entries;
+  insn_table *cur_entry = *ptr_to_cur_entry;
+
+  /* find the new table for this entry */
+  while (cur_entry != NULL
+        && cur_entry->opcode_nr < new_opcode_nr) {
+    ptr_to_cur_entry = &cur_entry->sibling;
+    cur_entry = *ptr_to_cur_entry;
+  }
+
+  if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) {
+    insn_table *new_entry = insn_table_new();
+    new_entry->opcode_nr = new_opcode_nr;
+    new_entry->expanded_bits = new_bits;
+    new_entry->opcode_rule = table->opcode_rule+1;
+    new_entry->sibling = cur_entry;
+    new_entry->parent = table;
+    *ptr_to_cur_entry = new_entry;
+    cur_entry = new_entry;
+    table->nr_entries++;
+  }
+  /* ASSERT new_bits == cur_entry bits */
+  ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr);
+  insn_table_insert_insn(cur_entry,
+                        old_insn->file_entry,
+                        old_insn->fields);
+}
+
+void
+insn_table_expand_opcode(insn_table *table,
+                        insn *instruction,
+                        int field_nr,
+                        int opcode_nr,
+                        insn_bits *bits)
+{
+
+  if (field_nr > table->opcode->last) {
+    insn_table_insert_expanded(table, instruction, opcode_nr, bits);
+  }
+  else {
+    insn_field *field = instruction->fields->bits[field_nr];
+    if (field->is_int || field->is_slash) {
+      ASSERT(field->first >= table->opcode->first
+            && field->last <= table->opcode->last);
+      insn_table_expand_opcode(table, instruction, field->last+1,
+                              ((opcode_nr << field->width) + field->val_int),
+                              bits);
+    }
+    else {
+      int val;
+      int last_pos = ((field->last < table->opcode->last)
+                       ? field->last : table->opcode->last);
+      int first_pos = ((field->first > table->opcode->first)
+                        ? field->first : table->opcode->first);
+      int width = last_pos - first_pos + 1;
+      int last_val = (table->opcode->is_boolean
+                     ? 2 : (1 << width));
+      for (val = 0; val < last_val; val++) {
+       insn_bits *new_bits = insn_bits_new();
+       new_bits->field = field;
+       new_bits->value = val;
+       new_bits->last = bits;
+       new_bits->opcode = table->opcode;
+       insn_table_expand_opcode(table, instruction, last_pos+1,
+                                ((opcode_nr << width) | val),
+                                new_bits);
+      }
+    }
+  }
+}
+
+insn_table_insert_expanding(insn_table *table,
+                           insn *entry)
+{
+  insn_table_expand_opcode(table,
+                          entry,
+                          table->opcode->first,
+                          0,
+                          table->expanded_bits);
+}
+
+
+void
+insn_table_expand_insns(insn_table *table)
+{
+
+  ASSERT(table->nr_insn >= 1);
+
+  /* determine a valid opcode */
+  while (table->opcode_rule->valid) {
+    /* specials only for single instructions */
+    if ((table->nr_insn > 1
+        && table->opcode_rule->special_mask == 0
+        && table->opcode_rule->special_rule == 0)
+       || (table->nr_insn == 1
+           && table->opcode_rule->special_mask != 0
+           && ((table->insns->fields->value
+                & table->opcode_rule->special_mask)
+               == table->opcode_rule->special_value))
+       || (idecode_expand_semantics
+           && table->opcode_rule->special_mask == 0
+           && table->opcode_rule->special_rule == 0))
+      table->opcode =
+       insn_table_find_opcode_field(table->insns,
+                                    table->opcode_rule,
+                                    table->nr_insn == 1/*string*/
+                                    );
+    if (table->opcode != NULL)
+      break;
+    table->opcode_rule++;
+  }
+
+  /* did we find anything */
+  if (table->opcode == NULL) {
+    return;
+  }
+  ASSERT(table->opcode != NULL);
+
+  /* back link what we found to its parent */
+  if (table->parent != NULL) {
+    ASSERT(table->parent->opcode != NULL);
+    table->opcode->parent = table->parent->opcode;
+  }
+
+  /* expand the raw instructions according to the opcode */
+  {
+    insn *entry;
+    for (entry = table->insns; entry != NULL; entry = entry->next) {
+      insn_table_insert_expanding(table, entry);
+    }
+  }
+
+  /* and do the same for the sub entries */
+  {
+    insn_table *entry;
+    for (entry = table->entries; entry != NULL; entry =  entry->sibling) {
+      insn_table_expand_insns(entry);
+    }
+  }
+}
+
+
+
+insn_table *
+insn_table_load_insns(char *file_name)
+{
+  file_table *file = file_table_open(file_name);
+  insn_table *table = insn_table_new();
+  file_table_entry *file_entry;
+  table->opcode_rule = opcode_table;
+
+  while (file_entry = file_table_read(file)) {
+    insn_fields *fields;
+    /* skip instructions that aren't relevant to the mode */
+    if (it_is("64", file_entry->fields[insn_flags]) && !WITH_64BIT_TARGET
+       || it_is("32", file_entry->fields[insn_flags]) && WITH_64BIT_TARGET)
+      continue;
+    /* create/insert the new instruction */
+    fields = parse_insn_format(file_entry, file_entry->fields[insn_format]);
+    insn_table_insert_insn(table, file_entry, fields);
+  }
+
+  return table;
+}
+
+
+void
+dump_insn(insn *entry, int indent, int levels)
+{
+  printf("(insn*)0x%x\n", entry);
+
+  if (levels && entry != NULL) {
+
+    dumpf(indent, "(file_entry ");
+    dump_file_table_entry(entry->file_entry, indent+1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(fields ");
+    dump_insn_fields(entry->fields, indent+1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(next ");
+    dump_insn(entry->next, indent+1, levels-1);
+    dumpf(indent, " )\n");
+
+  }
+
+}
+
+
+void
+dump_insn_table(insn_table *table,
+               int indent, int levels)
+{
+
+  printf("(insn_table*)0x%x\n", table);
+
+  if (levels && table != NULL) {
+    insn *entry;
+
+    dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr);
+
+    dumpf(indent, "(expanded_bits ");
+    dump_insn_bits(table->expanded_bits, indent+1, -1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(int nr_insn %d)\n", table->nr_insn);
+
+    dumpf(indent, "(insns ");
+    dump_insn(table->insns, indent+1, table->nr_insn);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(opcode_rule ");
+    dump_opcode_rule(table->opcode_rule, indent+1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(opcode ");
+    dump_opcode_field(table->opcode, indent+1, 1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(nr_entries %d)\n", table->entries);
+    dumpf(indent, "(entries ");
+    dump_insn_table(table->entries, indent+1, table->nr_entries);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(sibling ", table->sibling);
+    dump_insn_table(table->sibling, indent+1, levels-1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(parent ", table->parent);
+    dump_insn_table(table->parent, indent+1, 0);
+    dumpf(indent, " )\n");
+
+  }
+}
+
+
+/****************************************************************/
+
+
+void
+lf_print_copyleft(lf *file)
+{
+  lf_putstr(file, "\
+/* This file is part of psim (model of the PowerPC(tm) architecture)
+
+   Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License
+   as published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+   This library 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
+   Library General Public License for more details.
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+   --
+
+   PowerPC is a trademark of International Business Machines Corporation.
+
+   --
+
+   This file was generated by the program gen */
+");
+}
+
+
+void
+lf_print_c_line_nr(lf *file, file_table_entry *entry)
+{
+#if WITH_LINE_NUMBERS
+  lf_indent_suppress(file);
+  lf_putstr(file, "#line ");
+  lf_putint(file, entry->line_nr);
+  lf_putstr(file, " \"");
+  lf_putstr(file, entry->file_name);
+  lf_putstr(file, "\"\n");
+#endif
+}
+
+
+void
+lf_print_c_code(lf *file, char *code)
+{
+  char *chp = code;
+  int in_bit_field = 0;
+  while (*chp != '\0') {
+    if (*chp == '\t')
+      chp++;
+    if (*chp == '#')
+      lf_indent_suppress(file);
+    while (*chp != '\0' && *chp != '\n') {
+      if (chp[0] == '{' && !isspace(chp[1])) {
+       in_bit_field = 1;
+       lf_putchr(file, '_');
+      }
+      else if (in_bit_field && chp[0] == ':') {
+       lf_putchr(file, '_');
+      }
+      else if (in_bit_field && *chp == '}') {
+       lf_putchr(file, '_');
+       in_bit_field = 0;
+      }
+      else {
+       lf_putchr(file, *chp);
+      }
+      chp++;
+    }
+    if (in_bit_field)
+      error("bit field paren miss match some where\n");
+    if (*chp == '\n') {
+      lf_putchr(file, '\n');
+      chp++;
+    }
+  }
+  lf_putchr(file, '\n');
+}
+
+
+void
+lf_print_binary(lf *file, int decimal, int width)
+{
+  int bit;
+  ASSERT(width > 0);
+
+  for (bit = 1 << (width-1); bit != 0; bit >>= 1) {
+    if (decimal & bit)
+      lf_putchr(file, '1');
+    else
+      lf_putchr(file, '0');
+  }
+
+}
+
+
+void
+lf_print_insn_bits(lf *file, insn_bits *bits)
+{
+  if (bits == NULL)
+    return;
+  lf_print_insn_bits(file, bits->last);
+  lf_putchr(file, '_');
+  lf_putstr(file, bits->field->val_string);
+  if (!bits->opcode->is_boolean || bits->value == 0) {
+    if (bits->opcode->last < bits->field->last)
+      lf_putint(file, bits->value << (bits->field->last - bits->opcode->last));
+    else
+      lf_putint(file, bits->value);
+  }
+}
+
+void
+lf_print_opcodes(lf *file,
+                insn_table *table)
+{
+  if (table != NULL) {
+    while (1) {
+      lf_printf(file, "_%d_%d",
+               table->opcode->first,
+               table->opcode->last);
+      if (table->parent == NULL) break;
+      lf_printf(file, "__%d", table->opcode_nr);
+      table = table->parent;
+    }
+  }
+}
+
+void
+lf_print_table_name(lf *file,
+                   insn_table *table)
+{
+  lf_printf(file, "idecode_table");
+  lf_print_opcodes(file, table);
+}
+
+
+
+typedef enum {
+  function_name_prefix_semantics,
+  function_name_prefix_idecode,
+  function_name_prefix_none
+} lf_function_name_prefixes;
+
+void
+lf_print_function_name(lf *file,
+                      insn *instruction,
+                      insn_bits *expanded_bits,
+                      lf_function_name_prefixes prefix)
+{
+  /* the prefix */
+  switch (prefix) {
+  case function_name_prefix_semantics:
+    lf_putstr(file, "semantic_");
+    break;
+  case function_name_prefix_idecode:
+    lf_printf(file, "idecode_");
+    break;
+  default:
+    break;
+  }
+
+  /* the function name */
+  {
+    char *pos;
+    for (pos = instruction->file_entry->fields[insn_name];
+        *pos != '\0';
+        pos++) {
+      switch (*pos) {
+      case '/':
+      case '-':
+       break;
+      case ' ':
+       lf_putchr(file, '_');
+       break;
+      default:
+       lf_putchr(file, *pos);
+       break;
+      }
+    }
+  }
+
+  /* the suffix */
+  if (idecode_expand_semantics)
+    lf_print_insn_bits(file, expanded_bits);
+}
+
+
+void
+lf_print_idecode_table(lf *file,
+                      insn_table *entry)
+{
+  int can_assume_leaf;
+  int rule;
+
+  /* have a look at the rule table, if all table rules follow all
+     switch rules, I can assume that all end points are leaves */
+  rule = 0;
+  while (opcode_table[rule].valid
+        && opcode_table[rule].use_switch)
+    rule++;
+  while (opcode_table[rule].valid
+        && !opcode_table[rule].use_switch
+        && !opcode_table[rule].special_rule)
+    rule++;
+  can_assume_leaf = !opcode_table[rule].valid;
+
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  {
+    lf_printf(file, "idecode_table_entry *table = ");
+    lf_print_table_name(file, entry);
+    lf_printf(file, ";\n");
+    lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n",
+             entry->opcode->first, entry->opcode->last);
+    lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n");
+    lf_printf(file, "while (1) {\n");
+    lf_indent(file, +2);
+    {
+      lf_printf(file, "while (table_entry->mask != 0) {\n");
+      lf_indent(file, +2);
+      {
+       lf_printf(file, "table = ((idecode_table_entry*)\n");
+       lf_printf(file, "         table_entry->function_or_table);\n");
+       lf_printf(file, "opcode = ((instruction & table_entry->mask)\n");
+       lf_printf(file, "          >> table_entry->shift);\n");
+       lf_printf(file, "table_entry = table + opcode;\n");
+      }
+      lf_indent(file, -2);
+      lf_printf(file, "}\n");
+      if (!idecode_cache && can_assume_leaf) {
+       lf_printf(file, "return (((idecode_semantic*)\n");
+       lf_printf(file, "         table_entry->function_or_table)\n");
+       lf_printf(file, "        (%s));\n", insn_actual);
+      }
+      else if (!idecode_cache && !can_assume_leaf) {
+       lf_printf(file, "if (table_entry->shift == 0)");
+       lf_printf(file, "  return (((idecode_semantic*)\n");
+       lf_printf(file, "           table_entry->function_or_table)\n");
+       lf_printf(file, "          (%s));\n", insn_actual);
+      }
+      else if (idecode_cache == 1 && can_assume_leaf) {
+       lf_printf(file, "ASSERT(!entry->shift);\n");
+       lf_printf(file, "return ((idecode_semantic*)\n");
+       lf_printf(file, "        table_entry->function_or_table);\n");
+      }
+      else if (idecode_cache == 1 && !can_assume_leaf) {
+       lf_printf(file, "if (table_entry->shift == 0)\n");
+       lf_printf(file, "  return ((idecode_semantic*)\n");
+       lf_printf(file, "          table_entry->function_or_table);\n");
+       lf_printf(file, "else if (table_entry->shift == -1)\n");
+       lf_printf(file, "  return (((idecode_crack*)\n");
+       lf_printf(file, "           table_entry->function_or_table)\n");
+       lf_printf(file, "          (%s));\n", insn_actual);
+      }
+      else {
+       lf_printf(file, "if (table_entry->shift == 0)\n");
+       lf_printf(file, "  return (((idecode_crack*)\n");
+       lf_printf(file, "           table_entry->function_or_table)\n");
+       lf_printf(file, "          (%s));\n", cache_idecode_actual);
+      }
+      if (!can_assume_leaf) {
+       lf_printf(file, "opcode = (instruction & table_entry->shift) != 0;\n");
+       lf_printf(file, "table = ((idecode_table_entry*)\n");
+       lf_printf(file, "         table_entry->function_or_table);\n");
+       lf_printf(file, "table_entry = table + opcode;\n");
+      }
+    }
+    lf_indent(file, -2);
+    lf_printf(file, "}\n");
+  }
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+}
+
+
+void
+lf_print_my_prefix(lf *file,
+                  file_table_entry *file_entry)
+{
+  lf_printf(file, "const char *const my_prefix = \n");
+  lf_printf(file, "  \"%s:%s:%d:cache\";\n",
+           file_entry->file_name,
+           file_entry->fields[insn_name],
+           file_entry->line_nr);
+}
+
+
+void
+lf_print_ptrace(lf *file)
+{
+  lf_printf(file, "\n");
+  lf_putstr(file, "ITRACE(trace_semantics, (\"cia=0x%x\\n\", cia));\n");
+}
+
+
+/****************************************************************/
+
+typedef void leaf_handler
+(insn_table *entry,
+ void *data,
+ int depth);
+typedef void padding_handler
+(insn_table *table,
+ void *data,
+ int depth,
+ int opcode_nr);
+
+
+void
+insn_table_traverse_tree(insn_table *table,
+                        void *data,
+                        int depth,
+                        leaf_handler *start,
+                        leaf_handler *leaf,
+                        leaf_handler *end,
+                        padding_handler *padding)
+{
+  insn_table *entry;
+  int entry_nr;
+  
+  ASSERT(table != NULL
+        && table->opcode != NULL
+        && table->nr_entries > 0
+        && table->entries != 0);
+
+  if (start != NULL && depth >= 0)
+    start(table, data, depth);
+
+  for (entry_nr = 0, entry = table->entries;
+       entry_nr < (table->opcode->is_boolean
+                  ? 2
+                  : (1 << (table->opcode->last - table->opcode->first + 1)));
+       entry_nr ++) {
+    if (entry == NULL
+       || (!table->opcode->is_boolean
+           && entry_nr < entry->opcode_nr)) {
+      if (padding != NULL && depth >= 0)
+       padding(table, data, depth, entry_nr);
+    }
+    else {
+      ASSERT(entry != NULL && (entry->opcode_nr == entry_nr
+                              || table->opcode->is_boolean));
+      if (entry->opcode != NULL && depth != 0) {
+       insn_table_traverse_tree(entry, data, depth+1,
+                                start, leaf, end, padding);
+      }
+      else if (depth >= 0) {
+       if (leaf != NULL)
+         leaf(entry, data, depth);
+      }
+      entry = entry->sibling;
+    }
+  }
+  if (end != NULL && depth >= 0)
+    end(table, data, depth);
+}
+
+
+typedef void insn_handler
+(insn_table *table,
+ void *data,
+ insn *instruction);
+
+void
+insn_table_traverse_insn(insn_table *table,
+                        void *data,
+                        insn_handler *leaf)
+{
+  insn *instruction;
+  for (instruction = table->insns;
+       instruction != NULL;
+       instruction = instruction->next) {
+    leaf(table, data, instruction);
+  }
+}
+
+
+void
+update_depth(insn_table *entry,
+            void *data,
+            int depth)
+{
+  int *max_depth = (int*)data;
+  if (*max_depth < depth)
+    *max_depth = depth;
+}
+
+
+int
+insn_table_depth(insn_table *table)
+{
+  int depth = 0;
+  insn_table_traverse_tree(table,
+                          &depth,
+                          1,
+                          NULL, /*start*/
+                          update_depth,
+                          NULL, /*end*/
+                          NULL); /*padding*/
+  return depth;
+}
+
+
+/****************************************************************/
+
+void
+dump_traverse_start(insn_table *table,
+                   void *data,
+                   int depth)
+{
+  dumpf(depth*2, "(%d\n", table->opcode_nr);
+}
+
+void
+dump_traverse_leaf(insn_table *entry,
+                  void *data,
+                  int depth)
+{
+  ASSERT(entry->nr_entries == 0
+        && entry->nr_insn == 1
+        && entry->opcode == NULL);
+  dumpf(depth*2, ".%d %s\n", entry->opcode_nr,
+       entry->insns->file_entry->fields[insn_format]);
+}
+
+void
+dump_traverse_end(insn_table *table,
+                 void *data,
+                 int depth)
+{
+  dumpf(depth*2, ")\n");
+}
+
+void
+dump_traverse_padding(insn_table *table,
+                     void *data,
+                     int depth,
+                     int opcode_nr)
+{
+  dumpf(depth*2, ".<%d>\n", opcode_nr);
+}
+
+
+void
+dump_traverse(insn_table *table)
+{
+  insn_table_traverse_tree(table, NULL, 1,
+                          dump_traverse_start,
+                          dump_traverse_leaf,
+                          dump_traverse_end,
+                          dump_traverse_padding);
+}
+
+
+/****************************************************************/
+
+
+void
+semantics_h_print_function(lf *file,
+                          insn *instruction,
+                          insn_bits *expanded_bits)
+{
+  lf_printf(file, "\n");
+  lf_printf(file, "INLINE_SEMANTICS unsigned_word ");
+  lf_print_function_name(file,
+                        instruction,
+                        expanded_bits,
+                        function_name_prefix_semantics);
+  lf_printf(file, "\n(%s);\n",
+           idecode_cache > 1 ? cache_insn_formal : insn_formal);
+}
+
+
+void
+semantics_h_leaf(insn_table *entry,
+                void *data,
+                int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->nr_insn == 1);
+  semantics_h_print_function(file, entry->insns, entry->expanded_bits);
+}
+
+void
+semantics_h_insn(insn_table *entry,
+                void *data,
+                insn *instruction)
+{
+  lf *file = (lf*)data;
+  semantics_h_print_function(file, instruction, NULL);
+}
+
+
+void 
+gen_semantics_h(insn_table *table, lf *file)
+{
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SEMANTICS_H_\n");
+  lf_printf(file, "#define _SEMANTICS_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_SEMANTICS\n");
+  lf_printf(file, "#define INLINE_SEMANTICS\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+
+  if (idecode_expand_semantics)
+    insn_table_traverse_tree(table,
+                            file,
+                            1,
+                            NULL, /* start */
+                            semantics_h_leaf, /* leaf */
+                            NULL, /* end */
+                            NULL); /* padding */
+  else
+    insn_table_traverse_insn(table,
+                            file,
+                            semantics_h_insn);
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SEMANTICS_H_ */\n");
+
+}
+
+/****************************************************************/
+
+typedef struct _icache_tree icache_tree;
+struct _icache_tree {
+  char *name;
+  icache_tree *next;
+  icache_tree *children;
+};
+
+icache_tree *
+icache_tree_new()
+{
+  icache_tree *new_tree = (icache_tree*)zmalloc(sizeof(icache_tree));
+  ASSERT(new_tree != NULL);
+  return new_tree;
+}
+
+icache_tree *
+icache_tree_insert(icache_tree *tree,
+                  char *name)
+{
+  icache_tree *new_tree;
+  /* find it */
+  icache_tree **ptr_to_cur_tree = &tree->children;
+  icache_tree *cur_tree = *ptr_to_cur_tree;
+  while (cur_tree != NULL
+        && strcmp(cur_tree->name, name) < 0) {
+    ptr_to_cur_tree = &cur_tree->next;
+    cur_tree = *ptr_to_cur_tree;
+  }
+  ASSERT(cur_tree == NULL
+        || strcmp(cur_tree->name, name) >= 0);
+  /* already in the tree */
+  if (cur_tree != NULL
+      && strcmp(cur_tree->name, name) == 0)
+    return cur_tree;
+  /* missing, insert it */
+  ASSERT(cur_tree == NULL
+        || strcmp(cur_tree->name, name) > 0);
+  new_tree = icache_tree_new();
+  new_tree->name = name;
+  new_tree->next = cur_tree;
+  *ptr_to_cur_tree = new_tree;
+  return new_tree;
+}
+
+
+icache_tree *
+insn_table_cache_fields(insn_table *table)
+{
+  icache_tree *tree = icache_tree_new();
+  insn *instruction;
+  for (instruction = table->insns;
+       instruction != NULL;
+       instruction = instruction->next) {
+    insn_field *field;
+    icache_tree *form =
+      icache_tree_insert(tree,
+                        instruction->file_entry->fields[insn_form]);
+    for (field = instruction->fields->first;
+        field != NULL;
+        field = field->next) {
+      if (field->is_string)
+       icache_tree_insert(form, field->val_string);
+    }
+  }
+  return tree;
+}
+
+
+
+void
+gen_icache_h(icache_tree *tree,
+            lf *file)
+{
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _ICACHE_H_\n");
+  lf_printf(file, "#define _ICACHE_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_ICACHE\n");
+  lf_printf(file, "#define INLINE_ICACHE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+
+  /* create an instruction cache if being used */
+  if (idecode_cache) {
+    lf_printf(file, "typedef struct _idecode_cache {\n");
+    lf_printf(file, "  unsigned_word address;\n");
+    lf_printf(file, "  void *semantic;\n");
+    if (idecode_cache == 1) {
+      lf_printf(file, "  instruction_word instruction;\n");
+    }
+    else {
+      icache_tree *form;
+      lf_printf(file, "  union {\n");
+      for (form = tree->children;
+          form != NULL;
+          form = form->next) {
+       icache_tree *field;
+       lf_printf(file, "    struct {\n");
+       for (field = form->children;
+            field != NULL;
+            field = field->next) {
+         extraction_rules *rule;
+         int found_rule = 0;
+         for (rule = cachable_values;
+              rule->valid;
+              rule++) {
+           if (strcmp(field->name, rule->old_name) == 0) {
+             found_rule = 1;
+             if (rule->new_name != NULL)
+               lf_printf(file, "      %s %s; /* %s */\n",
+                         rule->type == NULL ? "unsigned" : rule->type,
+                         rule->new_name, rule->old_name);
+           }
+         }
+         if (!found_rule)
+           lf_printf(file, "      unsigned %s;\n", field->name);
+       }
+       lf_printf(file, "    } %s;\n", form->name);
+      }
+      lf_printf(file, "  } crack;\n");
+    }
+    lf_printf(file, "} idecode_cache;\n");
+  }
+
+  /* define various fields according to the cache */
+  if (idecode_cache <= 1) {
+    extraction_rules *rule;
+    lf_printf(file, "\n");
+    for (rule = cachable_values;
+        rule->valid;
+        rule++) {
+      if (rule->expression != NULL)
+       lf_printf(file, "#define %s %s\n",
+                 rule->new_name, rule->expression);
+    }
+  }
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _ICACHE_H_ */\n");
+}
+
+
+
+
+/****************************************************************/
+
+
+void
+lf_print_c_extraction(lf *file,
+                     insn *instruction,
+                     char *field_name,
+                     char *field_type,
+                     char *field_expression,
+                     insn_field *cur_field,
+                     insn_bits *bits,
+                     int get_value_from_cache,
+                     int put_value_in_cache)
+{
+  ASSERT(field_name != NULL);
+  if (bits != NULL
+      && (!bits->opcode->is_boolean || bits->value == 0)
+      && strcmp(field_name, cur_field->val_string) == 0) {
+    ASSERT(bits->field == cur_field);
+    ASSERT(field_type == NULL);
+    lf_print_c_line_nr(file, instruction->file_entry);
+    lf_printf(file, "const unsigned %s = ",
+             field_name);
+    if (bits->opcode->last < bits->field->last)
+      lf_printf(file, "%d;\n",
+               bits->value << (bits->field->last - bits->opcode->last));
+    else
+      lf_printf(file, "%d;\n", bits->value);
+  }
+  else {
+    /* put the field in the local variable */
+    lf_print_c_line_nr(file, instruction->file_entry);
+    lf_printf(file, "%s const %s = ",
+             field_type == NULL ? "unsigned" : field_type,
+             field_name);
+    /* getting it from the cache */
+    if (get_value_from_cache || put_value_in_cache) {
+      lf_printf(file, "cache_entry->crack.%s.%s",
+               instruction->file_entry->fields[insn_form],
+               field_name);
+      if (put_value_in_cache) /* also put it in the cache? */
+       lf_printf(file, " = ");
+    }
+    if (!get_value_from_cache) {
+      if (strcmp(field_name, cur_field->val_string) == 0)
+       lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
+                 cur_field->first, cur_field->last);
+      else if (field_expression != NULL)
+       lf_printf(file, "%s", field_expression);
+      else
+       lf_printf(file, "eval_%s", field_name);
+    }
+    lf_printf(file, ";\n");
+  }
+}
+
+
+void
+lf_print_c_extractions(lf *file,
+                      insn *instruction,
+                      insn_bits *expanded_bits,
+                      int get_value_from_cache,
+                      int put_value_in_cache)
+{
+  insn_field *cur_field;
+
+  /* extract instruction fields */
+  lf_printf(file, "/* extraction: %s */\n",
+           instruction->file_entry->fields[insn_format]);
+
+  for (cur_field = instruction->fields->first;
+       cur_field->first < insn_size;
+       cur_field = cur_field->next) {
+    if (cur_field->is_string) {
+      insn_bits *bits;
+      int found_rule = 0;
+      /* find any corresponding value */
+      for (bits = expanded_bits;
+          bits != NULL;
+          bits = bits->last) {
+       if (bits->field == cur_field)
+         break;
+      }
+      /* try the cache rule table for what to do */
+      if (get_value_from_cache || put_value_in_cache) {      
+       extraction_rules *field_rule;
+       for (field_rule = cachable_values;
+            field_rule->valid;
+            field_rule++) {
+         if (strcmp(cur_field->val_string, field_rule->old_name) == 0) {
+           found_rule = 1;
+           if (field_rule->valid > 1 && put_value_in_cache)
+             lf_print_c_extraction(file,
+                                   instruction,
+                                   field_rule->new_name,
+                                   field_rule->type,
+                                   field_rule->expression,
+                                   cur_field,
+                                   bits,
+                                   0,
+                                   0);
+           else if (field_rule->valid == 1)
+             lf_print_c_extraction(file,
+                                   instruction,
+                                   field_rule->new_name,
+                                   field_rule->type,
+                                   field_rule->expression,
+                                   cur_field,
+                                   bits,
+                                   get_value_from_cache,
+                                   put_value_in_cache);
+         }
+       }
+      }
+      if (found_rule == 0)
+       lf_print_c_extraction(file,
+                             instruction,
+                             cur_field->val_string,
+                             0,
+                             0,
+                             cur_field,
+                             bits,
+                             get_value_from_cache,
+                             put_value_in_cache);
+      /* if any (XXX == 0), output a corresponding test */
+      if (instruction->file_entry->annex != NULL) {
+       char *field_name = cur_field->val_string;
+       char *is_0_ptr = instruction->file_entry->annex;
+       int field_len = strlen(field_name);
+       if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) {
+         is_0_ptr += field_len;
+         while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) {
+           if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0
+               && !isalpha(is_0_ptr[ - field_len - 1])) {
+             lf_print_c_line_nr(file, instruction->file_entry);
+             lf_printf(file, "const unsigned %s_is_0 = (", field_name);
+             if (bits != NULL)
+               lf_printf(file, "%d", bits->value);
+             else
+               lf_printf(file, "%s", field_name);
+             lf_printf(file, " == 0);\n");
+             break;
+           }
+           is_0_ptr += strlen("_is_0");
+         }
+       }
+      }
+      /* any thing else ... */
+    }
+  }
+  lf_print_file_line_nr(file);
+}
+
+void
+lf_print_c_validate(lf *file,
+                   insn *instruction,
+                   opcode_field *opcodes)
+{
+  unsigned check_mask = 0;
+  unsigned check_val = 0;
+  insn_field *field;
+  opcode_field *opcode;
+
+  for (field = instruction->fields->first;
+       field->first < insn_size;
+       field = field->next) {
+
+    check_mask <<= field->width;
+    check_val <<= field->width;
+
+    /* is it a constant that could need validating? */
+    if (!field->is_int && !field->is_slash)
+      continue;
+
+    /* has it been checked by a table? */
+    for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) {
+      if (field->first >= opcode->first
+         && field->last <= opcode->last)
+       break;
+    }
+    if (opcode != NULL)
+      continue;
+
+    check_mask |= (1 << field->width)-1;
+    check_val |= field->val_int;
+  }
+
+  /* if any bits not checked by opcode tables, output code to check them */
+  if (!it_is("illegal", instruction->file_entry->fields[insn_flags])
+      && check_mask) {
+    lf_printf(file, "\n");
+    lf_printf(file, "/* validate: %s */\n",
+             instruction->file_entry->fields[insn_format]);
+    lf_printf(file, "if ((instruction & 0x%x) != 0x%x) {\n",
+             check_mask, check_val);
+    switch (idecode_cache) {
+    case 0:
+      lf_printf(file, "  return semantic_illegal(%s);\n", insn_actual);
+      break;
+    case 1:
+      lf_printf(file, "  return semantic_illegal;\n");
+      break;
+    default:
+      lf_printf(file, "  return idecode_illegal(%s);\n", cache_idecode_actual);
+    }
+    lf_printf(file, "}\n");
+  }
+
+}
+
+
+void
+lf_print_c_cracker(lf *file,
+                  insn *instruction,
+                  insn_bits *expanded_bits,
+                  opcode_field *opcodes)
+{
+
+  /* function header */
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+
+  lf_print_my_prefix(file,
+                    instruction->file_entry);
+
+  lf_print_ptrace(file);
+
+  lf_print_c_validate(file, instruction, opcodes);
+
+  lf_printf(file, "\n");
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  lf_print_c_extractions(file,
+                        instruction,
+                        expanded_bits,
+                        0/*get_value_from_cache*/,
+                        1/*put_value_in_cache*/);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+
+  /* return the function propper (main sorts this one out) */
+  lf_printf(file, "\n");
+  lf_printf(file, "/* semantic routine */\n");
+  lf_print_c_line_nr(file, instruction->file_entry);
+  lf_printf(file, "return ");
+  lf_print_function_name(file,
+                        instruction,
+                        expanded_bits,
+                        function_name_prefix_semantics);
+  lf_printf(file, ";\n");
+
+  lf_print_file_line_nr(file);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+}
+
+
+void
+lf_print_c_semantic(lf *file,
+                   insn *instruction,
+                   insn_bits *expanded_bits,
+                   opcode_field *opcodes)
+{
+
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+
+  lf_print_my_prefix(file,
+                    instruction->file_entry);
+  lf_putstr(file, insn_local);
+  lf_printf(file, "\n");
+
+  lf_printf(file, "\n");
+  lf_print_c_extractions(file,
+                        instruction,
+                        expanded_bits,
+                        idecode_cache > 1/*get_value_from_cache*/,
+                        0/*put_value_in_cache*/);
+
+  lf_print_ptrace(file);
+
+  /* generate code to check previously unchecked fields */
+  if (idecode_cache < 2)
+    lf_print_c_validate(file, instruction, opcodes);
+
+  /* if OEA and a floating point generate a check that fp is enabled */
+  if (it_is("f", instruction->file_entry->fields[insn_flags])) {
+    lf_printf(file, "\n");
+    lf_printf(file, "/* verify FP is enabled */\n");
+    lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n");
+    lf_printf(file, "  floating_point_unavailable_interrupt(processor, cia);\n");
+  }
+
+  /* generate the code (or at least something */
+  if (instruction->file_entry->annex != NULL) {
+    /* true code */
+    lf_printf(file, "\n");
+    lf_print_c_line_nr(file, instruction->file_entry);
+    lf_printf(file, "{\n");
+    lf_indent(file, +2);
+    lf_print_c_code(file, instruction->file_entry->annex);
+    lf_indent(file, -2);
+    lf_printf(file, "}\n");
+    lf_print_file_line_nr(file);
+  }
+  else if (it_is("nop", instruction->file_entry->fields[insn_flags])) {
+    lf_print_file_line_nr(file);
+  }
+  else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
+    /* unimplemented floating point - call for assistance */
+    lf_printf(file, "\n");
+    lf_print_c_line_nr(file, instruction->file_entry);
+    lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
+    lf_print_file_line_nr(file);
+  }
+  else {
+    /* abort so it is implemented now */
+    lf_print_c_line_nr(file, instruction->file_entry);
+    lf_putstr(file, "error(\"%s: unimplemented, cia=0x%x\\n\", my_prefix, cia);\n");
+    lf_print_file_line_nr(file);
+    lf_printf(file, "\n");
+  }
+
+  /* the function footer */
+  lf_printf(file, "return nia;\n");
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+}
+
+void
+lf_print_c_semantic_function(lf *file,
+                            insn *instruction,
+                            insn_bits *expanded_bits,
+                            opcode_field *opcodes)
+{
+
+  /* build the semantic routine to execute the instruction */
+
+  /* function header */
+  lf_printf(file, "\n");
+  lf_printf(file, "INLINE_SEMANTICS unsigned_word\n");
+  lf_print_function_name(file,
+                        instruction,
+                        expanded_bits,
+                        function_name_prefix_semantics);
+  lf_printf(file, "\n(%s)\n",
+           idecode_cache > 1 ? cache_insn_formal : insn_formal);
+
+  lf_print_c_semantic(file,
+                     instruction,
+                     expanded_bits,
+                     opcodes);
+
+}
+
+
+void
+semantics_c_leaf(insn_table *entry,
+                void *data,
+                int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->nr_insn == 1
+        && entry->opcode == NULL
+        && entry->parent != NULL
+        && entry->parent->opcode != NULL);
+  lf_print_c_semantic_function(file,
+                              entry->insns,
+                              entry->expanded_bits,
+                              entry->parent->opcode);
+}
+
+void
+semantics_c_insn(insn_table *table,
+                void *data,
+                insn *instruction)
+{
+  lf *file = (lf*)data;
+  lf_print_c_semantic_function(file, instruction,
+                              NULL, NULL);
+}
+
+
+
+void 
+gen_semantics_c(insn_table *table, lf *file)
+{
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SEMANTICS_C_\n");
+  lf_printf(file, "#define _SEMANTICS_C_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef STATIC_INLINE_SEMANTICS\n");
+  lf_printf(file, "#define STATIC_INLINE_SEMANTICS STATIC_INLINE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"cpu.h\"\n");
+  lf_printf(file, "#include \"idecode.h\"\n");
+  lf_printf(file, "#include \"semantics.h\"\n");
+  lf_printf(file, "\n");
+
+  if (idecode_expand_semantics)
+    insn_table_traverse_tree(table,
+                            file,
+                            1,
+                            NULL, /* start */
+                            semantics_c_leaf,
+                            NULL, /* end */
+                            NULL); /* padding */
+  else
+    insn_table_traverse_insn(table,
+                            file,
+                            semantics_c_insn);
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SEMANTICS_C_ */\n");
+}
+
+
+/****************************************************************/
+
+void
+gen_idecode_h(insn_table *table, lf *file)
+{
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _IDECODE_H_\n");
+  lf_printf(file, "#define _IDECODE_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_IDECODE\n");
+  lf_printf(file, "#define INLINE_IDECODE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"idecode_insn.h\"\n");
+  lf_printf(file, "#include \"idecode_expression.h\"\n");
+  lf_printf(file, "#include \"idecode_fields.h\"\n");
+  lf_printf(file, "#include \"idecode_branch.h\"\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"icache.h\"\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef unsigned_word idecode_semantic\n(%s);\n",
+           idecode_cache < 2 ? insn_formal : cache_insn_formal);
+  lf_printf(file, "\n");
+  if (!idecode_cache)
+    lf_printf(file, "INLINE_IDECODE unsigned_word idecode_issue\n(%s);\n",
+             insn_formal);
+  else if (idecode_cache)
+    lf_printf(file, "INLINE_IDECODE idecode_semantic *idecode\n(%s);\n",
+             idecode_cache == 1 ? insn_formal : cache_idecode_formal);
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _IDECODE_H_ */\n");
+}
+
+
+/****************************************************************/
+
+
+void
+idecode_table_start(insn_table *table,
+                   void *data,
+                   int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+  /* start of the table */
+  if (!table->opcode_rule->use_switch) {
+    lf_printf(file, "\n");
+    lf_printf(file, "static idecode_table_entry ");
+    lf_print_table_name(file, table);
+    lf_printf(file, "[] = {\n");
+  }
+}
+
+void
+idecode_table_leaf(insn_table *entry,
+                  void *data,
+                  int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->parent != NULL);
+  ASSERT(depth == 0);
+
+  /* add an entry to the table */
+  if (!entry->parent->opcode_rule->use_switch) {
+    if (entry->opcode == NULL) {
+      /* table leaf entry */
+      lf_printf(file, "  /*%d*/ { 0, 0, ", entry->opcode_nr);
+      lf_print_function_name(file,
+                            entry->insns,
+                            entry->expanded_bits,
+                            (idecode_cache < 2
+                             ? function_name_prefix_semantics
+                             : function_name_prefix_idecode));
+      lf_printf(file, " },\n");
+    }
+    else if (entry->opcode_rule->use_switch) {
+      /* table calling switch statement */
+      lf_printf(file, "  /*%d*/ { -1, 0, ",
+               entry->opcode_nr);
+      lf_print_table_name(file, entry);
+      lf_printf(file, " },\n");
+    }
+    else {
+      /* table `calling' another table */
+      lf_printf(file, "  /*%d*/ { ", entry->opcode_nr);
+      if (entry->opcode->is_boolean)
+       lf_printf(file, "MASK32(%d,%d), 0, ",
+                 entry->opcode->first, entry->opcode->last);
+      else
+       lf_printf(file, "%d, MASK32(%d,%d), ",
+                 insn_size - entry->opcode->last - 1,
+                 entry->opcode->first, entry->opcode->last);
+      lf_print_table_name(file, entry);
+      lf_printf(file, " },\n");
+    }
+  }
+}
+
+void
+idecode_table_end(insn_table *table,
+                 void *data,
+                 int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+
+  if (!table->opcode_rule->use_switch) {
+    lf_printf(file, "};\n");
+  }
+}
+
+void
+idecode_table_padding(insn_table *table,
+                     void *data,
+                     int depth,
+                     int opcode_nr)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+
+  if (!table->opcode_rule->use_switch) {
+    lf_printf(file, "  /*%d*/ { 0, 0, %s_illegal },\n",
+             opcode_nr, idecode_cache > 1 ? "idecode" : "semantic");
+  }
+}
+
+
+/****************************************************************/
+
+
+void lf_print_idecode_switch
+(lf *file, 
+ insn_table *table);
+
+
+void
+idecode_switch_start(insn_table *table,
+               void *data,
+               int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+  ASSERT(table->opcode_rule->use_switch);
+
+  lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n",
+           table->opcode->first, table->opcode->last);
+}
+
+
+void
+idecode_switch_leaf(insn_table *entry,
+                   void *data,
+                   int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->parent != NULL);
+  ASSERT(depth == 0);
+  ASSERT(entry->parent->opcode_rule->use_switch);
+
+  lf_printf(file, "case %d:\n", entry->opcode_nr);
+  lf_indent(file, +2);
+  {
+    if (entry->opcode == NULL) {
+      /* switch calling leaf */
+      lf_printf(file, "return ");
+      lf_print_function_name(file,
+                            entry->insns,
+                            entry->expanded_bits,
+                            (idecode_cache < 2
+                             ? function_name_prefix_semantics
+                             : function_name_prefix_idecode));
+      if (!idecode_cache)
+       lf_printf(file, "(%s);\n", insn_actual);
+      else if (idecode_cache == 1)
+       lf_printf(file, ";\n");
+      else
+       lf_printf(file, "(%s);\n", cache_idecode_actual);
+    }
+    else if (entry->opcode_rule->use_switch) {
+      /* switch calling switch */
+      lf_print_idecode_switch(file, entry);
+    }
+    else {
+      /* switch calling table */
+      lf_printf(file, "return ");
+      lf_print_idecode_table(file, entry);
+    }
+    lf_printf(file, "break;\n");
+  }
+  lf_indent(file, -2);
+}
+
+lf_print_idecode_switch_illegal(lf *file)
+{
+  switch (idecode_cache) {
+  case 0:
+    lf_printf(file, "  return semantic_illegal(%s);\n", insn_actual);
+    break;
+  case 1:
+    lf_printf(file, "  return semantic_illegal;\n");
+    break;
+  default:
+    lf_printf(file, "  return idecode_illegal(%s);\n", cache_idecode_actual);
+  }
+  lf_printf(file, "  break;\n");
+}
+
+void
+idecode_switch_end(insn_table *table,
+                  void *data,
+                  int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+  ASSERT(table->opcode_rule->use_switch);
+
+  if (table->opcode_rule->use_switch == 1) {
+    lf_printf(file, "default:\n");
+    lf_print_idecode_switch_illegal(file);
+  }
+  lf_printf(file, "}\n");
+}
+
+void
+idecode_switch_padding(insn_table *table,
+                      void *data,
+                      int depth,
+                      int opcode_nr)
+{
+  lf *file = (lf*)data;
+
+  ASSERT(depth == 0);
+  ASSERT(table->opcode_rule->use_switch);
+
+  if (table->opcode_rule->use_switch > 1) {
+    lf_printf(file, "case %d:\n", opcode_nr);
+    lf_print_idecode_switch_illegal(file);
+  }
+}
+
+
+void
+lf_print_idecode_switch(lf *file, 
+                       insn_table *table)
+{
+  insn_table_traverse_tree(table,
+                          file,
+                          0,
+                          idecode_switch_start,
+                          idecode_switch_leaf,
+                          idecode_switch_end,
+                          idecode_switch_padding);
+}
+
+
+void
+idecode_expand_if_switch(insn_table *table,
+                        void *data,
+                        int depth)
+{
+  lf *file = (lf*)data;
+
+  if (table->opcode_rule->use_switch
+      && table->parent != NULL /* don't expand the top one yet */
+      && !table->parent->opcode_rule->use_switch) {
+    lf_printf(file, "\n");
+    lf_printf(file, "STATIC_INLINE_IDECODE void\n");
+    lf_print_table_name(file, table);
+    lf_printf(file, "\n(%s)\n",
+             idecode_cache ? cache_idecode_formal : insn_formal);
+    lf_printf(file, "{\n");
+    {
+      lf_indent(file, +2);
+      lf_print_idecode_switch(file, table);
+      lf_indent(file, -2);
+    }
+    lf_printf(file, "}\n");
+  }
+}
+
+
+lf_print_c_cracker_function(lf *file,
+                           insn *instruction,
+                           insn_bits *expanded_bits,
+                           opcode_field *opcodes)
+{
+  /* if needed, generate code to enter this routine into a cache */
+  lf_printf(file, "\n");
+  lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
+  lf_print_function_name(file,
+                        instruction,
+                        expanded_bits,
+                        function_name_prefix_idecode);
+  lf_printf(file, "\n(%s)\n", cache_idecode_formal);
+
+  lf_print_c_cracker(file,
+                    instruction,
+                    expanded_bits,
+                    opcodes);
+}
+
+void
+idecode_crack_leaf(insn_table *entry,
+                  void *data,
+                  int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->nr_insn == 1
+        && entry->opcode == NULL
+        && entry->parent != NULL
+        && entry->parent->opcode != NULL);
+  lf_print_c_cracker_function(file,
+                             entry->insns,
+                             entry->expanded_bits,
+                             entry->opcode);
+}
+
+void
+idecode_crack_insn(insn_table *entry,
+                  void *data,
+                  insn *instruction)
+{
+  lf *file = (lf*)data;
+  lf_print_c_cracker_function(file,
+                             instruction,
+                             NULL,
+                             NULL);
+}
+
+/****************************************************************/
+
+gen_idecode_c(insn_table *table, lf *file)
+{
+  int depth;
+
+  /* the intro */
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _IDECODE_C_\n");
+  lf_printf(file, "#define _IDECODE_C_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef STATIC_INLINE_IDECODE\n");
+  lf_printf(file, "#define STATIC_INLINE_IDECODE STATIC_INLINE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"cpu.h\"\n");
+  lf_printf(file, "#include \"idecode.h\"\n");
+  lf_printf(file, "#include \"semantics.h\"\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef idecode_semantic *idecode_crack\n(%s);\n",
+           idecode_cache > 1 ? cache_idecode_formal : insn_formal);
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef struct _idecode_table_entry {\n");
+  lf_printf(file, "  unsigned shift;\n");
+  lf_printf(file, "  unsigned mask;\n");
+  lf_printf(file, "  void *function_or_table;\n");
+  lf_printf(file, "} idecode_table_entry;\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+
+  /* output cracking functions where needed */
+  if (idecode_cache > 1) {
+    if (idecode_expand_semantics)
+      insn_table_traverse_tree(table,
+                              file,
+                              1,
+                              NULL,
+                              idecode_crack_leaf,
+                              NULL,
+                              NULL);
+    else
+      insn_table_traverse_insn(table,
+                              file,
+                              idecode_crack_insn);
+  }
+
+
+  /* output tables where needed */
+  for (depth = insn_table_depth(table);
+       depth > 0;
+       depth--) {
+    insn_table_traverse_tree(table,
+                            file,
+                            1-depth,
+                            idecode_table_start,
+                            idecode_table_leaf,
+                            idecode_table_end,
+                            idecode_table_padding);
+  }
+
+  /* output switch functions where needed */
+  insn_table_traverse_tree(table,
+                          file,
+                          1,
+                          idecode_expand_if_switch, /* START */
+                          NULL, NULL, NULL);
+
+  /* output the main idecode routine */
+  lf_printf(file, "\n");
+  if (!idecode_cache)
+    lf_printf(file, "INLINE_IDECODE unsigned_word\nidecode_issue\n(%s)\n",
+             insn_formal);
+  else if (idecode_cache)
+    lf_printf(file, "INLINE_IDECODE idecode_semantic *\nidecode\n(%s)\n",
+             idecode_cache == 1 ? insn_formal : cache_idecode_formal);
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  if (table->opcode_rule->use_switch)
+    lf_print_idecode_switch(file, table);
+  else
+    lf_print_idecode_table(file, table);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif\n");
+}
+
+
+/****************************************************************/
+
+
+typedef enum {
+  spreg_name,
+  spreg_reg_nr,
+  spreg_readonly,
+  spreg_length,
+  nr_spreg_registers = file_table_max_fields
+} spreg_fields;
+
+typedef struct _spreg_table_entry spreg_table_entry;
+struct _spreg_table_entry {
+  char *name;
+  int spreg_nr;
+  int is_readonly;
+  int length;
+  file_table_entry *entry;
+  spreg_table_entry *next;
+};
+
+typedef struct _spreg_table spreg_table;
+struct _spreg_table {
+  spreg_table_entry *sprs;
+};
+
+spreg_table_entry *
+spreg_table_entry_new()
+{
+  spreg_table_entry *new_entry =
+    (spreg_table_entry*)zmalloc(sizeof(spreg_table_entry));
+  ASSERT(new_entry != NULL);
+  return new_entry;
+}
+
+spreg_table *
+spreg_table_new()
+{
+  spreg_table *new_table = (spreg_table*)zmalloc(sizeof(spreg_table));
+  ASSERT(new_table != NULL);
+  return new_table;
+}
+
+void
+spreg_table_insert(spreg_table *table, file_table_entry *entry)
+{
+  /* create a new spr entry */
+  spreg_table_entry *new_spr = spreg_table_entry_new();
+  new_spr->next = NULL;
+  new_spr->entry = entry;
+  new_spr->spreg_nr = atoi(entry->fields[spreg_reg_nr]);
+  new_spr->is_readonly = (entry->fields[spreg_readonly]
+                         ? atoi(entry->fields[spreg_readonly])
+                         : 0);
+  new_spr->length = atoi(entry->fields[spreg_length]);
+  new_spr->name = (char*)zmalloc(strlen(entry->fields[spreg_name]) + 1);
+  ASSERT(new_spr->name != NULL);
+  {
+    int i;
+    for (i = 0; entry->fields[spreg_name][i] != '\0'; i++) {
+      if (isupper(entry->fields[spreg_name][i]))
+       new_spr->name[i] = tolower(entry->fields[spreg_name][i]);
+      else
+       new_spr->name[i] = entry->fields[spreg_name][i];
+    }
+  }
+
+  /* insert, by spreg_nr order */
+  {
+    spreg_table_entry **ptr_to_spreg_entry = &table->sprs;
+    spreg_table_entry *spreg_entry = *ptr_to_spreg_entry;
+    while (spreg_entry != NULL && spreg_entry->spreg_nr < new_spr->spreg_nr) {
+      ptr_to_spreg_entry = &spreg_entry->next;
+      spreg_entry = *ptr_to_spreg_entry;
+    }
+    ASSERT(spreg_entry == NULL || spreg_entry->spreg_nr != new_spr->spreg_nr);
+    *ptr_to_spreg_entry = new_spr;
+    new_spr->next = spreg_entry;
+  }
+
+}
+
+
+spreg_table *
+spreg_table_load(char *file_name)
+{
+  file_table *file = file_table_open(file_name);
+  spreg_table *table = spreg_table_new();
+
+  {
+    file_table_entry *entry;
+    while (entry = file_table_read(file)) {
+      spreg_table_insert(table, entry);
+    }
+  }
+
+  return table;
+}
+
+
+/****************************************************************/
+
+char *spreg_attributes[] = {
+  "is_valid",
+  "is_readonly",
+  "name",
+  "index",
+  "length",
+  0
+};
+
+void
+gen_spreg_h(spreg_table *table, lf *file)
+{
+  spreg_table_entry *entry;
+  char **attribute;
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SPREG_H_\n");
+  lf_printf(file, "#define _SPREG_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_SPREG\n");
+  lf_printf(file, "#define INLINE_SPREG\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef unsigned_word spreg;\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef enum {\n");
+
+  for (entry = table->sprs;
+       entry != NULL ;
+       entry = entry->next) {
+    lf_printf(file, "  spr_%s = %d,\n", entry->name, entry->spreg_nr);
+  }
+
+  lf_printf(file, "  nr_of_sprs = %d\n", nr_of_sprs);
+  lf_printf(file, "} sprs;\n");
+  lf_printf(file, "\n");
+  for (attribute = spreg_attributes;
+       *attribute != NULL;
+       attribute++) {
+    if (strcmp(*attribute, "name") == 0)
+      lf_printf(file, "INLINE_SPREG char *spr_%s(sprs spr);\n",
+               *attribute);
+    else
+      lf_printf(file, "INLINE_SPREG int spr_%s(sprs spr);\n",
+               *attribute);
+  }
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SPREG_H_ */\n");
+}
+
+
+void
+gen_spreg_c(spreg_table *table, lf *file)
+{
+  spreg_table_entry *entry;
+  char **attribute;
+  int spreg_nr;
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SPREG_C_\n");
+  lf_printf(file, "#define _SPREG_C_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"words.h\"\n");
+  lf_printf(file, "#include \"spreg.h\"\n");
+
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef struct _spreg_info {\n");
+  lf_printf(file, "  char *name;\n");
+  lf_printf(file, "  int is_valid;\n");
+  lf_printf(file, "  int length;\n");
+  lf_printf(file, "  int is_readonly;\n");
+  lf_printf(file, "  int index;\n");
+  lf_printf(file, "} spreg_info;\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "static spreg_info spr_info[nr_of_sprs+1] = {\n");
+  entry = table->sprs;
+  for (spreg_nr = 0; spreg_nr < nr_of_sprs+1; spreg_nr++) {
+    if (entry == NULL || spreg_nr < entry->spreg_nr)
+      lf_printf(file, "  { 0, 0, 0, 0, %d},\n", spreg_nr);
+    else {
+      lf_printf(file, "  { \"%s\", %d, %d, %d, spr_%s /*%d*/ },\n",
+               entry->name, 1, entry->length, entry->is_readonly,
+               entry->name, entry->spreg_nr);
+      entry = entry->next;
+    }
+  }
+  lf_printf(file, "};\n");
+
+  for (attribute = spreg_attributes;
+       *attribute != NULL;
+       attribute++) {
+    lf_printf(file, "\n");
+    if (strcmp(*attribute, "name") == 0)
+      lf_printf(file, "INLINE_SPREG char *\n");
+    else
+      lf_printf(file, "INLINE_SPREG int\n");
+    lf_printf(file, "spr_%s(sprs spr)\n", *attribute);
+    lf_printf(file, "{\n");
+    if (spreg_lookup_table
+       || strcmp(*attribute, "name") == 0
+       || strcmp(*attribute, "index") == 0)
+      lf_printf(file, "  return spr_info[spr].%s;\n",
+               *attribute);
+    else {
+      spreg_table_entry *entry;
+      lf_printf(file, "  switch (spr) {\n");
+      for (entry = table->sprs; entry != NULL; entry = entry->next) {
+       lf_printf(file, "  case %d:\n", entry->spreg_nr);
+       if (strcmp(*attribute, "is_valid") == 0)
+         lf_printf(file, "    return 1;\n");
+       else if (strcmp(*attribute, "is_readonly") == 0)
+         lf_printf(file, "    return %d;\n", entry->is_readonly);
+       else if (strcmp(*attribute, "length") == 0)
+         lf_printf(file, "    return %d;\n", entry->length);
+       else
+         ASSERT(0);
+      }
+      lf_printf(file, "  default:\n");
+      lf_printf(file, "    return 0;\n");
+      lf_printf(file, "  }\n");
+    }
+    lf_printf(file, "}\n");
+  }
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SPREG_C_ */\n");
+}
+
+
+
+/****************************************************************/
+
+
+int
+main(int argc,
+     char **argv,
+     char **envp)
+{
+  insn_table *instructions = NULL;
+  spreg_table *sprs = NULL;
+  icache_tree *cache_fields = NULL;
+  int ch;
+
+  while ((ch = getopt(argc, argv, "i:I:r:S:s:D:d:P:p:C:")) != -1) {
+    fprintf(stderr, "\t-%c %s\n", ch, optarg);
+    switch(ch) {
+    case 'I':
+    case 'i':
+      instructions = insn_table_load_insns(optarg);
+      fprintf(stderr, "\texpanding ...\n");
+      insn_table_expand_insns(instructions);
+      fprintf(stderr, "\tcache fields ...\n");
+      cache_fields = insn_table_cache_fields(instructions);
+      if (ch == 'I') {
+       dump_traverse(instructions);
+       dump_insn_table(instructions, 0, 1);
+      }
+      break;
+    case 'r':
+      sprs = spreg_table_load(optarg);
+      break;
+    default:
+      {
+       lf *file = lf_open(optarg);
+       switch (ch) {
+       case 'S':
+         gen_semantics_h(instructions, file);
+         break;
+       case 's':
+         gen_semantics_c(instructions, file);
+         break;
+       case 'P':
+         gen_spreg_h(sprs, file);
+         break;
+       case 'p':
+         gen_spreg_c(sprs, file);
+         break;
+       case 'D':
+         gen_idecode_h(instructions, file);
+         break;
+       case 'd':
+         gen_idecode_c(instructions, file);
+         break;
+       case 'C':
+         gen_icache_h(cache_fields, file);
+         break;
+       }
+       lf_close(file);
+      }
+    }
+  }
+  return 0;
+}
diff --git a/sim/ppc/idecode_branch.h b/sim/ppc/idecode_branch.h
new file mode 100644 (file)
index 0000000..ecae98e
--- /dev/null
@@ -0,0 +1,62 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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.
+    */
+
+
+/* branch macro's:
+
+   The macro's below implement the semantics of the PowerPC jump
+   instructions. */
+
+
+/* If so required, update the Link Register with the next sequential
+   instruction address */
+
+#define UPDATE_LK \
+do { \
+  if (update_LK) { \
+    ppc_ia target = cia + 4; \
+    ppc_spr new_address = (ppc_spr)IEA_MASKED(ppc_is_64bit(processor), \
+                                             target); \
+    LR = new_address; \
+  } \
+  ITRACE(trace_branch, \
+        ("UPDATE_LK - update_LK=%d lr=0x%x cia=0x%x\n", \
+         update_LK, LR, cia); \
+} while (0)
+
+
+/* take the branch - absolute or relative - possibly updating the link
+   register */
+
+#define BRANCH(ADDRESS) \
+do { \
+  UPDATE_LK; \
+  if (update_AA) { \
+    ppc_ia target = (ppc_ia)(ADDRESS); \
+    nia = (ppc_ia)IEA_MASKED(ppc_is_64bit(processor), target); \
+  } \
+  else { \
+    ppc_ia target = cia + ADDRESS; \
+    nia = (ppc_ia)IEA_MASKED(ppc_is_64bit(processor), target); \
+  } \
+  PTRACE(trace_branch, \
+        ("BRANCH - update_AA=%d update_LK=%d nia=0x%x cia=0x%x\n", \
+         update_AA, update_LK, nia, cia); \
+} while (0)
diff --git a/sim/ppc/idecode_fields.h b/sim/ppc/idecode_fields.h
new file mode 100644 (file)
index 0000000..8d65b17
--- /dev/null
@@ -0,0 +1,103 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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.
+    */
+
+
+/* Instruction field macros:
+
+   The macro's below greatly simplify the process of translating the
+   pseudo code found in the PowerPC manual into C.
+
+   In addition to the below, more will be found in the gen program's
+   cache table */
+
+
+/* map some statements and variables directly across */
+
+#define then                    /*then*/
+#define is_64bit_implementation WITH_64BIT_TARGET
+#define is_64bit_mode           IS_64BIT_MODE(processor)
+
+#define NIA nia
+#define CIA cia
+
+
+/* reservation */
+
+#define RESERVE        cpu_reservation(processor)->valid
+#define RESERVE_ADDR   cpu_reservation(processor)->addr
+#define RESERVE_DATA   cpu_reservation(processor)->data
+
+#define real_addr(EA, IS_READ)  vm_real_data_addr(cpu_data_map(processor), \
+                                                 EA, \
+                                                 IS_READ, \
+                                                 processor, \
+                                                 cia)
+
+
+/* depending on mode return a 32 or 64bit number */
+
+#define IEA(X)       (is_64bit_mode \
+                     ? (X) \
+                     : MASKED((X), 32, 63))
+
+/* Expand argument to current architecture size */
+
+#define EXTS(X)                EXTS_##X
+
+
+/* Gen translates text of the form A{XX:YY} into A_XX_YY_ the macro's
+   below define such translated text into real expressions */
+
+/* the spr field as it normally is used */
+
+#define spr_5_9_ (spr & 0x1f)
+#define spr_0_4_ (spr >> 5)
+#define spr_0_ ((spr & BIT10(0)) != 0)
+
+#define tbr_5_9_ (tbr & 0x1f)
+#define tbr_0_4_ (tbr >> 5)
+
+
+#define TB cpu_get_time_base(processor)
+
+
+/* various registers with important masks */
+
+#define LR_0b00                (LR & ~3)
+#define CTR_0b00       (CTR & ~3)
+
+#define CR_BI_      ((CR & BIT32_BI) != 0)
+#define CR_BA_ ((CR & BIT32_BA) != 0)
+#define CR_BB_ ((CR & BIT32_BB) != 0)
+
+
+/* extended extracted fields */
+
+#define TO_0_ ((TO & BIT5(0)) != 0)
+#define TO_1_ ((TO & BIT5(1)) != 0)
+#define TO_2_ ((TO & BIT5(2)) != 0)
+#define TO_3_ ((TO & BIT5(3)) != 0)
+#define TO_4_ ((TO & BIT5(4)) != 0)
+
+#define BO_0_ ((BO & BIT5(0)) != 0)
+#define BO_1_ ((BO & BIT5(1)) != 0)
+#define BO_2_ ((BO & BIT5(2)) != 0)
+#define BO_3_ ((BO & BIT5(3)) != 0)
+#define BO_4_ ((BO & BIT5(4)) != 0)
diff --git a/sim/ppc/idecode_insn.h b/sim/ppc/idecode_insn.h
new file mode 100644 (file)
index 0000000..4e56b78
--- /dev/null
@@ -0,0 +1,67 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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.
+    */
+
+
+/*
+ * Interface for the Instruction execution routines
+ */
+
+/*
+ * Macro's that define the parts of an instruction
+ */
+
+#define FLOATING_POINT_ENABLED_PROGRAM_INTERRUPT \
+     program_interrupt(processor, \
+                      cia, \
+                      floating_point_enabled_program_interrupt)
+
+#define ILLEGAL_INSN_PROGRAM_INTERRUPT \
+     program_interrupt(processor, \
+                      cia, \
+                      illegal_instruction_program_interrupt)
+#define PRIVILEGED_INSN_PROGRAM_INTERRUPT \
+     program_interrupt(processor, \
+                      cia, \
+                      privileged_instruction_program_interrupt)
+
+#define TRAP_PROGRAM_INTERRUPT \
+     program_interrupt(processor, \
+                      cia, \
+                      trap_program_interrupt)
+
+#define FLOATING_POINT_UNAVAILABLE_INTERRUPT \
+     floating_point_unavailable_interrupt(processor, \
+                                         cia)
+
+#define FLOATING_POINT_ASSIST_INTERRUPT \
+     floating_point_assist_interrupt(processor, \
+                                    cia)
+
+#define BREAKPOINT \
+     do { \
+       ITRACE(trace_breakpoint, \
+             ("breakpoint - cia0x%x\n", \
+              cia)); \
+       cpu_halt(processor, cia, was_trap, 0); \
+     } while (0)
+
+#define SYSTEM_CALL_INTERRUPT \
+     system_call_interrupt(processor, \
+                          cia)
diff --git a/sim/ppc/memory_map.c b/sim/ppc/memory_map.c
new file mode 100644 (file)
index 0000000..af97006
--- /dev/null
@@ -0,0 +1,355 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _MEMORY_MAP_C_
+#define _MEMORY_MAP_C_
+
+#ifndef STATIC_INLINE_MEMORY_MAP
+#define STATIC_INLINE_MEMORY_MAP STATIC_INLINE
+#endif
+
+
+#include "basics.h"
+#include "device_tree.h"
+#include "memory_map.h"
+#include "interrupts.h"
+
+
+typedef struct _memory_mapping memory_mapping;
+struct _memory_mapping {
+  /* ram map */
+  void *buffer;
+  /* device map */
+  device_node *device;
+  device_reader_callback *reader;
+  device_writer_callback *writer;
+  /* common */
+  unsigned_word base;
+  unsigned_word bound;
+  unsigned_word size;
+  struct _memory_mapping *next;
+};
+
+struct _memory_map {
+  memory_mapping *first;
+};
+
+INLINE_MEMORY_MAP memory_map *
+new_memory_map(void)
+{
+  memory_map *new_map;
+  new_map = ZALLOC(memory_map);
+  return new_map;
+}
+
+STATIC_INLINE_MEMORY_MAP void
+memory_map_add_memory(memory_map *map,
+                     device_node *device,
+                     device_reader_callback *reader,
+                     device_writer_callback *writer,
+                     void *buffer,
+                     unsigned_word base,
+                     unsigned size)
+{
+  memory_mapping *new_mapping;
+  memory_mapping *next_mapping;
+  memory_mapping **last_mapping;
+
+  /* actually do occasionally get a zero size map */
+  if (size == 0)
+    return;
+
+  new_mapping = ZALLOC(memory_mapping);
+
+  /* ram */
+  new_mapping->buffer = buffer;
+  /* devices */
+  new_mapping->device = device;
+  new_mapping->reader = reader;
+  new_mapping->writer = writer;
+  /* common */
+  new_mapping->base = base;
+  new_mapping->size = size;
+  new_mapping->bound = base + size;
+
+  /* find the insertion point (between last/next) */
+  next_mapping = map->first;
+  last_mapping = &map->first;
+  while(next_mapping != NULL && next_mapping->bound <= new_mapping->base) {
+    /* assert: new_mapping->base > all bases before next_mapping */
+    /* assert: new_mapping->bound >= all bounds before next_mapping */
+    last_mapping = &next_mapping->next;
+    next_mapping = next_mapping->next;
+  }
+
+  /* check insertion point correct */
+  if (next_mapping != NULL && next_mapping->base < new_mapping->bound) {
+    error("memory_map_add_callback_memory() internal error - map overlap\n");
+  }
+
+  /* insert the new mapping */
+  *last_mapping = new_mapping;
+  new_mapping->next = next_mapping;
+
+}
+
+
+INLINE_MEMORY_MAP void
+memory_map_add_callback_memory(memory_map *map,
+                              device_node *device,
+                              device_reader_callback *reader,
+                              device_writer_callback *writer,
+                              unsigned_word base,
+                              unsigned size)
+{
+  memory_map_add_memory(map, device, reader, writer, NULL, base, size);
+}
+
+INLINE_MEMORY_MAP void
+memory_map_add_raw_memory(memory_map *map,
+                         void *buffer,
+                         unsigned_word base,
+                         unsigned size)
+{
+  memory_map_add_memory(map, NULL, NULL, NULL, buffer, base, size);
+}
+
+
+
+
+STATIC_INLINE_MEMORY_MAP memory_mapping *
+memory_map_find_mapping(memory_map *map,
+                       unsigned_word addr,
+                       unsigned nr_bytes,
+                       int abort,
+                       cpu *processor,
+                       unsigned_word cia)
+{
+  memory_mapping *mapping = map->first;
+  ASSERT((addr & (nr_bytes-1)) == 0);
+  while (1) {
+    if (addr >= mapping->base
+       && (addr + nr_bytes) <= mapping->bound)
+      break;
+    mapping = mapping->next;
+    if (mapping == NULL) {
+      if (abort) {
+       switch (CURRENT_ENVIRONMENT) {
+       case VIRTUAL_ENVIRONMENT:
+         data_storage_interrupt(processor,
+                                cia,
+                                addr,
+                                vea_storage_interrupt,
+                                0/* doesnt matter */);
+         break;
+       default:
+         error("memory_map_find_mapping() - %s%x%s%s%s%s%s",
+               "access to undefined address 0x", addr, "\n",
+               "this code should be passing back up the device tree an\n",
+               "abort event (with processor attached).  Somewhere in\n",
+               "the device tree this would be caught and either halt,\n",
+               "interrupt, or reset the processor\n");
+       }
+       return NULL;
+      }
+      else
+       return NULL;
+    }
+  }
+  return mapping;
+}
+
+
+STATIC_INLINE_MEMORY_MAP void *
+memory_map_translate(memory_mapping *mapping,
+                    unsigned_word addr)
+{
+  return mapping->buffer + addr - mapping->base;
+}
+
+
+INLINE_MEMORY_MAP unsigned
+memory_map_read_buffer(memory_map *map,
+                      void *buffer,
+                      unsigned_word addr,
+                      unsigned len,
+                      transfer_mode mode)
+{
+  unsigned count;
+  unsigned_1 byte;
+  for (count = 0; count < len; count++) {
+    unsigned pos = 0;
+    unsigned_word raddr = addr + count;
+    memory_mapping *mapping =
+      memory_map_find_mapping(map, raddr, 1,
+                             0/*abort*/,
+                             0, 0/*processor, cia*/);
+    if (mapping == NULL)
+      break;
+    if (mode == raw_transfer ||
+       CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER)
+      pos = count;
+    else if (mode == cooked_transfer)
+      pos = len-count-1;
+    else
+      error("memory_map_read_buffer() - transfer mode unknown\n");
+    if (mapping->reader != NULL)
+      /* hope it doesn't barf */
+      byte = mapping->reader(mapping->device,
+                            raddr - mapping->base,
+                            1,
+                            0, 0/*processor, cia*/);
+    else
+      byte = *(unsigned_1*)memory_map_translate(mapping,
+                                               raddr);
+    ((unsigned_1*)buffer)[pos] = T2H_1(byte);
+  }
+  return count;
+}
+
+
+INLINE_MEMORY_MAP unsigned
+memory_map_write_buffer(memory_map *map,
+                       const void *buffer,
+                       unsigned_word addr,
+                       unsigned len,
+                       transfer_mode mode)
+{
+  unsigned count;
+  unsigned_1 byte;
+  for (count = 0; count < len; count++) {
+    unsigned pos = 0;
+    unsigned_word raddr = addr + count;
+    memory_mapping *mapping =
+      memory_map_find_mapping(map, raddr, 1,
+                             0/*abort*/,
+                             0, 0/*processor, cia*/);
+    if (mapping == NULL)
+      break;
+    if (mode == raw_transfer || 
+       CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER)
+      pos = count;
+    else if (mode == cooked_transfer)
+      pos = len-count-1;
+    else
+      error("memory_map_write_buffer() - transfer mode unknown\n");
+    byte = H2T_1(((unsigned_1*)buffer)[pos]);
+    if (mapping->writer != NULL)
+      /* hope it doesn't barf */
+      mapping->writer(mapping->device,
+                     raddr - mapping->base,
+                     1,
+                     byte,
+                     0, 0/*processor, cia*/);
+    else
+      *(unsigned_1*)memory_map_translate(mapping, raddr) = byte;
+  }
+  return count;
+}
+
+
+INLINE_MEMORY_MAP unsigned
+memory_map_zero(memory_map *map,
+               unsigned_word addr,
+               unsigned len)
+{
+  unsigned pos;
+  for (pos = 0; pos < len; pos++) {
+    unsigned_word raddr = addr + pos;
+    memory_mapping *mapping =
+      memory_map_find_mapping(map, raddr, 1,
+                             0/*abort*/,
+                             0, 0/*processor, cia*/);
+    if (mapping == NULL)
+      break;
+    if (mapping->writer != NULL)
+      mapping->writer(mapping->device,
+                     raddr - mapping->base,
+                     1,
+                     0,
+                     0, 0/*processor, cia*/);
+    else
+      *(unsigned_1*)memory_map_translate(mapping, raddr) = 0;
+  }
+  return pos;
+}
+
+
+#define DEFINE_MEMORY_MAP_READ_N(N) \
+INLINE_MEMORY_MAP unsigned_##N \
+memory_map_read_##N(memory_map *map, \
+                   unsigned_word addr, \
+                   cpu *processor, \
+                   unsigned_word cia) \
+{ \
+  memory_mapping *mapping = memory_map_find_mapping(map, addr, \
+                                                   sizeof(unsigned_##N), \
+                                                   1, \
+                                                   processor, \
+                                                   cia); \
+  if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) \
+    return ((unsigned_##N) \
+           mapping->reader(mapping->device, \
+                           addr - mapping->base, \
+                           sizeof(unsigned_##N), \
+                           processor, \
+                           cia)); \
+  else \
+    return T2H_##N(*(unsigned_##N*)memory_map_translate(mapping, addr)); \
+}
+
+DEFINE_MEMORY_MAP_READ_N(1)
+DEFINE_MEMORY_MAP_READ_N(2)
+DEFINE_MEMORY_MAP_READ_N(4)
+DEFINE_MEMORY_MAP_READ_N(8)
+DEFINE_MEMORY_MAP_READ_N(word)
+
+#define DEFINE_MEMORY_MAP_WRITE_N(N) \
+INLINE_MEMORY_MAP void \
+memory_map_write_##N(memory_map *map, \
+                    unsigned_word addr, \
+                    unsigned_##N val, \
+                    cpu *processor, \
+                    unsigned_word cia) \
+{ \
+  memory_mapping *mapping = memory_map_find_mapping(map, addr, \
+                                                   sizeof(unsigned_##N), \
+                                                   1, \
+                                                   processor, \
+                                                   cia); \
+  if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) \
+    mapping->writer(mapping->device, \
+                   addr - mapping->base, \
+                   sizeof(unsigned_##N), \
+                   val, \
+                   processor, \
+                   cia); \
+  else \
+    *(unsigned_##N*)memory_map_translate(mapping, addr) = H2T_##N(val); \
+}
+
+DEFINE_MEMORY_MAP_WRITE_N(1)
+DEFINE_MEMORY_MAP_WRITE_N(2)
+DEFINE_MEMORY_MAP_WRITE_N(4)
+DEFINE_MEMORY_MAP_WRITE_N(8)
+DEFINE_MEMORY_MAP_WRITE_N(word)
+
+#endif /* _MEMORY_MAP_C_ */
diff --git a/sim/ppc/memory_map.h b/sim/ppc/memory_map.h
new file mode 100644 (file)
index 0000000..c197f43
--- /dev/null
@@ -0,0 +1,126 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _MEMORY_MAP_H_
+#define _MEMORY_MAP_H_
+
+#ifndef INLINE_MEMORY_MAP
+#define INLINE_MEMORY_MAP
+#endif
+
+/* basic types */
+
+typedef struct _memory_map memory_map;
+
+
+/* constructor */
+
+INLINE_MEMORY_MAP memory_map *new_memory_map
+(void);
+
+
+/* operators to add memory to a memory map
+
+   callback-memory:
+
+   includes a callback routine that is called upon for the data.
+   Useful when modeling memory mapped devices.
+
+   raw-memory:
+
+   normal base and bound memory map used to model ram or mapped memory
+   pages */
+
+INLINE_MEMORY_MAP void memory_map_add_callback_memory
+(memory_map *map,
+ device_node *device,
+ device_reader_callback *reader,
+ device_writer_callback *writer,
+ unsigned_word base,
+ unsigned size); /* host limited */
+
+INLINE_MEMORY_MAP void memory_map_add_raw_memory
+(memory_map *map,
+ void *buffer,
+ unsigned_word base,
+ unsigned size/*host limited*/);
+
+
+/* Variable sized read/write/zero:
+
+   Transfer (zero) a variable size block of data between the host and
+   target (possibly byte swapping it).  Should any problems occure,
+   the number of bytes actually transfered is returned. */
+
+INLINE_MEMORY_MAP unsigned memory_map_read_buffer
+(memory_map *map,
+ void *buffer,
+ unsigned_word addr,
+ unsigned len,
+ transfer_mode mode);
+
+INLINE_MEMORY_MAP unsigned memory_map_write_buffer
+(memory_map *map,
+ const void *buffer,
+ unsigned_word addr,
+ unsigned len,
+ transfer_mode mode);
+
+INLINE_MEMORY_MAP unsigned memory_map_zero
+(memory_map *map,
+ unsigned_word addr,
+ unsigned len);
+
+
+/* Fixed sized read/write:
+
+   Transfer a fixed amout of memory between the host and target.  The
+   memory always being translated and the operation always aborting
+   should a problem occure */
+
+#define DECLARE_MEMORY_MAP_WRITE_N(N) \
+INLINE_MEMORY_MAP void memory_map_write_##N \
+(memory_map *map, \
+ unsigned_word addr, \
+ unsigned_##N val, \
+ cpu *processor, \
+ unsigned_word cia);
+
+DECLARE_MEMORY_MAP_WRITE_N(1)
+DECLARE_MEMORY_MAP_WRITE_N(2)
+DECLARE_MEMORY_MAP_WRITE_N(4)
+DECLARE_MEMORY_MAP_WRITE_N(8)
+DECLARE_MEMORY_MAP_WRITE_N(word)
+
+#define DECLARE_MEMORY_MAP_READ_N(N) \
+INLINE_MEMORY_MAP unsigned_##N memory_map_read_##N \
+(memory_map *map, \
+ unsigned_word addr, \
+ cpu *processor, \
+ unsigned_word cia);
+
+DECLARE_MEMORY_MAP_READ_N(1)
+DECLARE_MEMORY_MAP_READ_N(2)
+DECLARE_MEMORY_MAP_READ_N(4)
+DECLARE_MEMORY_MAP_READ_N(8)
+DECLARE_MEMORY_MAP_READ_N(word)
+
+#endif
diff --git a/sim/ppc/ppc-endian.c b/sim/ppc/ppc-endian.c
new file mode 100644 (file)
index 0000000..0158116
--- /dev/null
@@ -0,0 +1,70 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _ENDIAN_C_
+#define _ENDIAN_C_
+
+#ifndef STATIC_INLINE_ENDIAN
+#define STATIC_INLINE_ENDIAN STATIC_INLINE
+#endif
+
+
+#include "config.h"
+#include "words.h"
+#include "ppc-endian.h"
+#include "sim_callbacks.h"
+
+
+typedef union {
+  unsigned_1 val_1[8];
+  unsigned_2 val_2[4];
+  unsigned_4 val_4[2];
+  unsigned_8 val_8[1];
+} endian_map;
+
+#define ENDIAN_N(NAME,BYTE_SIZE) \
+unsigned_##BYTE_SIZE \
+endian_##NAME##_##BYTE_SIZE(unsigned_##BYTE_SIZE raw_in) \
+{ \
+  if (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER) { \
+    return raw_in; \
+  } \
+  else { \
+    endian_map in; \
+    endian_map out; \
+    int byte_nr; \
+    in.val_##BYTE_SIZE[0] = raw_in; \
+    for (byte_nr = 0; byte_nr < BYTE_SIZE; byte_nr++) { \
+      out.val_1[BYTE_SIZE-1-byte_nr] = in.val_1[byte_nr]; \
+    } \
+    return out.val_##BYTE_SIZE[0]; \
+  } \
+}
+
+
+ENDIAN_N(h2t, 2)
+ENDIAN_N(h2t, 4)
+ENDIAN_N(h2t, 8)
+ENDIAN_N(t2h, 2)
+ENDIAN_N(t2h, 4)
+ENDIAN_N(t2h, 8)
+
+#endif /* _ENDIAN_C_ */
diff --git a/sim/ppc/ppc-endian.h b/sim/ppc/ppc-endian.h
new file mode 100644 (file)
index 0000000..6ac0601
--- /dev/null
@@ -0,0 +1,256 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _ENDIAN_H_
+#define _ENDIAN_H_
+
+/* C byte conversion functions */
+
+extern unsigned_1 endian_h2t_1(unsigned_1 x);
+extern unsigned_2 endian_h2t_2(unsigned_2 x);
+extern unsigned_4 endian_h2t_4(unsigned_4 x);
+extern unsigned_8 endian_h2t_8(unsigned_8 x);
+
+extern unsigned_1 endian_t2h_1(unsigned_1 x);
+extern unsigned_2 endian_t2h_2(unsigned_2 x);
+extern unsigned_4 endian_t2h_4(unsigned_4 x);
+extern unsigned_8 endian_t2h_8(unsigned_8 x);
+
+/* Host dependant:
+
+   The CPP below defines information about the compilation host.  In
+   particular it defines the macro's:
+
+       WITH_HOST_BYTE_ORDER    The byte order of the host. Could
+                               be any of LITTLE_ENDIAN, BIG_ENDIAN
+                               or 0 (unknown).  Those macro's also
+                               need to be defined.
+
+       WITH_NTOH               Network byte order macros defined.
+                               Possible value is 32 or (maybe one
+                               day 64 because some 64bit network
+                               byte order macro is defined.
+ */
+
+
+/* NetBSD:
+
+   NetBSD is easy, everything you could ever want is in a header file
+   (well almost :-) */
+
+#if defined(__NetBSD__)
+# include <machine/endian.h>
+# define WITH_NTOH 32 /* what about alpha? */
+# if (WITH_HOST_BYTE_ORDER == 0)
+#  undef WITH_HOST_BYTE_ORDER
+#  define WITH_HOST_BYTE_ORDER BYTE_ORDER
+# endif
+# if (BYTE_ORDER != WITH_HOST_BYTE_ORDER)
+#  error "host endian incorrectly configured, check config.h"
+# endif
+#endif
+
+/* Linux is similarly easy.  */
+
+#if defined(__linux__)
+# include <endian.h>
+# include <asm/byteorder.h>
+# if defined(__LITTLE_ENDIAN) && !defined(LITTLE_ENDIAN)
+#  define LITTLE_ENDIAN __LITTLE_ENDIAN
+# endif
+# if defined(__BIG_ENDIAN) && !defined(BIG_ENDIAN)
+#  define BIG_ENDIAN __BIG_ENDIAN
+# endif
+# if defined(__BYTE_ORDER) && !defined(BYTE_ORDER)
+#  define BYTE_ORDER __BYTE_ORDER
+# endif
+# if !defined(__alpha__)
+#  define WITH_NTOH 32 /* what about alpha? */
+# endif
+# if (WITH_HOST_BYTE_ORDER == 0)
+#  undef WITH_HOST_BYTE_ORDER
+#  define WITH_HOST_BYTE_ORDER BYTE_ORDER
+# endif
+# if (BYTE_ORDER != WITH_HOST_BYTE_ORDER)
+#  error "host endian incorrectly configured, check config.h"
+# endif
+#endif
+
+/* INSERT HERE - hosts that have available LITTLE_ENDIAN and
+   BIG_ENDIAN macro's */
+
+
+/* Some hosts don't define LITTLE_ENDIAN or BIG_ENDIAN, help them out */
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+
+/* SunOS on SPARC:
+
+   Big endian last time I looked */
+
+#if defined(sparc) || defined(__sparc__)
+# if (WITH_HOST_BYTE_ORDER == 0)
+#  undef WITH_HOST_BYTE_ORDER
+#  define WITH_HOST_BYTE_ORDER BIG_ENDIAN
+# endif
+# if (WITH_HOST_BYTE_ORDER != BIG_ENDIAN)
+#  error "sun was big endian last time I looked ..."
+# endif
+#endif
+
+
+/* Random x86
+
+   Little endian last time I looked */
+
+#if defined(i386) || defined(i486) || defined(i586) || defined(__i386__) || defined(__i486__) || defined(__i586__)
+# if (WITH_HOST_BYTE_ORDER == 0)
+#  undef WITH_HOST_BYTE_ORDER
+#  define WITH_HOST_BYTE_ORDER LITTLE_ENDIAN
+# endif
+# if (WITH_HOST_BYTE_ORDER != LITTLE_ENDIAN)
+#  error "x86 was little endian last time I looked ..."
+# endif
+#endif
+
+
+/* INSERT HERE - additional hosts that do not have LITTLE_ENDIAN and
+   BIG_ENDIAN definitions available.  */
+
+
+/* SWAPPING:
+
+   According to the following table:
+
+                TARG BE   TARG LE   TARG ??
+       HOST BE    ok        s/w      s/w
+       HOST LE   htohl      ok      ok|ntohl
+       HOST ??   ntohl      s/w      s/w
+
+    define host <-> target byte order conversion macro's */
+
+
+/* IN PLACE:
+
+   These macro's given a variable argument swap its value in place if
+   so required */
+
+#define H2T(VARIABLE) \
+do { \
+  switch (sizeof(VARIABLE)) { \
+  case 1: VARIABLE = H2T_1(VARIABLE); break; \
+  case 2: VARIABLE = H2T_2(VARIABLE); break; \
+  case 4: VARIABLE = H2T_4(VARIABLE); break; \
+  case 8: VARIABLE = H2T_8(VARIABLE); break; \
+  } \
+} while (0)
+
+#define T2H(VARIABLE) \
+do { \
+  switch (sizeof(VARIABLE)) { \
+  case 1: VARIABLE = T2H_1(VARIABLE); break; \
+  case 2: VARIABLE = T2H_2(VARIABLE); break; \
+  case 4: VARIABLE = T2H_4(VARIABLE); break; \
+  case 8: VARIABLE = T2H_8(VARIABLE); break; \
+  } \
+} while (0)
+
+
+/* TARGET WORD:
+
+   Byte swap a quantity the size of the targets word */
+
+#if WITH_64BIT_TARGET
+#define H2T_word(X) H2T_8(X)
+#define T2H_word(X) T2H_8(X)
+#else
+#define H2T_word(X) H2T_4(X)
+#define T2H_word(X) T2H_4(X)
+#endif
+
+
+/* FUNCTIONS:
+
+   Returns the value swapped according to the host/target byte order */
+
+/* no need to swap */
+#if 0
+#if (WITH_HOST_BYTE_ORDER \
+     && WITH_TARGET_BYTE_ORDER \
+     && WITH_HOST_BYTE_ORDER == WITH_TARGET_BYTE_ORDER )
+#define H2T_1(X) (X)
+#define H2T_2(X) (X)
+#define H2T_4(X) (X)
+#define H2T_8(X) (X)
+#define T2H_1(X) (X)
+#define T2H_2(X) (X)
+#define T2H_4(X) (X)
+#define T2H_8(X) (X)
+#endif
+
+/* have ntoh and big endian target */
+#if (WITH_TARGET_BYTE_ORDER == BIG_ENDIAN \
+     && WITH_HOST_BYTE_ORDER != BIG_ENDIAN \
+     && WITH_NTOH)
+#define H2T_8(X) endian_h2t_8(X)
+#define H2T_4(X) htonl(X)
+#define H2T_2(X) htons(X)
+#define H2T_1(X) (X)
+#define T2H_8(X) endian_t2h_8(X)
+#define T2H_4(X) htonl(X)
+#define T2H_2(X) htons(X)
+#define T2H_1(X) (X)
+#endif
+
+/* have ntoh, little host and unknown target */
+#if (WITH_HOST_BYTE_ORDER == LITTLE_ENDIAN \
+     && WITH_TARGET_BYTE_ORDER == 0 \
+     && WITH_NTOH)
+#define H2T_8(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : endian_h2t_8(X))
+#define H2T_4(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : htonl(X))
+#define H2T_2(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : htons(X))
+#define H2T_1(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : (X))
+#define T2H_8(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : endian_t2h_8(X))
+#define T2H_4(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : htonl(X))
+#define T2H_2(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : htons(X))
+#define T2H_1(X) (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER ? (X) : (X))
+#endif
+#endif
+
+/* if all else fails use software */
+#ifndef H2T_1
+#define H2T_1(X) (X)
+#define H2T_2(X) endian_h2t_2(X)
+#define H2T_4(X) endian_h2t_4(X)
+#define H2T_8(X) endian_h2t_8(X)
+#define T2H_1(X) (X)
+#define T2H_2(X) endian_t2h_2(X)
+#define T2H_4(X) endian_t2h_4(X)
+#define T2H_8(X) endian_t2h_8(X)
+#endif
+
+#endif
diff --git a/sim/ppc/ppc.mt b/sim/ppc/ppc.mt
new file mode 100644 (file)
index 0000000..ef3ea68
--- /dev/null
@@ -0,0 +1,3 @@
+ALL=all-ppc
+CLEAN=clean-ppc
+DO_INSTALL=install-ppc
diff --git a/sim/ppc/sim_callbacks.h b/sim/ppc/sim_callbacks.h
new file mode 100644 (file)
index 0000000..a8ee960
--- /dev/null
@@ -0,0 +1,36 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _SIM_CALLBACKS_H_
+#define _SIM_CALLBACKS_H_
+
+#ifndef NORETURN
+#define NORETURN
+#endif
+
+
+void printf_filtered (char *msg, ...);
+void NORETURN error (char *msg, ...);
+void *zalloc (long size);
+#define ZALLOC(TYPE) (TYPE*)zalloc(sizeof (TYPE))
+void zfree(void*);
+
+#endif
diff --git a/sim/ppc/system.c b/sim/ppc/system.c
new file mode 100644 (file)
index 0000000..ca62b27
--- /dev/null
@@ -0,0 +1,387 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _SYSTEM_C_
+#define _SYSTEM_C_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+
+#if (NetBSD >= 199306) /* here NetBSD as that is what we're emulating */
+#include <sys/syscall.h> /* FIXME - should not be including this one */
+#include <sys/sysctl.h>
+#endif
+
+#if (BSD < 199306) /* here BSD as just a bug */
+extern int errno;
+#endif
+
+#include "cpu.h"
+#include "idecode.h"
+#include "system.h"
+
+
+void
+system_call(cpu *processor,
+           unsigned_word cia)
+{
+  switch (cpu_registers(processor)->gpr[0]) {
+    
+
+  case 1/*SYS_exit*/:
+#if (NetBSD >= 199306) && (SYS_exit != 1)
+#  error "SYS_exit"
+#endif
+    {
+      int status = (int)cpu_registers(processor)->gpr[3];
+      cpu_halt(processor, cia, was_exited, status);
+      break;
+    }
+    
+
+  case 3/*SYS_read*/:
+#if (NetBSD >= 199306) && (SYS_read != 3)
+#  error "SYS_read"
+#endif
+    {
+      void *scratch_buffer;
+      int d = (int)cpu_registers(processor)->gpr[3];
+      unsigned_word buf = cpu_registers(processor)->gpr[4];
+      int nbytes = cpu_registers(processor)->gpr[5];
+      int status;
+      int nr_moved;
+
+      /* get a tempoary bufer */
+      scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]);
+
+      /* check if buffer exists by reading it */
+      nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+                                        scratch_buffer,
+                                        buf,
+                                        nbytes,
+                                        raw_transfer);
+      if (nr_moved != nbytes)
+       error("system_call()read - check on buffer failed\n");
+      
+      /* read */
+      if (d == 0) {
+       status = fread (scratch_buffer, 1, nbytes, stdin);
+       if (status == 0 && ferror (stdin))
+         status = -1;
+      } else {
+       status = read (d, scratch_buffer, nbytes);
+      }
+
+      if (status == -1) {
+       cpu_registers(processor)->gpr[0] = errno;
+       break;
+      } else {
+       cpu_registers(processor)->gpr[0] = 0;
+       cpu_registers(processor)->gpr[3] = status;
+
+       if (status > 0) {
+         nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
+                                             scratch_buffer,
+                                             buf,
+                                             status,
+                                             raw_transfer,
+                                             0/*violate_ro*/);
+
+         if (nr_moved != nbytes)
+           error("system_call()read - write to buffer failed\n");
+       }
+      }
+      
+      zfree(scratch_buffer);
+      
+      break;
+    }
+    
+
+  case 4/*SYS_write*/:
+#if (NetBSD >= 199306) && (SYS_write != 4)
+#  error "SYS_write"
+#endif
+    {
+      void *scratch_buffer;
+      int nr_moved;
+      int d = (int)cpu_registers(processor)->gpr[3];
+      unsigned_word buf = cpu_registers(processor)->gpr[4];
+      int nbytes = cpu_registers(processor)->gpr[5];
+      int status;
+      
+      /* get a tempoary bufer */
+      scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]);
+      
+      /* copy in */
+      nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+                                        scratch_buffer,
+                                        buf,
+                                        nbytes,
+                                        raw_transfer);
+      if (nr_moved != nbytes) {
+       /* FIXME - should handle better */
+       error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
+             nr_moved, nbytes);
+      }
+      
+      /* write */
+      status = write(d, scratch_buffer, nbytes);
+      if (status == -1) {
+       cpu_registers(processor)->gpr[0] = errno;
+       break;
+      }
+      cpu_registers(processor)->gpr[0] = 0;
+      cpu_registers(processor)->gpr[3] = status;
+      
+      zfree(scratch_buffer);
+      
+      break;
+    }
+    
+
+  case 17/*SYS_break*/:
+#if (NetBSD >= 199306) && (SYS_break != 17)
+#  error "SYS_break"
+#endif
+    {
+      unsigned_word new_sbrk = ALIGN_PAGE(cpu_registers(processor)->gpr[3]);
+      unsigned_word old_sbrk = core_data_upper_bound(cpu_core(processor));
+      signed_word delta = new_sbrk - old_sbrk;
+      if (delta > 0)
+       core_add_data(cpu_core(processor), delta);
+      cpu_registers(processor)->gpr[0] = 0;
+      cpu_registers(processor)->gpr[3] = new_sbrk;
+      break;
+    }
+
+
+  case 20/*SYS_getpid*/:
+#if (NetBSD >= 199306) && (SYS_getpid != 20)
+#  error "SYS_getpid"
+#endif
+    {
+      cpu_registers(processor)->gpr[3] = (int)getpid();
+      break;
+    }
+    
+
+  case 37/*SYS_kill*/:
+#if (NetBSD >= 199306) && (SYS_kill != 37)
+#  error "SYS_kill"
+#endif
+    {
+      pid_t pid = cpu_registers(processor)->gpr[3];
+      int sig = cpu_registers(processor)->gpr[4];
+      TRACE(trace_tbd, ("SYS_kill - more to this than just a kill\n"));
+      cpu_halt(processor, cia, was_signalled, sig);
+      break;
+    }
+    
+
+  case 48/*SYS_sigprocmask*/:
+#if (NetBSD >= 199306) && (SYS_sigprocmask != 48)
+#  error "SYS_sigprocmask"
+#endif
+    {
+      natural_word how = cpu_registers(processor)->gpr[3];
+      unsigned_word set = cpu_registers(processor)->gpr[4];
+      unsigned_word oset = cpu_registers(processor)->gpr[5];
+      TRACE(trace_system, ("SYS_sigprocmask: how=%d, set=0x%x, oset=0x%x\n",
+                          how, set, oset));
+      cpu_registers(processor)->gpr[0] = 0;
+      cpu_registers(processor)->gpr[3] = 0;
+      cpu_registers(processor)->gpr[4] = set;
+      break;
+    }
+
+
+  case 54/*SYS_ioctl*/:
+#if (NetBSD >= 199306) && (SYS_ioctl != 54)
+#  error "SYS_ioctl"
+#endif
+    {
+      TRACE(trace_system, ("SYS_ioctl: d=%d, request=0x%x, argp=0x%x\n",
+                          cpu_registers(processor)->gpr[3], cpu_registers(processor)->gpr[4], cpu_registers(processor)->gpr[5]));
+      cpu_registers(processor)->gpr[0] = 0;
+      cpu_registers(processor)->gpr[3] = 0;
+      break;
+    }
+
+
+  case 189/*SYS_fstat*/:
+#if (NetBSD >= 199306) && (SYS_fstat != 189)
+#  error "SYS_fstat"
+#endif
+    {
+      int fd = cpu_registers(processor)->gpr[3];
+      unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
+      struct stat buf;
+      int nr_moved;
+      int status;
+
+      /* check buffer all there, by reading it */
+      nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+                                        &buf,
+                                        stat_buf_addr,
+                                        sizeof(buf),
+                                        raw_transfer);
+      if (nr_moved != sizeof(buf))
+       error("system_call()fstat - check on buffer failed\n");
+
+      /* do the fstat call */
+      status = fstat(fd, &buf);
+      if (status == -1) {
+       cpu_registers(processor)->gpr[0] = errno;
+       break;
+      }
+      cpu_registers(processor)->gpr[0] = 0;
+      cpu_registers(processor)->gpr[3] = 0;
+
+      H2T(buf.st_dev);
+      H2T(buf.st_ino);
+      H2T(buf.st_mode);
+      H2T(buf.st_nlink);
+      H2T(buf.st_uid);
+      H2T(buf.st_gid);
+      H2T(buf.st_rdev);
+      H2T(buf.st_size);
+      H2T(buf.st_atime);
+      /* H2T(buf.st_spare1); */
+      H2T(buf.st_mtime);
+      /* H2T(buf.st_spare2); */
+      H2T(buf.st_ctime);
+      /* H2T(buf.st_spare3); */
+      H2T(buf.st_blksize);
+      H2T(buf.st_blocks);
+#if (NetBSD >= 199306)
+      H2T(buf.st_flags);
+      H2T(buf.st_gen);
+#endif
+      
+      nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
+                                         &buf,
+                                         stat_buf_addr,
+                                         sizeof(buf),
+                                         raw_transfer,
+                                         0/*violate_ro*/);
+      break;
+    }
+
+
+  case 202/*SYS___sysctl*/:
+#if (NetBSD >= 199306) && (SYS___sysctl != 202)
+#  error "SYS__sysctl"
+#endif
+    {
+      /* call the arguments by their real name */
+      unsigned_word name = cpu_registers(processor)->gpr[3];
+      natural_word namelen = cpu_registers(processor)->gpr[4];
+      unsigned_word oldp = cpu_registers(processor)->gpr[5];
+      unsigned_word oldlenp = cpu_registers(processor)->gpr[6];
+      natural_word oldlen;
+      natural_word mib;
+      natural_word int_val;
+
+      /* pluck out the management information base id */
+      if (namelen < 1
+         || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor),
+                                                   &mib,
+                                                   name,
+                                                   sizeof(mib),
+                                                   cooked_transfer))
+       error("system_call()SYS___sysctl bad name[0]\n");
+      name += sizeof(mib);
+
+      /* see what to do with it ... */
+      switch (mib) {
+      case 6/*CTL_HW*/:
+#if (NetBSD >= 199306) && (CTL_HW != 6)
+#  error "CTL_HW"
+#endif
+       if (namelen < 2
+           || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor),
+                                                     &mib,
+                                                     name,
+                                                     sizeof(mib),
+                                                     cooked_transfer))
+         error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n");
+       name += sizeof(mib);
+       switch (mib) {
+       case 7/*HW_PAGESIZE*/:
+#if (NetBSD >= 199306) && (HW_PAGESIZE != 7)
+#  error "HW_PAGESIZE"
+#endif
+         if (sizeof(oldlen) != vm_data_map_read_buffer(cpu_data_map(processor),
+                                                       &oldlen,
+                                                       oldlenp,
+                                                       sizeof(oldlen),
+                                                       cooked_transfer))
+           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen read\n");
+         if (sizeof(natural_word) > oldlen)
+           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n");
+         int_val = 8192;
+         oldlen = sizeof(int_val);
+         if (sizeof(int_val) != vm_data_map_write_buffer(cpu_data_map(processor),
+                                                         &int_val,
+                                                         oldp,
+                                                         sizeof(int_val),
+                                                         cooked_transfer,
+                                                         0/*violate_ro*/))
+           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - int_val\n");
+         if (sizeof(oldlen) != vm_data_map_write_buffer(cpu_data_map(processor),
+                                                        &oldlen,
+                                                        oldlenp,
+                                                        sizeof(oldlen),
+                                                        cooked_transfer,
+                                                        0/*violate_ro*/))
+           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen write\n");
+         break;
+       default:
+         error("sysctl() CTL_HW.%d unknown\n", mib);
+         break;
+       }
+       break;
+      default:
+       error("sysctl() name[0]=%s unknown\n", (int)mib);
+       break;
+      }
+      cpu_registers(processor)->gpr[0] = 0;
+      cpu_registers(processor)->gpr[3] = 0;
+      break;
+    }
+
+
+  default:
+    error("system_call() unimplemented system call %d, cia=0x%x, arg[0]=0x%x, lr=0x%x\n",
+         cpu_registers(processor)->gpr[0], cia, cpu_registers(processor)->gpr[3], LR);
+    break;
+    
+  }
+}
+
+#endif /* _SYSTEM_C_ */
diff --git a/sim/ppc/system.h b/sim/ppc/system.h
new file mode 100644 (file)
index 0000000..4a0df87
--- /dev/null
@@ -0,0 +1,29 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _SYSTEM_H_
+#define _SYSTEM_H_
+
+void system_call
+(cpu *processor,
+ unsigned_word cia);
+
+#endif
diff --git a/sim/ppc/vm.h b/sim/ppc/vm.h
new file mode 100644 (file)
index 0000000..335b0bc
--- /dev/null
@@ -0,0 +1,127 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 _VM_H_
+#define _VM_H_
+
+#ifndef INLINE_VM
+#define INLINE_VM
+#endif
+
+typedef struct _vm vm;
+typedef struct _vm_data_map vm_data_map;
+typedef struct _vm_instruction_map vm_instruction_map;
+
+
+/* each PowerPC requires two virtual memory maps */
+
+INLINE_VM vm *vm_create
+(core *memory);
+
+INLINE_VM vm_data_map *vm_create_data_map
+(vm *memory);
+
+INLINE_VM vm_instruction_map *vm_create_instruction_map
+(vm *memory);
+
+
+/* address translation, if the translation is invalid
+   these will not return */
+
+INLINE_VM unsigned_word vm_real_data_addr
+(vm_data_map *data_map,
+ unsigned_word ea,
+ int is_read,
+ cpu *processor,
+ unsigned_word cia);
+
+INLINE_VM unsigned_word vm_real_instruction_addr
+(vm_instruction_map *instruction_map,
+ cpu *processor,
+ unsigned_word cia);
+
+
+/* block transfers */
+
+INLINE_VM int vm_data_map_read_buffer
+(vm_data_map *data_map,
+ void *target,
+ unsigned_word addr,
+ unsigned len,
+ transfer_mode mode);
+
+INLINE_VM int vm_data_map_write_buffer
+(vm_data_map *data_map,
+ const void *source,
+ unsigned_word addr,
+ unsigned len,
+ transfer_mode mode,
+ int violate_read_only_section);
+
+
+/* fetch the next instruction from memory */
+
+INLINE_VM instruction_word vm_instruction_map_read
+(vm_instruction_map *instruction_map,
+ cpu *processor,
+ unsigned_word cia);
+
+
+/* read data from memory */
+
+#define DECLARE_VM_DATA_MAP_READ_N(N) \
+INLINE_VM unsigned_##N vm_data_map_read_##N \
+(vm_data_map *map, \
+ unsigned_word ea, \
+ cpu *processor, \
+ unsigned_word cia);
+
+DECLARE_VM_DATA_MAP_READ_N(1)
+DECLARE_VM_DATA_MAP_READ_N(2)
+DECLARE_VM_DATA_MAP_READ_N(4)
+DECLARE_VM_DATA_MAP_READ_N(8)
+
+
+/* write data to memory */
+
+#define DECLARE_VM_DATA_MAP_WRITE_N(N) \
+INLINE_VM void vm_data_map_write_##N \
+(vm_data_map *map, \
+ unsigned_word addr, \
+ unsigned_##N val, \
+ cpu *processor, \
+ unsigned_word cia);
+
+DECLARE_VM_DATA_MAP_WRITE_N(1)
+DECLARE_VM_DATA_MAP_WRITE_N(2)
+DECLARE_VM_DATA_MAP_WRITE_N(4)
+DECLARE_VM_DATA_MAP_WRITE_N(8)
+
+
+/* update vm data structures due to a synchronization point */
+
+INLINE_VM void vm_synchronize_context
+(vm *memory,
+ spreg *sprs,
+ sreg *srs,
+ msreg msr);
+
+#endif
diff --git a/sim/ppc/words.h b/sim/ppc/words.h
new file mode 100644 (file)
index 0000000..35bdadd
--- /dev/null
@@ -0,0 +1,100 @@
+/* This file is part of psim (model of the PowerPC(tm) architecture)
+
+   Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License
+   as published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+   This library 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
+   Library General Public License for more details.
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+   --
+
+   PowerPC is a trademark of International Business Machines Corporation. */
+
+
+/* Basic type sizes for the PowerPC */
+
+#ifndef _WORDS_H_
+#define _WORDS_H_
+
+/* TYPES:
+
+     natural*  sign determined by host
+     signed*    signed type of the given size
+     unsigned*  The corresponding insigned type
+
+   SIZES
+
+     *NN       Size based on the number of bits
+     *_NN       Size according to the number of bytes
+     *_word     Size based on the target architecture's word
+               word size (32/64 bits)
+
+*/
+
+
+/* bit based */
+typedef char natural8;
+typedef short natural16;
+typedef long natural32;
+typedef long long natural64;
+
+typedef signed char signed8;
+typedef signed short signed16;
+typedef signed long signed32;
+typedef signed long long signed64;
+
+typedef unsigned char unsigned8;
+typedef unsigned short unsigned16;
+typedef unsigned long unsigned32;
+typedef unsigned long long unsigned64;
+
+
+/* byte based */
+typedef natural8 natural_1;
+typedef natural16 natural_2;
+typedef natural32 natural_4;
+typedef natural64 natural_8;
+
+typedef signed8 signed_1;
+typedef signed16 signed_2;
+typedef signed32 signed_4;
+typedef signed64 signed_8;
+
+typedef unsigned8 unsigned_1;
+typedef unsigned16 unsigned_2;
+typedef unsigned32 unsigned_4;
+typedef unsigned64 unsigned_8;
+
+
+/* for general work, the following are defined */
+/* unsigned: >= 32 bits */
+/* signed:   >= 32 bits */
+/* long:     >= 32 bits, sign undefined */
+/* int:      small indicator */
+
+/* target architecture based */
+#if (WITH_64BIT_TARGET)
+typedef natural64 natural_word;
+typedef unsigned64 unsigned_word;
+typedef signed64 signed_word;
+#else
+typedef natural32 natural_word;
+typedef unsigned32 unsigned_word;
+typedef signed32 signed_word;
+#endif
+
+
+/* Other instructions */
+typedef unsigned32 instruction_word;
+
+#endif /* _WORDS_H_ */
This page took 0.131804 seconds and 4 git commands to generate.