aboutsummaryrefslogtreecommitdiff
path: root/sim/ppc
diff options
context:
space:
mode:
authorMichael Meissner <gnu@the-meissners.org>1995-08-23 21:06:36 +0000
committerMichael Meissner <gnu@the-meissners.org>1995-08-23 21:06:36 +0000
commitcb7a68927ab066fb794ed40ad38f601845516fe4 (patch)
tree393e8c5129cfacb4fdf20ecbbeb8125c06041a7f /sim/ppc
parent19c3fec4bf74083f6136dd64e4b503426c77b474 (diff)
downloadgdb-cb7a68927ab066fb794ed40ad38f601845516fe4.zip
gdb-cb7a68927ab066fb794ed40ad38f601845516fe4.tar.gz
gdb-cb7a68927ab066fb794ed40ad38f601845516fe4.tar.bz2
Add PowerPC simulator from Andrew Cagney <cagney@highland.com.au>
Diffstat (limited to 'sim/ppc')
-rw-r--r--sim/ppc/.Sanitize85
-rw-r--r--sim/ppc/COPYING339
-rw-r--r--sim/ppc/COPYING.LIB481
-rw-r--r--sim/ppc/ChangeLog81
-rw-r--r--sim/ppc/Makefile.in297
-rw-r--r--sim/ppc/README.psim253
-rw-r--r--sim/ppc/bits.h194
-rw-r--r--sim/ppc/configure.in32
-rw-r--r--sim/ppc/core.c356
-rw-r--r--sim/ppc/core.h103
-rw-r--r--sim/ppc/device_tree.c506
-rw-r--r--sim/ppc/device_tree.h234
-rw-r--r--sim/ppc/devices.c442
-rw-r--r--sim/ppc/devices.h42
-rw-r--r--sim/ppc/double.c42
-rw-r--r--sim/ppc/dp-bit.c1307
-rw-r--r--sim/ppc/events.c238
-rw-r--r--sim/ppc/events.h75
-rw-r--r--sim/ppc/gen.c3111
-rw-r--r--sim/ppc/idecode_branch.h62
-rw-r--r--sim/ppc/idecode_fields.h103
-rw-r--r--sim/ppc/idecode_insn.h67
-rw-r--r--sim/ppc/memory_map.c355
-rw-r--r--sim/ppc/memory_map.h126
-rw-r--r--sim/ppc/ppc-endian.c70
-rw-r--r--sim/ppc/ppc-endian.h256
-rw-r--r--sim/ppc/ppc.mt3
-rw-r--r--sim/ppc/sim_callbacks.h36
-rw-r--r--sim/ppc/system.c387
-rw-r--r--sim/ppc/system.h29
-rw-r--r--sim/ppc/vm.h127
-rw-r--r--sim/ppc/words.h100
32 files changed, 9939 insertions, 0 deletions
diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize
new file mode 100644
index 0000000..625fd36
--- /dev/null
+++ b/sim/ppc/.Sanitize
@@ -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
index 0000000..a43ea21
--- /dev/null
+++ b/sim/ppc/COPYING
@@ -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.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ 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
index 0000000..eb685a5
--- /dev/null
+++ b/sim/ppc/COPYING.LIB
@@ -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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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
+
+ 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
index 0000000..5fc6a07
--- /dev/null
+++ b/sim/ppc/ChangeLog
@@ -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
index 0000000..8c5865e
--- /dev/null
+++ b/sim/ppc/Makefile.in
@@ -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
index 0000000..c76c023
--- /dev/null
+++ b/sim/ppc/README.psim
@@ -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
index 0000000..e3889b4
--- /dev/null
+++ b/sim/ppc/bits.h
@@ -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
index 0000000..4cd6559
--- /dev/null
+++ b/sim/ppc/configure.in
@@ -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
index 0000000..5e8479f
--- /dev/null
+++ b/sim/ppc/core.c
@@ -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
index 0000000..5d7837a
--- /dev/null
+++ b/sim/ppc/core.h
@@ -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
index 0000000..3478320
--- /dev/null
+++ b/sim/ppc/device_tree.c
@@ -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
index 0000000..59d764e
--- /dev/null
+++ b/sim/ppc/device_tree.h
@@ -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
index 0000000..96b8109
--- /dev/null
+++ b/sim/ppc/devices.c
@@ -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
index 0000000..e115779
--- /dev/null
+++ b/sim/ppc/devices.h
@@ -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
index 0000000..8594301
--- /dev/null
+++ b/sim/ppc/double.c
@@ -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
index 0000000..3313132
--- /dev/null
+++ b/sim/ppc/dp-bit.c
@@ -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
index 0000000..4b26a6a
--- /dev/null
+++ b/sim/ppc/events.c
@@ -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
index 0000000..fc81263
--- /dev/null
+++ b/sim/ppc/events.h
@@ -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
index 0000000..e6e5c16
--- /dev/null
+++ b/sim/ppc/gen.c
@@ -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
index 0000000..ecae98e
--- /dev/null
+++ b/sim/ppc/idecode_branch.h
@@ -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
index 0000000..8d65b17
--- /dev/null
+++ b/sim/ppc/idecode_fields.h
@@ -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
index 0000000..4e56b78
--- /dev/null
+++ b/sim/ppc/idecode_insn.h
@@ -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
index 0000000..af97006
--- /dev/null
+++ b/sim/ppc/memory_map.c
@@ -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
index 0000000..c197f43
--- /dev/null
+++ b/sim/ppc/memory_map.h
@@ -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
index 0000000..0158116
--- /dev/null
+++ b/sim/ppc/ppc-endian.c
@@ -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
index 0000000..6ac0601
--- /dev/null
+++ b/sim/ppc/ppc-endian.h
@@ -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
index 0000000..ef3ea68
--- /dev/null
+++ b/sim/ppc/ppc.mt
@@ -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
index 0000000..a8ee960
--- /dev/null
+++ b/sim/ppc/sim_callbacks.h
@@ -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
index 0000000..ca62b27
--- /dev/null
+++ b/sim/ppc/system.c
@@ -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
index 0000000..4a0df87
--- /dev/null
+++ b/sim/ppc/system.h
@@ -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
index 0000000..335b0bc
--- /dev/null
+++ b/sim/ppc/vm.h
@@ -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
index 0000000..35bdadd
--- /dev/null
+++ b/sim/ppc/words.h
@@ -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_ */