From 8e4d5e5f4017f3e330285fd13144163e5d2099fd Mon Sep 17 00:00:00 2001 From: cebix <> Date: Mon, 4 Feb 2002 16:58:13 +0000 Subject: [PATCH] Imported sources --- SheepShaver/COPYING | 340 +++ SheepShaver/Makefile | 60 + SheepShaver/doc/BeOS/acknowledgements.html | 24 + SheepShaver/doc/BeOS/contact.html | 47 + SheepShaver/doc/BeOS/graphics.gif | Bin 0 -> 8854 bytes SheepShaver/doc/BeOS/history.html | 59 + SheepShaver/doc/BeOS/icon.gif | Bin 0 -> 2011 bytes SheepShaver/doc/BeOS/iconsmall.gif | Bin 0 -> 1297 bytes SheepShaver/doc/BeOS/index.html | 28 + SheepShaver/doc/BeOS/installation.html | 25 + SheepShaver/doc/BeOS/introduction.html | 45 + SheepShaver/doc/BeOS/memory.gif | Bin 0 -> 5510 bytes SheepShaver/doc/BeOS/quickstart.html | 38 + SheepShaver/doc/BeOS/serial.gif | Bin 0 -> 4844 bytes SheepShaver/doc/BeOS/settings.html | 127 + SheepShaver/doc/BeOS/troubleshooting.html | 79 + SheepShaver/doc/BeOS/using.html | 76 + SheepShaver/doc/BeOS/volumes.gif | Bin 0 -> 7456 bytes SheepShaver/doc/Linux/acknowledgements.html | 24 + SheepShaver/doc/Linux/contact.html | 47 + SheepShaver/doc/Linux/graphics.gif | Bin 0 -> 5480 bytes SheepShaver/doc/Linux/history.html | 25 + SheepShaver/doc/Linux/icon.gif | Bin 0 -> 2011 bytes SheepShaver/doc/Linux/iconsmall.gif | Bin 0 -> 1297 bytes SheepShaver/doc/Linux/index.html | 28 + SheepShaver/doc/Linux/installation.html | 25 + SheepShaver/doc/Linux/introduction.html | 44 + SheepShaver/doc/Linux/memory.gif | Bin 0 -> 5697 bytes SheepShaver/doc/Linux/quickstart.html | 39 + SheepShaver/doc/Linux/serial.gif | Bin 0 -> 5325 bytes SheepShaver/doc/Linux/settings.html | 117 + SheepShaver/doc/Linux/troubleshooting.html | 65 + SheepShaver/doc/Linux/using.html | 113 + SheepShaver/doc/Linux/volumes.gif | Bin 0 -> 7705 bytes .../src/BeOS/CreatePCIDrivers/Ethernet.cpp | 255 ++ .../src/BeOS/CreatePCIDrivers/Makefile | 25 + .../src/BeOS/CreatePCIDrivers/Video.cpp | 78 + .../src/BeOS/CreatePCIDrivers/hexconv.cpp | 34 + SheepShaver/src/BeOS/Makefile | 117 + SheepShaver/src/BeOS/NetPeek/Makefile | 110 + SheepShaver/src/BeOS/NetPeek/NetPeek.cpp | 49 + SheepShaver/src/BeOS/SaveROM/Makefile | 110 + SheepShaver/src/BeOS/SaveROM/README | 8 + SheepShaver/src/BeOS/SaveROM/SaveROM.cpp | 128 + SheepShaver/src/BeOS/SaveROM/SaveROM.rsrc | Bin 0 -> 4323 bytes SheepShaver/src/BeOS/SheepShaver.rsrc | Bin 0 -> 4247 bytes SheepShaver/src/BeOS/about_window_beos.cpp | 289 +++ SheepShaver/src/BeOS/clip_beos.cpp | 366 +++ SheepShaver/src/BeOS/ether_beos.cpp | 398 +++ SheepShaver/src/BeOS/main_beos.cpp | 2185 +++++++++++++++++ SheepShaver/src/BeOS/prefs_beos.cpp | 112 + SheepShaver/src/BeOS/prefs_editor_beos.cpp | 877 +++++++ SheepShaver/src/BeOS/sysdeps.h | 55 + SheepShaver/src/BeOS/user_strings_beos.cpp | 69 + SheepShaver/src/BeOS/user_strings_beos.h | 34 + SheepShaver/src/BeOS/video_beos.cpp | 768 ++++++ SheepShaver/src/BeOS/video_screen.h | 262 ++ SheepShaver/src/BeOS/video_window.h | 523 ++++ SheepShaver/src/EthernetDriverStub.i | 43 + SheepShaver/src/Unix/Linux/asm_linux.S | 888 +++++++ SheepShaver/src/Unix/Linux/ether_linux.cpp | 396 +++ SheepShaver/src/Unix/Linux/paranoia.cpp | 168 ++ SheepShaver/src/Unix/Linux/sheepthreads.c | 251 ++ SheepShaver/src/Unix/Makefile.in | 96 + SheepShaver/src/Unix/SheepShaver.1 | 29 + SheepShaver/src/Unix/about_window_unix.cpp | 30 + SheepShaver/src/Unix/acconfig.h | 39 + SheepShaver/src/Unix/autogen.sh | 36 + SheepShaver/src/Unix/clip_unix.cpp | 124 + SheepShaver/src/Unix/configure.in | 180 ++ SheepShaver/src/Unix/install-sh | 238 ++ SheepShaver/src/Unix/main_unix.cpp | 1805 ++++++++++++++ SheepShaver/src/Unix/mkinstalldirs | 40 + SheepShaver/src/Unix/ppc_asm.tmpl | 66 + SheepShaver/src/Unix/prefs_editor_gtk.cpp | 859 +++++++ SheepShaver/src/Unix/prefs_unix.cpp | 97 + SheepShaver/src/Unix/sysdeps.h | 136 + SheepShaver/src/Unix/user_strings_unix.cpp | 92 + SheepShaver/src/Unix/user_strings_unix.h | 58 + SheepShaver/src/Unix/video_x.cpp | 1419 +++++++++++ SheepShaver/src/VideoDriverStub.i | 24 + SheepShaver/src/emul_op.cpp | 477 ++++ SheepShaver/src/emul_ppc/emul_ppc.cpp | 1661 +++++++++++++ SheepShaver/src/ether.cpp | 1632 ++++++++++++ SheepShaver/src/include/about_window.h | 26 + SheepShaver/src/include/cpu_emulation.h | 73 + SheepShaver/src/include/emul_op.h | 108 + SheepShaver/src/include/ether.h | 70 + SheepShaver/src/include/ether_defs.h | 444 ++++ SheepShaver/src/include/macos_util.h | 379 +++ SheepShaver/src/include/main.h | 76 + SheepShaver/src/include/name_registry.h | 26 + SheepShaver/src/include/prefs_editor.h | 30 + SheepShaver/src/include/rom_patches.h | 40 + SheepShaver/src/include/rsrc_patches.h | 27 + SheepShaver/src/include/user_strings.h | 161 ++ SheepShaver/src/include/version.h | 27 + SheepShaver/src/include/video.h | 113 + SheepShaver/src/include/video_defs.h | 381 +++ SheepShaver/src/include/xlowmem.h | 58 + SheepShaver/src/macos_util.cpp | 306 +++ SheepShaver/src/name_registry.cpp | 290 +++ SheepShaver/src/prefs_items.cpp | 75 + SheepShaver/src/rom_patches.cpp | 2087 ++++++++++++++++ SheepShaver/src/rsrc_patches.cpp | 751 ++++++ SheepShaver/src/serial.cpp | 308 +++ SheepShaver/src/timer.cpp | 432 ++++ SheepShaver/src/user_strings.cpp | 154 ++ SheepShaver/src/video.cpp | 963 ++++++++ 109 files changed, 26616 insertions(+) create mode 100644 SheepShaver/COPYING create mode 100644 SheepShaver/Makefile create mode 100644 SheepShaver/doc/BeOS/acknowledgements.html create mode 100644 SheepShaver/doc/BeOS/contact.html create mode 100644 SheepShaver/doc/BeOS/graphics.gif create mode 100644 SheepShaver/doc/BeOS/history.html create mode 100644 SheepShaver/doc/BeOS/icon.gif create mode 100644 SheepShaver/doc/BeOS/iconsmall.gif create mode 100644 SheepShaver/doc/BeOS/index.html create mode 100644 SheepShaver/doc/BeOS/installation.html create mode 100644 SheepShaver/doc/BeOS/introduction.html create mode 100644 SheepShaver/doc/BeOS/memory.gif create mode 100644 SheepShaver/doc/BeOS/quickstart.html create mode 100644 SheepShaver/doc/BeOS/serial.gif create mode 100644 SheepShaver/doc/BeOS/settings.html create mode 100644 SheepShaver/doc/BeOS/troubleshooting.html create mode 100644 SheepShaver/doc/BeOS/using.html create mode 100644 SheepShaver/doc/BeOS/volumes.gif create mode 100644 SheepShaver/doc/Linux/acknowledgements.html create mode 100644 SheepShaver/doc/Linux/contact.html create mode 100644 SheepShaver/doc/Linux/graphics.gif create mode 100644 SheepShaver/doc/Linux/history.html create mode 100644 SheepShaver/doc/Linux/icon.gif create mode 100644 SheepShaver/doc/Linux/iconsmall.gif create mode 100644 SheepShaver/doc/Linux/index.html create mode 100644 SheepShaver/doc/Linux/installation.html create mode 100644 SheepShaver/doc/Linux/introduction.html create mode 100644 SheepShaver/doc/Linux/memory.gif create mode 100644 SheepShaver/doc/Linux/quickstart.html create mode 100644 SheepShaver/doc/Linux/serial.gif create mode 100644 SheepShaver/doc/Linux/settings.html create mode 100644 SheepShaver/doc/Linux/troubleshooting.html create mode 100644 SheepShaver/doc/Linux/using.html create mode 100644 SheepShaver/doc/Linux/volumes.gif create mode 100644 SheepShaver/src/BeOS/CreatePCIDrivers/Ethernet.cpp create mode 100644 SheepShaver/src/BeOS/CreatePCIDrivers/Makefile create mode 100644 SheepShaver/src/BeOS/CreatePCIDrivers/Video.cpp create mode 100644 SheepShaver/src/BeOS/CreatePCIDrivers/hexconv.cpp create mode 100644 SheepShaver/src/BeOS/Makefile create mode 100644 SheepShaver/src/BeOS/NetPeek/Makefile create mode 100644 SheepShaver/src/BeOS/NetPeek/NetPeek.cpp create mode 100644 SheepShaver/src/BeOS/SaveROM/Makefile create mode 100644 SheepShaver/src/BeOS/SaveROM/README create mode 100644 SheepShaver/src/BeOS/SaveROM/SaveROM.cpp create mode 100644 SheepShaver/src/BeOS/SaveROM/SaveROM.rsrc create mode 100644 SheepShaver/src/BeOS/SheepShaver.rsrc create mode 100644 SheepShaver/src/BeOS/about_window_beos.cpp create mode 100644 SheepShaver/src/BeOS/clip_beos.cpp create mode 100644 SheepShaver/src/BeOS/ether_beos.cpp create mode 100644 SheepShaver/src/BeOS/main_beos.cpp create mode 100644 SheepShaver/src/BeOS/prefs_beos.cpp create mode 100644 SheepShaver/src/BeOS/prefs_editor_beos.cpp create mode 100644 SheepShaver/src/BeOS/sysdeps.h create mode 100644 SheepShaver/src/BeOS/user_strings_beos.cpp create mode 100644 SheepShaver/src/BeOS/user_strings_beos.h create mode 100644 SheepShaver/src/BeOS/video_beos.cpp create mode 100644 SheepShaver/src/BeOS/video_screen.h create mode 100644 SheepShaver/src/BeOS/video_window.h create mode 100644 SheepShaver/src/EthernetDriverStub.i create mode 100644 SheepShaver/src/Unix/Linux/asm_linux.S create mode 100644 SheepShaver/src/Unix/Linux/ether_linux.cpp create mode 100644 SheepShaver/src/Unix/Linux/paranoia.cpp create mode 100644 SheepShaver/src/Unix/Linux/sheepthreads.c create mode 100644 SheepShaver/src/Unix/Makefile.in create mode 100644 SheepShaver/src/Unix/SheepShaver.1 create mode 100644 SheepShaver/src/Unix/about_window_unix.cpp create mode 100644 SheepShaver/src/Unix/acconfig.h create mode 100755 SheepShaver/src/Unix/autogen.sh create mode 100644 SheepShaver/src/Unix/clip_unix.cpp create mode 100644 SheepShaver/src/Unix/configure.in create mode 100755 SheepShaver/src/Unix/install-sh create mode 100644 SheepShaver/src/Unix/main_unix.cpp create mode 100755 SheepShaver/src/Unix/mkinstalldirs create mode 100644 SheepShaver/src/Unix/ppc_asm.tmpl create mode 100644 SheepShaver/src/Unix/prefs_editor_gtk.cpp create mode 100644 SheepShaver/src/Unix/prefs_unix.cpp create mode 100644 SheepShaver/src/Unix/sysdeps.h create mode 100644 SheepShaver/src/Unix/user_strings_unix.cpp create mode 100644 SheepShaver/src/Unix/user_strings_unix.h create mode 100644 SheepShaver/src/Unix/video_x.cpp create mode 100644 SheepShaver/src/VideoDriverStub.i create mode 100644 SheepShaver/src/emul_op.cpp create mode 100644 SheepShaver/src/emul_ppc/emul_ppc.cpp create mode 100644 SheepShaver/src/ether.cpp create mode 100644 SheepShaver/src/include/about_window.h create mode 100644 SheepShaver/src/include/cpu_emulation.h create mode 100644 SheepShaver/src/include/emul_op.h create mode 100644 SheepShaver/src/include/ether.h create mode 100644 SheepShaver/src/include/ether_defs.h create mode 100644 SheepShaver/src/include/macos_util.h create mode 100644 SheepShaver/src/include/main.h create mode 100644 SheepShaver/src/include/name_registry.h create mode 100644 SheepShaver/src/include/prefs_editor.h create mode 100644 SheepShaver/src/include/rom_patches.h create mode 100644 SheepShaver/src/include/rsrc_patches.h create mode 100644 SheepShaver/src/include/user_strings.h create mode 100644 SheepShaver/src/include/version.h create mode 100644 SheepShaver/src/include/video.h create mode 100644 SheepShaver/src/include/video_defs.h create mode 100644 SheepShaver/src/include/xlowmem.h create mode 100644 SheepShaver/src/macos_util.cpp create mode 100644 SheepShaver/src/name_registry.cpp create mode 100644 SheepShaver/src/prefs_items.cpp create mode 100644 SheepShaver/src/rom_patches.cpp create mode 100644 SheepShaver/src/rsrc_patches.cpp create mode 100644 SheepShaver/src/serial.cpp create mode 100644 SheepShaver/src/timer.cpp create mode 100644 SheepShaver/src/user_strings.cpp create mode 100644 SheepShaver/src/video.cpp diff --git a/SheepShaver/COPYING b/SheepShaver/COPYING new file mode 100644 index 00000000..60549be5 --- /dev/null +++ b/SheepShaver/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 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/SheepShaver/Makefile b/SheepShaver/Makefile new file mode 100644 index 00000000..86c5e5a5 --- /dev/null +++ b/SheepShaver/Makefile @@ -0,0 +1,60 @@ +# Makefile for creating SheepShaver distributions +# Written in 1999 by Christian Bauer + +VERSION := 2 +RELEASE := 2 +VERNAME := SheepShaver-$(VERSION) + +SRCARCHIVE := $(shell date +SheepShaver_src_%d%m%Y.tar.gz) + +TMPDIR := $(shell date +/tmp/build%m%s) +DOCS := HISTORY LOG TODO +SRCS := src + +default: help + +help: + @echo "This top-level Makefile is for creating SheepShaver distributions." + @echo "The following targets are available:" + @echo " tarball source tarball ($(SRCARCHIVE))" + @echo " links create links to Basilisk II sources" + +clean: + -rm -f $(SRCARCHIVE) + +# +# Source tarball +# +tarball: $(SRCARCHIVE) + +$(SRCARCHIVE): $(SRCS) $(DOCS) + -rm -rf $(TMPDIR) + mkdir $(TMPDIR) + cd $(TMPDIR); cvs export -D "$(ISODATE)" SheepShaver + rm $(TMPDIR)/SheepShaver/Makefile + mv $(TMPDIR)/SheepShaver $(TMPDIR)/$(VERNAME) + cd $(TMPDIR); tar cfz $@ $(VERNAME) + mv $(TMPDIR)/$@ . + rm -rf $(TMPDIR) + +# +# Links to Basilisk II sources +# +links: + @list='adb.cpp audio.cpp cdrom.cpp disk.cpp extfs.cpp prefs.cpp \ + scsi.cpp sony.cpp xpram.cpp \ + include/adb.h include/audio.h include/audio_defs.h \ + include/cdrom.h include/clip.h include/debug.h include/disk.h \ + include/extfs.h include/extfs_defs.h include/prefs.h \ + include/scsi.h include/serial.h include/serial_defs.h \ + include/sony.h include/sys.h include/timer.h include/xpram.h \ + BeOS/audio_beos.cpp BeOS/extfs_beos.cpp BeOS/scsi_beos.cpp \ + BeOS/serial_beos.cpp BeOS/sys_beos.cpp BeOS/timer_beos.cpp \ + BeOS/xpram_beos.cpp BeOS/SheepDriver BeOS/SheepNet \ + Unix/audio_oss_esd.cpp Unix/extfs_unix.cpp Unix/serial_unix.cpp \ + Unix/sys_unix.cpp Unix/timer_unix.cpp Unix/xpram_unix.cpp \ + Unix/Linux/scsi_linux.cpp Unix/Linux/NetDriver'; \ + for i in $$list; do \ + echo $$i; \ + ln -sf `pwd`/../BasiliskII/src/$$i src/$$i; \ + done; diff --git a/SheepShaver/doc/BeOS/acknowledgements.html b/SheepShaver/doc/BeOS/acknowledgements.html new file mode 100644 index 00000000..204e8d20 --- /dev/null +++ b/SheepShaver/doc/BeOS/acknowledgements.html @@ -0,0 +1,24 @@ + + +Acknowledgements + + + +

Acknowledgements

+ +The following persons/companies deserve special thanks from us as they +made a significant contribution to the development of SheepShaver: + +

+

+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/contact.html b/SheepShaver/doc/BeOS/contact.html new file mode 100644 index 00000000..f29ef2dd --- /dev/null +++ b/SheepShaver/doc/BeOS/contact.html @@ -0,0 +1,47 @@ + + +Contact Information + + + +

Contact Information and Copyright

+ +SheepShaver was brought to you by + + +

SheepShaver WWW Site:

+
+www.sheepshaver.com
+
+ +

EMail:

+
+Christian.Bauer@uni-mainz.de
+
+ +

License

+ +

SheepShaver is available under the terms of the GNU General Public License. +See the file "COPYING" that is included in the distribution for details. + +

© Copyright 1997-2002 Christian Bauer and Marc Hellwig + +

Names of hardware and software items mentioned in this manual and +in program texts are in most cases registered trade marks of the respective +companies and not marked as such. So the lack of such a note may not be +used as an indication that these names are free. + +

SheepShaver is not designed, intended, or authorized for use as a component +in systems intended for surgical implant within the body, or other applications intended +to support or sustain life, or for any other application in which the failure of SheepShaver +could create a situation where personal injury or death may occur (so-called "killer application"). + +


+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/graphics.gif b/SheepShaver/doc/BeOS/graphics.gif new file mode 100644 index 0000000000000000000000000000000000000000..10a33553808ea9b69dd054448f4fe53f5cb227ee GIT binary patch literal 8854 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 literal 0 HcmV?d00001 diff --git a/SheepShaver/doc/BeOS/history.html b/SheepShaver/doc/BeOS/history.html new file mode 100644 index 00000000..8d016a73 --- /dev/null +++ b/SheepShaver/doc/BeOS/history.html @@ -0,0 +1,59 @@ + + +Revision History + + + +

SheepShaver Revision History

+ +

V2.2 (04-Feb-2002)

+
    +
  • Integrated code from Basilisk II +
  • Source released under GPL +
+ +

V2.1 (31-Mar-2001)

+
    +
  • Support for MacOS 8.5 and 8.6 +
  • Support for G3 ROMs +
  • It's possible to select which video modes are to be used by MacOS +
  • SheepShaver will not use up all CPU time when "nothing" is running +
  • More stable networking +
  • 16 and 32 bit window modes +
  • Small bug fixes +
+ +

V2.0 (20-Jan-1999)

+
    +
  • "BeOS" icon on the Mac desktop to access files on BeOS volumes from Mac applications. +
  • Handling of removable media (i.e. automatic detection of disk insertion) +
  • More flexible parallel port selection on BeBox +
  • Greatly improved Time Manager (higher accuracy) +
  • Fixed "audio lags" +
  • Option to ignore illegal memory accesses +
  • Adapted for (and requires) BeOS R4 +
  • MacOS 7.5.5/7.6/7.6.1 run better on some systems +
  • Small bug fixes +
+ +

V1.1 (13-Jul-1998)

+
    +
  • Support for more machine types (esp. PowerMac 4400) +
  • Corrected time zone handling +
  • Volume list in preferences handles dropped volumes and files +
  • BeBox: 16/24 bit modes have correct colors with a Millennium II +
  • Video/SetEntries didn't set last palette entry +
  • Mac programs trying to use the (non-existant) SCSI Manager shouldn't crash any longer +
+ +

V1.0 (18-May-1998)

+
    +
  • Initial release +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/icon.gif b/SheepShaver/doc/BeOS/icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..51368b117dcc38bde6f0ac4457387bad5fd31efa GIT binary patch literal 2011 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 Kyw<#mUj7$_>qdM4 literal 0 HcmV?d00001 diff --git a/SheepShaver/doc/BeOS/index.html b/SheepShaver/doc/BeOS/index.html new file mode 100644 index 00000000..52328333 --- /dev/null +++ b/SheepShaver/doc/BeOS/index.html @@ -0,0 +1,28 @@ + + +The SheepShaver User's Guide + + + +

SheepShaver V2.2 Installation and User's Guide (BeOS)

+ +

Contents

+ + + +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/installation.html b/SheepShaver/doc/BeOS/installation.html new file mode 100644 index 00000000..105d9c8f --- /dev/null +++ b/SheepShaver/doc/BeOS/installation.html @@ -0,0 +1,25 @@ + + +Installation + + + +

Installation

+ +You need BeOS/PowerPC R4. R3 or earlier versions will not work. + +
    +
  1. Unpack the SheepShaver package (if you are reading this, you probably have already done this) +
  2. On a BeBox, you need a copy of a PCI PowerMac ROM (4MB) in a file +called "ROM" in the same folder SheepShaver is in (but you can select a different +location in the settings window). SheepShaver can also use the "Mac OS ROM" file +that comes with MacOS 8.5/8.6 (look in the System Folder on your MacOS CD). In +order to legally use SheepShaver, you have to own the ROM the image file was taken from. +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/introduction.html b/SheepShaver/doc/BeOS/introduction.html new file mode 100644 index 00000000..f3356787 --- /dev/null +++ b/SheepShaver/doc/BeOS/introduction.html @@ -0,0 +1,45 @@ + + +Introduction + + + +

Introduction

+ +SheepShaver is a MacOS run-time environment for BeOS that allows you +to run MacOS applications at native speed inside the BeOS multitasking +environment on PowerPC-based BeOS systems. This means that both BeOS +and MacOS applications can run at the same time and data can be exchanged +between them. + +

SheepShaver is neither a MacOS replacement nor an emulator. It runs an +unmodified PowerPC MacOS under control of the BeOS at full speed without +any kind of emulation. So it also uses the MacOS 68k emulator to run 68k +applications. In this way, SheepShaver is comparable to the "Blue Box" of +Apple's Rhapsody operating system. + +

Some of SheepShaver's features:

+ +
    +
  • Compatibility: SheepShaver runs MacOS 7.5.2 thru 8.6 with all system + extensions like AppleGuide, AppleScript, QuickTime, QuickTime VR, + QuickDraw 3D, Open Transport, PPP, Language Kits, ColorSync, etc. +
  • Graphics: The MacOS user interface is displayed in a BeOS window or + full-screen (with QuickDraw acceleration) in resolutions up to + 1600x1200 in 24 bit. +
  • Sound: CD-quality stereo sound output +
  • Networking: SheepShaver supports Internet and LAN networking via + Ethernet and PPP with all Open Transport compatible MacOS applications. +
  • Volumes: Any HFS or HFS+ volume can be used with SheepShaver (this + includes Zip/Jaz/SyQuest drives etc.). It also features a built-in + CD-ROM driver and a driver for HD floppy disks. +
  • Data Exchange: You can access BeOS files from the MacOS via a "BeOS" + icon on the Mac desktop and copy and paste text between BeOS and MacOS +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/memory.gif b/SheepShaver/doc/BeOS/memory.gif new file mode 100644 index 0000000000000000000000000000000000000000..9867b003e7f6922b967f969903d0154343e986f2 GIT binary patch literal 5510 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 I^&tQNJBtH3EC2ui literal 0 HcmV?d00001 diff --git a/SheepShaver/doc/BeOS/quickstart.html b/SheepShaver/doc/BeOS/quickstart.html new file mode 100644 index 00000000..62f9be15 --- /dev/null +++ b/SheepShaver/doc/BeOS/quickstart.html @@ -0,0 +1,38 @@ + + +Quick Start + + + +

Quick Start

+ +The following is a step-by-step guide that shows you how to get SheepShaver +up and running in the quickest possible way. We assume that you are running +on a PowerMac that already has MacOS installed on a partition of your hard drive +and that you have booted into BeOS. + +

+

    +
  1. Double-click the SheepShaver icon. The "SheepShaver Settings" window will appear. +
  2. Click on "Start". SheepShaver will try to detect on which partition MacOS is installed and should then start booting MacOS. +
  3. If this is the first time you start SheepShaver you will be asked if you want your +network configuration to be modified to enable Ethernet networking under SheepShaver. +If you want to use Ethernet with SheepShaver you should press "OK" (this will change the +file /boot/home/config/settings/network; a backup of the the original file will +be stored in network.orig). +
  4. To quit SheepShaver, select "Shutdown" from the Finder's "Special" menu. +
+ +

One word of caution:

+ +Volumes which are used by SheepShaver must not also be mounted under BeOS +while SheepShaver is running. You will lose data and corrupt the +volume if you do this! Don't press the "Mount all disks now" button in the +BeOS "Disk Mount Settings" window while SheepShaver is running! + +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/serial.gif b/SheepShaver/doc/BeOS/serial.gif new file mode 100644 index 0000000000000000000000000000000000000000..b491d769dea310cfd695607bf91ca7b1749fd6cf GIT binary patch literal 4844 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 Sec70u*_yrCoISlE0029JP30i~ literal 0 HcmV?d00001 diff --git a/SheepShaver/doc/BeOS/settings.html b/SheepShaver/doc/BeOS/settings.html new file mode 100644 index 00000000..7c05c2a9 --- /dev/null +++ b/SheepShaver/doc/BeOS/settings.html @@ -0,0 +1,127 @@ + + +Setting up SheepShaver + + + +

Setting up SheepShaver

+ +In the "SheepShaver Settings" window that pops up when you double-click on +the SheepShaver icon, you can configure certain features of SheepShaver. +When you click on "Start", the current settings are saved to disk and will be +available next time you start SheepShaver. + +

The settings are divided into four groups: Volumes, Graphics/Sound, Serial/Network and Memory/Misc. + +

Volumes

+ + + +

The main part of the volumes pane is a list that contains all volumes to be mounted +by SheepShaver. If this list is empty, SheepShaver will try to detect and mount all HFS partitions +it can find. CD-ROM drives are always automatically detected and used. + +

SheepShaver can use HFS partitions, whole HFS formatted drives, and it can also +emulate hard disks in single BeOS files ("hardfiles"). + +

To add a Mac volume to the list, mount it on the BeOS side, click on "Add...", go to the "Disks" +level in the topmost popup menu of the file panel, click once on the volume you want and +click on "Add". A line beginning with "/dev/disk/" should then appear in the volume list. +After adding volumes to the list, you should unmount them on the BeOS side again.To remove +a Mac volume, select it in the list and click on "Remove". + +

You can create a new, empty hardfile by clicking on "Create...". Enter the file +name and the size of the hardfile and click on "Create". The hardfile will be created (this may +take some seconds) and added to the volume list. The so-created hardfile will have to be +formatted under MacOS before you can store something in it. If you start up SheepShaver, +the Finder will display a message about an "unreadable" volume being found and give you the +option to format it. + +

Double-clicking on an entry in the volume list will add or remove a "*" in front of the +device name. Volumes marked with a "*" are read-only for the MacOS under SheepShaver. + +

SheepShaver will show a "BeOS" disk icon on the Mac desktop that allows access to BeOS +files from Mac applications. In "BeOS Root" you specify which BeOS directory will +be at the root of this virtual "BeOS" disk. You can enter a path name here or drag and drop a +Tracker folder onto it. The default setting of "/boot" means that the "BeOS" icon in the MacOS +Finder will correspond to your BeOS boot volume. If you want to access files on other BeOS +volumes, you should enter "/" here. The "BeOS" disk will then contain folders for each BeOS +volume (among other things). The MacOS will create files and folders like "Desktop", "Trash", +"OpenFolderListDF" etc. in the directory you specify as "BeOS Root". If they annoy you, you +can delete them. + +

To boot from CD-ROM, set the "Boot From" setting to "CD-ROM". +The "Disable CD-ROM Driver" box is used to disable SheepShaver's built-in CD-ROM driver. +This is currently of not much use and you should leave the box unselected. + +

Graphics/Sound

+ + + +

WIth "Window Refresh Rate" you can set the refresh rate of the MacOS window. +Higher rates mean faster screen updates and less "sluggish" behaviour, but also require more CPU time. + +

The "QuickDraw Acceleration" box should always be enabled. It allows for faster graphics in +full-screen modes. But if your machine uses the "IXMicro" BeOS video driver, you have to disable the +QuickDraw acceleration or full-screen modes won't work (this is because of BeOS bug #981112-032247). + +

The main part of the window is occupied by a list of checkboxes that allows you to select +which graphics modes are available for displaying the MacOS desktop. You can, for +example, disable the modes that your monitor or graphics card can't display, or disable the +window modes when you want to run some Mac programs in full-screen mode that would otherwise +erroneously switch to a window mode. The actual mode to be used is selected in the "Monitors" +control panel under MacOS. + +

The "Disable Sound Output" box allows you to disable all sound output by SheepShaver. +This is useful if the sound takes too much CPU time on your machine or to get rid of warning +messages if SheepShaver can't use your audio hardware. + +

Serial/Network

+ + + +

You can select to which ports the MacOS modem and printer ports are redirected. +This doesn't make much sense on a PowerMac, but on a BeBox you can assign the modem +and printer ports to any of the four serial ports (or com3/com4) or even parallel ports of +the BeBox (useful for printing if you have Mac drivers for parallel printers, like the PowerPrint +package from www.gdt.com). + +

If you don't want SheepShaver's Ethernet support to be enabled for some reason, you +can use the "Disable Ethernet" checkbox to disable it (this will also get rid of the annoying +"no network hardware" messages if your Mac is not equipped with Ethernet). + +

Memory/Misc

+ + + +

With "MacOS RAM Size" you select how much RAM will be available to the MacOS +(and all MacOS applications running under it). SheepShaver uses the BeOS virtual memory system, +so you can select more RAM than you physically have in your machine. The MacOS virtual memory +system is not available under SheepShaver (i.e. if you have 32MB of RAM in your computer and +select 64MB to be used for MacOS in the SheepShaver settings, MacOS will behave as if it's running on +a computer that has 64MB of RAM but no virtual memory). + +

The "Ignore Illegal Memory Accesses" option is there to make some broken Mac +programs work that access addresses where there is no RAM or ROM. With this option unchecked, +SheepShaver will in this case display an error message and quit. When the option is activated, +SheepShaver will try to continue as if the illegal access never happened (writes are ignored, reads +return 0). This may or may not make the program work (when a program performs an illegal access, +it is most likely that something else went wrong). When a Mac program behaves strangely or hangs, +you can quit SheepShaver, uncheck this option and retry. If you get an "illegal access" message, +you will know that something is broken. + +

If the "Don't Use CPU When Idle" option is enabled, SheepShaver will try to reduce +CPU usage to a minimum when the MacOS is doing "nothing" but waiting for user input. This doesn't +work with all programs and it may confuse the timing of some games but in general you should +leave it enabled. + +

"ROM File" specifies the path name of the Mac ROM file to be used. If it is left +blank, SheepShaver expects the ROM file to be called "ROM" and be in the same directory as +the SheepShaver application. + +


+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/troubleshooting.html b/SheepShaver/doc/BeOS/troubleshooting.html new file mode 100644 index 00000000..b46aa585 --- /dev/null +++ b/SheepShaver/doc/BeOS/troubleshooting.html @@ -0,0 +1,79 @@ + + +Troubleshooting + + + +

Troubleshooting

+ +

SheepShaver doesn't boot

+ +SheepShaver should boot all MacOS versions >=7.5.2, except MacOS X. However, +your mileage may vary. If it doesn't boot, try again with extensions disabled +(by pressing the shift key) and then remove some of these extensions: +"MacOS Licensing Extension", Speed Doubler, 68k FPU extensions and MacsBug. + +

The colors are wrong in 16 or 32 bit graphics modes

+ +If you're running SheepShaver on a BeBox, the only graphics modes that have +the right colors are the 8 bit modes (this is actually a hardware problem +and has to do with frame buffers being little-endian on the BeBox), unless +you are using a Matrox Milennium I/II. +

You should also be aware that not all graphics cards support 16 bit modes +under BeOS (especially S3 cards don't). Check the BeOS "Screen" preferences +application to see if your card does. + +

SheepShaver appears to be very slow

+ +
    +
  • Don't use the window modes, the fullscreen modes are much faster. +
  • If you nevertheless want (or have) to use a window mode, you should set the +color depth in MacOS to the same as the BeOS workspace you are running SheepShaver on +(e.g. if you are on a 16-bit workspace, set the color depth in MacOS to "Thousands"). +Also, set the window refresh rate to a low value (high values like 30Hz will make SheepShaver +(and BeOS) slower, not faster!). +
+ +

Full-screen mode doesn't work

+ +If your machine uses the "IXMicro" BeOS video driver (TwinTurbo cards), you +will have to disable the "QuickDraw Acceleration" in the "Video" pane of the +SheepShaver settings. + +

Ethernet doesn't work

+ +
    +
  • Is the Ethernet set up under BeOS? Ethernet will not work in SheepShaver if you didn't set it up in the BeOS "Network" preferences. +
  • If you're using TCP/IP on the MacOS side, you have to set up different IP addresses for the BeOS and for the MacOS. +
  • Try disabling AppleTalk in the BeOS Network preferences (there might be conflicts between BeOS AppleTalk and SheepShaver networking). +
+ +

SheepShaver crashes, but yesterday it worked

+ +Try the "Zap PRAM File" item in the main menu of the SheepShaver preferences editor. +When you are using a ROM file and switching to a different ROM version, you have +to zap the PRAM file or SheepShaver might behave very weird. + +

Known incompatibilities

+ +
    +
  • MacOS programs or drivers which access Mac hardware directly are not supported by SheepShaver. +
  • Speed Doubler, RAM Doubler, 68k FPU emulators and similar programs don't run under SheepShaver. +
  • MacsBug is not compatible with SheepShaver. +
  • If you want to run RealPC on a BeBox, you have to disable one CPU in the "Pulse" application or it will crash. +
+ +

Known bugs

+ +
    +
  • The QuickTime 2.5 Cinepak codec crashes the emulator. +
  • Programs that use InputSprockets crash the emulator when in window mode. +
  • The mouse cursor hotspot in window mode is not correct. +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/using.html b/SheepShaver/doc/BeOS/using.html new file mode 100644 index 00000000..8f9395bc --- /dev/null +++ b/SheepShaver/doc/BeOS/using.html @@ -0,0 +1,76 @@ + + +Using SheepShaver + + + +

Using SheepShaver

+ +

Changing the display mode

+ +SheepShaver can display the MacOS user interface in a BeOS window or full-screen +(much faster) in several resolutions and color depths. You select the display mode +as usual under MacOS in the "Monitors" control panel (under System 7.x, click on "Options"). +The "75Hz" modes are full-screen modes, the "60Hz" modes are window modes +(this doesn't mean that the video refresh rate is 75 or 60Hz in the respective modes; +the rate displayed has no meaning; it's simply there to distinguish full screen modes +from window modes). + +

Window mode

+ +The SheepShaver window has a menu at the bottom that allows you to change the +graphics refresh rate and to mount floppy disks (see below). The window refresh is +disabled as long as the "Scroll Lock" key is pressed (the graphics output is then frozen). + +

Full-screen mode

+ +The full-screen mode uses a whole BeOS workspace for displaying the MacOS user +interface. You can switch workspaces with Command-F1/F2/F3/etc. Please note that +the MacOS (and all MacOS applications) will be suspended when you switch to a different +workspace. It will only be resumed when you go back to the SheepShaver workspace. + +

Networking

+ +SheepShaver only supports Ethernet networking (and PPP via the serial +ports). If there are multiple Ethernet cards installed, only the first +card will be used. The Ethernet support is implemented at the data-link +level. This implies that the "Mac" and the "Be" side must have two different +network addresses. + +

Using floppy disks

+ +Floppy disks are not automatically detected when they are inserted. They have to be +mounted explicitly. After inserting a floppy disk, select the "Mount Floppy" item in the +"SheepShaver" menu (when running in window mode), or press Ctrl-F1 (when running in +full-screen mode). BeBox users should note that floppy disks also have to be unmounted +under MacOS before ejecting them from the drive. + +

Accessing BeOS files

+ +SheepShaver will display a "BeOS" disk icon on the Mac desktop that allows you +to access any BeOS files/folders which are in the directory specified as "BeOS Root" +in the "Volumes" pane of the SheepShaver settings. You can open and save files on the +"BeOS" disk from Mac applications, copy, move or rename files from the Finder etc. +Putting files/folder to the trash may however not always work. SheepShaver translates +some BeOS file types to MacOS types and vice versa, so e.g. JPEG and PDF files will +show up the correct icons in the Finder. To store Mac resources and other additional +data, SheepShaver uses the following BeOS file attributes: + +
    +
  • MACOS:RFORK contains the complete Mac resource fork of the file +
  • MACOS:HFS_FLAGS contains Finder flags +
  • MACOS:CREATOR contains the MacOS creator application ID +
+ +

Copying text via the clipboard

+ +SheepShaver tries to keep the BeOS and MacOS clipboards synchronized. That means, +when you copy a piece of text under BeOS, you can paste it into a MacOS application +and vice versa. + +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/BeOS/volumes.gif b/SheepShaver/doc/BeOS/volumes.gif new file mode 100644 index 0000000000000000000000000000000000000000..857dd0a21e5144e9ab9a4de2309c827b8c3193ed GIT binary patch literal 7456 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 literal 0 HcmV?d00001 diff --git a/SheepShaver/doc/Linux/acknowledgements.html b/SheepShaver/doc/Linux/acknowledgements.html new file mode 100644 index 00000000..5d8c9fd6 --- /dev/null +++ b/SheepShaver/doc/Linux/acknowledgements.html @@ -0,0 +1,24 @@ + + +Acknowledgements + + + +

Acknowledgements

+ +The following persons/companies deserve special thanks from us as they +made a significant contribution to the development of SheepShaver: + +

+

+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/contact.html b/SheepShaver/doc/Linux/contact.html new file mode 100644 index 00000000..3ccbf6a0 --- /dev/null +++ b/SheepShaver/doc/Linux/contact.html @@ -0,0 +1,47 @@ + + +Contact Information + + + +

Contact Information and Copyright

+ +SheepShaver was brought to you by + + +

SheepShaver WWW Site:

+
+www.sheepshaver.com
+
+ +

EMail:

+
+sheep@sheepshaver.com
+
+ +

License

+ +

SheepShaver is available under the terms of the GNU General Public License. +See the file "COPYING" that is included in the distribution for details. + +

© Copyright 1997-2002 Christian Bauer and Marc Hellwig + +

Names of hardware and software items mentioned in this manual and +in program texts are in most cases registered trade marks of the respective +companies and not marked as such. So the lack of such a note may not be +used as an indication that these names are free. + +

SheepShaver is not designed, intended, or authorized for use as a component +in systems intended for surgical implant within the body, or other applications intended +to support or sustain life, or for any other application in which the failure of SheepShaver +could create a situation where personal injury or death may occur (so-called "killer application"). + +


+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/graphics.gif b/SheepShaver/doc/Linux/graphics.gif new file mode 100644 index 0000000000000000000000000000000000000000..267a4f9e23bfbc42241480af5595afebb54cecb1 GIT binary patch literal 5480 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 Uze4t5g<^T-ZlVK + +Revision History + + + +

SheepShaver Revision History

+ +

V2.2 (04-Feb-2002)

+
    +
  • Integrated code from Basilisk II +
  • Source released under GPL +
+ +

V2.1 (31-Mar-2001)

+
    +
  • Initial Linux PPC release +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/icon.gif b/SheepShaver/doc/Linux/icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..51368b117dcc38bde6f0ac4457387bad5fd31efa GIT binary patch literal 2011 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 Kyw<#mUj7$_>qdM4 literal 0 HcmV?d00001 diff --git a/SheepShaver/doc/Linux/index.html b/SheepShaver/doc/Linux/index.html new file mode 100644 index 00000000..3fb408d0 --- /dev/null +++ b/SheepShaver/doc/Linux/index.html @@ -0,0 +1,28 @@ + + +The SheepShaver User's Guide + + + +

SheepShaver V2.2 Installation and User's Guide (Linux)

+ +

Contents

+ + + +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/installation.html b/SheepShaver/doc/Linux/installation.html new file mode 100644 index 00000000..75f588fc --- /dev/null +++ b/SheepShaver/doc/Linux/installation.html @@ -0,0 +1,25 @@ + + +Installation + + + +

Installation

+ +You need at least a 2.2.x kernel, glibc 2.1 and GTK+ 1.2. Earlier versions will not work. + +
    +
  1. Unpack the SheepShaver archive (if you are reading this, you probably have already done this) +
  2. Even when running on a PowerMac, you need a copy of a PCI PowerMac ROM (4MB) in +a file called "ROM" in the same folder SheepShaver is in (but you can select a different location +in the settings window). SheepShaver can also use the "Mac OS ROM" file that comes with +MacOS 8.5/8.6 (look in the System Folder on your MacOS CD). In order to legally use SheepShaver, +you have to own the ROM the image file was taken from. +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/introduction.html b/SheepShaver/doc/Linux/introduction.html new file mode 100644 index 00000000..42d78a4e --- /dev/null +++ b/SheepShaver/doc/Linux/introduction.html @@ -0,0 +1,44 @@ + + +Introduction + + + +

Introduction

+ +SheepShaver is a MacOS run-time environment for Linux that allows you +to run MacOS applications at native speed inside the Linux multitasking +environment on PowerPC-based Linux systems. This means that both Linux +and MacOS applications can run at the same time and data can be exchanged +between them. + +

SheepShaver is neither a MacOS replacement nor an emulator. It runs an +unmodified PowerPC MacOS under control of Linux at full speed without any +kind of emulation. So it also uses the MacOS 68k emulator to run 68k +applications. In this way, SheepShaver is comparable to the "Blue Box" of +Apple's Rhapsody operating system. + +

Some of SheepShaver's features:

+ +
    +
  • Compatibility: SheepShaver runs MacOS 7.5.2 thru 8.6 with all system + extensions like AppleGuide, AppleScript, QuickTime, QuickTime VR, + QuickDraw 3D, Open Transport, PPP, Language Kits, ColorSync, etc. +
  • Graphics: The MacOS user interface is displayed in an X11 window or + full-screen (requires DGA) +
  • Sound: CD-quality stereo sound output +
  • Networking: SheepShaver supports Internet and LAN networking via + Ethernet and PPP with all Open Transport compatible MacOS applications. +
  • Volumes: Any HFS or HFS+ volume can be used with SheepShaver (this + includes Zip/Jaz/SyQuest drives etc.). It also features a built-in + CD-ROM driver and a driver for HD floppy disks. +
  • Data Exchange: You can access Linux files from the MacOS via a "Linux" + icon on the Mac desktop and copy and paste text between Linux and MacOS +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/memory.gif b/SheepShaver/doc/Linux/memory.gif new file mode 100644 index 0000000000000000000000000000000000000000..f09a46076f5524ad6585b455fffd104826784efa GIT binary patch literal 5697 zcmajecRUn;|HpAjWkhA3z1JC;$5~~B>}(=*arUZg$v$M9v&oFJ!&!%uy~#Lx?<2~} zD(?IH{-5vf`FQ>Jc|6|#ebk<-N`q}OZ#}tnMnHi7e?ai~eDK2ne=sj^KX~{O|3*zwne8Pw3PkUegyX~zL~1_C?XO;$iO>(RFQT%{u=C%{#N;W z=F`wiZ2$4HUY-$P*-LW12k)Tr&M2VmSHea6kA$f zG2a04Kf3HC6CNzJI^JCzZ1}Y#OW@~&RxYSo?SxSYyc%k(Uhhrd)XdgG*K7`^i90O~ zp;6G`k9Q_W<JAaD)VcnlD*NusGVf6lqZ3`u1)oE!wT<=2& zSdFxxkGDq)G;?$?GVbFAw^Qq1Es&vuHdH+Dth%i&7st4XGOHjK*&W%v^}!t7Z>?8< z&I_BTDRO*Q{&tLo%moqLm9`H4PU6E5Oq^e2{op?BxpnB!KCfxez%yKi%ePrChRE7L zz#5FHV{7#ZwpKOkBf|&SsuSmF)k__YXrI?GmZFIK=+5eyMaSB7K!J<+63jeKa;bxZIJ+sJUza>GpQo>#6ex0Z&tA8J*?s(q|TY>fr+viY9W- z!^0wgj=8FpUi`(c%r7$$-RyJQ#Z^6c;E(cCdcTaaE+K{m$Fh^%A79(<3hY&N(K_u_ z_gy<~)(nAu?4d?g1@>#P#!mZnGj?VB^$T9j6_phA8C(8e$4i%zaO3troA$<`Wsd7d zCaxZ6%L|)02|s(c=D(+dt}e->r_AoVcfo6|^3eheX!PZegU*NXm%^2u!HkF90BHGA z*J0(XySK3scBGG1afaLF;8AB@GLzCko{wpM>6ci3&gX@RC3AgZgM4MDM->88d&PtD zYCu#{=4)_Ck5+2$VaL&jg%hlyiO}N2tKxnn*4TUh_jJ2W#rynrv-_vB_J0IGoixb( z(|NkD%Ggf*AAPdN*ipRavdzb8H0mcDqtk)(EZ z-jWQh1iw#xi@Dg&6_`e^UhI@-Dm1NC^uD_MQ8Vq@>`uL0+58jDsTM;Q zK6W&F5KE$~Jk<u%7uJNEjNXKdPdCG4mwBBR<`+hchRjtK(&SI%5?& zFYRmzdRO7ym>Y>4`R46Wxx*DYp6l}m(?R%yU;a9Ovn0OZ>GguXujdf1PFJ@H9Rz2- z{jOo|nL?V_EesgSy(`t%Uc1u$nC*TZu^MqlRV@*ZBz^l`RT0A4Vs2hp@PMvgNM&9c zj!%qBgThQnxnSiW0u)A0f%nMoWFdS6RM=yG5Ic@2I(NVQ@!^`Gf_ewg{4m<|MBSdP zFF=nXC&G~}R1#sI595Lu*jUcaLGnk3@z%$j zdre{NY@he!EasA<2)&px6?x%|GBh3oNnA#XKNH@G(I<(h^lOMA5yegh?WFbDM1&d% zwtuL&@@^08lcKOp;VhPm&rM`l5`__kBFV2b>VgOJ1eHjLXRyX$Xwi&%ZP`TDSr}#_*eN++;R7Q+ybf(SBVW@h zszn@cdBeot|6=gmkkjcwW{)HKr*)5OVJNiD7ceuM-S9rC&A*X1+x_7`=>1WrE)?b&aIp*rh|OE zto!YPtdrdQn?!cyXlmy!@e<8pzUk)5q>9kk0xJ`JtL_nU6!fjLanzB&*ckY{P){N=xMd|_DB=3>q$0JM)Izo0|w9O~;Ue@9)JEn7jx5T8M zVBya@&)`Wv^?VpUE4}-x*Zf}Pz5U=xcHwaG=uV->{5!NIvn_k=D_ighu&dA6V~WJQK546_Hx@$N**;09^~6)nI1u|8Td zEbA~sanJtwgqg5+)G>;J<%m?pkJUmRU$1(6)!mUooK0;P{3uJl+HhG0ays3^6Lhcw z$S1E6;>vjJbUe$#yJb)8y^_p!U9qFolh43rsju*_cIomh(2Gbf+#9c*NPcN02~enr z`!r)pJ^oDTE(vq!&>vNPVnc1ghu#EMKa!DJ`FY<*8Sq(heIf<&MpEU=K` zqL6BX5Mg^+5kP2-c&NmT49F)Gi3pXEmKB@{g?5ELJqIgEhh-RqshWb-)4~v_Fs(jm zo%678s&IX2X+zWSz_;P1K2qk5;qNEHU!8-j0TB-35pR4zc0LhShzQ3SNz=&)G6@HF zds$EE$eP;@6PzY^h^dz;n@_P>`jnZoQNZsB>vxk(LF)2b1(C~~umHTYk9{{R)dOZv z>4m0c`)Ep!&y^2JrbvjyeoSfA*F*HP((Fb_%k z83a{U-~EMS6MS1tqAj4!GEV=MIJFs^))x*)hclqzTg8;52XHp} zL=JEwmsui@Zz5lMA`qP@IGZSZk;t?2MqUabK|-L`^F|tBrR|Xmc~Z$ zQL+ZyLR6HyyW8UTGYFtwg|o=Ul3wMaJLO52&EfA9krNfrhQ$F*>g9W7Rf%MsQHb^% z4pA)QxIS&?8J*r62s$c*v5owRC>_Yos+GjD!NKai zs6{J@b%{g99WU$KcFBrk8DG(#O{p`fR5Nwah#7oT(sNMuCw|02diEk%vE^CP&*#}l zk{tCZORfmTxsvSj9XcugoWHX<%!V{%^tpsGxkP>s9gpIJBx3J0<=&smrMS#}NSbF8 zkxSqZ^;$LW?*tUy6#!t6VaTwHCCX>kkY@GsXz^n7I#mVbd#P|h&9>ij%1CniiG8M4 z+nMJ3S|lbyRiGta(CVR+mG8kK<`KKbE>6hV+Fl?gleeo#zFS|Qp&=>GP*@Sl_sFl% zG^5bGsn9~^;k9~Uok67aob+p%q8NiBJB@s+j3OjwB+VF`n}!3F5_x+(uI zWrO%>5m&j4r+lv11z{mqzMDX(#GiW{-5Rc}XW|*2;yi><;>H3g$_m=)GAVP;r->Z- zm*us$oUc+1>wp0sT?}8_#WyY=h*0sTA)RV#N-$ex_w6NAIC$O}zyC>F`rZ7?i?atq zr9l+Z!6cj-Ua0|UkP0UvT|HhGq@Vgvwddgf8+5<->f_g6(ZFLF&mdm@wDD@Sj?$Bi zGSXev$J@vT4a3x3VFa+`F_~Vl$yX=5Ba`?`=48i`ts0a_CdveYYRX`GT80vr(hAY9 zRTL2LDy&u2EK&c%tJ7RtMX2qZ5&p!dE}%2QoKe7HzOHH`pj6qwItJ7NE%PH}ys~jJ zh;%9z6*=qpz^~yBa8!3@Z1C`}utNGOI~hKQx~33{4;rg0Dp#{4LYXP6j3R+3xTg^x zlvhc@;9jFhlV?C?%^LxU5`C`hclpNN?0VZSF<&a%MFFpsD6T}g-xN1(tMGJ8d$04< zf1?hp*6{oj&9S}Z#_QLhvFt;_28NHS1|TS%9Ge>&-=ZST>+RF(Mt^{; zWHEXI&C4f-Q)HmYX3XPA%qTw9e>qKf<7MlXe=9Dtb+@^7Z@%^CpVkA$Z%4A$7-+tI7h@K6MqAqLtQyPP$rB zCmZI<^b~;{`!WI9G2QIuok|8hgWf&EbloU{R(m-~0lD6@7rkBqZ$-0u>1evr2YV?( zdp|OQ&4rplw2ES9CM@8B4?gpqxLXbEExnbG#8%bBHoe6fSDg-` z-NqxnKm-Fw&)hmsouiwbQJ{fkV>R25##Vp+5@%=EmoD|jF4V>S?SuWF{}yc_B_R4k zrEBU|`i!|9=*iMbYq6U5c0+G98!AehYR9;y%Uw|LVaRFVI`0P#&JS=Vu2U~puu_Y~ zrxE;?`|wcDmjKVR6i?fh#vP5v0mFf$wTxGvck$xt!ZB8vI*cwzmx zU|{X_Uc+PNdLBHcUA$skl(|PLwpbW5QG=aOSnL1?jwuFWB$-E_k@InW#->YPJ%_L& zf!Lt?lS)F9c&*8ZT`XnnWJJLv-|%DtDb{-N#VckMB(V2&;1p-_l%sZ^^Ws#V@l@pf z>3hzTV%pR8LeoBrlU@}Q{@PQ4+Snj+l%MSENLWqAA28U}WH1vskU z-CpF}!7Tq}UYavqCR_qs#WI~#EW@j#B-%{caez=G`g6;b`wH~90tNaJ0F{pErlko! zHfl(Fm?M_>6D2{?1MhDWEWx!W@t5+T`t$cd6zHn^HyR?dUvD$RD z1g~Cg;xh}P`Si4Pi8T(!&H}piVdWG1M!nibO10b&WPS8_!%}ihUtyC-VdL)gW>nrL zhJ5pt&Xz69mXX4iqbtDf)f9)$6N%BnJ7a5iT(^nXV@9vG5=9rOt|I9Ig!cC_{S^y) tJRUe$B};TG4mXC2b7k>Q%t?B+lX6W%CXUN!-N{ + +Quick Start + + + +

Quick Start

+ +The following is a step-by-step guide that shows you how to get SheepShaver +up and running in the quickest possible way. We assume that you are running +on a PowerMac that already has MacOS installed on a partition of your hard drive +and that you have booted into Linux. + +

+

    +
  1. Start the "SheepShaver" program. The "SheepShaver Settings" window will appear. +
  2. Click on "Start". SheepShaver will try to detect on which partition MacOS is installed and should then start booting MacOS. +
  3. To quit SheepShaver, select "Shutdown" from the Finder's "Special" menu. +
+ +When SheepShaver hangs or crashes in fullscreen mode, pressing Ctrl-Esc should +quit it and restore the display. + +

In fullscreen mode, press Ctrl-Tab to suspend SheepShaver and return to the +normal X11 destop. Press space inside the "SheepShaver suspended" window to +reactivate it. + +

One word of caution:

+ +Volumes which are used by SheepShaver must not also be mounted under Linux +while SheepShaver is running. You will lose data and corrupt the +volume if you do this! + +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/serial.gif b/SheepShaver/doc/Linux/serial.gif new file mode 100644 index 0000000000000000000000000000000000000000..49ca90f95d9d0525684991a2611d9fecb741dc77 GIT binary patch literal 5325 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 O30 + +Setting up SheepShaver + + + +

Setting up SheepShaver

+ +In the "SheepShaver Settings" window that pops up when you start SheepShaver, +you can configure certain features of SheepShaver. When you click on "Start", +the current settings are saved to disk and will be available next time you start +SheepShaver. + +

The settings are divided into four groups: Volumes, Graphics/Sound, Serial/Network and Memory/Misc. + +

Volumes

+ + + +

The main part of the volumes pane is a list that contains all volumes to be mounted +by SheepShaver. If this list is empty, SheepShaver will try to detect and mount all +HFS partitions it can find. A CD-ROM drive is always automatically detected and used. + +

SheepShaver can use HFS partitions, whole HFS formatted drives, and it can also +emulate hard disks in single Linux files ("hardfiles"). + +

To add a Mac volume to the list, click on "Add...", go to the "/dev" directory +in the file panel, click once on the partition you want and click on "OK". The selected +partition device name should then appear in the volume list. After adding volumes to +the list, you should unmount them on the Linux side. To remove a Mac volume, select it +in the list and click on "Remove". + +

You can create a new, empty hardfile by clicking on "Create...". Enter the file +name and the size of the hardfile and click on "Create". The hardfile will be created (this may +take some seconds) and added to the volume list. The so-created hardfile will have to be +formatted under MacOS before you can store something in it. If you start up SheepShaver, +the Finder will display a message about an "unreadable" volume being found and give you the +option to format it. + +

Double-clicking on an entry in the volume list will add or remove a "*" in front of the +device name. Volumes marked with a "*" are read-only for the MacOS under SheepShaver. + +

SheepShaver will show a "Linux" disk icon on the Mac desktop that allows access to Linux +files from Mac applications. In "Linux Root" you specify which Linux directory will +be at the root of this virtual "Linux" disk. The default setting of "/" means that the +"Linux" icon in the MacOS Finder will correspond to your Linux root directory. The MacOS +will try to create files and folders like "Desktop", "Trash", "OpenFolderListDF" etc. +in the directory you specify as "Linux Root" (provided that you have access rights +to that directory). If they annoy you, you can delete them. + +

To boot from CD-ROM, set the "Boot From" setting to "CD-ROM". +The "Disable CD-ROM Driver" box is used to disable SheepShaver's built-in CD-ROM driver. +This is currently of not much use and you should leave the box unselected. + +

Graphics/Sound

+ + + +

With "Window Refresh Rate" you can set the refresh rate of the MacOS window. +Higher rates mean faster screen updates and less "sluggish" behaviour, but also require more CPU time. + +

The "Enabled Video Modes" controls allow you to select which graphics modes +are available for displaying the MacOS desktop. You can, for example, disable the window modes +when you want to run some Mac programs in full-screen mode that would otherwise erroneously +switch to a window mode. If your X server doesn't support DGA you should disable the Fullscreen +mode. The actual mode to be used is selected in the "Monitors" control panel under MacOS. The +color depth is always that of the X11 screen and cannot be changed. + +

The "Disable Sound Output" box allows you to disable all sound output by SheepShaver. +This is useful if the sound takes too much CPU time on your machine or to get rid of warning +messages if SheepShaver can't use your audio hardware. + +

Serial/Network

+ + + +

You can select to which devices the MacOS modem and printer ports are redirected. +You can assign them to any serial ports you have (/dev/ttyS*), or even to parallel +ports (/dev/lp*, useful for printing if you have Mac drivers for parallel printers, +like the PowerPrint package from www.gdt.com). + +

With "Ethernet Interface" you select which Ethernet card is to be used for +networking. It can either be the name of a real Ethernet card (e.g. "eth0") or of an ethertap +interface (e.g. "tap0"). Using a real Ethernet card requires the "sheep_net" driver to be installed +and accessible. See Using SheepShaver for more +information about setting up networking. + +

Memory/Misc

+ + + +

With "MacOS RAM Size" you select how much RAM will be available to the MacOS +(and all MacOS applications running under it). SheepShaver uses the Linux virtual memory system, +so you can select more RAM than you physically have in your machine. The MacOS virtual memory +system is not available under SheepShaver (i.e. if you have 32MB of RAM in your computer and +select 64MB to be used for MacOS in the SheepShaver settings, MacOS will behave as if it's running on +a computer that has 64MB of RAM but no virtual memory). + +

"ROM File" specifies the path name of the Mac ROM file to be used. If it is left +blank, SheepShaver expects the ROM file to be called "ROM" and be in the same directory as +the SheepShaver application. + +

The "Ignore Illegal Memory Accesses" option is there to make some broken Mac +programs work that access addresses where there is no RAM or ROM. With this option unchecked, +SheepShaver will in this case display an error message and quit. When the option is activated, +SheepShaver will try to continue as if the illegal access never happened (writes are ignored, reads +return 0). This may or may not make the program work (when a program performs an illegal access, +it is most likely that something else went wrong). When a Mac program behaves strangely or hangs, +you can quit SheepShaver, uncheck this option and retry. If you get an "illegal access" message, +you will know that something is broken. + +


+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/troubleshooting.html b/SheepShaver/doc/Linux/troubleshooting.html new file mode 100644 index 00000000..4dc3e293 --- /dev/null +++ b/SheepShaver/doc/Linux/troubleshooting.html @@ -0,0 +1,65 @@ + + +Troubleshooting + + + +

Troubleshooting

+ +

SheepShaver doesn't boot

+ +SheepShaver should boot all MacOS versions >=7.5.2, except MacOS X. However, +your mileage may vary. If it doesn't boot, try again with extensions disabled +(by pressing the shift key) and then remove some of these extensions: +"MacOS Licensing Extension", Speed Doubler, 68k FPU extensions and MacsBug. + +

The colors are wrong in 16 or 32 bit graphics modes

+ +If you're running SheepShaver on a something other than a PowerMac, it may be +that 16 or 32 bit graphics modes show false colors due to the frame buffer being +little-endian. Apart from patching the X server, there's unfortunately nothing +that you or SheepShaver can do about this. + +

Full-screen mode doesn't work

+ +Some X servers on Linux PPC don't support DGA and full-screen mode cannot be used +with these (in this case, you should disable it in the "Graphics" settings). If you +are seeing a message like "cannot map /dev/kmem (permission denied)", you have to +either run SheepShaver as root (not recommended) or give yourself appropriate access +rights to /dev/kmem if you can login as root. + +

Ethernet doesn't work

+ +
    +
  • You have to either install the sheep_net driver or configure the ethertap device in the Linux kernel to use Ethernet. See Using SheepShaver for more information. +
  • If you're using TCP/IP on the MacOS side, you have to set up different IP addresses for Linux and for the MacOS. +
+ +

SheepShaver crashes, but yesterday it worked

+ +Try the "Zap PRAM File" item in the main menu of the SheepShaver preferences editor. +When you are using a ROM file and switching to a different ROM version, you have +to zap the PRAM file or SheepShaver might behave very weird. + +

Known incompatibilities

+ +
    +
  • MacOS programs or drivers which access Mac hardware directly are not supported by SheepShaver. +
  • Speed Doubler, RAM Doubler, 68k FPU emulators and similar programs don't run under SheepShaver. +
  • MacsBug is not compatible with SheepShaver. +
+ +

Known bugs

+ +
    +
  • The QuickTime 2.5 Cinepak codec crashes the emulator. +
  • Programs that use InputSprockets crash the emulator when in window mode. +
  • The mouse cursor hotspot in window mode is not correct. +
+ +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/using.html b/SheepShaver/doc/Linux/using.html new file mode 100644 index 00000000..9fbceec5 --- /dev/null +++ b/SheepShaver/doc/Linux/using.html @@ -0,0 +1,113 @@ + + +Using SheepShaver + + + +

Using SheepShaver

+ +

Changing the display mode

+ +SheepShaver can display the MacOS user interface in an X11 window or full-screen +(much faster). You select the display mode as usual under MacOS in the "Monitors" +control panel (under System 7.x, click on "Options"). The "75Hz" modes are full-screen +modes, the "60Hz" modes are window modes (this doesn't mean that the video refresh +rate is 75 or 60Hz in the respective modes; the rate displayed has no meaning; it's +simply there to distinguish full screen modes from window modes). + +

Full-screen mode

+ +The full-screen mode uses the whole X11 screen for displaying the MacOS user interface. +You can temporarily switch back to the X11 desktop by pressing Ctrl-Tab. The MacOS (and +all MacOS applications) will now be suspended. You can resume SheepShaver by activating +the "SheepShaver suspended" window and pressing the space key. Using full-screen mode +requires a DGA capable X server. + +

Networking

+ +There are three approaches to networking with SheepShaver: + +
    +
  1. Direct access to an Ethernet card via the "sheep_net" driver. +In this case, the "ethernet card description" must be the name +of a real Ethernet card, e.g. "eth0". It also requires the "sheep_net" +driver to be installed and accessible. This approach will allow you +to run all networking protocols under MacOS (TCP/IP, AppleTalk, IPX +etc.) but there is no connection between Linux networking and MacOS +networking. MacOS will only be able to talk to other machines on +the Ethernet, but not to other networks that your Linux box routes +(e.g. a second Ethernet or a PPP connection to the Internet). + +
  2. Putting SheepShaver on a virtual Ethernet via the "ethertap" device. +In this case, the "ethernet card description" must be the name +of an ethertap interface, e.g. "tap0". It also requires that you +configure your kernel to enable routing and the ethertap device: +under "Networking options", enable "Kernel/User netlink socket" and +"Netlink device emulation", under "Network device support", activate +"Ethertap network tap". You also have to modify devices/net/ethertap.c +a bit before compiling the new kernel: + +
      +
    • insert #define CONFIG_ETHERTAP_MC 1 near the top (after the #include lines) +
    • comment out the line dev->flags|=IFF_NOARP; in ethertap_probe() +
    + +

    +Next, see /usr/src/linux/Documentation/networking/ethertap.txt for +information on how to set up /dev/tap* device nodes and activate the +ethertap interface. Under MacOS, select an IP address that is on the +virtual network and set the default gateway to the IP address of the +ethertap interface. This approach will let you access all networks +that your Linux box has access to (especially, if your Linux box has +a dial-up Internet connection and is configured for IP masquerading, +you can access the Internet from MacOS). The drawback is that you +can only use network protocols that Linux can route, so you have to +install and configure netatalk if you want to use AppleTalk. Here is +an example /etc/atalk/atalkd.conf for a LAN: + +

    +eth0 -seed -phase 2 -net 1 -addr 1.47 -zone "Ethernet"
    +tap0 -seed -phase 2 -net 2 -addr 2.47 -zone "Sheepnet"
    +
    + +(the "47" is an arbitrary node number). This will set up a zone +"Ethernet" (net 1) for the Ethernet and a zone "Sheepnet" (net 2) +for the internal network connection of the ethertap interface. +MacOS should automatically recognize the nets and zones upon startup. +If you are in an existing AppleTalk network, you should contact +your network administrator about the nets and zones you can use +(instead of the ones given in the example above). + +
  3. Networking protocols for serial connections (PPP and SLIP, for example) +can be used provided that you have the appropriate MacOS system components +installed (e.g. Open Transport/PPP). +
+ +

Using floppy disks

+ +Floppy disks are not automatically detected when they are inserted. They have to be +mounted explicitly: after inserting a floppy disk, press Ctrl-F1. + +

Accessing Linux files

+ +SheepShaver will display a "Linux" disk icon on the Mac desktop that allows you +to access any Linux files which are in the directory specified as "Linux Root" +in the "Volumes" pane of the SheepShaver settings. You can open and save files on the +"Linux" disk from Mac applications, copy, move or rename files from the Finder etc. +SheepShaver translates some file name extensions to MacOS types and vice versa, +so e.g. *.jpg and *.pdf files will show the correct icons in the Finder. MacOS +resources and Finder attributes are stored in hidden .rsrc and +.finf directories. + +

Copying text via the clipboard

+ +SheepShaver tries to keep the Linux and MacOS clipboards synchronized. That means, +when you copy a piece of text under Linux, you can paste it into a MacOS application +and vice versa. + +
+
+SheepShaver User's Guide +
+ + diff --git a/SheepShaver/doc/Linux/volumes.gif b/SheepShaver/doc/Linux/volumes.gif new file mode 100644 index 0000000000000000000000000000000000000000..676248b7acd71ad6e381e0c209561415e925aeca GIT binary patch literal 7705 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 + +int main(int argc, char **argv) +{ + if (argc != 3) { + printf("Usage: %s \n", argv[0]); + return 0; + } + + FILE *fin = fopen(argv[1], "rb"); + if (fin == NULL) { + printf("Can't open '%s' for reading\n", argv[1]); + return 0; + } + + FILE *fout = fopen(argv[2], "w"); + if (fout == NULL) { + printf("Can't open '%s' for writing\n", argv[2]); + return 0; + } + + unsigned char buf[16]; + while (!feof(fin)) { + fprintf(fout, "\t"); + int actual = fread(buf, 1, 16, fin); + for (int i=0; i@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +SRCS= main_beos.cpp ../prefs.cpp ../prefs_items.cpp prefs_beos.cpp \ + prefs_editor_beos.cpp sys_beos.cpp ../rom_patches.cpp ../rsrc_patches.cpp \ + ../emul_op.cpp ../name_registry.cpp ../macos_util.cpp ../timer.cpp \ + timer_beos.cpp ../xpram.cpp xpram_beos.cpp ../adb.cpp clip_beos.cpp \ + ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp scsi_beos.cpp \ + ../video.cpp video_beos.cpp ../audio.cpp audio_beos.cpp ../ether.cpp \ + ether_beos.cpp ../serial.cpp serial_beos.cpp ../extfs.cpp extfs_beos.cpp \ + about_window_beos.cpp ../user_strings.cpp user_strings_beos.cpp + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS= SheepShaver.rsrc + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS= be tracker game media translation textencoding device GL + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS= + +# additional paths to look for system headers +# thes use the form: #include
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS = + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS = ../include SheepDriver SheepNet + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE= FULL + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES= + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS = + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS = + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER = + +# specify additional compiler flags for all files +COMPILER_FLAGS = -prefix BeHeaders + +# specify additional linker flags +LINKER_FLAGS = + + +## include the makefile-engine +include /boot/develop/etc/makefile-engine + diff --git a/SheepShaver/src/BeOS/NetPeek/Makefile b/SheepShaver/src/BeOS/NetPeek/Makefile new file mode 100644 index 00000000..233c7e5f --- /dev/null +++ b/SheepShaver/src/BeOS/NetPeek/Makefile @@ -0,0 +1,110 @@ +## BeOS Generic Makefile v2.1 ## + +## Fill in this file to specify the project being created, and the referenced +## makefile-engine will do all of the hard work for you. This handles both +## Intel and PowerPC builds of the BeOS. + +## Application Specific Settings --------------------------------------------- + +# specify the name of the binary +NAME= NetPeek + +# specify the type of binary +# APP: Application +# SHARED: Shared library or add-on +# STATIC: Static library archive +# DRIVER: Kernel Driver +TYPE= APP + +# add support for new Pe and Eddie features +# to fill in generic makefile + +#%{ +# @src->@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +SRCS= NetPeek.cpp + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS= + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS= + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS= + +# additional paths to look for system headers +# thes use the form: #include
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS = + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS = ../ ../../include ../NetAddOn + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE= FULL + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES= + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS = + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS = + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER = + +# specify additional compiler flags for all files +COMPILER_FLAGS = + +# specify additional linker flags +LINKER_FLAGS = + + +## include the makefile-engine +include /boot/develop/etc/makefile-engine + diff --git a/SheepShaver/src/BeOS/NetPeek/NetPeek.cpp b/SheepShaver/src/BeOS/NetPeek/NetPeek.cpp new file mode 100644 index 00000000..ccf5629a --- /dev/null +++ b/SheepShaver/src/BeOS/NetPeek/NetPeek.cpp @@ -0,0 +1,49 @@ +/* + * NetPeek.cpp - Utility program for monitoring SheepNet add-on + */ + +#include "sysdeps.h" +#include "sheep_net.h" + +#include + +static area_id buffer_area; // Packet buffer area +static net_buffer *net_buffer_ptr; // Pointer to packet buffer + +int main(void) +{ + area_id handler_buffer; + if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) { + printf("Can't find packet buffer\n"); + return 10; + } + if ((buffer_area = clone_area("local packet buffer", &net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) { + printf("Can't clone packet buffer\n"); + return 10; + } + + uint8 *p = net_buffer_ptr->ether_addr; + printf("Ethernet address : %02x %02x %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3], p[4], p[5]); + printf("read_sem : %d\n", net_buffer_ptr->read_sem); + printf("read_ofs : %d\n", net_buffer_ptr->read_ofs); + printf("read_packet_size : %d\n", net_buffer_ptr->read_packet_size); + printf("read_packet_count : %d\n", net_buffer_ptr->read_packet_count); + printf("write_sem : %d\n", net_buffer_ptr->write_sem); + printf("write_ofs : %d\n", net_buffer_ptr->write_ofs); + printf("write_packet_size : %d\n", net_buffer_ptr->write_packet_size); + printf("write_packet_count: %d\n", net_buffer_ptr->write_packet_count); + + printf("\nRead packets:\n"); + for (int i=0; iread[i]; + printf("cmd : %08lx\n", p->cmd); + printf("length: %d\n", p->length); + } + printf("\nWrite packets:\n"); + for (int i=0; iwrite[i]; + printf("cmd : %08lx\n", p->cmd); + printf("length: %d\n", p->length); + } + return 0; +} diff --git a/SheepShaver/src/BeOS/SaveROM/Makefile b/SheepShaver/src/BeOS/SaveROM/Makefile new file mode 100644 index 00000000..cba232e1 --- /dev/null +++ b/SheepShaver/src/BeOS/SaveROM/Makefile @@ -0,0 +1,110 @@ +## BeOS Generic Makefile v2.1 ## + +## Fill in this file to specify the project being created, and the referenced +## makefile-engine will do all of the hard work for you. This handles both +## Intel and PowerPC builds of the BeOS. + +## Application Specific Settings --------------------------------------------- + +# specify the name of the binary +NAME= SaveROM + +# specify the type of binary +# APP: Application +# SHARED: Shared library or add-on +# STATIC: Static library archive +# DRIVER: Kernel Driver +TYPE= APP + +# add support for new Pe and Eddie features +# to fill in generic makefile + +#%{ +# @src->@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +SRCS= SaveROM.cpp + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS= SaveROM.rsrc + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS= be + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS= + +# additional paths to look for system headers +# thes use the form: #include
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS = + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS = ../ ../../include ../NetAddOn + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE= FULL + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES= + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS = + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS = + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER = + +# specify additional compiler flags for all files +COMPILER_FLAGS = + +# specify additional linker flags +LINKER_FLAGS = + + +## include the makefile-engine +include /boot/develop/etc/makefile-engine + diff --git a/SheepShaver/src/BeOS/SaveROM/README b/SheepShaver/src/BeOS/SaveROM/README new file mode 100644 index 00000000..37214b34 --- /dev/null +++ b/SheepShaver/src/BeOS/SaveROM/README @@ -0,0 +1,8 @@ +"SaveROM" is a program that allows you to save the ROM of +a PowerMac running under BeOS to a file. + +1. Copy "sheep_driver" to ~/config/add-ons/kernel/drivers. +2. Double-click the "SaveROM" icon. + +This will create a file called "ROM" which should be 4MB +in size. diff --git a/SheepShaver/src/BeOS/SaveROM/SaveROM.cpp b/SheepShaver/src/BeOS/SaveROM/SaveROM.cpp new file mode 100644 index 00000000..a646aa40 --- /dev/null +++ b/SheepShaver/src/BeOS/SaveROM/SaveROM.cpp @@ -0,0 +1,128 @@ +/* + * SaveROM - Save Mac ROM to file + * + * Copyright (C) 1998-2002 Christian Bauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include + + +// Constants +const char APP_SIGNATURE[] = "application/x-vnd.cebix-SaveROM"; +const char ROM_FILE_NAME[] = "ROM"; + +// Global variables +static uint8 buf[0x400000]; + +// Application object +class SaveROM : public BApplication { +public: + SaveROM() : BApplication(APP_SIGNATURE) + { + // Find application directory and cwd to it + app_info the_info; + GetAppInfo(&the_info); + BEntry the_file(&the_info.ref); + BEntry the_dir; + the_file.GetParent(&the_dir); + BPath the_path; + the_dir.GetPath(&the_path); + chdir(the_path.Path()); + } + virtual void ReadyToRun(void); +}; + + +/* + * Create application object and start it + */ + +int main(int argc, char **argv) +{ + SaveROM *the_app = new SaveROM(); + the_app->Run(); + delete the_app; + return 0; +} + + +/* + * Display error alert + */ + +static void ErrorAlert(const char *text) +{ + BAlert *alert = new BAlert("SaveROM Error", text, "Quit", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); + alert->Go(); +} + + +/* + * Display OK alert + */ + +static void InfoAlert(const char *text) +{ + BAlert *alert = new BAlert("SaveROM Message", text, "Quit", NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT); + alert->Go(); +} + + +/* + * Main program + */ + +void SaveROM::ReadyToRun(void) +{ + int fd = open("/dev/sheep", 0); + if (fd < 0) { + ErrorAlert("Cannot open '/dev/sheep'."); + goto done; + } + + if (read(fd, buf, 0x400000) != 0x400000) { + ErrorAlert("Cannot read ROM."); + close(fd); + goto done; + } + + FILE *f = fopen(ROM_FILE_NAME, "wb"); + if (f == NULL) { + ErrorAlert("Cannot open ROM file."); + close(fd); + goto done; + } + + if (fwrite(buf, 1, 0x400000, f) != 0x400000) { + ErrorAlert("Cannot write ROM."); + fclose(f); + close(fd); + goto done; + } + + InfoAlert("ROM saved."); + + fclose(f); + close(fd); +done: + PostMessage(B_QUIT_REQUESTED); +} diff --git a/SheepShaver/src/BeOS/SaveROM/SaveROM.rsrc b/SheepShaver/src/BeOS/SaveROM/SaveROM.rsrc new file mode 100644 index 0000000000000000000000000000000000000000..a61919ba80a170f7ce863bf1ad107b503bfc093d GIT binary patch literal 4323 zcmeHJzfV(96h6f&rP24E(N+frH8D6QW?ns-6xt+7^FW7WT>UY0}-HVCQy(3rt zn>hVvJNZ83w3D0s5Rv~eBL7oF{%2gJO0i(alx@S-quaErI*MKyc5>5*x50OwMdZJT z$bS`)|E7U|PWonzY{R#%tGi>0;l%5r}tv*2g^iobY&t+cS@Q$4o6e5-HKUno~HUTNK*Di-)c^gjl+ zkMf_H%YE6tEL-~SJyXW`f_E12x1ilD#UTT}sLKuO)+AO1Y`M z86@CTx;2BvkqsELc^4%vVNeW*M!99uSC^+GL@q89kCT8I z#b8wWA|O!VTNdtCqe34Ms|TOy@H}t>kE8IE579&+KRkie$2>#M^^u}CP#Ey0b94FO z;zW=q9LY*6)_5~(XmWBCI{cdRDPZ)XSqM9`-#4?%nOTr}u>bP2 z!|3_Xr}Zy>JZXP}lZ7{<)35&eE|9=ca$>@jrPD)QZDjqh2rcIqF!>jk!NLe_rS(z|5;$w|?bZI$ZLZFFPmG z_?Opj)7(yTJMDpK5BxtpAn(!-i{h)SX=r{E@D*CREsDH{ueYga8LH`Kv)2_Ip9|1* zAu?N{H#BTpWrE4Lp<9534DHHPdfv~VZ4RHPqdmShVbQR1GxcceMx&wmfuTJyGZ$@N zx8Vb+m&g(269g{z@e;u+A*0g&rSbs}#LoL6B~=u~%s|B#aRomPf*>YK#VWp59Hhwa zB4Wb%;L@C+%%PHeo5V8}IlLCH<(n%o;bs1vyY zvc4tkYA+$&!np9y>zxO7wUauD>!39je}|6<=^rQ_%+rp69iDS+`~{anAoY<32vT}W zuDLem)H1kvhy-gXJ4m>+v&=DQg(p4|j~!(|=S&P&l0g4NDD*8YFfqi}Xck_g?wloaMkdy>tbcIubgmNmjvgZtc<(~xJCZOBj z-3(U_Ukq1AgJ+Sfe4L#3Ux|iCgTwvdvuHS4*}ir2+m8!2Wlu9uWT4x*`-rM^WDN`7 zZES|OySKx~>rXm&Hy@QZF*8QankiTh-)D6@-H>sl_phK~Vm +#include +#include +#include + +#include "about_window.h" +#include "video.h" +#include "version.h" +#include "user_strings.h" + + +// About window dimensions +static const BRect about_frame = BRect(0, 0, 383, 99); + +// Special colors +const rgb_color fill_color = {216, 216, 216, 0}; + +// SheepShaver icon +static const uint8 sheep_icon[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xda, 0x15, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xff, 0x00, 0x00, 0x00, 0x16, 0xda, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, + 0x00, 0x1d, 0xda, 0x1e, 0x1e, 0x1e, 0xda, 0x16, 0x00, 0x00, 0x16, 0xda, 0x16, 0xda, 0x08, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0x11, 0x00, 0xda, + 0x1d, 0xda, 0x1e, 0xda, 0x1e, 0xda, 0x1e, 0xda, 0x1e, 0x16, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, + 0xff, 0x0b, 0x00, 0x00, 0x16, 0x16, 0x00, 0x12, 0xfd, 0x1d, 0x0b, 0x00, 0x00, 0x1d, 0xfd, 0x1d, + 0xfd, 0x1e, 0xda, 0x1e, 0xda, 0x1e, 0xda, 0x3f, 0xda, 0x3f, 0xda, 0x15, 0x00, 0xff, 0xff, 0xff, + 0x16, 0x00, 0x17, 0x16, 0x00, 0x00, 0x1d, 0xfd, 0x1d, 0xfd, 0x1d, 0xfd, 0x16, 0x0f, 0x0b, 0x1d, + 0x1e, 0xfd, 0x1e, 0xda, 0x1e, 0xda, 0x3f, 0xda, 0x3f, 0xda, 0x1d, 0x5a, 0x15, 0xff, 0xff, 0xff, + 0x05, 0x17, 0x16, 0x00, 0x12, 0x1d, 0x00, 0x1d, 0xfd, 0x00, 0xfd, 0x00, 0x00, 0x16, 0x0b, 0x00, + 0x00, 0x0e, 0x1d, 0x3f, 0xda, 0x3f, 0xda, 0x1d, 0xda, 0x1b, 0x5a, 0x1b, 0x0f, 0x1d, 0xff, 0xff, + 0xff, 0x05, 0x00, 0x00, 0x1d, 0xfd, 0x1d, 0xfd, 0x1d, 0xfd, 0x1a, 0xfd, 0x00, 0x0f, 0x14, 0x14, + 0x16, 0x00, 0x15, 0xfd, 0x1d, 0xda, 0x1b, 0xda, 0x1b, 0x5a, 0x1b, 0x5a, 0x0f, 0x14, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x1d, 0xfd, 0x1d, 0xfd, 0x1d, 0xfd, 0x1a, 0xfd, 0x12, 0x00, 0x16, 0x00, 0x0f, + 0x00, 0x1b, 0xfd, 0x1e, 0xfd, 0x1b, 0xda, 0x1b, 0x5a, 0x1b, 0x5a, 0x1b, 0x5a, 0x14, 0xff, 0xff, + 0xff, 0x00, 0x1d, 0xfd, 0x1d, 0xfd, 0x1d, 0xfd, 0x1a, 0xfd, 0x12, 0x00, 0x16, 0x1b, 0x16, 0x0e, + 0x1b, 0xfd, 0x1b, 0xfd, 0x1b, 0xfd, 0x1b, 0x5a, 0x18, 0x00, 0x00, 0x5a, 0x1b, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xfd, 0x14, 0xfd, 0x14, 0xfd, 0x1d, 0xfd, 0x12, 0x00, 0x16, 0xfd, 0x1b, 0xfd, 0x1b, + 0xfd, 0x1b, 0xfd, 0x1e, 0xfd, 0x1b, 0x5a, 0x18, 0x5a, 0x00, 0x00, 0x1b, 0x9b, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x0f, 0xfd, 0x1d, 0xfd, 0x0f, 0xfd, 0x12, 0x00, 0x16, 0xfd, 0x1b, 0xfd, 0x1b, 0xfd, + 0x1b, 0xfd, 0x18, 0xfd, 0x1b, 0xf9, 0x18, 0x5a, 0x00, 0x12, 0x00, 0x9b, 0x1b, 0x00, 0xff, 0xff, + 0xff, 0x00, 0xfd, 0x0a, 0x0a, 0x0a, 0xfd, 0x10, 0x00, 0x1b, 0xfd, 0x1b, 0xfd, 0x1b, 0xfd, 0x18, + 0xfd, 0x15, 0xfa, 0x15, 0xf9, 0x18, 0x15, 0x00, 0x12, 0x9b, 0x00, 0x1b, 0x9b, 0x00, 0x15, 0x15, + 0xff, 0xff, 0x00, 0xfd, 0x1d, 0xfd, 0x1d, 0x00, 0x16, 0x00, 0x1b, 0xfd, 0x1b, 0xfd, 0x15, 0xfd, + 0x15, 0xfa, 0x15, 0xf9, 0x15, 0x16, 0x00, 0x0f, 0x9b, 0x12, 0x00, 0x9b, 0x1b, 0x00, 0x15, 0x15, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x1d, 0x00, 0xfa, 0x1e, 0x00, 0x1e, 0xfa, 0x15, + 0xfa, 0x15, 0x16, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x12, 0x15, 0x15, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1d, 0xf9, 0x00, 0x3f, 0xfa, 0x00, 0xfa, 0x1b, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x00, 0x00, 0x12, 0x15, 0x15, 0x15, 0x15, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf9, 0x1d, 0x00, 0xf9, 0x1b, 0x00, 0x1b, 0xf9, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1d, 0xf9, 0x00, 0x3f, 0xf9, 0x00, 0xf9, 0x1b, 0x00, + 0xff, 0xff, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x16, 0x1d, 0x00, 0xf9, 0x1b, 0x00, 0x1b, 0xf9, 0x00, + 0xff, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x16, 0xf9, 0x00, 0x1b, 0x16, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, + 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x15, 0x00, 0x0a, 0x19, 0x0a, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x16, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x19, 0x1c, 0x18, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0x00, 0x18, 0x11, 0x00, 0x15, 0x00, 0x1c, 0x18, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0x00, 0x00, 0x00, 0x0b, 0x0b, + 0x00, 0x00, 0x0f, 0xff, 0x12, 0x00, 0x18, 0x19, 0x00, 0x15, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0x00, 0x00, 0x14, 0x1e, 0xfd, 0x01, 0xfd, 0x14, + 0xfa, 0xf9, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x19, 0x1c, 0x00, 0x18, 0x1c, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x14, 0xfd, 0x1e, 0xf9, 0x1e, 0xfa, 0x1e, 0xf9, + 0x14, 0xfa, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x18, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x14, 0x1e, 0xf9, 0x14, 0xfa, 0x1e, 0xf9, 0x1e, + 0xfd, 0x1e, 0x00, 0x15, 0xff, 0xff, 0xff, 0x15, 0x15, 0x15, 0x00, 0x00, 0x18, 0x00, 0x1c, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0x00, 0xfd, 0x1e, 0xfd, 0x14, 0xfd, 0x1e, 0xfd, + 0x1e, 0x01, 0x00, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x00, 0x00, 0x1c, 0x00, 0x15, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x14, 0xfa, 0x01, 0xf9, 0x1e, 0xf9, 0x14, + 0x14, 0x00, 0x0f, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x00, 0x00, 0x15, 0x15, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x15, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x15, 0x15, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +// View class +class AboutViewT : public BView { +public: + AboutViewT(BRect r) : BView(r, "", B_FOLLOW_NONE, B_WILL_DRAW) {} + + virtual void Draw(BRect update) + { + char str[256]; + sprintf(str, GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); + + SetFont(be_bold_font); + SetDrawingMode(B_OP_OVER); + MovePenTo(20, 20); + DrawString(str); + SetFont(be_plain_font); + MovePenTo(20, 40); + DrawString(GetString(STR_ABOUT_TEXT2)); + MovePenTo(20, 60); + DrawString(B_UTF8_COPYRIGHT "1997-2002 Christian Bauer and Marc Hellwig"); + } + + virtual void MouseDown(BPoint point) + { + Window()->PostMessage(B_QUIT_REQUESTED); + } +}; + + +// 3D view class +class AboutView3D : public BGLView { +public: + AboutView3D(BRect r) : BGLView(r, "", B_FOLLOW_NONE, 0, BGL_RGB | BGL_DOUBLE) + { + rot_x = rot_y = 0; + + if (!VideoSnapshot(64, 64, texture)) { + uint8 *p = texture; + const uint8 *q = sheep_icon; + const color_map *cm = system_colors(); + for (int i=0; i<32*32; i++) { + uint8 red = cm->color_list[*q].red; + uint8 green = cm->color_list[*q].green; + uint8 blue = cm->color_list[*q++].blue; + p[0] = p[3] = p[64*3] = p[65*3] = red; + p[1] = p[4] = p[64*3+1] = p[65*3+1] = green; + p[2] = p[5] = p[64*3+2] = p[65*3+2] = blue; + p += 6; + if ((i & 31) == 31) + p += 64*3; + } + } + } + + virtual void AttachedToWindow(void) + { + BGLView::AttachedToWindow(); + LockGL(); + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glShadeModel(GL_SMOOTH); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(30, 1, 0.5, 20); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLfloat light_color[4] = {1, 1, 1, 1}; + GLfloat light_dir[4] = {1, 2, 1.5, 1}; + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color); + glLightfv(GL_LIGHT0, GL_POSITION, light_dir); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHTING); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexImage2D(GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, texture); + glEnable(GL_TEXTURE_2D); + + UnlockGL(); + + tick_thread_active = true; + tick_thread = spawn_thread(tick_func, "OpenGL Animation", B_NORMAL_PRIORITY, this); + resume_thread(tick_thread); + } + + virtual void DetachedFromWindow(void) + { + status_t l; + tick_thread_active = false; + wait_for_thread(tick_thread, &l); + + BGLView::DetachedFromWindow(); + } + + virtual void Draw(BRect update) + { + LockGL(); + glClear(GL_COLOR_BUFFER_BIT); + glBegin(GL_QUADS); + glNormal3d(0, 0, 1); + glTexCoord2f(0, 0); + glVertex3d(-1, 1, 0); + glTexCoord2f(1, 0); + glVertex3d(1, 1, 0); + glTexCoord2f(1, 1); + glVertex3d(1, -1, 0); + glTexCoord2f(0, 1); + glVertex3d(-1, -1, 0); + glEnd(); + SwapBuffers(); + UnlockGL(); + } + + static status_t tick_func(void *arg) + { + AboutView3D *obj = (AboutView3D *)arg; + while (obj->tick_thread_active) { + obj->rot_x += 2; + obj->rot_y += 2; + obj->LockGL(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -5); + glRotatef(obj->rot_x, 1, 0, 0); + glRotatef(obj->rot_y, 0, 1, 0); + obj->UnlockGL(); + if (obj->LockLooperWithTimeout(20000) == B_OK) { + obj->Draw(obj->Bounds()); + obj->UnlockLooper(); + } + snooze(16667); + } + return 0; + } + +private: + thread_id tick_thread; + bool tick_thread_active; + + float rot_x, rot_y; + uint8 texture[64*64*3]; +}; + + +// Window class +class AboutWindowT : public BWindow { +public: + AboutWindowT() : BWindow(about_frame, NULL, B_MODAL_WINDOW_LOOK, B_FLOATING_APP_WINDOW_FEEL, B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK) + { + Lock(); + MoveTo(100, 100); + BRect r = Bounds(); + r.right = 100; + AboutView3D *view_3d = new AboutView3D(r); + AddChild(view_3d); + r = Bounds(); + r.left = 100; + AboutViewT *view = new AboutViewT(r); + AddChild(view); + view->SetHighColor(0, 0, 0); + view->SetViewColor(fill_color); + view->MakeFocus(); + Unlock(); + Show(); + } +}; + + +/* + * Open "About" window + */ + +void OpenAboutWindow(void) +{ + new AboutWindowT; +} diff --git a/SheepShaver/src/BeOS/clip_beos.cpp b/SheepShaver/src/BeOS/clip_beos.cpp new file mode 100644 index 00000000..002a0128 --- /dev/null +++ b/SheepShaver/src/BeOS/clip_beos.cpp @@ -0,0 +1,366 @@ +/* + * clip_beos.cpp - Clipboard handling, BeOS implementation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "clip.h" +#include "main.h" +#include "cpu_emulation.h" +#include "emul_op.h" + +#define DEBUG 0 +#include "debug.h" + + +// Global variables +static bool we_put_this_data = false; // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Be side +static BTranslatorRoster *roster; +static float input_cap = 0; +static translator_info input_info; +static float output_cap = 0; +static translator_id output_trans = 0; + + +/* + * Clipboard manager thread (for calling clipboard functions; this is not safe + * under R4 when running on the MacOS stack in kernel space) + */ + +// Message constants +const uint32 MSG_QUIT_CLIP_MANAGER = 'quit'; +const uint32 MSG_PUT_TEXT = 'ptxt'; + +static thread_id cm_thread = -1; +static sem_id cm_done_sem = -1; + +// Argument passing +static void *cm_scrap; +static int32 cm_length; + +static status_t clip_manager(void *arg) +{ + for (;;) { + + // Receive message + thread_id sender; + uint32 code = receive_data(&sender, NULL, 0); + D(bug("Clipboard manager received %08lx\n", code)); + switch (code) { + case MSG_QUIT_CLIP_MANAGER: + return 0; + + case MSG_PUT_TEXT: + if (be_clipboard->Lock()) { + be_clipboard->Clear(); + BMessage *clipper = be_clipboard->Data(); + + // Convert text from Mac charset to UTF-8 + int32 dest_length = cm_length * 3; + int32 state = 0; + char *inbuf = new char[cm_length]; + memcpy(inbuf, cm_scrap, cm_length); // Copy to user space + char *outbuf = new char[dest_length]; + if (convert_to_utf8(B_MAC_ROMAN_CONVERSION, inbuf, &cm_length, outbuf, &dest_length, &state) == B_OK) { + for (int i=0; iAddData("text/plain", B_MIME_TYPE, outbuf, dest_length); + be_clipboard->Commit(); + } else { + D(bug(" text conversion failed\n")); + } + delete[] outbuf; + delete[] inbuf; + be_clipboard->Unlock(); + } + break; + } + + // Acknowledge + release_sem(cm_done_sem); + } +} + + +/* + * Initialize clipboard + */ + +void ClipInit(void) +{ + // check if there is a translator that can handle the pict datatype + roster = BTranslatorRoster::Default(); + int32 num_translators, i,j; + translator_id *translators; + const char *translator_name, *trans_info; + int32 translator_version; + const translation_format *t_formats; + long t_num; + + roster->GetAllTranslators(&translators, &num_translators); + for (i=0;iGetTranslatorInfo(translators[i], &translator_name, + &trans_info, &translator_version); + D(bug("found translator %s: %s (%.2f)\n", translator_name, trans_info, + translator_version/100.)); + // does this translator support the pict datatype ? + roster->GetInputFormats(translators[i], &t_formats,&t_num); + //printf(" supports %d input formats \n",t_num); + for (j=0;jinput_cap) { + input_info.type = t_formats[j].type; + input_info.group = t_formats[j].group; + input_info.quality = t_formats[j].quality; + input_info.capability = t_formats[j].capability; + strcpy(input_info.MIME,t_formats[j].MIME); + strcpy(input_info.name,t_formats[j].name); + input_info.translator=translators[i]; + input_cap = t_formats[j].capability; + } + D(bug("matching input translator found:type:%c%c%c%c group:%c%c%c%c quality:%f capability:%f MIME:%s name:%s\n", + t_formats[j].type>>24,t_formats[j].type>>16,t_formats[j].type>>8,t_formats[j].type, + t_formats[j].group>>24,t_formats[j].group>>16,t_formats[j].group>>8,t_formats[j].group, + t_formats[j].quality, + t_formats[j].capability,t_formats[j].MIME, + t_formats[j].name)); + } + + } + roster->GetOutputFormats(translators[i], &t_formats,&t_num); + //printf("and %d output formats \n",t_num); + for (j=0;joutput_cap) { + output_trans = translators[i]; + output_cap = t_formats[j].capability; + } + D(bug("matching output translator found:type:%c%c%c%c group:%c%c%c%c quality:%f capability:%f MIME:%s name:%s\n", + t_formats[j].type>>24,t_formats[j].type>>16,t_formats[j].type>>8,t_formats[j].type, + t_formats[j].group>>24,t_formats[j].group>>16,t_formats[j].group>>8,t_formats[j].group, + t_formats[j].quality, + t_formats[j].capability,t_formats[j].MIME, + t_formats[j].name)); + } + } + } + delete [] translators; // clean up our droppings + + // Start clipboard manager thread + cm_done_sem = create_sem(0, "Clipboard Manager Done"); + cm_thread = spawn_thread(clip_manager, "Clipboard Manager", B_NORMAL_PRIORITY, NULL); + resume_thread(cm_thread); +} + + +/* + * Deinitialize clipboard + */ + +void ClipExit(void) +{ + // Stop clipboard manager + if (cm_thread > 0) { + status_t l; + send_data(cm_thread, MSG_QUIT_CLIP_MANAGER, NULL, 0); + while (wait_for_thread(cm_thread, &l) == B_INTERRUPTED) ; + } + + // Delete semaphores + delete_sem(cm_done_sem); +} + + +/* + * Mac application wrote to clipboard + */ + +void PutScrap(uint32 type, void *scrap, int32 length) +{ + D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length)); + if (we_put_this_data) { + we_put_this_data = false; + return; + } + if (length <= 0) + return; + + switch (type) { + case 'TEXT': + D(bug(" clipping TEXT\n")); + cm_scrap = scrap; + cm_length = length; + while (send_data(cm_thread, MSG_PUT_TEXT, NULL, 0) == B_INTERRUPTED) ; + while (acquire_sem(cm_done_sem) == B_INTERRUPTED) ; + break; + + case 'PICT': + D(bug(" clipping PICT\n")); + //!! this has to be converted to use the Clipboard Manager +#if 0 + if (be_clipboard->Lock()) { + be_clipboard->Clear(); + BMessage *clipper = be_clipboard->Data(); + // Waaaah! This crashes! + if (input_cap > 0) { // if there is an converter for PICT datatype convert data to bitmap. + BMemoryIO *in_buffer = new BMemoryIO(scrap, length); + BMallocIO *out_buffer = new BMallocIO(); + status_t result=roster->Translate(in_buffer,&input_info,NULL,out_buffer,B_TRANSLATOR_BITMAP); + clipper->AddData("image/x-be-bitmap", B_MIME_TYPE, out_buffer->Buffer(), out_buffer->BufferLength()); + D(bug("conversion result:%08x buffer_size:%d\n",result,out_buffer->BufferLength())); + delete in_buffer; + delete out_buffer; + } + clipper->AddData("image/pict", B_MIME_TYPE, scrap, length); + be_clipboard->Commit(); + be_clipboard->Unlock(); + } +#endif + break; + } +} + + +/* + * Mac application reads clipboard + */ + +void GetScrap(void **handle, uint32 type, int32 offset) +{ + M68kRegisters r; + D(bug("GetScrap handle %p, type %08lx, offset %ld\n", handle, type, offset)); + return; //!! GetScrap is currently broken (should use Clipboard Manager) + //!! replace with clipboard notification in BeOS R4.1 + + switch (type) { + case 'TEXT': + D(bug(" clipping TEXT\n")); + if (be_clipboard->Lock()) { + BMessage *clipper = be_clipboard->Data(); + char *clip; + ssize_t length; + + // Check if we already copied this data + if (clipper->HasData("application/x-SheepShaver-cookie", B_MIME_TYPE)) + return; + bigtime_t cookie = system_time(); + clipper->AddData("application/x-SheepShaver-cookie", B_MIME_TYPE, &cookie, sizeof(bigtime_t)); + + // No, is there text in it? + if (clipper->FindData("text/plain", B_MIME_TYPE, &clip, &length) == B_OK) { + D(bug(" text/plain found\n")); + + // Convert text from UTF-8 to Mac charset + int32 src_length = length; + int32 dest_length = length; + int32 state = 0; + char *outbuf = new char[dest_length]; + if (convert_from_utf8(B_MAC_ROMAN_CONVERSION, clip, &src_length, outbuf, &dest_length, &state) == B_OK) { + for (int i=0; iCommit(); + be_clipboard->Unlock(); + } + break; + + case 'PICT': + D(bug(" clipping PICT\n")); + if (be_clipboard->Lock()) { + BMessage *clipper = be_clipboard->Data(); + char *clip; + ssize_t length; + + // Check if we already copied this data + if (clipper->HasData("application/x-SheepShaver-cookie", B_MIME_TYPE)) + return; + bigtime_t cookie = system_time(); + clipper->AddData("application/x-SheepShaver-cookie", B_MIME_TYPE, &cookie, sizeof(bigtime_t)); + + static uint16 proc2[] = { + 0x598f, // subq.l #4,sp + 0xa9fc, // ZeroScrap() + 0x2f3c, 0, 0, // move.l #length,-(sp) + 0x2f3c, 'PI', 'CT', // move.l #'PICT',-(sp) + 0x2f3c, 0, 0, // move.l #buf,-(sp) + 0xa9fe, // PutScrap() + 0x588f, // addq.l #4,sp + M68K_RTS + }; + + // No, is there a pict ? + if (clipper->FindData("image/pict", B_MIME_TYPE, &clip, &length) == B_OK ) { + D(bug(" image/pict found\n")); + + // Add pict to Mac clipboard + *(int32 *)(proc2 + 3) = length; + *(char **)(proc2 + 9) = clip; + we_put_this_data = true; + Execute68k((uint32)proc2, &r); +#if 0 + // No, is there a bitmap ? + } else if (clipper->FindData("image/x-be-bitmap", B_MIME_TYPE, &clip, &length) == B_OK || output_cap > 0) { + D(bug(" image/x-be-bitmap found\nstarting conversion to PICT\n")); + + BMemoryIO *in_buffer = new BMemoryIO(clip, length); + BMallocIO *out_buffer = new BMallocIO(); + status_t result=roster->Translate(output_trans,in_buffer,NULL,out_buffer,'PICT'); + D(bug("result of conversion:%08x buffer_size:%d\n",result,out_buffer->BufferLength())); + + // Add pict to Mac clipboard + *(int32 *)(proc2 + 3) = out_buffer->BufferLength(); + *(char **)(proc2 + 9) = (char *)out_buffer->Buffer(); + we_put_this_data = true; + Execute68k(proc2, &r); + + delete in_buffer; + delete out_buffer; +#endif + } + be_clipboard->Commit(); + be_clipboard->Unlock(); + } + break; + } +} diff --git a/SheepShaver/src/BeOS/ether_beos.cpp b/SheepShaver/src/BeOS/ether_beos.cpp new file mode 100644 index 00000000..a8c3b168 --- /dev/null +++ b/SheepShaver/src/BeOS/ether_beos.cpp @@ -0,0 +1,398 @@ +/* + * ether_beos.cpp - SheepShaver Ethernet Device Driver (DLPI), BeOS specific stuff + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include "ether.h" +#include "ether_defs.h" +#include "prefs.h" +#include "xlowmem.h" +#include "main.h" +#include "user_strings.h" +#include "sheep_net.h" + +#define DEBUG 0 +#include "debug.h" + +#define STATISTICS 0 +#define MONITOR 0 + + +// Global variables +static thread_id read_thread; // Packet receiver thread +static bool ether_thread_active = true; // Flag for quitting the receiver thread + +static area_id buffer_area; // Packet buffer area +static net_buffer *net_buffer_ptr; // Pointer to packet buffer +static sem_id read_sem, write_sem; // Semaphores to trigger packet reading/writing +static uint32 rd_pos; // Current read position in packet buffer +static uint32 wr_pos; // Current write position in packet buffer + +static bool net_open = false; // Flag: initialization succeeded, network device open + + +// Prototypes +static status_t AO_receive_thread(void *data); + + +/* + * Initialize ethernet + */ + +void EtherInit(void) +{ + // Do nothing if the user disabled the network + if (PrefsFindBool("nonet")) + return; + + // find net-server team +i_wanna_try_that_again: + bool found_add_on = false; + team_info t_info; + int32 t_cookie = 0; + image_info i_info; + int32 i_cookie = 0; + while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) { + if (strstr(t_info.args,"net_server")!=NULL) { + // check if sheep_net add-on is loaded + while (get_next_image_info(t_info.team,&i_cookie,&i_info) == B_NO_ERROR) { + if (strstr(i_info.name,"sheep_net")!=NULL) { + found_add_on = true; + break; + } + } + } + if (found_add_on) break; + } + if (!found_add_on) { + + // Search for sheep_net in network config file + char str[1024]; + bool sheep_net_found = false; + FILE *fin = fopen("/boot/home/config/settings/network", "r"); + while (!feof(fin)) { + fgets(str, 1024, fin); + if (strstr(str, "PROTOCOLS")) + if (strstr(str, "sheep_net")) + sheep_net_found = true; + } + fclose(fin); + + // It was found, so something else must be wrong + if (sheep_net_found) { + WarningAlert(GetString(STR_NO_NET_ADDON_WARN)); + return; + } + + // Not found, inform the user + if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON))) + return; + + // Change the network config file and restart the network + fin = fopen("/boot/home/config/settings/network", "r"); + FILE *fout = fopen("/boot/home/config/settings/network.2", "w"); + bool global_found = false; + bool modified = false; + while (!feof(fin)) { + str[0] = 0; + fgets(str, 1024, fin); + if (!global_found && strstr(str, "GLOBAL:")) { + global_found = true; + } else if (global_found && !modified && strstr(str, "PROTOCOLS")) { + str[strlen(str)-1] = 0; + strcat(str, " sheep_net\n"); + modified = true; + } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') { + fputs("\tPROTOCOLS = sheep_net\n", fout); + modified = true; + } + fputs(str, fout); + } + if (!modified) + fputs("\tPROTOCOLS = sheep_net\n", fout); + fclose(fout); + fclose(fin); + remove("/boot/home/config/settings/network.orig"); + rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig"); + rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network"); + + app_info ai; + if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) { + BMessenger msg(NULL, ai.team); + if (msg.IsValid()) { + while (be_roster->IsRunning("application/x-vnd.Be-NETS")) { + msg.SendMessage(B_QUIT_REQUESTED); + snooze(500000); + } + } + } + BPath path; + find_directory(B_BEOS_BOOT_DIRECTORY, &path); + path.Append("Netscript"); + char *argv[3] = {"/bin/sh", (char *)path.Path(), NULL}; + thread_id net_server = load_image(2, argv, environ); + resume_thread(net_server); + status_t l; + wait_for_thread(net_server, &l); + goto i_wanna_try_that_again; + } + + // Set up communications with add-on + area_id handler_buffer; + if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) { + WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED)); + return; + } + if ((buffer_area = clone_area("local packet buffer", &net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) { + D(bug("EtherInit: couldn't clone packet area\n")); + WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED)); + return; + } + if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) { + printf("FATAL: can't create Ethernet semaphore\n"); + return; + } + net_buffer_ptr->read_sem = read_sem; + write_sem = net_buffer_ptr->write_sem; + read_thread = spawn_thread(AO_receive_thread, "ether read", B_URGENT_DISPLAY_PRIORITY, NULL); + resume_thread(read_thread); + for (int i=0; iwrite[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8); + rd_pos = wr_pos = 0; + release_sem(write_sem); + + // Everything OK + net_open = true; +} + + +/* + * Exit ethernet + */ + +void EtherExit(void) +{ + if (net_open) { + + // Close communications with add-on + for (int i=0; iwrite[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8); + release_sem(write_sem); + + // Quit receiver thread + ether_thread_active = false; + status_t result; + release_sem(read_sem); + while (wait_for_thread(read_thread, &result) == B_INTERRUPTED) ; + + delete_sem(read_sem); + delete_area(buffer_area); + } + +#if STATISTICS + // Show statistics + printf("%ld messages put on write queue\n", num_wput); + printf("%ld error acks\n", num_error_acks); + printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets); + printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full); + printf("%ld packets received\n", num_rx_packets); + printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind); + printf("EtherIRQ called %ld times\n", num_ether_irq); + printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem); + printf("%ld rx packets dropped because no stream found\n", num_rx_dropped); + printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready); + printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem); +#endif +} + + +/* + * Ask add-on for ethernet hardware address + */ + +void AO_get_ethernet_address(uint8 *addr) +{ + if (net_open) { + OTCopy48BitAddress(net_buffer_ptr->ether_addr, addr); + } else { + addr[0] = 0x12; + addr[1] = 0x34; + addr[2] = 0x56; + addr[3] = 0x78; + addr[4] = 0x9a; + addr[5] = 0xbc; + } + D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5])); +} + + +/* + * Tell add-on to enable multicast address + */ + +void AO_enable_multicast(uint8 *addr) +{ + D(bug("AO_enable_multicast\n")); + if (net_open) { + net_packet *p = &net_buffer_ptr->write[wr_pos]; + if (p->cmd & IN_USE) { + D(bug("WARNING: couldn't enable multicast address\n")); + } else { + memcpy(p->data, addr, 6); + p->length = 6; + p->cmd = IN_USE | (ADD_MULTICAST << 8); + wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; + release_sem(write_sem); + } + } +} + + +/* + * Tell add-on to disable multicast address + */ + +void AO_disable_multicast(uint8 *addr) +{ + D(bug("AO_disable_multicast\n")); + if (net_open) { + net_packet *p = &net_buffer_ptr->write[wr_pos]; + if (p->cmd & IN_USE) { + D(bug("WARNING: couldn't enable multicast address\n")); + } else { + memcpy(p->data, addr, 6); + p->length = 6; + p->cmd = IN_USE | (REMOVE_MULTICAST << 8); + wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; + release_sem(write_sem); + } + D(bug("WARNING: couldn't disable multicast address\n")); + } +} + + +/* + * Tell add-on to transmit one packet + */ + +void AO_transmit_packet(mblk_t *mp) +{ + D(bug("AO_transmit_packet\n")); + if (net_open) { + net_packet *p = &net_buffer_ptr->write[wr_pos]; + if (p->cmd & IN_USE) { + D(bug("WARNING: couldn't transmit packet (buffer full)\n")); + num_tx_buffer_full++; + } else { + D(bug(" write packet pos %d\n", i)); + num_tx_packets++; + + // Copy packet to buffer + uint8 *start; + uint8 *bp = start = p->data; + while (mp) { + uint32 size = mp->b_wptr - mp->b_rptr; + memcpy(bp, mp->b_rptr, size); + bp += size; + mp = mp->b_cont; + } + +#if MONITOR + bug("Sending Ethernet packet:\n"); + for (int i=0; i<(uint32)(bp - start); i++) { + bug("%02lx ", start[i]); + } + bug("\n"); +#endif + + // Notify add-on + p->length = (uint32)(bp - start); + p->cmd = IN_USE | (SHEEP_PACKET << 8); + wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; + release_sem(write_sem); + } + } +} + + +/* + * Packet reception thread + */ + +static status_t AO_receive_thread(void *data) +{ + while (ether_thread_active) { + if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) { + if (ether_driver_opened) { + D(bug(" packet received, triggering Ethernet interrupt\n")); + SetInterruptFlag(INTFLAG_ETHER); + TriggerInterrupt(); + } + } + acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000); + } + return 0; +} + + +/* + * Ethernet interrupt + */ + +void EtherIRQ(void) +{ + D(bug("EtherIRQ\n")); + num_ether_irq++; + OTEnterInterrupt(); + + // Send received packets to OpenTransport + net_packet *p = &net_buffer_ptr->read[rd_pos]; + while (p->cmd & IN_USE) { + if ((p->cmd >> 8) == SHEEP_PACKET) { + num_rx_packets++; + D(bug(" read packet pos %d\n", i)); + uint32 size = p->length; + +#if MONITOR + bug("Receiving Ethernet packet:\n"); + for (int i=0; idata[i]); + } + bug("\n"); +#endif + + // Wrap packet in message block + //!! maybe use esballoc() + mblk_t *mp; + if ((mp = allocb(size, 0)) != NULL) { + D(bug(" packet data at %p\n", mp->b_rptr)); + memcpy(mp->b_rptr, p->data, size); + mp->b_wptr += size; + ether_packet_received(mp); + } else { + D(bug("WARNING: Cannot allocate mblk for received packet\n")); + num_rx_no_mem++; + } + } + p->cmd = 0; // Free packet + rd_pos = (rd_pos + 1) % READ_PACKET_COUNT; + p = &net_buffer_ptr->read[rd_pos]; + } + OTLeaveInterrupt(); +} diff --git a/SheepShaver/src/BeOS/main_beos.cpp b/SheepShaver/src/BeOS/main_beos.cpp new file mode 100644 index 00000000..d0fa5185 --- /dev/null +++ b/SheepShaver/src/BeOS/main_beos.cpp @@ -0,0 +1,2185 @@ +/* + * main_beos.cpp - Emulation core, BeOS implementation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 + */ + +/* + * NOTES: + * + * SheepShaver uses three run-time environments, reflected by the value of XLM_RUN_MODE. + * The two modes which are also present in the original MacOS, are: + * MODE_68K - 68k emulator is active + * MODE_NATIVE - 68k emulator is inactive + * In the original MacOS, these two modes have different memory mappings and exception + * tables. Under SheepShaver, the only difference is the handling of interrupts (see below). + * SheepShaver extends the 68k emulator with special opcodes (EMUL_OP) to perform faster + * mode switches when patching 68k routines with PowerPC code and adds a third run mode: + * MODE_EMUL_OP - 68k emulator active, but native register usage + * + * Switches between MODE_68K and MODE_NATIVE are only done with the Mixed Mode Manager + * (via nanokernel patches). The switch from MODE_68K to MODE_EMUL_OP occurs when executin + * one of the EMUL_OP 68k opcodes. When the opcode routine is done, it returns to MODE_68K. + * + * The Execute68k() routine allows EMUL_OP routines to execute 68k subroutines. It switches + * from MODE_EMUL_OP back to MODE_68K, so it must not be used by native routines (executing + * in MODE_NATIVE) nor by any other thread than the emul_thread (because the 68k emulator + * is not reentrant). When the 68k subroutine returns, it switches back to MODE_EMUL_OP. + * It is OK for a 68k routine called with Execute68k() to contain an EMUL_OP opcode. + * + * The handling of interrupts depends on the current run mode: + * MODE_68K - The USR1 signal handler sets one bit in the processor's CR. The 68k emulator + * will then execute the 68k interrupt routine when fetching the next instruction. + * MODE_NATIVE - The USR1 signal handler switches back to the original stack (signals run + * on a separate signal stack) and enters the External Interrupt routine in the + * nanokernel. + * MODE_EMUL_OP - The USR1 signal handler directly executes the 68k interrupt routine + * with Execute68k(). Before doing this, it must first check the current 68k interrupt + * level which is stored in XLM_68K_R25. This variable is set to the current level + * when entering EMUL_OP mode. Execute68k() also uses it to restore the level so that + * Execute68k()'d routines will run at the same interrupt level as the EMUL_OP routine + * it was called from. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "main.h" +#include "version.h" +#include "prefs.h" +#include "prefs_editor.h" +#include "cpu_emulation.h" +#include "emul_op.h" +#include "xlowmem.h" +#include "xpram.h" +#include "timer.h" +#include "adb.h" +#include "sony.h" +#include "disk.h" +#include "cdrom.h" +#include "scsi.h" +#include "video.h" +#include "audio.h" +#include "ether.h" +#include "serial.h" +#include "clip.h" +#include "extfs.h" +#include "sys.h" +#include "macos_util.h" +#include "rom_patches.h" +#include "user_strings.h" + +#include "sheep_driver.h" + +#define DEBUG 0 +#include "debug.h" + +// Enable Execute68k() safety checks? +#define SAFE_EXEC_68K 0 + +// Save FP regs in Execute68k()? +#define SAVE_FP_EXEC_68K 0 + +// Interrupts in EMUL_OP mode? +#define INTERRUPTS_IN_EMUL_OP_MODE 1 + +// Interrupts in native mode? +#define INTERRUPTS_IN_NATIVE_MODE 1 + + +// Constants +const char APP_SIGNATURE[] = "application/x-vnd.cebix-SheepShaver"; +const char ROM_FILE_NAME[] = "ROM"; +const char ROM_FILE_NAME2[] = "Mac OS ROM"; +const char KERNEL_AREA_NAME[] = "Macintosh Kernel Data"; +const char KERNEL_AREA2_NAME[] = "Macintosh Kernel Data 2"; +const char RAM_AREA_NAME[] = "Macintosh RAM"; +const char ROM_AREA_NAME[] = "Macintosh ROM"; +const char DR_CACHE_AREA_NAME[] = "Macintosh DR Cache"; + +const uint32 ROM_AREA_SIZE = 0x500000; // Size of ROM area + +const uint32 KERNEL_DATA_BASE = 0x68ffe000; // Address of Kernel Data +const uint32 KERNEL_DATA2_BASE = 0x5fffe000;// Alternate address of Kernel Data +const uint32 KERNEL_AREA_SIZE = 0x2000; // Size of Kernel Data area + +const uint32 SIG_STACK_SIZE = 8192; // Size of signal stack + +const uint32 MSG_START = 'strt'; // Emulator start message + + +// Emulator Data +struct EmulatorData { + uint32 v[0x400]; +}; + + +// Kernel Data +struct KernelData { + uint32 v[0x400]; + EmulatorData ed; +}; + + +// Application object +class SheepShaver : public BApplication { +public: + SheepShaver() : BApplication(APP_SIGNATURE) + { + // Find application directory and cwd to it + app_info the_info; + GetAppInfo(&the_info); + BEntry the_file(&the_info.ref); + BEntry the_dir; + the_file.GetParent(&the_dir); + BPath the_path; + the_dir.GetPath(&the_path); + chdir(the_path.Path()); + + // Initialize other variables + sheep_fd = -1; + emulator_data = NULL; + kernel_area = kernel_area2 = rom_area = ram_area = dr_cache_area = -1; + emul_thread = nvram_thread = tick_thread = -1; + ReadyForSignals = false; + AllowQuitting = true; + NVRAMThreadActive = true; + TickThreadActive = true; + memset(last_xpram, 0, XPRAM_SIZE); + } + virtual void ReadyToRun(void); + virtual void MessageReceived(BMessage *msg); + void StartEmulator(void); + virtual bool QuitRequested(void); + virtual void Quit(void); + + thread_id emul_thread; // Emulator thread + thread_id nvram_thread; // NVRAM watchdog thread + thread_id tick_thread; // 60Hz thread + + KernelData *kernel_data; // Pointer to Kernel Data + EmulatorData *emulator_data; + + bool ReadyForSignals; // Flag: emul_thread ready to receive signals + bool AllowQuitting; // Flag: Alt-Q quitting allowed + bool NVRAMThreadActive; // nvram_thread will exit when this is false + bool TickThreadActive; // tick_thread will exit when this is false + + uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes + +private: + static status_t emul_func(void *arg); + static status_t nvram_func(void *arg); + static status_t tick_func(void *arg); + static void sigusr1_invoc(int sig, void *arg, vregs *r); + void sigusr1_handler(vregs *r); + static void sigsegv_invoc(int sig, void *arg, vregs *r); + static void sigill_invoc(int sig, void *arg, vregs *r); + void jump_to_rom(uint32 entry); + + void init_rom(void); + void load_rom(void); + + int sheep_fd; // FD of sheep driver + + area_id kernel_area; // Kernel Data area ID + area_id kernel_area2; // Alternate Kernel Data area ID + area_id rom_area; // ROM area ID + area_id ram_area; // RAM area ID + area_id dr_cache_area; // DR Cache area ID + + struct sigaction sigusr1_action; // Interrupt signal (of emulator thread) + struct sigaction sigsegv_action; // Data access exception signal (of emulator thread) + struct sigaction sigill_action; // Illegal instruction exception signal (of emulator thread) + + // Exceptions + class area_error {}; + class file_open_error {}; + class file_read_error {}; + class rom_size_error {}; +}; + + +// Global variables +SheepShaver *the_app; // Pointer to application object +#if !EMULATED_PPC +void *TOC; // TOC pointer +#endif +uint32 RAMBase; // Base address of Mac RAM +uint32 RAMSize; // Size of Mac RAM +uint32 KernelDataAddr; // Address of Kernel Data +uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM +uint32 DRCacheAddr; // Address of DR Cache +uint32 PVR; // Theoretical PVR +int64 CPUClockSpeed; // Processor clock speed (Hz) +int64 BusClockSpeed; // Bus clock speed (Hz) +system_info SysInfo; // System information + +static void *sig_stack = NULL; // Stack for signal handlers +static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler + + +// Prototypes +static void sigsegv_handler(vregs *r); +static void sigill_handler(vregs *r); + + +/* + * Create application object and start it + */ + +int main(int argc, char **argv) +{ + tzset(); + the_app = new SheepShaver(); + the_app->Run(); + delete the_app; + return 0; +} + + +/* + * Run application + */ + +#if !EMULATED_PPC +static asm void *get_toc(void) +{ + mr r3,r2 + blr +} +#endif + +void SheepShaver::ReadyToRun(void) +{ + // Print some info + printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); + printf(" %s\n", GetString(STR_ABOUT_TEXT2)); + +#if !EMULATED_PPC + // Get TOC pointer + TOC = get_toc(); +#endif + + // Get system info + get_system_info(&SysInfo); + switch (SysInfo.cpu_type) { + case B_CPU_PPC_601: + PVR = 0x00010000; + break; + case B_CPU_PPC_603: + PVR = 0x00030000; + break; + case B_CPU_PPC_603e: + PVR = 0x00060000; + break; + case B_CPU_PPC_604: + PVR = 0x00040000; + break; + case B_CPU_PPC_604e: + PVR = 0x00090000; + break; + case B_CPU_PPC_750: + PVR = 0x00080000; + break; + default: + PVR = 0x00040000; + break; + } + CPUClockSpeed = SysInfo.cpu_clock_speed; + BusClockSpeed = SysInfo.bus_clock_speed; + + // Delete old areas + area_id old_kernel_area = find_area(KERNEL_AREA_NAME); + if (old_kernel_area > 0) + delete_area(old_kernel_area); + area_id old_kernel2_area = find_area(KERNEL_AREA2_NAME); + if (old_kernel2_area > 0) + delete_area(old_kernel2_area); + area_id old_ram_area = find_area(RAM_AREA_NAME); + if (old_ram_area > 0) + delete_area(old_ram_area); + area_id old_rom_area = find_area(ROM_AREA_NAME); + if (old_rom_area > 0) + delete_area(old_rom_area); + area_id old_dr_cache_area = find_area(DR_CACHE_AREA_NAME); + if (old_dr_cache_area > 0) + delete_area(old_dr_cache_area); + + // Read preferences + int argc = 0; + char **argv = NULL; + PrefsInit(argc, argv); + + // Init system routines + SysInit(); + + // Test amount of RAM available for areas + if (SysInfo.max_pages * B_PAGE_SIZE < 16 * 1024 * 1024) { + ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); + PostMessage(B_QUIT_REQUESTED); + return; + } + + // Show preferences editor (or start emulator directly) + if (!PrefsFindBool("nogui")) + PrefsEditor(MSG_START); + else + PostMessage(MSG_START); +} + + +/* + * Message received + */ + +void SheepShaver::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case MSG_START: + StartEmulator(); + break; + default: + BApplication::MessageReceived(msg); + } +} + + +/* + * Start emulator + */ + +void SheepShaver::StartEmulator(void) +{ + char str[256]; + + // Open sheep driver and remap low memory + sheep_fd = open("/dev/sheep", 0); + if (sheep_fd < 0) { + sprintf(str, GetString(STR_NO_SHEEP_DRIVER_ERR), strerror(sheep_fd), sheep_fd); + ErrorAlert(str); + PostMessage(B_QUIT_REQUESTED); + return; + } + status_t res = ioctl(sheep_fd, SHEEP_UP); + if (res < 0) { + sprintf(str, GetString(STR_SHEEP_UP_ERR), strerror(res), res); + ErrorAlert(str); + PostMessage(B_QUIT_REQUESTED); + return; + } + + // Create areas for Kernel Data + kernel_data = (KernelData *)KERNEL_DATA_BASE; + kernel_area = create_area(KERNEL_AREA_NAME, &kernel_data, B_EXACT_ADDRESS, KERNEL_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + if (kernel_area < 0) { + sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(kernel_area), kernel_area); + ErrorAlert(str); + PostMessage(B_QUIT_REQUESTED); + return; + } + emulator_data = &kernel_data->ed; + KernelDataAddr = (uint32)kernel_data; + D(bug("Kernel Data area %ld at %p, Emulator Data at %p\n", kernel_area, kernel_data, emulator_data)); + + void *kernel_data2 = (void *)KERNEL_DATA2_BASE; + kernel_area2 = clone_area(KERNEL_AREA2_NAME, &kernel_data2, B_EXACT_ADDRESS, B_READ_AREA | B_WRITE_AREA, kernel_area); + if (kernel_area2 < 0) { + sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(kernel_area2), kernel_area2); + ErrorAlert(str); + PostMessage(B_QUIT_REQUESTED); + return; + } + D(bug("Kernel Data 2 area %ld at %p\n", kernel_area2, kernel_data2)); + + // Create area for Mac RAM + RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary + if (RAMSize < 8*1024*1024) { + WarningAlert(GetString(STR_SMALL_RAM_WARN)); + RAMSize = 8*1024*1024; + } + + RAMBase = 0x10000000; + ram_area = create_area(RAM_AREA_NAME, (void **)&RAMBase, B_BASE_ADDRESS, RAMSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + if (ram_area < 0) { + sprintf(str, GetString(STR_NO_RAM_AREA_ERR), strerror(ram_area), ram_area); + ErrorAlert(str); + PostMessage(B_QUIT_REQUESTED); + return; + } + D(bug("RAM area %ld at %p\n", ram_area, RAMBase)); + + // Create area and load Mac ROM + try { + init_rom(); + } catch (area_error) { + ErrorAlert(GetString(STR_NO_ROM_AREA_ERR)); + PostMessage(B_QUIT_REQUESTED); + return; + } catch (file_open_error) { + ErrorAlert(GetString(STR_NO_ROM_FILE_ERR)); + PostMessage(B_QUIT_REQUESTED); + return; + } catch (file_read_error) { + ErrorAlert(GetString(STR_ROM_FILE_READ_ERR)); + PostMessage(B_QUIT_REQUESTED); + return; + } catch (rom_size_error) { + ErrorAlert(GetString(STR_ROM_SIZE_ERR)); + PostMessage(B_QUIT_REQUESTED); + return; + } + + // Create area for DR Cache + DRCacheAddr = DR_CACHE_BASE; + dr_cache_area = create_area(DR_CACHE_AREA_NAME, (void **)&DRCacheAddr, B_EXACT_ADDRESS, DR_CACHE_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + if (dr_cache_area < 0) { + sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(dr_cache_area), dr_cache_area); + ErrorAlert(str); + PostMessage(B_QUIT_REQUESTED); + return; + } + D(bug("DR Cache area %ld at %p\n", dr_cache_area, DRCacheAddr)); + + // Load NVRAM + XPRAMInit(); + + // Set boot volume + drive = PrefsFindInt32("bootdrive"); + XPRAM[0x1378] = i16 >> 8; + XPRAM[0x1379] = i16 & 0xff; + driver = PrefsFindInt32("bootdriver"); + XPRAM[0x137a] = i16 >> 8; + XPRAM[0x137b] = i16 & 0xff; + + // Create BootGlobs at top of Mac memory + memset((void *)(RAMBase + RAMSize - 4096), 0, 4096); + BootGlobsAddr = RAMBase + RAMSize - 0x1c; + uint32 *boot_globs = (uint32 *)BootGlobsAddr; + boot_globs[-5] = htonl(RAMBase + RAMSize); // MemTop + boot_globs[0] = htonl(RAMBase); // First RAM bank + boot_globs[1] = htonl(RAMSize); + boot_globs[2] = htonl((uint32)-1); // End of bank table + + // Init drivers + SonyInit(); + DiskInit(); + CDROMInit(); + SCSIInit(); + + // Init external file system + ExtFSInit(); + + // Init audio + AudioInit(); + + // Init network + EtherInit(); + + // Init serial ports + SerialInit(); + + // Init Time Manager + TimerInit(); + + // Init clipboard + ClipInit(); + + // Init video + if (!VideoInit()) { + PostMessage(B_QUIT_REQUESTED); + return; + } + + // Install ROM patches + if (!PatchROM()) { + ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); + PostMessage(B_QUIT_REQUESTED); + return; + } + + // Clear caches (as we loaded and patched code) and write protect ROM +#if !EMULATED_PPC + clear_caches((void *)ROM_BASE, ROM_AREA_SIZE, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE); +#endif + set_area_protection(rom_area, B_READ_AREA); + + // Initialize Kernel Data + memset(kernel_data, 0, sizeof(KernelData)); + if (ROMType == ROMTYPE_NEWWORLD) { + static uint32 of_dev_tree[4] = {0, 0, 0, 0}; + static uint8 vector_lookup_tbl[128]; + static uint8 vector_mask_tbl[64]; + memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80); + memset(vector_lookup_tbl, 0, 128); + memset(vector_mask_tbl, 0, 64); + kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE); + kernel_data->v[0xb84 >> 2] = htonl((uint32)of_dev_tree); // OF device tree base + kernel_data->v[0xb90 >> 2] = htonl((uint32)vector_lookup_tbl); + kernel_data->v[0xb94 >> 2] = htonl((uint32)vector_mask_tbl); + kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE); // OpenPIC base + kernel_data->v[0xbb0 >> 2] = htonl(0); // ADB base + kernel_data->v[0xc20 >> 2] = htonl(RAMSize); + kernel_data->v[0xc24 >> 2] = htonl(RAMSize); + kernel_data->v[0xc30 >> 2] = htonl(RAMSize); + kernel_data->v[0xc34 >> 2] = htonl(RAMSize); + kernel_data->v[0xc38 >> 2] = htonl(0x00010020); + kernel_data->v[0xc3c >> 2] = htonl(0x00200001); + kernel_data->v[0xc40 >> 2] = htonl(0x00010000); + kernel_data->v[0xc50 >> 2] = htonl(RAMBase); + kernel_data->v[0xc54 >> 2] = htonl(RAMSize); + kernel_data->v[0xf60 >> 2] = htonl(PVR); + kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed); + kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed); + kernel_data->v[0xf6c >> 2] = htonl(CPUClockSpeed); + } else { + kernel_data->v[0xc80 >> 2] = htonl(RAMSize); + kernel_data->v[0xc84 >> 2] = htonl(RAMSize); + kernel_data->v[0xc90 >> 2] = htonl(RAMSize); + kernel_data->v[0xc94 >> 2] = htonl(RAMSize); + kernel_data->v[0xc98 >> 2] = htonl(0x00010020); + kernel_data->v[0xc9c >> 2] = htonl(0x00200001); + kernel_data->v[0xca0 >> 2] = htonl(0x00010000); + kernel_data->v[0xcb0 >> 2] = htonl(RAMBase); + kernel_data->v[0xcb4 >> 2] = htonl(RAMSize); + kernel_data->v[0xf80 >> 2] = htonl(PVR); + kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed); + kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed); + kernel_data->v[0xf8c >> 2] = htonl(CPUClockSpeed); + } + + // Initialize extra low memory + D(bug("Initializing Low Memory...\n")); + memset(NULL, 0, 0x3000); + WriteMacInt32(XLM_SIGNATURE, 'Baah'); // Signature to detect SheepShaver + WriteMacInt32(XLM_KERNEL_DATA, (uint32)kernel_data); // For trap replacement routines + WriteMacInt32(XLM_SHEEP_OBJ, (uint32)this); // Pointer to SheepShaver object + WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR + WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch + WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode) +#if !EMULATED_PPC + WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator + WriteMacInt32(XLM_ETHER_INIT, *(uint32 *)InitStreamModule); // DLPI ethernet driver functions + WriteMacInt32(XLM_ETHER_TERM, *(uint32 *)TerminateStreamModule); + WriteMacInt32(XLM_ETHER_OPEN, *(uint32 *)ether_open); + WriteMacInt32(XLM_ETHER_CLOSE, *(uint32 *)ether_close); + WriteMacInt32(XLM_ETHER_WPUT, *(uint32 *)ether_wput); + WriteMacInt32(XLM_ETHER_RSRV, *(uint32 *)ether_rsrv); + WriteMacInt32(XLM_VIDEO_DOIO, *(uint32 *)VideoDoDriverIO); +#endif + D(bug("Low Memory initialized\n")); + + // Disallow quitting with Alt-Q from now on + AllowQuitting = false; + + // Start 60Hz interrupt + tick_thread = spawn_thread(tick_func, "60Hz", B_URGENT_DISPLAY_PRIORITY, this); + resume_thread(tick_thread); + + // Start NVRAM watchdog thread + memcpy(last_xpram, XPRAM, XPRAM_SIZE); + nvram_thread = spawn_thread(nvram_func, "NVRAM Watchdog", B_LOW_PRIORITY, this); + resume_thread(nvram_thread); + + // Start emulator thread + emul_thread = spawn_thread(emul_func, "MacOS", B_NORMAL_PRIORITY, this); + resume_thread(emul_thread); +} + + +/* + * Quit requested + */ + +bool SheepShaver::QuitRequested(void) +{ + if (AllowQuitting) + return BApplication::QuitRequested(); + else + return false; +} + +void SheepShaver::Quit(void) +{ + status_t l; + + // Stop 60Hz interrupt + if (tick_thread > 0) { + TickThreadActive = false; + wait_for_thread(tick_thread, &l); + } + + // Stop NVRAM watchdog + if (nvram_thread > 0) { + status_t l; + NVRAMThreadActive = false; + suspend_thread(nvram_thread); // Wake thread up from snooze() + snooze(1000); + resume_thread(nvram_thread); + while (wait_for_thread(nvram_thread, &l) == B_INTERRUPTED) ; + } + + // Wait for emulator thread to finish + if (emul_thread > 0) + wait_for_thread(emul_thread, &l); + + // Save NVRAM + XPRAMExit(); + + // Exit clipboard + ClipExit(); + + // Exit Time Manager + TimerExit(); + + // Exit serial + SerialExit(); + + // Exit network + EtherExit(); + + // Exit audio + AudioExit(); + + // Exit video + VideoExit(); + + // Exit external file system + ExtFSExit(); + + // Exit drivers + SCSIExit(); + CDROMExit(); + DiskExit(); + SonyExit(); + + // Delete DR Cache area + if (dr_cache_area >= 0) + delete_area(dr_cache_area); + + // Delete ROM area + if (rom_area >= 0) + delete_area(rom_area); + + // Delete RAM area + if (ram_area >= 0) + delete_area(ram_area); + + // Delete Kernel Data area2 + if (kernel_area2 >= 0) + delete_area(kernel_area2); + if (kernel_area >= 0) + delete_area(kernel_area); + + // Unmap low memory and close sheep driver + if (sheep_fd >= 0) { + ioctl(sheep_fd, SHEEP_DOWN); + close(sheep_fd); + } + + // Exit system routines + SysExit(); + + // Exit preferences + PrefsExit(); + + BApplication::Quit(); +} + + +/* + * Create area for ROM (sets rom_area) and load ROM file + * + * area_error : Cannot create area + * file_open_error: Cannot open ROM file + * file_read_error: Cannot read ROM file + */ + +void SheepShaver::init_rom(void) +{ + // Create area for ROM + void *rom_addr = (void *)ROM_BASE; + rom_area = create_area(ROM_AREA_NAME, &rom_addr, B_EXACT_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); + if (rom_area < 0) + throw area_error(); + D(bug("ROM area %ld at %p\n", rom_area, rom_addr)); + + // Load ROM + load_rom(); +} + + +/* + * Load ROM file + * + * file_open_error: Cannot open ROM file (nor use built-in ROM) + * file_read_error: Cannot read ROM file + */ + +// Decode LZSS data +static void decode_lzss(const uint8 *src, uint8 *dest, int size) +{ + char dict[0x1000]; + int run_mask = 0, dict_idx = 0xfee; + for (;;) { + if (run_mask < 0x100) { + // Start new run + if (--size < 0) + break; + run_mask = *src++ | 0xff00; + } + bool bit = run_mask & 1; + run_mask >>= 1; + if (bit) { + // Verbatim copy + if (--size < 0) + break; + int c = *src++; + dict[dict_idx++] = c; + *dest++ = c; + dict_idx &= 0xfff; + } else { + // Copy from dictionary + if (--size < 0) + break; + int idx = *src++; + if (--size < 0) + break; + int cnt = *src++; + idx |= (cnt << 4) & 0xf00; + cnt = (cnt & 0x0f) + 3; + while (cnt--) { + char c = dict[idx++]; + dict[dict_idx++] = c; + *dest++ = c; + idx &= 0xfff; + dict_idx &= 0xfff; + } + } + } +} + +void SheepShaver::load_rom(void) +{ + // Get rom file path from preferences + const char *rom_path = PrefsFindString("rom"); + + // Try to open ROM file + BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY); + if (file.InitCheck() != B_NO_ERROR) { + + // Failed, then ask memory_mess driver for ROM + uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work + ssize_t actual = read(sheep_fd, (void *)rom, ROM_SIZE); + if (actual == ROM_SIZE) { + memcpy((void *)ROM_BASE, rom, ROM_SIZE); + delete[] rom; + return; + } else + throw file_open_error(); + } + + printf(GetString(STR_READING_ROM_FILE)); + + // Get file size + off_t rom_size = 0; + file.GetSize(&rom_size); + + uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work + ssize_t actual = file.Read((void *)rom, ROM_SIZE); + if (actual == ROM_SIZE) { + // Plain ROM image + memcpy((void *)ROM_BASE, rom, ROM_SIZE); + delete[] rom; + } else { + if (strncmp((char *)rom, "", 11) == 0) { + // CHRP compressed ROM image + D(bug("CHRP ROM image\n")); + uint32 lzss_offset, lzss_size; + + char *s = strstr((char *)rom, "constant lzss-offset"); + if (s == NULL) + throw rom_size_error(); + s -= 7; + if (sscanf(s, "%06lx", &lzss_offset) != 1) + throw rom_size_error(); + s = strstr((char *)rom, "constant lzss-size"); + if (s == NULL) + throw rom_size_error(); + s -= 7; + if (sscanf(s, "%06lx", &lzss_size) != 1) + throw rom_size_error(); + D(bug("Offset of compressed data: %08lx\n", lzss_offset)); + D(bug("Size of compressed data: %08lx\n", lzss_size)); + + D(bug("Uncompressing ROM...\n")); + decode_lzss(rom + lzss_offset, (uint8 *)ROM_BASE, lzss_size); + delete[] rom; + } else if (rom_size != 4*1024*1024) + throw rom_size_error(); + else + throw file_read_error(); + } +} + + +/* + * Emulator thread function + */ + +status_t SheepShaver::emul_func(void *arg) +{ + SheepShaver *obj = (SheepShaver *)arg; + + // Install interrupt signal handler + sigemptyset(&obj->sigusr1_action.sa_mask); + obj->sigusr1_action.sa_handler = (__signal_func_ptr)(obj->sigusr1_invoc); + obj->sigusr1_action.sa_flags = 0; + obj->sigusr1_action.sa_userdata = arg; + sigaction(SIGUSR1, &obj->sigusr1_action, NULL); + + // Install data access signal handler + sigemptyset(&obj->sigsegv_action.sa_mask); + obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc); + obj->sigsegv_action.sa_flags = 0; + obj->sigsegv_action.sa_userdata = arg; + sigaction(SIGSEGV, &obj->sigsegv_action, NULL); + +#if !EMULATED_PPC + // Install illegal instruction signal handler + sigemptyset(&obj->sigill_action.sa_mask); + obj->sigill_action.sa_handler = (__signal_func_ptr)(obj->sigill_invoc); + obj->sigill_action.sa_flags = 0; + obj->sigill_action.sa_userdata = arg; + sigaction(SIGILL, &obj->sigill_action, NULL); +#endif + + // Exceptions will send signals + disable_debugger(true); + + // Install signal stack + sig_stack = malloc(SIG_STACK_SIZE); + extra_stack = malloc(SIG_STACK_SIZE); + set_signal_stack(sig_stack, SIG_STACK_SIZE); + + // We're now ready to receive signals + obj->ReadyForSignals = true; + + // Jump to ROM boot routine + D(bug("Jumping to ROM\n")); + obj->jump_to_rom(ROM_BASE + 0x310000); + D(bug("Returned from ROM\n")); + + // We're no longer ready to receive signals + obj->ReadyForSignals = false; + obj->AllowQuitting = true; + + // Quit program + be_app->PostMessage(B_QUIT_REQUESTED); + return 0; +} + + +/* + * Jump into Mac ROM, start 680x0 emulator + * (also contains other EMUL_RETURN and EMUL_OP routines) + */ + +#if EMULATED_PPC +extern void emul_ppc(uint32 start); +extern void init_emul_ppc(void); +void SheepShaver::jump_to_rom(uint32 entry) +{ + init_emul_ppc(); + emul_ppc(entry); +} +#else +asm void SheepShaver::jump_to_rom(register uint32 entry) +{ + // Create stack frame + mflr r0 + stw r0,8(r1) + mfcr r0 + stw r0,4(r1) + stwu r1,-(56+19*4+18*8)(r1) + + // Save PowerPC registers + stmw r13,56(r1) + stfd f14,56+19*4+0*8(r1) + stfd f15,56+19*4+1*8(r1) + stfd f16,56+19*4+2*8(r1) + stfd f17,56+19*4+3*8(r1) + stfd f18,56+19*4+4*8(r1) + stfd f19,56+19*4+5*8(r1) + stfd f20,56+19*4+6*8(r1) + stfd f21,56+19*4+7*8(r1) + stfd f22,56+19*4+8*8(r1) + stfd f23,56+19*4+9*8(r1) + stfd f24,56+19*4+10*8(r1) + stfd f25,56+19*4+11*8(r1) + stfd f26,56+19*4+12*8(r1) + stfd f27,56+19*4+13*8(r1) + stfd f28,56+19*4+14*8(r1) + stfd f29,56+19*4+15*8(r1) + stfd f30,56+19*4+16*8(r1) + stfd f31,56+19*4+17*8(r1) + + // Move entry address to ctr, get pointer to Emulator Data + mtctr r4 + lwz r4,SheepShaver.emulator_data(r3) + + // Skip over EMUL_RETURN routine and get its address + bl @1 + + + /* + * EMUL_RETURN: Returned from emulator + */ + + // Restore PowerPC registers + lwz r1,XLM_EMUL_RETURN_STACK + lwz r2,XLM_TOC + lmw r13,56(r1) + lfd f14,56+19*4+0*8(r1) + lfd f15,56+19*4+1*8(r1) + lfd f16,56+19*4+2*8(r1) + lfd f17,56+19*4+3*8(r1) + lfd f18,56+19*4+4*8(r1) + lfd f19,56+19*4+5*8(r1) + lfd f20,56+19*4+6*8(r1) + lfd f21,56+19*4+7*8(r1) + lfd f22,56+19*4+8*8(r1) + lfd f23,56+19*4+9*8(r1) + lfd f24,56+19*4+10*8(r1) + lfd f25,56+19*4+11*8(r1) + lfd f26,56+19*4+12*8(r1) + lfd f27,56+19*4+13*8(r1) + lfd f28,56+19*4+14*8(r1) + lfd f29,56+19*4+15*8(r1) + lfd f30,56+19*4+16*8(r1) + lfd f31,56+19*4+17*8(r1) + + // Exiting from 68k emulator + li r0,1 + stw r0,XLM_IRQ_NEST + li r0,MODE_NATIVE + stw r0,XLM_RUN_MODE + + // Return to caller of jump_to_rom() + lwz r0,56+19*4+18*8+8(r1) + mtlr r0 + lwz r0,56+19*4+18*8+4(r1) + mtcrf 0xff,r0 + addi r1,r1,56+19*4+18*8 + blr + + + // Save address of EMUL_RETURN routine for 68k emulator patch +@1 mflr r0 + stw r0,XLM_EMUL_RETURN_PROC + + // Skip over EXEC_RETURN routine and get its address + bl @2 + + + /* + * EXEC_RETURN: Returned from 68k routine executed with Execute68k() + */ + + // Save r25 (contains current 68k interrupt level) + stw r25,XLM_68K_R25 + + // Reentering EMUL_OP mode + li r0,MODE_EMUL_OP + stw r0,XLM_RUN_MODE + + // Save 68k registers + lwz r4,56+19*4+18*8+12(r1) + stw r8,M68kRegisters.d[0](r4) + stw r9,M68kRegisters.d[1](r4) + stw r10,M68kRegisters.d[2](r4) + stw r11,M68kRegisters.d[3](r4) + stw r12,M68kRegisters.d[4](r4) + stw r13,M68kRegisters.d[5](r4) + stw r14,M68kRegisters.d[6](r4) + stw r15,M68kRegisters.d[7](r4) + stw r16,M68kRegisters.a[0](r4) + stw r17,M68kRegisters.a[1](r4) + stw r18,M68kRegisters.a[2](r4) + stw r19,M68kRegisters.a[3](r4) + stw r20,M68kRegisters.a[4](r4) + stw r21,M68kRegisters.a[5](r4) + stw r22,M68kRegisters.a[6](r4) + + // Restore PowerPC registers + lmw r13,56(r1) +#if SAVE_FP_EXEC_68K + lfd f14,56+19*4+0*8(r1) + lfd f15,56+19*4+1*8(r1) + lfd f16,56+19*4+2*8(r1) + lfd f17,56+19*4+3*8(r1) + lfd f18,56+19*4+4*8(r1) + lfd f19,56+19*4+5*8(r1) + lfd f20,56+19*4+6*8(r1) + lfd f21,56+19*4+7*8(r1) + lfd f22,56+19*4+8*8(r1) + lfd f23,56+19*4+9*8(r1) + lfd f24,56+19*4+10*8(r1) + lfd f25,56+19*4+11*8(r1) + lfd f26,56+19*4+12*8(r1) + lfd f27,56+19*4+13*8(r1) + lfd f28,56+19*4+14*8(r1) + lfd f29,56+19*4+15*8(r1) + lfd f30,56+19*4+16*8(r1) + lfd f31,56+19*4+17*8(r1) +#endif + + // Return to caller + lwz r0,56+19*4+18*8+8(r1) + mtlr r0 + addi r1,r1,56+19*4+18*8 + blr + + + // Stave address of EXEC_RETURN routine for 68k emulator patch +@2 mflr r0 + stw r0,XLM_EXEC_RETURN_PROC + + // Skip over EMUL_BREAK/EMUL_OP routine and get its address + bl @3 + + + /* + * EMUL_BREAK/EMUL_OP: Execute native routine, selector in r5 (my own private mode switch) + * + * 68k registers are stored in a M68kRegisters struct on the stack + * which the native routine may read and modify + */ + + // Save r25 (contains current 68k interrupt level) + stw r25,XLM_68K_R25 + + // Entering EMUL_OP mode within 68k emulator + li r0,MODE_EMUL_OP + stw r0,XLM_RUN_MODE + + // Create PowerPC stack frame, reserve space for M68kRegisters + mr r3,r1 + subi r1,r1,56 // Fake "caller" frame + rlwinm r1,r1,0,0,29 // Align stack + + mfcr r0 + rlwinm r0,r0,0,11,8 + stw r0,4(r1) + mfxer r0 + stw r0,16(r1) + stw r2,12(r1) + stwu r1,-(56+16*4+15*8)(r1) + lwz r2,XLM_TOC + + // Save 68k registers + stw r8,56+M68kRegisters.d[0](r1) + stw r9,56+M68kRegisters.d[1](r1) + stw r10,56+M68kRegisters.d[2](r1) + stw r11,56+M68kRegisters.d[3](r1) + stw r12,56+M68kRegisters.d[4](r1) + stw r13,56+M68kRegisters.d[5](r1) + stw r14,56+M68kRegisters.d[6](r1) + stw r15,56+M68kRegisters.d[7](r1) + stw r16,56+M68kRegisters.a[0](r1) + stw r17,56+M68kRegisters.a[1](r1) + stw r18,56+M68kRegisters.a[2](r1) + stw r19,56+M68kRegisters.a[3](r1) + stw r20,56+M68kRegisters.a[4](r1) + stw r21,56+M68kRegisters.a[5](r1) + stw r22,56+M68kRegisters.a[6](r1) + stw r3,56+M68kRegisters.a[7](r1) + stfd f0,56+16*4+0*8(r1) + stfd f1,56+16*4+1*8(r1) + stfd f2,56+16*4+2*8(r1) + stfd f3,56+16*4+3*8(r1) + stfd f4,56+16*4+4*8(r1) + stfd f5,56+16*4+5*8(r1) + stfd f6,56+16*4+6*8(r1) + stfd f7,56+16*4+7*8(r1) + mffs f0 + stfd f8,56+16*4+8*8(r1) + stfd f9,56+16*4+9*8(r1) + stfd f10,56+16*4+10*8(r1) + stfd f11,56+16*4+11*8(r1) + stfd f12,56+16*4+12*8(r1) + stfd f13,56+16*4+13*8(r1) + stfd f0,56+16*4+14*8(r1) + + // Execute native routine + addi r3,r1,56 + mr r4,r24 + bl EmulOp + + // Restore 68k registers + lwz r8,56+M68kRegisters.d[0](r1) + lwz r9,56+M68kRegisters.d[1](r1) + lwz r10,56+M68kRegisters.d[2](r1) + lwz r11,56+M68kRegisters.d[3](r1) + lwz r12,56+M68kRegisters.d[4](r1) + lwz r13,56+M68kRegisters.d[5](r1) + lwz r14,56+M68kRegisters.d[6](r1) + lwz r15,56+M68kRegisters.d[7](r1) + lwz r16,56+M68kRegisters.a[0](r1) + lwz r17,56+M68kRegisters.a[1](r1) + lwz r18,56+M68kRegisters.a[2](r1) + lwz r19,56+M68kRegisters.a[3](r1) + lwz r20,56+M68kRegisters.a[4](r1) + lwz r21,56+M68kRegisters.a[5](r1) + lwz r22,56+M68kRegisters.a[6](r1) + lwz r3,56+M68kRegisters.a[7](r1) + lfd f13,56+16*4+14*8(r1) + lfd f0,56+16*4+0*8(r1) + lfd f1,56+16*4+1*8(r1) + lfd f2,56+16*4+2*8(r1) + lfd f3,56+16*4+3*8(r1) + lfd f4,56+16*4+4*8(r1) + lfd f5,56+16*4+5*8(r1) + lfd f6,56+16*4+6*8(r1) + lfd f7,56+16*4+7*8(r1) + mtfsf 0xff,f13 + lfd f8,56+16*4+8*8(r1) + lfd f9,56+16*4+9*8(r1) + lfd f10,56+16*4+10*8(r1) + lfd f11,56+16*4+11*8(r1) + lfd f12,56+16*4+12*8(r1) + lfd f13,56+16*4+13*8(r1) + + // Delete PowerPC stack frame + lwz r2,56+16*4+15*8+12(r1) + lwz r0,56+16*4+15*8+16(r1) + mtxer r0 + lwz r0,56+16*4+15*8+4(r1) + mtcrf 0xff,r0 + mr r1,r3 + + // Reeintering 68k emulator + li r0,MODE_68K + stw r0,XLM_RUN_MODE + + // Set r0 to 0 for 68k emulator + li r0,0 + + // Execute next 68k opcode + rlwimi r29,r27,3,13,28 + lhau r27,2(r24) + mtlr r29 + blr + + + // Save address of EMUL_BREAK/EMUL_OP routine for 68k emulator patch +@3 mflr r0 + stw r0,XLM_EMUL_OP_PROC + + // Save stack pointer for EMUL_RETURN + stw r1,XLM_EMUL_RETURN_STACK + + // Preset registers for ROM boot routine + lis r3,0x40b0 // Pointer to ROM boot structure + ori r3,r3,0xd000 + + // 68k emulator is now active + li r0,MODE_68K + stw r0,XLM_RUN_MODE + + // Jump to ROM + bctr +} +#endif + + +#if !EMULATED_PPC +/* + * Execute 68k subroutine (must be ended with RTS) + * This must only be called by the emul_thread when in EMUL_OP mode + * r->a[7] is unused, the routine runs on the caller's stack + */ + +#if SAFE_EXEC_68K +void execute_68k(uint32 pc, M68kRegisters *r); + +void Execute68k(uint32 pc, M68kRegisters *r) +{ + if (*(uint32 *)XLM_RUN_MODE != MODE_EMUL_OP) + printf("FATAL: Execute68k() not called from EMUL_OP mode\n"); + if (find_thread(NULL) != the_app->emul_thread) + printf("FATAL: Execute68k() not called from emul_thread\n"); + execute_68k(pc, r); +} + +asm void execute_68k(register uint32 pc, register M68kRegisters *r) +#else +asm void Execute68k(register uint32 pc, register M68kRegisters *r) +#endif +{ + // Create stack frame + mflr r0 + stw r0,8(r1) + stw r4,12(r1) + stwu r1,-(56+19*4+18*8)(r1) + + // Save PowerPC registers + stmw r13,56(r1) +#if SAVE_FP_EXEC_68K + stfd f14,56+19*4+0*8(r1) + stfd f15,56+19*4+1*8(r1) + stfd f16,56+19*4+2*8(r1) + stfd f17,56+19*4+3*8(r1) + stfd f18,56+19*4+4*8(r1) + stfd f19,56+19*4+5*8(r1) + stfd f20,56+19*4+6*8(r1) + stfd f21,56+19*4+7*8(r1) + stfd f22,56+19*4+8*8(r1) + stfd f23,56+19*4+9*8(r1) + stfd f24,56+19*4+10*8(r1) + stfd f25,56+19*4+11*8(r1) + stfd f26,56+19*4+12*8(r1) + stfd f27,56+19*4+13*8(r1) + stfd f28,56+19*4+14*8(r1) + stfd f29,56+19*4+15*8(r1) + stfd f30,56+19*4+16*8(r1) + stfd f31,56+19*4+17*8(r1) +#endif + + // Set up registers for 68k emulator + lwz r31,XLM_KERNEL_DATA // Pointer to Kernel Data + addi r31,r31,0x1000 + li r0,0 + mtcrf 0xff,r0 + creqv 11,11,11 // Supervisor mode + lwz r8,M68kRegisters.d[0](r4) + lwz r9,M68kRegisters.d[1](r4) + lwz r10,M68kRegisters.d[2](r4) + lwz r11,M68kRegisters.d[3](r4) + lwz r12,M68kRegisters.d[4](r4) + lwz r13,M68kRegisters.d[5](r4) + lwz r14,M68kRegisters.d[6](r4) + lwz r15,M68kRegisters.d[7](r4) + lwz r16,M68kRegisters.a[0](r4) + lwz r17,M68kRegisters.a[1](r4) + lwz r18,M68kRegisters.a[2](r4) + lwz r19,M68kRegisters.a[3](r4) + lwz r20,M68kRegisters.a[4](r4) + lwz r21,M68kRegisters.a[5](r4) + lwz r22,M68kRegisters.a[6](r4) + li r23,0 + mr r24,r3 + lwz r25,XLM_68K_R25 // MSB of SR + li r26,0 + li r28,0 // VBR + lwz r29,0x74(r31) // Pointer to opcode table + lwz r30,0x78(r31) // Address of emulator + + // Push return address (points to EXEC_RETURN opcode) on stack + li r0,XLM_EXEC_RETURN_OPCODE + stwu r0,-4(r1) + + // Reentering 68k emulator + li r0,MODE_68K + stw r0,XLM_RUN_MODE + + // Set r0 to 0 for 68k emulator + li r0,0 + + // Execute 68k opcode + lha r27,0(r24) + rlwimi r29,r27,3,13,28 + lhau r27,2(r24) + mtlr r29 + blr +} + + +/* + * Execute 68k A-Trap from EMUL_OP routine + * r->a[7] is unused, the routine runs on the caller's stack + */ + +void Execute68kTrap(uint16 trap, M68kRegisters *r) +{ + uint16 proc[2] = {trap, M68K_RTS}; + Execute68k((uint32)proc, r); +} + + +/* + * Execute PPC code from EMUL_OP routine (real mode switch) + */ + +void ExecutePPC(void (*func)()) +{ + RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, func); + M68kRegisters r; + Execute68k((uint32)&desc, &r); +} + + +/* + * Quit emulator (must only be called from main thread) + */ + +asm void QuitEmulator(void) +{ + lwz r0,XLM_EMUL_RETURN_PROC + mtlr r0 + blr +} +#endif + + +/* + * Dump 68k registers + */ + +void Dump68kRegs(M68kRegisters *r) +{ + // Display 68k registers + for (int i=0; i<8; i++) { + printf("d%d: %08lx", i, r->d[i]); + if (i == 3 || i == 7) + printf("\n"); + else + printf(", "); + } + for (int i=0; i<8; i++) { + printf("a%d: %08lx", i, r->a[i]); + if (i == 3 || i == 7) + printf("\n"); + else + printf(", "); + } +} + + +/* + * Make code executable + */ + +void MakeExecutable(int dummy, void *start, uint32 length) +{ + if (((uint32)start >= ROM_BASE) && ((uint32)start < (ROM_BASE + ROM_SIZE))) + return; + clear_caches(start, length, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE); +} + + +/* + * Patch things after system startup (gets called by disk driver accRun routine) + */ + +void PatchAfterStartup(void) +{ + ExecutePPC(VideoInstallAccel); + InstallExtFS(); +} + + +/* + * NVRAM watchdog thread (saves NVRAM every minute) + */ + +static status_t SheepShaver::nvram_func(void *arg) +{ + SheepShaver *obj = (SheepShaver *)arg; + + while (obj->NVRAMThreadActive) { + snooze(60*1000000); + if (memcmp(obj->last_xpram, XPRAM, XPRAM_SIZE)) { + memcpy(obj->last_xpram, XPRAM, XPRAM_SIZE); + SaveXPRAM(); + } + } + return 0; +} + + +/* + * 60Hz thread (really 60.15Hz) + */ + +status_t SheepShaver::tick_func(void *arg) +{ + SheepShaver *obj = (SheepShaver *)arg; + int tick_counter = 0; + bigtime_t current = system_time(); + + while (obj->TickThreadActive) { + + // Wait + current += 16625; + snooze_until(current, B_SYSTEM_TIMEBASE); + + // Pseudo Mac 1Hz interrupt, update local time + if (++tick_counter > 60) { + tick_counter = 0; + WriteMacInt32(0x20c, TimerDateTime()); + } + + // 60Hz interrupt + if (ReadMacInt32(XLM_IRQ_NEST) == 0) { + SetInterruptFlag(INTFLAG_VIA); + TriggerInterrupt(); + } + } + return 0; +} + + +/* + * Trigger signal USR1 from another thread + */ + +void TriggerInterrupt(void) +{ +#if 0 + WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); +#else + if (the_app->emul_thread > 0 && the_app->ReadyForSignals) + send_signal(the_app->emul_thread, SIGUSR1); +#endif +} + + +/* + * Mutexes + */ + +struct B2_mutex { + int dummy; //!! +}; + +B2_mutex *B2_create_mutex(void) +{ + return new B2_mutex; +} + +void B2_lock_mutex(B2_mutex *mutex) +{ +} + +void B2_unlock_mutex(B2_mutex *mutex) +{ +} + +void B2_delete_mutex(B2_mutex *mutex) +{ + delete mutex; +} + + +/* + * Set/clear interrupt flags (must be done atomically!) + */ + +volatile uint32 InterruptFlags = 0; + +void SetInterruptFlag(uint32 flag) +{ + atomic_or((int32 *)&InterruptFlags, flag); +} + +void ClearInterruptFlag(uint32 flag) +{ + atomic_and((int32 *)&InterruptFlags, ~flag); +} + + +/* + * Disable interrupts + */ + +void DisableInterrupt(void) +{ + atomic_add((int32 *)XLM_IRQ_NEST, 1); +} + + +/* + * Enable interrupts + */ + +void EnableInterrupt(void) +{ + atomic_add((int32 *)XLM_IRQ_NEST, -1); +} + + +/* + * USR1 handler + */ + +void SheepShaver::sigusr1_invoc(int sig, void *arg, vregs *r) +{ + ((SheepShaver *)arg)->sigusr1_handler(r); +} + +#if !EMULATED_PPC +static asm void ppc_interrupt(register uint32 entry) +{ + fralloc + + // Get address of return routine + bl @1 + + // Return routine + frfree + blr + +@1 + // Prepare registers for nanokernel interrupt routine + mtctr r1 + lwz r1,XLM_KERNEL_DATA + stw r6,0x018(r1) + mfctr r6 + stw r6,0x004(r1) + lwz r6,0x65c(r1) + stw r7,0x13c(r6) + stw r8,0x144(r6) + stw r9,0x14c(r6) + stw r10,0x154(r6) + stw r11,0x15c(r6) + stw r12,0x164(r6) + stw r13,0x16c(r6) + + mflr r10 + mfcr r13 + lwz r7,0x660(r1) + mflr r12 + rlwimi. r7,r7,8,0,0 + li r11,0 + ori r11,r11,0xf072 // MSR (SRR1) + mtcrf 0x70,r11 + li r8,0 + + // Enter nanokernel + mtlr r3 + blr +} +#endif + +void SheepShaver::sigusr1_handler(vregs *r) +{ + // Do nothing if interrupts are disabled + if ((*(int32 *)XLM_IRQ_NEST) > 0) + return; + + // Interrupt action depends on current run mode + switch (*(uint32 *)XLM_RUN_MODE) { + case MODE_68K: + // 68k emulator active, trigger 68k interrupt level 1 + *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1; + r->cr |= kernel_data->v[0x674 >> 2]; + break; + +#if INTERRUPTS_IN_NATIVE_MODE + case MODE_NATIVE: + // 68k emulator inactive, in nanokernel? + if (r->r1 != KernelDataAddr) { + // No, prepare for 68k interrupt level 1 + *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1; + *(uint32 *)(kernel_data->v[0x658 >> 2] + 0xdc) |= kernel_data->v[0x674 >> 2]; + + // Execute nanokernel interrupt routine (this will activate the 68k emulator) + atomic_add((int32 *)XLM_IRQ_NEST, 1); + if (ROMType == ROMTYPE_NEWWORLD) + ppc_interrupt(ROM_BASE + 0x312b1c); + else + ppc_interrupt(ROM_BASE + 0x312a3c); + } + break; +#endif + +#if INTERRUPTS_IN_EMUL_OP_MODE + case MODE_EMUL_OP: + // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 + if ((*(uint32 *)XLM_68K_R25 & 7) == 0) { + + // Set extra stack for SIGSEGV handler + set_signal_stack(extra_stack, SIG_STACK_SIZE); +#if 1 + // Execute full 68k interrupt routine + M68kRegisters r; + uint32 old_r25 = *(uint32 *)XLM_68K_R25; // Save interrupt level + *(uint32 *)XLM_68K_R25 = 0x21; // Execute with interrupt level 1 + static const uint16 proc[] = { + 0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word) + 0x487a, 0x000a, // pea @1(pc) (return address) + 0x40e7, // move sr,-(sp) (saved SR) + 0x2078, 0x0064, // move.l $64,a0 + 0x4ed0, // jmp (a0) + M68K_RTS // @1 + }; + Execute68k((uint32)proc, &r); + *(uint32 *)XLM_68K_R25 = old_r25; // Restore interrupt level +#else + // Only update cursor + if (HasMacStarted()) { + if (InterruptFlags & INTFLAG_VIA) { + ClearInterruptFlag(INTFLAG_VIA); + ADBInterrupt(); + ExecutePPC(VideoVBL); + } + } +#endif + // Reset normal signal stack + set_signal_stack(sig_stack, SIG_STACK_SIZE); + } + break; +#endif + } +} + + +/* + * SIGSEGV handler + */ + +static uint32 segv_r[32]; + +#if !EMULATED_PPC +asm void SheepShaver::sigsegv_invoc(register int sig, register void *arg, register vregs *r) +{ + mflr r0 + stw r0,8(r1) + stwu r1,-56(r1) + + lwz r3,segv_r(r2) + stmw r13,13*4(r3) + + mr r3,r5 + bl sigsegv_handler + + lwz r3,segv_r(r2) + lmw r13,13*4(r3) + + lwz r0,56+8(r1) + mtlr r0 + addi r1,r1,56 + blr +} +#endif + +static void sigsegv_handler(vregs *r) +{ + char str[256]; + + // Fetch volatile registers + segv_r[0] = r->r0; + segv_r[1] = r->r1; + segv_r[2] = r->r2; + segv_r[3] = r->r3; + segv_r[4] = r->r4; + segv_r[5] = r->r5; + segv_r[6] = r->r6; + segv_r[7] = r->r7; + segv_r[8] = r->r8; + segv_r[9] = r->r9; + segv_r[10] = r->r10; + segv_r[11] = r->r11; + segv_r[12] = r->r12; + + // Get opcode and divide into fields + uint32 opcode = *(uint32 *)r->pc; + uint32 primop = opcode >> 26; + uint32 exop = (opcode >> 1) & 0x3ff; + uint32 ra = (opcode >> 16) & 0x1f; + uint32 rb = (opcode >> 11) & 0x1f; + uint32 rd = (opcode >> 21) & 0x1f; + uint32 imm = opcode & 0xffff; + + // Fault in Mac ROM or RAM? + bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize)); + if (mac_fault) { + + // "VM settings" during MacOS 8 installation + if (r->pc == ROM_BASE + 0x488160 && segv_r[20] == 0xf8000000) { + r->pc += 4; + segv_r[8] = 0; + goto rti; + + // MacOS 8.5 installation + } else if (r->pc == ROM_BASE + 0x488140 && segv_r[16] == 0xf8000000) { + r->pc += 4; + segv_r[8] = 0; + goto rti; + + // MacOS 8 serial drivers on startup + } else if (r->pc == ROM_BASE + 0x48e080 && (segv_r[8] == 0xf3012002 || segv_r[8] == 0xf3012000)) { + r->pc += 4; + segv_r[8] = 0; + goto rti; + + // MacOS 8.1 serial drivers on startup + } else if (r->pc == ROM_BASE + 0x48c5e0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) { + r->pc += 4; + goto rti; + } else if (r->pc == ROM_BASE + 0x4a10a0 && (segv_r[20] == 0xf3012002 || segv_r[20] == 0xf3012000)) { + r->pc += 4; + goto rti; + } + } + + // Analyze opcode + enum { + TYPE_UNKNOWN, + TYPE_LOAD, + TYPE_STORE + } transfer_type = TYPE_UNKNOWN; + enum { + SIZE_UNKNOWN, + SIZE_BYTE, + SIZE_HALFWORD, + SIZE_WORD + } transfer_size = SIZE_UNKNOWN; + enum { + MODE_UNKNOWN, + MODE_NORM, + MODE_U, + MODE_X, + MODE_UX + } addr_mode = MODE_UNKNOWN; + switch (primop) { + case 31: + switch (exop) { + case 23: // lwzx + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; + case 55: // lwzux + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; + case 87: // lbzx + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; + case 119: // lbzux + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; + case 151: // stwx + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; + case 183: // stwux + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; + case 215: // stbx + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; + case 247: // stbux + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; + case 279: // lhzx + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; + case 311: // lhzux + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; + case 343: // lhax + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; + case 375: // lhaux + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; + case 407: // sthx + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; + case 439: // sthux + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; + } + break; + + case 32: // lwz + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; + case 33: // lwzu + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; + case 34: // lbz + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; + case 35: // lbzu + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; + case 36: // stw + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; + case 37: // stwu + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; + case 38: // stb + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; + case 39: // stbu + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; + case 40: // lhz + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; + case 41: // lhzu + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; + case 42: // lha + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; + case 43: // lhau + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; + case 44: // sth + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; + case 45: // sthu + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; + } + + // Calculate effective address + uint32 addr = 0; + switch (addr_mode) { + case MODE_X: + case MODE_UX: + if (ra == 0) + addr = segv_r[rb]; + else + addr = segv_r[ra] + segv_r[rb]; + break; + case MODE_NORM: + case MODE_U: + if (ra == 0) + addr = (int32)(int16)imm; + else + addr = segv_r[ra] + (int32)(int16)imm; + break; + default: + break; + } + + // Ignore ROM writes + if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) { + D(bug("WARNING: %s write access to ROM at %p, pc %p\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc)); + if (addr_mode == MODE_U || addr_mode == MODE_UX) + segv_r[ra] = addr; + r->pc += 4; + goto rti; + } + + // Fault in Mac ROM or RAM? + if (mac_fault) { + + // Ignore illegal memory accesses? + if (PrefsFindBool("ignoresegv")) { + if (addr_mode == MODE_U || addr_mode == MODE_UX) + segv_r[ra] = addr; + if (transfer_type == TYPE_LOAD) + segv_r[rd] = 0; + r->pc += 4; + goto rti; + } + + // In GUI mode, show error alert + if (!PrefsFindBool("nogui")) { + if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE) + sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->pc, segv_r[24], segv_r[1]); + else + sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode); + ErrorAlert(str); + QuitEmulator(); + return; + } + } + + // For all other errors, jump into debugger + sprintf(str, "SIGSEGV\n" + " pc %08lx lr %08lx ctr %08lx msr %08lx\n" + " xer %08lx cr %08lx fpscr %08lx\n" + " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n" + " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n" + " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n" + " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n" + " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n" + " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" + " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" + " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", + r->pc, r->lr, r->ctr, r->msr, + r->xer, r->cr, r->fpscr, + r->r0, r->r1, r->r2, r->r3, + r->r4, r->r5, r->r6, r->r7, + r->r8, r->r9, r->r10, r->r11, + r->r12, segv_r[13], segv_r[14], segv_r[15], + segv_r[16], segv_r[17], segv_r[18], segv_r[19], + segv_r[20], segv_r[21], segv_r[22], segv_r[23], + segv_r[24], segv_r[25], segv_r[26], segv_r[27], + segv_r[28], segv_r[29], segv_r[30], segv_r[31]); + VideoQuitFullScreen(); + disable_debugger(false); + debugger(str); + exit(1); + return; + +rti: + // Restore volatile registers + r->r0 = segv_r[0]; + r->r1 = segv_r[1]; + r->r2 = segv_r[2]; + r->r3 = segv_r[3]; + r->r4 = segv_r[4]; + r->r5 = segv_r[5]; + r->r6 = segv_r[6]; + r->r7 = segv_r[7]; + r->r8 = segv_r[8]; + r->r9 = segv_r[9]; + r->r10 = segv_r[10]; + r->r11 = segv_r[11]; + r->r12 = segv_r[12]; +} + + +/* + * SIGILL handler + */ + +#if !EMULATED_PPC +asm void SheepShaver::sigill_invoc(register int sig, register void *arg, register vregs *r) +{ + mflr r0 + stw r0,8(r1) + stwu r1,-56(r1) + + lwz r3,segv_r(r2) + stmw r13,13*4(r3) + + mr r3,r5 + bl sigill_handler + + lwz r3,segv_r(r2) + lmw r13,13*4(r3) + + lwz r0,56+8(r1) + mtlr r0 + addi r1,r1,56 + blr +} +#endif + +static void sigill_handler(vregs *r) +{ + char str[256]; + + // Fetch volatile registers + segv_r[0] = r->r0; + segv_r[1] = r->r1; + segv_r[2] = r->r2; + segv_r[3] = r->r3; + segv_r[4] = r->r4; + segv_r[5] = r->r5; + segv_r[6] = r->r6; + segv_r[7] = r->r7; + segv_r[8] = r->r8; + segv_r[9] = r->r9; + segv_r[10] = r->r10; + segv_r[11] = r->r11; + segv_r[12] = r->r12; + + // Get opcode and divide into fields + uint32 opcode = *(uint32 *)r->pc; + uint32 primop = opcode >> 26; + uint32 exop = (opcode >> 1) & 0x3ff; + uint32 ra = (opcode >> 16) & 0x1f; + uint32 rb = (opcode >> 11) & 0x1f; + uint32 rd = (opcode >> 21) & 0x1f; + uint32 imm = opcode & 0xffff; + + // Fault in Mac ROM or RAM? + bool mac_fault = (r->pc >= ROM_BASE) && (r->pc < (ROM_BASE + ROM_AREA_SIZE)) || (r->pc >= RAMBase) && (r->pc < (RAMBase + RAMSize)); + if (mac_fault) { + + switch (primop) { + case 9: // POWER instructions + case 22: +power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->pc, segv_r[1], opcode); + ErrorAlert(str); + QuitEmulator(); + return; + + case 31: + switch (exop) { + case 83: // mfmsr + segv_r[rd] = 0xf072; + r->pc += 4; + goto rti; + + case 210: // mtsr + case 242: // mtsrin + case 306: // tlbie + r->pc += 4; + goto rti; + + case 339: { // mfspr + int spr = ra | (rb << 5); + switch (spr) { + case 0: // MQ + case 22: // DEC + case 952: // MMCR0 + case 953: // PMC1 + case 954: // PMC2 + case 955: // SIA + case 956: // MMCR1 + case 957: // PMC3 + case 958: // PMC4 + case 959: // SDA + r->pc += 4; + goto rti; + case 25: // SDR1 + segv_r[rd] = 0xdead001f; + r->pc += 4; + goto rti; + case 287: // PVR + segv_r[rd] = PVR; + r->pc += 4; + goto rti; + } + break; + } + + case 467: { // mtspr + int spr = ra | (rb << 5); + switch (spr) { + case 0: // MQ + case 22: // DEC + case 275: // SPRG3 + case 528: // IBAT0U + case 529: // IBAT0L + case 530: // IBAT1U + case 531: // IBAT1L + case 532: // IBAT2U + case 533: // IBAT2L + case 534: // IBAT3U + case 535: // IBAT3L + case 536: // DBAT0U + case 537: // DBAT0L + case 538: // DBAT1U + case 539: // DBAT1L + case 540: // DBAT2U + case 541: // DBAT2L + case 542: // DBAT3U + case 543: // DBAT3L + case 952: // MMCR0 + case 953: // PMC1 + case 954: // PMC2 + case 955: // SIA + case 956: // MMCR1 + case 957: // PMC3 + case 958: // PMC4 + case 959: // SDA + r->pc += 4; + goto rti; + } + break; + } + + case 29: case 107: case 152: case 153: // POWER instructions + case 184: case 216: case 217: case 248: + case 264: case 277: case 331: case 360: + case 363: case 488: case 531: case 537: + case 541: case 664: case 665: case 696: + case 728: case 729: case 760: case 920: + case 921: case 952: + goto power_inst; + } + } + + // In GUI mode, show error alert + if (!PrefsFindBool("nogui")) { + sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->pc, segv_r[24], segv_r[1], opcode); + ErrorAlert(str); + QuitEmulator(); + return; + } + } + + // For all other errors, jump into debugger + sprintf(str, "SIGILL\n" + " pc %08lx lr %08lx ctr %08lx msr %08lx\n" + " xer %08lx cr %08lx fpscr %08lx\n" + " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n" + " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n" + " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n" + " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n" + " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n" + " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" + " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" + " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", + r->pc, r->lr, r->ctr, r->msr, + r->xer, r->cr, r->fpscr, + r->r0, r->r1, r->r2, r->r3, + r->r4, r->r5, r->r6, r->r7, + r->r8, r->r9, r->r10, r->r11, + r->r12, segv_r[13], segv_r[14], segv_r[15], + segv_r[16], segv_r[17], segv_r[18], segv_r[19], + segv_r[20], segv_r[21], segv_r[22], segv_r[23], + segv_r[24], segv_r[25], segv_r[26], segv_r[27], + segv_r[28], segv_r[29], segv_r[30], segv_r[31]); + VideoQuitFullScreen(); + disable_debugger(false); + debugger(str); + exit(1); + return; + +rti: + // Restore volatile registers + r->r0 = segv_r[0]; + r->r1 = segv_r[1]; + r->r2 = segv_r[2]; + r->r3 = segv_r[3]; + r->r4 = segv_r[4]; + r->r5 = segv_r[5]; + r->r6 = segv_r[6]; + r->r7 = segv_r[7]; + r->r8 = segv_r[8]; + r->r9 = segv_r[9]; + r->r10 = segv_r[10]; + r->r11 = segv_r[11]; + r->r12 = segv_r[12]; +} + + +/* + * Display error alert + */ + +void ErrorAlert(const char *text) +{ + if (PrefsFindBool("nogui")) { + printf(GetString(STR_SHELL_ERROR_PREFIX), text); + return; + } + char str[256]; + sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text); + VideoQuitFullScreen(); + BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); + alert->Go(); +} + + +/* + * Display warning alert + */ + +void WarningAlert(const char *text) +{ + if (PrefsFindBool("nogui")) { + printf(GetString(STR_SHELL_WARNING_PREFIX), text); + return; + } + char str[256]; + sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text); + BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT); + alert->Go(); +} + + +/* + * Display choice alert + */ + +bool ChoiceAlert(const char *text, const char *pos, const char *neg) +{ + char str[256]; + sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text); + BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT); + return alert->Go() == 0; +} diff --git a/SheepShaver/src/BeOS/prefs_beos.cpp b/SheepShaver/src/BeOS/prefs_beos.cpp new file mode 100644 index 00000000..d758614f --- /dev/null +++ b/SheepShaver/src/BeOS/prefs_beos.cpp @@ -0,0 +1,112 @@ +/* + * prefs_beos.cpp - Preferences handling, BeOS specific things + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "prefs.h" +#include "main.h" + + +// Platform-specific preferences items +prefs_desc platform_prefs_items[] = { + {"bitbang", TYPE_BOOLEAN, false, "draw Mac desktop directly on screen in window mode"}, + {"idlewait", TYPE_BOOLEAN, false, "sleep when idle"}, + {NULL, TYPE_END, false, NULL} // End of list +}; + + +// Preferences file name and path +const char PREFS_FILE_NAME[] = "SheepShaver_prefs"; +static BPath prefs_path; + +// Modification date of prefs file +time_t PrefsFileDate = 0; + + +/* + * Load preferences from settings file + */ + +void LoadPrefs(void) +{ + // Construct prefs path + find_directory(B_USER_SETTINGS_DIRECTORY, &prefs_path, true); + prefs_path.Append(PREFS_FILE_NAME); + + // Read preferences from settings file + FILE *f = fopen(prefs_path.Path(), "r"); + if (f == NULL) // Not found in settings directory, look in app directory + f = fopen(PREFS_FILE_NAME, "r"); + if (f != NULL) { + LoadPrefsFromStream(f); + + struct stat s; + fstat(fileno(f), &s); + PrefsFileDate = s.st_ctime; + fclose(f); + + } else { + + // No prefs file, save defaults + SavePrefs(); + PrefsFileDate = real_time_clock(); + } +} + + +/* + * Save preferences to settings file + */ + +void SavePrefs(void) +{ + FILE *f; + if ((f = fopen(prefs_path.Path(), "w")) != NULL) { + SavePrefsToStream(f); + fclose(f); + } +} + + +/* + * Add defaults of platform-specific prefs items + * You may also override the defaults set in PrefsInit() + */ + +void AddPlatformPrefsDefaults(void) +{ + PrefsReplaceString("extfs", "/boot"); + PrefsAddInt32("windowmodes", + B_8_BIT_640x480 | B_15_BIT_640x480 | B_32_BIT_640x480 | + B_8_BIT_800x600 | B_15_BIT_800x600 | B_32_BIT_800x600 + ); + PrefsAddInt32("screenmodes", + B_8_BIT_640x480 | B_15_BIT_640x480 | B_32_BIT_640x480 | + B_8_BIT_800x600 | B_15_BIT_800x600 | B_32_BIT_800x600 | + B_8_BIT_1024x768 | B_15_BIT_1024x768 + ); + PrefsAddBool("bitbang", false); + PrefsAddBool("idlewait", true); +} diff --git a/SheepShaver/src/BeOS/prefs_editor_beos.cpp b/SheepShaver/src/BeOS/prefs_editor_beos.cpp new file mode 100644 index 00000000..bbfa71a0 --- /dev/null +++ b/SheepShaver/src/BeOS/prefs_editor_beos.cpp @@ -0,0 +1,877 @@ +/* + * prefs_editor_beos.cpp - Preferences editor, BeOS implementation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "prefs_editor.h" +#include "prefs.h" +#include "main.h" +#include "cdrom.h" +#include "xpram.h" +#include "about_window.h" +#include "user_strings.h" + + +// Special colors +const rgb_color fill_color = {216, 216, 216, 0}; +const rgb_color slider_fill_color = {102, 152, 255, 0}; + + +// Window messages +const uint32 MSG_OK = 'okok'; // "Start" clicked +const uint32 MSG_CANCEL = 'cncl'; // "Quit" clicked +const uint32 MSG_ZAP_PRAM = 'zprm'; + +const int NUM_PANES = 4; + +const uint32 MSG_VOLUME_SELECTED = 'volu'; // "Volumes" pane +const uint32 MSG_VOLUME_INVOKED = 'voli'; +const uint32 MSG_ADD_VOLUME = 'addv'; +const uint32 MSG_CREATE_VOLUME = 'crev'; +const uint32 MSG_REMOVE_VOLUME = 'remv'; +const uint32 MSG_ADD_VOLUME_PANEL = 'advp'; +const uint32 MSG_CREATE_VOLUME_PANEL = 'crvp'; +const uint32 MSG_DEVICE_NAME = 'devn'; +const uint32 MSG_BOOT_ANY = 'bany'; +const uint32 MSG_BOOT_CDROM = 'bcdr'; +const uint32 MSG_NOCDROM = 'nocd'; + +const uint32 MSG_REF_5HZ = ' 5Hz'; // "Graphics" pane +const uint32 MSG_REF_7_5HZ = ' 7Hz'; +const uint32 MSG_REF_10HZ = '10Hz'; +const uint32 MSG_REF_15HZ = '15Hz'; +const uint32 MSG_REF_30HZ = '30Hz'; +const uint32 MSG_GFXACCEL = 'gfac'; +const uint32 MSG_WINDOW_MODE = 'wmod'; +const uint32 MSG_SCREEN_MODE = 'smod'; +const uint32 MSG_NOSOUND = 'nosn'; + +const uint32 MSG_SER_A = 'sera'; // "Serial"/"Network" pane +const uint32 MSG_SER_B = 'serb'; +const uint32 MSG_NONET = 'noet'; + +const uint32 MSG_RAMSIZE = 'rmsz'; // "Memory" pane +const uint32 MSG_IGNORESEGV = 'isgv'; +const uint32 MSG_IDLEWAIT = 'idlw'; + + +// RAM size slider class +class RAMSlider : public BSlider { +public: + RAMSlider(BRect frame, const char *name, const char *label, BMessage *message, + int32 minValue, int32 maxValue, thumb_style thumbType = B_BLOCK_THUMB, + uint32 resizingMode = B_FOLLOW_LEFT | + B_FOLLOW_TOP, + uint32 flags = B_NAVIGABLE | B_WILL_DRAW | + B_FRAME_EVENTS) : BSlider(frame, name, label, message, minValue, maxValue, thumbType, resizingMode, flags) + { + update_text = (char *)malloc(256); + } + + virtual ~RAMSlider() + { + if (update_text) + free(update_text); + } + + virtual char *UpdateText(void) const + { + if (update_text) { + sprintf(update_text, GetString(STR_RAMSIZE_FMT), Value()); + } + return update_text; + } + +private: + char *update_text; +}; + + +// Volumes list view class +class VolumeListView : public BListView { +public: + VolumeListView(BRect frame, const char *name, list_view_type type = B_SINGLE_SELECTION_LIST, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE) + : BListView(frame, name, type, resizeMask, flags) + {} + + // Handle dropped files and volumes + virtual void MessageReceived(BMessage *msg) + { + if (msg->what == B_SIMPLE_DATA) { + BMessage msg2(MSG_ADD_VOLUME_PANEL); + entry_ref ref; + for (int i=0; msg->FindRef("refs", i, &ref) == B_NO_ERROR; i++) + msg2.AddRef("refs", &ref); + Window()->PostMessage(&msg2); + } else + BListView::MessageReceived(msg); + } +}; + + +// Number-entry BTextControl +class NumberControl : public BTextControl { +public: + NumberControl(BRect frame, float divider, const char *name, const char *label, long value, BMessage *message) + : BTextControl(frame, name, label, NULL, message, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE) + { + SetDivider(divider); + for (int c=0; c<256; c++) + if (!isdigit(c) && c != B_BACKSPACE && c != B_LEFT_ARROW && c != B_RIGHT_ARROW) + ((BTextView *)ChildAt(0))->DisallowChar(c); + SetValue(value); + } + + // Set integer value + void SetValue(long value) + { + char str[32]; + sprintf(str, "%ld", value); + SetText(str); + } + + // Get integer value + long Value(void) + { + return atol(Text()); + } +}; + + +// Path-entry BTextControl +class PathControl : public BTextControl { +public: + PathControl(bool dir_ctrl_, BRect frame, const char *name, const char *label, const char *text, BMessage *message) : BTextControl(frame, name, label, text, message), dir_ctrl(dir_ctrl_) + { + for (int c=0; c<' '; c++) + if (c != B_BACKSPACE && c != B_LEFT_ARROW && c != B_RIGHT_ARROW) + ((BTextView *)ChildAt(0))->DisallowChar(c); + } + + virtual void MessageReceived(BMessage *msg) + { + if (msg->what == B_SIMPLE_DATA) { + entry_ref the_ref; + BEntry the_entry; + + // Look for dropped refs + if (msg->FindRef("refs", &the_ref) == B_NO_ERROR) { + if (the_entry.SetTo(&the_ref) == B_NO_ERROR && (dir_ctrl&& the_entry.IsDirectory() || !dir_ctrl && the_entry.IsFile())) { + BPath the_path; + the_entry.GetPath(&the_path); + SetText(the_path.Path()); + } + } else + BTextControl::MessageReceived(msg); + + MakeFocus(); + } else + BTextControl::MessageReceived(msg); + } + +private: + bool dir_ctrl; +}; + + +// Preferences window class +class PrefsWindow : public BWindow { +public: + PrefsWindow(uint32 msg); + virtual ~PrefsWindow(); + virtual void MessageReceived(BMessage *msg); + +private: + BView *create_volumes_pane(void); + BView *create_graphics_pane(void); + BView *create_serial_pane(void); + BView *create_memory_pane(void); + + uint32 ok_message; + bool send_quit_on_close; + + BMessenger this_messenger; + BView *top; + BRect top_frame; + BTabView *pane_tabs; + BView *panes[NUM_PANES]; + int current_pane; + + VolumeListView *volume_list; + BCheckBox *nocdrom_checkbox; + BCheckBox *gfxaccel_checkbox; + BCheckBox *nosound_checkbox; + BCheckBox *nonet_checkbox; + BCheckBox *ignoresegv_checkbox; + BCheckBox *idlewait_checkbox; + RAMSlider *ramsize_slider; + PathControl *extfs_control; + PathControl *rom_control; + + BFilePanel *add_volume_panel; + BFilePanel *create_volume_panel; + + uint32 max_ramsize; // In MB +}; + + +/* + * Show preferences editor + * When the user clicks on "OK", the message given as parameter is sent + * to the application; if he clicks on "Quit", B_QUIT_REQUESTED is sent + */ + +void PrefsEditor(uint32 msg) +{ + new PrefsWindow(msg); +} + + +/* + * Preferences window constructor + */ + +PrefsWindow::PrefsWindow(uint32 msg) : BWindow(BRect(0, 0, 400, 289), GetString(STR_PREFS_TITLE), B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS), this_messenger(this) +{ + int i; + ok_message = msg; + send_quit_on_close = true; + + // Move window to right position + Lock(); + MoveTo(80, 80); + + // Set up menus + BMenuBar *bar = new BMenuBar(Bounds(), "menu"); + BMenu *menu = new BMenu(GetString(STR_PREFS_MENU)); + menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_ABOUT), new BMessage(B_ABOUT_REQUESTED))); + menu->AddItem(new BSeparatorItem); + menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_START), new BMessage(MSG_OK))); + menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_ZAP_PRAM), new BMessage(MSG_ZAP_PRAM))); + menu->AddItem(new BSeparatorItem); + menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_QUIT), new BMessage(MSG_CANCEL), 'Q')); + bar->AddItem(menu); + AddChild(bar); + SetKeyMenuBar(bar); + int mbar_height = bar->Bounds().bottom + 1; + + // Resize window to fit menu bar + ResizeBy(0, mbar_height); + + // Light gray background + BRect b = Bounds(); + top = new BView(BRect(0, mbar_height, b.right, b.bottom), "top", B_FOLLOW_NONE, B_WILL_DRAW); + AddChild(top); + top->SetViewColor(fill_color); + top_frame = top->Bounds(); + + // Create panes + panes[0] = create_volumes_pane(); + panes[1] = create_graphics_pane(); + panes[2] = create_serial_pane(); + panes[3] = create_memory_pane(); + + // Prefs item tab view + pane_tabs = new BTabView(BRect(10, 10, top_frame.right-10, top_frame.bottom-50), "items", B_WIDTH_FROM_LABEL); + for (i=0; iAddTab(panes[i]); + top->AddChild(pane_tabs); + + volume_list->Select(0); + + // Create volume file panels + add_volume_panel = new BFilePanel(B_OPEN_PANEL, &this_messenger, NULL, B_FILE_NODE | B_DIRECTORY_NODE, false, new BMessage(MSG_ADD_VOLUME_PANEL)); + add_volume_panel->SetButtonLabel(B_DEFAULT_BUTTON, GetString(STR_ADD_VOLUME_PANEL_BUTTON)); + add_volume_panel->Window()->SetTitle(GetString(STR_ADD_VOLUME_TITLE)); + create_volume_panel = new BFilePanel(B_SAVE_PANEL, &this_messenger, NULL, B_FILE_NODE | B_DIRECTORY_NODE, false, new BMessage(MSG_CREATE_VOLUME_PANEL)); + create_volume_panel->SetButtonLabel(B_DEFAULT_BUTTON, GetString(STR_CREATE_VOLUME_PANEL_BUTTON)); + create_volume_panel->Window()->SetTitle(GetString(STR_CREATE_VOLUME_TITLE)); + + create_volume_panel->Window()->Lock(); + BView *background = create_volume_panel->Window()->ChildAt(0); + background->FindView("PoseView")->ResizeBy(0, -30); + background->FindView("VScrollBar")->ResizeBy(0, -30); + background->FindView("CountVw")->MoveBy(0, -30); + BView *v = background->FindView("HScrollBar"); + if (v) + v->MoveBy(0, -30); + else { + i = 0; + while ((v = background->ChildAt(i++)) != NULL) { + if (v->Name() == NULL || v->Name()[0] == 0) { + v->MoveBy(0, -30); // unnamed horizontal scroll bar + break; + } + } + } + BView *filename = background->FindView("text view"); + BRect fnr(filename->Frame()); + fnr.OffsetBy(0, -30); + NumberControl *nc = new NumberControl(fnr, 80, "hardfile_size", GetString(STR_HARDFILE_SIZE_CTRL), 40, NULL); + background->AddChild(nc); + create_volume_panel->Window()->Unlock(); + + // "Start" button + BButton *button = new BButton(BRect(20, top_frame.bottom-35, 90, top_frame.bottom-10), "start", GetString(STR_START_BUTTON), new BMessage(MSG_OK)); + top->AddChild(button); + SetDefaultButton(button); + + // "Quit" button + top->AddChild(new BButton(BRect(top_frame.right-90, top_frame.bottom-35, top_frame.right-20, top_frame.bottom-10), "cancel", GetString(STR_QUIT_BUTTON), new BMessage(MSG_CANCEL))); + + Unlock(); + Show(); +} + + +/* + * Preferences window destructor + */ + +PrefsWindow::~PrefsWindow() +{ + delete add_volume_panel; + if (send_quit_on_close) + be_app->PostMessage(B_QUIT_REQUESTED); +} + + +/* + * Create "Volumes" pane + */ + +BView *PrefsWindow::create_volumes_pane(void) +{ + BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_VOLUMES_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); + pane->SetViewColor(fill_color); + float right = pane->Bounds().right-10; + + const char *str; + int32 index = 0; + volume_list = new VolumeListView(BRect(15, 10, pane->Bounds().right-30, 108), "volumes"); + while ((str = PrefsFindString("disk", index++)) != NULL) + volume_list->AddItem(new BStringItem(str)); + volume_list->SetSelectionMessage(new BMessage(MSG_VOLUME_SELECTED)); + volume_list->SetInvocationMessage(new BMessage(MSG_VOLUME_INVOKED)); + pane->AddChild(new BScrollView("volumes_border", volume_list, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true)); + + pane->AddChild(new BButton(BRect(10, 113, pane->Bounds().right/3, 133), "add_volume", GetString(STR_ADD_VOLUME_BUTTON), new BMessage(MSG_ADD_VOLUME))); + pane->AddChild(new BButton(BRect(pane->Bounds().right/3, 113, pane->Bounds().right*2/3, 133), "create_volume", GetString(STR_CREATE_VOLUME_BUTTON), new BMessage(MSG_CREATE_VOLUME))); + pane->AddChild(new BButton(BRect(pane->Bounds().right*2/3, 113, pane->Bounds().right-11, 133), "remove_volume", GetString(STR_REMOVE_VOLUME_BUTTON), new BMessage(MSG_REMOVE_VOLUME))); + + extfs_control = new PathControl(true, BRect(10, 145, right, 160), "extfs", GetString(STR_EXTFS_CTRL), PrefsFindString("extfs"), NULL); + extfs_control->SetDivider(90); + pane->AddChild(extfs_control); + + BMenuField *menu_field; + BPopUpMenu *menu = new BPopUpMenu(""); + menu_field = new BMenuField(BRect(10, 165, right, 180), "bootdriver", GetString(STR_BOOTDRIVER_CTRL), menu); + menu_field->SetDivider(90); + menu->AddItem(new BMenuItem(GetString(STR_BOOT_ANY_LAB), new BMessage(MSG_BOOT_ANY))); + menu->AddItem(new BMenuItem(GetString(STR_BOOT_CDROM_LAB), new BMessage(MSG_BOOT_CDROM))); + pane->AddChild(menu_field); + int16 i16 = PrefsFindInt32("bootdriver"); + BMenuItem *item; + if (i16 == 0) { + if ((item = menu->FindItem(GetString(STR_BOOT_ANY_LAB))) != NULL) + item->SetMarked(true); + } else if (i16 == CDROMRefNum) { + if ((item = menu->FindItem(GetString(STR_BOOT_CDROM_LAB))) != NULL) + item->SetMarked(true); + } + + nocdrom_checkbox = new BCheckBox(BRect(10, 185, right, 200), "nocdrom", GetString(STR_NOCDROM_CTRL), new BMessage(MSG_NOCDROM)); + pane->AddChild(nocdrom_checkbox); + nocdrom_checkbox->SetValue(PrefsFindBool("nocdrom") ? B_CONTROL_ON : B_CONTROL_OFF); + + return pane; +} + + +/* + * Create "Graphics/Sound" pane + */ + +struct video_mode_box { + uint32 mode; + int mode_string_id, bit_string_id; + float left, top; + BCheckBox *box; +}; + +const int NUM_WINDOW_MODES = 6; +const int NUM_SCREEN_MODES = 18; + +static video_mode_box window_mode_boxes[NUM_SCREEN_MODES] = { + {B_8_BIT_640x480, STR_W_640x480_CTRL, STR_8_BIT_CTRL, 140, 48, NULL}, + {B_15_BIT_640x480, STR_W_640x480_CTRL, STR_16_BIT_CTRL, 220, 48, NULL}, + {B_32_BIT_640x480, STR_W_640x480_CTRL, STR_32_BIT_CTRL, 300, 48, NULL}, + {B_8_BIT_800x600, STR_W_800x600_CTRL, STR_8_BIT_CTRL, 140, 65, NULL}, + {B_15_BIT_800x600, STR_W_800x600_CTRL, STR_16_BIT_CTRL, 220, 65, NULL}, + {B_32_BIT_800x600, STR_W_800x600_CTRL, STR_32_BIT_CTRL, 300, 65, NULL}, +}; + +static video_mode_box screen_mode_boxes[NUM_SCREEN_MODES] = { + {B_8_BIT_640x480, STR_640x480_CTRL, STR_8_BIT_CTRL, 140, 82, NULL}, + {B_15_BIT_640x480, STR_640x480_CTRL, STR_16_BIT_CTRL, 220, 82, NULL}, + {B_32_BIT_640x480, STR_640x480_CTRL, STR_32_BIT_CTRL, 300, 82, NULL}, + {B_8_BIT_800x600, STR_800x600_CTRL, STR_8_BIT_CTRL, 140, 99, NULL}, + {B_15_BIT_800x600, STR_800x600_CTRL, STR_16_BIT_CTRL, 220, 99, NULL}, + {B_32_BIT_800x600, STR_800x600_CTRL, STR_32_BIT_CTRL, 300, 99, NULL}, + {B_8_BIT_1024x768, STR_1024x768_CTRL, STR_8_BIT_CTRL, 140, 116, NULL}, + {B_15_BIT_1024x768, STR_1024x768_CTRL, STR_16_BIT_CTRL, 220, 116, NULL}, + {B_32_BIT_1024x768, STR_1024x768_CTRL, STR_32_BIT_CTRL, 300, 116, NULL}, + {B_8_BIT_1152x900, STR_1152x900_CTRL, STR_8_BIT_CTRL, 140, 133, NULL}, + {B_15_BIT_1152x900, STR_1152x900_CTRL, STR_16_BIT_CTRL, 220, 133, NULL}, + {B_32_BIT_1152x900, STR_1152x900_CTRL, STR_32_BIT_CTRL, 300, 133, NULL}, + {B_8_BIT_1280x1024, STR_1280x1024_CTRL, STR_8_BIT_CTRL, 140, 150, NULL}, + {B_15_BIT_1280x1024, STR_1280x1024_CTRL, STR_16_BIT_CTRL, 220, 150, NULL}, + {B_32_BIT_1280x1024, STR_1280x1024_CTRL, STR_32_BIT_CTRL, 300, 150, NULL}, + {B_8_BIT_1600x1200, STR_1600x1200_CTRL, STR_8_BIT_CTRL, 140, 167, NULL}, + {B_15_BIT_1600x1200, STR_1600x1200_CTRL, STR_16_BIT_CTRL, 220, 167, NULL}, + {B_32_BIT_1600x1200, STR_1600x1200_CTRL, STR_32_BIT_CTRL, 300, 167, NULL} +}; + +BView *PrefsWindow::create_graphics_pane(void) +{ + BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_GRAPHICS_SOUND_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); + pane->SetViewColor(fill_color); + float right = pane->Bounds().right-10; + + BMenuField *menu_field; + BPopUpMenu *menu = new BPopUpMenu(""); + menu_field = new BMenuField(BRect(10, 5, right, 20), "frameskip", GetString(STR_FRAMESKIP_CTRL), menu); + menu_field->SetDivider(120); + menu->AddItem(new BMenuItem(GetString(STR_REF_5HZ_LAB), new BMessage(MSG_REF_5HZ))); + menu->AddItem(new BMenuItem(GetString(STR_REF_7_5HZ_LAB), new BMessage(MSG_REF_7_5HZ))); + menu->AddItem(new BMenuItem(GetString(STR_REF_10HZ_LAB), new BMessage(MSG_REF_10HZ))); + menu->AddItem(new BMenuItem(GetString(STR_REF_15HZ_LAB), new BMessage(MSG_REF_15HZ))); + menu->AddItem(new BMenuItem(GetString(STR_REF_30HZ_LAB), new BMessage(MSG_REF_30HZ))); + pane->AddChild(menu_field); + int32 i32 = PrefsFindInt32("frameskip"); + BMenuItem *item; + if (i32 == 12) { + if ((item = menu->FindItem(GetString(STR_REF_5HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (i32 == 8) { + if ((item = menu->FindItem(GetString(STR_REF_7_5HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (i32 == 6) { + if ((item = menu->FindItem(GetString(STR_REF_10HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (i32 == 4) { + if ((item = menu->FindItem(GetString(STR_REF_15HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (i32 == 2) { + if ((item = menu->FindItem(GetString(STR_REF_30HZ_LAB))) != NULL) + item->SetMarked(true); + } + + gfxaccel_checkbox = new BCheckBox(BRect(10, 25, right, 40), "gfxaccel", GetString(STR_GFXACCEL_CTRL), new BMessage(MSG_GFXACCEL)); + pane->AddChild(gfxaccel_checkbox); + gfxaccel_checkbox->SetValue(PrefsFindBool("gfxaccel") ? B_CONTROL_ON : B_CONTROL_OFF); + + uint32 window_modes = PrefsFindInt32("windowmodes"); + for (int i=0; ibit_string_id == STR_8_BIT_CTRL) { + BStringView *text = new BStringView(BRect(10, p->top, 120, p->top + 15), "", GetString(p->mode_string_id)); + pane->AddChild(text); + } + p->box = new BCheckBox(BRect(p->left, p->top, p->left + 80, p->top + 15), "", GetString(p->bit_string_id), new BMessage(MSG_WINDOW_MODE)); + pane->AddChild(p->box); + p->box->SetValue(window_modes & p->mode ? B_CONTROL_ON : B_CONTROL_OFF); + } + uint32 screen_modes = PrefsFindInt32("screenmodes"); + for (int i=0; ibit_string_id == STR_8_BIT_CTRL) { + BStringView *text = new BStringView(BRect(10, p->top, 120, p->top + 15), "", GetString(p->mode_string_id)); + pane->AddChild(text); + } + p->box = new BCheckBox(BRect(p->left, p->top, p->left + 80, p->top + 15), "", GetString(p->bit_string_id), new BMessage(MSG_SCREEN_MODE)); + pane->AddChild(p->box); + p->box->SetValue(screen_modes & p->mode ? B_CONTROL_ON : B_CONTROL_OFF); + } + + nosound_checkbox = new BCheckBox(BRect(10, 185, right, 200), "nosound", GetString(STR_NOSOUND_CTRL), new BMessage(MSG_NOSOUND)); + pane->AddChild(nosound_checkbox); + nosound_checkbox->SetValue(PrefsFindBool("nosound") ? B_CONTROL_ON : B_CONTROL_OFF); + + return pane; +} + + +/* + * Create "Serial/Network" pane + */ + +static void add_serial_names(BPopUpMenu *menu, uint32 msg) +{ + BSerialPort *port = new BSerialPort; + char name[B_PATH_NAME_LENGTH]; + for (int i=0; iCountDevices(); i++) { + port->GetDeviceName(i, name); + menu->AddItem(new BMenuItem(name, new BMessage(msg))); + } + if (SysInfo.platform_type == B_BEBOX_PLATFORM) { + BDirectory dir; + BEntry entry; + dir.SetTo("/dev/parallel"); + if (dir.InitCheck() == B_NO_ERROR) { + dir.Rewind(); + while (dir.GetNextEntry(&entry) >= 0) { + if (!entry.IsDirectory()) { + entry.GetName(name); + menu->AddItem(new BMenuItem(name, new BMessage(msg))); + } + } + } + } + delete port; +} + +static void set_serial_label(BPopUpMenu *menu, const char *prefs_name) +{ + const char *str; + BMenuItem *item; + if ((str = PrefsFindString(prefs_name)) != NULL) + if ((item = menu->FindItem(str)) != NULL) + item->SetMarked(true); +} + +BView *PrefsWindow::create_serial_pane(void) +{ + BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_SERIAL_NETWORK_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); + pane->SetViewColor(fill_color); + float right = pane->Bounds().right-10; + + BMenuField *menu_field; + BPopUpMenu *menu_a = new BPopUpMenu(""); + add_serial_names(menu_a, MSG_SER_A); + menu_field = new BMenuField(BRect(10, 5, right, 20), "seriala", GetString(STR_SERPORTA_CTRL), menu_a); + menu_field->SetDivider(90); + pane->AddChild(menu_field); + set_serial_label(menu_a, "seriala"); + + BPopUpMenu *menu_b = new BPopUpMenu(""); + add_serial_names(menu_b, MSG_SER_B); + menu_field = new BMenuField(BRect(10, 26, right, 41), "serialb", GetString(STR_SERPORTB_CTRL), menu_b); + menu_field->SetDivider(90); + pane->AddChild(menu_field); + set_serial_label(menu_b, "serialb"); + + nonet_checkbox = new BCheckBox(BRect(10, 47, right, 62), "nonet", GetString(STR_NONET_CTRL), new BMessage(MSG_NONET)); + pane->AddChild(nonet_checkbox); + nonet_checkbox->SetValue(PrefsFindBool("nonet") ? B_CONTROL_ON : B_CONTROL_OFF); + + return pane; +} + + +/* + * Create "Memory/Misc" pane + */ + +BView *PrefsWindow::create_memory_pane(void) +{ + char str[256], str2[256]; + BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_MEMORY_MISC_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); + pane->SetViewColor(fill_color); + float right = pane->Bounds().right-10; + + BEntry entry("/boot/var/swap"); + off_t swap_space; + if (entry.GetSize(&swap_space) == B_NO_ERROR) + max_ramsize = swap_space / (1024 * 1024) - 8; + else + max_ramsize = SysInfo.max_pages * B_PAGE_SIZE / (1024 * 1024) - 8; + + int32 value = PrefsFindInt32("ramsize") / (1024 * 1024); + + ramsize_slider = new RAMSlider(BRect(10, 5, right, 55), "ramsize", GetString(STR_RAMSIZE_SLIDER), new BMessage(MSG_RAMSIZE), 8, max_ramsize, B_TRIANGLE_THUMB); + ramsize_slider->SetValue(value); + ramsize_slider->UseFillColor(true, &slider_fill_color); + sprintf(str, GetString(STR_RAMSIZE_FMT), 8); + sprintf(str2, GetString(STR_RAMSIZE_FMT), max_ramsize); + ramsize_slider->SetLimitLabels(str, str2); + pane->AddChild(ramsize_slider); + + ignoresegv_checkbox = new BCheckBox(BRect(10, 60, right, 75), "ignoresegv", GetString(STR_IGNORESEGV_CTRL), new BMessage(MSG_IGNORESEGV)); + pane->AddChild(ignoresegv_checkbox); + ignoresegv_checkbox->SetValue(PrefsFindBool("ignoresegv") ? B_CONTROL_ON : B_CONTROL_OFF); + + idlewait_checkbox = new BCheckBox(BRect(10, 80, right, 95), "idlewait", GetString(STR_IDLEWAIT_CTRL), new BMessage(MSG_IDLEWAIT)); + pane->AddChild(idlewait_checkbox); + idlewait_checkbox->SetValue(PrefsFindBool("idlewait") ? B_CONTROL_ON : B_CONTROL_OFF); + + rom_control = new PathControl(false, BRect(10, 100, right, 115), "rom", GetString(STR_ROM_FILE_CTRL), PrefsFindString("rom"), NULL); + rom_control->SetDivider(117); + pane->AddChild(rom_control); + + return pane; +} + + +/* + * Message from controls/menus received + */ + +void PrefsWindow::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case MSG_OK: // "Start" button clicked + PrefsReplaceString("extfs", extfs_control->Text()); + const char *str = rom_control->Text(); + if (strlen(str)) + PrefsReplaceString("rom", str); + else + PrefsRemoveItem("rom"); + SavePrefs(); + send_quit_on_close = false; + PostMessage(B_QUIT_REQUESTED); + be_app->PostMessage(ok_message); + break; + + case MSG_CANCEL: // "Quit" button clicked + send_quit_on_close = false; + PostMessage(B_QUIT_REQUESTED); + be_app->PostMessage(B_QUIT_REQUESTED); + break; + + case B_ABOUT_REQUESTED: // "About" menu item selected + OpenAboutWindow(); + break; + + case MSG_ZAP_PRAM: // "Zap PRAM File" menu item selected + ZapPRAM(); + break; + + case MSG_VOLUME_INVOKED: { // Double-clicked on volume name, toggle read-only flag + int selected = volume_list->CurrentSelection(); + if (selected >= 0) { + const char *str = PrefsFindString("disk", selected); + BStringItem *item = (BStringItem *)volume_list->RemoveItem(selected); + delete item; + char newstr[256]; + if (str[0] == '*') + strcpy(newstr, str+1); + else { + strcpy(newstr, "*"); + strcat(newstr, str); + } + PrefsReplaceString("disk", newstr, selected); + volume_list->AddItem(new BStringItem(newstr), selected); + volume_list->Select(selected); + } + break; + } + + case MSG_ADD_VOLUME: + add_volume_panel->Show(); + break; + + case MSG_CREATE_VOLUME: + create_volume_panel->Show(); + break; + + case MSG_ADD_VOLUME_PANEL: { + entry_ref ref; + if (msg->FindRef("refs", &ref) == B_NO_ERROR) { + BEntry entry(&ref, true); + BPath path; + entry.GetPath(&path); + if (entry.IsFile()) { + PrefsAddString("disk", path.Path()); + volume_list->AddItem(new BStringItem(path.Path())); + } else if (entry.IsDirectory()) { + BVolume volume; + if (path.Path()[0] == '/' && strchr(path.Path()+1, '/') == NULL && entry.GetVolume(&volume) == B_NO_ERROR) { + int32 i = 0; + dev_t d; + fs_info info; + while ((d = next_dev(&i)) >= 0) { + fs_stat_dev(d, &info); + if (volume.Device() == info.dev) { + PrefsAddString("disk", info.device_name); + volume_list->AddItem(new BStringItem(info.device_name)); + } + } + } + } + } + break; + } + + case MSG_CREATE_VOLUME_PANEL: { + entry_ref dir; + if (msg->FindRef("directory", &dir) == B_NO_ERROR) { + BEntry entry(&dir, true); + BPath path; + entry.GetPath(&path); + path.Append(msg->FindString("name")); + + create_volume_panel->Window()->Lock(); + BView *background = create_volume_panel->Window()->ChildAt(0); + NumberControl *v = (NumberControl *)background->FindView("hardfile_size"); + int size = v->Value(); + + char cmd[1024]; + sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", path.Path(), size); + int ret = system(cmd); + if (ret == 0) { + PrefsAddString("disk", path.Path()); + volume_list->AddItem(new BStringItem(path.Path())); + } else { + sprintf(cmd, GetString(STR_CREATE_VOLUME_WARN), strerror(ret)); + WarningAlert(cmd); + } + } + break; + } + + case MSG_REMOVE_VOLUME: { + int selected = volume_list->CurrentSelection(); + if (selected >= 0) { + PrefsRemoveItem("disk", selected); + BStringItem *item = (BStringItem *)volume_list->RemoveItem(selected); + delete item; + volume_list->Select(selected); + } + break; + } + + case MSG_BOOT_ANY: + PrefsReplaceInt32("bootdriver", 0); + break; + + case MSG_BOOT_CDROM: + PrefsReplaceInt32("bootdriver", CDROMRefNum); + break; + + case MSG_NOCDROM: + PrefsReplaceBool("nocdrom", nocdrom_checkbox->Value() == B_CONTROL_ON); + break; + + case MSG_GFXACCEL: + PrefsReplaceBool("gfxaccel", gfxaccel_checkbox->Value() == B_CONTROL_ON); + break; + + case MSG_NOSOUND: + PrefsReplaceBool("nosound", nosound_checkbox->Value() == B_CONTROL_ON); + break; + + case MSG_WINDOW_MODE: { + BCheckBox *source = NULL; + msg->FindPointer("source", &source); + if (source == NULL) + break; + for (int i=0; ibox == source) { + if (p->box->Value() == B_CONTROL_ON) + PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | p->mode); + else + PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~(p->mode)); + break; + } + } + break; + } + + case MSG_SCREEN_MODE: { + BCheckBox *source = NULL; + msg->FindPointer("source", &source); + if (source == NULL) + break; + for (int i=0; ibox == source) { + if (p->box->Value() == B_CONTROL_ON) + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | p->mode); + else + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~(p->mode)); + break; + } + } + break; + } + + case MSG_REF_5HZ: + PrefsReplaceInt32("frameskip", 12); + break; + + case MSG_REF_7_5HZ: + PrefsReplaceInt32("frameskip", 8); + break; + + case MSG_REF_10HZ: + PrefsReplaceInt32("frameskip", 6); + break; + + case MSG_REF_15HZ: + PrefsReplaceInt32("frameskip", 4); + break; + + case MSG_REF_30HZ: + PrefsReplaceInt32("frameskip", 2); + break; + + case MSG_SER_A: { + BMenuItem *source = NULL; + msg->FindPointer("source", &source); + if (source) + PrefsReplaceString("seriala", source->Label()); + break; + } + + case MSG_SER_B: { + BMenuItem *source = NULL; + msg->FindPointer("source", &source); + if (source) + PrefsReplaceString("serialb", source->Label()); + break; + } + + case MSG_NONET: + PrefsReplaceBool("nonet", nonet_checkbox->Value() == B_CONTROL_ON); + break; + + case MSG_IGNORESEGV: + PrefsReplaceBool("ignoresegv", ignoresegv_checkbox->Value() == B_CONTROL_ON); + break; + + case MSG_IDLEWAIT: + PrefsReplaceBool("idlewait", idlewait_checkbox->Value() == B_CONTROL_ON); + break; + + case MSG_RAMSIZE: + PrefsReplaceInt32("ramsize", ramsize_slider->Value() * 1024 * 1024); + break; + + default: + BWindow::MessageReceived(msg); + } +} diff --git a/SheepShaver/src/BeOS/sysdeps.h b/SheepShaver/src/BeOS/sysdeps.h new file mode 100644 index 00000000..46966c57 --- /dev/null +++ b/SheepShaver/src/BeOS/sysdeps.h @@ -0,0 +1,55 @@ +/* + * sysdeps.h - System dependent definitions for BeOS + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 SYSDEPS_H +#define SYSDEPS_H + +#include +#include +#include + +#include "user_strings_beos.h" + +// Are we using a PPC emulator or the real thing? +#ifdef __POWERPC__ +#define EMULATED_PPC 0 +#else +#define EMULATED_PPC 1 +#endif + +#define POWERPC_ROM 1 + +// Time data type for Time Manager emulation +typedef bigtime_t tm_time_t; + +// 64 bit file offsets +typedef off_t loff_t; + +// Macro for calling MacOS routines +#define CallMacOS(type, proc) (*(type)proc)() +#define CallMacOS1(type, proc, arg1) (*(type)proc)(arg1) +#define CallMacOS2(type, proc, arg1, arg2) (*(type)proc)(arg1, arg2) +#define CallMacOS3(type, proc, arg1, arg2, arg3) (*(type)proc)(arg1, arg2, arg3) +#define CallMacOS4(type, proc, arg1, arg2, arg3, arg4) (*(type)proc)(arg1, arg2, arg3, arg4) +#define CallMacOS5(type, proc, arg1, arg2, arg3, arg4, arg5) (*(type)proc)(arg1, arg2, arg3, arg4, arg5) +#define CallMacOS6(type, proc, arg1, arg2, arg3, arg4, arg5, arg6) (*(type)proc)(arg1, arg2, arg3, arg4, arg5, arg6) +#define CallMacOS7(type, proc, arg1, arg2, arg3, arg4, arg5, arg6, arg7) (*(type)proc)(arg1, arg2, arg3, arg4, arg5, arg6, arg7) + +#endif diff --git a/SheepShaver/src/BeOS/user_strings_beos.cpp b/SheepShaver/src/BeOS/user_strings_beos.cpp new file mode 100644 index 00000000..4b85d4fc --- /dev/null +++ b/SheepShaver/src/BeOS/user_strings_beos.cpp @@ -0,0 +1,69 @@ +/* + * user_strings_beos.cpp - Localizable strings, BeOS specific strings + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include "user_strings.h" + + +// Platform-specific string definitions +user_string_def platform_strings[] = { + // Common strings that have a platform-specific variant + {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under BeOS. Basilisk II will try to unmount it."}, + {STR_EXTFS_CTRL, "BeOS Root"}, + {STR_EXTFS_NAME, "BeOS Directory Tree"}, + {STR_EXTFS_VOLUME_NAME, "BeOS"}, + + // Purely platform-specific strings + {STR_NO_SHEEP_DRIVER_ERR, "Cannot open /dev/sheep: %s (%08x). SheepShaver is not properly installed."}, + {STR_NO_RAM_AREA_ERR, "Not enough memory to create RAM area: %s (%08x)."}, + {STR_NO_ROM_AREA_ERR, "Not enough memory to create ROM area."}, + {STR_SHEEP_UP_ERR, "Cannot allocate Low Memory Globals: %s (%08x)."}, + {STR_NO_NET_ADDON_WARN, "The SheepShaver net server add-on cannot be found. Ethernet will not be available."}, + {STR_NET_CONFIG_MODIFY_WARN, "To enable Ethernet networking for SheepShaver, your network configuration has to be modified and the network restarted. Do you want this to be done now (selecting \"Cancel\" will disable Ethernet under SheepShaver)?."}, + {STR_NET_ADDON_INIT_FAILED, "SheepShaver net server add-on found\nbut there seems to be no network hardware.\nPlease check your network preferences."}, + {STR_NET_ADDON_CLONE_FAILED, "Cloning of the network transfer area failed."}, + + {-1, NULL} // End marker +}; + + +/* + * Fetch pointer to string, given the string number + */ + +const char *GetString(int num) +{ + // First search for platform-specific string + int i = 0; + while (platform_strings[i].num >= 0) { + if (platform_strings[i].num == num) + return platform_strings[i].str; + i++; + } + + // Not found, search for common string + i = 0; + while (common_strings[i].num >= 0) { + if (common_strings[i].num == num) + return common_strings[i].str; + i++; + } + return NULL; +} diff --git a/SheepShaver/src/BeOS/user_strings_beos.h b/SheepShaver/src/BeOS/user_strings_beos.h new file mode 100644 index 00000000..a1cc7070 --- /dev/null +++ b/SheepShaver/src/BeOS/user_strings_beos.h @@ -0,0 +1,34 @@ +/* + * user_strings_beos.h - BeOS-specific localizable strings + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 USER_STRINGS_BEOS_H +#define USER_STRINGS_BEOS_H + +enum { + STR_NO_SHEEP_DRIVER_ERR = 10000, + STR_NO_ROM_AREA_ERR, + STR_SHEEP_UP_ERR, + STR_NO_NET_ADDON_WARN, + STR_NET_CONFIG_MODIFY_WARN, + STR_NET_ADDON_INIT_FAILED, + STR_NET_ADDON_CLONE_FAILED +}; + +#endif diff --git a/SheepShaver/src/BeOS/video_beos.cpp b/SheepShaver/src/BeOS/video_beos.cpp new file mode 100644 index 00000000..5c1403dd --- /dev/null +++ b/SheepShaver/src/BeOS/video_beos.cpp @@ -0,0 +1,768 @@ +/* + * video_beos.cpp - Video/graphics emulation, BeOS specific things + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" + +#include "video.h" +#include "video_defs.h" +#include "main.h" +#include "adb.h" +#include "prefs.h" +#include "user_strings.h" +#include "about_window.h" +#include "version.h" + +#define DEBUG 0 +#include "debug.h" + + +// Global variables +static sem_id video_lock = -1; // Protection during mode changes +static sem_id mac_os_lock = -1; // This is used to stop the MacOS thread when the SheepShaver workspace is switched out + +// Prototypes +static filter_result filter_func(BMessage *msg, BHandler **target, BMessageFilter *filter); + +// From sys_beos.cpp +extern void SysCreateVolumeMenu(BMenu *menu, uint32 msg); +extern void SysMountVolume(const char *name); + + +#include "video_window.h" +#include "video_screen.h" + + +/* + * Display manager thread (for opening and closing windows and screens; + * this is not safe under R4 when running on the MacOS stack in kernel + * space) + */ + +// Message constants +const uint32 MSG_OPEN_WINDOW = 'owin'; +const uint32 MSG_CLOSE_WINDOW = 'cwin'; +const uint32 MSG_OPEN_SCREEN = 'oscr'; +const uint32 MSG_CLOSE_SCREEN = 'cscr'; +const uint32 MSG_QUIT_DISPLAY_MANAGER = 'quit'; + +static thread_id dm_thread = -1; +static sem_id dm_done_sem = -1; + +static status_t display_manager(void *arg) +{ + for (;;) { + + // Receive message + thread_id sender; + uint32 code = receive_data(&sender, NULL, 0); + D(bug("Display manager received %08lx\n", code)); + switch (code) { + case MSG_QUIT_DISPLAY_MANAGER: + return 0; + + case MSG_OPEN_WINDOW: + D(bug("Opening window\n")); + the_window = new MacWindow(BRect(0, 0, VModes[cur_mode].viXsize-1, VModes[cur_mode].viYsize-1)); + D(bug("Opened\n")); + break; + + case MSG_CLOSE_WINDOW: + if (the_window != NULL) { + D(bug("Posting quit to window\n")); + the_window->PostMessage(B_QUIT_REQUESTED); + D(bug("Posted, waiting\n")); + while (the_window) + snooze(200000); + D(bug("Window closed\n")); + } + break; + + case MSG_OPEN_SCREEN: { + D(bug("Opening screen\n")); + long scr_mode = 0; + switch (VModes[cur_mode].viAppleMode) { + case APPLE_8_BIT: + switch (VModes[cur_mode].viAppleID) { + case APPLE_640x480: + scr_mode = B_8_BIT_640x480; + break; + case APPLE_800x600: + scr_mode = B_8_BIT_800x600; + break; + case APPLE_1024x768: + scr_mode = B_8_BIT_1024x768; + break; + case APPLE_1152x900: + scr_mode = B_8_BIT_1152x900; + break; + case APPLE_1280x1024: + scr_mode = B_8_BIT_1280x1024; + break; + case APPLE_1600x1200: + scr_mode = B_8_BIT_1600x1200; + break; + } + break; + case APPLE_16_BIT: + switch (VModes[cur_mode].viAppleID) { + case APPLE_640x480: + scr_mode = B_15_BIT_640x480; + break; + case APPLE_800x600: + scr_mode = B_15_BIT_800x600; + break; + case APPLE_1024x768: + scr_mode = B_15_BIT_1024x768; + break; + case APPLE_1152x900: + scr_mode = B_15_BIT_1152x900; + break; + case APPLE_1280x1024: + scr_mode = B_15_BIT_1280x1024; + break; + case APPLE_1600x1200: + scr_mode = B_15_BIT_1600x1200; + break; + } + break; + case APPLE_32_BIT: + switch (VModes[cur_mode].viAppleID) { + case APPLE_640x480: + scr_mode = B_32_BIT_640x480; + break; + case APPLE_800x600: + scr_mode = B_32_BIT_800x600; + break; + case APPLE_1024x768: + scr_mode = B_32_BIT_1024x768; + break; + case APPLE_1152x900: + scr_mode = B_32_BIT_1152x900; + break; + case APPLE_1280x1024: + scr_mode = B_32_BIT_1280x1024; + break; + case APPLE_1600x1200: + scr_mode = B_32_BIT_1600x1200; + break; + } + break; + } + the_screen = new MacScreen(GetString(STR_WINDOW_TITLE), scr_mode); + D(bug("Opened, error %08lx\n", screen_error)); + if (screen_error != B_NO_ERROR) { + D(bug("Error, posting quit to screen\n")); + the_screen->PostMessage(B_QUIT_REQUESTED); + D(bug("Posted, waiting\n")); + while (the_screen) + snooze(200000); + D(bug("Screen closed\n")); + break; + } + + // Wait for video mem access + D(bug("Showing screen\n")); + the_screen->Show(); + D(bug("Shown, waiting for frame buffer access\n")); + while (!drawing_enable) + snooze(200000); + D(bug("Access granted\n")); + break; + } + + case MSG_CLOSE_SCREEN: + if (the_screen != NULL) { + D(bug("Posting quit to screen\n")); + the_screen->PostMessage(B_QUIT_REQUESTED); + D(bug("Posted, waiting\n")); + while (the_screen) + snooze(200000); + D(bug("Screen closed\n")); + } + break; + } + + // Acknowledge + release_sem(dm_done_sem); + } +} + + +/* + * Open display (window or screen) + */ + +static void open_display(void) +{ + D(bug("entering open_display()\n")); + display_type = VModes[cur_mode].viType; + if (display_type == DIS_SCREEN) { + while (send_data(dm_thread, MSG_OPEN_SCREEN, NULL, 0) == B_INTERRUPTED) ; + while (acquire_sem(dm_done_sem) == B_INTERRUPTED) ; + } else if (display_type == DIS_WINDOW) { + while (send_data(dm_thread, MSG_OPEN_WINDOW, NULL, 0) == B_INTERRUPTED) ; + while (acquire_sem(dm_done_sem) == B_INTERRUPTED) ; + } + D(bug("exiting open_display()\n")); +} + + +/* + * Close display + */ + +static void close_display(void) +{ + D(bug("entering close_display()\n")); + if (display_type == DIS_SCREEN) { + while (send_data(dm_thread, MSG_CLOSE_SCREEN, NULL, 0) == B_INTERRUPTED) ; + while (acquire_sem(dm_done_sem) == B_INTERRUPTED) ; + } else if (display_type == DIS_WINDOW) { + while (send_data(dm_thread, MSG_CLOSE_WINDOW, NULL, 0) == B_INTERRUPTED) ; + while (acquire_sem(dm_done_sem) == B_INTERRUPTED) ; + } + D(bug("exiting close_display()\n")); +} + + +/* + * Initialization + */ + +static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type) +{ + if (allow & test) { + p->viType = type; + switch (apple_id) { + case APPLE_W_640x480: + case APPLE_640x480: + p->viXsize = 640; + p->viYsize = 480; + break; + case APPLE_W_800x600: + case APPLE_800x600: + p->viXsize = 800; + p->viYsize = 600; + break; + case APPLE_1024x768: + p->viXsize = 1024; + p->viYsize = 768; + break; + case APPLE_1152x900: + p->viXsize = 1152; + p->viYsize = 900; + break; + case APPLE_1280x1024: + p->viXsize = 1280; + p->viYsize = 1024; + break; + case APPLE_1600x1200: + p->viXsize = 1600; + p->viYsize = 1200; + break; + } + switch (apple_mode) { + case APPLE_8_BIT: + p->viRowBytes = p->viXsize; + break; + case APPLE_16_BIT: + p->viRowBytes = p->viXsize * 2; + break; + case APPLE_32_BIT: + p->viRowBytes = p->viXsize * 4; + break; + } + p->viAppleMode = apple_mode; + p->viAppleID = apple_id; + p++; + } +} + +bool VideoInit(void) +{ + // Init variables, create semaphores + private_data = NULL; + cur_mode = 0; // Window 640x480 + video_lock = create_sem(1, "Video Lock"); + mac_os_lock = create_sem(0, "MacOS Frame Buffer Lock"); + dm_done_sem = create_sem(0, "Display Manager Done"); + + // Construct video mode table + VideoInfo *p = VModes; + uint32 window_modes = PrefsFindInt32("windowmodes"); + uint32 screen_modes = PrefsFindInt32("screenmodes"); + if (window_modes == 0 && screen_modes == 0) + window_modes |= B_8_BIT_640x480 | B_8_BIT_800x600; // Allow at least 640x480 and 800x600 window modes + add_mode(p, window_modes, B_8_BIT_640x480, APPLE_8_BIT, APPLE_W_640x480, DIS_WINDOW); + add_mode(p, window_modes, B_8_BIT_800x600, APPLE_8_BIT, APPLE_W_800x600, DIS_WINDOW); + add_mode(p, window_modes, B_15_BIT_640x480, APPLE_16_BIT, APPLE_W_640x480, DIS_WINDOW); + add_mode(p, window_modes, B_15_BIT_800x600, APPLE_16_BIT, APPLE_W_800x600, DIS_WINDOW); + add_mode(p, window_modes, B_32_BIT_640x480, APPLE_32_BIT, APPLE_W_640x480, DIS_WINDOW); + add_mode(p, window_modes, B_32_BIT_800x600, APPLE_32_BIT, APPLE_W_800x600, DIS_WINDOW); + add_mode(p, screen_modes, B_8_BIT_640x480, APPLE_8_BIT, APPLE_640x480, DIS_SCREEN); + add_mode(p, screen_modes, B_8_BIT_800x600, APPLE_8_BIT, APPLE_800x600, DIS_SCREEN); + add_mode(p, screen_modes, B_8_BIT_1024x768, APPLE_8_BIT, APPLE_1024x768, DIS_SCREEN); + add_mode(p, screen_modes, B_8_BIT_1152x900, APPLE_8_BIT, APPLE_1152x900, DIS_SCREEN); + add_mode(p, screen_modes, B_8_BIT_1280x1024, APPLE_8_BIT, APPLE_1280x1024, DIS_SCREEN); + add_mode(p, screen_modes, B_8_BIT_1600x1200, APPLE_8_BIT, APPLE_1600x1200, DIS_SCREEN); + add_mode(p, screen_modes, B_15_BIT_640x480, APPLE_16_BIT, APPLE_640x480, DIS_SCREEN); + add_mode(p, screen_modes, B_15_BIT_800x600, APPLE_16_BIT, APPLE_800x600, DIS_SCREEN); + add_mode(p, screen_modes, B_15_BIT_1024x768, APPLE_16_BIT, APPLE_1024x768, DIS_SCREEN); + add_mode(p, screen_modes, B_15_BIT_1152x900, APPLE_16_BIT, APPLE_1152x900, DIS_SCREEN); + add_mode(p, screen_modes, B_15_BIT_1280x1024, APPLE_16_BIT, APPLE_1280x1024, DIS_SCREEN); + add_mode(p, screen_modes, B_15_BIT_1600x1200, APPLE_16_BIT, APPLE_1600x1200, DIS_SCREEN); + add_mode(p, screen_modes, B_32_BIT_640x480, APPLE_32_BIT, APPLE_640x480, DIS_SCREEN); + add_mode(p, screen_modes, B_32_BIT_800x600, APPLE_32_BIT, APPLE_800x600, DIS_SCREEN); + add_mode(p, screen_modes, B_32_BIT_1024x768, APPLE_32_BIT, APPLE_1024x768, DIS_SCREEN); + add_mode(p, screen_modes, B_32_BIT_1152x900, APPLE_32_BIT, APPLE_1152x900, DIS_SCREEN); + add_mode(p, screen_modes, B_32_BIT_1280x1024, APPLE_32_BIT, APPLE_1280x1024, DIS_SCREEN); + add_mode(p, screen_modes, B_32_BIT_1600x1200, APPLE_32_BIT, APPLE_1600x1200, DIS_SCREEN); + p->viType = DIS_INVALID; // End marker + p->viRowBytes = 0; + p->viXsize = p->viYsize = 0; + p->viAppleMode = 0; + p->viAppleID = 0; + + // Start display manager thread + dm_thread = spawn_thread(display_manager, "Display Manager", B_NORMAL_PRIORITY, NULL); + resume_thread(dm_thread); + + // Open window/screen + open_display(); + if (display_type == DIS_SCREEN && the_screen == NULL) { + char str[256]; + sprintf(str, GetString(STR_FULL_SCREEN_ERR), strerror(screen_error), screen_error); + ErrorAlert(str); + return false; + } + return true; +} + + +/* + * Deinitialization + */ + +void VideoExit(void) +{ + if (dm_thread >= 0) { + + // Close display + acquire_sem(video_lock); + close_display(); + if (private_data != NULL) { + delete private_data->gammaTable; + delete private_data; + } + + // Stop display manager + status_t l; + send_data(dm_thread, MSG_QUIT_DISPLAY_MANAGER, NULL, 0); + while (wait_for_thread(dm_thread, &l) == B_INTERRUPTED) ; + } + + // Delete semaphores + delete_sem(video_lock); + delete_sem(mac_os_lock); + delete_sem(dm_done_sem); +} + + +/* + * Close screen in full-screen mode + */ + +void VideoQuitFullScreen(void) +{ + D(bug("VideoQuitFullScreen()\n")); + if (display_type == DIS_SCREEN) { + acquire_sem(video_lock); + close_display(); + release_sem(video_lock); + } +} + + +/* + * Execute video VBL routine + */ + +void VideoVBL(void) +{ + release_sem(mac_os_lock); + if (private_data != NULL && private_data->interruptsEnabled) + VSLDoInterruptService(private_data->vslServiceID); + while (acquire_sem(mac_os_lock) == B_INTERRUPTED) ; +} + + +/* + * Filter function for receiving mouse and keyboard events + */ + +#define MENU_IS_POWER 0 + +// Be -> Mac raw keycode translation table +static const uint8 keycode2mac[0x80] = { + 0xff, 0x35, 0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, // inv Esc F1 F2 F3 F4 F5 F6 + 0x62, 0x64, 0x65, 0x6d, 0x67, 0x6f, 0x69, 0x6b, // F7 F8 F9 F10 F11 F12 F13 F14 + 0x71, 0x0a, 0x12, 0x13, 0x14, 0x15, 0x17, 0x16, // F15 ` 1 2 3 4 5 6 + 0x1a, 0x1c, 0x19, 0x1d, 0x1b, 0x18, 0x33, 0x72, // 7 8 9 0 - = BSP INS + 0x73, 0x74, 0x47, 0x4b, 0x43, 0x4e, 0x30, 0x0c, // HOM PUP NUM / * - TAB Q + 0x0d, 0x0e, 0x0f, 0x11, 0x10, 0x20, 0x22, 0x1f, // W E R T Y U I O + 0x23, 0x21, 0x1e, 0x2a, 0x75, 0x77, 0x79, 0x59, // P [ ] \ DEL END PDN 7 + 0x5b, 0x5c, 0x45, 0x39, 0x00, 0x01, 0x02, 0x03, // 8 9 + CAP A S D F + 0x05, 0x04, 0x26, 0x28, 0x25, 0x29, 0x27, 0x24, // G H J K L ; ' RET + 0x56, 0x57, 0x58, 0x38, 0x06, 0x07, 0x08, 0x09, // 4 5 6 SHL Z X C V + 0x0b, 0x2d, 0x2e, 0x2b, 0x2f, 0x2c, 0x38, 0x3e, // B N M , . / SHR CUP + 0x53, 0x54, 0x55, 0x4c, 0x36, 0x37, 0x31, 0x37, // 1 2 3 ENT CTL ALT SPC ALT + 0x36, 0x3b, 0x3d, 0x3c, 0x52, 0x41, 0x3a, 0x3a, // CTR CLF CDN CRT 0 . CMD CMD +#if MENU_IS_POWER + 0x7f, 0x32, 0x51, 0x7f, 0xff, 0xff, 0xff, 0xff, // MNU EUR = POW inv inv inv inv +#else + 0x32, 0x32, 0x51, 0x7f, 0xff, 0xff, 0xff, 0xff, // MNU EUR = POW inv inv inv inv +#endif + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv +}; + +static const uint8 modifier2mac[0x20] = { +#if MENU_IS_POWER + 0x38, 0x37, 0x36, 0x39, 0x6b, 0x47, 0x3a, 0x7f, // SHF CMD inv CAP F14 NUM OPT MNU +#else + 0x38, 0x37, 0x36, 0x39, 0x6b, 0x47, 0x3a, 0x32, // SHF CMD CTR CAP F14 NUM OPT MNU +#endif + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv +}; + +static filter_result filter_func(BMessage *msg, BHandler **target, BMessageFilter *filter) +{ +// msg->PrintToStream(); + switch (msg->what) { + case B_KEY_DOWN: + case B_KEY_UP: { + uint32 be_code = msg->FindInt32("key") & 0xff; + uint32 mac_code = keycode2mac[be_code]; + + // Intercept Ctrl-F1 (mount floppy disk shortcut) + uint32 mods = msg->FindInt32("modifiers"); + if (be_code == 0x02 && (mods & B_CONTROL_KEY)) + SysMountVolume("/dev/disk/floppy/raw"); + + if (mac_code == 0xff) + return B_DISPATCH_MESSAGE; + if (msg->what == B_KEY_DOWN) + ADBKeyDown(mac_code); + else + ADBKeyUp(mac_code); + return B_SKIP_MESSAGE; + } + + case B_MODIFIERS_CHANGED: { + uint32 mods = msg->FindInt32("modifiers"); + uint32 old_mods = msg->FindInt32("be:old_modifiers"); + uint32 changed = mods ^ old_mods; + uint32 mask = 1; + for (int i=0; i<32; i++, mask<<=1) + if (changed & mask) { + uint32 mac_code = modifier2mac[i]; + if (mac_code == 0xff) + continue; + if (mods & mask) + ADBKeyDown(mac_code); + else + ADBKeyUp(mac_code); + } + return B_SKIP_MESSAGE; + } + + case B_MOUSE_MOVED: { + BPoint point; + msg->FindPoint("where", &point); + ADBMouseMoved(int(point.x), int(point.y)); + return B_DISPATCH_MESSAGE; // Otherwise BitmapView::MouseMoved() wouldn't be called + } + + case B_MOUSE_DOWN: { + uint32 buttons = msg->FindInt32("buttons"); + if (buttons & B_PRIMARY_MOUSE_BUTTON) + ADBMouseDown(0); + if (buttons & B_SECONDARY_MOUSE_BUTTON) + ADBMouseDown(1); + if (buttons & B_TERTIARY_MOUSE_BUTTON) + ADBMouseDown(2); + return B_SKIP_MESSAGE; + } + + case B_MOUSE_UP: // B_MOUSE_UP means "all buttons released" + ADBMouseUp(0); + ADBMouseUp(1); + ADBMouseUp(2); + return B_SKIP_MESSAGE; + + default: + return B_DISPATCH_MESSAGE; + } +} + + +/* + * Install graphics acceleration + */ + +// Rectangle blitting +static void accl_bitblt(accl_params *p) +{ + D(bug("accl_bitblt\n")); + + // Get blitting parameters + int16 src_X = p->src_rect[1] - p->src_bounds[1]; + int16 src_Y = p->src_rect[0] - p->src_bounds[0]; + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 width = p->dest_rect[3] - p->dest_rect[1] - 1; + int16 height = p->dest_rect[2] - p->dest_rect[0] - 1; + D(bug(" src X %d, src Y %d, dest X %d, dest Y %d\n", src_X, src_Y, dest_X, dest_Y)); + D(bug(" width %d, height %d\n", width, height)); + + // And perform the blit + bitblt_hook(src_X, src_Y, dest_X, dest_Y, width, height); +} + +static bool accl_bitblt_hook(accl_params *p) +{ + D(bug("accl_draw_hook %p\n", p)); + + // Check if we can accelerate this bitblt + if (p->src_base_addr == screen_base && p->dest_base_addr == screen_base && + display_type == DIS_SCREEN && bitblt_hook != NULL && + ((uint32 *)p)[0x18 >> 2] + ((uint32 *)p)[0x128 >> 2] == 0 && + ((uint32 *)p)[0x130 >> 2] == 0 && + p->transfer_mode == 0 && + p->src_row_bytes > 0 && ((uint32 *)p)[0x15c >> 2] > 0) { + + // Yes, set function pointer + p->draw_proc = accl_bitblt; + return true; + } + return false; +} + +// Rectangle filling/inversion +static void accl_fillrect8(accl_params *p) +{ + D(bug("accl_fillrect8\n")); + + // Get filling parameters + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; + int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; + uint8 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen; + D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); + D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); + + // And perform the fill + fillrect8_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); +} + +static void accl_fillrect32(accl_params *p) +{ + D(bug("accl_fillrect32\n")); + + // Get filling parameters + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; + int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; + uint32 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen; + D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); + D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); + + // And perform the fill + fillrect32_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); +} + +static void accl_invrect(accl_params *p) +{ + D(bug("accl_invrect\n")); + + // Get inversion parameters + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; + int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; + D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); + D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); + + //!!?? pen_mode == 14 + + // And perform the inversion + invrect_hook(dest_X, dest_Y, dest_X_max, dest_Y_max); +} + +static bool accl_fillrect_hook(accl_params *p) +{ + D(bug("accl_fillrect_hook %p\n", p)); + + // Check if we can accelerate this fillrect + if (p->dest_base_addr == screen_base && ((uint32 *)p)[0x284 >> 2] != 0 && display_type == DIS_SCREEN) { + if (p->transfer_mode == 8) { + // Fill + if (p->dest_pixel_size == 8 && fillrect8_hook != NULL) { + p->draw_proc = accl_fillrect8; + return true; + } else if (p->dest_pixel_size == 32 && fillrect32_hook != NULL) { + p->draw_proc = accl_fillrect32; + return true; + } + } else if (p->transfer_mode == 10 && invrect_hook != NULL) { + // Invert + p->draw_proc = accl_invrect; + return true; + } + } + return false; +} + +// Dummy for testing +/* +static void do_nothing(accl_params *p) {} +static bool accl_foobar_hook(accl_params *p) +{ + printf("accl_foobar_hook %p\n", p); + printf(" src_base_addr %p, dest_base_addr %p\n", p->src_base_addr, p->dest_base_addr); + printf(" src_row_bytes %d, dest_row_bytes %d\n", p->src_row_bytes, p->dest_row_bytes); + printf(" src_pixel_size %d, dest_pixel_size %d\n", p->src_pixel_size, p->dest_pixel_size); + printf(" src_bounds (%d,%d,%d,%d), dest_bounds (%d,%d,%d,%d)\n", p->src_bounds[0], p->src_bounds[1], p->src_bounds[2], p->src_bounds[3], p->dest_bounds[0], p->dest_bounds[1], p->dest_bounds[2], p->dest_bounds[3]); + printf(" src_rect (%d,%d,%d,%d), dest_rect (%d,%d,%d,%d)\n", p->src_rect[0], p->src_rect[1], p->src_rect[2], p->src_rect[3], p->dest_rect[0], p->dest_rect[1], p->dest_rect[2], p->dest_rect[3]); + printf(" transfer mode %d\n", p->transfer_mode); + printf(" pen mode %d\n", p->pen_mode); + printf(" fore_pen %08x, back_pen %08x\n", p->fore_pen, p->back_pen); + printf(" val1 %08x, val2 %08x\n", ((uint32 *)p)[0x18 >> 2], ((uint32 *)p)[0x128 >> 2]); + printf(" val3 %08x\n", ((uint32 *)p)[0x130 >> 2]); + printf(" val4 %08x\n", ((uint32 *)p)[0x15c >> 2]); + printf(" val5 %08x\n", ((uint32 *)p)[0x160 >> 2]); + printf(" val6 %08x\n", ((uint32 *)p)[0x1b4 >> 2]); + printf(" val7 %08x\n", ((uint32 *)p)[0x284 >> 2]); + p->draw_proc = do_nothing; + return true; +} +static struct accl_hook_info foobar_hook_info = {accl_foobar_hook, accl_sync_hook, 6}; +*/ + +// Wait for graphics operation to finish +static bool accl_sync_hook(void *arg) +{ + D(bug("accl_sync_hook %p\n", arg)); + if (sync_hook != NULL) + sync_hook(); + return true; +} + +static struct accl_hook_info bitblt_hook_info = {accl_bitblt_hook, accl_sync_hook, ACCL_BITBLT}; +static struct accl_hook_info fillrect_hook_info = {accl_fillrect_hook, accl_sync_hook, ACCL_FILLRECT}; + +void VideoInstallAccel(void) +{ + // Install acceleration hooks + if (PrefsFindBool("gfxaccel")) { + D(bug("Video: Installing acceleration hooks\n")); + NQDMisc(6, &bitblt_hook_info); + NQDMisc(6, &fillrect_hook_info); + } +} + + +/* + * Change video mode + */ + +int16 video_mode_change(VidLocals *csSave, uint32 ParamPtr) +{ + /* return if no mode change */ + if ((csSave->saveData == ReadMacInt32(ParamPtr + csData)) && + (csSave->saveMode == ReadMacInt16(ParamPtr + csMode))) return noErr; + + /* first find video mode in table */ + for (int i=0; VModes[i].viType != DIS_INVALID; i++) { + if ((ReadMacInt16(ParamPtr + csMode) == VModes[i].viAppleMode) && + (ReadMacInt32(ParamPtr + csData) == VModes[i].viAppleID)) { + csSave->saveMode = ReadMacInt16(ParamPtr + csMode); + csSave->saveData = ReadMacInt32(ParamPtr + csData); + csSave->savePage = ReadMacInt16(ParamPtr + csPage); + + while (acquire_sem(video_lock) == B_INTERRUPTED) ; + DisableInterrupt(); + + /* close old display */ + close_display(); + + /* open new display */ + cur_mode = i; + open_display(); + + /* opening the screen failed? Then bail out */ + if (display_type == DIS_SCREEN && the_screen == NULL) { + release_sem(video_lock); + ErrorAlert(GetString(STR_FULL_SCREEN_ERR)); + QuitEmulator(); + } + + WriteMacInt32(ParamPtr + csBaseAddr, screen_base); + csSave->saveBaseAddr=screen_base; + csSave->saveData=VModes[cur_mode].viAppleID;/* First mode ... */ + csSave->saveMode=VModes[cur_mode].viAppleMode; + + EnableInterrupt(); + release_sem(video_lock); + return noErr; + } + } + return paramErr; +} + + +/* + * Set color palette + */ + +void video_set_palette(void) +{ + if (display_type == DIS_SCREEN && the_screen != NULL) + the_screen->palette_changed = true; + else { // remap colors to BeOS-Palette + BScreen screen; + for (int i=0;i<256;i++) + remap_mac_be[i]=screen.IndexForColor(mac_pal[i].red,mac_pal[i].green,mac_pal[i].blue); + } +} + + +/* + * Set cursor image for window + */ + +void video_set_cursor(void) +{ + the_window->cursor_changed = true; // Inform window (don't set cursor directly because this may run at interrupt (i.e. signal handler) time) +} diff --git a/SheepShaver/src/BeOS/video_screen.h b/SheepShaver/src/BeOS/video_screen.h new file mode 100644 index 00000000..ed86ab1b --- /dev/null +++ b/SheepShaver/src/BeOS/video_screen.h @@ -0,0 +1,262 @@ +/* + * video_screen.h - Full screen video modes + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * 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 + */ + + +static bool drawing_enable = false; // This flag indicated if the access to the screen is allowed +static int page_num; // Index of the currently displayed buffer + + +// Blitter functions +typedef void (*bitblt_ptr)(int32, int32, int32, int32, int32, int32); +static bitblt_ptr bitblt_hook; +typedef void (*fillrect8_ptr)(int32, int32, int32, int32, uint8); +static fillrect8_ptr fillrect8_hook; +typedef void (*fillrect32_ptr)(int32, int32, int32, int32, uint32); +static fillrect32_ptr fillrect32_hook; +typedef void (*invrect_ptr)(int32, int32, int32, int32); +static invrect_ptr invrect_hook; +typedef void (*sync_ptr)(void); +static sync_ptr sync_hook; + + +class MacScreen : public BWindowScreen { +public: + MacScreen(const char *name, uint32 space); + virtual ~MacScreen(); + virtual void Quit(void); + virtual void ScreenConnected(bool active); + + bool palette_changed; + +private: + static status_t tick_func(void *arg); + + BView *view; // Main view for GetMouse() + + uint8 *frame_backup; // Frame buffer backup when switching from/to different workspace + bool quitting; // Flag for ScreenConnected: We are quitting, don't pause emulator thread + bool first; // Flag for ScreenConnected: This is the first time we become active + + thread_id tick_thread; + bool tick_thread_active; +}; + + +// Pointer to our screen +static MacScreen *the_screen = NULL; + +// Error code from BWindowScreen constructor +static status_t screen_error; + +// to enable debugger mode. +#define SCREEN_DEBUG false + + +/* + * Screen constructor + */ + +MacScreen::MacScreen(const char *name, uint32 space) : BWindowScreen(name, space, &screen_error, SCREEN_DEBUG), tick_thread(-1) +{ + D(bug("Screen constructor\n")); + + // Set all variables + frame_backup = NULL; + palette_changed = false; + quitting = false; + first = true; + drawing_enable = false; + ADBSetRelMouseMode(true); + + // Create view to poll the mouse + view = new BView (BRect(0,0,VModes[cur_mode].viXsize-1,VModes[cur_mode].viYsize-1),NULL,B_FOLLOW_NONE,0); + AddChild(view); + + // Start 60Hz interrupt + tick_thread_active = true; + tick_thread = spawn_thread(tick_func, "Polling sucks...", B_DISPLAY_PRIORITY, this); + RegisterThread(tick_thread); + resume_thread(tick_thread); + + // Add filter for keyboard and mouse events + BMessageFilter *filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, filter_func); + AddCommonFilter(filter); + D(bug("Screen constructor done\n")); +} + + +/* + * Screen destructor + */ + +MacScreen::~MacScreen() +{ + D(bug("Screen destructor, quitting tick thread\n")); + + // Stop 60Hz interrupt + if (tick_thread > 0) { + status_t l; + tick_thread_active = false; + while (wait_for_thread(tick_thread, &l) == B_INTERRUPTED) ; + } + D(bug("tick thread quit\n")); + + // Tell the emulator that we're done + the_screen = NULL; + D(bug("Screen destructor done\n")); +} + + +/* + * Screen closed + */ + +void MacScreen::Quit(void) +{ + // Tell ScreenConnected() that we are quitting + quitting = true; + D(bug("MacScreen::Quit(), disconnecting\n")); + Disconnect(); + D(bug("disconnected\n")); + BWindowScreen::Quit(); +} + + +/* + * Screen connected/disconnected + */ + +void MacScreen::ScreenConnected(bool active) +{ + D(bug("ScreenConnected(%d)\n", active)); + graphics_card_info *info = CardInfo(); + D(bug(" card_info %p\n", info)); + + if (active) { + + // Read graphics parameters + D(bug(" active\n")); + screen_base = (uint32)info->frame_buffer; + D(bug(" screen_base %p\n", screen_base)); + VModes[cur_mode].viRowBytes = info->bytes_per_row; + D(bug(" xmod %d\n", info->bytes_per_row)); + + // Get acceleration functions + if (PrefsFindBool("gfxaccel")) { + bitblt_hook = (bitblt_ptr)CardHookAt(7); + D(bug(" bitblt_hook %p\n", bitblt_hook)); + fillrect8_hook = (fillrect8_ptr)CardHookAt(5); + D(bug(" fillrect8_hook %p\n", fillrect8_hook)); + fillrect32_hook = (fillrect32_ptr)CardHookAt(6); + D(bug(" fillrect32_hook %p\n", fillrect32_hook)); + invrect_hook = (invrect_ptr)CardHookAt(11); + D(bug(" invrect_hook %p\n", invrect_hook)); + sync_hook = (sync_ptr)CardHookAt(10); + D(bug(" sync_hook %p\n", sync_hook)); + } else { + bitblt_hook = NULL; + fillrect8_hook = NULL; + fillrect32_hook = NULL; + invrect_hook = NULL; + sync_hook = NULL; + } + + // The first time we got the screen, we need to init the Window + if (first) { + D(bug(" first time\n")); + first = false; + page_num = 0; // current display : page 0 + } else { // we get our screen back + D(bug(" not first time\n")); + // copy from backup bitmap to framebuffer + memcpy((void *)screen_base, frame_backup, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize); + // delete backup bitmap + delete[] frame_backup; + frame_backup = NULL; + // restore palette + if (info->bits_per_pixel == 8) + SetColorList(mac_pal); + // restart emul thread + release_sem(mac_os_lock); + } + + // allow the drawing in the frame buffer + D(bug(" enabling frame buffer access\n")); + drawing_enable = true; + video_activated = true; + + } else { + + drawing_enable = false; // stop drawing. + video_activated = false; + if (!quitting) { + // stop emul thread + acquire_sem(mac_os_lock); + // create bitmap and store frame buffer into + frame_backup = new uint8[VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize]; + memcpy(frame_backup, (void *)screen_base, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize); + } + } + D(bug("ScreenConnected() done\n")); +} + + +/* + * 60Hz interrupt routine + */ + +status_t MacScreen::tick_func(void *arg) +{ + MacScreen *obj = (MacScreen *)arg; + while (obj->tick_thread_active) { + + // Wait + snooze(16667); + + // Workspace activated? Then poll the mouse and change the palette if needed + if (video_activated) { + BPoint pt; + uint32 button = 0; + if (obj->LockWithTimeout(200000) == B_OK) { + if (obj->palette_changed) { + obj->palette_changed = false; + obj->SetColorList(mac_pal); + } + obj->view->GetMouse(&pt, &button); + obj->Unlock(); + set_mouse_position(320, 240); + ADBMouseMoved(int(pt.x) - 320, int(pt.y) - 240); + if (button & B_PRIMARY_MOUSE_BUTTON) + ADBMouseDown(0); + if (!(button & B_PRIMARY_MOUSE_BUTTON)) + ADBMouseUp(0); + if (button & B_SECONDARY_MOUSE_BUTTON) + ADBMouseDown(1); + if (!(button & B_SECONDARY_MOUSE_BUTTON)) + ADBMouseUp(1); + if (button & B_TERTIARY_MOUSE_BUTTON) + ADBMouseDown(2); + if (!(button & B_TERTIARY_MOUSE_BUTTON)) + ADBMouseUp(2); + } + } + } + return 0; +} diff --git a/SheepShaver/src/BeOS/video_window.h b/SheepShaver/src/BeOS/video_window.h new file mode 100644 index 00000000..c847b2cc --- /dev/null +++ b/SheepShaver/src/BeOS/video_window.h @@ -0,0 +1,523 @@ +/* + * video_window.h - Window video modes + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +// Messages +static const uint32 MSG_REDRAW = 'draw'; +static const uint32 MSG_ABOUT_REQUESTED = B_ABOUT_REQUESTED; +static const uint32 MSG_REF_5HZ = ' 5Hz'; +static const uint32 MSG_REF_7_5HZ = ' 7Hz'; +static const uint32 MSG_REF_10HZ = '10Hz'; +static const uint32 MSG_REF_15HZ = '15Hz'; +static const uint32 MSG_REF_30HZ = '30Hz'; +static const uint32 MSG_REF_60HZ = '60Hz'; +static const uint32 MSG_MOUNT = 'moun'; + +static bool mouse_in_view; // Flag: Mouse pointer within bitmap view + +// From sys_beos.cpp +extern void SysCreateVolumeMenu(BMenu *menu, uint32 msg); +extern void SysMountVolume(const char *name); + + +/* + * A simple view class for blitting a bitmap on the screen + */ + +class BitmapView : public BView { +public: + BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "bitmap", B_FOLLOW_NONE, B_WILL_DRAW) + { + the_bitmap = bitmap; + } + virtual void Draw(BRect update) + { + if (the_bitmap) + DrawBitmap(the_bitmap, update, update); + } + virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + +private: + BBitmap *the_bitmap; +}; + + +/* + * Window class + */ + +class MacWindow : public BDirectWindow { +public: + MacWindow(BRect frame); + virtual ~MacWindow(); + virtual void MessageReceived(BMessage *msg); + virtual void DirectConnected(direct_buffer_info *info); + virtual void WindowActivated(bool active); + + int32 frame_skip; + bool cursor_changed; // Flag: set new cursor image in tick function + +private: + static status_t tick_func(void *arg); + + BitmapView *main_view; + BBitmap *the_bitmap; + uint8 *the_buffer; + + uint32 old_scroll_lock_state; + + thread_id tick_thread; + bool tick_thread_active; + + bool supports_direct_mode; + bool bit_bang; + sem_id drawing_sem; + + color_space mode; + void *bits; + int32 bytes_per_row; + color_space pixel_format; + bool unclipped; +}; + + +// Pointer to our window +static MacWindow *the_window = NULL; + + +/* + * Window constructor + */ + +MacWindow::MacWindow(BRect frame) : BDirectWindow(frame, GetString(STR_WINDOW_TITLE), B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE) +{ + D(bug("Window constructor\n")); + supports_direct_mode = SupportsWindowMode(); + cursor_changed = false; + bit_bang = supports_direct_mode && PrefsFindBool("bitbang"); + + // Move window to right position + Lock(); + MoveTo(80, 60); + + // Allocate bitmap + { + BScreen scr(this); + mode = B_COLOR_8_BIT; + switch (VModes[cur_mode].viAppleMode) { + case APPLE_8_BIT: + mode = B_COLOR_8_BIT; + bit_bang = false; + break; + case APPLE_16_BIT: + mode = B_RGB_16_BIT; + if (scr.ColorSpace() != B_RGB15_BIG && scr.ColorSpace() != B_RGBA15_BIG) + bit_bang = false; + break; + case APPLE_32_BIT: + mode = B_RGB_32_BIT; + if (scr.ColorSpace() != B_RGB32_BIG && scr.ColorSpace() != B_RGBA32_BIG) + bit_bang = false; + break; + } + } + if (bit_bang) { + the_bitmap = NULL; + the_buffer = NULL; + } else { + the_bitmap = new BBitmap(frame, mode); + the_buffer = new uint8[VModes[cur_mode].viRowBytes * (VModes[cur_mode].viYsize + 2)]; // ("height + 2" for safety) + screen_base = (uint32)the_buffer; + } + + // Create bitmap view + main_view = new BitmapView(frame, the_bitmap); + AddChild(main_view); + main_view->MakeFocus(); + + // Read frame skip prefs + frame_skip = PrefsFindInt32("frameskip"); + + // Set up menus + BRect bounds = Bounds(); + bounds.OffsetBy(0, bounds.IntegerHeight() + 1); + BMenuItem *item; + BMenuBar *bar = new BMenuBar(bounds, "menu"); + BMenu *menu = new BMenu(GetString(STR_WINDOW_MENU)); + menu->AddItem(new BMenuItem(GetString(STR_WINDOW_ITEM_ABOUT), new BMessage(MSG_ABOUT_REQUESTED))); + menu->AddItem(new BSeparatorItem); + BMenu *submenu = new BMenu(GetString(STR_WINDOW_ITEM_REFRESH)); + submenu->AddItem(new BMenuItem(GetString(STR_REF_5HZ_LAB), new BMessage(MSG_REF_5HZ))); + submenu->AddItem(new BMenuItem(GetString(STR_REF_7_5HZ_LAB), new BMessage(MSG_REF_7_5HZ))); + submenu->AddItem(new BMenuItem(GetString(STR_REF_10HZ_LAB), new BMessage(MSG_REF_10HZ))); + submenu->AddItem(new BMenuItem(GetString(STR_REF_15HZ_LAB), new BMessage(MSG_REF_15HZ))); + submenu->AddItem(new BMenuItem(GetString(STR_REF_30HZ_LAB), new BMessage(MSG_REF_30HZ))); + submenu->AddItem(new BMenuItem(GetString(STR_REF_60HZ_LAB), new BMessage(MSG_REF_60HZ))); + submenu->SetRadioMode(true); + if (frame_skip == 12) { + if ((item = submenu->FindItem(GetString(STR_REF_5HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (frame_skip == 8) { + if ((item = submenu->FindItem(GetString(STR_REF_7_5HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (frame_skip == 6) { + if ((item = submenu->FindItem(GetString(STR_REF_10HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (frame_skip == 4) { + if ((item = submenu->FindItem(GetString(STR_REF_15HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (frame_skip == 2) { + if ((item = submenu->FindItem(GetString(STR_REF_30HZ_LAB))) != NULL) + item->SetMarked(true); + } else if (frame_skip == 1) { + if ((item = submenu->FindItem(GetString(STR_REF_60HZ_LAB))) != NULL) + item->SetMarked(true); + } + menu->AddItem(submenu); + submenu = new BMenu(GetString(STR_WINDOW_ITEM_MOUNT)); + SysCreateVolumeMenu(submenu, MSG_MOUNT); + menu->AddItem(submenu); + bar->AddItem(menu); + AddChild(bar); + SetKeyMenuBar(bar); + int mbar_height = bar->Frame().IntegerHeight() + 1; + + // Resize window to fit menu bar + ResizeBy(0, mbar_height); + + // Set mouse mode and scroll lock state + ADBSetRelMouseMode(false); + mouse_in_view = true; + old_scroll_lock_state = modifiers() & B_SCROLL_LOCK; + if (old_scroll_lock_state) + SetTitle(GetString(STR_WINDOW_TITLE_FROZEN)); + else + SetTitle(GetString(STR_WINDOW_TITLE)); + + // Clear Mac cursor image + memset(MacCursor + 4, 0, 64); + + // Keep window aligned to 8-byte frame buffer boundaries for faster blitting + SetWindowAlignment(B_BYTE_ALIGNMENT, 8); + + // Create drawing semaphore (for direct mode) + drawing_sem = create_sem(0, "direct frame buffer access"); + + // Start 60Hz interrupt + tick_thread_active = true; + tick_thread = spawn_thread(tick_func, "Window Redraw", B_DISPLAY_PRIORITY, this); + resume_thread(tick_thread); + + // Add filter for keyboard and mouse events + BMessageFilter *filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, filter_func); + main_view->AddFilter(filter); + + // Show window + Unlock(); + Show(); + Sync(); + D(bug("Window constructor done\n")); +} + + +/* + * Window destructor + */ + +MacWindow::~MacWindow() +{ + // Restore cursor + mouse_in_view = false; + be_app->SetCursor(B_HAND_CURSOR); + + // Hide window + D(bug("Window destructor, hiding window\n")); + Hide(); + Sync(); + + // Stop 60Hz interrupt + D(bug("Quitting tick thread\n")); + status_t l; + tick_thread_active = false; + delete_sem(drawing_sem); + while (wait_for_thread(tick_thread, &l) == B_INTERRUPTED) ; + D(bug("tick thread quit\n")); + + // dispose allocated memory + delete the_bitmap; + delete[] the_buffer; + + // Tell emulator that we're done + the_window = NULL; + D(bug("Window destructor done\n")); +} + + +/* + * Window connected/disconnected + */ + +void MacWindow::DirectConnected(direct_buffer_info *info) +{ + D(bug("DirectConnected, state %d\n", info->buffer_state)); + switch (info->buffer_state & B_DIRECT_MODE_MASK) { + case B_DIRECT_STOP: + acquire_sem(drawing_sem); + break; + case B_DIRECT_MODIFY: + acquire_sem(drawing_sem); + case B_DIRECT_START: + bits = (void *)((uint8 *)info->bits + info->window_bounds.top * info->bytes_per_row + info->window_bounds.left * info->bits_per_pixel / 8); + bytes_per_row = info->bytes_per_row; + pixel_format = info->pixel_format; + unclipped = false; + if (info->clip_list_count == 1) + if (memcmp(&info->clip_bounds, &info->window_bounds, sizeof(clipping_rect)) == 0) + unclipped = true; + if (bit_bang) { + screen_base = (uint32)bits; + VModes[cur_mode].viRowBytes = bytes_per_row; + } + release_sem(drawing_sem); + break; + } + D(bug("DirectConnected done\n")); +} + + +/* + * Handles redraw messages + */ + +void MacWindow::MessageReceived(BMessage *msg) +{ + BMessage *msg2; + + switch (msg->what) { + case MSG_REDRAW: { + + // Prevent backlog of messages + MessageQueue()->Lock(); + while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) { + MessageQueue()->RemoveMessage(msg2); + delete msg2; + } + MessageQueue()->Unlock(); + + // Convert Mac screen buffer to BeOS palette and blit + uint32 length = VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize; + if (mode == B_COLOR_8_BIT) { + // Palette conversion + uint8 *source = the_buffer - 1; + uint8 *dest = (uint8 *)the_bitmap->Bits() - 1; + for (int i=0; iBits() - 1; + for (int i=0; iBits() - 1; + for (int i=0; iDrawBitmapAsync(the_bitmap, update_rect, update_rect); + break; + } + + case MSG_ABOUT_REQUESTED: + OpenAboutWindow(); + break; + + case MSG_REF_5HZ: + PrefsReplaceInt32("frameskip", frame_skip = 12); + break; + + case MSG_REF_7_5HZ: + PrefsReplaceInt32("frameskip", frame_skip = 8); + break; + + case MSG_REF_10HZ: + PrefsReplaceInt32("frameskip", frame_skip = 6); + break; + + case MSG_REF_15HZ: + PrefsReplaceInt32("frameskip", frame_skip = 4); + break; + + case MSG_REF_30HZ: + PrefsReplaceInt32("frameskip", frame_skip = 2); + break; + + case MSG_REF_60HZ: + PrefsReplaceInt32("frameskip", frame_skip = 1); + break; + + case MSG_MOUNT: { + BMenuItem *source = NULL; + msg->FindPointer("source", (void **)&source); + if (source) + SysMountVolume(source->Label()); + break; + } + + default: + BDirectWindow::MessageReceived(msg); + } +} + + +/* + * Window activated/deactivated + */ + +void MacWindow::WindowActivated(bool active) +{ + video_activated = active; + if (active) + frame_skip = PrefsFindInt32("frameskip"); + else + frame_skip = 12; // 5Hz in background + BDirectWindow::WindowActivated(active); +} + + +/* + * 60Hz interrupt routine + */ + +status_t MacWindow::tick_func(void *arg) +{ + MacWindow *obj = (MacWindow *)arg; + static int tick_counter = 0; + while (obj->tick_thread_active) { + + // Wait + snooze(16667); + + // Refresh window + if (!obj->bit_bang) + tick_counter++; + if (tick_counter >= obj->frame_skip) { + tick_counter = 0; + + // Window title is determined by Scroll Lock state + uint32 scroll_lock_state = modifiers() & B_SCROLL_LOCK; + if (scroll_lock_state != obj->old_scroll_lock_state) { + if (scroll_lock_state) + obj->SetTitle(GetString(STR_WINDOW_TITLE_FROZEN)); + else + obj->SetTitle(GetString(STR_WINDOW_TITLE)); + obj->old_scroll_lock_state = scroll_lock_state; + } + + // Refresh display unless Scroll Lock is down + if (!scroll_lock_state) { + + // If direct frame buffer access is supported and the content area is completely visible, + // convert the Mac screen buffer directly. Otherwise, send a message to the window to do + // it into a bitmap + if (obj->supports_direct_mode) { + if (acquire_sem_etc(obj->drawing_sem, 1, B_TIMEOUT, 200000) == B_NO_ERROR) { + if (obj->unclipped && obj->mode == B_COLOR_8_BIT && obj->pixel_format == B_CMAP8) { + uint8 *source = obj->the_buffer - 1; + uint8 *dest = (uint8 *)obj->bits; + uint32 bytes_per_row = obj->bytes_per_row; + int xsize = VModes[cur_mode].viXsize; + int ysize = VModes[cur_mode].viYsize; + for (int y=0; yunclipped && obj->mode == B_RGB_16_BIT && (obj->pixel_format == B_RGB15_BIG || obj->pixel_format == B_RGBA15_BIG)) { + uint8 *source = obj->the_buffer; + uint8 *dest = (uint8 *)obj->bits; + uint32 sbpr = VModes[cur_mode].viRowBytes; + uint32 dbpr = obj->bytes_per_row; + int xsize = VModes[cur_mode].viXsize; + int ysize = VModes[cur_mode].viYsize; + for (int y=0; yunclipped && obj->mode == B_RGB_32_BIT && (obj->pixel_format == B_RGB32_BIG || obj->pixel_format == B_RGBA32_BIG)) { + uint8 *source = obj->the_buffer; + uint8 *dest = (uint8 *)obj->bits; + uint32 sbpr = VModes[cur_mode].viRowBytes; + uint32 dbpr = obj->bytes_per_row; + int xsize = VModes[cur_mode].viXsize; + int ysize = VModes[cur_mode].viYsize; + for (int y=0; yPostMessage(MSG_REDRAW); + release_sem(obj->drawing_sem); + } + } else + obj->PostMessage(MSG_REDRAW); + } + } + + // Set new cursor image if desired + if (obj->cursor_changed) { + if (mouse_in_view) + be_app->SetCursor(MacCursor); + obj->cursor_changed = false; + } + } + return 0; +} + + +/* + * Mouse moved + */ + +void BitmapView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) +{ + switch (transit) { + case B_ENTERED_VIEW: + mouse_in_view = true; + be_app->SetCursor(MacCursor); + break; + case B_EXITED_VIEW: + mouse_in_view = false; + be_app->SetCursor(B_HAND_CURSOR); + break; + } +} diff --git a/SheepShaver/src/EthernetDriverStub.i b/SheepShaver/src/EthernetDriverStub.i new file mode 100644 index 00000000..fa381407 --- /dev/null +++ b/SheepShaver/src/EthernetDriverStub.i @@ -0,0 +1,43 @@ + 0x4a, 0x6f, 0x79, 0x21, 0x70, 0x65, 0x66, 0x66, 0x70, 0x77, 0x70, 0x63, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0x90, + 0x00, 0x04, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x58, + 0x00, 0x00, 0x01, 0x54, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x80, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0xb4, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x46, 0x07, 0x09, 0xc1, 0x01, 0x43, 0x00, 0x41, 0x00, 0x41, + 0x00, 0x42, 0x00, 0x41, 0x00, 0x42, 0x00, 0x81, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, + 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x68, 0x65, + 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x47, 0x65, 0x74, 0x4f, 0x54, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x49, 0x6e, 0x66, + 0x6f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, + 0x00, 0x04, 0x00, 0x04, 0x00, 0x15, 0x5e, 0x85, 0x00, 0x14, 0xbd, 0xe0, 0x00, 0x10, 0x8f, 0x84, + 0x00, 0x10, 0xae, 0x97, 0x00, 0x10, 0x4e, 0x3c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x44, 0x00, 0x01, 0x02, 0x00, 0x00, 0x29, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x02, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x60, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x38, 0x62, 0x01, 0x3c, 0x4e, 0x80, 0x00, 0x20, + 0x80, 0x40, 0x28, 0x08, 0x80, 0x00, 0x28, 0xc0, 0x7c, 0x09, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x80, 0x40, 0x28, 0x08, 0x80, 0x00, 0x28, 0xc4, 0x7c, 0x09, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x80, 0x40, 0x28, 0x08, 0x80, 0x00, 0x28, 0xc8, 0x7c, 0x09, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x80, 0x40, 0x28, 0x08, 0x80, 0x00, 0x28, 0xcc, 0x7c, 0x09, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x80, 0x40, 0x28, 0x08, 0x80, 0x00, 0x28, 0xd0, 0x7c, 0x09, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x80, 0x40, 0x28, 0x08, 0x80, 0x00, 0x28, 0xd4, 0x7c, 0x09, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, + 0x02, 0x22, 0x01, 0x3c, 0x03, 0x21, 0x20, 0x86, 0x02, 0x02, 0x00, 0x10, 0x00, 0x08, 0x09, 0x21, + 0x50, 0x86, 0x02, 0x02, 0x00, 0x60, 0x00, 0x30, 0x01, 0x21, 0x40, 0x04, 0x24, 0x6d, 0x74, 0x65, + 0x6a, 0x04, 0x35, 0x14, 0x53, 0x68, 0x65, 0x65, 0x70, 0x53, 0x68, 0x61, 0x76, 0x65, 0x72, 0x20, + 0x45, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x0b, 0x21, 0x01, 0x01, 0x21, 0x80, 0x04, 0x26, + 0x04, 0x04, 0x65, 0x6e, 0x65, 0x74, 0x00, 0x3e, 0x25, 0x01, 0x6f, 0x74, 0x61, 0x6e, 0x01, 0x24, + 0x0a, 0x0b, 0x01, 0x01, 0x03, 0x34, 0x53, 0x68, 0x65, 0x65, 0x70, 0x53, 0x68, 0x61, 0x76, 0x65, + 0x72, 0x20, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x04, 0x22, 0x1b, 0xbd, 0x05, 0x21, + 0xc4, 0x06, 0x22, 0x05, 0xea, 0x02, 0x22, 0x17, 0x70, 0x02, 0x22, 0x13, 0x88, 0x07, 0x21, 0x2c, + 0x03, 0x21, 0x34, 0x03, 0x21, 0x3c, 0x86, 0x02, 0x02, 0x00, 0xdc, 0x00, 0x24, 0x01, 0x21, 0x34, + 0x03, 0x21, 0x3c, 0x86, 0x02, 0x01, 0x00, 0xdc, 0x01, 0x21, 0xf4, 0x02, 0x22, 0x01, 0x10, 0x0a, + 0x22, 0x01, 0x2c, 0x03, 0x21, 0x01, 0x03, 0x21, 0x03, 0x0c, diff --git a/SheepShaver/src/Unix/Linux/asm_linux.S b/SheepShaver/src/Unix/Linux/asm_linux.S new file mode 100644 index 00000000..a095925f --- /dev/null +++ b/SheepShaver/src/Unix/Linux/asm_linux.S @@ -0,0 +1,888 @@ +/* + * asm_linux.S - Assembly routines + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#define SAVE_FP_EXEC_68K 1 + + +/* + * void *get_toc(void) - Get TOC pointer (small data pointer r13 under Linux) + */ + + .globl get_toc +get_toc: + mr r3,r13 + blr + + +/* + * void *get_sp(void) - Get stack pointer + */ + + .globl get_sp +get_sp: + mr r3,r1 + blr + + +/* + * void set_r2(uint32 val {r3}) - Set r2 + */ + + .globl set_r2 +set_r2: + mr r2,r3 + blr + + +/* + * void flush_icache_range(void *start {r3}, void *end {r3}) - Flush D and I cache + */ + +CACHE_LINE_SIZE = 32 +LG_CACHE_LINE_SIZE = 5 + + .globl flush_icache_range +flush_icache_range: + li r5,CACHE_LINE_SIZE-1 + andc r3,r3,r5 + subf r4,r3,r4 + add r4,r4,r5 + srwi. r4,r4,LG_CACHE_LINE_SIZE + beqlr + mtctr r4 + mr r6,r3 +1: dcbst 0,r3 + addi r3,r3,CACHE_LINE_SIZE + bdnz 1b + sync /* wait for dcbst's to get to ram */ + mtctr r4 +2: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 2b + sync + isync + blr + + +/* + * long atomic_add(long *var{r3}, long add{r4}) - Atomic add operation + * long atomic_and(long *var{r3}, long and{r4}) - Atomic and operation + * long atomic_or(long *var{r3}, long or{r4}) - Atomic or operation + * int test_and_set(int *var{r3}, int val{r4}) - Atomic test-and-set + */ + + .globl atomic_add +atomic_add: +10: dcbf r0,r3 + sync + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + isync + lwarx r5,r0,r3 + add r0,r4,r5 + stwcx. r0,r0,r3 + bne- 10b + mr r3,r5 + isync + blr + + .globl atomic_and +atomic_and: +10: dcbf r0,r3 + sync + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + isync + lwarx r5,r0,r3 + and r0,r4,r5 + stwcx. r0,r0,r3 + bne- 10b + mr r3,r5 + isync + blr + + .globl atomic_or +atomic_or: +10: dcbf r0,r3 + sync + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + isync + lwarx r5,r0,r3 + or r0,r4,r5 + stwcx. r0,r0,r3 + bne- 10b + mr r3,r5 + isync + blr + + .globl test_and_set +test_and_set: +10: dcbf r0,r3 + sync + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + ori r0,r0,1 + isync + lwarx r5,r0,r3 + cmpi 0,r5,0x0000 + beq 1f + stwcx. r4,r0,r3 + bne- 10b +1: isync + mr r3,r5 + blr + + +/* + * void quit_emulator(void) - Jump to XLM_EMUL_RETURN_PROC + */ + + .globl quit_emulator +quit_emulator: + lwz r0,XLM_EMUL_RETURN_PROC(r0) + mtlr r0 + blr + + +/* + * void jump_to_rom(uint32 entry {r3}, uint32 emulator_data {r4}) - Jump to Mac ROM + */ + + .globl jump_to_rom +jump_to_rom: + // Create stack frame + mflr r0 + stw r0,4(r1) + stwu r1,-(20+19*4+18*8)(r1) // maintain 16 byte alignment + + // Save PowerPC registers + stmw r13,20(r1) + stfd f14,20+19*4+0*8(r1) + stfd f15,20+19*4+1*8(r1) + stfd f16,20+19*4+2*8(r1) + stfd f17,20+19*4+3*8(r1) + stfd f18,20+19*4+4*8(r1) + stfd f19,20+19*4+5*8(r1) + stfd f20,20+19*4+6*8(r1) + stfd f21,20+19*4+7*8(r1) + stfd f22,20+19*4+8*8(r1) + stfd f23,20+19*4+9*8(r1) + stfd f24,20+19*4+10*8(r1) + stfd f25,20+19*4+11*8(r1) + stfd f26,20+19*4+12*8(r1) + stfd f27,20+19*4+13*8(r1) + stfd f28,20+19*4+14*8(r1) + stfd f29,20+19*4+15*8(r1) + stfd f30,20+19*4+16*8(r1) + stfd f31,20+19*4+17*8(r1) + + // Move entry address to ctr + mtctr r3 + + // Skip over EMUL_RETURN routine and get its address + bl 1f + + + /* + * EMUL_RETURN: Returned from emulator + */ + + // Restore PowerPC registers + lwz r1,XLM_EMUL_RETURN_STACK(r0) + lmw r13,20(r1) + lfd f14,20+19*4+0*8(r1) + lfd f15,20+19*4+1*8(r1) + lfd f16,20+19*4+2*8(r1) + lfd f17,20+19*4+3*8(r1) + lfd f18,20+19*4+4*8(r1) + lfd f19,20+19*4+5*8(r1) + lfd f20,20+19*4+6*8(r1) + lfd f21,20+19*4+7*8(r1) + lfd f22,20+19*4+8*8(r1) + lfd f23,20+19*4+9*8(r1) + lfd f24,20+19*4+10*8(r1) + lfd f25,20+19*4+11*8(r1) + lfd f26,20+19*4+12*8(r1) + lfd f27,20+19*4+13*8(r1) + lfd f28,20+19*4+14*8(r1) + lfd f29,20+19*4+15*8(r1) + lfd f30,20+19*4+16*8(r1) + lfd f31,20+19*4+17*8(r1) + + // Exiting from 68k emulator + li r0,1 + stw r0,XLM_IRQ_NEST(r0) + li r0,MODE_NATIVE + stw r0,XLM_RUN_MODE(r0) + + // Return to caller of jump_to_rom() + lwz r0,20+19*4+18*8+4(r1) + mtlr r0 + addi r1,r1,20+19*4+18*8 + blr + + + // Save address of EMUL_RETURN routine for 68k emulator patch +1: mflr r0 + stw r0,XLM_EMUL_RETURN_PROC(r0) + + // Skip over EXEC_RETURN routine and get its address + bl 2f + + + /* + * EXEC_RETURN: Returned from 68k routine executed with Execute68k() + */ + + // Save r25 (contains current 68k interrupt level) + stw r25,XLM_68K_R25(r0) + + // Reentering EMUL_OP mode + li r0,MODE_EMUL_OP + stw r0,XLM_RUN_MODE(r0) + + // Save 68k registers + lwz r4,48(r1) // Pointer to M68kRegisters + stw r8,0*4(r4) // d[0]...d[7] + stw r9,1*4(r4) + stw r10,2*4(r4) + stw r11,3*4(r4) + stw r12,4*4(r4) + stw r13,5*4(r4) + stw r14,6*4(r4) + stw r15,7*4(r4) + stw r16,8*4(r4) // a[0]..a[6] + stw r17,9*4(r4) + stw r18,10*4(r4) + stw r19,11*4(r4) + stw r20,12*4(r4) + stw r21,13*4(r4) + stw r22,14*4(r4) + + // Restore PowerPC registers + lmw r13,56(r1) +#if SAVE_FP_EXEC_68K + lfd f14,56+19*4+0*8(r1) + lfd f15,56+19*4+1*8(r1) + lfd f16,56+19*4+2*8(r1) + lfd f17,56+19*4+3*8(r1) + lfd f18,56+19*4+4*8(r1) + lfd f19,56+19*4+5*8(r1) + lfd f20,56+19*4+6*8(r1) + lfd f21,56+19*4+7*8(r1) + lfd f22,56+19*4+8*8(r1) + lfd f23,56+19*4+9*8(r1) + lfd f24,56+19*4+10*8(r1) + lfd f25,56+19*4+11*8(r1) + lfd f26,56+19*4+12*8(r1) + lfd f27,56+19*4+13*8(r1) + lfd f28,56+19*4+14*8(r1) + lfd f29,56+19*4+15*8(r1) + lfd f30,56+19*4+16*8(r1) + lfd f31,56+19*4+17*8(r1) +#endif + + // Return to caller + lwz r0,52(r1) + mtcrf 0xff,r0 + lwz r0,56+19*4+18*8+4(r1) + mtlr r0 + addi r1,r1,56+19*4+18*8 + blr + + + // Save address of EXEC_RETURN routine for 68k emulator patch +2: mflr r0 + stw r0,XLM_EXEC_RETURN_PROC(r0) + + // Skip over EMUL_BREAK/EMUL_OP routine and get its address + bl 3f + + + /* + * EMUL_BREAK/EMUL_OP: Execute native routine, selector in r5 (my own private mode switch) + * + * 68k registers are stored in a M68kRegisters struct on the stack + * which the native routine may read and modify + */ + + // Save r25 (contains current 68k interrupt level) + stw r25,XLM_68K_R25(r0) + + // Entering EMUL_OP mode within 68k emulator + li r0,MODE_EMUL_OP + stw r0,XLM_RUN_MODE(r0) + + // Create PowerPC stack frame, reserve space for M68kRegisters + mr r3,r1 + subi r1,r1,64 // Fake "caller" frame + rlwinm r1,r1,0,0,27 // Align stack + + mfcr r0 + rlwinm r0,r0,0,11,8 + stw r0,4(r1) + mfxer r0 + stw r0,16(r1) + stw r2,12(r1) + stwu r1,-(8+16*4+15*8)(r1) + + // Save 68k registers (M68kRegisters) + stw r8,8+0*4(r1) // d[0]..d[7] + stw r9,8+1*4(r1) + stw r10,8+2*4(r1) + stw r11,8+3*4(r1) + stw r12,8+4*4(r1) + stw r13,8+5*4(r1) + stw r14,8+6*4(r1) + stw r15,8+7*4(r1) + stw r16,8+8*4(r1) // a[0]..a[7] + stw r17,8+9*4(r1) + stw r18,8+10*4(r1) + stw r19,8+11*4(r1) + stw r20,8+12*4(r1) + stw r21,8+13*4(r1) + stw r22,8+14*4(r1) + stw r3,8+15*4(r1) + stfd f0,8+16*4+0*8(r1) + stfd f1,8+16*4+1*8(r1) + stfd f2,8+16*4+2*8(r1) + stfd f3,8+16*4+3*8(r1) + stfd f4,8+16*4+4*8(r1) + stfd f5,8+16*4+5*8(r1) + stfd f6,8+16*4+6*8(r1) + stfd f7,8+16*4+7*8(r1) + mffs f0 + stfd f8,8+16*4+8*8(r1) + stfd f9,8+16*4+9*8(r1) + stfd f10,8+16*4+10*8(r1) + stfd f11,8+16*4+11*8(r1) + stfd f12,8+16*4+12*8(r1) + stfd f13,8+16*4+13*8(r1) + stfd f0,8+16*4+14*8(r1) + + // Execute native routine + lwz r13,XLM_TOC(r0) + addi r3,r1,8 + mr r4,r24 + bl EmulOp__FP13M68kRegistersUii + + // Restore 68k registers (M68kRegisters) + lwz r8,8+0*4(r1) // d[0]..d[7] + lwz r9,8+1*4(r1) + lwz r10,8+2*4(r1) + lwz r11,8+3*4(r1) + lwz r12,8+4*4(r1) + lwz r13,8+5*4(r1) + lwz r14,8+6*4(r1) + lwz r15,8+7*4(r1) + lwz r16,8+8*4(r1) // a[0]..a[7] + lwz r17,8+9*4(r1) + lwz r18,8+10*4(r1) + lwz r19,8+11*4(r1) + lwz r20,8+12*4(r1) + lwz r21,8+13*4(r1) + lwz r22,8+14*4(r1) + lwz r3,8+15*4(r1) + lfd f13,8+16*4+14*8(r1) + lfd f0,8+16*4+0*8(r1) + lfd f1,8+16*4+1*8(r1) + lfd f2,8+16*4+2*8(r1) + lfd f3,8+16*4+3*8(r1) + lfd f4,8+16*4+4*8(r1) + lfd f5,8+16*4+5*8(r1) + lfd f6,8+16*4+6*8(r1) + lfd f7,8+16*4+7*8(r1) + mtfsf 0xff,f13 + lfd f8,8+16*4+8*8(r1) + lfd f9,8+16*4+9*8(r1) + lfd f10,8+16*4+10*8(r1) + lfd f11,8+16*4+11*8(r1) + lfd f12,8+16*4+12*8(r1) + lfd f13,8+16*4+13*8(r1) + + // Delete PowerPC stack frame + lwz r2,8+16*4+15*8+12(r1) + lwz r0,8+16*4+15*8+16(r1) + mtxer r0 + lwz r0,8+16*4+15*8+4(r1) + mtcrf 0xff,r0 + mr r1,r3 + + // Reentering 68k emulator + li r0,MODE_68K + stw r0,XLM_RUN_MODE(r0) + + // Set r0 to 0 for 68k emulator + li r0,0 + + // Execute next 68k opcode + rlwimi r29,r27,3,13,28 + lhau r27,2(r24) + mtlr r29 + blr + + + // Save address of EMUL_BREAK/EMUL_OP routine for 68k emulator patch +3: mflr r0 + stw r0,XLM_EMUL_OP_PROC(r0) + + // Save stack pointer for EMUL_RETURN + stw r1,XLM_EMUL_RETURN_STACK(r0) + + // Preset registers for ROM boot routine + lis r3,0x40b0 // Pointer to ROM boot structure + ori r3,r3,0xd000 + + // 68k emulator is now active + li r0,MODE_68K + stw r0,XLM_RUN_MODE(r0) + + // Jump to ROM + bctr + + +/* + * void execute_68k(uint32 pc {r3}, M68kRegisters *r {r4}) - Execute 68k routine + */ + + .globl execute_68k +execute_68k: + // Create MacOS stack frame + mflr r0 + stw r0,4(r1) + stwu r1,-(56+19*4+18*8)(r1) + mfcr r0 + stw r4,48(r1) // save pointer to M68kRegisters for EXEC_RETURN + stw r0,52(r1) // save CR + + // Save PowerPC registers + stmw r13,56(r1) +#if SAVE_FP_EXEC_68K + stfd f14,56+19*4+0*8(r1) + stfd f15,56+19*4+1*8(r1) + stfd f16,56+19*4+2*8(r1) + stfd f17,56+19*4+3*8(r1) + stfd f18,56+19*4+4*8(r1) + stfd f19,56+19*4+5*8(r1) + stfd f20,56+19*4+6*8(r1) + stfd f21,56+19*4+7*8(r1) + stfd f22,56+19*4+8*8(r1) + stfd f23,56+19*4+9*8(r1) + stfd f24,56+19*4+10*8(r1) + stfd f25,56+19*4+11*8(r1) + stfd f26,56+19*4+12*8(r1) + stfd f27,56+19*4+13*8(r1) + stfd f28,56+19*4+14*8(r1) + stfd f29,56+19*4+15*8(r1) + stfd f30,56+19*4+16*8(r1) + stfd f31,56+19*4+17*8(r1) +#endif + + // Set up registers for 68k emulator + lwz r31,XLM_KERNEL_DATA(r0) // Pointer to Kernel Data + addi r31,r31,0x1000 + li r0,0 + mtcrf 0xff,r0 + creqv 11,11,11 // Supervisor mode + lwz r8,0*4(r4) // d[0]..d[7] + lwz r9,1*4(r4) + lwz r10,2*4(r4) + lwz r11,3*4(r4) + lwz r12,4*4(r4) + lwz r13,5*4(r4) + lwz r14,6*4(r4) + lwz r15,7*4(r4) + lwz r16,8*4(r4) // a[0]..a[6] + lwz r17,9*4(r4) + lwz r18,10*4(r4) + lwz r19,11*4(r4) + lwz r20,12*4(r4) + lwz r21,13*4(r4) + lwz r22,14*4(r4) + li r23,0 + mr r24,r3 + lwz r25,XLM_68K_R25(r0) // MSB of SR + li r26,0 + li r28,0 // VBR + lwz r29,0x74(r31) // Pointer to opcode table + lwz r30,0x78(r31) // Address of emulator + + // Push return address (points to EXEC_RETURN opcode) on stack + li r0,XLM_EXEC_RETURN_OPCODE + stwu r0,-4(r1) + + // Reentering 68k emulator + li r0,MODE_68K + stw r0,XLM_RUN_MODE(r0) + + // Set r0 to 0 for 68k emulator + li r0,0 + + // Execute 68k opcode + lha r27,0(r24) + rlwimi r29,r27,3,13,28 + lhau r27,2(r24) + mtlr r29 + blr + + +/* + * uint32 call_macos1(uint32 tvect{r3}, uint32 arg1{r4}) ... - Call MacOS routines + */ + +#define prolog \ + mflr r0; \ + stw r0,4(r1); \ + stwu r1,-64(r1) + +#define epilog \ + lwz r13,XLM_TOC(r0);\ + lwz r0,64+4(r1); \ + mtlr r0; \ + addi r1,r1,64; \ + blr + + .globl call_macos +call_macos: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + bctrl + epilog + + .globl call_macos1 +call_macos1: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + mr r3,r4 + bctrl + epilog + + .globl call_macos2 +call_macos2: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + mr r3,r4 + mr r4,r5 + bctrl + epilog + + .globl call_macos3 +call_macos3: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + mr r3,r4 + mr r4,r5 + mr r5,r6 + bctrl + epilog + + .globl call_macos4 +call_macos4: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + mr r3,r4 + mr r4,r5 + mr r5,r6 + mr r6,r7 + bctrl + epilog + + .globl call_macos5 +call_macos5: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + mr r3,r4 + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + bctrl + epilog + + .globl call_macos6 +call_macos6: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + mr r3,r4 + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + mr r8,r9 + bctrl + epilog + + .globl call_macos7 +call_macos7: + prolog + lwz r0,0(r3) // Get routine address + lwz r2,4(r3) // Load TOC pointer + mtctr r0 + mr r3,r4 + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + mr r8,r9 + mr r9,r10 + bctrl + epilog + + +/* + * Native resource manager patches + */ + + .globl get_resource +get_resource: + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/ID + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_RESOURCE(r0) + lwz r2,XLM_RES_LIB_TOC(r0) + mtctr r0 + bctrl + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc__FUisPPUs + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr + + .globl get_1_resource +get_1_resource: + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/ID + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_1_RESOURCE(r0) + lwz r2,XLM_RES_LIB_TOC(r0) + mtctr r0 + bctrl + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc__FUisPPUs + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr + + .globl get_ind_resource +get_ind_resource: + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/index + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_IND_RESOURCE(r0) + lwz r2,XLM_RES_LIB_TOC(r0) + mtctr r0 + bctrl + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc__FUisPPUs + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr + + .globl get_1_ind_resource +get_1_ind_resource: + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/index + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_1_IND_RESOURCE(r0) + lwz r2,XLM_RES_LIB_TOC(r0) + mtctr r0 + bctrl + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc__FUisPPUs + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr + + .globl r_get_resource +r_get_resource: + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/ID + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_R_GET_RESOURCE(r0) + lwz r2,XLM_RES_LIB_TOC(r0) + mtctr r0 + bctrl + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc__FUisPPUs + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr + + +/* + * void ppc_interrupt(uint32 entry{r3}, uint32 kernel_data{r4}) - Execute PPC interrupt + */ + + .globl ppc_interrupt +ppc_interrupt: + mflr r0 + stw r0,4(r1) + stwu r1,-64(r1) + + // Get address of return routine + bl 1f + + // Return routine + lwz r0,64+4(r1) + mtlr r0 + addi r1,r1,64 + blr + + // Prepare registers for nanokernel interrupt routine +1: mtctr r1 + mr r1,r4 + stw r6,0x018(r1) + mfctr r6 + stw r6,0x004(r1) + lwz r6,0x65c(r1) + stw r7,0x13c(r6) + stw r8,0x144(r6) + stw r9,0x14c(r6) + stw r10,0x154(r6) + stw r11,0x15c(r6) + stw r12,0x164(r6) + stw r13,0x16c(r6) + + mflr r10 + mfcr r13 + lwz r7,0x660(r1) + mflr r12 + rlwimi. r7,r7,8,0,0 + li r11,0 + ori r11,r11,0xf072 // MSR (SRR1) + mtcrf 0x70,r11 + li r8,0 + + // Enter nanokernel + mtlr r3 + blr diff --git a/SheepShaver/src/Unix/Linux/ether_linux.cpp b/SheepShaver/src/Unix/Linux/ether_linux.cpp new file mode 100644 index 00000000..9829137d --- /dev/null +++ b/SheepShaver/src/Unix/Linux/ether_linux.cpp @@ -0,0 +1,396 @@ +/* + * ether_linux.cpp - SheepShaver Ethernet Device Driver (DLPI), Linux specific stuff + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "main.h" +#include "macos_util.h" +#include "prefs.h" +#include "user_strings.h" +#include "ether.h" +#include "ether_defs.h" + +#define DEBUG 0 +#include "debug.h" + +#define STATISTICS 0 +#define MONITOR 0 + + +// Global variables +static int fd = -1; // fd of sheep_net device + +static pthread_t ether_thread; // Packet reception thread +static bool thread_active = false; // Flag: Packet reception thread installed + +static sem_t int_ack; // Interrupt acknowledge semaphore +static uint8 ether_addr[6]; // Our Ethernet address + +static bool net_open = false; // Flag: initialization succeeded, network device open +static bool is_ethertap = false; // Flag: Ethernet device is ethertap + + +// Prototypes +static void *receive_func(void *arg); + + +/* + * Initialize ethernet + */ + +void EtherInit(void) +{ + int nonblock = 1; + char str[256]; + + // Do nothing if the user disabled the network + if (PrefsFindBool("nonet")) + return; + + // Do nothing if no Ethernet device specified + const char *name = PrefsFindString("ether"); + if (name == NULL) + return; + + // Is it Ethertap? + is_ethertap = (strncmp(name, "tap", 3) == 0); + + // Open sheep_net or ethertap device + char dev_name[16]; + if (is_ethertap) + sprintf(dev_name, "/dev/%s", name); + else + strcpy(dev_name, "/dev/sheep_net"); + fd = open(dev_name, O_RDWR); + if (fd < 0) { + sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno)); + WarningAlert(str); + goto open_error; + } + + // Attach to selected Ethernet card + if (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) { + sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno)); + WarningAlert(str); + goto open_error; + } + + // Set nonblocking I/O + ioctl(fd, FIONBIO, &nonblock); + + // Get Ethernet address + if (is_ethertap) { + pid_t p = getpid(); // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID + ether_addr[0] = 0xfe; + ether_addr[1] = 0xfd; + ether_addr[2] = p >> 24; + ether_addr[3] = p >> 16; + ether_addr[4] = p >> 8; + ether_addr[5] = p; + } else + ioctl(fd, SIOCGIFADDR, ether_addr); + D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); + + // Start packet reception thread + if (sem_init(&int_ack, 0, 0) < 0) { + WarningAlert("WARNING: Cannot init semaphore"); + goto open_error; + } + thread_active = (pthread_create(ðer_thread, NULL, receive_func, NULL) == 0); + if (!thread_active) { + WarningAlert("WARNING: Cannot start Ethernet thread"); + goto open_error; + } + + // Everything OK + net_open = true; + return; + +open_error: + if (thread_active) { + pthread_cancel(ether_thread); + pthread_join(ether_thread, NULL); + sem_destroy(&int_ack); + thread_active = false; + } + if (fd > 0) { + close(fd); + fd = -1; + } +} + + +/* + * Exit ethernet + */ + +void EtherExit(void) +{ + // Stop reception thread + if (thread_active) { + pthread_cancel(ether_thread); + pthread_join(ether_thread, NULL); + sem_destroy(&int_ack); + thread_active = false; + } + + // Close sheep_net device + if (fd > 0) + close(fd); + +#if STATISTICS + // Show statistics + printf("%ld messages put on write queue\n", num_wput); + printf("%ld error acks\n", num_error_acks); + printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets); + printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full); + printf("%ld packets received\n", num_rx_packets); + printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind); + printf("EtherIRQ called %ld times\n", num_ether_irq); + printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem); + printf("%ld rx packets dropped because no stream found\n", num_rx_dropped); + printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready); + printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem); +#endif +} + + +/* + * Get ethernet hardware address + */ + +void AO_get_ethernet_address(uint8 *addr) +{ + if (net_open) { + OTCopy48BitAddress(ether_addr, addr); + } else { + addr[0] = 0x12; + addr[1] = 0x34; + addr[2] = 0x56; + addr[3] = 0x78; + addr[4] = 0x9a; + addr[5] = 0xbc; + } + D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5])); +} + + +/* + * Enable multicast address + */ + +void AO_enable_multicast(uint8 *addr) +{ + D(bug("AO_enable_multicast\n")); + if (net_open) { + if (ioctl(fd, SIOCADDMULTI, addr) < 0) { + D(bug("WARNING: couldn't enable multicast address\n")); + } + } +} + + +/* + * Disable multicast address + */ + +void AO_disable_multicast(uint8 *addr) +{ + D(bug("AO_disable_multicast\n")); + if (net_open) { + if (ioctl(fd, SIOCDELMULTI, addr) < 0) { + D(bug("WARNING: couldn't disable multicast address\n")); + } + } +} + + +/* + * Transmit one packet + */ + +void AO_transmit_packet(mblk_t *mp) +{ + D(bug("AO_transmit_packet\n")); + if (net_open) { + + // Copy packet to buffer + uint8 packet[1516], *p = packet; + int len = 0; + if (is_ethertap) { + *p++ = 0; // Ethertap discards the first 2 bytes + *p++ = 0; + len += 2; + } + while (mp) { + uint32 size = mp->b_wptr - mp->b_rptr; + memcpy(p, mp->b_rptr, size); + len += size; + p += size; + mp = mp->b_cont; + } + +#if MONITOR + bug("Sending Ethernet packet:\n"); + for (int i=0; ib_rptr)); + memcpy(mp->b_rptr, p, size); + mp->b_wptr += size; + ether_packet_received(mp); + } else { + D(bug("WARNING: Cannot allocate mblk for received packet\n")); + num_rx_no_mem++; + } + + } else { + + // Get size of first packet + int size = 0; + if (ioctl(fd, FIONREAD, &size) < 0 || size == 0) + break; + + // Discard packets which are too short + if (size < 14) { + uint8 dummy[14]; + read(fd, dummy, size); + continue; + } + + // Truncate packets which are too long + if (size > 1514) + size = 1514; + + // Read packet and wrap it in message block + num_rx_packets++; + mblk_t *mp; + if ((mp = allocb(size, 0)) != NULL) { + D(bug(" packet data at %p\n", mp->b_rptr)); + read(fd, mp->b_rptr, 1514); +#if MONITOR + bug("Receiving Ethernet packet:\n"); + for (int i=0; ib_rptr)[i]); + } + bug("\n"); +#endif + mp->b_wptr += size; + ether_packet_received(mp); + } else { + D(bug("WARNING: Cannot allocate mblk for received packet\n")); + num_rx_no_mem++; + } + } + } + OTLeaveInterrupt(); + + // Acknowledge interrupt to reception thread + D(bug(" EtherIRQ done\n")); + sem_post(&int_ack); +} diff --git a/SheepShaver/src/Unix/Linux/paranoia.cpp b/SheepShaver/src/Unix/Linux/paranoia.cpp new file mode 100644 index 00000000..583014c3 --- /dev/null +++ b/SheepShaver/src/Unix/Linux/paranoia.cpp @@ -0,0 +1,168 @@ +/* + * paranoia.cpp - Check undocumented features of the Linux kernel that + * SheepShaver relies upon + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "sysdeps.h" +#include "main.h" +#include "user_strings.h" + +typedef struct { + uint32 u[4]; +} __attribute((aligned(16))) vector128; +#include + +#define DEBUG 1 +#include "debug.h" + + +// Constants +const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack + +// Prototypes +extern "C" void *get_sp(void); +extern "C" void set_r2(uint32 val); +extern void paranoia_check(void); +static void sigusr2_handler(int sig, sigcontext_struct *sc); + +// Global variables +static void *sig_stack = NULL; + +static int err = 0; +static void *sig_sp = NULL; +static void *sig_r4 = NULL; +static int sig_sc_signal = 0; +static void *sig_sc_regs = NULL; +static uint32 sig_r2 = 0; + + +void paranoia_check(void) +{ + char str[256]; + + D(bug("Paranoia checks...\n")); + + // Create and install stack for signal handler + sig_stack = malloc(SIG_STACK_SIZE); + if (sig_stack == NULL) { + ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); + exit(1); + } + + struct sigaltstack old_stack; + struct sigaltstack new_stack; + new_stack.ss_sp = sig_stack; + new_stack.ss_flags = 0; + new_stack.ss_size = SIG_STACK_SIZE; + if (sigaltstack(&new_stack, &old_stack) < 0) { + sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); + ErrorAlert(str); + exit(1); + } + + // Install SIGUSR2 signal handler + static struct sigaction old_action; + static struct sigaction sigusr2_action; + sigemptyset(&sigusr2_action.sa_mask); + sigusr2_action.sa_handler = (__sighandler_t)sigusr2_handler; + sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART; + sigusr2_action.sa_restorer = NULL; + if (sigaction(SIGUSR2, &sigusr2_action, &old_action) < 0) { + sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno)); + ErrorAlert(str); + exit(1); + } + + // Raise SIGUSR2 + set_r2(0xaffebad5); + raise(SIGUSR2); + + // Check error code + switch (err) { + case 1: + printf("FATAL: sigaltstack() doesn't seem to work (sp in signal handler was %08lx, expected %08lx..%08lx)\n", (uint32)sig_sp, (uint32)sig_stack, (uint32)sig_stack + SIG_STACK_SIZE); + break; + case 2: + printf("FATAL: r4 in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_r4); + break; + case 3: + printf("FATAL: r4 in signal handler doesn't seem to point to a sigcontext_struct (signal number was %d, expected %d)", sig_sc_signal, SIGUSR2); + break; + case 4: + printf("FATAL: sc->regs in signal handler (%08lx) doesn't point to stack\n", (uint32)sig_sc_regs); + break; + case 5: + printf("FATAL: sc->regs->gpr[2] in signal handler (%08lx) doesn't have expected value (%08x)\n", (uint32)sig_r2, 0xaffebad5); + break; + } + if (err) { + printf("Maybe you need a different kernel?\n"); + exit(1); + } + + // Clean up + D(bug("...passed\n")); + sigaction(SIGUSR2, &old_action, NULL); + sigaltstack(&old_stack, NULL); + free(sig_stack); +} + + +static void sigusr2_handler(int sig, sigcontext_struct *sc) +{ + // Check whether sigaltstack works + sig_sp = get_sp(); + if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { + err = 1; + return; + } + + // Check whether r4 points to info on the stack + sig_r4 = sc; + if (sig_r4 < sig_stack || sig_r4 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { + err = 2; + return; + } + + // Check whether r4 looks like a sigcontext + sig_sc_signal = sc->signal; + if (sig_sc_signal != SIGUSR2) { + err = 3; + return; + } + + // Check whether sc->regs points to info on the stack + sig_sc_regs = sc->regs; + if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { + err = 4; + return; + } + + // Check whether r2 still holds the value we set it to + sig_r2 = sc->regs->gpr[2]; + if (sig_r2 != 0xaffebad5) { + err = 5; + return; + } +} diff --git a/SheepShaver/src/Unix/Linux/sheepthreads.c b/SheepShaver/src/Unix/Linux/sheepthreads.c new file mode 100644 index 00000000..4bd381ab --- /dev/null +++ b/SheepShaver/src/Unix/Linux/sheepthreads.c @@ -0,0 +1,251 @@ +/* + * sheepthreads.c - Minimal pthreads implementation (libpthreads doesn't + * like nonstandard stacks) + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 + */ + +/* + * NOTES: + * - pthread_cancel() kills the thread immediately + * - Semaphores are VERY restricted: the only supported use is to have one + * thread sem_wait() on the semaphore while other threads sem_post() it + * (i.e. to use the semaphore as a signal) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Thread stack size */ +#define STACK_SIZE 65536 + +/* From asm_linux.S */ +extern int atomic_add(int *var, int add); +extern int atomic_and(int *var, int and); +extern int atomic_or(int *var, int or); +extern int test_and_set(int *var, int val); + +/* Linux kernel calls */ +extern int __clone(int (*fn)(void *), void *, int, void *); + +/* struct sem_t */ +#define sem_lock __sem_lock +#define sem_value __sem_value +#define sem_waiting __sem_waiting + + +/* + * Return pthread ID of self + */ + +pthread_t pthread_self(void) +{ + return getpid(); +} + + +/* + * Test whether two pthread IDs are equal + */ + +int pthread_equal(pthread_t t1, pthread_t t2) +{ + return t1 == t2; +} + + +/* + * Send signal to thread + */ + +int pthread_kill(pthread_t thread, int sig) +{ + if (kill(thread, sig) == -1) + return errno; + else + return 0; +} + + +/* + * Create pthread + */ + +struct new_thread { + void *(*fn)(void *); + void *arg; +}; + +static int start_thread(void *arg) +{ + struct new_thread *nt = (struct new_thread *)arg; + nt->fn(nt->arg); + return 0; +} + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) +{ + struct new_thread *nt; + void *stack; + int pid; + + nt = (struct new_thread *)malloc(sizeof(struct new_thread)); + nt->fn = start_routine; + nt->arg = arg; + stack = malloc(STACK_SIZE); + + pid = __clone(start_thread, (char *)stack + STACK_SIZE - 16, CLONE_VM | CLONE_FS | CLONE_FILES, nt); + if (pid == -1) { + free(stack); + free(nt); + return errno; + } else { + *thread = pid; + return 0; + } +} + + +/* + * Join pthread + */ + +int pthread_join(pthread_t thread, void **ret) +{ + do { + if (waitpid(thread, NULL, 0) >= 0) + break; + } while (errno == EINTR); + if (ret) + *ret = NULL; + return 0; +} + + +/* + * Cancel thread + */ + +int pthread_cancel(pthread_t thread) +{ + kill(thread, SIGINT); + return 0; +} + + +/* + * Test for cancellation + */ + +void pthread_testcancel(void) +{ +} + + +/* + * Spinlocks + */ + +static void acquire_spinlock(volatile int *lock) +{ + do { + while (*lock) ; + } while (test_and_set((int *)lock, 1) != 0); +} + +static void release_spinlock(int *lock) +{ + *lock = 0; +} + + +/* + * Init semaphore + */ + +int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + sem->sem_lock.status = 0; + sem->sem_lock.spinlock = 0; + sem->sem_value = value; + sem->sem_waiting = NULL; + return 0; +} + + +/* + * Delete remaphore + */ + +int sem_destroy(sem_t *sem) +{ + return 0; +} + + +/* + * Wait on semaphore + */ + +void null_handler(int sig) +{ +} + +int sem_wait(sem_t *sem) +{ + acquire_spinlock(&sem->sem_lock.spinlock); + if (atomic_add((int *)&sem->sem_value, -1) >= 0) { + sigset_t mask; + if (!sem->sem_lock.status) { + struct sigaction sa; + sem->sem_lock.status = SIGUSR2; + sa.sa_handler = null_handler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(sem->sem_lock.status, &sa, NULL); + } + sem->sem_waiting = (struct _pthread_descr_struct *)getpid(); + sigemptyset(&mask); + sigsuspend(&mask); + sem->sem_waiting = NULL; + } + release_spinlock(&sem->sem_lock.spinlock); + return 0; +} + + +/* + * Post semaphore + */ + +int sem_post(sem_t *sem) +{ + acquire_spinlock(&sem->sem_lock.spinlock); + atomic_add((int *)&sem->sem_value, 1); + if (sem->sem_waiting) + kill((pid_t)sem->sem_waiting, sem->sem_lock.status); + release_spinlock(&sem->sem_lock.spinlock); + return 0; +} diff --git a/SheepShaver/src/Unix/Makefile.in b/SheepShaver/src/Unix/Makefile.in new file mode 100644 index 00000000..8463a90c --- /dev/null +++ b/SheepShaver/src/Unix/Makefile.in @@ -0,0 +1,96 @@ +# Linux makefile for SheepShaver + +## System specific configuration +@SET_MAKE@ +SHELL = /bin/sh + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 + +CC = @CC@ +CXX = @CXX@ +CFLAGS = @CFLAGS@ +CXXFLAGS = @CXXFLAGS@ +CPPFLAGS = @CPPFLAGS@ -I../include -I. +DEFS = @DEFS@ -D_REENTRANT -DDATADIR=\"$(datadir)/$(APP)\" +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +SYSSRCS = @SYSSRCS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ -s +INSTALL_DATA = @INSTALL_DATA@ + +## Files +SRCS = main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp sys_unix.cpp \ + ../rom_patches.cpp ../rsrc_patches.cpp ../emul_op.cpp ../name_registry.cpp \ + ../macos_util.cpp ../timer.cpp timer_unix.cpp ../xpram.cpp xpram_unix.cpp \ + ../adb.cpp clip_unix.cpp ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp \ + Linux/scsi_linux.cpp ../video.cpp video_x.cpp ../audio.cpp audio_oss_esd.cpp ../ether.cpp \ + Linux/ether_linux.cpp ../serial.cpp serial_unix.cpp ../extfs.cpp extfs_unix.cpp \ + about_window_unix.cpp ../user_strings.cpp user_strings_unix.cpp $(SYSSRCS) +APP = SheepShaver + +## Rules +.PHONY: modules install uninstall clean distclean depend dep +.SUFFIXES: +.SUFFIXES: .c .cpp .S .o .h + +all: $(APP) + +OBJ_DIR = obj +$(OBJ_DIR):: + @[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1 + +define SRCS_LIST_TO_OBJS + $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(SRCS), \ + $(basename $(notdir $(file)))))) +endef +OBJS = $(SRCS_LIST_TO_OBJS) + +SRC_PATHS += $(sort $(foreach file, $(SRCS), $(dir $(file)))) +VPATH := +VPATH += $(addprefix :, $(subst ,:, $(filter-out $($(subst, :, ,$(VPATH))), $(SRC_PATHS)))) + +$(APP): $(OBJ_DIR) $(OBJS) + $(CXX) -o $(APP) $(LDFLAGS) $(OBJS) $(LIBS) + +modules: + cd NetDriver; make + +install: $(APP) installdirs + $(INSTALL_PROGRAM) $(APP) $(bindir)/$(APP) + -$(INSTALL_DATA) $(APP).1 $(man1dir)/$(APP).1 + +installdirs: + $(SHELL) mkinstalldirs $(bindir) $(man1dir) + +uninstall: + rm -f $(bindir)/$(APP) + rm -f $(man1dir)/$(APP).1 + +clean: + rm -f $(APP) $(OBJ_DIR)/* core* *.core *~ *.bak + +distclean: clean + rm -rf $(OBJ_DIR) + rm -f Makefile + rm -f config.cache config.log config.status config.h + +depend dep: + makedepend $(CPPFLAGS) -Y. $(SRCS) 2>/dev/null + +$(OBJ_DIR)/%.o : %.c + $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ +$(OBJ_DIR)/%.o : %.cpp + $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ +$(OBJ_DIR)/%.o : %.S + $(CPP) $(CPPFLAGS) -D__ASSEMBLY__ $< -o $*.s + $(AS) $(ASFLAGS) -o $@ $*.s + rm $*.s + +#------------------------------------------------------------------------- +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/SheepShaver/src/Unix/SheepShaver.1 b/SheepShaver/src/Unix/SheepShaver.1 new file mode 100644 index 00000000..12358963 --- /dev/null +++ b/SheepShaver/src/Unix/SheepShaver.1 @@ -0,0 +1,29 @@ +.TH SheepShaver 1 "April, 2000" +.SH NAME +SheepShaver \- Macintosh emulator +.SH SYNOPSIS +.B SheepShaver +[\-display +.IR display-name ] +.SH DESCRIPTION +.B SheepShaver +is a Macintosh emulator for PowerPC-based Linux systems. +For more information, see the included documentation. +.SH OPTIONS +.TP +.BI "\-display " display-name +specifies the display to use; see +.BR X (1) +.SH FILES +.TP +.I ~/.sheepshaver_prefs +User-specific configuration file. +.TP +.I ~/.sheeshaver_nvram +Contents of Mac non-volatile RAM. +.SH SEE ALSO +http://www.sheepshaver.com/ (Official SheepShaver homepage) +.SH AUTHORS +Christian Bauer +.br +Marc Hellwig diff --git a/SheepShaver/src/Unix/about_window_unix.cpp b/SheepShaver/src/Unix/about_window_unix.cpp new file mode 100644 index 00000000..6b04529e --- /dev/null +++ b/SheepShaver/src/Unix/about_window_unix.cpp @@ -0,0 +1,30 @@ +/* + * about_window_unix.cpp - "About" window, Unix implementation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "about_window.h" + + +/* + * Open "About" window + */ + +void OpenAboutWindow(void) +{ +} diff --git a/SheepShaver/src/Unix/acconfig.h b/SheepShaver/src/Unix/acconfig.h new file mode 100644 index 00000000..9ba67fda --- /dev/null +++ b/SheepShaver/src/Unix/acconfig.h @@ -0,0 +1,39 @@ +/* acconfig.h + This file is in the public domain. + + Descriptive text for the C preprocessor macros that + the distributed Autoconf macros can define. + No software package will use all of them; autoheader copies the ones + your configure.in uses into your configuration header file templates. + + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). Although this order + can split up related entries, it makes it easier to check whether + a given entry is in the file. + + Leave the following blank line there!! Autoheader needs it. */ + + +/* Define to 'off_t' if doesn't define. */ +#undef loff_t + +/* Define if using ESD. */ +#undef ENABLE_ESD + +/* Define if using GTK. */ +#undef ENABLE_GTK + +/* Define if using "mon". */ +#undef ENABLE_MON + +/* Define if using XFree86 DGA extension. */ +#undef ENABLE_XF86_DGA + +/* Define if using XFree86 VidMode extension. */ +#undef ENABLE_XF86_VIDMODE + + +/* Leave that blank line there!! Autoheader needs it. + If you're adding to this file, keep in mind: + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). */ diff --git a/SheepShaver/src/Unix/autogen.sh b/SheepShaver/src/Unix/autogen.sh new file mode 100755 index 00000000..3c2a5225 --- /dev/null +++ b/SheepShaver/src/Unix/autogen.sh @@ -0,0 +1,36 @@ +#! /bin/sh +# Run this to generate all the initial makefiles, etc. +# This was lifted from the Gimp, and adapted slightly by +# Christian Bauer. + +DIE=0 + +PROG=SheepShaver + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $PROG." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if test -z "$*"; then + echo "I am going to run ./configure with no arguments - if you wish " + echo "to pass any to it, please specify them on the $0 command line." +fi + +for dir in . +do + echo processing $dir + (cd $dir; \ + aclocalinclude="$ACLOCAL_FLAGS"; \ + aclocal $aclocalinclude; \ + autoheader; autoconf) +done + +./configure "$@" diff --git a/SheepShaver/src/Unix/clip_unix.cpp b/SheepShaver/src/Unix/clip_unix.cpp new file mode 100644 index 00000000..27abef21 --- /dev/null +++ b/SheepShaver/src/Unix/clip_unix.cpp @@ -0,0 +1,124 @@ +/* + * clip_unix.cpp - Clipboard handling, Unix implementation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" + +#include + +#include "macos_util.h" +#include "clip.h" + +#define DEBUG 0 +#include "debug.h" + + +// From main_linux.cpp +extern Display *x_display; + + +// Conversion tables +static const uint8 mac2iso[0x80] = { + 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, + 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, + 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, + 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, + 0x2b, 0xb0, 0xa2, 0xa3, 0xa7, 0xb7, 0xb6, 0xdf, + 0xae, 0xa9, 0x20, 0xb4, 0xa8, 0x23, 0xc6, 0xd8, + 0x20, 0xb1, 0x3c, 0x3e, 0xa5, 0xb5, 0xf0, 0x53, + 0x50, 0x70, 0x2f, 0xaa, 0xba, 0x4f, 0xe6, 0xf8, + 0xbf, 0xa1, 0xac, 0x2f, 0x66, 0x7e, 0x44, 0xab, + 0xbb, 0x2e, 0x20, 0xc0, 0xc3, 0xd5, 0x4f, 0x6f, + 0x2d, 0x2d, 0x22, 0x22, 0x60, 0x27, 0xf7, 0x20, + 0xff, 0x59, 0x2f, 0xa4, 0x3c, 0x3e, 0x66, 0x66, + 0x23, 0xb7, 0x2c, 0x22, 0x25, 0xc2, 0xca, 0xc1, + 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, + 0x20, 0xd2, 0xda, 0xdb, 0xd9, 0x69, 0x5e, 0x7e, + 0xaf, 0x20, 0xb7, 0xb0, 0xb8, 0x22, 0xb8, 0x20 +}; + + +/* + * Initialization + */ + +void ClipInit(void) +{ +} + + +/* + * Deinitialization + */ + +void ClipExit(void) +{ +} + + +/* + * Mac application wrote to clipboard + */ + +void PutScrap(uint32 type, void *scrap, int32 length) +{ + D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length)); + if (length <= 0) + return; + + switch (type) { + case FOURCC('T','E','X','T'): + D(bug(" clipping TEXT\n")); + + // Convert text from Mac charset to ISO-Latin1 + uint8 *buf = new uint8[length]; + uint8 *p = (uint8 *)scrap; + uint8 *q = buf; + for (int i=0; i LF + c = 10; + } else + c = mac2iso[c & 0x7f]; + *q++ = c; + } + + // Put text into cut buffer + //!! XStoreBytes(x_display, buf, length); + delete[] buf; + break; + } +} + + +/* + * Mac application reads clipboard + */ + +void GetScrap(void **handle, uint32 type, int32 offset) +{ + D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); + switch (type) { + case FOURCC('T','E','X','T'): + D(bug(" clipping TEXT\n")); + //!! + break; + } +} diff --git a/SheepShaver/src/Unix/configure.in b/SheepShaver/src/Unix/configure.in new file mode 100644 index 00000000..600c1a2a --- /dev/null +++ b/SheepShaver/src/Unix/configure.in @@ -0,0 +1,180 @@ +dnl Process this file with autoconf to produce a configure script. +dnl Written in 2002 by Christian Bauer + +AC_INIT(main_unix.cpp) +AC_PREREQ(2.12) +AC_CONFIG_HEADER(config.h) + +dnl Options. +AC_ARG_ENABLE(xf86-dga, [ --enable-xf86-dga use the XFree86 DGA extension [default=yes]], [WANT_XF86_DGA=$enableval], [WANT_XF86_DGA=yes]) +AC_ARG_ENABLE(xf86-vidmode, [ --enable-xf86-vidmode use the XFree86 VidMode extension [default=yes]], [WANT_XF86_VIDMODE=$enableval], [WANT_XF86_VIDMODE=yes]) +AC_ARG_WITH(esd, [ --with-esd support ESD for sound under Linux/FreeBSD [default=yes]], [WANT_ESD=$withval], [WANT_ESD=yes]) +AC_ARG_WITH(gtk, [ --with-gtk use GTK user interface [default=yes]], [WANT_GTK=$withval], [WANT_GTK=yes]) +AC_ARG_WITH(mon, [ --with-mon use mon as debugger [default=yes]], [WANT_MON=$withval], [WANT_MON=yes]) + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_CPP +AC_PROG_CXX +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +dnl Check for PowerPC target CPU. +HAVE_PPC=no +AC_MSG_CHECKING(for PowerPC target CPU) +AC_EGREP_CPP(yes, +[ +#ifdef __powerpc__ + yes +#endif +], [AC_MSG_RESULT(yes); HAVE_PPC=yes], AC_MSG_RESULT(no)) + +dnl We use mon if possible. +MONSRCS= +if [[ "x$WANT_MON" = "xyes" ]]; then + AC_MSG_CHECKING(for mon) + mon_srcdir=../../../mon/src + if grep mon_init $mon_srcdir/mon.h >/dev/null 2>/dev/null; then + AC_MSG_RESULT(yes) + AC_DEFINE(ENABLE_MON) + MONSRCS="$mon_srcdir/mon.cpp $mon_srcdir/mon_6502.cpp $mon_srcdir/mon_z80.cpp $mon_srcdir/mon_cmd.cpp $mon_srcdir/mon_lowmem.cpp $mon_srcdir/mon_disass.cpp $mon_srcdir/mon_ppc.cpp $mon_srcdir/disass/floatformat.c $mon_srcdir/disass/i386-dis.c $mon_srcdir/disass/m68k-dis.c $mon_srcdir/disass/m68k-opc.c" + CXXFLAGS="$CXXFLAGS -I$mon_srcdir -I$mon_srcdir/disass" + AC_CHECK_LIB(readline, readline) + AC_CHECK_LIB(termcap, tputs) + AC_CHECK_HEADERS(readline.h history.h readline/readline.h readline/history.h) + else + AC_MSG_RESULT(no) + AC_MSG_WARN([Could not find mon, ignoring --with-mon.]) + WANT_MON=no + fi +fi + +dnl Checks for libraries. +AC_CHECK_LIB(posix4, sem_init) + +dnl We need X11. +AC_PATH_XTRA +if [[ "x$no_x" = "xyes" ]]; then + AC_MSG_ERROR([You need X11 to run SheepShaver.]) +fi +CFLAGS="$CFLAGS $X_CFLAGS" +CXXFLAGS="$CXXFLAGS $X_CFLAGS" +LIBS="$LIBS $X_PRE_LIBS $X_LIBS -lX11 -lXext $X_EXTRA_LIBS" + +dnl We need pthreads on non-PowerPC systems. Try libpthread first, then libc_r (FreeBSD), then PTL. +HAVE_PTHREADS=yes +if [[ "x$HAVE_PPC" = "xno" ]]; then + AC_CHECK_LIB(pthread, pthread_create, , [ + AC_CHECK_LIB(c_r, pthread_create, , [ + AC_CHECK_LIB(PTL, pthread_create, , [ + AC_MSG_ERROR([You need pthreads to run Basilisk II.]) + ]) + ]) + ]) + AC_CHECK_FUNCS(pthread_cancel) +fi + +dnl If POSIX.4 semaphores are not available, we emulate them with pthread mutexes. +SEMSRC= +AC_CHECK_FUNCS(sem_init, , [ + if [[ "x$HAVE_PTHREADS" = "xyes" ]]; then + SEMSRC=posix_sem.cpp + fi +]) + +dnl We use XFree86 DGA if possible. +if [[ "x$WANT_XF86_DGA" = "xyes" ]]; then + AC_CHECK_LIB(Xxf86dga, XF86DGAQueryExtension, [ + AC_DEFINE(ENABLE_XF86_DGA) + LIBS="$LIBS -lXxf86dga" + ], [ + AC_MSG_WARN([Could not find XFree86 DGA extension, ignoring --enable-xf86-dga.]) + WANT_XF86_DGA=no + ]) +fi + +dnl We use XFree86 VidMode if possible. +if [[ "x$WANT_XF86_VIDMODE" = "xyes" ]]; then + AC_CHECK_LIB(Xxf86vm, XF86VidModeQueryExtension, [ + AC_DEFINE(ENABLE_XF86_VIDMODE) + LIBS="$LIBS -lXxf86vm" + ], [ + AC_MSG_WARN([Could not find XFree86 VidMode extension, ignoring --enable-xf86-vidmode.]) + WANT_XF86_VIDMODE=no + ]) +fi + +dnl We use GTK+ if possible. +UISRCS= +if [[ "x$WANT_GTK" = "xyes" ]]; then + AM_PATH_GTK(1.2.0, [ + AC_DEFINE(ENABLE_GTK) + CFLAGS="$CFLAGS $GTK_CFLAGS" + CXXFLAGS="$CXXFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + UISRCS=prefs_editor_gtk.cpp + ], [ + AC_MSG_WARN([Could not find GTK+, disabling user interface.]) + WANT_GTK=no + ]) +fi + +dnl We use ESD if possible. +if [[ "x$WANT_ESD" = "xyes" ]]; then + AM_PATH_ESD(0.2.8, [ + AC_DEFINE(ENABLE_ESD) + CFLAGS="$CFLAGS $ESD_CFLAGS" + CXXFLAGS="$CXXFLAGS $ESD_CFLAGS" + LIBS="$LIBS $ESD_LIBS" + ], [ + AC_MSG_WARN([Could not find ESD, disabling ESD support.]) + WANT_ESD=no + ]) +fi + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(unistd.h fcntl.h sys/time.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_BIGENDIAN +AC_C_CONST +AC_C_INLINE +AC_CHECK_SIZEOF(short, 2) +AC_CHECK_SIZEOF(int, 4) +AC_CHECK_SIZEOF(long, 4) +AC_CHECK_SIZEOF(long long, 8) +AC_TYPE_OFF_T +AC_CHECK_TYPE(loff_t, off_t) +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_STRUCT_TM + +dnl Checks for library functions. +AC_CHECK_FUNCS(strdup cfmakeraw) +AC_CHECK_FUNCS(nanosleep clock_gettime timer_create) + +dnl Select system-dependant sources. +if [[ "x$HAVE_PPC" = "xyes" ]]; then + SYSSRCS="Linux/paranoia.cpp Linux/sheepthreads.c Linux/asm_linux.S" +else + SYSSRCS="../emul_ppc/emul_ppc.cpp" +fi +SYSSRCS="$SYSSRCS $SEMSRCS $UISRCS $MONSRCS" + +dnl Generate Makefile. +AC_SUBST(SYSSRCS) +AC_OUTPUT(Makefile) + +dnl Print summary. +echo +echo SheepShaver configuration summary: +echo +echo XFree86 DGA support .............. : $WANT_XF86_DGA +echo XFree86 VidMode support .......... : $WANT_XF86_VIDMODE +echo ESD sound support ................ : $WANT_ESD +echo GTK user interface ............... : $WANT_GTK +echo mon debugger support ............. : $WANT_MON +echo +echo "Configuration done. Now type \"make\"." diff --git a/SheepShaver/src/Unix/install-sh b/SheepShaver/src/Unix/install-sh new file mode 100755 index 00000000..89fc9b09 --- /dev/null +++ b/SheepShaver/src/Unix/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/SheepShaver/src/Unix/main_unix.cpp b/SheepShaver/src/Unix/main_unix.cpp new file mode 100644 index 00000000..f348c31c --- /dev/null +++ b/SheepShaver/src/Unix/main_unix.cpp @@ -0,0 +1,1805 @@ +/* + * main_unix.cpp - Emulation core, Unix implementation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 + */ + +/* + * NOTES: + * + * See main_beos.cpp for a description of the three operating modes. + * + * In addition to that, we have to handle the fact that the MacOS ABI + * is slightly different from the SysV ABI used by Linux: + * - Stack frames are different (e.g. LR is stored in 8(r1) under + * MacOS, but in 4(r1) under Linux) + * - There is no TOC under Linux; r2 is free for the user + * - r13 is used as a small data pointer under Linux (but appearently + * it is not used this way? To be sure, we specify -msdata=none + * in the Makefile) + * - As there is no TOC, there are also no TVECTs under Linux; + * function pointers point directly to the function code + * The Execute*() functions have to account for this. Additionally, we + * cannot simply call MacOS functions by getting their TVECT and jumping + * to it. Such calls are done via the call_macos*() functions in + * asm_linux.S that create a MacOS stack frame, load the TOC pointer + * and put the arguments into the right registers. + * + * As on the BeOS, we have to specify an alternate signal stack because + * interrupts (and, under Linux, Low Memory accesses) may occur when r1 + * is pointing to the Kernel Data or to Low Memory. There is one + * problem, however, due to the alternate signal stack being global to + * all signal handlers. Consider the following scenario: + * - The main thread is executing some native PPC MacOS code in + * MODE_NATIVE, running on the MacOS stack (somewhere in the Mac RAM). + * - A SIGUSR2 interrupt occurs. The kernel switches to the signal + * stack and starts executing the SIGUSR2 signal handler. + * - The signal handler sees the MODE_NATIVE and calls ppc_interrupt() + * to handle a native interrupt. + * - ppc_interrupt() sets r1 to point to the Kernel Data and jumps to + * the nanokernel. + * - The nanokernel accesses a Low Memory global (most likely one of + * the XLMs), a SIGSEGV occurs. + * - The kernel sees that r1 does not point to the signal stack and + * switches to the signal stack again, thus overwriting the data that + * the SIGUSR2 handler put there. + * The same problem arises when calling ExecutePPC() inside the MODE_EMUL_OP + * interrupt handler. + * + * The solution is to set the signal stack to a second, "extra" stack + * inside the SIGUSR2 handler before entering the Nanokernel or calling + * ExecutePPC (or any function that might cause a mode switch). The signal + * stack is restored before exiting the SIGUSR2 handler. + * + * TODO: + * check if SIGSEGV handler works for all registers (including FP!) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "main.h" +#include "version.h" +#include "prefs.h" +#include "prefs_editor.h" +#include "cpu_emulation.h" +#include "emul_op.h" +#include "xlowmem.h" +#include "xpram.h" +#include "timer.h" +#include "adb.h" +#include "sony.h" +#include "disk.h" +#include "cdrom.h" +#include "scsi.h" +#include "video.h" +#include "audio.h" +#include "ether.h" +#include "serial.h" +#include "clip.h" +#include "extfs.h" +#include "sys.h" +#include "macos_util.h" +#include "rom_patches.h" +#include "user_strings.h" + +#define DEBUG 0 +#include "debug.h" + + +#include + +#ifdef ENABLE_GTK +#include +#endif + +#ifdef ENABLE_XF86_DGA +#include +#include +#include +#endif + +#ifdef ENABLE_MON +#include "mon.h" +#endif + + +// Enable Execute68k() safety checks? +#define SAFE_EXEC_68K 0 + +// Interrupts in EMUL_OP mode? +#define INTERRUPTS_IN_EMUL_OP_MODE 1 + +// Interrupts in native mode? +#define INTERRUPTS_IN_NATIVE_MODE 1 + + +// Constants +const char ROM_FILE_NAME[] = "ROM"; +const char ROM_FILE_NAME2[] = "Mac OS ROM"; + +const uint32 ROM_AREA_SIZE = 0x500000; // Size of ROM area +const uint32 ROM_END = ROM_BASE + ROM_SIZE; // End of ROM + +const uint32 KERNEL_DATA_BASE = 0x68ffe000; // Address of Kernel Data +const uint32 KERNEL_DATA2_BASE = 0x5fffe000; // Alternate address of Kernel Data +const uint32 KERNEL_AREA_SIZE = 0x2000; // Size of Kernel Data area + +const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack + + +// 68k Emulator Data +struct EmulatorData { + uint32 v[0x400]; +}; + + +// Kernel Data +struct KernelData { + uint32 v[0x400]; + EmulatorData ed; +}; + + +#if !EMULATED_PPC +// Structure in which registers are saved in a signal handler; +// sigcontext->regs points to it +// (see arch/ppc/kernel/signal.c) +typedef struct { + uint32 u[4]; +} __attribute((aligned(16))) vector128; +#include + +struct sigregs { + elf_gregset_t gp_regs; // Identical to pt_regs + double fp_regs[ELF_NFPREG]; // f0..f31 and fpsrc + //more (uninteresting) stuff following here +}; +#endif + + +// Global variables (exported) +#if !EMULATED_PPC +void *TOC; // Small data pointer (r13) +#endif +uint32 RAMBase; // Base address of Mac RAM +uint32 RAMSize; // Size of Mac RAM +uint32 KernelDataAddr; // Address of Kernel Data +uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM +uint32 PVR; // Theoretical PVR +int64 CPUClockSpeed; // Processor clock speed (Hz) +int64 BusClockSpeed; // Bus clock speed (Hz) + + +// Global variables +static char *x_display_name = NULL; // X11 display name +Display *x_display = NULL; // X11 display handle + +static int zero_fd = 0; // FD of /dev/zero +static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped +static int kernel_area = -1; // SHM ID of Kernel Data area +static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped +static bool ram_area_mapped = false; // Flag: Mac RAM mmap()ped +static void *mmap_RAMBase = NULL; // Base address of mmap()ed RAM area +static KernelData *kernel_data; // Pointer to Kernel Data +static EmulatorData *emulator_data; + +static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes + +static bool nvram_thread_active = false; // Flag: NVRAM watchdog installed +static pthread_t nvram_thread; // NVRAM watchdog +static bool tick_thread_active = false; // Flag: MacOS thread installed +static pthread_t tick_thread; // 60Hz thread +static pthread_t emul_thread; // MacOS thread + +static bool ready_for_signals = false; // Handler installed, signals can be sent +static int64 num_segv = 0; // Number of handled SEGV signals + +#if !EMULATED_PPC +static struct sigaction sigusr2_action; // Interrupt signal (of emulator thread) +static struct sigaction sigsegv_action; // Data access exception signal (of emulator thread) +static struct sigaction sigill_action; // Illegal instruction signal (of emulator thread) +static void *sig_stack = NULL; // Stack for signal handlers +static void *extra_stack = NULL; // Stack for SIGSEGV inside interrupt handler +static bool emul_thread_fatal = false; // Flag: MacOS thread crashed, tick thread shall dump debug output +static sigregs sigsegv_regs; // Register dump when crashed +#endif + + +// Prototypes +static void Quit(void); +static void *emul_func(void *arg); +static void *nvram_func(void *arg); +static void *tick_func(void *arg); +#if !EMULATED_PPC +static void sigusr2_handler(int sig, sigcontext_struct *sc); +static void sigsegv_handler(int sig, sigcontext_struct *sc); +static void sigill_handler(int sig, sigcontext_struct *sc); +#endif + + +// From asm_linux.S +#if EMULATED_PPC +extern int atomic_add(int *var, int v); +extern int atomic_and(int *var, int v); +extern int atomic_or(int *var, int v); +#else +extern "C" void *get_toc(void); +extern "C" void *get_sp(void); +extern "C" void flush_icache_range(void *start, void *end); +extern "C" void jump_to_rom(uint32 entry, uint32 context); +extern "C" void quit_emulator(void); +extern "C" void execute_68k(uint32 pc, M68kRegisters *r); +extern "C" void ppc_interrupt(uint32 entry, uint32 kernel_data); +extern "C" int atomic_add(int *var, int v); +extern "C" int atomic_and(int *var, int v); +extern "C" int atomic_or(int *var, int v); +extern void paranoia_check(void); +#endif + + +// Decode LZSS data +static void decode_lzss(const uint8 *src, uint8 *dest, int size) +{ + char dict[0x1000]; + int run_mask = 0, dict_idx = 0xfee; + for (;;) { + if (run_mask < 0x100) { + // Start new run + if (--size < 0) + break; + run_mask = *src++ | 0xff00; + } + bool bit = run_mask & 1; + run_mask >>= 1; + if (bit) { + // Verbatim copy + if (--size < 0) + break; + int c = *src++; + dict[dict_idx++] = c; + *dest++ = c; + dict_idx &= 0xfff; + } else { + // Copy from dictionary + if (--size < 0) + break; + int idx = *src++; + if (--size < 0) + break; + int cnt = *src++; + idx |= (cnt << 4) & 0xf00; + cnt = (cnt & 0x0f) + 3; + while (cnt--) { + char c = dict[idx++]; + dict[dict_idx++] = c; + *dest++ = c; + idx &= 0xfff; + dict_idx &= 0xfff; + } + } + } +} + + +/* + * Main program + */ + +static void usage(const char *prg_name) +{ + printf("Usage: %s [OPTION...]\n", prg_name); + printf("\nUnix options:\n"); + printf(" --display STRING\n X display to use\n"); + PrefsPrintUsage(); + exit(0); +} + +int main(int argc, char **argv) +{ + char str[256]; + uint32 *boot_globs; + int16 i16; + int drive, driver; + int rom_fd; + FILE *proc_file; + const char *rom_path; + uint32 rom_size, actual; + uint8 *rom_tmp; + time_t now, expire; + + // Initialize variables + RAMBase = 0; + mmap_RAMBase = NULL; + tzset(); + + // Print some info + printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); + printf(" %s\n", GetString(STR_ABOUT_TEXT2)); + +#if !EMULATED_PPC + // Get TOC pointer + TOC = get_toc(); +#endif + +#ifdef ENABLE_GTK + // Init GTK + gtk_set_locale(); + gtk_init(&argc, &argv); +#endif + + // Read preferences + PrefsInit(argc, argv); + + // Parse command line arguments + for (int i=1; ied; + KernelDataAddr = (uint32)kernel_data; + D(bug("Kernel Data at %p, Emulator Data at %p\n", kernel_data, emulator_data)); + + // Create area for Mac ROM + if (mmap((char *)ROM_BASE, ROM_AREA_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) == (void *)-1) { + sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } + rom_area_mapped = true; + D(bug("ROM area at %08x\n", ROM_BASE)); + + // Create area for Mac RAM + RAMSize = PrefsFindInt32("ramsize"); + if (RAMSize < 8*1024*1024) { + WarningAlert(GetString(STR_SMALL_RAM_WARN)); + RAMSize = 8*1024*1024; + } + + mmap_RAMBase = mmap((void *)0x20000000, RAMSize, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0); + if (mmap_RAMBase == (void *)-1) { + sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } + RAMBase = (uint32)mmap_RAMBase; + ram_area_mapped = true; + D(bug("RAM area at %08x\n", RAMBase)); + + if (RAMBase > ROM_BASE) { + ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR)); + goto quit; + } + + // Load Mac ROM + rom_path = PrefsFindString("rom"); + rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY); + if (rom_fd < 0) { + rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME2, O_RDONLY); + if (rom_fd < 0) { + ErrorAlert(GetString(STR_NO_ROM_FILE_ERR)); + goto quit; + } + } + printf(GetString(STR_READING_ROM_FILE)); + rom_size = lseek(rom_fd, 0, SEEK_END); + lseek(rom_fd, 0, SEEK_SET); + rom_tmp = new uint8[ROM_SIZE]; + actual = read(rom_fd, (void *)rom_tmp, ROM_SIZE); + close(rom_fd); + if (actual == ROM_SIZE) { + // Plain ROM image + memcpy((void *)ROM_BASE, rom_tmp, ROM_SIZE); + delete[] rom_tmp; + } else { + if (strncmp((char *)rom_tmp, "", 11) == 0) { + // CHRP compressed ROM image + D(bug("CHRP ROM image\n")); + uint32 lzss_offset, lzss_size; + + char *s = strstr((char *)rom_tmp, "constant lzss-offset"); + if (s == NULL) { + ErrorAlert(GetString(STR_ROM_SIZE_ERR)); + goto quit; + } + s -= 7; + if (sscanf(s, "%06x", &lzss_offset) != 1) { + ErrorAlert(GetString(STR_ROM_SIZE_ERR)); + goto quit; + } + s = strstr((char *)rom_tmp, "constant lzss-size"); + if (s == NULL) { + ErrorAlert(GetString(STR_ROM_SIZE_ERR)); + goto quit; + } + s -= 7; + if (sscanf(s, "%06x", &lzss_size) != 1) { + ErrorAlert(GetString(STR_ROM_SIZE_ERR)); + goto quit; + } + D(bug("Offset of compressed data: %08x\n", lzss_offset)); + D(bug("Size of compressed data: %08x\n", lzss_size)); + + D(bug("Uncompressing ROM...\n")); + decode_lzss(rom_tmp + lzss_offset, (uint8 *)ROM_BASE, lzss_size); + delete[] rom_tmp; + } else if (rom_size != 4*1024*1024) { + ErrorAlert(GetString(STR_ROM_SIZE_ERR)); + goto quit; + } else { + ErrorAlert(GetString(STR_ROM_FILE_READ_ERR)); + goto quit; + } + } + + // Load NVRAM + XPRAMInit(); + + // Set boot volume + drive = PrefsFindInt32("bootdrive"); + XPRAM[0x1378] = i16 >> 8; + XPRAM[0x1379] = i16 & 0xff; + driver = PrefsFindInt32("bootdriver"); + XPRAM[0x137a] = i16 >> 8; + XPRAM[0x137b] = i16 & 0xff; + + // Create BootGlobs at top of Mac memory + memset((void *)(RAMBase + RAMSize - 4096), 0, 4096); + BootGlobsAddr = RAMBase + RAMSize - 0x1c; + boot_globs = (uint32 *)BootGlobsAddr; + boot_globs[-5] = htonl(RAMBase + RAMSize); // MemTop + boot_globs[0] = htonl(RAMBase); // First RAM bank + boot_globs[1] = htonl(RAMSize); + boot_globs[2] = htonl((uint32)-1); // End of bank table + + // Init drivers + SonyInit(); + DiskInit(); + CDROMInit(); + SCSIInit(); + + // Init external file system + ExtFSInit(); + + // Init audio + AudioInit(); + + // Init network + EtherInit(); + + // Init serial ports + SerialInit(); + + // Init Time Manager + TimerInit(); + + // Init clipboard + ClipInit(); + + // Init video + if (!VideoInit()) + goto quit; + + // Install ROM patches + if (!PatchROM()) { + ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); + goto quit; + } + + // Clear caches (as we loaded and patched code) and write protect ROM +#if !EMULATED_PPC + MakeExecutable(0, (void *)ROM_BASE, ROM_AREA_SIZE); +#endif + mprotect((char *)ROM_BASE, ROM_AREA_SIZE, PROT_EXEC | PROT_READ); + + // Initialize Kernel Data + memset(kernel_data, 0, sizeof(KernelData)); + if (ROMType == ROMTYPE_NEWWORLD) { + static uint32 of_dev_tree[4] = {0, 0, 0, 0}; + static uint8 vector_lookup_tbl[128]; + static uint8 vector_mask_tbl[64]; + memset((uint8 *)kernel_data + 0xb80, 0x3d, 0x80); + memset(vector_lookup_tbl, 0, 128); + memset(vector_mask_tbl, 0, 64); + kernel_data->v[0xb80 >> 2] = htonl(ROM_BASE); + kernel_data->v[0xb84 >> 2] = htonl((uint32)of_dev_tree); // OF device tree base + kernel_data->v[0xb90 >> 2] = htonl((uint32)vector_lookup_tbl); + kernel_data->v[0xb94 >> 2] = htonl((uint32)vector_mask_tbl); + kernel_data->v[0xb98 >> 2] = htonl(ROM_BASE); // OpenPIC base + kernel_data->v[0xbb0 >> 2] = htonl(0); // ADB base + kernel_data->v[0xc20 >> 2] = htonl(RAMSize); + kernel_data->v[0xc24 >> 2] = htonl(RAMSize); + kernel_data->v[0xc30 >> 2] = htonl(RAMSize); + kernel_data->v[0xc34 >> 2] = htonl(RAMSize); + kernel_data->v[0xc38 >> 2] = htonl(0x00010020); + kernel_data->v[0xc3c >> 2] = htonl(0x00200001); + kernel_data->v[0xc40 >> 2] = htonl(0x00010000); + kernel_data->v[0xc50 >> 2] = htonl(RAMBase); + kernel_data->v[0xc54 >> 2] = htonl(RAMSize); + kernel_data->v[0xf60 >> 2] = htonl(PVR); + kernel_data->v[0xf64 >> 2] = htonl(CPUClockSpeed); + kernel_data->v[0xf68 >> 2] = htonl(BusClockSpeed); + kernel_data->v[0xf6c >> 2] = htonl(CPUClockSpeed); + } else { + kernel_data->v[0xc80 >> 2] = htonl(RAMSize); + kernel_data->v[0xc84 >> 2] = htonl(RAMSize); + kernel_data->v[0xc90 >> 2] = htonl(RAMSize); + kernel_data->v[0xc94 >> 2] = htonl(RAMSize); + kernel_data->v[0xc98 >> 2] = htonl(0x00010020); + kernel_data->v[0xc9c >> 2] = htonl(0x00200001); + kernel_data->v[0xca0 >> 2] = htonl(0x00010000); + kernel_data->v[0xcb0 >> 2] = htonl(RAMBase); + kernel_data->v[0xcb4 >> 2] = htonl(RAMSize); + kernel_data->v[0xf80 >> 2] = htonl(PVR); + kernel_data->v[0xf84 >> 2] = htonl(CPUClockSpeed); + kernel_data->v[0xf88 >> 2] = htonl(BusClockSpeed); + kernel_data->v[0xf8c >> 2] = htonl(CPUClockSpeed); + } + + // Initialize extra low memory + D(bug("Initializing Low Memory...\n")); + memset(NULL, 0, 0x3000); + WriteMacInt32(XLM_SIGNATURE, FOURCC('B','a','a','h')); // Signature to detect SheepShaver + WriteMacInt32(XLM_KERNEL_DATA, (uint32)kernel_data); // For trap replacement routines + WriteMacInt32(XLM_PVR, PVR); // Theoretical PVR + WriteMacInt32(XLM_BUS_CLOCK, BusClockSpeed); // For DriverServicesLib patch + WriteMacInt16(XLM_EXEC_RETURN_OPCODE, M68K_EXEC_RETURN); // For Execute68k() (RTS from the executed 68k code will jump here and end 68k mode) +#if !EMULATED_PPC + WriteMacInt32(XLM_TOC, (uint32)TOC); // TOC pointer of emulator + WriteMacInt32(XLM_ETHER_INIT, (uint32)InitStreamModule); // DLPI ethernet driver functions + WriteMacInt32(XLM_ETHER_TERM, (uint32)TerminateStreamModule); + WriteMacInt32(XLM_ETHER_OPEN, (uint32)ether_open); + WriteMacInt32(XLM_ETHER_CLOSE, (uint32)ether_close); + WriteMacInt32(XLM_ETHER_WPUT, (uint32)ether_wput); + WriteMacInt32(XLM_ETHER_RSRV, (uint32)ether_rsrv); + WriteMacInt32(XLM_VIDEO_DOIO, (uint32)VideoDoDriverIO); +#endif + D(bug("Low Memory initialized\n")); + + // Start 60Hz thread + tick_thread_active = (pthread_create(&tick_thread, NULL, tick_func, NULL) == 0); + D(bug("Tick thread installed (%ld)\n", tick_thread)); + + // Start NVRAM watchdog thread + memcpy(last_xpram, XPRAM, XPRAM_SIZE); + nvram_thread_active = (pthread_create(&nvram_thread, NULL, nvram_func, NULL) == 0); + D(bug("NVRAM thread installed (%ld)\n", nvram_thread)); + +#if !EMULATED_PPC + // Create and install stacks for signal handlers + sig_stack = malloc(SIG_STACK_SIZE); + D(bug("Signal stack at %p\n", sig_stack)); + if (sig_stack == NULL) { + ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); + goto quit; + } + extra_stack = malloc(SIG_STACK_SIZE); + D(bug("Extra stack at %p\n", extra_stack)); + if (extra_stack == NULL) { + ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR)); + goto quit; + } + struct sigaltstack new_stack; + new_stack.ss_sp = sig_stack; + new_stack.ss_flags = 0; + new_stack.ss_size = SIG_STACK_SIZE; + if (sigaltstack(&new_stack, NULL) < 0) { + sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } +#endif + +#if !EMULATED_PPC + // Install SIGSEGV handler + sigemptyset(&sigsegv_action.sa_mask); // Block interrupts during SEGV handling + sigaddset(&sigsegv_action.sa_mask, SIGUSR2); + sigsegv_action.sa_handler = (__sighandler_t)sigsegv_handler; + sigsegv_action.sa_flags = SA_ONSTACK; + sigsegv_action.sa_restorer = NULL; + if (sigaction(SIGSEGV, &sigsegv_action, NULL) < 0) { + sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } + + // Install SIGILL handler + sigemptyset(&sigill_action.sa_mask); // Block interrupts during ILL handling + sigaddset(&sigill_action.sa_mask, SIGUSR2); + sigill_action.sa_handler = (__sighandler_t)sigill_handler; + sigill_action.sa_flags = SA_ONSTACK; + sigill_action.sa_restorer = NULL; + if (sigaction(SIGILL, &sigill_action, NULL) < 0) { + sprintf(str, GetString(STR_SIGILL_INSTALL_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } + + // Install interrupt signal handler + sigemptyset(&sigusr2_action.sa_mask); + sigusr2_action.sa_handler = (__sighandler_t)sigusr2_handler; + sigusr2_action.sa_flags = SA_ONSTACK | SA_RESTART; + sigusr2_action.sa_restorer = NULL; + if (sigaction(SIGUSR2, &sigusr2_action, NULL) < 0) { + sprintf(str, GetString(STR_SIGUSR2_INSTALL_ERR), strerror(errno)); + ErrorAlert(str); + goto quit; + } +#endif + + // Get my thread ID and execute MacOS thread function + emul_thread = pthread_self(); + D(bug("MacOS thread is %ld\n", emul_thread)); + emul_func(NULL); + +quit: + Quit(); + return 0; +} + + +/* + * Cleanup and quit + */ + +static void Quit(void) +{ + // Stop 60Hz thread + if (tick_thread_active) { + pthread_cancel(tick_thread); + pthread_join(tick_thread, NULL); + } + + // Stop NVRAM watchdog thread + if (nvram_thread_active) { + pthread_cancel(nvram_thread); + pthread_join(nvram_thread, NULL); + } + +#if !EMULATED_PPC + // Uninstall SIGSEGV handler + sigemptyset(&sigsegv_action.sa_mask); + sigsegv_action.sa_handler = SIG_DFL; + sigsegv_action.sa_flags = 0; + sigaction(SIGSEGV, &sigsegv_action, NULL); + + // Uninstall SIGILL handler + sigemptyset(&sigill_action.sa_mask); + sigill_action.sa_handler = SIG_DFL; + sigill_action.sa_flags = 0; + sigaction(SIGILL, &sigill_action, NULL); +#endif + + // Save NVRAM + XPRAMExit(); + + // Exit clipboard + ClipExit(); + + // Exit Time Manager + TimerExit(); + + // Exit serial + SerialExit(); + + // Exit network + EtherExit(); + + // Exit audio + AudioExit(); + + // Exit video + VideoExit(); + + // Exit external file system + ExtFSExit(); + + // Exit drivers + SCSIExit(); + CDROMExit(); + DiskExit(); + SonyExit(); + + // Delete RAM area + if (ram_area_mapped) + munmap(mmap_RAMBase, RAMSize); + + // Delete ROM area + if (rom_area_mapped) + munmap((char *)ROM_BASE, ROM_AREA_SIZE); + + // Delete Kernel Data area + if (kernel_area >= 0) { + shmdt((void *)KERNEL_DATA_BASE); + shmdt((void *)KERNEL_DATA2_BASE); + shmctl(kernel_area, IPC_RMID, NULL); + } + + // Delete Low Memory area + if (lm_area_mapped) + munmap((char *)0x0000, 0x3000); + + // Close /dev/zero + if (zero_fd > 0) + close(zero_fd); + + // Exit system routines + SysExit(); + + // Exit preferences + PrefsExit(); + +#ifdef ENABLE_MON + // Exit mon + mon_exit(); +#endif + + // Close X11 server connection + if (x_display) + XCloseDisplay(x_display); + + exit(0); +} + + +/* + * Jump into Mac ROM, start 680x0 emulator + */ + +#if EMULATED_PPC +extern void emul_ppc(uint32 start); +extern void init_emul_ppc(void); +void jump_to_rom(uint32 entry) +{ + init_emul_ppc(); + emul_ppc(entry); +} +#endif + + +/* + * Emulator thread function + */ + +static void *emul_func(void *arg) +{ + // We're now ready to receive signals + ready_for_signals = true; + + // Decrease priority, so more time-critical things like audio will work better + nice(1); + + // Jump to ROM boot routine + D(bug("Jumping to ROM\n")); +#if EMULATED_PPC + jump_to_rom(ROM_BASE + 0x310000); +#else + jump_to_rom(ROM_BASE + 0x310000, (uint32)emulator_data); +#endif + D(bug("Returned from ROM\n")); + + // We're no longer ready to receive signals + ready_for_signals = false; + return NULL; +} + + +#if !EMULATED_PPC +/* + * Execute 68k subroutine (must be ended with RTS) + * This must only be called by the emul_thread when in EMUL_OP mode + * r->a[7] is unused, the routine runs on the caller's stack + */ + +void Execute68k(uint32 pc, M68kRegisters *r) +{ +#if SAFE_EXEC_68K + if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP) + printf("FATAL: Execute68k() not called from EMUL_OP mode\n"); + if (!pthread_equal(pthread_self(), emul_thread)) + printf("FATAL: Execute68k() not called from emul_thread\n"); +#endif + execute_68k(pc, r); +} + + +/* + * Execute 68k A-Trap from EMUL_OP routine + * r->a[7] is unused, the routine runs on the caller's stack + */ + +void Execute68kTrap(uint16 trap, M68kRegisters *r) +{ + uint16 proc[2] = {trap, M68K_RTS}; + Execute68k((uint32)proc, r); +} +#endif + + +/* + * Execute PPC code from EMUL_OP routine (real mode switch) + */ + +void ExecutePPC(void (*func)()) +{ + uint32 tvect[2] = {(uint32)func, 0}; // Fake TVECT + RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect); + M68kRegisters r; + Execute68k((uint32)&desc, &r); +} + + +/* + * Quit emulator (cause return from jump_to_rom) + */ + +void QuitEmulator(void) +{ +#if EMULATED_PPC + Quit(); +#else + quit_emulator(); +#endif +} + + +/* + * Pause/resume emulator + */ + +void PauseEmulator(void) +{ + pthread_kill(emul_thread, SIGSTOP); +} + +void ResumeEmulator(void) +{ + pthread_kill(emul_thread, SIGCONT); +} + + +/* + * Dump 68k registers + */ + +void Dump68kRegs(M68kRegisters *r) +{ + // Display 68k registers + for (int i=0; i<8; i++) { + printf("d%d: %08x", i, r->d[i]); + if (i == 3 || i == 7) + printf("\n"); + else + printf(", "); + } + for (int i=0; i<8; i++) { + printf("a%d: %08x", i, r->a[i]); + if (i == 3 || i == 7) + printf("\n"); + else + printf(", "); + } +} + + +/* + * Make code executable + */ + +void MakeExecutable(int dummy, void *start, uint32 length) +{ +#if !EMULATED_PPC + if (((uint32)start >= ROM_BASE) && ((uint32)start < (ROM_BASE + ROM_SIZE))) + return; + flush_icache_range(start, (void *)((uint32)start + length)); +#endif +} + + +/* + * Patch things after system startup (gets called by disk driver accRun routine) + */ + +void PatchAfterStartup(void) +{ + ExecutePPC(VideoInstallAccel); + InstallExtFS(); +} + + +/* + * NVRAM watchdog thread (saves NVRAM every minute) + */ + +static void *nvram_func(void *arg) +{ + struct timespec req = {60, 0}; // 1 minute + + for (;;) { + pthread_testcancel(); + nanosleep(&req, NULL); + pthread_testcancel(); + if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) { + memcpy(last_xpram, XPRAM, XPRAM_SIZE); + SaveXPRAM(); + } + } + return NULL; +} + + +/* + * 60Hz thread (really 60.15Hz) + */ + +static void *tick_func(void *arg) +{ + int tick_counter = 0; + struct timespec req = {0, 16625000}; + + for (;;) { + + // Wait + nanosleep(&req, NULL); + +#if !EMULATED_PPC + // Did we crash? + if (emul_thread_fatal) { + + // Yes, dump registers + pt_regs *r = (pt_regs *)&sigsegv_regs; + char str[256]; + sprintf(str, "SIGSEGV\n" + " pc %08lx lr %08lx ctr %08lx msr %08lx\n" + " xer %08lx cr %08lx \n" + " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n" + " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n" + " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n" + " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n" + " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n" + " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" + " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" + " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", + r->nip, r->link, r->ctr, r->msr, + r->xer, r->ccr, + r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3], + r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7], + r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11], + r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15], + r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19], + r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23], + r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27], + r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]); + printf(str); + VideoQuitFullScreen(); + +#ifdef ENABLE_MON + // Start up mon in real-mode + printf("Welcome to the sheep factory.\n"); + char *arg[4] = {"mon", "-m", "-r", NULL}; + mon(3, arg); +#endif + return NULL; + } +#endif + + // Pseudo Mac 1Hz interrupt, update local time + if (++tick_counter > 60) { + tick_counter = 0; + WriteMacInt32(0x20c, TimerDateTime()); + } + + // Trigger 60Hz interrupt + if (ReadMacInt32(XLM_IRQ_NEST) == 0) { + SetInterruptFlag(INTFLAG_VIA); + TriggerInterrupt(); + } + } + return NULL; +} + + +/* + * Mutexes + */ + +struct B2_mutex { + int dummy; +}; + +B2_mutex *B2_create_mutex(void) +{ + return new B2_mutex; +} + +void B2_lock_mutex(B2_mutex *mutex) +{ +} + +void B2_unlock_mutex(B2_mutex *mutex) +{ +} + +void B2_delete_mutex(B2_mutex *mutex) +{ + delete mutex; +} + + +/* + * Trigger signal USR2 from another thread + */ + +void TriggerInterrupt(void) +{ +#if EMULATED_PPC + WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); +#else +#if 0 + WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); +#else + if (ready_for_signals) + pthread_kill(emul_thread, SIGUSR2); +#endif +#endif +} + + +/* + * Interrupt flags (must be handled atomically!) + */ + +volatile uint32 InterruptFlags = 0; + +void SetInterruptFlag(uint32 flag) +{ + atomic_or((int *)&InterruptFlags, flag); +} + +void ClearInterruptFlag(uint32 flag) +{ + atomic_and((int *)&InterruptFlags, ~flag); +} + + +/* + * Disable interrupts + */ + +void DisableInterrupt(void) +{ + atomic_add((int *)XLM_IRQ_NEST, 1); +} + + +/* + * Enable interrupts + */ + +void EnableInterrupt(void) +{ + atomic_add((int *)XLM_IRQ_NEST, -1); +} + + +#if !EMULATED_PPC +/* + * USR2 handler + */ + +static void sigusr2_handler(int sig, sigcontext_struct *sc) +{ + pt_regs *r = sc->regs; + + // Do nothing if interrupts are disabled + if (*(int32 *)XLM_IRQ_NEST > 0) + return; + + // Disable MacOS stack sniffer + WriteMacInt32(0x110, 0); + + // Interrupt action depends on current run mode + switch (ReadMacInt32(XLM_RUN_MODE)) { + case MODE_68K: + // 68k emulator active, trigger 68k interrupt level 1 + WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); + r->ccr |= ntohl(kernel_data->v[0x674 >> 2]); + break; + +#if INTERRUPTS_IN_NATIVE_MODE + case MODE_NATIVE: + // 68k emulator inactive, in nanokernel? + if (r->gpr[1] != KernelDataAddr) { + // Prepare for 68k interrupt level 1 + WriteMacInt16(ntohl(kernel_data->v[0x67c >> 2]), 1); + WriteMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc, ReadMacInt32(ntohl(kernel_data->v[0x658 >> 2]) + 0xdc) | ntohl(kernel_data->v[0x674 >> 2])); + + // Execute nanokernel interrupt routine (this will activate the 68k emulator) + atomic_add((int32 *)XLM_IRQ_NEST, 1); + if (ROMType == ROMTYPE_NEWWORLD) + ppc_interrupt(ROM_BASE + 0x312b1c, KernelDataAddr); + else + ppc_interrupt(ROM_BASE + 0x312a3c, KernelDataAddr); + } + break; +#endif + +#if INTERRUPTS_IN_EMUL_OP_MODE + case MODE_EMUL_OP: + // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 + if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { + + // Set extra stack for SIGSEGV handler + struct sigaltstack new_stack; + new_stack.ss_sp = extra_stack; + new_stack.ss_flags = 0; + new_stack.ss_size = SIG_STACK_SIZE; + sigaltstack(&new_stack, NULL); +#if 1 + // Execute full 68k interrupt routine + M68kRegisters r; + uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level + WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1 + static const uint16 proc[] = { + 0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word) + 0x487a, 0x000a, // pea @1(pc) (return address) + 0x40e7, // move sr,-(sp) (saved SR) + 0x2078, 0x0064, // move.l $64,a0 + 0x4ed0, // jmp (a0) + M68K_RTS // @1 + }; + Execute68k((uint32)proc, &r); + WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level +#else + // Only update cursor + if (HasMacStarted()) { + if (InterruptFlags & INTFLAG_VIA) { + ClearInterruptFlag(INTFLAG_VIA); + ADBInterrupt(); + ExecutePPC(VideoVBL); + } + } +#endif + // Reset normal signal stack + new_stack.ss_sp = sig_stack; + new_stack.ss_flags = 0; + new_stack.ss_size = SIG_STACK_SIZE; + sigaltstack(&new_stack, NULL); + } + break; +#endif + + } +} + + +/* + * SIGSEGV handler + */ + +static void sigsegv_handler(int sig, sigcontext_struct *sc) +{ + pt_regs *r = sc->regs; + num_segv++; + + // Fault in Mac ROM or RAM? + bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize)); + if (mac_fault) { + + // Get opcode and divide into fields + uint32 opcode = *((uint32 *)r->nip); + uint32 primop = opcode >> 26; + uint32 exop = (opcode >> 1) & 0x3ff; + uint32 ra = (opcode >> 16) & 0x1f; + uint32 rb = (opcode >> 11) & 0x1f; + uint32 rd = (opcode >> 21) & 0x1f; + int32 imm = (int16)(opcode & 0xffff); + + // "VM settings" during MacOS 8 installation + if (r->nip == ROM_BASE + 0x488160 && r->gpr[20] == 0xf8000000) { + r->nip += 4; + r->gpr[8] = 0; + return; + + // MacOS 8.5 installation + } else if (r->nip == ROM_BASE + 0x488140 && r->gpr[16] == 0xf8000000) { + r->nip += 4; + r->gpr[8] = 0; + return; + + // MacOS 8 serial drivers on startup + } else if (r->nip == ROM_BASE + 0x48e080 && (r->gpr[8] == 0xf3012002 || r->gpr[8] == 0xf3012000)) { + r->nip += 4; + r->gpr[8] = 0; + return; + + // MacOS 8.1 serial drivers on startup + } else if (r->nip == ROM_BASE + 0x48c5e0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) { + r->nip += 4; + return; + } else if (r->nip == ROM_BASE + 0x4a10a0 && (r->gpr[20] == 0xf3012002 || r->gpr[20] == 0xf3012000)) { + r->nip += 4; + return; + } + + // Analyze opcode + enum { + TYPE_UNKNOWN, + TYPE_LOAD, + TYPE_STORE + } transfer_type = TYPE_UNKNOWN; + enum { + SIZE_UNKNOWN, + SIZE_BYTE, + SIZE_HALFWORD, + SIZE_WORD + } transfer_size = SIZE_UNKNOWN; + enum { + MODE_UNKNOWN, + MODE_NORM, + MODE_U, + MODE_X, + MODE_UX + } addr_mode = MODE_UNKNOWN; + switch (primop) { + case 31: + switch (exop) { + case 23: // lwzx + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; + case 55: // lwzux + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; + case 87: // lbzx + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; + case 119: // lbzux + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; + case 151: // stwx + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; + case 183: // stwux + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; + case 215: // stbx + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; + case 247: // stbux + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; + case 279: // lhzx + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; + case 311: // lhzux + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; + case 343: // lhax + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; + case 375: // lhaux + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; + case 407: // sthx + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; + case 439: // sthux + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; + } + break; + + case 32: // lwz + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; + case 33: // lwzu + transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; + case 34: // lbz + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; + case 35: // lbzu + transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; + case 36: // stw + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; + case 37: // stwu + transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; + case 38: // stb + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; + case 39: // stbu + transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; + case 40: // lhz + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; + case 41: // lhzu + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; + case 42: // lha + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; + case 43: // lhau + transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; + case 44: // sth + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; + case 45: // sthu + transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; + } + + // Calculate effective address + uint32 addr = 0; + switch (addr_mode) { + case MODE_X: + case MODE_UX: + if (ra == 0) + addr = r->gpr[rb]; + else + addr = r->gpr[ra] + r->gpr[rb]; + break; + case MODE_NORM: + case MODE_U: + if (ra == 0) + addr = (int32)(int16)imm; + else + addr = r->gpr[ra] + (int32)(int16)imm; + break; + default: + break; + } + + // Ignore ROM writes + if (transfer_type == TYPE_STORE && addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) { +// D(bug("WARNING: %s write access to ROM at %08lx, pc %08lx\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->nip)); + if (addr_mode == MODE_U || addr_mode == MODE_UX) + r->gpr[ra] = addr; + r->nip += 4; + goto rti; + } + + // Ignore illegal memory accesses? + if (PrefsFindBool("ignoresegv")) { + if (addr_mode == MODE_U || addr_mode == MODE_UX) + r->gpr[ra] = addr; + if (transfer_type == TYPE_LOAD) + r->gpr[rd] = 0; + r->nip += 4; + goto rti; + } + + // In GUI mode, show error alert + if (!PrefsFindBool("nogui")) { + char str[256]; + if (transfer_type == TYPE_LOAD || transfer_type == TYPE_STORE) + sprintf(str, GetString(STR_MEM_ACCESS_ERR), transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_HALFWORD ? "halfword" : "word", transfer_type == TYPE_LOAD ? GetString(STR_MEM_ACCESS_READ) : GetString(STR_MEM_ACCESS_WRITE), addr, r->nip, r->gpr[24], r->gpr[1]); + else + sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode); + ErrorAlert(str); + QuitEmulator(); + return; + } + } + + // For all other errors, jump into debugger (sort of...) + if (!ready_for_signals) { + printf("SIGSEGV\n"); + printf(" sigcontext %p, pt_regs %p\n", sc, r); + printf( + " pc %08lx lr %08lx ctr %08lx msr %08lx\n" + " xer %08lx cr %08lx \n" + " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n" + " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n" + " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n" + " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n" + " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n" + " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" + " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" + " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", + r->nip, r->link, r->ctr, r->msr, + r->xer, r->ccr, + r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3], + r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7], + r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11], + r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15], + r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19], + r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23], + r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27], + r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]); + exit(1); + QuitEmulator(); + return; + } else { + // We crashed. Save registers, tell tick thread and loop forever + sigsegv_regs = *(sigregs *)r; + emul_thread_fatal = true; + for (;;) ; + } +rti:; +} + + +/* + * SIGILL handler + */ + +static void sigill_handler(int sig, sigcontext_struct *sc) +{ + pt_regs *r = sc->regs; + char str[256]; + + // Fault in Mac ROM or RAM? + bool mac_fault = (r->nip >= ROM_BASE) && (r->nip < (ROM_BASE + ROM_AREA_SIZE)) || (r->nip >= RAMBase) && (r->nip < (RAMBase + RAMSize)); + if (mac_fault) { + + // Get opcode and divide into fields + uint32 opcode = *((uint32 *)r->nip); + uint32 primop = opcode >> 26; + uint32 exop = (opcode >> 1) & 0x3ff; + uint32 ra = (opcode >> 16) & 0x1f; + uint32 rb = (opcode >> 11) & 0x1f; + uint32 rd = (opcode >> 21) & 0x1f; + int32 imm = (int16)(opcode & 0xffff); + + switch (primop) { + case 9: // POWER instructions + case 22: +power_inst: sprintf(str, GetString(STR_POWER_INSTRUCTION_ERR), r->nip, r->gpr[1], opcode); + ErrorAlert(str); + QuitEmulator(); + return; + + case 31: + switch (exop) { + case 83: // mfmsr + r->gpr[rd] = 0xf072; + r->nip += 4; + goto rti; + + case 210: // mtsr + case 242: // mtsrin + case 306: // tlbie + r->nip += 4; + goto rti; + + case 339: { // mfspr + int spr = ra | (rb << 5); + switch (spr) { + case 0: // MQ + case 22: // DEC + case 952: // MMCR0 + case 953: // PMC1 + case 954: // PMC2 + case 955: // SIA + case 956: // MMCR1 + case 957: // PMC3 + case 958: // PMC4 + case 959: // SDA + r->nip += 4; + goto rti; + case 25: // SDR1 + r->gpr[rd] = 0xdead001f; + r->nip += 4; + goto rti; + case 287: // PVR + r->gpr[rd] = PVR; + r->nip += 4; + goto rti; + } + break; + } + + case 467: { // mtspr + int spr = ra | (rb << 5); + switch (spr) { + case 0: // MQ + case 22: // DEC + case 275: // SPRG3 + case 528: // IBAT0U + case 529: // IBAT0L + case 530: // IBAT1U + case 531: // IBAT1L + case 532: // IBAT2U + case 533: // IBAT2L + case 534: // IBAT3U + case 535: // IBAT3L + case 536: // DBAT0U + case 537: // DBAT0L + case 538: // DBAT1U + case 539: // DBAT1L + case 540: // DBAT2U + case 541: // DBAT2L + case 542: // DBAT3U + case 543: // DBAT3L + case 952: // MMCR0 + case 953: // PMC1 + case 954: // PMC2 + case 955: // SIA + case 956: // MMCR1 + case 957: // PMC3 + case 958: // PMC4 + case 959: // SDA + r->nip += 4; + goto rti; + } + break; + } + + case 29: case 107: case 152: case 153: // POWER instructions + case 184: case 216: case 217: case 248: + case 264: case 277: case 331: case 360: + case 363: case 488: case 531: case 537: + case 541: case 664: case 665: case 696: + case 728: case 729: case 760: case 920: + case 921: case 952: + goto power_inst; + } + } + + // In GUI mode, show error alert + if (!PrefsFindBool("nogui")) { + sprintf(str, GetString(STR_UNKNOWN_SEGV_ERR), r->nip, r->gpr[24], r->gpr[1], opcode); + ErrorAlert(str); + QuitEmulator(); + return; + } + } + + // For all other errors, jump into debugger (sort of...) + if (!ready_for_signals) { + printf("SIGILL\n"); + printf(" sigcontext %p, pt_regs %p\n", sc, r); + printf( + " pc %08lx lr %08lx ctr %08lx msr %08lx\n" + " xer %08lx cr %08lx \n" + " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n" + " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n" + " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n" + " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n" + " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n" + " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" + " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" + " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", + r->nip, r->link, r->ctr, r->msr, + r->xer, r->ccr, + r->gpr[0], r->gpr[1], r->gpr[2], r->gpr[3], + r->gpr[4], r->gpr[5], r->gpr[6], r->gpr[7], + r->gpr[8], r->gpr[9], r->gpr[10], r->gpr[11], + r->gpr[12], r->gpr[13], r->gpr[14], r->gpr[15], + r->gpr[16], r->gpr[17], r->gpr[18], r->gpr[19], + r->gpr[20], r->gpr[21], r->gpr[22], r->gpr[23], + r->gpr[24], r->gpr[25], r->gpr[26], r->gpr[27], + r->gpr[28], r->gpr[29], r->gpr[30], r->gpr[31]); + exit(1); + QuitEmulator(); + return; + } else { + // We crashed. Save registers, tell tick thread and loop forever + sigsegv_regs = *(sigregs *)r; + emul_thread_fatal = true; + for (;;) ; + } +rti:; +} +#endif + + +/* + * Display alert + */ + +#ifdef ENABLE_GTK +static void dl_destroyed(void) +{ + gtk_main_quit(); +} + +static void dl_quit(GtkWidget *dialog) +{ + gtk_widget_destroy(dialog); +} + +void display_alert(int title_id, int prefix_id, int button_id, const char *text) +{ + char str[256]; + sprintf(str, GetString(prefix_id), text); + + GtkWidget *dialog = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id)); + gtk_container_border_width(GTK_CONTAINER(dialog), 5); + gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150); + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL); + + GtkWidget *label = gtk_label_new(str); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0); + + GtkWidget *button = gtk_button_new_with_label(GetString(button_id)); + gtk_widget_show(button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog)); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show(dialog); + + gtk_main(); +} +#endif + + +/* + * Display error alert + */ + +void ErrorAlert(const char *text) +{ +#ifdef ENABLE_GTK + if (PrefsFindBool("nogui") || x_display == NULL) { + printf(GetString(STR_SHELL_ERROR_PREFIX), text); + return; + } + VideoQuitFullScreen(); + display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text); +#else + printf(GetString(STR_SHELL_ERROR_PREFIX), text); +#endif +} + + +/* + * Display warning alert + */ + +void WarningAlert(const char *text) +{ +#ifdef ENABLE_GTK + if (PrefsFindBool("nogui") || x_display == NULL) { + printf(GetString(STR_SHELL_WARNING_PREFIX), text); + return; + } + display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text); +#else + printf(GetString(STR_SHELL_WARNING_PREFIX), text); +#endif +} + + +/* + * Display choice alert + */ + +bool ChoiceAlert(const char *text, const char *pos, const char *neg) +{ + printf(GetString(STR_SHELL_WARNING_PREFIX), text); + return false; //!! +} diff --git a/SheepShaver/src/Unix/mkinstalldirs b/SheepShaver/src/Unix/mkinstalldirs new file mode 100755 index 00000000..6b3b5fc5 --- /dev/null +++ b/SheepShaver/src/Unix/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id$ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/SheepShaver/src/Unix/ppc_asm.tmpl b/SheepShaver/src/Unix/ppc_asm.tmpl new file mode 100644 index 00000000..4cd0a17b --- /dev/null +++ b/SheepShaver/src/Unix/ppc_asm.tmpl @@ -0,0 +1,66 @@ +/* Register names */ +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + +#define f0 0 +#define f1 1 +#define f2 2 +#define f3 3 +#define f4 4 +#define f5 5 +#define f6 6 +#define f7 7 +#define f8 8 +#define f9 9 +#define f10 10 +#define f11 11 +#define f12 12 +#define f13 13 +#define f14 14 +#define f15 15 +#define f16 16 +#define f17 17 +#define f18 18 +#define f19 19 +#define f20 20 +#define f21 21 +#define f22 22 +#define f23 23 +#define f24 24 +#define f25 25 +#define f26 26 +#define f27 27 +#define f28 28 +#define f29 29 +#define f30 30 +#define f31 31 diff --git a/SheepShaver/src/Unix/prefs_editor_gtk.cpp b/SheepShaver/src/Unix/prefs_editor_gtk.cpp new file mode 100644 index 00000000..e6626ddb --- /dev/null +++ b/SheepShaver/src/Unix/prefs_editor_gtk.cpp @@ -0,0 +1,859 @@ +/* + * prefs_editor_linux.cpp - Preferences editor, Linux implementation using GTK+ + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "user_strings.h" +#include "version.h" +#include "cdrom.h" +#include "xpram.h" +#include "prefs.h" +#include "prefs_editor.h" + + +// Global variables +static GtkWidget *win; // Preferences window +static bool start_clicked = true; // Return value of PrefsEditor() function + + +// Prototypes +static void create_volumes_pane(GtkWidget *top); +static void create_graphics_pane(GtkWidget *top); +static void create_serial_pane(GtkWidget *top); +static void create_memory_pane(GtkWidget *top); +static void read_settings(void); + + +/* + * Utility functions + */ + +struct opt_desc { + int label_id; + GtkSignalFunc func; +}; + +static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func) +{ + GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id)); + gtk_widget_show(item); + gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL); + gtk_menu_append(GTK_MENU(menu), item); +} + +static GtkWidget *make_pane(GtkWidget *notebook, int title_id) +{ + GtkWidget *frame, *label, *box; + + frame = gtk_frame_new(NULL); + gtk_widget_show(frame); + gtk_container_border_width(GTK_CONTAINER(frame), 4); + + label = gtk_label_new(GetString(title_id)); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); + + box = gtk_vbox_new(FALSE, 4); + gtk_widget_show(box); + gtk_container_set_border_width(GTK_CONTAINER(box), 4); + gtk_container_add(GTK_CONTAINER(frame), box); + return box; +} + +static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons) +{ + GtkWidget *bb, *button; + + bb = gtk_hbutton_box_new(); + gtk_widget_show(bb); + gtk_container_set_border_width(GTK_CONTAINER(bb), border); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4); + gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0); + + while (buttons->label_id) { + button = gtk_button_new_with_label(GetString(buttons->label_id)); + gtk_widget_show(button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL); + gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0); + buttons++; + } + return bb; +} + +static GtkWidget *make_separator(GtkWidget *top) +{ + GtkWidget *sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0); + gtk_widget_show(sep); + return sep; +} + +static GtkWidget *make_table(GtkWidget *top, int x, int y) +{ + GtkWidget *table = gtk_table_new(x, y, FALSE); + gtk_widget_show(table); + gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0); + return table; +} + +static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active) +{ + GtkWidget *box, *label, *opt, *menu; + + box = gtk_hbox_new(FALSE, 4); + gtk_widget_show(box); + gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); + + label = gtk_label_new(GetString(label_id)); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); + + opt = gtk_option_menu_new(); + gtk_widget_show(opt); + menu = gtk_menu_new(); + + while (options->label_id) { + add_menu_item(menu, options->label_id, options->func); + options++; + } + gtk_menu_set_active(GTK_MENU(menu), active); + + gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); + gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0); + return menu; +} + +static GtkWidget *make_entry(GtkWidget *top, int label_id, const char *prefs_item) +{ + GtkWidget *box, *label, *entry; + + box = gtk_hbox_new(FALSE, 4); + gtk_widget_show(box); + gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); + + label = gtk_label_new(GetString(label_id)); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); + + entry = gtk_entry_new(); + gtk_widget_show(entry); + const char *str = PrefsFindString(prefs_item); + if (str == NULL) + str = ""; + gtk_entry_set_text(GTK_ENTRY(entry), str); + gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); + return entry; +} + +static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func) +{ + GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id)); + gtk_widget_show(button); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item)); + gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button); + gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0); + return button; +} + +static GtkWidget *make_checkbox(GtkWidget *top, int label_id, bool active, GtkSignalFunc func) +{ + GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id)); + gtk_widget_show(button); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), active); + gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button); + gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0); + return button; +} + + +/* + * Show preferences editor + * Returns true when user clicked on "Start", false otherwise + */ + +// Window closed +static gint window_closed(void) +{ + return FALSE; +} + +// Window destroyed +static void window_destroyed(void) +{ + gtk_main_quit(); +} + +// "Start" button clicked +static void cb_start(...) +{ + start_clicked = true; + read_settings(); + SavePrefs(); + gtk_widget_destroy(win); +} + +// "Quit" button clicked +static void cb_quit(...) +{ + start_clicked = false; + gtk_widget_destroy(win); +} + +// "OK" button of "About" dialog clicked +static void dl_quit(GtkWidget *dialog) +{ + gtk_widget_destroy(dialog); +} + +// "About" selected +static void mn_about(...) +{ + GtkWidget *dialog, *label, *button; + + char str[512]; + sprintf(str, + "SheepShaver\nVersion %d.%d\n\n" + "Copyright (C) 1997-2002 Christian Bauer and Marc Hellwig\n" + "E-mail: Christian.Bauer@uni-mainz.de\n" + "http://www.uni-mainz.de/~bauec002/\n\n" + "SheepShaver comes with ABSOLUTELY NO\n" + "WARRANTY. This is free software, and\n" + "you are welcome to redistribute it\n" + "under the terms of the GNU General\n" + "Public License.\n", + VERSION_MAJOR, VERSION_MINOR + ); + + dialog = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE)); + gtk_container_border_width(GTK_CONTAINER(dialog), 5); + gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150); + + label = gtk_label_new(str); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(GetString(STR_OK_BUTTON)); + gtk_widget_show(button); + gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog)); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(button); + gtk_widget_show(dialog); +} + +// "Zap NVRAM" selected +static void mn_zap_pram(...) +{ + ZapPRAM(); +} + +// Menu item descriptions +static GtkItemFactoryEntry menu_items[] = { + {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, ""}, + {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), NULL, GTK_SIGNAL_FUNC(cb_start), 0, NULL}, + {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(mn_zap_pram), 0, NULL}, + {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, ""}, + {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL}, + {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, ""}, + {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(mn_about), 0, NULL} +}; + +bool PrefsEditor(void) +{ + // Create window + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE)); + gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL); + gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL); + + // Create window contents + GtkWidget *box = gtk_vbox_new(FALSE, 4); + gtk_widget_show(box); + gtk_container_add(GTK_CONTAINER(win), box); + + GtkAccelGroup *accel_group = gtk_accel_group_new(); + GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "
", accel_group); + gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL); + gtk_accel_group_attach(accel_group, GTK_OBJECT(win)); + GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "
"); + gtk_widget_show(menu_bar); + gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0); + + GtkWidget *notebook = gtk_notebook_new(); + gtk_widget_show(notebook); + gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP); + gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE); + gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0); + + create_volumes_pane(notebook); + create_graphics_pane(notebook); + create_serial_pane(notebook); + create_memory_pane(notebook); + + static const opt_desc buttons[] = { + {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)}, + {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)}, + {0, NULL} + }; + make_button_box(box, 4, buttons); + + // Show window and enter main loop + gtk_widget_show(win); + gtk_main(); + return start_clicked; +} + + +/* + * "Volumes" pane + */ + +static GtkWidget *volume_list, *w_extfs; +static int selected_volume; + +// Volume in list selected +static void cl_selected(GtkWidget *list, int row, int column) +{ + selected_volume = row; +} + +struct file_req_assoc { + file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {} + GtkWidget *req; + GtkWidget *entry; +}; + +// Volume selected for addition +static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc) +{ + char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); + gtk_clist_append(GTK_CLIST(volume_list), &file); + gtk_widget_destroy(assoc->req); + delete assoc; +} + +// Volume selected for creation +static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc) +{ + char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); + + char *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry)); + int size = atoi(str); + + char cmd[1024]; + sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size); + int ret = system(cmd); + if (ret == 0) + gtk_clist_append(GTK_CLIST(volume_list), &file); + gtk_widget_destroy(GTK_WIDGET(assoc->req)); + delete assoc; +} + +// "Add Volume" button clicked +static void cb_add_volume(...) +{ + GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE)); + gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL)); + gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); + gtk_widget_show(req); +} + +// "Create Hardfile" button clicked +static void cb_create_volume(...) +{ + GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE)); + + GtkWidget *box = gtk_hbox_new(FALSE, 4); + gtk_widget_show(box); + GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL)); + gtk_widget_show(label); + GtkWidget *entry = gtk_entry_new(); + gtk_widget_show(entry); + char str[32]; + sprintf(str, "%d", 40); + gtk_entry_set_text(GTK_ENTRY(entry), str); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0); + + gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry)); + gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); + gtk_widget_show(req); +} + +// "Remove Volume" button clicked +static void cb_remove_volume(...) +{ + gtk_clist_remove(GTK_CLIST(volume_list), selected_volume); +} + +// "Boot From" selected +static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);} +static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);} + +// "No CD-ROM Driver" button toggled +static void tb_nocdrom(GtkWidget *widget) +{ + PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active); +} + +// Read settings from widgets and set preferences +static void read_volumes_settings(void) +{ + while (PrefsFindString("disk")) + PrefsRemoveItem("disk"); + + for (int i=0; irows; i++) { + char *str; + gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str); + PrefsAddString("disk", str); + } + + PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs))); +} + +// Create "Volumes" pane +static void create_volumes_pane(GtkWidget *top) +{ + GtkWidget *box, *scroll, *menu; + + box = make_pane(top, STR_VOLUMES_PANE_TITLE); + + scroll = gtk_scrolled_window_new(NULL, NULL); + gtk_widget_show(scroll); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + volume_list = gtk_clist_new(1); + gtk_widget_show(volume_list); + gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE); + gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE); + gtk_clist_set_reorderable(GTK_CLIST(volume_list), true); + gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL); + char *str; + int32 index = 0; + while ((str = (char *)PrefsFindString("disk", index++)) != NULL) + gtk_clist_append(GTK_CLIST(volume_list), &str); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list); + gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0); + selected_volume = 0; + + static const opt_desc buttons[] = { + {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)}, + {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)}, + {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)}, + {0, NULL}, + }; + make_button_box(box, 0, buttons); + make_separator(box); + + w_extfs = make_entry(box, STR_EXTFS_CTRL, "extfs"); + + static const opt_desc options[] = { + {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)}, + {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)}, + {0, NULL} + }; + int bootdriver = PrefsFindInt32("bootdriver"), active = 0; + switch (bootdriver) { + case 0: active = 0; break; + case CDROMRefNum: active = 1; break; + } + menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active); + + make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom)); +} + + +/* + * "Graphics/Sound" pane + */ + +static GtkWidget *w_frameskip; + +// "5 Hz".."60Hz" selected +static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);} +static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);} +static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);} +static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);} +static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);} +static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);} + +// Video modes +static void tb_w640x480(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 1); + else + PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~1); +} + +static void tb_w800x600(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") | 2); + else + PrefsReplaceInt32("windowmodes", PrefsFindInt32("windowmodes") & ~2); +} + +static void tb_fs640x480(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 1); + else + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~1); +} + +static void tb_fs800x600(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 2); + else + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~2); +} + +static void tb_fs1024x768(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 4); + else + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~4); +} + +static void tb_fs1152x900(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 8); + else + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~8); +} + +static void tb_fs1280x1024(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 16); + else + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~16); +} + +static void tb_fs1600x1200(GtkWidget *widget) +{ + if (GTK_TOGGLE_BUTTON(widget)->active) + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") | 32); + else + PrefsReplaceInt32("screenmodes", PrefsFindInt32("screenmodes") & ~32); +} + +// "Disable Sound Output" button toggled +static void tb_nosound(GtkWidget *widget) +{ + PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active); +} + +// Read settings from widgets and set preferences +static void read_graphics_settings(void) +{ +} + +// Create "Graphics/Sound" pane +static void create_graphics_pane(GtkWidget *top) +{ + GtkWidget *box, *vbox, *frame; + + box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE); + + static const opt_desc options[] = { + {STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz)}, + {STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz)}, + {STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz)}, + {STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz)}, + {STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz)}, + {STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz)}, + {0, NULL} + }; + int frameskip = PrefsFindInt32("frameskip"), active = 0; + switch (frameskip) { + case 12: active = 0; break; + case 8: active = 1; break; + case 6: active = 2; break; + case 4: active = 3; break; + case 2: active = 4; break; + case 1: active = 5; break; + } + w_frameskip = make_option_menu(box, STR_FRAMESKIP_CTRL, options, active); + + frame = gtk_frame_new (GetString(STR_VIDEO_MODE_CTRL)); + gtk_widget_show(frame); + gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0); + + vbox = gtk_vbox_new(FALSE, 4); + gtk_widget_show(vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); + gtk_container_add(GTK_CONTAINER(frame), vbox); + + make_checkbox(vbox, STR_W_640x480_CTRL, PrefsFindInt32("windowmodes") & 1, GTK_SIGNAL_FUNC(tb_w640x480)); + make_checkbox(vbox, STR_W_800x600_CTRL, PrefsFindInt32("windowmodes") & 2, GTK_SIGNAL_FUNC(tb_w800x600)); + make_checkbox(vbox, STR_640x480_CTRL, PrefsFindInt32("screenmodes") & 1, GTK_SIGNAL_FUNC(tb_fs640x480)); + make_checkbox(vbox, STR_800x600_CTRL, PrefsFindInt32("screenmodes") & 2, GTK_SIGNAL_FUNC(tb_fs800x600)); + make_checkbox(vbox, STR_1024x768_CTRL, PrefsFindInt32("screenmodes") & 4, GTK_SIGNAL_FUNC(tb_fs1024x768)); + make_checkbox(vbox, STR_1152x900_CTRL, PrefsFindInt32("screenmodes") & 8, GTK_SIGNAL_FUNC(tb_fs1152x900)); + make_checkbox(vbox, STR_1280x1024_CTRL, PrefsFindInt32("screenmodes") & 16, GTK_SIGNAL_FUNC(tb_fs1280x1024)); + make_checkbox(vbox, STR_1600x1200_CTRL, PrefsFindInt32("screenmodes") & 32, GTK_SIGNAL_FUNC(tb_fs1600x1200)); + + make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound)); +} + + +/* + * "Serial/Network" pane + */ + +static GtkWidget *w_seriala, *w_serialb, *w_ether; + +// Read settings from widgets and set preferences +static void read_serial_settings(void) +{ + const char *str; + + str = gtk_entry_get_text(GTK_ENTRY(w_seriala)); + PrefsReplaceString("seriala", str); + + str = gtk_entry_get_text(GTK_ENTRY(w_serialb)); + PrefsReplaceString("serialb", str); + + str = gtk_entry_get_text(GTK_ENTRY(w_ether)); + if (str && strlen(str)) + PrefsReplaceString("ether", str); + else + PrefsRemoveItem("ether"); +} + +// Add names of serial devices +static gint gl_str_cmp(gconstpointer a, gconstpointer b) +{ + return strcmp((char *)a, (char *)b); +} + +static GList *add_serial_names(void) +{ + GList *glist = NULL; + + // Search /dev for ttyS* and lp* + DIR *d = opendir("/dev"); + if (d) { + struct dirent *de; + while ((de = readdir(d)) != NULL) { + if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) { + char *str = new char[64]; + sprintf(str, "/dev/%s", de->d_name); + glist = g_list_append(glist, str); + } + } + closedir(d); + } + if (glist) + g_list_sort(glist, gl_str_cmp); + else + glist = g_list_append(glist, (void *)""); + return glist; +} + +// Add names of ethernet interfaces +static GList *add_ether_names(void) +{ + GList *glist = NULL; + + // Get list of all Ethernet interfaces + int s = socket(PF_INET, SOCK_DGRAM, 0); + if (s >= 0) { + char inbuf[8192]; + struct ifconf ifc; + ifc.ifc_len = sizeof(inbuf); + ifc.ifc_buf = inbuf; + if (ioctl(s, SIOCGIFCONF, &ifc) == 0) { + struct ifreq req, *ifr = ifc.ifc_req; + for (int i=0; iifr_name, 63); + glist = g_list_append(glist, str); + } + } + } + close(s); + } + if (glist) + g_list_sort(glist, gl_str_cmp); + else + glist = g_list_append(glist, (void *)""); + return glist; +} + +// Create "Serial/Network" pane +static void create_serial_pane(GtkWidget *top) +{ + GtkWidget *box, *table, *label, *combo; + GList *glist = add_serial_names(); + + box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE); + table = make_table(box, 2, 3); + + label = gtk_label_new(GetString(STR_SERPORTA_CTRL)); + gtk_widget_show(label); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); + + combo = gtk_combo_new(); + gtk_widget_show(combo); + gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); + const char *str = PrefsFindString("seriala"); + if (str == NULL) + str = ""; + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); + w_seriala = GTK_COMBO(combo)->entry; + + label = gtk_label_new(GetString(STR_SERPORTB_CTRL)); + gtk_widget_show(label); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); + + combo = gtk_combo_new(); + gtk_widget_show(combo); + gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); + str = PrefsFindString("serialb"); + if (str == NULL) + str = ""; + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); + w_serialb = GTK_COMBO(combo)->entry; + + label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL)); + gtk_widget_show(label); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); + + glist = add_ether_names(); + combo = gtk_combo_new(); + gtk_widget_show(combo); + gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); + str = PrefsFindString("ether"); + if (str == NULL) + str = ""; + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); + gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); + w_ether = GTK_COMBO(combo)->entry; +} + + +/* + * "Memory/Misc" pane + */ + +static GtkObject *w_ramsize_adj; +static GtkWidget *w_rom_file; + +// "Ignore SEGV" button toggled +static void tb_ignoresegv(GtkWidget *widget) +{ + PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active); +} + +// Read settings from widgets and set preferences +static void read_memory_settings(void) +{ + PrefsReplaceInt32("ramsize", int(GTK_ADJUSTMENT(w_ramsize_adj)->value) << 20); + + const char *str = gtk_entry_get_text(GTK_ENTRY(w_rom_file)); + if (str && strlen(str)) + PrefsReplaceString("rom", str); + else + PrefsRemoveItem("rom"); +} + +// Create "Memory/Misc" pane +static void create_memory_pane(GtkWidget *top) +{ + GtkWidget *box, *vbox, *hbox, *hbox2, *label, *scale; + + box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE); + + hbox = gtk_hbox_new(FALSE, 4); + gtk_widget_show(hbox); + + label = gtk_label_new(GetString(STR_RAMSIZE_SLIDER)); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + vbox = gtk_vbox_new(FALSE, 4); + gtk_widget_show(vbox); + + gfloat min, max; + min = 1; + max = 256; + w_ramsize_adj = gtk_adjustment_new(min, min, max, 1, 16, 0); + gtk_adjustment_set_value(GTK_ADJUSTMENT(w_ramsize_adj), PrefsFindInt32("ramsize") >> 20); + + scale = gtk_hscale_new(GTK_ADJUSTMENT(w_ramsize_adj)); + gtk_widget_show(scale); + gtk_scale_set_digits(GTK_SCALE(scale), 0); + gtk_box_pack_start(GTK_BOX(vbox), scale, TRUE, TRUE, 0); + + hbox2 = gtk_hbox_new(FALSE, 4); + gtk_widget_show(hbox2); + + char val[32]; + sprintf(val, GetString(STR_RAMSIZE_FMT), int(min)); + label = gtk_label_new(val); + gtk_widget_show(label); + gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0); + + sprintf(val, GetString(STR_RAMSIZE_FMT), int(max)); + label = gtk_label_new(val); + gtk_widget_show(label); + gtk_box_pack_end(GTK_BOX(hbox2), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox2, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); + + w_rom_file = make_entry(box, STR_ROM_FILE_CTRL, "rom"); + + make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv)); +} + + +/* + * Read settings from widgets and set preferences + */ + +static void read_settings(void) +{ + read_volumes_settings(); + read_graphics_settings(); + read_serial_settings(); + read_memory_settings(); +} diff --git a/SheepShaver/src/Unix/prefs_unix.cpp b/SheepShaver/src/Unix/prefs_unix.cpp new file mode 100644 index 00000000..aad13296 --- /dev/null +++ b/SheepShaver/src/Unix/prefs_unix.cpp @@ -0,0 +1,97 @@ +/* + * prefs_unix.cpp - Preferences handling, Unix specific things + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" + +#include +#include +#include + +#include "prefs.h" + + +// Platform-specific preferences items +prefs_desc platform_prefs_items[] = { + {"ether", TYPE_STRING, false, "device name of Mac ethernet adapter"}, + {NULL, TYPE_END, false, NULL} // End of list +}; + + +// Prefs file name and path +const char PREFS_FILE_NAME[] = ".sheepshaver_prefs"; +static char prefs_path[1024]; + + +/* + * Load preferences from settings file + */ + +void LoadPrefs(void) +{ + // Construct prefs path + prefs_path[0] = 0; + char *home = getenv("HOME"); + if (home != NULL && strlen(home) < 1000) { + strncpy(prefs_path, home, 1000); + strcat(prefs_path, "/"); + } + strcat(prefs_path, PREFS_FILE_NAME); + + // Read preferences from settings file + FILE *f = fopen(prefs_path, "r"); + if (f != NULL) { + + // Prefs file found, load settings + LoadPrefsFromStream(f); + fclose(f); + + } else { + + // No prefs file, save defaults + SavePrefs(); + } +} + + +/* + * Save preferences to settings file + */ + +void SavePrefs(void) +{ + FILE *f; + if ((f = fopen(prefs_path, "w")) != NULL) { + SavePrefsToStream(f); + fclose(f); + } +} + + +/* + * Add defaults of platform-specific prefs items + * You may also override the defaults set in PrefsInit() + */ + +void AddPlatformPrefsDefaults(void) +{ + PrefsReplaceString("extfs", "/"); + PrefsAddInt32("windowmodes", 3); + PrefsAddInt32("screenmodes", 0x3f); +} diff --git a/SheepShaver/src/Unix/sysdeps.h b/SheepShaver/src/Unix/sysdeps.h new file mode 100644 index 00000000..12c2fae8 --- /dev/null +++ b/SheepShaver/src/Unix/sysdeps.h @@ -0,0 +1,136 @@ +/* + * sysdeps.h - System dependent definitions for Linux + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 SYSDEPS_H +#define SYSDEPS_H + +#ifndef __STDC__ +#error "Your compiler is not ANSI. Get a real one." +#endif + +#include "config.h" +#include "user_strings_unix.h" + +#ifndef STDC_HEADERS +#error "You don't have ANSI C header files." +#endif + +#ifdef HAVE_UNISTD_H +# include +# include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +// Are we using a PPC emulator or the real thing? +#ifdef __powerpc__ +#define EMULATED_PPC 0 +#else +#define EMULATED_PPC 1 +#endif + +#define POWERPC_ROM 1 + +// Data types +typedef unsigned char uint8; +typedef signed char int8; +#if SIZEOF_SHORT == 2 +typedef unsigned short uint16; +typedef short int16; +#elif SIZEOF_INT == 2 +typedef unsigned int uint16; +typedef int int16; +#else +#error "No 2 byte type, you lose." +#endif +#if SIZEOF_INT == 4 +typedef unsigned int uint32; +typedef int int32; +#elif SIZEOF_LONG == 4 +typedef unsigned long uint32; +typedef long int32; +#else +#error "No 4 byte type, you lose." +#endif +#if SIZEOF_LONG == 8 +typedef unsigned long uint64; +typedef long int64; +#elif SIZEOF_LONG_LONG == 8 +typedef unsigned long long uint64; +typedef long long int64; +#else +#error "No 8 byte type, you lose." +#endif + +// Time data type for Time Manager emulation +#ifdef HAVE_CLOCK_GETTIME +typedef struct timespec tm_time_t; +#else +typedef struct timeval tm_time_t; +#endif + +// Various definitions +typedef struct rgb_color { + uint8 red; + uint8 green; + uint8 blue; + uint8 alpha; +} rgb_color; + +// Macro for calling MacOS routines +#define CallMacOS(type, tvect) call_macos((uint32)tvect) +#define CallMacOS1(type, tvect, arg1) call_macos1((uint32)tvect, (uint32)arg1) +#define CallMacOS2(type, tvect, arg1, arg2) call_macos2((uint32)tvect, (uint32)arg1, (uint32)arg2) +#define CallMacOS3(type, tvect, arg1, arg2, arg3) call_macos3((uint32)tvect, (uint32)arg1, (uint32)arg2, (uint32)arg3) +#define CallMacOS4(type, tvect, arg1, arg2, arg3, arg4) call_macos4((uint32)tvect, (uint32)arg1, (uint32)arg2, (uint32)arg3, (uint32)arg4) +#define CallMacOS5(type, tvect, arg1, arg2, arg3, arg4, arg5) call_macos5((uint32)tvect, (uint32)arg1, (uint32)arg2, (uint32)arg3, (uint32)arg4, (uint32)arg5) +#define CallMacOS6(type, tvect, arg1, arg2, arg3, arg4, arg5, arg6) call_macos6((uint32)tvect, (uint32)arg1, (uint32)arg2, (uint32)arg3, (uint32)arg4, (uint32)arg5, (uint32)arg6) +#define CallMacOS7(type, tvect, arg1, arg2, arg3, arg4, arg5, arg6, arg7) call_macos7((uint32)tvect, (uint32)arg1, (uint32)arg2, (uint32)arg3, (uint32)arg4, (uint32)arg5, (uint32)arg6, (uint32)arg7) + +extern "C" uint32 call_macos(uint32 tvect); +extern "C" uint32 call_macos1(uint32 tvect, uint32 arg1); +extern "C" uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2); +extern "C" uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3); +extern "C" uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4); +extern "C" uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5); +extern "C" uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6); +extern "C" uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7); + +#endif diff --git a/SheepShaver/src/Unix/user_strings_unix.cpp b/SheepShaver/src/Unix/user_strings_unix.cpp new file mode 100644 index 00000000..b6011d2f --- /dev/null +++ b/SheepShaver/src/Unix/user_strings_unix.cpp @@ -0,0 +1,92 @@ +/* + * user_strings_unix.cpp - Localizable strings, Unix specific strings + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include "user_strings.h" + + +// Platform-specific string definitions +user_string_def platform_strings[] = { + // Common strings that have a platform-specific variant + {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under Linux. Basilisk II will try to unmount it."}, + {STR_EXTFS_CTRL, "Linux Root"}, + {STR_EXTFS_NAME, "Linux Directory Tree"}, + {STR_EXTFS_VOLUME_NAME, "Linux"}, + + // Purely platform-specific strings + {STR_NO_DEV_ZERO_ERR, "Cannot open /dev/zero: %s."}, + {STR_LOW_MEM_MMAP_ERR, "Cannot map Low Memory Globals: %s."}, + {STR_KD_SHMGET_ERR, "Cannot create SHM segment for Kernel Data: %s."}, + {STR_KD_SHMAT_ERR, "Cannot map first Kernel Data area: %s."}, + {STR_KD2_SHMAT_ERR, "Cannot map second Kernel Data area: %s."}, + {STR_ROM_MMAP_ERR, "Cannot map ROM: %s."}, + {STR_RAM_MMAP_ERR, "Cannot map RAM: %s."}, + {STR_SIGALTSTACK_ERR, "Cannot install alternate signal stack (%s). It seems that you need a newer kernel."}, + {STR_SIGSEGV_INSTALL_ERR, "Cannot install SIGSEGV handler: %s."}, + {STR_SIGILL_INSTALL_ERR, "Cannot install SIGILL handler: %s."}, + {STR_SIGUSR2_INSTALL_ERR, "Cannot install SIGUSR2 handler (%s). It seems that you need a newer libc."}, + {STR_NO_XSERVER_ERR, "Cannot connect to X server %s."}, + {STR_NO_XVISUAL_ERR, "Cannot obtain appropriate X visual."}, + {STR_UNSUPP_DEPTH_ERR, "Unsupported color depth of screen."}, + {STR_PROC_CPUINFO_WARN, "Cannot open /proc/cpuinfo (%s). Assuming 100MHz PowerPC 604."}, + {STR_NO_SHEEP_NET_DRIVER_WARN, "Cannot open %s (%s). Ethernet will not be available."}, + {STR_SHEEP_NET_ATTACH_WARN, "Cannot attach to Ethernet card (%s). Ethernet will not be available."}, + {STR_NO_AUDIO_DEV_WARN, "Cannot open %s (%s). Audio output will be disabled."}, + {STR_NO_AUDIO_WARN, "No audio device found, audio output will be disabled."}, + {STR_NO_ESD_WARN, "Cannot open ESD connection. Audio output will be disabled."}, + {STR_AUDIO_FORMAT_WARN, "/dev/dsp doesn't support signed 16 bit format. Audio output will be disabled."}, + {STR_SCSI_DEVICE_OPEN_WARN, "Cannot open %s (%s). SCSI Manager access to this device will be disabled."}, + {STR_SCSI_DEVICE_NOT_SCSI_WARN, "%s doesn't seem to comply to the Generic SCSI API. SCSI Manager access to this device will be disabled."}, + {STR_PREFS_MENU_FILE_GTK, "/_File"}, + {STR_PREFS_ITEM_START_GTK, "/File/_Start SheepShaver"}, + {STR_PREFS_ITEM_ZAP_PRAM_GTK, "/File/_Zap PRAM File"}, + {STR_PREFS_ITEM_SEPL_GTK, "/File/sepl"}, + {STR_PREFS_ITEM_QUIT_GTK, "/File/_Quit SheepShaver"}, + {STR_HELP_MENU_GTK, "/_Help"}, + {STR_HELP_ITEM_ABOUT_GTK, "/Help/_About SheepShaver"}, + {STR_SUSPEND_WINDOW_TITLE, "SheepShaver suspended. Press Space to reactivate."}, + + {-1, NULL} // End marker +}; + + +/* + * Fetch pointer to string, given the string number + */ + +const char *GetString(int num) +{ + // First search for platform-specific string + int i = 0; + while (platform_strings[i].num >= 0) { + if (platform_strings[i].num == num) + return platform_strings[i].str; + i++; + } + + // Not found, search for common string + i = 0; + while (common_strings[i].num >= 0) { + if (common_strings[i].num == num) + return common_strings[i].str; + i++; + } + return NULL; +} diff --git a/SheepShaver/src/Unix/user_strings_unix.h b/SheepShaver/src/Unix/user_strings_unix.h new file mode 100644 index 00000000..73196a18 --- /dev/null +++ b/SheepShaver/src/Unix/user_strings_unix.h @@ -0,0 +1,58 @@ +/* + * user_strings_unix.h - Unix-specific localizable strings + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 USER_STRINGS_LINUX_H +#define USER_STRINGS_LINUX_H + +enum { + STR_NO_DEV_ZERO_ERR = 10000, + STR_LOW_MEM_MMAP_ERR, + STR_KD_SHMGET_ERR, + STR_KD_SHMAT_ERR, + STR_KD2_SHMAT_ERR, + STR_ROM_MMAP_ERR, + STR_RAM_MMAP_ERR, + STR_SIGALTSTACK_ERR, + STR_SIGSEGV_INSTALL_ERR, + STR_SIGILL_INSTALL_ERR, + STR_SIGUSR2_INSTALL_ERR, + STR_NO_XSERVER_ERR, + STR_NO_XVISUAL_ERR, + STR_UNSUPP_DEPTH_ERR, + STR_PROC_CPUINFO_WARN, + STR_NO_SHEEP_NET_DRIVER_WARN, + STR_SHEEP_NET_ATTACH_WARN, + STR_NO_AUDIO_DEV_WARN, + STR_NO_AUDIO_WARN, + STR_NO_ESD_WARN, + STR_AUDIO_FORMAT_WARN, + STR_SCSI_DEVICE_OPEN_WARN, + STR_SCSI_DEVICE_NOT_SCSI_WARN, + STR_PREFS_MENU_FILE_GTK, + STR_PREFS_ITEM_START_GTK, + STR_PREFS_ITEM_ZAP_PRAM_GTK, + STR_PREFS_ITEM_SEPL_GTK, + STR_PREFS_ITEM_QUIT_GTK, + STR_HELP_MENU_GTK, + STR_HELP_ITEM_ABOUT_GTK, + STR_SUSPEND_WINDOW_TITLE +}; + +#endif diff --git a/SheepShaver/src/Unix/video_x.cpp b/SheepShaver/src/Unix/video_x.cpp new file mode 100644 index 00000000..a69e306b --- /dev/null +++ b/SheepShaver/src/Unix/video_x.cpp @@ -0,0 +1,1419 @@ +/* + * video_x.cpp - Video/graphics emulation, X11 specific stuff + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "main.h" +#include "adb.h" +#include "prefs.h" +#include "user_strings.h" +#include "about_window.h" +#include "video.h" +#include "video_defs.h" + +#define DEBUG 0 +#include "debug.h" + +#ifdef ENABLE_XF86_DGA +#include +#endif + +#ifdef ENABLE_XF86_VIDMODE +#include +#endif + + +// Global variables +static int32 frame_skip; +static bool redraw_thread_active = false; // Flag: Redraw thread installed +static pthread_t redraw_thread; // Redraw thread + +static volatile bool thread_stop_req = false; +static volatile bool thread_stop_ack = false; // Acknowledge for thread_stop_req + +static bool has_dga = false; // Flag: Video DGA capable +static bool has_vidmode = false; // Flag: VidMode extension available + +static bool palette_changed = false; // Flag: Palette changed, redraw thread must update palette +static bool ctrl_down = false; // Flag: Ctrl key pressed +static bool quit_full_screen = false; // Flag: DGA close requested from redraw thread +static volatile bool quit_full_screen_ack = false; // Acknowledge for quit_full_screen +static bool emerg_quit = false; // Flag: Ctrl-Esc pressed, emergency quit requested from MacOS thread + +static bool emul_suspended = false; // Flag: emulator suspended +static Window suspend_win; // "Suspend" window +static void *fb_save = NULL; // Saved frame buffer for suspend + +// X11 variables +static int screen; // Screen number +static int xdepth; // Depth of X screen +static int depth; // Depth of Mac frame buffer +static Window rootwin, the_win; // Root window and our window +static XVisualInfo visualInfo; +static Visual *vis; +static Colormap cmap[2]; // Two colormaps (DGA) for 8-bit mode +static XColor black, white; +static unsigned long black_pixel, white_pixel; +static int eventmask; +static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask; +static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask; + +// Variables for window mode +static GC the_gc; +static XImage *img = NULL; +static XShmSegmentInfo shminfo; +static XImage *cursor_image, *cursor_mask_image; +static Pixmap cursor_map, cursor_mask_map; +static Cursor mac_cursor; +static GC cursor_gc, cursor_mask_gc; +static bool cursor_changed = false; // Flag: Cursor changed, window_func must update cursor +static bool have_shm = false; // Flag: SHM present and usable +static uint8 *the_buffer; // Pointer to Mac frame buffer +static uint8 *the_buffer_copy = NULL; // Copy of Mac frame buffer + +// Variables for DGA mode +static char *dga_screen_base; +static int dga_fb_width; +static int current_dga_cmap; + +#ifdef ENABLE_XF86_VIDMODE +// Variables for XF86 VidMode support +static XF86VidModeModeInfo **x_video_modes; // Array of all available modes +static int num_x_video_modes; +#endif + + +// Prototypes +static void *redraw_func(void *arg); + + +// From main_linux.cpp +extern Display *x_display; + +// From sys_unix.cpp +extern void SysMountFirstFloppy(void); + + +/* + * Open display (window or fullscreen) + */ + +// Trap SHM errors +static bool shm_error = false; +static int (*old_error_handler)(Display *, XErrorEvent *); + +static int error_handler(Display *d, XErrorEvent *e) +{ + if (e->error_code == BadAccess) { + shm_error = true; + return 0; + } else + return old_error_handler(d, e); +} + +// Open window +static bool open_window(int width, int height) +{ + // Set absolute mouse mode + ADBSetRelMouseMode(false); + + // Read frame skip prefs + frame_skip = PrefsFindInt32("frameskip"); + if (frame_skip == 0) + frame_skip = 1; + + // Create window + XSetWindowAttributes wattr; + wattr.event_mask = eventmask = win_eventmask; + wattr.background_pixel = black_pixel; + wattr.border_pixel = black_pixel; + wattr.backing_store = NotUseful; + + XSync(x_display, false); + the_win = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, + InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWBackingStore, &wattr); + XSync(x_display, false); + XStoreName(x_display, the_win, GetString(STR_WINDOW_TITLE)); + XMapRaised(x_display, the_win); + XSync(x_display, false); + + // Set colormap + if (depth == 8) { + XSetWindowColormap(x_display, the_win, cmap[0]); + XSetWMColormapWindows(x_display, the_win, &the_win, 1); + } + + // Make window unresizable + XSizeHints *hints; + if ((hints = XAllocSizeHints()) != NULL) { + hints->min_width = width; + hints->max_width = width; + hints->min_height = height; + hints->max_height = height; + hints->flags = PMinSize | PMaxSize; + XSetWMNormalHints(x_display, the_win, hints); + XFree((char *)hints); + } + + // Try to create and attach SHM image + have_shm = false; + if (depth != 1 && XShmQueryExtension(x_display)) { + + // Create SHM image ("height + 2" for safety) + img = XShmCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, &shminfo, width, height); + shminfo.shmid = shmget(IPC_PRIVATE, (height + 2) * img->bytes_per_line, IPC_CREAT | 0777); + screen_base = (uint32)shmat(shminfo.shmid, 0, 0); + the_buffer = (uint8 *)screen_base; + shminfo.shmaddr = img->data = (char *)screen_base; + shminfo.readOnly = False; + + // Try to attach SHM image, catching errors + shm_error = false; + old_error_handler = XSetErrorHandler(error_handler); + XShmAttach(x_display, &shminfo); + XSync(x_display, false); + XSetErrorHandler(old_error_handler); + if (shm_error) { + shmdt(shminfo.shmaddr); + XDestroyImage(img); + shminfo.shmid = -1; + } else { + have_shm = true; + shmctl(shminfo.shmid, IPC_RMID, 0); + } + } + + // Create normal X image if SHM doesn't work ("height + 2" for safety) + if (!have_shm) { + int bytes_per_row = width; + switch (depth) { + case 1: + bytes_per_row /= 8; + break; + case 15: + case 16: + bytes_per_row *= 2; + break; + case 24: + case 32: + bytes_per_row *= 4; + break; + } + screen_base = (uint32)malloc((height + 2) * bytes_per_row); + the_buffer = (uint8 *)screen_base; + img = XCreateImage(x_display, vis, depth, depth == 1 ? XYBitmap : ZPixmap, 0, (char *)screen_base, width, height, 32, bytes_per_row); + } + + // 1-Bit mode is big-endian + if (depth == 1) { + img->byte_order = MSBFirst; + img->bitmap_bit_order = MSBFirst; + } + + // Allocate memory for frame buffer copy + the_buffer_copy = (uint8 *)malloc((height + 2) * img->bytes_per_line); + + // Create GC + the_gc = XCreateGC(x_display, the_win, 0, 0); + XSetForeground(x_display, the_gc, black_pixel); + + // Create cursor + cursor_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 4, 16, 16, 16, 2); + cursor_image->byte_order = MSBFirst; + cursor_image->bitmap_bit_order = MSBFirst; + cursor_mask_image = XCreateImage(x_display, vis, 1, XYPixmap, 0, (char *)MacCursor + 36, 16, 16, 16, 2); + cursor_mask_image->byte_order = MSBFirst; + cursor_mask_image->bitmap_bit_order = MSBFirst; + cursor_map = XCreatePixmap(x_display, the_win, 16, 16, 1); + cursor_mask_map = XCreatePixmap(x_display, the_win, 16, 16, 1); + cursor_gc = XCreateGC(x_display, cursor_map, 0, 0); + cursor_mask_gc = XCreateGC(x_display, cursor_mask_map, 0, 0); + mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, 0, 0); + cursor_changed = false; + + // Set bytes per row + VModes[cur_mode].viRowBytes = img->bytes_per_line; + XSync(x_display, false); + return true; +} + +// Open DGA display (!! should use X11 VidMode extensions to set mode) +static bool open_dga(int width, int height) +{ +#ifdef ENABLE_XF86_DGA + // Set relative mouse mode + ADBSetRelMouseMode(true); + +#ifdef ENABLE_XF86_VIDMODE + // Switch to best mode + if (has_vidmode) { + int best = 0; + for (int i=1; ihdisplay >= width && x_video_modes[i]->vdisplay >= height && + x_video_modes[i]->hdisplay <= x_video_modes[best]->hdisplay && x_video_modes[i]->vdisplay <= x_video_modes[best]->vdisplay) { + best = i; + } + } + XF86VidModeSwitchToMode(x_display, screen, x_video_modes[best]); + XF86VidModeSetViewPort(x_display, screen, 0, 0); + } +#endif + + // Establish direct screen connection + XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); + XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse); + XF86DGASetViewPort(x_display, screen, 0, 0); + XF86DGASetVidPage(x_display, screen, 0); + screen_base = (uint32)dga_screen_base; + + // Set colormap + if (depth == 8) + XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); + + // Set bytes per row + int bytes_per_row = (dga_fb_width + 7) & ~7; + switch (depth) { + case 15: + case 16: + bytes_per_row *= 2; + break; + case 24: + case 32: + bytes_per_row *= 4; + break; + } + VModes[cur_mode].viRowBytes = bytes_per_row; + XSync(x_display, false); + return true; +#else + ErrorAlert("SheepShaver has been compiled with DGA support disabled."); + return false; +#endif +} + +static bool open_display(void) +{ + display_type = VModes[cur_mode].viType; + switch (VModes[cur_mode].viAppleMode) { + case APPLE_1_BIT: + depth = 1; + break; + case APPLE_2_BIT: + depth = 2; + break; + case APPLE_4_BIT: + depth = 4; + break; + case APPLE_8_BIT: + depth = 8; + break; + case APPLE_16_BIT: + depth = 16; + break; + case APPLE_32_BIT: + depth = 32; + break; + } + if (display_type == DIS_SCREEN) + return open_dga(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize); + else if (display_type == DIS_WINDOW) + return open_window(VModes[cur_mode].viXsize, VModes[cur_mode].viYsize); + else + return false; +} + + +/* + * Close display + */ + +// Close window +static void close_window(void) +{ + // Close window + XDestroyWindow(x_display, the_win); + + // Close frame buffer copy + if (the_buffer_copy) { + free(the_buffer_copy); + the_buffer_copy = NULL; + } +} + +// Close DGA mode +static void close_dga(void) +{ +#ifdef ENABLE_XF86_DGA + XF86DGADirectVideo(x_display, screen, 0); + XUngrabPointer(x_display, CurrentTime); + XUngrabKeyboard(x_display, CurrentTime); +#endif + +#ifdef ENABLE_XF86_VIDMODE + if (has_vidmode) + XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]); +#endif +} + +static void close_display(void) +{ + if (display_type == DIS_SCREEN) + close_dga(); + else if (display_type == DIS_WINDOW) + close_window(); +} + + +/* + * Initialization + */ + +static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type) +{ + if (allow & test) { + p->viType = type; + switch (apple_id) { + case APPLE_W_640x480: + case APPLE_640x480: + p->viXsize = 640; + p->viYsize = 480; + break; + case APPLE_W_800x600: + case APPLE_800x600: + p->viXsize = 800; + p->viYsize = 600; + break; + case APPLE_1024x768: + p->viXsize = 1024; + p->viYsize = 768; + break; + case APPLE_1152x900: + p->viXsize = 1152; + p->viYsize = 900; + break; + case APPLE_1280x1024: + p->viXsize = 1280; + p->viYsize = 1024; + break; + case APPLE_1600x1200: + p->viXsize = 1600; + p->viYsize = 1200; + break; + } + switch (apple_mode) { + case APPLE_8_BIT: + p->viRowBytes = p->viXsize; + break; + case APPLE_16_BIT: + p->viRowBytes = p->viXsize * 2; + break; + case APPLE_32_BIT: + p->viRowBytes = p->viXsize * 4; + break; + } + p->viAppleMode = apple_mode; + p->viAppleID = apple_id; + p++; + } +} + +static bool has_mode(int x, int y) +{ +#ifdef ENABLE_XF86_VIDMODE + for (int i=0; ihdisplay >= x && x_video_modes[i]->vdisplay >= y) + return true; + return false; +#else + return DisplayWidth(x_display, screen) >= x && DisplayHeight(x_display, screen) >= y; +#endif +} + +bool VideoInit(void) +{ + // Init variables + private_data = NULL; + cur_mode = 0; // Window 640x480 + video_activated = true; + + // Find screen and root window + screen = XDefaultScreen(x_display); + rootwin = XRootWindow(x_display, screen); + + // Get screen depth + xdepth = DefaultDepth(x_display, screen); + +#ifdef ENABLE_XF86_DGA + // DGA available? + int event_base, error_base; + if (XF86DGAQueryExtension(x_display, &event_base, &error_base)) { + int dga_flags = 0; + XF86DGAQueryDirectVideo(x_display, screen, &dga_flags); + has_dga = dga_flags & XF86DGADirectPresent; + } else + has_dga = false; +#endif + +#ifdef ENABLE_XF86_VIDMODE + // VidMode available? + int vm_event_base, vm_error_base; + has_vidmode = XF86VidModeQueryExtension(x_display, &vm_event_base, &vm_error_base); + if (has_vidmode) + XF86VidModeGetAllModeLines(x_display, screen, &num_x_video_modes, &x_video_modes); +#endif + + // Find black and white colors + XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:00/00/00", &black); + XAllocColor(x_display, DefaultColormap(x_display, screen), &black); + XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:ff/ff/ff", &white); + XAllocColor(x_display, DefaultColormap(x_display, screen), &white); + black_pixel = BlackPixel(x_display, screen); + white_pixel = WhitePixel(x_display, screen); + + // Get appropriate visual + int color_class; + switch (xdepth) { +#if 0 + case 1: + color_class = StaticGray; + break; +#endif + case 8: + color_class = PseudoColor; + break; + case 15: + case 16: + case 24: + case 32: + color_class = TrueColor; + break; + default: + ErrorAlert(GetString(STR_UNSUPP_DEPTH_ERR)); + return false; + } + if (!XMatchVisualInfo(x_display, screen, xdepth, color_class, &visualInfo)) { + ErrorAlert(GetString(STR_NO_XVISUAL_ERR)); + return false; + } + if (visualInfo.depth != xdepth) { + ErrorAlert(GetString(STR_NO_XVISUAL_ERR)); + return false; + } + vis = visualInfo.visual; + + // Mac screen depth follows X depth (for now) + depth = xdepth; + + // Create color maps for 8 bit mode + if (depth == 8) { + cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); + cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); + XInstallColormap(x_display, cmap[0]); + XInstallColormap(x_display, cmap[1]); + } + + // Construct video mode table + int mode = APPLE_8_BIT; + int bpr_mult = 8; + switch (depth) { + case 1: + mode = APPLE_1_BIT; + bpr_mult = 1; + break; + case 8: + mode = APPLE_8_BIT; + bpr_mult = 8; + break; + case 15: + case 16: + mode = APPLE_16_BIT; + bpr_mult = 16; + break; + case 24: + case 32: + mode = APPLE_32_BIT; + bpr_mult = 32; + break; + } + + uint32 window_modes = PrefsFindInt32("windowmodes"); + uint32 screen_modes = PrefsFindInt32("screenmodes"); + if (!has_dga) + screen_modes = 0; + if (window_modes == 0 && screen_modes == 0) + window_modes |= 3; // Allow at least 640x480 and 800x600 window modes + + VideoInfo *p = VModes; + add_mode(p, window_modes, 1, mode, APPLE_W_640x480, DIS_WINDOW); + add_mode(p, window_modes, 2, mode, APPLE_W_800x600, DIS_WINDOW); + if (has_vidmode) { + if (has_mode(640, 480)) + add_mode(p, screen_modes, 1, mode, APPLE_640x480, DIS_SCREEN); + if (has_mode(800, 600)) + add_mode(p, screen_modes, 2, mode, APPLE_800x600, DIS_SCREEN); + if (has_mode(1024, 768)) + add_mode(p, screen_modes, 4, mode, APPLE_1024x768, DIS_SCREEN); + if (has_mode(1152, 900)) + add_mode(p, screen_modes, 8, mode, APPLE_1152x900, DIS_SCREEN); + if (has_mode(1280, 1024)) + add_mode(p, screen_modes, 16, mode, APPLE_1280x1024, DIS_SCREEN); + if (has_mode(1600, 1200)) + add_mode(p, screen_modes, 32, mode, APPLE_1600x1200, DIS_SCREEN); + } else if (screen_modes) { + int xsize = DisplayWidth(x_display, screen); + int ysize = DisplayHeight(x_display, screen); + int apple_id; + if (xsize < 800) + apple_id = APPLE_640x480; + else if (xsize < 1024) + apple_id = APPLE_800x600; + else if (xsize < 1152) + apple_id = APPLE_1024x768; + else if (xsize < 1280) + apple_id = APPLE_1152x900; + else if (xsize < 1600) + apple_id = APPLE_1280x1024; + else + apple_id = APPLE_1600x1200; + p->viType = DIS_SCREEN; + p->viRowBytes = 0; + p->viXsize = xsize; + p->viYsize = ysize; + p->viAppleMode = mode; + p->viAppleID = apple_id; + p++; + } + p->viType = DIS_INVALID; // End marker + p->viRowBytes = 0; + p->viXsize = p->viYsize = 0; + p->viAppleMode = 0; + p->viAppleID = 0; + +#ifdef ENABLE_XF86_DGA + if (has_dga && screen_modes) { + int v_bank, v_size; + XF86DGAGetVideo(x_display, screen, &dga_screen_base, &dga_fb_width, &v_bank, &v_size); + D(bug("DGA screen_base %p, v_width %d\n", dga_screen_base, dga_fb_width)); + } +#endif + + // Open window/screen + if (!open_display()) + return false; + +#if 0 + // Ignore errors from now on + XSetErrorHandler(ignore_errors); +#endif + + // Start periodic thread + XSync(x_display, false); + redraw_thread_active = (pthread_create(&redraw_thread, NULL, redraw_func, NULL) == 0); + D(bug("Redraw thread installed (%ld)\n", redraw_thread)); + return true; +} + + +/* + * Deinitialization + */ + +void VideoExit(void) +{ + // Stop redraw thread + if (redraw_thread_active) { + pthread_cancel(redraw_thread); + pthread_join(redraw_thread, NULL); + redraw_thread_active = false; + } + + // Close window and server connection + if (x_display != NULL) { + XSync(x_display, false); + close_display(); + XFlush(x_display); + XSync(x_display, false); + if (depth == 8) { + XFreeColormap(x_display, cmap[0]); + XFreeColormap(x_display, cmap[1]); + } + } +} + + +/* + * Suspend/resume emulator + */ + +extern void PauseEmulator(void); +extern void ResumeEmulator(void); + +static void suspend_emul(void) +{ + if (display_type == DIS_SCREEN) { + // Release ctrl key + ADBKeyUp(0x36); + ctrl_down = false; + + // Pause MacOS thread + PauseEmulator(); + emul_suspended = true; + + // Save frame buffer + fb_save = malloc(VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); + if (fb_save) + memcpy(fb_save, (void *)screen_base, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); + + // Close full screen display +#ifdef ENABLE_XF86_DGA + XF86DGADirectVideo(x_display, screen, 0); + XUngrabPointer(x_display, CurrentTime); + XUngrabKeyboard(x_display, CurrentTime); +#endif + XSync(x_display, false); + + // Open "suspend" window + XSetWindowAttributes wattr; + wattr.event_mask = KeyPressMask; + wattr.background_pixel = black_pixel; + wattr.border_pixel = black_pixel; + wattr.backing_store = Always; + wattr.backing_planes = xdepth; + wattr.colormap = DefaultColormap(x_display, screen); + XSync(x_display, false); + suspend_win = XCreateWindow(x_display, rootwin, 0, 0, 512, 1, 0, xdepth, + InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | + CWBackingStore | CWBackingPlanes | (xdepth == 8 ? CWColormap : 0), &wattr); + XSync(x_display, false); + XStoreName(x_display, suspend_win, GetString(STR_SUSPEND_WINDOW_TITLE)); + XMapRaised(x_display, suspend_win); + XSync(x_display, false); + } +} + +static void resume_emul(void) +{ + // Close "suspend" window + XDestroyWindow(x_display, suspend_win); + XSync(x_display, false); + + // Reopen full screen display + XGrabKeyboard(x_display, rootwin, 1, GrabModeAsync, GrabModeAsync, CurrentTime); + XGrabPointer(x_display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse); + XF86DGASetViewPort(x_display, screen, 0, 0); + XSync(x_display, false); + + // Restore frame buffer + if (fb_save) { + memcpy((void *)screen_base, fb_save, VModes[cur_mode].viYsize * VModes[cur_mode].viRowBytes); + free(fb_save); + fb_save = NULL; + } + if (depth == 8) + palette_changed = true; + + // Resume MacOS thread + emul_suspended = false; + ResumeEmulator(); +} + + +/* + * Close screen in full-screen mode + */ + +void VideoQuitFullScreen(void) +{ + D(bug("VideoQuitFullScreen()\n")); + if (display_type == DIS_SCREEN) { + quit_full_screen = true; + while (!quit_full_screen_ack) ; + } +} + + +/* + * X11 event handling + */ + +// Translate key event to Mac keycode +static int kc_decode(KeySym ks) +{ + switch (ks) { + case XK_A: case XK_a: return 0x00; + case XK_B: case XK_b: return 0x0b; + case XK_C: case XK_c: return 0x08; + case XK_D: case XK_d: return 0x02; + case XK_E: case XK_e: return 0x0e; + case XK_F: case XK_f: return 0x03; + case XK_G: case XK_g: return 0x05; + case XK_H: case XK_h: return 0x04; + case XK_I: case XK_i: return 0x22; + case XK_J: case XK_j: return 0x26; + case XK_K: case XK_k: return 0x28; + case XK_L: case XK_l: return 0x25; + case XK_M: case XK_m: return 0x2e; + case XK_N: case XK_n: return 0x2d; + case XK_O: case XK_o: return 0x1f; + case XK_P: case XK_p: return 0x23; + case XK_Q: case XK_q: return 0x0c; + case XK_R: case XK_r: return 0x0f; + case XK_S: case XK_s: return 0x01; + case XK_T: case XK_t: return 0x11; + case XK_U: case XK_u: return 0x20; + case XK_V: case XK_v: return 0x09; + case XK_W: case XK_w: return 0x0d; + case XK_X: case XK_x: return 0x07; + case XK_Y: case XK_y: return 0x10; + case XK_Z: case XK_z: return 0x06; + + case XK_1: case XK_exclam: return 0x12; + case XK_2: case XK_at: return 0x13; + case XK_3: case XK_numbersign: return 0x14; + case XK_4: case XK_dollar: return 0x15; + case XK_5: case XK_percent: return 0x17; + case XK_6: return 0x16; + case XK_7: return 0x1a; + case XK_8: return 0x1c; + case XK_9: return 0x19; + case XK_0: return 0x1d; + + case XK_grave: case XK_asciitilde: return 0x0a; + case XK_minus: case XK_underscore: return 0x1b; + case XK_equal: case XK_plus: return 0x18; + case XK_bracketleft: case XK_braceleft: return 0x21; + case XK_bracketright: case XK_braceright: return 0x1e; + case XK_backslash: case XK_bar: return 0x2a; + case XK_semicolon: case XK_colon: return 0x29; + case XK_apostrophe: case XK_quotedbl: return 0x27; + case XK_comma: case XK_less: return 0x2b; + case XK_period: case XK_greater: return 0x2f; + case XK_slash: case XK_question: return 0x2c; + + case XK_Tab: if (ctrl_down) {suspend_emul(); return -1;} else return 0x30; + case XK_Return: return 0x24; + case XK_space: return 0x31; + case XK_BackSpace: return 0x33; + + case XK_Delete: return 0x75; + case XK_Insert: return 0x72; + case XK_Home: case XK_Help: return 0x73; + case XK_End: return 0x77; +#ifdef __hpux + case XK_Prior: return 0x74; + case XK_Next: return 0x79; +#else + case XK_Page_Up: return 0x74; + case XK_Page_Down: return 0x79; +#endif + + case XK_Control_L: return 0x36; + case XK_Control_R: return 0x36; + case XK_Shift_L: return 0x38; + case XK_Shift_R: return 0x38; + case XK_Alt_L: return 0x37; + case XK_Alt_R: return 0x37; + case XK_Meta_L: return 0x3a; + case XK_Meta_R: return 0x3a; + case XK_Menu: return 0x32; + case XK_Caps_Lock: return 0x39; + case XK_Num_Lock: return 0x47; + + case XK_Up: return 0x3e; + case XK_Down: return 0x3d; + case XK_Left: return 0x3b; + case XK_Right: return 0x3c; + + case XK_Escape: if (ctrl_down) {quit_full_screen = true; emerg_quit = true; return -1;} else return 0x35; + + case XK_F1: if (ctrl_down) {SysMountFirstFloppy(); return -1;} else return 0x7a; + case XK_F2: return 0x78; + case XK_F3: return 0x63; + case XK_F4: return 0x76; + case XK_F5: return 0x60; + case XK_F6: return 0x61; + case XK_F7: return 0x62; + case XK_F8: return 0x64; + case XK_F9: return 0x65; + case XK_F10: return 0x6d; + case XK_F11: return 0x67; + case XK_F12: return 0x6f; + + case XK_Print: return 0x69; + case XK_Scroll_Lock: return 0x6b; + case XK_Pause: return 0x71; + +#if defined(XK_KP_Prior) && defined(XK_KP_Left) && defined(XK_KP_Insert) && defined (XK_KP_End) + case XK_KP_0: case XK_KP_Insert: return 0x52; + case XK_KP_1: case XK_KP_End: return 0x53; + case XK_KP_2: case XK_KP_Down: return 0x54; + case XK_KP_3: case XK_KP_Next: return 0x55; + case XK_KP_4: case XK_KP_Left: return 0x56; + case XK_KP_5: case XK_KP_Begin: return 0x57; + case XK_KP_6: case XK_KP_Right: return 0x58; + case XK_KP_7: case XK_KP_Home: return 0x59; + case XK_KP_8: case XK_KP_Up: return 0x5b; + case XK_KP_9: case XK_KP_Prior: return 0x5c; + case XK_KP_Decimal: case XK_KP_Delete: return 0x41; +#else + case XK_KP_0: return 0x52; + case XK_KP_1: return 0x53; + case XK_KP_2: return 0x54; + case XK_KP_3: return 0x55; + case XK_KP_4: return 0x56; + case XK_KP_5: return 0x57; + case XK_KP_6: return 0x58; + case XK_KP_7: return 0x59; + case XK_KP_8: return 0x5b; + case XK_KP_9: return 0x5c; + case XK_KP_Decimal: return 0x41; +#endif + case XK_KP_Add: return 0x45; + case XK_KP_Subtract: return 0x4e; + case XK_KP_Multiply: return 0x43; + case XK_KP_Divide: return 0x4b; + case XK_KP_Enter: return 0x4c; + case XK_KP_Equal: return 0x51; + } + return -1; +} + +static int event2keycode(XKeyEvent *ev) +{ + KeySym ks; + int as; + int i = 0; + + do { + ks = XLookupKeysym(ev, i++); + as = kc_decode(ks); + if (as != -1) + return as; + } while (ks != NoSymbol); + + return -1; +} + +static void handle_events(void) +{ + // Handle events + for (;;) { + XEvent event; + + if (!XCheckMaskEvent(x_display, eventmask, &event)) + break; + + switch (event.type) { + // Mouse button + case ButtonPress: { + unsigned int button = ((XButtonEvent *)&event)->button; + if (button < 4) + ADBMouseDown(button - 1); + break; + } + case ButtonRelease: { + unsigned int button = ((XButtonEvent *)&event)->button; + if (button < 4) + ADBMouseUp(button - 1); + break; + } + + // Mouse moved + case EnterNotify: + ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y); + break; + case MotionNotify: + ADBMouseMoved(((XMotionEvent *)&event)->x, ((XMotionEvent *)&event)->y); + break; + + // Keyboard + case KeyPress: { + int code; + if ((code = event2keycode((XKeyEvent *)&event)) != -1) { + if (!emul_suspended) { + ADBKeyDown(code); + if (code == 0x36) + ctrl_down = true; + } else { + if (code == 0x31) + resume_emul(); // Space wakes us up + } + } + break; + } + case KeyRelease: { + int code; + if ((code = event2keycode((XKeyEvent *)&event)) != -1) { + ADBKeyUp(code); + if (code == 0x36) + ctrl_down = false; + } + break; + } + + // Hidden parts exposed, force complete refresh + case Expose: + memset(the_buffer_copy, 0, VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize); + break; + } + } +} + + +/* + * Execute video VBL routine + */ + +void VideoVBL(void) +{ + if (emerg_quit) + QuitEmulator(); + + // Execute video VBL + if (private_data != NULL && private_data->interruptsEnabled) + VSLDoInterruptService(private_data->vslServiceID); +} + + +/* + * Install graphics acceleration + */ + +#if 0 +// Rectangle blitting +static void accl_bitblt(accl_params *p) +{ + D(bug("accl_bitblt\n")); + + // Get blitting parameters + int16 src_X = p->src_rect[1] - p->src_bounds[1]; + int16 src_Y = p->src_rect[0] - p->src_bounds[0]; + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 width = p->dest_rect[3] - p->dest_rect[1] - 1; + int16 height = p->dest_rect[2] - p->dest_rect[0] - 1; + D(bug(" src X %d, src Y %d, dest X %d, dest Y %d\n", src_X, src_Y, dest_X, dest_Y)); + D(bug(" width %d, height %d\n", width, height)); + + // And perform the blit + bitblt_hook(src_X, src_Y, dest_X, dest_Y, width, height); +} + +static bool accl_bitblt_hook(accl_params *p) +{ + D(bug("accl_draw_hook %p\n", p)); + + // Check if we can accelerate this bitblt + if (p->src_base_addr == screen_base && p->dest_base_addr == screen_base && + display_type == DIS_SCREEN && bitblt_hook != NULL && + ((uint32 *)p)[0x18 >> 2] + ((uint32 *)p)[0x128 >> 2] == 0 && + ((uint32 *)p)[0x130 >> 2] == 0 && + p->transfer_mode == 0 && + p->src_row_bytes > 0 && ((uint32 *)p)[0x15c >> 2] > 0) { + + // Yes, set function pointer + p->draw_proc = accl_bitblt; + return true; + } + return false; +} + +// Rectangle filling/inversion +static void accl_fillrect8(accl_params *p) +{ + D(bug("accl_fillrect8\n")); + + // Get filling parameters + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; + int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; + uint8 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen; + D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); + D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); + + // And perform the fill + fillrect8_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); +} + +static void accl_fillrect32(accl_params *p) +{ + D(bug("accl_fillrect32\n")); + + // Get filling parameters + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; + int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; + uint32 color = p->pen_mode == 8 ? p->fore_pen : p->back_pen; + D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); + D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); + + // And perform the fill + fillrect32_hook(dest_X, dest_Y, dest_X_max, dest_Y_max, color); +} + +static void accl_invrect(accl_params *p) +{ + D(bug("accl_invrect\n")); + + // Get inversion parameters + int16 dest_X = p->dest_rect[1] - p->dest_bounds[1]; + int16 dest_Y = p->dest_rect[0] - p->dest_bounds[0]; + int16 dest_X_max = p->dest_rect[3] - p->dest_bounds[1] - 1; + int16 dest_Y_max = p->dest_rect[2] - p->dest_bounds[0] - 1; + D(bug(" dest X %d, dest Y %d\n", dest_X, dest_Y)); + D(bug(" dest X max %d, dest Y max %d\n", dest_X_max, dest_Y_max)); + + //!!?? pen_mode == 14 + + // And perform the inversion + invrect_hook(dest_X, dest_Y, dest_X_max, dest_Y_max); +} + +static bool accl_fillrect_hook(accl_params *p) +{ + D(bug("accl_fillrect_hook %p\n", p)); + + // Check if we can accelerate this fillrect + if (p->dest_base_addr == screen_base && ((uint32 *)p)[0x284 >> 2] != 0 && display_type == DIS_SCREEN) { + if (p->transfer_mode == 8) { + // Fill + if (p->dest_pixel_size == 8 && fillrect8_hook != NULL) { + p->draw_proc = accl_fillrect8; + return true; + } else if (p->dest_pixel_size == 32 && fillrect32_hook != NULL) { + p->draw_proc = accl_fillrect32; + return true; + } + } else if (p->transfer_mode == 10 && invrect_hook != NULL) { + // Invert + p->draw_proc = accl_invrect; + return true; + } + } + return false; +} + +// Wait for graphics operation to finish +static bool accl_sync_hook(void *arg) +{ + D(bug("accl_sync_hook %p\n", arg)); + if (sync_hook != NULL) + sync_hook(); + return true; +} + +static struct accl_hook_info bitblt_hook_info = {accl_bitblt_hook, accl_sync_hook, ACCL_BITBLT}; +static struct accl_hook_info fillrect_hook_info = {accl_fillrect_hook, accl_sync_hook, ACCL_FILLRECT}; +#endif + +void VideoInstallAccel(void) +{ + // Install acceleration hooks + if (PrefsFindBool("gfxaccel")) { + D(bug("Video: Installing acceleration hooks\n")); +//!! NQDMisc(6, &bitblt_hook_info); +// NQDMisc(6, &fillrect_hook_info); + } +} + + +/* + * Change video mode + */ + +int16 video_mode_change(VidLocals *csSave, uint32 ParamPtr) +{ + /* return if no mode change */ + if ((csSave->saveData == ReadMacInt32(ParamPtr + csData)) && + (csSave->saveMode == ReadMacInt16(ParamPtr + csMode))) return noErr; + + /* first find video mode in table */ + for (int i=0; VModes[i].viType != DIS_INVALID; i++) { + if ((ReadMacInt16(ParamPtr + csMode) == VModes[i].viAppleMode) && + (ReadMacInt32(ParamPtr + csData) == VModes[i].viAppleID)) { + csSave->saveMode = ReadMacInt16(ParamPtr + csMode); + csSave->saveData = ReadMacInt32(ParamPtr + csData); + csSave->savePage = ReadMacInt16(ParamPtr + csPage); + + // Disable interrupts and pause redraw thread + DisableInterrupt(); + thread_stop_ack = false; + thread_stop_req = true; + while (!thread_stop_ack) ; + + /* close old display */ + close_display(); + + /* open new display */ + cur_mode = i; + bool ok = open_display(); + + /* opening the screen failed? Then bail out */ + if (!ok) { + ErrorAlert(GetString(STR_FULL_SCREEN_ERR)); + QuitEmulator(); + } + + WriteMacInt32(ParamPtr + csBaseAddr, screen_base); + csSave->saveBaseAddr=screen_base; + csSave->saveData=VModes[cur_mode].viAppleID;/* First mode ... */ + csSave->saveMode=VModes[cur_mode].viAppleMode; + + // Enable interrupts and resume redraw thread + thread_stop_req = false; + EnableInterrupt(); + return noErr; + } + } + return paramErr; +} + + +/* + * Set color palette + */ + +void video_set_palette(void) +{ + palette_changed = true; +} + + +/* + * Set cursor image for window + */ + +void video_set_cursor(void) +{ + cursor_changed = true; +} + + +/* + * Thread for window refresh, event handling and other periodic actions + */ + +static void update_display(void) +{ + // Incremental update code + int wide = 0, high = 0, x1, x2, y1, y2, i, j; + int bytes_per_row = VModes[cur_mode].viRowBytes; + int bytes_per_pixel = VModes[cur_mode].viRowBytes / VModes[cur_mode].viXsize; + uint8 *p, *p2; + + // Check for first line from top and first line from bottom that have changed + y1 = 0; + for (j=0; j=y1; j--) { + if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) { + y2 = j; + break; + } + } + high = y2 - y1 + 1; + + // Check for first column from left and first column from right that have changed + if (high) { + if (depth == 1) { + x1 = VModes[cur_mode].viXsize; + for (j=y1; j<=y2; j++) { + p = &the_buffer[j * bytes_per_row]; + p2 = &the_buffer_copy[j * bytes_per_row]; + for (i=0; i<(x1>>3); i++) { + if (*p != *p2) { + x1 = i << 3; + break; + } + p++; + p2++; + } + } + x2 = x1; + for (j=y1; j<=y2; j++) { + p = &the_buffer[j * bytes_per_row]; + p2 = &the_buffer_copy[j * bytes_per_row]; + p += bytes_per_row; + p2 += bytes_per_row; + for (i=(VModes[cur_mode].viXsize>>3); i>(x2>>3); i--) { + p--; + p2--; + if (*p != *p2) { + x2 = i << 3; + break; + } + } + } + wide = x2 - x1; + + // Update copy of the_buffer + if (high && wide) { + for (j=y1; j<=y2; j++) { + i = j * bytes_per_row + (x1 >> 3); + memcpy(&the_buffer_copy[i], &the_buffer[i], wide >> 3); + } + } + + } else { + x1 = VModes[cur_mode].viXsize; + for (j=y1; j<=y2; j++) { + p = &the_buffer[j * bytes_per_row]; + p2 = &the_buffer_copy[j * bytes_per_row]; + for (i=0; ix2; i--) { + p -= bytes_per_pixel; + p2 -= bytes_per_pixel; + if (memcmp(p, p2, bytes_per_pixel)) { + x2 = i; + break; + } + } + } + wide = x2 - x1; + + // Update copy of the_buffer + if (high && wide) { + for (j=y1; j<=y2; j++) { + i = j * bytes_per_row + x1 * bytes_per_pixel; + memcpy(&the_buffer_copy[i], &the_buffer[i], bytes_per_pixel * wide); + } + } + } + } + + // Refresh display + if (high && wide) { + if (have_shm) + XShmPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high, 0); + else + XPutImage(x_display, the_win, the_gc, img, x1, y1, x1, y1, wide, high); + } +} + +static void *redraw_func(void *arg) +{ + int tick_counter = 0; + struct timespec req = {0, 16666667}; + + for (;;) { + + // Wait + nanosleep(&req, NULL); + + // Pause if requested (during video mode switches) + while (thread_stop_req) + thread_stop_ack = true; + + // Handle X11 events + handle_events(); + + // Quit DGA mode if requested + if (quit_full_screen) { + quit_full_screen = false; + if (display_type == DIS_SCREEN) { +#ifdef ENABLE_XF86_DGA + XF86DGADirectVideo(x_display, screen, 0); + XUngrabPointer(x_display, CurrentTime); + XUngrabKeyboard(x_display, CurrentTime); +#endif + XSync(x_display, false); + quit_full_screen_ack = true; + return NULL; + } + } + + // Refresh display and set cursor image in window mode + if (display_type == DIS_WINDOW) { + tick_counter++; + if (tick_counter >= frame_skip) { + tick_counter = 0; + + // Update display + update_display(); + + // Set new cursor image if it was changed + if (cursor_changed) { + cursor_changed = false; + memcpy(cursor_image->data, MacCursor + 4, 32); + memcpy(cursor_mask_image->data, MacCursor + 36, 32); + XFreeCursor(x_display, mac_cursor); + XPutImage(x_display, cursor_map, cursor_gc, cursor_image, 0, 0, 0, 0, 16, 16); + XPutImage(x_display, cursor_mask_map, cursor_mask_gc, cursor_mask_image, 0, 0, 0, 0, 16, 16); + mac_cursor = XCreatePixmapCursor(x_display, cursor_map, cursor_mask_map, &black, &white, MacCursor[2], MacCursor[3]); + XDefineCursor(x_display, the_win, mac_cursor); + } + } + } + + // Set new palette if it was changed + if (palette_changed && !emul_suspended) { + palette_changed = false; + XColor c[256]; + for (int i=0; i<256; i++) { + c[i].pixel = i; + c[i].red = mac_pal[i].red * 0x0101; + c[i].green = mac_pal[i].green * 0x0101; + c[i].blue = mac_pal[i].blue * 0x0101; + c[i].flags = DoRed | DoGreen | DoBlue; + } + if (depth == 8) { + XStoreColors(x_display, cmap[0], c, 256); + XStoreColors(x_display, cmap[1], c, 256); +#ifdef ENABLE_XF86_DGA + if (display_type == DIS_SCREEN) { + current_dga_cmap ^= 1; + XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); + } +#endif + } + } + } + return NULL; +} diff --git a/SheepShaver/src/VideoDriverStub.i b/SheepShaver/src/VideoDriverStub.i new file mode 100644 index 00000000..ad2ed630 --- /dev/null +++ b/SheepShaver/src/VideoDriverStub.i @@ -0,0 +1,24 @@ + 0x4a, 0x6f, 0x79, 0x21, 0x70, 0x65, 0x66, 0x66, 0x70, 0x77, 0x70, 0x63, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x01, 0x10, + 0x00, 0x04, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, + 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x01, 0x40, 0x02, 0x01, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x80, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x54, 0x68, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, + 0x72, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x44, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x49, 0x4f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, + 0x00, 0x14, 0xbd, 0xe0, 0x00, 0x0a, 0xd1, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x61, 0x00, 0x18, 0x90, 0x81, 0x00, 0x1c, 0x90, 0xa1, 0x00, 0x20, 0x90, 0xc1, 0x00, 0x24, + 0x90, 0xe1, 0x00, 0x28, 0x80, 0x40, 0x28, 0x08, 0x80, 0x00, 0x28, 0xd8, 0x7c, 0x09, 0x03, 0xa6, + 0x4e, 0x80, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x24, 0x6d, 0x74, 0x65, 0x6a, 0x04, 0x26, 0x05, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x1a, 0x21, + 0x01, 0x01, 0x21, 0x80, 0x04, 0x3b, 0x06, 0x19, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x56, 0x69, 0x64, 0x65, 0x6f, 0x5f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x5f, 0x53, 0x68, 0x65, 0x65, + 0x70, 0x00, 0x29, 0x2a, 0x01, 0x6e, 0x64, 0x72, 0x76, 0x76, 0x69, 0x64, 0x6f, 0x01, 0x03, diff --git a/SheepShaver/src/emul_op.cpp b/SheepShaver/src/emul_op.cpp new file mode 100644 index 00000000..bada48e8 --- /dev/null +++ b/SheepShaver/src/emul_op.cpp @@ -0,0 +1,477 @@ +/* + * emul_op.cpp - 68k opcodes for ROM patches + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "sysdeps.h" +#include "main.h" +#include "version.h" +#include "prefs.h" +#include "cpu_emulation.h" +#include "xlowmem.h" +#include "xpram.h" +#include "timer.h" +#include "adb.h" +#include "sony.h" +#include "disk.h" +#include "cdrom.h" +#include "scsi.h" +#include "video.h" +#include "audio.h" +#include "ether.h" +#include "serial.h" +#include "clip.h" +#include "extfs.h" +#include "macos_util.h" +#include "rom_patches.h" +#include "rsrc_patches.h" +#include "name_registry.h" +#include "user_strings.h" +#include "emul_op.h" + +#define DEBUG 0 +#include "debug.h" + + +#if __BEOS__ +#define PRECISE_TIMING 1 +#else +#define PRECISE_TIMING 0 +#endif + + +// TVector of MakeExecutable +static uint32 *MakeExecutableTvec; + + +/* + * Execute EMUL_OP opcode (called by 68k emulator) + */ + +void EmulOp(M68kRegisters *r, uint32 pc, int selector) +{ + + D(bug("EmulOp %04x at %08x\n", selector, pc)); + switch (selector) { + case OP_BREAK: // Breakpoint + printf("*** Breakpoint\n"); + Dump68kRegs(r); + break; + + case OP_XPRAM1: { // Read/write from/to XPRam + uint32 len = r->d[3]; + uint8 *adr = Mac2HostAddr(r->a[3]); + D(bug("XPRAMReadWrite d3: %08lx, a3: %p\n", len, adr)); + int ofs = len & 0xffff; + len >>= 16; + if (len & 0x8000) { + len &= 0x7fff; + for (uint32 i=0; id[1] = XPRAM[(r->d[1] & 0xff) + 0x1300]; + break; + + case OP_XPRAM3: // Write to XPRam + XPRAM[(r->d[1] & 0xff) + 0x1300] = r->d[2]; + break; + + case OP_NVRAM1: { // Read from NVRAM + int ofs = r->d[0]; + r->d[0] = XPRAM[ofs & 0x1fff]; + bool localtalk = !(XPRAM[0x13e0] || XPRAM[0x13e1]); // LocalTalk enabled? + switch (ofs) { + case 0x13e0: // Disable LocalTalk (use EtherTalk instead) + if (localtalk) + r->d[0] = 0x00; + break; + case 0x13e1: + if (localtalk) + r->d[0] = 0x01; + break; + case 0x13e2: + if (localtalk) + r->d[0] = 0x00; + break; + case 0x13e3: + if (localtalk) + r->d[0] = 0x0a; + break; + } + break; + } + + case OP_NVRAM2: // Write to NVRAM + XPRAM[r->d[0] & 0x1fff] = r->d[1]; + break; + + case OP_NVRAM3: // Read/write from/to NVRAM + if (r->d[3]) { + r->d[0] = XPRAM[(r->d[4] + 0x1300) & 0x1fff]; + } else { + XPRAM[(r->d[4] + 0x1300) & 0x1fff] = r->d[5]; + r->d[0] = 0; + } + break; + + case OP_FIX_MEMTOP: // Fixes MemTop in BootGlobs during startup + D(bug("Fix MemTop\n")); + WriteMacInt32(BootGlobsAddr - 20, RAMBase + RAMSize); // MemTop + r->a[6] = RAMBase + RAMSize; + break; + + case OP_FIX_MEMSIZE: { // Fixes physical/logical RAM size during startup + D(bug("Fix MemSize\n")); + uint32 diff = ReadMacInt32(0x1ef8) - ReadMacInt32(0x1ef4); + WriteMacInt32(0x1ef8, RAMSize); // Physical RAM size + WriteMacInt32(0x1ef4, RAMSize - diff); // Logical RAM size + break; + } + + case OP_FIX_BOOTSTACK: // Fixes boot stack pointer in boot 3 resource + D(bug("Fix BootStack\n")); + r->a[1] = r->a[7] = RAMBase + RAMSize * 3 / 4; + break; + + case OP_SONY_OPEN: // Floppy driver functions + r->d[0] = SonyOpen(r->a[0], r->a[1]); + break; + case OP_SONY_PRIME: + r->d[0] = SonyPrime(r->a[0], r->a[1]); + break; + case OP_SONY_CONTROL: + r->d[0] = SonyControl(r->a[0], r->a[1]); + break; + case OP_SONY_STATUS: + r->d[0] = SonyStatus(r->a[0], r->a[1]); + break; + + case OP_DISK_OPEN: // Disk driver functions + r->d[0] = DiskOpen(r->a[0], r->a[1]); + break; + case OP_DISK_PRIME: + r->d[0] = DiskPrime(r->a[0], r->a[1]); + break; + case OP_DISK_CONTROL: + r->d[0] = DiskControl(r->a[0], r->a[1]); + break; + case OP_DISK_STATUS: + r->d[0] = DiskStatus(r->a[0], r->a[1]); + break; + + case OP_CDROM_OPEN: // CD-ROM driver functions + r->d[0] = CDROMOpen(r->a[0], r->a[1]); + break; + case OP_CDROM_PRIME: + r->d[0] = CDROMPrime(r->a[0], r->a[1]); + break; + case OP_CDROM_CONTROL: + r->d[0] = CDROMControl(r->a[0], r->a[1]); + break; + case OP_CDROM_STATUS: + r->d[0] = CDROMStatus(r->a[0], r->a[1]); + break; + + case OP_AUDIO_DISPATCH: // Audio component functions + r->d[0] = AudioDispatch(r->a[3], r->a[4]); + break; + + case OP_SOUNDIN_OPEN: // Sound input driver functions + r->d[0] = SoundInOpen(r->a[0], r->a[1]); + break; + case OP_SOUNDIN_PRIME: + r->d[0] = SoundInPrime(r->a[0], r->a[1]); + break; + case OP_SOUNDIN_CONTROL: + r->d[0] = SoundInControl(r->a[0], r->a[1]); + break; + case OP_SOUNDIN_STATUS: + r->d[0] = SoundInStatus(r->a[0], r->a[1]); + break; + case OP_SOUNDIN_CLOSE: + r->d[0] = SoundInClose(r->a[0], r->a[1]); + break; + + case OP_ADBOP: // ADBOp() replacement + ADBOp(r->d[0], Mac2HostAddr(ReadMacInt32(r->a[0]))); + break; + + case OP_INSTIME: // InsTime() replacement + r->d[0] = InsTime(r->a[0], r->d[1]); + break; + case OP_RMVTIME: // RmvTime() replacement + r->d[0] = RmvTime(r->a[0]); + break; + case OP_PRIMETIME: // PrimeTime() replacement + r->d[0] = PrimeTime(r->a[0], r->d[0]); + break; + + case OP_MICROSECONDS: // Microseconds() replacement + Microseconds(r->a[0], r->d[0]); + break; + + case OP_PUT_SCRAP: // PutScrap() patch + PutScrap(ReadMacInt32(r->a[7] + 8), Mac2HostAddr(ReadMacInt32(r->a[7] + 4)), ReadMacInt32(r->a[7] + 12)); + break; + + case OP_GET_SCRAP: // GetScrap() patch + GetScrap((void **)Mac2HostAddr(ReadMacInt32(r->a[7] + 4)), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 12)); + break; + + case OP_DEBUG_STR: // DebugStr() shows warning message + if (PrefsFindBool("nogui")) { + uint8 *pstr = Mac2HostAddr(ReadMacInt32(r->a[7] + 4)); + char str[256]; + int i; + for (i=0; id[0] = (uint32)-1; + PatchNameRegistry(); + InitCallUniversalProc(); + break; + + case OP_RESET: // Early in MacOS reset + D(bug("*** RESET ***\n")); + TimerReset(); + MacOSUtilReset(); + AudioReset(); +#if 0 + printf("DR activated\n"); + WriteMacInt32(KernelDataAddr + 0x17a0, 3); // Prepare for DR emulator activation + WriteMacInt32(KernelDataAddr + 0x17c0, DR_CACHE_BASE); + WriteMacInt32(KernelDataAddr + 0x17c4, DR_CACHE_SIZE); + WriteMacInt32(KernelDataAddr + 0x1b00, DR_CACHE_BASE + 0x10000); + memcpy((void *)(DR_CACHE_BASE + 0x10000), (void *)(ROM_BASE + 0x370000), 0x10000); + clear_caches((void *)(DR_CACHE_BASE + 0x10000), 0x10000, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE); +#endif + break; + + case OP_IRQ: // Level 1 interrupt + WriteMacInt16(ReadMacInt32(KernelDataAddr + 0x67c), 0); // Clear interrupt + r->d[0] = 0; + if (HasMacStarted()) { + if (InterruptFlags & INTFLAG_VIA) { + ClearInterruptFlag(INTFLAG_VIA); +#if !PRECISE_TIMING + TimerInterrupt(); +#endif + ExecutePPC(VideoVBL); + + static int tick_counter = 0; + if (++tick_counter >= 60) { + tick_counter = 0; + SonyInterrupt(); + DiskInterrupt(); + CDROMInterrupt(); + } + + r->d[0] = 1; // Flag: 68k interrupt routine executes VBLTasks etc. + } + if (InterruptFlags & INTFLAG_SERIAL) { + ClearInterruptFlag(INTFLAG_SERIAL); + SerialInterrupt(); + } + if (InterruptFlags & INTFLAG_ETHER) { + ClearInterruptFlag(INTFLAG_ETHER); + ExecutePPC(EtherIRQ); + } + if (InterruptFlags & INTFLAG_TIMER) { + ClearInterruptFlag(INTFLAG_TIMER); + TimerInterrupt(); + } + if (InterruptFlags & INTFLAG_AUDIO) { + ClearInterruptFlag(INTFLAG_AUDIO); + AudioInterrupt(); + } + if (InterruptFlags & INTFLAG_ADB) { + ClearInterruptFlag(INTFLAG_ADB); + ADBInterrupt(); + } + } else + r->d[0] = 1; + break; + + case OP_SCSI_DISPATCH: { // SCSIDispatch() replacement + uint32 ret = ReadMacInt32(r->a[7]); + uint16 sel = ReadMacInt16(r->a[7] + 4); + r->a[7] += 6; +// D(bug("SCSIDispatch(%d)\n", sel)); + int stack; + switch (sel) { + case 0: // SCSIReset + WriteMacInt16(r->a[7], SCSIReset()); + stack = 0; + break; + case 1: // SCSIGet + WriteMacInt16(r->a[7], SCSIGet()); + stack = 0; + break; + case 2: // SCSISelect + case 11: // SCSISelAtn + WriteMacInt16(r->a[7] + 2, SCSISelect(ReadMacInt8(r->a[7] + 1))); + stack = 2; + break; + case 3: // SCSICmd + WriteMacInt16(r->a[7] + 6, SCSICmd(ReadMacInt16(r->a[7]), Mac2HostAddr(ReadMacInt32(r->a[7] + 2)))); + stack = 6; + break; + case 4: // SCSIComplete + WriteMacInt16(r->a[7] + 12, SCSIComplete(ReadMacInt32(r->a[7]), ReadMacInt32(r->a[7] + 4), ReadMacInt32(r->a[7] + 8))); + stack = 12; + break; + case 5: // SCSIRead + case 8: // SCSIRBlind + WriteMacInt16(r->a[7] + 4, SCSIRead(ReadMacInt32(r->a[7]))); + stack = 4; + break; + case 6: // SCSIWrite + case 9: // SCSIWBlind + WriteMacInt16(r->a[7] + 4, SCSIWrite(ReadMacInt32(r->a[7]))); + stack = 4; + break; + case 10: // SCSIStat + WriteMacInt16(r->a[7], SCSIStat()); + stack = 0; + break; + case 12: // SCSIMsgIn + WriteMacInt16(r->a[7] + 4, 0); + stack = 4; + break; + case 13: // SCSIMsgOut + WriteMacInt16(r->a[7] + 2, 0); + stack = 2; + break; + case 14: // SCSIMgrBusy + WriteMacInt16(r->a[7], SCSIMgrBusy()); + stack = 0; + break; + default: + printf("FATAL: SCSIDispatch: illegal selector\n"); + stack = 0; + //!! SysError(12) + } + r->a[0] = ret; + r->a[7] += stack; + break; + } + + case OP_SCSI_ATOMIC: // SCSIAtomic() replacement + D(bug("SCSIAtomic\n")); + r->d[0] = (uint32)-7887; + break; + + case OP_NTRB_17_PATCH: + r->a[2] = ReadMacInt32(r->a[7]); + r->a[7] += 4; + if (ReadMacInt16(r->a[2] + 6) == 17) + PatchNativeResourceManager(); + break; + + case OP_NTRB_17_PATCH2: + r->a[7] += 8; + PatchNativeResourceManager(); + break; + + case OP_NTRB_17_PATCH3: + r->a[2] = ReadMacInt32(r->a[7]); + r->a[7] += 4; + D(bug("%d %d\n", ReadMacInt16(r->a[2]), ReadMacInt16(r->a[2] + 6))); + if (ReadMacInt16(r->a[2]) == 11 && ReadMacInt16(r->a[2] + 6) == 17) + PatchNativeResourceManager(); + break; + + case OP_CHECKLOAD: { // vCheckLoad() patch + uint32 type = ReadMacInt32(r->a[7]); + r->a[7] += 4; + int16 id = ReadMacInt16(r->a[2]); + if (r->a[0] == 0) + break; + uint32 adr = ReadMacInt32(r->a[0]); + if (adr == 0) + break; + uint16 *p = (uint16 *)Mac2HostAddr(adr); + uint32 size = ReadMacInt32(adr - 8) & 0xffffff; + CheckLoad(type, id, p, size); + break; + } + + case OP_EXTFS_COMM: // External file system routines + WriteMacInt16(r->a[7] + 14, ExtFSComm(ReadMacInt16(r->a[7] + 12), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 4))); + break; + + case OP_EXTFS_HFS: + WriteMacInt16(r->a[7] + 20, ExtFSHFS(ReadMacInt32(r->a[7] + 16), ReadMacInt16(r->a[7] + 14), ReadMacInt32(r->a[7] + 10), ReadMacInt32(r->a[7] + 6), ReadMacInt16(r->a[7] + 4))); + break; + + case OP_IDLE_TIME: +#if __BEOS__ + // Sleep if no events pending + if (ReadMacInt32(0x14c) == 0) { + sleep(16667); + } +#endif + r->a[0] = ReadMacInt32(0x2b6); + break; + + default: + printf("FATAL: EMUL_OP called with bogus selector %08x\n", selector); + QuitEmulator(); + break; + } +} diff --git a/SheepShaver/src/emul_ppc/emul_ppc.cpp b/SheepShaver/src/emul_ppc/emul_ppc.cpp new file mode 100644 index 00000000..8fadf1e7 --- /dev/null +++ b/SheepShaver/src/emul_ppc/emul_ppc.cpp @@ -0,0 +1,1661 @@ +/* + * emul_ppc.cpp - PowerPC processor emulation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 + */ + +/* +TODO: +addme +addmeo +addze +addzeo +dcbst +dcbt +dcbtst +divwuo +fabs +fadd +fadds +fcmpo +fcmpu +fctiw +fctiwz +fdiv +fdivs +fmadd +fmadds +fmr +fmsub +fmsubs +fmul +fmuls +fnabs +fneg +fnmadd +fnmadds +fnmsub +fnmsubs +fres +frsp +frsqrte +fsel +fsqrt +fsqrts +fsub +fsubs +lfdu +lfdux +lfdx +lfs +lfsu +lfsux +lfsx +lhbrx +lwbrx +mcrfs +mcrxr +mtfsb0 +mtfsb1 +mtfsfi +mulhwu +mullwo +nego +sc +stfdu +stfdux +stfdx +stfs +stfsu +stfsux +stfsx +sthbrx +stwbrx +subfo +subfme +subfmeo +subfze +subfzeo +tw +twi + +CHECK: +crxor +creqv + */ + +#include +#include + +#include "sysdeps.h" +#include "cpu_emulation.h" +#include "main.h" +#include "xlowmem.h" +#include "emul_op.h" + +#if ENABLE_MON +#include "mon.h" +#include "mon_disass.h" +#endif + +#define DEBUG 1 +#include "debug.h" + +#define FLIGHT_RECORDER 1 + + +// PowerPC user mode registers +uint32 r[32]; +double fr[32]; +uint32 lr, ctr; +uint32 cr, xer; +uint32 fpscr; +uint32 pc; + +// Convert 8-bit field mask (e.g. mtcrf) to bit mask +static uint32 field2mask[256]; + + +/* + * Flight recorder + */ + +#if FLIGHT_RECORDER +struct rec_step { + uint32 r[32]; + double fr[32]; + uint32 lr, ctr; + uint32 cr, xer; + uint32 fpscr; + uint32 pc; + uint32 opcode; +}; + +const int LOG_SIZE = 8192; +static rec_step log[LOG_SIZE]; +static int log_ptr = 0; + +static void record_step(uint32 opcode) +{ + for (int i=0; i<32; i++) { + log[log_ptr].r[i] = r[i]; + log[log_ptr].fr[i] = fr[i]; + } + log[log_ptr].lr = lr; + log[log_ptr].ctr = ctr; + log[log_ptr].cr = cr; + log[log_ptr].xer = xer; + log[log_ptr].fpscr = fpscr; + log[log_ptr].pc = pc; + log[log_ptr].opcode = opcode; + log_ptr++; + if (log_ptr == LOG_SIZE) + log_ptr = 0; +} + +static void dump_log(void) +{ + FILE *f = fopen("log", "w"); + if (f == NULL) + return; + for (int i=0; i> 4) & 0x0f000000); +} + + +/* + * Convert mask begin/end to mask + */ + +static uint32 mbme2mask(uint32 op) +{ + uint32 mb = (op >> 6) & 0x1f; + uint32 me = (op >> 1) & 0x1f; + uint32 m = 0; + uint32 i; + + if (mb <= me) + for (i=mb; i<=me; i++) + m |= 0x80000000 >> i; + else { + for (i=0; i<=me; i++) + m |= 0x80000000 >> i; + for (i=mb; i<=31; i++) + m |= 0x80000000 >> i; + } + return m; +} + + +/* + * Emulate instruction with primary opcode = 19 + */ + +static void emul19(uint32 op) +{ + uint32 exop = (op >> 1) & 0x3ff; + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + switch (exop) { + + case 0: { // mcrf + uint32 crfd = 0x1c - (rd & 0x1c); + uint32 crfa = 0x1c - (ra & 0x1c); + uint32 crf = (cr >> crfa) & 0xf; + cr = (cr & ~(0xf << crfd)) | (crf << crfd); + break; + } + + case 16: { // bclr + uint32 oldpc = pc; + if (!(rd & 4)) { + ctr--; + if (rd & 2) { + if (ctr) + goto blr_nobranch; + } else { + if (!ctr) + goto blr_nobranch; + } + } + if (!(rd & 0x10)) { + if (rd & 8) { + if (!(cr & (0x80000000 >> ra))) + goto blr_nobranch; + } else { + if (cr & (0x80000000 >> ra)) + goto blr_nobranch; + } + } + pc = lr & 0xfffffffc; +blr_nobranch: + if (op & 1) + lr = oldpc; + break; + } + + case 33: // crnor + if ((cr & (0x80000000 >> ra)) || ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) + cr &= ~(0x80000000 >> rd); + else + cr |= 0x80000000 >> rd; + break; + + case 129: // crandc + if ((cr & (0x80000000 >> ra)) && !((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) + cr |= 0x80000000 >> rd; + else + cr &= ~(0x80000000 >> rd); + break; + + case 150: // isync + break; + + case 193: { // crxor + uint32 mask = 0x80000000 >> rd; + cr = (((((cr >> (31 - ra)) ^ (cr >> (31 - ((op >> 11) & 0x1f)))) & 1) << (31 - rd)) & mask) | (cr & ~mask); + break; + } + + case 225: // crnand + if ((cr & (0x80000000 >> ra)) && ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) + cr &= ~(0x80000000 >> rd); + else + cr |= 0x80000000 >> rd; + break; + + case 257: // crand + if ((cr & (0x80000000 >> ra)) && ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) + cr |= 0x80000000 >> rd; + else + cr &= ~(0x80000000 >> rd); + break; + + case 289: { // creqv + uint32 mask = 0x80000000 >> rd; + cr = (((~((cr >> (31 - ra)) ^ (cr >> (31 - ((op >> 11) & 0x1f)))) & 1) << (31 - rd)) & mask) | (cr & ~mask); + break; + } + + case 417: // crorc + if ((cr & (0x80000000 >> ra)) || !((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) + cr |= 0x80000000 >> rd; + else + cr &= ~(0x80000000 >> rd); + break; + + case 449: // cror + if ((cr & (0x80000000 >> ra)) || ((cr & (0x80000000 >> ((op >> 11) & 0x1f))))) + cr |= 0x80000000 >> rd; + else + cr &= ~(0x80000000 >> rd); + break; + + case 528: { // bcctr + if (op & 1) + lr = pc; + if (!(rd & 4)) { + ctr--; + if (rd & 2) { + if (ctr) + goto bctr_nobranch; + } else { + if (!ctr) + goto bctr_nobranch; + } + } + if (!(rd & 0x10)) { + if (rd & 8) { + if (!(cr & (0x80000000 >> ra))) + goto bctr_nobranch; + } else { + if (cr & (0x80000000 >> ra)) + goto bctr_nobranch; + } + } + pc = ctr & 0xfffffffc; +bctr_nobranch: + break; + } + + default: + printf("Illegal 19 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); + dump(); + break; + } +} + + +/* + * Emulate instruction with primary opcode = 31 + */ + +static void emul31(uint32 op) +{ + uint32 exop = (op >> 1) & 0x3ff; + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint32 rb = (op >> 11) & 0x1f; + switch (exop) { + + case 0: { // cmpw + uint32 crfd = 0x1c - (rd & 0x1c); + uint8 crf = 0; + if (r[ra] == r[rb]) + crf |= 2; + else if ((int32)r[ra] < (int32)r[rb]) + crf |= 8; + else + crf |= 4; + if (xer & 0x80000000) + crf |= 1; + cr = (cr & ~(0xf << crfd)) | (crf << crfd); + break; + } + + case 8: { // subfc + uint64 tmp = (uint64)r[rb] - (uint64)r[ra]; + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer &= ~0x20000000; + else + xer |= 0x20000000; + if (op & 1) + record(r[rd]); + break; + } + + case 10: { // addc + uint64 tmp = (uint64)r[ra] + (uint64)r[rb]; + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer |= 0x20000000; + else + xer &= ~0x20000000; + if (op & 1) + record(r[rd]); + break; + } + + case 19: // mfcr + r[rd] = cr; + break; + + case 20: // lwarx + r[rd] = ReadMacInt32(r[rb] + (ra ? r[ra] : 0)); + //!! set reservation bit + break; + + case 23: // lwzx + r[rd] = ReadMacInt32(r[rb] + (ra ? r[ra] : 0)); + break; + + case 24: // slw + r[ra] = r[rd] << (r[rb] & 0x3f); + if (op & 1) + record(r[ra]); + break; + + case 26: { // cntlzw + uint32 mask = 0x80000000; + for (int i=0; i<32; i++, mask>>=1) { + if (r[rd] & mask) { + r[ra] = i; + goto cntlzw_done; + } + } + r[ra] = 32; +cntlzw_done:if (op & 1) + record(r[ra]); + break; + } + + case 28: // and + r[ra] = r[rd] & r[rb]; + if (op & 1) + record(r[ra]); + break; + + case 32: { // cmplw + uint32 crfd = 0x1c - (rd & 0x1c); + uint8 crf = 0; + if (r[ra] == r[rb]) + crf |= 2; + else if (r[ra] < r[rb]) + crf |= 8; + else + crf |= 4; + if (xer & 0x80000000) + crf |= 1; + cr = (cr & ~(0xf << crfd)) | (crf << crfd); + break; + } + + case 40: // subf + r[rd] = r[rb] - r[ra]; + if (op & 1) + record(r[rd]); + break; + + case 55: // lwzux + r[ra] += r[rb]; + r[rd] = ReadMacInt32(r[ra]); + break; + + case 60: // andc + r[ra] = r[rd] & ~r[rb]; + if (op & 1) + record(r[ra]); + break; + + case 75: // mulhw + r[rd] = ((int64)(int32)r[ra] * (int32)r[rb]) >> 32; + if (op & 1) + record(r[rd]); + break; + + case 86: // dcbf + break; + + case 87: // lbzx + r[rd] = ReadMacInt8(r[rb] + (ra ? r[ra] : 0)); + break; + + case 104: // neg + if (r[ra] == 0x80000000) + r[rd] = 0x80000000; + else + r[rd] = -(int32)r[ra]; + if (op & 1) + record(r[rd]); + break; + + case 119: // lbzux + r[ra] += r[rb]; + r[rd] = ReadMacInt8(r[ra]); + break; + + case 124: // nor + r[ra] = ~(r[rd] | r[rb]); + if (op & 1) + record(r[ra]); + break; + + case 136: { // subfe + uint64 tmp = (uint64)r[rb] - (uint64)r[ra]; + if (!(xer & 0x20000000)) + tmp--; + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer &= ~0x20000000; + else + xer |= 0x20000000; + if (op & 1) + record(r[rd]); + break; + } + + case 138: { // adde + uint64 tmp = (uint64)r[ra] + (uint64)r[rb]; + if (xer & 0x20000000) + tmp++; + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer |= 0x20000000; + else + xer &= ~0x20000000; + if (op & 1) + record(r[rd]); + break; + } + + case 144: { // mtcrf + uint32 mask = field2mask[(op >> 12) & 0xff]; + cr = (r[rd] & mask) | (cr & ~mask); + break; + } + + case 150: // stwcx + //!! check reserved bit + WriteMacInt32(r[rb] + (ra ? r[ra] : 0), r[rd]); + record(0); + break; + + case 151: // stwx + WriteMacInt32(r[rb] + (ra ? r[ra] : 0), r[rd]); + break; + + case 183: // stwux + r[ra] += r[rb]; + WriteMacInt32(r[ra], r[rd]); + break; + + case 215: // stbx + WriteMacInt8(r[rb] + (ra ? r[ra] : 0), r[rd]); + break; + + case 235: // mullw + r[rd] = (int32)r[ra] * (int32)r[rb]; + if (op & 1) + record(r[rd]); + break; + + case 247: // stbux + r[ra] += r[rb]; + WriteMacInt8(r[ra], r[rd]); + break; + + case 266: // add + r[rd] = r[ra] + r[rb]; + if (op & 1) + record(r[rd]); + break; + + case 279: // lhzx + r[rd] = ReadMacInt16(r[rb] + (ra ? r[ra] : 0)); + break; + + case 284: // eqv + r[ra] = ~(r[rd] ^ r[rb]); + if (op & 1) + record(r[ra]); + break; + + case 311: // lhzux + r[ra] += r[rb]; + r[rd] = ReadMacInt16(r[ra]); + break; + + case 316: // xor + r[ra] = r[rd] ^ r[rb]; + if (op & 1) + record(r[ra]); + break; + + case 339: { // mfspr + uint32 spr = ra | (rb << 5); + switch (spr) { + case 1: r[rd] = xer; break; + case 8: r[rd] = lr; break; + case 9: r[rd] = ctr; break; + default: + printf("Illegal mfspr opcode %08x at %08x\n", op, pc-4); + dump(); + } + break; + } + + case 343: // lhax + r[rd] = (int32)(int16)ReadMacInt16(r[rb] + (ra ? r[ra] : 0)); + break; + + case 371: // mftb + r[rd] = 0; //!! + break; + + case 375: // lhaux + r[ra] += r[rb]; + r[rd] = (int32)(int16)ReadMacInt16(r[ra]); + break; + + case 407: // sthx + WriteMacInt16(r[rb] + (ra ? r[ra] : 0), r[rd]); + break; + + case 412: // orc + r[ra] = r[rd] | ~r[rb]; + if (op & 1) + record(r[ra]); + break; + + case 439: // sthux + r[ra] += r[rb]; + WriteMacInt16(r[ra], r[rd]); + break; + + case 444: // or + r[ra] = r[rd] | r[rb]; + if (op & 1) + record(r[ra]); + break; + + case 459: // divwu + if (r[rb]) + r[rd] = r[ra] / r[rb]; + if (op & 1) + record(r[rd]); + break; + + case 467: { // mtspr + uint32 spr = ra | (rb << 5); + switch (spr) { + case 1: xer = r[rd] & 0xe000007f; break; + case 8: lr = r[rd]; break; + case 9: ctr = r[rd]; break; + default: + printf("Illegal mtspr opcode %08x at %08x\n", op, pc-4); + dump(); + } + break; + } + + case 476: // nand + r[ra] = ~(r[rd] & r[rb]); + if (op & 1) + record(r[ra]); + break; + + case 491: // divw + if (r[rb]) + r[rd] = (int32)r[ra] / (int32)r[rb]; + if (op & 1) + record(r[rd]); + break; + + case 520: { // subfco + uint64 tmp = (uint64)r[rb] - (uint64)r[ra]; + uint32 ov = (r[ra] ^ r[rb]) & ((uint32)tmp ^ r[rb]); + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer &= ~0x20000000; + else + xer |= 0x20000000; + if (ov & 0x80000000) + xer |= 0xc0000000; + else + xer &= ~0x40000000; + if (op & 1) + record(r[rd]); + break; + } + + case 522: { // addco + uint64 tmp = (uint64)r[ra] + (uint64)r[rb]; + uint32 ov = (r[ra] ^ (uint32)tmp) & (r[rb] ^ (uint32)tmp); + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer |= 0x20000000; + else + xer &= ~0x20000000; + if (ov & 0x80000000) + xer |= 0xc0000000; + else + xer &= ~0x40000000; + if (op & 1) + record(r[rd]); + break; + } + + case 533: { // lswx + uint32 addr = r[rb] + (ra ? r[ra] : 0); + int nb = xer & 0x7f; + int reg = rd; + for (int i=0; i> (r[rb] & 0x3f); + if (op & 1) + record(r[ra]); + break; + + case 597: { // lswi + uint32 addr = ra ? r[ra] : 0; + int nb = rb ? rb : 32; + int reg = rd; + for (int i=0; i> shift)); + shift -= 8; + if ((i & 3) == 3) { + shift = 24; + reg = (reg + 1) & 0x1f; + } + } + break; + } + + case 725: { // stswi + uint32 addr = ra ? r[ra] : 0; + int nb = rb ? rb : 32; + int reg = rd; + int shift = 24; + for (int i=0; i> shift)); + shift -= 8; + if ((i & 3) == 3) { + shift = 24; + reg = (reg + 1) & 0x1f; + } + } + break; + } + + case 778: { // addo + uint32 tmp = r[ra] + r[rb]; + uint32 ov = (r[ra] ^ tmp) & (r[rb] ^ tmp); + r[rd] = tmp; + if (ov & 0x80000000) + xer |= 0xc0000000; + else + xer &= ~0x40000000; + if (op & 1) + record(r[rd]); + break; + } + + case 792: { // sraw + uint32 sh = r[rb] & 0x3f; + uint32 mask = ~(0xffffffff << sh); + if ((r[rd] & 0x80000000) && (r[rd] & mask)) + xer |= 0x20000000; + else + xer &= ~0x20000000; + r[ra] = (int32)r[rd] >> sh; + if (op & 1) + record(r[ra]); + break; + } + + case 824: { // srawi + uint32 mask = ~(0xffffffff << rb); + if ((r[rd] & 0x80000000) && (r[rd] & mask)) + xer |= 0x20000000; + else + xer &= ~0x20000000; + r[ra] = (int32)r[rd] >> rb; + if (op & 1) + record(r[ra]); + break; + } + + case 854: // eieio + break; + + case 922: // extsh + r[ra] = (int32)(int16)r[rd]; + if (op & 1) + record(r[ra]); + break; + + case 954: // extsb + r[ra] = (int32)(int8)r[rd]; + if (op & 1) + record(r[ra]); + break; + + case 982: // icbi + break; + + case 1003: // divwo + if (r[rb] == 0 || (r[ra] == 0x80000000 && r[rb] == 0xffffffff)) + xer |= 0xc0000000; + else { + r[rd] = (int32)r[ra] / (int32)r[rb]; + xer &= ~0x40000000; + } + if (op & 1) + record(r[rd]); + break; + +#if 0 + case 1014: // dcbz + memset(r[rb] + (ra ? r[ra] : 0), 0, 32); + break; +#endif + + default: + printf("Illegal 31 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); + dump(); + break; + } +} + + +/* + * Emulate instruction with primary opcode = 59 + */ + +static void emul59(uint32 op) +{ + uint32 exop = (op >> 1) & 0x3ff; + switch (exop) { + default: + printf("Illegal 59 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); + dump(); + break; + } +} + + +/* + * Emulate instruction with primary opcode = 63 + */ + +static void emul63(uint32 op) +{ + uint32 exop = (op >> 1) & 0x3ff; + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint32 rb = (op >> 11) & 0x1f; + switch (exop) { + + case 583: // mffs + fr[rd] = (double)(uint64)fpscr; + if (op & 1) + record1(); + break; + + case 711: // mtfsf + //!! + if (op & 1) + record1(); + break; + + default: + printf("Illegal 63 opcode %08x (exop %d) at %08x\n", op, exop, pc-4); + dump(); + break; + } +} + + +/* + * Emulation loop + */ + +void emul_ppc(uint32 start) +{ + pc = start; +//uint32 old_val = 0; + for (;;) { +//uint32 val = ReadMacInt32(0x68fff778); +//if (val != old_val) { +// printf("insn at %08lx changed %08lx->%08lx\n", pc-4, old_val, val); +// old_val = val; +//} + uint32 op = ReadMacInt32(pc); +#if FLIGHT_RECORDER + record_step(op); +#endif +// printf("%08lx at %08lx\n", op, pc); + uint32 primop = op >> 26; + pc += 4; + switch (primop) { + + case 6: // SheepShaver extensions + printf("Extended opcode %08x at %08x (68k pc %08x)\n", op, pc-4, r[24]); + switch (op & 0x3f) { + case 0: // EMUL_RETURN + QuitEmulator(); + break; + + case 1: // EXEC_RETURN + //!! + dump(); + break; + + default: { // EMUL_OP + M68kRegisters r68; + WriteMacInt32(XLM_68K_R25, r[25]); + WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP); + for (int i=0; i<8; i++) + r68.d[i] = r[8 + i]; + for (int i=0; i<7; i++) + r68.a[i] = r[16 + i]; + r68.a[7] = r[1]; + EmulOp(&r68, r[24], (op & 0x3f) - 2); + for (int i=0; i<8; i++) + r[8 + i] = r68.d[i]; + for (int i=0; i<7; i++) + r[16 + i] = r68.a[i]; + r[1] = r68.a[7]; + WriteMacInt32(XLM_RUN_MODE, MODE_68K); + break; + } + } + break; + + case 7: { // mulli + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[rd] = (int32)r[ra] * (int32)(int16)(op & 0xffff); + break; + } + + case 8: { // subfic + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint64 tmp = (uint32)(int32)(int16)(op & 0xffff) - (uint64)r[ra]; + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer &= ~0x20000000; + else + xer |= 0x20000000; + break; + } + + case 10: { // cmpli + uint32 crfd = 0x1c - ((op >> 21) & 0x1c); + uint32 ra = (op >> 16) & 0x1f; + uint32 val = (op & 0xffff); + uint8 crf = 0; + if (r[ra] == val) + crf |= 2; + else if (r[ra] < val) + crf |= 8; + else + crf |= 4; + if (xer & 0x80000000) + crf |= 1; + cr = (cr & ~(0xf << crfd)) | (crf << crfd); + break; + } + + case 11: { // cmpi + uint32 crfd = 0x1c - ((op >> 21) & 0x1c); + uint32 ra = (op >> 16) & 0x1f; + int32 val = (int32)(int16)(op & 0xffff); + uint8 crf = 0; + if ((int32)r[ra] == val) + crf |= 2; + else if ((int32)r[ra] < val) + crf |= 8; + else + crf |= 4; + if (xer & 0x80000000) + crf |= 1; + cr = (cr & ~(0xf << crfd)) | (crf << crfd); + break; + } + + case 12: { // addic + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint64 tmp = (uint64)r[ra] + (uint32)(int32)(int16)(op & 0xffff); + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer |= 0x20000000; + else + xer &= ~0x20000000; + break; + } + + case 13: { // addic. + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint64 tmp = (uint64)r[ra] + (uint32)(int32)(int16)(op & 0xffff); + r[rd] = tmp; + if (tmp & 0x100000000LL) + xer |= 0x20000000; + else + xer &= ~0x20000000; + record(r[rd]); + break; + } + + case 14: { // addi + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[rd] = (ra ? r[ra] : 0) + (int32)(int16)(op & 0xffff); + break; + } + + case 15: { // addis + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[rd] = (ra ? r[ra] : 0) + (op << 16); + break; + } + + case 16: { // bc + uint32 bo = (op >> 21) & 0x1f; + uint32 bi = (op >> 16) & 0x1f; + if (op & 1) + lr = pc; + if (!(bo & 4)) { + ctr--; + if (bo & 2) { + if (ctr) + goto bc_nobranch; + } else { + if (!ctr) + goto bc_nobranch; + } + } + if (!(bo & 0x10)) { + if (bo & 8) { + if (!(cr & (0x80000000 >> bi))) + goto bc_nobranch; + } else { + if (cr & (0x80000000 >> bi)) + goto bc_nobranch; + } + } + if (op & 2) + pc = (int32)(int16)(op & 0xfffc); + else + pc += (int32)(int16)(op & 0xfffc) - 4; +bc_nobranch: + break; + } + + case 18: { // b + int32 target = op & 0x03fffffc; + if (target & 0x02000000) + target |= 0xfc000000; + if (op & 1) + lr = pc; + if (op & 2) + pc = target; + else + pc += target - 4; + break; + } + + case 19: + emul19(op); + break; + + case 20: { // rlwimi + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint32 sh = (op >> 11) & 0x1f; + uint32 mask = mbme2mask(op); + r[ra] = (((r[rs] << sh) | (r[rs] >> (32-sh))) & mask) | (r[ra] & ~mask); + if (op & 1) + record(r[ra]); + break; + } + + case 21: { // rlwinm + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint32 sh = (op >> 11) & 0x1f; + r[ra] = ((r[rs] << sh) | (r[rs] >> (32-sh))) & mbme2mask(op); + if (op & 1) + record(r[ra]); + break; + } + + case 23: { // rlwnm + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint32 sh = r[(op >> 11) & 0x1f] & 0x1f; + r[ra] = ((r[rs] << sh) | (r[rs] >> (32-sh))) & mbme2mask(op); + if (op & 1) + record(r[ra]); + break; + } + + case 24: { // ori + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] = r[rs] | (op & 0xffff); + break; + } + + case 25: { // oris + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] = r[rs] | (op << 16); + break; + } + + case 26: { // xori + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] = r[rs] ^ (op & 0xffff); + break; + } + + case 27: { // xoris + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] = r[rs] ^ (op << 16); + break; + } + + case 28: { // andi. + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] = r[rs] & (op & 0xffff); + record(r[ra]); + break; + } + + case 29: { // andis. + uint32 rs = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] = r[rs] & (op << 16); + record(r[ra]); + break; + } + + case 31: + emul31(op); + break; + + case 32: { // lwz + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[rd] = ReadMacInt32(int16(op & 0xffff) + (ra ? r[ra] : 0)); + break; + } + + case 33: { // lwzu + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] += int16(op & 0xffff); + r[rd] = ReadMacInt32(r[ra]); + break; + } + + case 34: { // lbz + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[rd] = ReadMacInt8(int16(op & 0xffff) + (ra ? r[ra] : 0)); + break; + } + + case 35: { // lbzu + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] += int16(op & 0xffff); + r[rd] = ReadMacInt8(r[ra]); + break; + } + + case 36: { // stw + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + WriteMacInt32(int16(op & 0xffff) + (ra ? r[ra] : 0), r[rd]); + break; + } + + case 37: { // stwu + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] += int16(op & 0xffff); + WriteMacInt32(r[ra], r[rd]); + break; + } + + case 38: { // stb + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + WriteMacInt8(int16(op & 0xffff) + (ra ? r[ra] : 0), r[rd]); + break; + } + + case 39: { // stbu + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] += int16(op & 0xffff); + WriteMacInt8(r[ra], r[rd]); + break; + } + + case 40: { // lhz + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[rd] = ReadMacInt16(int16(op & 0xffff) + (ra ? r[ra] : 0)); + break; + } + + case 41: { // lhzu + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] += int16(op & 0xffff); + r[rd] = ReadMacInt16(r[ra]); + break; + } + + case 42: { // lha + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[rd] = (int32)(int16)ReadMacInt16(int16(op & 0xffff) + (ra ? r[ra] : 0)); + break; + } + + case 43: { // lhau + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] += int16(op & 0xffff); + r[rd] = (int32)(int16)ReadMacInt16(r[ra]); + break; + } + + case 44: { // sth + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + WriteMacInt16(int16(op & 0xffff) + (ra ? r[ra] : 0), r[rd]); + break; + } + + case 45: { // sthu + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + r[ra] += int16(op & 0xffff); + WriteMacInt16(r[ra], r[rd]); + break; + } + + case 46: { // lmw + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint32 addr = int16(op & 0xffff) + (ra ? r[ra] : 0); + while (rd <= 31) { + r[rd] = ReadMacInt32(addr); + rd++; + addr += 4; + } + break; + } + + case 47: { // stmw + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + uint32 addr = int16(op & 0xffff) + (ra ? r[ra] : 0); + while (rd <= 31) { + WriteMacInt32(addr, r[rd]); + rd++; + addr += 4; + } + break; + } + + case 50: { // lfd + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + fr[rd] = (double)ReadMacInt64(int16(op & 0xffff) + (ra ? r[ra] : 0)); + break; + } + + case 54: { // stfd + uint32 rd = (op >> 21) & 0x1f; + uint32 ra = (op >> 16) & 0x1f; + WriteMacInt64(int16(op & 0xffff) + (ra ? r[ra] : 0), (uint64)fr[rd]); + break; + } + + case 59: + emul59(op); + break; + + case 63: + emul63(op); + break; + + default: + printf("Illegal opcode %08x at %08x\n", op, pc-4); + dump(); + break; + } + } +} + + +static struct sigaction sigsegv_action; + +static void sigsegv_handler(int sig) +{ + printf("SIGSEGV\n"); + dump(); +} + +void init_emul_ppc(void) +{ + // Init field2mask + for (int i=0; i<256; i++) { + uint32 mask = 0; + if (i & 0x01) mask |= 0x0000000f; + if (i & 0x02) mask |= 0x000000f0; + if (i & 0x04) mask |= 0x00000f00; + if (i & 0x08) mask |= 0x0000f000; + if (i & 0x10) mask |= 0x000f0000; + if (i & 0x20) mask |= 0x00f00000; + if (i & 0x40) mask |= 0x0f000000; + if (i & 0x80) mask |= 0xf0000000; + field2mask[i] = mask; + } + + // Init registers + for (int i=0; i<32; i++) { + r[i] = 0; + fr[i] = 0.0; + } + lr = ctr = 0; + cr = xer = 0; + fpscr = 0; + + r[3] = ROM_BASE + 0x30d000; + + // Install SIGSEGV handler + sigemptyset(&sigsegv_action.sa_mask); + sigsegv_action.sa_handler = (__sighandler_t)sigsegv_handler; + sigsegv_action.sa_flags = 0; + sigsegv_action.sa_restorer = NULL; + sigaction(SIGSEGV, &sigsegv_action, NULL); + +#if FLIGHT_RECORDER && ENABLE_MON + // Install "log" command in mon + mon_add_command("log", dump_log, "log Dump PowerPC emulation log\n"); +#endif +} + + +/* + * Execute 68k subroutine (must be ended with EXEC_RETURN) + * This must only be called by the emul_thread when in EMUL_OP mode + * r->a[7] is unused, the routine runs on the caller's stack + */ + +void Execute68k(uint32 pc, M68kRegisters *r) +{ + printf("ERROR: Execute68k() unimplemented\n"); + QuitEmulator(); +} + + +/* + * Execute 68k A-Trap from EMUL_OP routine + * r->a[7] is unused, the routine runs on the caller's stack + */ + +void Execute68kTrap(uint16 trap, M68kRegisters *r) +{ + printf("ERROR: Execute68kTrap() unimplemented\n"); + QuitEmulator(); +} + + +/* + * Call MacOS PPC code + */ + +uint32 call_macos(uint32 tvect) +{ + printf("ERROR: call_macos() unimplemented\n"); + QuitEmulator(); + return 0; +} + +uint32 call_macos1(uint32 tvect, uint32 arg1) +{ + printf("ERROR: call_macos1() unimplemented\n"); + QuitEmulator(); + return 0; +} + +uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2) +{ + printf("ERROR: call_macos2() unimplemented\n"); + QuitEmulator(); + return 0; +} + +uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3) +{ + printf("ERROR: call_macos3() unimplemented\n"); + QuitEmulator(); + return 0; +} + +uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4) +{ + printf("ERROR: call_macos4() unimplemented\n"); + QuitEmulator(); + return 0; +} + +uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5) +{ + printf("ERROR: call_macos5() unimplemented\n"); + QuitEmulator(); + return 0; +} + +uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6) +{ + printf("ERROR: call_macos6() unimplemented\n"); + QuitEmulator(); + return 0; +} + +uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7) +{ + printf("ERROR: call_macos7() unimplemented\n"); + QuitEmulator(); + return 0; +} + + +/* + * Atomic operations + */ + +extern int atomic_add(int *var, int v) +{ + int ret = *var; + *var += v; + return ret; +} + +extern int atomic_and(int *var, int v) +{ + int ret = *var; + *var &= v; + return ret; +} + +extern int atomic_or(int *var, int v) +{ + int ret = *var; + *var |= v; + return ret; +} + + +extern "C" void get_resource(void); +extern "C" void get_1_resource(void); +extern "C" void get_ind_resource(void); +extern "C" void get_1_ind_resource(void); +extern "C" void r_get_resource(void); + +void get_resource(void) +{ + printf("ERROR: get_resource() unimplemented\n"); + QuitEmulator(); +} + +void get_1_resource(void) +{ + printf("ERROR: get_1_resource() unimplemented\n"); + QuitEmulator(); +} + +void get_ind_resource(void) +{ + printf("ERROR: get_ind_resource() unimplemented\n"); + QuitEmulator(); +} + +void get_1_ind_resource(void) +{ + printf("ERROR: get_1_ind_resource() unimplemented\n"); + QuitEmulator(); +} + +void r_get_resource(void) +{ + printf("ERROR: r_get_resource() unimplemented\n"); + QuitEmulator(); +} diff --git a/SheepShaver/src/ether.cpp b/SheepShaver/src/ether.cpp new file mode 100644 index 00000000..16ae179c --- /dev/null +++ b/SheepShaver/src/ether.cpp @@ -0,0 +1,1632 @@ +/* + * ether.cpp - SheepShaver Ethernet Device Driver (DLPI) + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * 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 + */ + +/* + * TODO + * - 802.2 TEST/XID + * - MIB statistics + */ + +#include + +#include "sysdeps.h" +#include "ether.h" +#include "ether_defs.h" +#include "macos_util.h" +#include "cpu_emulation.h" +#include "emul_op.h" +#include "main.h" + +#define DEBUG 0 +#include "debug.h" + + +// Packet types +enum { + kPktDIX = 0, + kPkt8022SAP = 1, + kPkt8022GroupSAP = 2, + kPkt8022SNAP = 3, + kPktIPX = 4, + kPktUnknown = 5 +}; + + +/* + * Stream private data structure + */ + +static const int kGroupSAPMapSize = 128/32; // Number of 32-bit values we need for 128 bits +static const int kGSshift = 6; +static const int kGSmask = 0x1F; + +struct multicast_node { + multicast_node *next; + uint8 addr[kEnetPhysicalAddressLength]; +}; + +struct DLPIStream { + void SetGroupSAP(uint8 sap) + { + group_sap[sap >> kGSshift] |= (1L << ((sap >> 1) & kGSmask)); + } + + void ClearGroupSAP(uint8 sap) + { + group_sap[sap >> kGSshift] &= ~(1L << ((sap >> 1) & kGSmask)); + } + + void ClearAllGroupSAPs(void) + { + for (int i=0; i> kGSshift] & (1L << ((sap >> 1) & kGSmask)); + } + + void AddMulticast(uint8 *addr) + { + multicast_node *n = new multicast_node; + memcpy(n->addr, addr, kEnetPhysicalAddressLength); + n->next = multicast_list; + multicast_list = n; + } + + void RemoveMulticast(uint8 *addr) + { + multicast_node *p = multicast_list; + while (p) { + if (memcmp(addr, p->addr, kEnetPhysicalAddressLength) == 0) + goto found; + p = p->next; + } + return; + found: + multicast_node *q = (multicast_node *)&multicast_list; + while (q) { + if (q->next == p) { + q->next = p->next; + delete p; + return; + } + q = q->next; + } + } + + uint8 *IsMulticastRegistered(uint8 *addr) + { + multicast_node *n = multicast_list; + while (n) { + if (memcmp(addr, n->addr, kEnetPhysicalAddressLength) == 0) + return n->addr; + n = n->next; + } + return NULL; + } + + uint32 minor_num; // Minor device number of this stream + uint32 dlpi_state; // DLPI state of this stream + uint32 flags; // Flags + uint16 dlsap; // SAP bound to this stream + bool framing_8022; // Using 802.2 framing? This is only used to report the MAC type for DL_INFO_ACK and can be set with an ioctl() call + queue_t *rdq; // Read queue for this stream + uint32 group_sap[kGroupSAPMapSize]; // Map of bound group SAPs + uint8 snap[k8022SNAPLength]; // SNAP bound to this stream + multicast_node *multicast_list; // List of enabled multicast addresses +}; + +// Stream flags +enum { + kSnapStream = 0x00000001, + kAcceptMulticasts = 0x00000002, + kAcceptAll8022Packets = 0x00000004, + kFastPathMode = 0x00000008 +}; + +// List of opened streams (used internally by OpenTransport) +static DLPIStream *dlpi_stream_list = NULL; + +// Are we open? +bool ether_driver_opened = false; + +// Our ethernet hardware address +static uint8 hardware_address[6] = {0, 0, 0, 0, 0, 0}; + +// Statistics +int32 num_wput = 0; +int32 num_error_acks = 0; +int32 num_tx_packets = 0; +int32 num_tx_raw_packets = 0; +int32 num_tx_normal_packets = 0; +int32 num_tx_buffer_full = 0; +int32 num_rx_packets = 0; +int32 num_ether_irq = 0; +int32 num_unitdata_ind = 0; +int32 num_rx_fastpath = 0; +int32 num_rx_no_mem = 0; +int32 num_rx_dropped = 0; +int32 num_rx_stream_not_ready = 0; +int32 num_rx_no_unitdata_mem = 0; + + +// Function pointers of imported functions +typedef mblk_t *(*allocb_ptr)(size_t size, int pri); +static uint32 allocb_tvect = 0; +mblk_t *allocb(size_t arg1, int arg2) +{ + return (mblk_t *)CallMacOS2(allocb_ptr, allocb_tvect, arg1, arg2); +} +typedef void (*freeb_ptr)(mblk_t *); +static uint32 freeb_tvect = 0; +static inline void freeb(mblk_t *arg1) +{ + CallMacOS1(freeb_ptr, freeb_tvect, arg1); +} +typedef int16 (*freemsg_ptr)(mblk_t *); +static uint32 freemsg_tvect = 0; +static inline int16 freemsg(mblk_t *arg1) +{ + return (int16)CallMacOS1(freemsg_ptr, freemsg_tvect, arg1); +} +typedef mblk_t *(*copyb_ptr)(mblk_t *); +static uint32 copyb_tvect = 0; +static inline mblk_t *copyb(mblk_t *arg1) +{ + return (mblk_t *)CallMacOS1(copyb_ptr, copyb_tvect, arg1); +} +typedef mblk_t *(*dupmsg_ptr)(mblk_t *); +static uint32 dupmsg_tvect = 0; +static inline mblk_t *dupmsg(mblk_t *arg1) +{ + return (mblk_t *)CallMacOS1(dupmsg_ptr, dupmsg_tvect, arg1); +} +typedef mblk_t *(*getq_ptr)(queue_t *); +static uint32 getq_tvect = 0; +static inline mblk_t *getq(queue_t *arg1) +{ + return (mblk_t *)CallMacOS1(getq_ptr, getq_tvect, arg1); +} +typedef int (*putq_ptr)(queue_t *, mblk_t *); +static uint32 putq_tvect = 0; +static inline int putq(queue_t *arg1, mblk_t *arg2) +{ + return (int)CallMacOS2(putq_ptr, putq_tvect, arg1, arg2); +} +typedef int (*putnext_ptr)(queue_t *, mblk_t *); +static uint32 putnext_tvect = 0; +static inline int putnext(queue_t *arg1, mblk_t *arg2) +{ + return (int)CallMacOS2(putnext_ptr, putnext_tvect, arg1, arg2); +} +typedef int (*putnextctl1_ptr)(queue_t *, int type, int c); +static uint32 putnextctl1_tvect = 0; +static inline int putnextctl1(queue_t *arg1, int arg2, int arg3) +{ + return (int)CallMacOS3(putnextctl1_ptr, putnextctl1_tvect, arg1, arg2, arg3); +} +typedef int (*canputnext_ptr)(queue_t *); +static uint32 canputnext_tvect = 0; +static inline int canputnext(queue_t *arg1) +{ + return (int)CallMacOS1(canputnext_ptr, canputnext_tvect, arg1); +} +typedef int (*qreply_ptr)(queue_t *, mblk_t *); +static uint32 qreply_tvect = 0; +static inline int qreply(queue_t *arg1, mblk_t *arg2) +{ + return (int)CallMacOS2(qreply_ptr, qreply_tvect, arg1, arg2); +} +typedef void (*flushq_ptr)(queue_t *, int flag); +static uint32 flushq_tvect = 0; +static inline void flushq(queue_t *arg1, int arg2) +{ + CallMacOS2(flushq_ptr, flushq_tvect, arg1, arg2); +} +typedef int (*msgdsize_ptr)(const mblk_t *); +static uint32 msgdsize_tvect = 0; +static inline int msgdsize(const mblk_t *arg1) +{ + return (int)CallMacOS1(msgdsize_ptr, msgdsize_tvect, arg1); +} +typedef void (*otenterint_ptr)(void); +static uint32 otenterint_tvect = 0; +void OTEnterInterrupt(void) +{ + CallMacOS(otenterint_ptr, otenterint_tvect); +} +typedef void (*otleaveint_ptr)(void); +static uint32 otleaveint_tvect = 0; +void OTLeaveInterrupt(void) +{ + CallMacOS(otleaveint_ptr, otleaveint_tvect); +} +typedef int (*mi_open_comm_ptr)(DLPIStream **mi_opp_orig, size_t size, queue_t *q, void *dev, int flag, int sflag, void *credp); +static uint32 mi_open_comm_tvect = 0; +static inline int mi_open_comm(DLPIStream **arg1, size_t arg2, queue_t *arg3, void *arg4, int arg5, int arg6, void *arg7) +{ + return (int)CallMacOS7(mi_open_comm_ptr, mi_open_comm_tvect, arg1, arg2, arg3, arg4, arg5, arg6, arg7); +} +typedef int (*mi_close_comm_ptr)(DLPIStream **mi_opp_orig, queue_t *q); +static uint32 mi_close_comm_tvect = 0; +static inline int mi_close_comm(DLPIStream **arg1, queue_t *arg2) +{ + return (int)CallMacOS2(mi_close_comm_ptr, mi_close_comm_tvect, arg1, arg2); +} +typedef DLPIStream *(*mi_next_ptr_ptr)(DLPIStream *); +static uint32 mi_next_ptr_tvect = 0; +static inline DLPIStream *mi_next_ptr(DLPIStream *arg1) +{ + return (DLPIStream *)CallMacOS1(mi_next_ptr_ptr, mi_next_ptr_tvect, arg1); +} + + +// Prototypes +static void ether_ioctl(DLPIStream *the_stream, queue_t* q, mblk_t* mp); +static void ether_flush(queue_t* q, mblk_t* mp); +static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path); +static void transmit_packet(mblk_t *mp); +static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr); +static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim); +static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp); + + +/* + * Initialize ethernet stream module + */ + +uint8 InitStreamModule(void *theID) +{ + D(bug("InitStreamModule\n")); + + // Don't re-open if already open + if (ether_driver_opened) + return true; + ether_driver_opened = false; + + // Import functions from OTKernelLib + allocb_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006allocb"); + D(bug("allocb TVECT at %08lx\n", allocb_tvect)); + if (allocb_tvect == 0) + return false; + freeb_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\005freeb"); + D(bug("freeb TVECT at %08lx\n", freeb_tvect)); + if (freeb_tvect == 0) + return false; + freemsg_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\007freemsg"); + D(bug("freemsg TVECT at %08lx\n", freemsg_tvect)); + if (freemsg_tvect == 0) + return false; + copyb_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\005copyb"); + D(bug("copyb TVECT at %08lx\n", copyb_tvect)); + if (copyb_tvect == 0) + return false; + dupmsg_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006dupmsg"); + D(bug("dupmsg TVECT at %08lx\n", dupmsg_tvect)); + if (dupmsg_tvect == 0) + return false; + getq_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\004getq"); + D(bug("getq TVECT at %08lx\n", getq_tvect)); + if (getq_tvect == 0) + return false; + putq_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\004putq"); + D(bug("putq TVECT at %08lx\n", putq_tvect)); + if (putq_tvect == 0) + return false; + putnext_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\007putnext"); + D(bug("putnext TVECT at %08lx\n", putnext_tvect)); + if (putnext_tvect == 0) + return false; + putnextctl1_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\013putnextctl1"); + D(bug("putnextctl1 TVECT at %08lx\n", putnextctl1_tvect)); + if (putnextctl1_tvect == 0) + return false; + canputnext_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\012canputnext"); + D(bug("canputnext TVECT at %08lx\n", canputnext_tvect)); + if (canputnext_tvect == 0) + return false; + qreply_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006qreply"); + D(bug("qreply TVECT at %08lx\n", qreply_tvect)); + if (qreply_tvect == 0) + return false; + flushq_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\006flushq"); + D(bug("flushq TVECT at %08lx\n", flushq_tvect)); + if (flushq_tvect == 0) + return false; + msgdsize_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\010msgdsize"); + D(bug("msgdsize TVECT at %08lx\n", msgdsize_tvect)); + if (msgdsize_tvect == 0) + return false; + otenterint_tvect = (uint32)FindLibSymbol("\017OTKernelUtilLib", "\020OTEnterInterrupt"); + D(bug("OTEnterInterrupt TVECT at %08lx\n", otenterint_tvect)); + if (otenterint_tvect == 0) + return false; + otleaveint_tvect = (uint32)FindLibSymbol("\017OTKernelUtilLib", "\020OTLeaveInterrupt"); + D(bug("OTLeaveInterrupt TVECT at %08lx\n", otleaveint_tvect)); + if (otleaveint_tvect == 0) + return false; + mi_open_comm_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\014mi_open_comm"); + D(bug("mi_open_comm TVECT at %08lx\n", mi_open_comm_tvect)); + if (mi_open_comm_tvect == 0) + return false; + mi_close_comm_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\015mi_close_comm"); + D(bug("mi_close_comm TVECT at %08lx\n", mi_close_comm_tvect)); + if (mi_close_comm_tvect == 0) + return false; + mi_next_ptr_tvect = (uint32)FindLibSymbol("\013OTKernelLib", "\013mi_next_ptr"); + D(bug("mi_next_ptr TVECT at %08lx\n", mi_next_ptr_tvect)); + if (mi_next_ptr_tvect == 0) + return false; + + // Initialize stream list (which might be leftover) + dlpi_stream_list = NULL; + + // Ask add-on for ethernet hardware address + AO_get_ethernet_address(hardware_address); + + // Yes, we're open + ether_driver_opened = true; + return true; +} + + +/* + * Terminate ethernet stream module + */ + +void TerminateStreamModule(void) +{ + D(bug("TerminateStreamModule\n")); + + // This happens sometimes. I don't know why. + if (dlpi_stream_list != NULL) + printf("FATAL: TerminateStreamModule() called, but streams still open\n"); + + // Sorry, we're closed + ether_driver_opened = false; +} + + +/* + * Open new stream + */ + +int ether_open(queue_t *rdq, void *dev, int flag, int sflag, void *creds) +{ + D(bug("ether_open(%p,%p,%d,%d,%p)\n", rdq, dev, flag, sflag, creds)); + + // Return if driver was closed + if (!ether_driver_opened) { + printf("FATAL: ether_open(): Ethernet driver not opened\n"); + return MAC_ENXIO; + } + + // If we're being reopened, just return + if (rdq->q_ptr != NULL) + return 0; + + // Allocate DLPIStream structure + int err = mi_open_comm(&dlpi_stream_list, sizeof(DLPIStream), rdq, dev, flag, sflag, creds); + if (err) + return err; + DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr; + the_stream->rdq = rdq; + the_stream->dlpi_state = DL_UNBOUND; + the_stream->flags = 0; + the_stream->dlsap = 0; + the_stream->framing_8022 = false; + the_stream->multicast_list = NULL; + return 0; +} + + +/* + * Close stream + */ + +int ether_close(queue_t *rdq, int flag, void *creds) +{ + D(bug("ether_close(%p,%d,%p)\n", rdq, flag, creds)); + + // Return if driver was closed + if (!ether_driver_opened) { + printf("FATAL: ether_close(): Ethernet driver not opened\n"); + return MAC_ENXIO; + } + + // Get stream + DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr; + + // Don't close if never opened + if (the_stream == NULL) + return 0; + + // Disable all registered multicast addresses + while (the_stream->multicast_list) { + AO_disable_multicast(the_stream->multicast_list->addr); + the_stream->RemoveMulticast(the_stream->multicast_list->addr); + } + the_stream->multicast_list = NULL; + + // Delete the DLPIStream + return mi_close_comm(&dlpi_stream_list, rdq); +} + + +/* + * Put something on the write queue + */ + +int ether_wput(queue_t *q, mblk_t *mp) +{ + D(bug("ether_wput(%p,%p)\n", q, mp)); + + // Return if driver was closed + if (!ether_driver_opened) { + printf("FATAL: ether_wput(): Ethernet driver not opened\n"); + return MAC_ENXIO; + } + + // Get stream + DLPIStream *the_stream = (DLPIStream *)q->q_ptr; + if (the_stream == NULL) + return MAC_ENXIO; + + D(bug(" db_type %d\n", mp->b_datap->db_type)); + switch (mp->b_datap->db_type) { + + case M_DATA: + // Transmit raw packet + D(bug(" raw packet\n")); + num_tx_raw_packets++; + transmit_packet(mp); + break; + + case M_PROTO: + case M_PCPROTO: { + union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr; + uint32 prim = dlp->dl_primitive; + D(bug(" dl_primitive %d\n", prim)); + switch (prim) { + case DL_UNITDATA_REQ: + // Transmit normal packet + num_tx_normal_packets++; + DLPI_unit_data(the_stream, q, mp); + break; + + case DL_INFO_REQ: + DLPI_info(the_stream, q, mp); + break; + + case DL_PHYS_ADDR_REQ: + DLPI_phys_addr(the_stream, q, mp); + break; + + case DL_BIND_REQ: + DLPI_bind(the_stream, q, mp); + break; + + case DL_UNBIND_REQ: + DLPI_unbind(the_stream, q, mp); + break; + + case DL_SUBS_BIND_REQ: + DLPI_subs_bind(the_stream, q, mp); + break; + + case DL_SUBS_UNBIND_REQ: + DLPI_subs_unbind(the_stream, q, mp); + break; + + case DL_ENABMULTI_REQ: + DLPI_enable_multi(the_stream, q, mp); + break; + + case DL_DISABMULTI_REQ: + DLPI_disable_multi(the_stream, q, mp); + break; + + default: + D(bug("WARNING: ether_wsrv(): Unknown primitive\n")); + DLPI_error_ack(the_stream, q, mp, prim, DL_NOTSUPPORTED, 0); + break; + } + break; + } + + case M_IOCTL: + ether_ioctl(the_stream, q, mp); + break; + + case M_FLUSH: + ether_flush(q, mp); + break; + + default: + D(bug("WARNING: ether_wput(): Unknown message type\n")); + freemsg(mp); + break; + } + num_wput++; + return 0; +} + + +/* + * Dequeue and process messages from the read queue + */ + +int ether_rsrv(queue_t *q) +{ + mblk_t *mp; + while ((mp = getq(q)) != NULL) { + if (canputnext(q)) + putnext(q, mp); + else { + freemsg(mp); + flushq(q, FLUSHDATA); + break; + } + } + return 0; +} + + +/* + * Handle ioctl calls + */ + +static void ether_ioctl(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + struct iocblk *ioc = (struct iocblk *)mp->b_rptr; + D(bug(" ether_ioctl(%p,%p) cmd %d\n", q, mp, ioc->ioc_cmd)); + + switch (ioc->ioc_cmd) { + + case I_OTSetFramingType: { // Toggles what the general info primitive returns for dl_mac_type in dl_info_ack_t structure + mblk_t *info_mp = mp->b_cont; + if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(uint32))) { + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + uint32 framing_type = *(uint32 *)info_mp->b_rptr; + D(bug(" I_OTSetFramingType type %d\n", framing_type)); + if (framing_type != kOTGetFramingValue) + the_stream->framing_8022 = (framing_type == kOTFraming8022); + mp->b_cont = NULL; + freemsg(info_mp); + if (the_stream->framing_8022) + ioc->ioc_rval = kOTFraming8022; + else + ioc->ioc_rval = kOTFramingEthernet; + goto ioctl_ok; + } + + case DL_IOC_HDR_INFO: { // Special Mentat call, for fast transmits + D(bug(" DL_IOC_HDR_INFO\n")); + mblk_t *info_mp = mp->b_cont; + + // Copy DL_UNITDATA_REQ block + mblk_t *unitdata_mp = copyb(info_mp); + if (unitdata_mp == NULL) { + ioc->ioc_error = MAC_ENOMEM; + goto ioctl_error; + } + unitdata_mp->b_datap->db_type = M_PROTO; + + // Construct header (converts DL_UNITDATA_REQ -> M_DATA) + mblk_t *header_mp = build_tx_packet_header(the_stream, unitdata_mp, true); + + if (header_mp == NULL) { + // Could not allocate a message block large enough + ioc->ioc_error = MAC_ENOMEM; + goto ioctl_error; + } + + // Attach header block at the end + mp->b_cont->b_cont = header_mp; + the_stream->flags |= kFastPathMode; + goto ioctl_ok; + } + + case I_OTSetRawMode: { + mblk_t *info_mp = mp->b_cont; + dl_recv_control_t *dlrc; + if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(dlrc->dl_primitive))) { + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + dlrc = (dl_recv_control_t *)info_mp->b_rptr; + D(bug(" I_OTSetRawMode primitive %d\n", dlrc->dl_primitive)); + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + + default: + D(bug("WARNING: Unknown ether_ioctl() call\n")); + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + +ioctl_ok: + ioc->ioc_count = 0; + for (mblk_t *mp1 = mp; (mp1 = mp1->b_cont) != NULL;) + ioc->ioc_count += mp1->b_wptr - mp1->b_rptr; + ioc->ioc_error = 0; + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); + return; + +ioctl_error: + mp->b_datap->db_type = M_IOCNAK; + qreply(q, mp); + return; +} + + +/* + * Flush call, send it up to the read side of the stream + */ + +static void ether_flush(queue_t* q, mblk_t* mp) +{ + D(bug(" ether_flush(%p,%p)\n", q, mp)); + + uint8 *rptr = mp->b_rptr; + if (*rptr & FLUSHW) + flushq(q, FLUSHALL); + if (*rptr & FLUSHR) { + flushq(RD(q), FLUSHALL); + *rptr &= ~FLUSHW; + qreply(q, mp); + } else + freemsg(mp); +} + + +/* + * Classify packet into the different types of protocols + */ + +static uint16 classify_packet_type(uint16 primarySAP, uint16 secondarySAP) +{ + if (primarySAP >= kMinDIXSAP) + return kPktDIX; + + if ((primarySAP == kIPXSAP) && (secondarySAP == kIPXSAP)) + return kPktIPX; + + if (primarySAP == kSNAPSAP) + return kPkt8022SNAP; + + if (primarySAP <= k8022GlobalSAP) + return kPkt8022SAP; + + return kPktUnknown; +} + + +/* + * Check if the address is a multicast, broadcast or standard address + */ + +static int32 get_address_type(uint8 *addr) +{ + if (addr[0] & 1) { // Multicast/broadcast flag + if (OTIs48BitBroadcastAddress(addr)) + return keaBroadcast; + else + return keaMulticast; + } else + return keaStandardAddress; +} + + +/* + * Reuse a message block, make room for more data + */ + +static mblk_t *reuse_message_block(mblk_t *mp, uint16 needed_size) +{ + mblk_t *nmp; + + if ((mp->b_datap->db_ref == 1) && ((mp->b_datap->db_lim - mp->b_datap->db_base) >= needed_size)) { + mp->b_datap->db_type = M_DATA; + mp->b_rptr = mp->b_datap->db_base; + mp->b_wptr = mp->b_datap->db_base + needed_size; + } else { + nmp = mp->b_cont; // Grab the M_DATA blocks + mp->b_cont = NULL; // Detach the M_(PC)PROTO + freemsg(mp); // Free the M_(PC)PROTO + mp = nmp; // Point to the M_DATA blocks + + // Try to get space on the first M_DATA block + if (mp && (mp->b_datap->db_ref == 1) && ((mp->b_rptr - mp->b_datap->db_base) >= needed_size)) + mp->b_rptr -= needed_size; + else { + // Try to allocate a new message + if ((nmp = allocb(needed_size, BPRI_HI)) == NULL) { + // Could not get a new message block so lets forget about the message altogether + freemsg(mp); // Free the original M_DATA portion of the message + mp = NULL; // Indicates the reuse failed + } else { + nmp->b_cont = mp; // Attach the new message block as the head + nmp->b_wptr += needed_size; + mp = nmp; + } + } + } + + return mp; +} + + +/* + * Built header for packet to be transmitted (convert DL_UNITDATA_REQ -> M_DATA) + * The passed-in message has the header info in the first message block and the data + * in the following blocks + */ + +static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path) +{ + // Only handle unit_data requests + dl_unitdata_req_t *req = (dl_unitdata_req_t *)mp->b_rptr; + if (req->dl_primitive != DL_UNITDATA_REQ) { + freemsg(mp); + return NULL; + } + + // Extract destination address and its length + uint8 *destAddrOrig = ((uint8 *)req) + req->dl_dest_addr_offset; + uint32 destAddrLen = req->dl_dest_addr_length; + uint8 ctrl = 0x03; + + // Extract DLSAP + uint16 dlsap; + switch (destAddrLen) { + case kEnetPhysicalAddressLength: + dlsap = the_stream->dlsap; + break; + case kEnetAndSAPAddressLength: + dlsap = *(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength); + break; + case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength: // SNAP SAP + dlsap = *(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength); + break; + default: + dlsap = the_stream->dlsap; + break; + } + + // Extract data size (excluding header info) and packet type + uint16 datasize = msgdsize(mp); + uint16 packetType = classify_packet_type(the_stream->dlsap, dlsap); + + // Calculate header size and protocol type/size field + uint16 hdrsize, proto; + switch (packetType) { + case kPktDIX: + hdrsize = kEnetPacketHeaderLength; + proto = dlsap; + break; + case kPkt8022SAP: + hdrsize = kEnetPacketHeaderLength + k8022BasicHeaderLength; + if (fast_path) + proto = 0; + else + proto = datasize + k8022BasicHeaderLength; + break; + case kPkt8022SNAP: + hdrsize = kEnetPacketHeaderLength + k8022SNAPHeaderLength; + if (fast_path) + proto = 0; + else + proto = datasize + k8022SNAPHeaderLength; + break; + case kPktIPX: + hdrsize = kEnetPacketHeaderLength; + if (fast_path) + proto = 0; + else + proto = datasize; + break; + default: + hdrsize = kEnetPacketHeaderLength; + proto = dlsap; + break; + } + + // We need to copy the dest address info in the message before we can reuse it + uint8 destAddrCopy[kMaxBoundAddrLength]; + memcpy(destAddrCopy, destAddrOrig, destAddrLen); + + // Resize header info in message block + if ((mp = reuse_message_block(mp, hdrsize)) == NULL) + return NULL; + struct T8022FullPacketHeader *packetHeader = (struct T8022FullPacketHeader *)mp->b_rptr; + + // Set protocol type/size field + packetHeader->fEnetPart.fProto = proto; + + // Set destination ethernet address + OTCopy48BitAddress(destAddrCopy, packetHeader->fEnetPart.fDestAddr); + + // Set other header fields + switch (packetType) { + case kPkt8022SAP: + packetHeader->f8022Part.fDSAP = (uint8)dlsap; + packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap; + packetHeader->f8022Part.fCtrl = ctrl; + break; + case kPkt8022SNAP: { + uint8 *snapStart; + packetHeader->f8022Part.fDSAP = (uint8)dlsap; + packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap; + packetHeader->f8022Part.fCtrl = ctrl; + if (destAddrLen >= kEnetAndSAPAddressLength + k8022SNAPLength) + snapStart = destAddrCopy + kEnetAndSAPAddressLength; + else + snapStart = the_stream->snap; + OTCopy8022SNAP(snapStart, packetHeader->f8022Part.fSNAP); + break; + } + } + + // Return updated message + return mp; +} + + +/* + * Transmit packet + */ + +static void transmit_packet(mblk_t *mp) +{ + EnetPacketHeader *enetHeader = (EnetPacketHeader *)mp->b_rptr; + + // Fill in length in 802.3 packets + if (enetHeader->fProto == 0) + enetHeader->fProto = msgdsize(mp) - sizeof(EnetPacketHeader); + + // Fill in ethernet source address + OTCopy48BitAddress(hardware_address, enetHeader->fSourceAddr); + + // Tell add-on to transmit packet + AO_transmit_packet(mp); + freemsg(mp); +} + + +/* + * Handle incoming packet (one stream), construct DL_UNITDATA_IND message + */ + +static void handle_received_packet(DLPIStream *the_stream, mblk_t *mp, uint16 packet_type, int32 dest_addr_type) +{ + // Find address and header length + uint32 addr_len; + uint32 header_len; + switch (packet_type) { + case kPkt8022SAP: + addr_len = kEnetAndSAPAddressLength; + header_len = kEnetPacketHeaderLength + k8022BasicHeaderLength; + break; + case kPkt8022SNAP: + addr_len = kEnetAndSAPAddressLength + k8022SNAPLength; + header_len = kEnetPacketHeaderLength + k8022SNAPHeaderLength; + break; + default: // DIX and IPX + addr_len = kEnetAndSAPAddressLength; + header_len = kEnetPacketHeaderLength; + break; + } + + // In Fast Path mode, don't send DL_UNITDATA_IND messages for unicast packets + if ((the_stream->flags & kFastPathMode) && dest_addr_type == keaStandardAddress) { + mp->b_rptr += header_len; + num_rx_fastpath++; + putq(the_stream->rdq, mp); + return; + } + + // Allocate the dl_unitdata_ind_t message + mblk_t *nmp; + if ((nmp = allocb(sizeof(dl_unitdata_ind_t) + 2*addr_len, BPRI_HI)) == NULL) { + freemsg(mp); + num_rx_no_unitdata_mem++; + return; + } + + // Set message type + nmp->b_datap->db_type = M_PROTO; + dl_unitdata_ind_t *ind = (dl_unitdata_ind_t*)nmp->b_rptr; + ind->dl_primitive = DL_UNITDATA_IND; + nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + 2*addr_len); + + // Link M_DATA block + nmp->b_cont = mp; + + // Set address fields + ind->dl_dest_addr_length = addr_len; + ind->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t); + ind->dl_src_addr_length = addr_len; + ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t) + addr_len; + + // Set address type + ind->dl_group_address = dest_addr_type; + + // Set address fields + T8022FullPacketHeader *packetHeader = (T8022FullPacketHeader *)mp->b_rptr; + T8022AddressStruct *destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset)); + T8022AddressStruct *srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset)); + + OTCopy48BitAddress(packetHeader->fEnetPart.fDestAddr, destAddr->fHWAddr); + OTCopy48BitAddress(packetHeader->fEnetPart.fSourceAddr, srcAddr->fHWAddr); + + destAddr->fSAP = packetHeader->f8022Part.fDSAP; + srcAddr->fSAP = packetHeader->f8022Part.fSSAP; + + if (packet_type == kPkt8022SNAP) { + OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, destAddr->fSNAP); + OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, srcAddr->fSNAP); + } + + // "Hide" the ethernet and protocol header(s) + mp->b_rptr += header_len; + + // Pass message up the stream + num_unitdata_ind++; + putq(the_stream->rdq, nmp); + return; +} + + +/* + * Packet received, distribute it to the streams that want it + */ + +void ether_packet_received(mblk_t *mp) +{ + // Extract address and types + EnetPacketHeader *pkt = (EnetPacketHeader *)mp->b_rptr; + T8022FullPacketHeader *fullpkt = (T8022FullPacketHeader *)pkt; + uint16 sourceSAP, destSAP; + destSAP = fullpkt->fEnetPart.fProto; + if (destSAP >= kMinDIXSAP) { + // Classic ethernet + sourceSAP = destSAP; + } else { + destSAP = fullpkt->f8022Part.fDSAP; + sourceSAP = fullpkt->f8022Part.fSSAP; + } + uint16 packetType = classify_packet_type(sourceSAP, destSAP); + int32 destAddressType = get_address_type(pkt->fDestAddr); + + // Look which streams want it + DLPIStream *the_stream, *found_stream = NULL; + uint16 found_packetType = 0; + int32 found_destAddressType = 0; + for (the_stream = dlpi_stream_list; the_stream != NULL; the_stream = mi_next_ptr(the_stream)) { + + // Don't send to unbound streams + if (the_stream->dlpi_state == DL_UNBOUND) + continue; + + // Does this stream want all 802.2 packets? + if ((the_stream->flags & kAcceptAll8022Packets) && (destSAP <= 0xff)) + goto type_found; + + // No, check SAP/SNAP + if (destSAP == the_stream->dlsap) { + if (the_stream->flags & kSnapStream) { + // Check SNAPs if necessary + uint8 sum = fullpkt->f8022Part.fSNAP[0] ^ the_stream->snap[0]; + sum |= fullpkt->f8022Part.fSNAP[1] ^ the_stream->snap[1]; + sum |= fullpkt->f8022Part.fSNAP[2] ^ the_stream->snap[2]; + sum |= fullpkt->f8022Part.fSNAP[3] ^ the_stream->snap[3]; + sum |= fullpkt->f8022Part.fSNAP[4] ^ the_stream->snap[4]; + if (sum == 0) + goto type_found; + } else { + // No SNAP, found a match since saps match + goto type_found; + } + } else { + // Check for an 802.3 Group/Global (odd) + if (((packetType == kPkt8022SAP) || (packetType == kPkt8022SNAP)) && (destSAP & 1) && the_stream->TestGroupSAP(destSAP)) + goto type_found; + } + + // No stream for this SAP/SNAP found + continue; + +type_found: + // If it's a multicast packet, it must be in the stream's multicast list + if ((destAddressType == keaMulticast) && (the_stream->flags & kAcceptMulticasts) && (!the_stream->IsMulticastRegistered(pkt->fDestAddr))) + continue; + + // Send packet to stream + // found_stream keeps a pointer to the previously found stream, so that only the last + // stream gets the original message, the other ones get duplicates + if (found_stream) + handle_received_packet(found_stream, dupmsg(mp), found_packetType, found_destAddressType); + found_stream = the_stream; + found_packetType = packetType; + found_destAddressType = destAddressType; + } + + // Send original message to last found stream + if (found_stream) + handle_received_packet(found_stream, mp, found_packetType, found_destAddressType); + else { + freemsg(mp); // Nobody wants it *snief* + num_rx_dropped++; + } +} + + +/* + * Build and send an error acknowledge + */ + +static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr) +{ + D(bug(" DLPI_error_ack(%p,%p) prim %d, err %d, uerr %d\n", the_stream, ack_mp, prim, err, uerr)); + num_error_acks++; + + if (ack_mp != NULL) + freemsg(ack_mp); + if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) + return; + + ack_mp->b_datap->db_type = M_PCPROTO; + dl_error_ack_t *errp = (dl_error_ack_t *)ack_mp->b_wptr; + errp->dl_primitive = DL_ERROR_ACK; + errp->dl_error_primitive = prim; + errp->dl_errno = err; + errp->dl_unix_errno = uerr; + ack_mp->b_wptr += sizeof(dl_error_ack_t); + qreply(q, ack_mp); +} + + +/* + * Build and send an OK acknowledge + */ + +static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim) +{ + if (ack_mp->b_datap->db_ref != 1) { + // Message already in use, create a new one + freemsg(ack_mp); + if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) + return; + } else { + // Message free + if (ack_mp->b_cont != NULL) { + freemsg(ack_mp->b_cont); + ack_mp->b_cont = NULL; + } + } + + ack_mp->b_datap->db_type = M_PCPROTO; + dl_ok_ack_t *ackp = (dl_ok_ack_t *)ack_mp->b_rptr; + ackp->dl_primitive = DL_OK_ACK; + ackp->dl_correct_primitive = prim; + ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_ok_ack_t); + qreply(q, ack_mp); +} + + +/* + * Handle DL_INFO_REQ (report general information) + */ + +static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_info(%p)\n", the_stream)); + uint32 saplen = 0; + uint32 addrlen = kEnetPhysicalAddressLength; + uint32 bcastlen = kEnetPhysicalAddressLength; + uint32 hdrlen = kEnetPacketHeaderLength; + + // Calculate header length + if (the_stream->dlpi_state != DL_UNBOUND) { + saplen = (the_stream->flags & kSnapStream) ? k8022DLSAPLength+k8022SNAPLength : k8022DLSAPLength; + if (the_stream->dlsap == kSNAPSAP) + hdrlen = kEnetPacketHeaderLength + k8022SNAPHeaderLength; // SNAP address + else if ((the_stream->dlsap <= kMax8022SAP) || (the_stream->dlsap == kIPXSAP)) + hdrlen = kEnetPacketHeaderLength + k8022BasicHeaderLength; // SAP or IPX + else + hdrlen = kEnetPacketHeaderLength; // Basic Ethernet + } + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen, BPRI_LO)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_INFO_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_info_ack_t *ackp = (dl_info_ack_t *)ack_mp->b_rptr; + ackp->dl_primitive = DL_INFO_ACK; + + // Info/version fields + ackp->dl_service_mode = DL_CLDLS; + ackp->dl_provider_style = DL_STYLE1; + ackp->dl_version = DL_VERSION_2; + ackp->dl_current_state = the_stream->dlpi_state; + ackp->dl_mac_type = the_stream->framing_8022 ? DL_CSMACD : DL_ETHER; + ackp->dl_reserved = 0; + ackp->dl_qos_length = 0; + ackp->dl_qos_offset = (uint32)DL_UNKNOWN; + ackp->dl_qos_range_length = 0; + ackp->dl_qos_range_offset = (uint32)DL_UNKNOWN; + ackp->dl_growth = 0; + ackp->dl_min_sdu = 1; + ackp->dl_max_sdu = kEnetTSDU - hdrlen; + + // Address fields + ackp->dl_sap_length = -saplen; // Negative to indicate sap follows physical address + ackp->dl_addr_length = addrlen + saplen; + ackp->dl_addr_offset = sizeof(dl_info_ack_t); + T8022AddressStruct *boundAddr = ((T8022AddressStruct *)(ack_mp->b_rptr + ackp->dl_addr_offset)); + OTCopy48BitAddress(hardware_address, boundAddr->fHWAddr); + if (saplen) { + boundAddr->fSAP = the_stream->dlsap; + if (the_stream->flags & kSnapStream) + OTCopy8022SNAP(the_stream->snap, boundAddr->fSNAP); + } + ackp->dl_brdcst_addr_length = bcastlen; + ackp->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + addrlen + saplen; + OTSet48BitBroadcastAddress(ack_mp->b_rptr + ackp->dl_brdcst_addr_offset); + + // Advance write pointer + ack_mp->b_wptr += sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen; + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_PHYS_ADDR_REQ (report physical address) + */ + +static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_phys_addr(%p,%p)\n", the_stream, mp)); + dl_phys_addr_req_t *req = (dl_phys_addr_req_t *)mp->b_rptr; + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength, BPRI_HI)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_phys_addr_ack_t *ackp = (dl_phys_addr_ack_t *)ack_mp->b_wptr; + ackp->dl_primitive = DL_PHYS_ADDR_ACK; + + // Fill in address + ackp->dl_addr_length = kEnetPhysicalAddressLength; + ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t); + ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength; + if (req->dl_addr_type == DL_CURR_PHYS_ADDR || req->dl_addr_type == DL_FACT_PHYS_ADDR) + OTCopy48BitAddress(hardware_address, ack_mp->b_rptr + ackp->dl_addr_offset); + else { + DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); + return; + } + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_BIND_REQ (bind a stream) + */ + +static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_bind_req_t *req = (dl_bind_req_t *)mp->b_rptr; + uint32 sap = req->dl_sap; + D(bug(" DLPI_bind(%p,%p) SAP %04x\n", the_stream, mp, sap)); + + // Stream must be unbound + if (the_stream->dlpi_state != DL_UNBOUND) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_OUTSTATE, 0); + return; + } + + // We only support connectionless data link services + if (req->dl_service_mode != DL_CLDLS || req->dl_max_conind != 0) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0); + return; + } + + // Don't bind to 802.2 group saps, can't check 802.2 global sap (0xFF) + // because it looks like IPX + if ((sap <= kMax8022SAP) && (sap & 1)) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0); + return; + } + + if (classify_packet_type(sap, sap) == kPktUnknown) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0); + return; + } + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength, BPRI_HI)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_bind_ack_t *ackp = (dl_bind_ack_t *)ack_mp->b_rptr; + ackp->dl_primitive = DL_BIND_ACK; + + // Fill in other fields + ackp->dl_sap = sap; + ackp->dl_addr_length = kEnetAndSAPAddressLength; + ackp->dl_addr_offset = sizeof(dl_bind_ack_t); + ackp->dl_max_conind = 0; + ackp->dl_xidtest_flg = 0; + + T8022AddressStruct *addrInfo = (T8022AddressStruct *)(ack_mp->b_rptr + sizeof(dl_bind_ack_t)); + OTCopy48BitAddress(hardware_address, addrInfo->fHWAddr); + addrInfo->fSAP = sap; + + // Must move b_wptr past the address info data + ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength; + + // Set group SAP if necessary + the_stream->ClearAllGroupSAPs(); + if (sap <= kMax8022SAP) + the_stream->SetGroupSAP(k8022GlobalSAP); + + // The stream is now bound and idle + the_stream->dlpi_state = DL_IDLE; + the_stream->dlsap = sap; + the_stream->flags &= ~kSnapStream; + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_UNBIND_REQ (unbind a stream) + */ + +static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_unbind(%p,%p)\n", the_stream, mp)); + + // Stream must be bound and idle + if (the_stream->dlpi_state != DL_IDLE) { + DLPI_error_ack(the_stream, q, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); + return; + } + + // Stream is now unbound + the_stream->dlpi_state = DL_UNBOUND; + the_stream->dlsap = 0; + + // Flush all pending outbound messages + flushq(q, FLUSHDATA); + + // Flush all inbound messages pending on the stream + flushq(RD(q), FLUSHDATA); + putnextctl1(RD(q), M_FLUSH, FLUSHRW); + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_UNBIND_REQ); + return; +} + + +/* + * Handle DL_SUBS_BIND_REQ (register 802.2 SAP group addresses and SNAPs) + */ + +static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_subs_bind_req_t *req = (dl_subs_bind_req_t *)mp->b_rptr; + uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset; + int32 length = req->dl_subs_sap_length; + uint16 theSap = *((uint16 *)sap); + int32 error = 0; + D(bug(" DLPI_subs_bind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4])); + + // Stream must be idle + if (the_stream->dlpi_state != DL_IDLE) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_OUTSTATE, 0); + return; + } + + // Check if address is valid + switch (req->dl_subs_bind_class) { + case DL_PEER_BIND: // Bind a group address + if (the_stream->dlsap <= kMax8022SAP) { + if ((theSap & 1) && (length == sizeof(theSap))) + the_stream->SetGroupSAP(theSap); + else + if (theSap == 0x0000) // special case to receive all 802.2 packets + the_stream->flags |= kAcceptAll8022Packets; + else + error = DL_BADADDR; + } else + error = DL_UNSUPPORTED; + break; + + case DL_HIERARCHICAL_BIND: // Bind an additional SNAP + if (the_stream->dlsap == kSNAPSAP) { + if (the_stream->flags & kSnapStream) + error = DL_TOOMANY; // only one SNAP binding allowed + else { + OTCopy8022SNAP(sap, the_stream->snap); + the_stream->flags |= kSnapStream; + } + } else + error = DL_BADADDR; + break; + + default: + error = DL_UNSUPPORTED; + break; + } + if (error) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, error, 0); + return; + } + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_subs_bind_ack_t) + length, BPRI_HI)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_subs_bind_ack_t *ackp = (dl_subs_bind_ack_t *)ack_mp->b_wptr; + memset(ackp, 0, sizeof(dl_subs_bind_ack_t) + length); + ackp->dl_primitive = DL_SUBS_BIND_ACK; + + // Fill in other fields + ackp->dl_subs_sap_length = length; + ackp->dl_subs_sap_offset = length ? sizeof(dl_subs_bind_ack_t) : 0; + ack_mp->b_wptr += sizeof(dl_subs_bind_ack_t); + if (length) + memcpy(ack_mp->b_wptr, sap, length); + ack_mp->b_wptr += length; + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_SUBS_UNBIND_REQ (unregister 802.2 SAP group addresses and snaps) + */ + +static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_subs_unbind_req_t *req = (dl_subs_unbind_req_t *)mp->b_rptr; + uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset; + int32 length = req->dl_subs_sap_length; + int32 error = 0; + D(bug(" DLPI_subs_unbind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4])); + + // Stream must be idle + if (the_stream->dlpi_state != DL_IDLE) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, DL_OUTSTATE, 0); + return; + } + + // Check if we are unbinding from an address we are bound to + if (length == k8022SAPLength) { + if ((*sap & 1) && (*sap != kIPXSAP)) { + if (the_stream->dlsap <= kMax8022SAP) + the_stream->ClearGroupSAP(*sap); + else + error = DL_UNSUPPORTED; + } else + error = DL_BADADDR; + } else if (length == k8022SNAPLength) { + if (the_stream->dlsap == kSNAPSAP) { + if (the_stream->flags & kSnapStream) { + if (memcmp(the_stream->snap, sap, length) != 0) + error = DL_BADADDR; + } else + error = DL_BADADDR; + } else + error = DL_UNSUPPORTED; + } + if (error) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, error, 0); + return; + } + + // Stream is no longer bound to SNAP + the_stream->flags &= ~kSnapStream; + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ); + return; +} + + +/* + * Handles DL_ENABMULTI_REQ (enable multicast address) + */ + +static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_enabmulti_req_t* req = (dl_enabmulti_req_t*)mp->b_rptr; + uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset); + D(bug(" DLPI_enable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5])); + + // Address must be a multicast address + if (get_address_type(reqaddr) != keaMulticast) { + DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Address already in multicast list? + if (the_stream->IsMulticastRegistered(reqaddr)) { + DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Tell add-on to enable multicast address + AO_enable_multicast(reqaddr); + + // Add new address to multicast list + uint8 *addr = new uint8[kEnetPhysicalAddressLength]; + OTCopy48BitAddress(reqaddr, addr); + the_stream->AddMulticast(addr); + + // On receive now check multicast packets + the_stream->flags |= kAcceptMulticasts; + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_ENABMULTI_REQ); + return; +} + + +/* + * Handles DL_DISABMULTI_REQ (disable multicast address) + */ + +static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_disabmulti_req_t *req = (dl_disabmulti_req_t*)mp->b_rptr; + uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset); + D(bug(" DLPI_disable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5])); + + // Address must be a multicast address + if (get_address_type(reqaddr) != keaMulticast) { + DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Find address in multicast list + uint8 *addr = the_stream->IsMulticastRegistered(reqaddr); + if (addr == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Found, then remove + the_stream->RemoveMulticast(addr); + delete addr; + + // Tell add-on to disable multicast address + AO_disable_multicast(reqaddr); + + // No longer check multicast packets if no multicast addresses are registered + if (the_stream->multicast_list == NULL) + the_stream->flags &= ~kAcceptMulticasts; + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_DISABMULTI_REQ); + return; +} + + +/* + * Handle DL_UNITDATA_REQ (transmit packet) + */ + +static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_unit_data(%p,%p)\n", the_stream, mp)); + dl_unitdata_req_t *req = (dl_unitdata_req_t *)mp->b_rptr; + + // Stream must be idle + if (the_stream->dlpi_state != DL_IDLE) { + + // Not idle, send error response + dl_uderror_ind_t *errp; + mblk_t *bp; + + int i = sizeof(dl_uderror_ind_t) + req->dl_dest_addr_length; + if ((bp = allocb(i, BPRI_HI)) == NULL) { + freemsg(mp); + return; + } + bp->b_datap->db_type = M_PROTO; + errp = (dl_uderror_ind_t *)bp->b_wptr; + errp->dl_primitive = DL_UDERROR_IND; + errp->dl_errno = DL_OUTSTATE; + errp->dl_unix_errno = 0; + errp->dl_dest_addr_length = req->dl_dest_addr_length; + errp->dl_dest_addr_offset = sizeof(dl_uderror_ind_t); + bp->b_wptr += sizeof(dl_uderror_ind_t); + memcpy((uint8 *)bp->b_wptr, ((uint8 *)req) + req->dl_dest_addr_offset, req->dl_dest_addr_length); + bp->b_wptr += req->dl_dest_addr_length; + qreply(q, bp); + + freemsg(mp); + return; + } + + // Build packet header and transmit packet + if ((mp = build_tx_packet_header(the_stream, mp, false)) != NULL) + transmit_packet(mp); +} diff --git a/SheepShaver/src/include/about_window.h b/SheepShaver/src/include/about_window.h new file mode 100644 index 00000000..0d014b44 --- /dev/null +++ b/SheepShaver/src/include/about_window.h @@ -0,0 +1,26 @@ +/* + * about_window.h - "About" window + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 ABOUT_WINDOW_H +#define ABOUT_WINDOW_H + +extern void OpenAboutWindow(void); + +#endif diff --git a/SheepShaver/src/include/cpu_emulation.h b/SheepShaver/src/include/cpu_emulation.h new file mode 100644 index 00000000..88442767 --- /dev/null +++ b/SheepShaver/src/include/cpu_emulation.h @@ -0,0 +1,73 @@ +/* + * cpu_emulation.h - Definitions for CPU emulation and Mac memory access + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 CPU_EMULATION_H +#define CPU_EMULATION_H + + +/* + * Memory system + */ + +// Constants +const uint32 ROM_BASE = 0x40800000; // Base address of ROM +const uint32 ROM_SIZE = 0x00400000; // Size of ROM file +const uint32 DR_CACHE_BASE = 0x69000000; // Address of DR cache +const uint32 DR_CACHE_SIZE = 0x80000; // Size of DR Cache + +// RAM and ROM pointers (allocated and set by main_*.cpp) +extern uint32 RAMBase; // Base address of Mac RAM +extern uint32 RAMSize; // Size address of Mac RAM + +// Mac memory access functions +static inline uint32 ReadMacInt8(uint32 addr) {return *(uint8 *)addr;} +static inline void WriteMacInt8(uint32 addr, uint32 b) {*(uint8 *)addr = b;} +#ifdef __i386__ +static inline uint32 ReadMacInt16(uint32 addr) {uint32 retval; __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswapl %k0\n" : "=&r" (retval) : "m" (*(uint16 *)addr) : "cc"); return retval;} +static inline uint32 ReadMacInt32(uint32 addr) {uint32 retval; __asm__ ("bswap %0" : "=r" (retval) : "0" (*(uint32 *)addr) : "cc"); return retval;} +static inline uint64 ReadMacInt64(uint32 addr) {return ((uint64)ReadMacInt32(addr) << 32) | ReadMacInt32(addr + 4);} +static inline void WriteMacInt16(uint32 addr, uint32 w) {__asm__ ("bswapl %0" : "=&r" (w) : "0" (w << 16) : "cc"); *(uint16 *)addr = w;} +static inline void WriteMacInt32(uint32 addr, uint32 l) {__asm__ ("bswap %0" : "=r" (l) : "0" (l) : "cc"); *(uint32 *)addr = l;} +static inline void WriteMacInt64(uint32 addr, uint64 ll) {WriteMacInt32(addr, ll >> 32); WriteMacInt32(addr, ll);} +#else +static inline uint32 ReadMacInt16(uint32 addr) {return *(uint16 *)addr;} +static inline uint32 ReadMacInt32(uint32 addr) {return *(uint32 *)addr;} +static inline uint64 ReadMacInt64(uint32 addr) {return *(uint64 *)addr;} +static inline void WriteMacInt16(uint32 addr, uint32 w) {*(uint16 *)addr = w;} +static inline void WriteMacInt32(uint32 addr, uint32 l) {*(uint32 *)addr = l;} +static inline void WriteMacInt64(uint32 addr, uint64 ll) {*(uint64 *)addr = ll;} +#endif +static inline uint8 *Mac2HostAddr(uint32 addr) {return (uint8 *)addr;} +static inline void *Mac_memset(uint32 addr, int c, size_t n) {return memset(Mac2HostAddr(addr), c, n);} +static inline void *Mac2Host_memcpy(void *dest, uint32 src, size_t n) {return memcpy(dest, Mac2HostAddr(src), n);} +static inline void *Host2Mac_memcpy(uint32 dest, const void *src, size_t n) {return memcpy(Mac2HostAddr(dest), src, n);} +static inline void *Mac2Mac_memcpy(uint32 dest, uint32 src, size_t n) {return memcpy(Mac2HostAddr(dest), Mac2HostAddr(src), n);} + + +/* + * 680x0 and PPC emulation + */ + +struct M68kRegisters; +extern void Execute68k(uint32, M68kRegisters *r); // Execute 68k subroutine from EMUL_OP routine, must be ended with RTS +extern void Execute68kTrap(uint16 trap, M68kRegisters *r); // Execute 68k A-Trap from EMUL_OP routine +extern void ExecutePPC(void (*func)()); // Execute PPC code from EMUL_OP routine (real mode switch) + +#endif diff --git a/SheepShaver/src/include/emul_op.h b/SheepShaver/src/include/emul_op.h new file mode 100644 index 00000000..b594f31a --- /dev/null +++ b/SheepShaver/src/include/emul_op.h @@ -0,0 +1,108 @@ +/* + * emul_op.h - 68k opcodes for ROM patches + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 EMUL_OP_H +#define EMUL_OP_H + +// PowerPC opcodes +const uint32 POWERPC_NOP = 0x60000000; +const uint32 POWERPC_ILLEGAL = 0x00000000; +const uint32 POWERPC_BLR = 0x4e800020; +const uint32 POWERPC_BCTR = 0x4e800420; +const uint32 POWERPC_EMUL_OP = 0x18000000; // Base opcode for EMUL_OP opcodes (only used with PPC emulation) + +// 68k opcodes +const uint16 M68K_ILLEGAL = 0x4afc; +const uint16 M68K_NOP = 0x4e71; +const uint16 M68K_RTS = 0x4e75; +const uint16 M68K_RTD = 0x4e74; +const uint16 M68K_JMP = 0x4ef9; +const uint16 M68K_JMP_A0 = 0x4ed0; +const uint16 M68K_JSR = 0x4eb9; +const uint16 M68K_JSR_A0 = 0x4e90; +enum { // Selectors for EMUL_OP opcodes + OP_BREAK, OP_XPRAM1, OP_XPRAM2, OP_XPRAM3, OP_NVRAM1, OP_NVRAM2, OP_NVRAM3, + OP_FIX_MEMTOP, OP_FIX_MEMSIZE, OP_FIX_BOOTSTACK, + OP_SONY_OPEN, OP_SONY_PRIME, OP_SONY_CONTROL, OP_SONY_STATUS, + OP_DISK_OPEN, OP_DISK_PRIME, OP_DISK_CONTROL, OP_DISK_STATUS, + OP_CDROM_OPEN, OP_CDROM_PRIME, OP_CDROM_CONTROL, OP_CDROM_STATUS, + OP_AUDIO_DISPATCH, OP_SOUNDIN_OPEN, OP_SOUNDIN_PRIME, OP_SOUNDIN_CONTROL, OP_SOUNDIN_STATUS, OP_SOUNDIN_CLOSE, + OP_ADBOP, OP_INSTIME, OP_RMVTIME, OP_PRIMETIME, OP_MICROSECONDS, OP_PUT_SCRAP, OP_GET_SCRAP, + OP_DEBUG_STR, OP_INSTALL_DRIVERS, OP_NAME_REGISTRY, OP_RESET, OP_IRQ, + OP_SCSI_DISPATCH, OP_SCSI_ATOMIC, + OP_NTRB_17_PATCH, OP_NTRB_17_PATCH2, OP_NTRB_17_PATCH3, OP_CHECKLOAD, + OP_EXTFS_COMM, OP_EXTFS_HFS, OP_IDLE_TIME, + OP_MAX +}; +const uint16 M68K_EMUL_RETURN = 0xfe40; // Extended opcodes +const uint16 M68K_EXEC_RETURN = 0xfe41; +const uint16 M68K_EMUL_BREAK = 0xfe42; +const uint16 M68K_EMUL_OP_XPRAM1 = M68K_EMUL_BREAK + OP_XPRAM1; +const uint16 M68K_EMUL_OP_XPRAM2 = M68K_EMUL_BREAK + OP_XPRAM2; +const uint16 M68K_EMUL_OP_XPRAM3 = M68K_EMUL_BREAK + OP_XPRAM3; +const uint16 M68K_EMUL_OP_NVRAM1 = M68K_EMUL_BREAK + OP_NVRAM1; +const uint16 M68K_EMUL_OP_NVRAM2 = M68K_EMUL_BREAK + OP_NVRAM2; +const uint16 M68K_EMUL_OP_NVRAM3 = M68K_EMUL_BREAK + OP_NVRAM3; +const uint16 M68K_EMUL_OP_FIX_MEMTOP = M68K_EMUL_BREAK + OP_FIX_MEMTOP; +const uint16 M68K_EMUL_OP_FIX_MEMSIZE = M68K_EMUL_BREAK + OP_FIX_MEMSIZE; +const uint16 M68K_EMUL_OP_FIX_BOOTSTACK = M68K_EMUL_BREAK + OP_FIX_BOOTSTACK; +const uint16 M68K_EMUL_OP_SONY_OPEN = M68K_EMUL_BREAK + OP_SONY_OPEN; +const uint16 M68K_EMUL_OP_SONY_PRIME = M68K_EMUL_BREAK + OP_SONY_PRIME; +const uint16 M68K_EMUL_OP_SONY_CONTROL = M68K_EMUL_BREAK + OP_SONY_CONTROL; +const uint16 M68K_EMUL_OP_SONY_STATUS = M68K_EMUL_BREAK + OP_SONY_STATUS; +const uint16 M68K_EMUL_OP_DISK_OPEN = M68K_EMUL_BREAK + OP_DISK_OPEN; +const uint16 M68K_EMUL_OP_DISK_PRIME = M68K_EMUL_BREAK + OP_DISK_PRIME; +const uint16 M68K_EMUL_OP_DISK_CONTROL = M68K_EMUL_BREAK + OP_DISK_CONTROL; +const uint16 M68K_EMUL_OP_DISK_STATUS = M68K_EMUL_BREAK + OP_DISK_STATUS; +const uint16 M68K_EMUL_OP_CDROM_OPEN = M68K_EMUL_BREAK + OP_CDROM_OPEN; +const uint16 M68K_EMUL_OP_CDROM_PRIME = M68K_EMUL_BREAK + OP_CDROM_PRIME; +const uint16 M68K_EMUL_OP_CDROM_CONTROL = M68K_EMUL_BREAK + OP_CDROM_CONTROL; +const uint16 M68K_EMUL_OP_CDROM_STATUS = M68K_EMUL_BREAK + OP_CDROM_STATUS; +const uint16 M68K_EMUL_OP_AUDIO_DISPATCH = M68K_EMUL_BREAK + OP_AUDIO_DISPATCH; +const uint16 M68K_EMUL_OP_SOUNDIN_OPEN = M68K_EMUL_BREAK + OP_SOUNDIN_OPEN; +const uint16 M68K_EMUL_OP_SOUNDIN_CLOSE = M68K_EMUL_BREAK + OP_SOUNDIN_CLOSE; +const uint16 M68K_EMUL_OP_SOUNDIN_PRIME = M68K_EMUL_BREAK + OP_SOUNDIN_PRIME; +const uint16 M68K_EMUL_OP_SOUNDIN_CONTROL = M68K_EMUL_BREAK + OP_SOUNDIN_CONTROL; +const uint16 M68K_EMUL_OP_SOUNDIN_STATUS = M68K_EMUL_BREAK + OP_SOUNDIN_STATUS; +const uint16 M68K_EMUL_OP_ADBOP = M68K_EMUL_BREAK + OP_ADBOP; +const uint16 M68K_EMUL_OP_INSTIME = M68K_EMUL_BREAK + OP_INSTIME; +const uint16 M68K_EMUL_OP_RMVTIME = M68K_EMUL_BREAK + OP_RMVTIME; +const uint16 M68K_EMUL_OP_PRIMETIME = M68K_EMUL_BREAK + OP_PRIMETIME; +const uint16 M68K_EMUL_OP_MICROSECONDS = M68K_EMUL_BREAK + OP_MICROSECONDS; +const uint16 M68K_EMUL_OP_PUT_SCRAP = M68K_EMUL_BREAK + OP_PUT_SCRAP; +const uint16 M68K_EMUL_OP_GET_SCRAP = M68K_EMUL_BREAK + OP_GET_SCRAP; +const uint16 M68K_EMUL_OP_DEBUG_STR = M68K_EMUL_BREAK + OP_DEBUG_STR; +const uint16 M68K_EMUL_OP_INSTALL_DRIVERS = M68K_EMUL_BREAK + OP_INSTALL_DRIVERS; +const uint16 M68K_EMUL_OP_NAME_REGISTRY = M68K_EMUL_BREAK + OP_NAME_REGISTRY; +const uint16 M68K_EMUL_OP_RESET = M68K_EMUL_BREAK + OP_RESET; +const uint16 M68K_EMUL_OP_IRQ = M68K_EMUL_BREAK + OP_IRQ; +const uint16 M68K_EMUL_OP_SCSI_DISPATCH = M68K_EMUL_BREAK + OP_SCSI_DISPATCH; +const uint16 M68K_EMUL_OP_SCSI_ATOMIC = M68K_EMUL_BREAK + OP_SCSI_ATOMIC; +const uint16 M68K_EMUL_OP_NTRB_17_PATCH = M68K_EMUL_BREAK + OP_NTRB_17_PATCH; +const uint16 M68K_EMUL_OP_NTRB_17_PATCH2 = M68K_EMUL_BREAK + OP_NTRB_17_PATCH2; +const uint16 M68K_EMUL_OP_NTRB_17_PATCH3 = M68K_EMUL_BREAK + OP_NTRB_17_PATCH3; +const uint16 M68K_EMUL_OP_CHECKLOAD = M68K_EMUL_BREAK + OP_CHECKLOAD; +const uint16 M68K_EMUL_OP_EXTFS_COMM = M68K_EMUL_BREAK + OP_EXTFS_COMM; +const uint16 M68K_EMUL_OP_EXTFS_HFS = M68K_EMUL_BREAK + OP_EXTFS_HFS; +const uint16 M68K_EMUL_OP_IDLE_TIME = M68K_EMUL_BREAK + OP_IDLE_TIME; + +extern void EmulOp(M68kRegisters *r, uint32 pc, int selector); + +#endif diff --git a/SheepShaver/src/include/ether.h b/SheepShaver/src/include/ether.h new file mode 100644 index 00000000..e337919b --- /dev/null +++ b/SheepShaver/src/include/ether.h @@ -0,0 +1,70 @@ +/* + * ether.h - SheepShaver Ethernet Device Driver + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * 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 ETHER_H +#define ETHER_H + +struct queue; +struct msgb; +typedef struct queue queue_t; +typedef struct msgb mblk_t; + +extern uint8 InitStreamModule(void *theID); +extern void TerminateStreamModule(void); +extern int ether_open(queue_t *rdq, void *dev, int flag, int sflag, void *creds); +extern int ether_close(queue_t *rdq, int flag, void *creds); +extern int ether_wput(queue_t *q, mblk_t *mp); +extern int ether_rsrv(queue_t *q); + +// System specific and internal functions/data +extern void EtherInit(void); +extern void EtherExit(void); + +extern void EtherIRQ(void); + +extern void AO_get_ethernet_address(uint8 *addr); +extern void AO_enable_multicast(uint8 *addr); +extern void AO_disable_multicast(uint8 *addr); +extern void AO_transmit_packet(mblk_t *mp); + +extern mblk_t *allocb(size_t size, int pri); +extern void OTEnterInterrupt(void); +extern void OTLeaveInterrupt(void); + +extern void ether_packet_received(mblk_t *mp); + +extern bool ether_driver_opened; + +extern int32 num_wput; +extern int32 num_error_acks; +extern int32 num_tx_packets; +extern int32 num_tx_raw_packets; +extern int32 num_tx_normal_packets; +extern int32 num_tx_buffer_full; +extern int32 num_rx_packets; +extern int32 num_ether_irq; +extern int32 num_unitdata_ind; +extern int32 num_rx_fastpath; +extern int32 num_rx_no_mem; +extern int32 num_rx_dropped; +extern int32 num_rx_stream_not_ready; +extern int32 num_rx_no_unitdata_mem; + +#endif diff --git a/SheepShaver/src/include/ether_defs.h b/SheepShaver/src/include/ether_defs.h new file mode 100644 index 00000000..072f10b6 --- /dev/null +++ b/SheepShaver/src/include/ether_defs.h @@ -0,0 +1,444 @@ +/* + * ether_defs.h - Definitions for DLPI Ethernet Driver + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * 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 ETHER_DEFS_H +#define ETHER_DEFS_H + + +#if __BEOS__ && __POWERPC__ +#define PRAGMA_ALIGN_SUPPORTED 1 +#define PACKED__ +#else +#define PACKED__ __attribute__ ((packed)) +#endif + + +/* + * Macros + */ + +// Get pointer to the read queue, assumes 'q' is a write queue ptr +#define RD(q) (&q[-1]) + +// Get pointer to the write queue, assumes 'q' is a read queue ptr +#define WR(q) (&q[1]) + +#define OTCompare48BitAddresses(p1, p2) \ + (*(const uint32*)((const uint8*)(p1)) == *(const uint32*)((const uint8*)(p2)) && \ + *(const uint16*)(((const uint8*)(p1))+4) == *(const uint16*)(((const uint8*)(p2))+4) ) + +#define OTCopy48BitAddress(p1, p2) \ + (*(uint32*)((uint8*)(p2)) = *(const uint32*)((const uint8*)(p1)), \ + *(uint16*)(((uint8*)(p2))+4) = *(const uint16*)(((const uint8*)(p1))+4) ) + +#define OTClear48BitAddress(p1) \ + (*(uint32*)((uint8*)(p1)) = 0, \ + *(uint16*)(((uint8*)(p1))+4) = 0 ) + +#define OTCompare8022SNAP(p1, p2) \ + (*(const uint32*)((const uint8*)(p1)) == *(const uint32*)((const uint8*)(p2)) && \ + *(((const uint8*)(p1))+4) == *(((const uint8*)(p2))+4) ) + +#define OTCopy8022SNAP(p1, p2) \ + (*(uint32*)((uint8*)(p2)) = *(const uint32*)((const uint8*)(p1)), \ + *(((uint8*)(p2))+4) = *(((const uint8*)(p1))+4) ) + +#define OTIs48BitBroadcastAddress(p1) \ + (*(uint32*)((uint8*)(p1)) == 0xffffffff && \ + *(uint16*)(((uint8*)(p1))+4) == 0xffff ) + +#define OTSet48BitBroadcastAddress(p1) \ + (*(uint32*)((uint8*)(p1)) = 0xffffffff, \ + *(uint16*)(((uint8*)(p1))+4) = 0xffff ) + +#define OTIs48BitZeroAddress(p1) \ + (*(uint32*)((uint8*)(p1)) == 0 && \ + *(uint16*)(((uint8*)(p1))+4) == 0 ) + + +/* + * Constants + */ + +enum { + // Address and packet lengths + kEnetPhysicalAddressLength = 6, + k8022SAPLength = 1, + k8022DLSAPLength = 2, + k8022SNAPLength = 5, + kMaxBoundAddrLength = 6 + 2 + 5, // addr/SAP/SNAP + kEnetAndSAPAddressLength = kEnetPhysicalAddressLength + k8022DLSAPLength, + kEnetPacketHeaderLength = (2 * kEnetPhysicalAddressLength) + k8022DLSAPLength, + k8022BasicHeaderLength = 3, // SSAP/DSAP/Control + k8022SNAPHeaderLength = k8022SNAPLength + k8022BasicHeaderLength, + kMinDIXSAP = 1501, + kEnetTSDU = 1514, + + // Special addresses + kSNAPSAP = 0xaa, + kMax8022SAP = 0xfe, + k8022GlobalSAP = 0xff, + kIPXSAP = 0xff, + + // DLPI interface states + DL_UNBOUND = 0, + + // Message types + M_DATA = 0, + M_PROTO = 1, + M_IOCTL = 14, + M_IOCACK = 129, + M_IOCNAK = 130, + M_PCPROTO = 131, // priority message + M_FLUSH = 134, + FLUSHDATA = 0, + FLUSHALL = 1, + FLUSHR = 1, + FLUSHW = 2, + FLUSHRW = 3, + + // DLPI primitives + DL_INFO_REQ = 0, + DL_BIND_REQ = 1, + DL_PEER_BIND = 1, + DL_HIERARCHICAL_BIND = 2, + DL_UNBIND_REQ = 2, + DL_INFO_ACK = 3, + DL_BIND_ACK = 4, + DL_ERROR_ACK = 5, + DL_OK_ACK = 6, + DL_UNITDATA_REQ = 7, + DL_UNITDATA_IND = 8, + DL_UDERROR_IND = 9, + DL_SUBS_UNBIND_REQ = 21, + DL_SUBS_BIND_REQ = 27, + DL_SUBS_BIND_ACK = 28, + DL_ENABMULTI_REQ = 29, + DL_DISABMULTI_REQ = 30, + DL_PHYS_ADDR_REQ = 49, + DL_PHYS_ADDR_ACK = 50, + DL_FACT_PHYS_ADDR = 1, + DL_CURR_PHYS_ADDR = 2, + + // DLPI states + DL_IDLE = 3, + + // DLPI error codes + DL_BADADDR = 1, // improper address format + DL_OUTSTATE = 3, // improper state + DL_SYSERR = 4, // UNIX system error + DL_UNSUPPORTED = 7, // service unsupported + DL_BADPRIM = 9, // primitive unknown + DL_NOTSUPPORTED = 18, // primitive not implemented + DL_TOOMANY = 19, // limit exceeded + + // errnos + MAC_ENXIO = 6, + MAC_ENOMEM = 12, + MAC_EINVAL = 22, + + // Various DLPI constants + DL_CLDLS = 2, // connectionless data link service + DL_STYLE1 = 0x500, + DL_VERSION_2 = 2, + DL_CSMACD = 0, + DL_ETHER = 4, + DL_UNKNOWN = -1, + + // ioctl() codes + I_OTSetFramingType = (('O' << 8) | 2), + kOTGetFramingValue = -1, + kOTFramingEthernet = 1, + kOTFramingEthernetIPX = 2, + kOTFramingEthernet8023 = 4, + kOTFraming8022 = 8, + I_OTSetRawMode = (('O' << 8) | 3), + DL_IOC_HDR_INFO = (('l' << 8) | 10), + + // Buffer allocation priority + BPRI_LO = 1, + BPRI_HI = 3, + + // Misc constants + kEnetModuleID = 7101 +}; + +enum EAddrType { + keaStandardAddress = 0, + keaMulticast, + keaBroadcast, + keaBadAddress +}; + + +/* + * Structures + */ + +// Data block +struct datab { + datab *db_freep; + uint8 *db_base; + uint8 *db_lim; + uint8 db_ref; + uint8 db_type; + // ... +}; + +// Message block +struct msgb { + msgb *b_next; + msgb *b_prev; + msgb *b_cont; + uint8 *b_rptr; + uint8 *b_wptr; + datab *b_datap; + // ... +}; + +// Queue (full structure required because of size) +struct queue { + void *q_qinfo; + msgb *q_first; + msgb *q_last; + queue *q_next; + queue *q_link; + void *q_ptr; + uint32 q_count; + int32 q_minpsz; + int32 q_maxpsz; + uint32 q_hiwat; + uint32 q_lowat; + void *q_bandp; + uint16 q_flag; + uint8 q_nband; + uint8 q_pad1[1]; + void *q_osx; + queue *q_ffcp; + queue *q_bfcp; +}; +typedef struct queue queue_t; + +// M_IOCTL parameters +struct iocblk { + int32 ioc_cmd; + void *ioc_cr; + uint32 ioc_id; + uint32 ioc_count; + int32 ioc_error; + int32 ioc_rval; + int32 ioc_filler[4]; +}; + +// Priority specification +struct dl_priority_t { + int32 dl_min, dl_max; +}; + +// DPLI primitives +struct dl_info_req_t { + uint32 dl_primitive; // DL_INFO_REQ +}; + +struct dl_info_ack_t { + uint32 dl_primitive; // DL_INFO_ACK + uint32 dl_max_sdu; + uint32 dl_min_sdu; + uint32 dl_addr_length; + uint32 dl_mac_type; + uint32 dl_reserved; + uint32 dl_current_state; + int32 dl_sap_length; + uint32 dl_service_mode; + uint32 dl_qos_length; + uint32 dl_qos_offset; + uint32 dl_qos_range_length; + uint32 dl_qos_range_offset; + uint32 dl_provider_style; + uint32 dl_addr_offset; + uint32 dl_version; + uint32 dl_brdcst_addr_length; + uint32 dl_brdcst_addr_offset; + uint32 dl_growth; +}; + +struct dl_bind_req_t { + uint32 dl_primitive; // DL_BIND_REQ + uint32 dl_sap; + uint32 dl_max_conind; + uint16 dl_service_mode; + uint16 dl_conn_mgmt; + uint32 dl_xidtest_flg; +}; + +struct dl_bind_ack_t { + uint32 dl_primitive; // DL_BIND_ACK + uint32 dl_sap; + uint32 dl_addr_length; + uint32 dl_addr_offset; + uint32 dl_max_conind; + uint32 dl_xidtest_flg; +}; + +struct dl_error_ack_t { + uint32 dl_primitive; // DL_ERROR_ACK + uint32 dl_error_primitive; + uint32 dl_errno; + uint32 dl_unix_errno; +}; + +struct dl_ok_ack_t { + uint32 dl_primitive; // DL_ERROR_ACK + uint32 dl_correct_primitive; +}; + +struct dl_unitdata_req_t { + uint32 dl_primitive; // DL_UNITDATA_REQ + uint32 dl_dest_addr_length; + uint32 dl_dest_addr_offset; + dl_priority_t dl_priority; +}; + +struct dl_unitdata_ind_t { + uint32 dl_primitive; // DL_UNITDATA_IND + uint32 dl_dest_addr_length; + uint32 dl_dest_addr_offset; + uint32 dl_src_addr_length; + uint32 dl_src_addr_offset; + uint32 dl_group_address; +}; + +struct dl_uderror_ind_t { + uint32 dl_primitive; // DL_UDERROR_IND + uint32 dl_dest_addr_length; + uint32 dl_dest_addr_offset; + uint32 dl_unix_errno; + uint32 dl_errno; +}; + +struct dl_subs_bind_req_t { + uint32 dl_primitive; // DL_SUBS_BIND_REQ + uint32 dl_subs_sap_offset; + uint32 dl_subs_sap_length; + uint32 dl_subs_bind_class; +}; + +struct dl_subs_bind_ack_t { + uint32 dl_primitive; // DL_SUBS_BIND_ACK + uint32 dl_subs_sap_offset; + uint32 dl_subs_sap_length; +}; + +struct dl_subs_unbind_req_t { + uint32 dl_primitive; // DL_SUBS_UNBIND_REQ + uint32 dl_subs_sap_offset; + uint32 dl_subs_sap_length; +}; + +struct dl_enabmulti_req_t { + uint32 dl_primitive; // DL_ENABMULTI_REQ + uint32 dl_addr_length; + uint32 dl_addr_offset; +}; + +struct dl_disabmulti_req_t { + uint32 dl_primitive; // DL_DISABMULTI_REQ + uint32 dl_addr_length; + uint32 dl_addr_offset; +}; + +struct dl_phys_addr_req_t { + uint32 dl_primitive; // DL_PHYS_ADDR_REQ + uint32 dl_addr_type; +}; + +struct dl_phys_addr_ack_t { + uint32 dl_primitive; // DL_PHYS_ADDR_ACK + uint32 dl_addr_length; + uint32 dl_addr_offset; +}; + +// Parameters for I_OTSetRawMode/kOTSetRecvMode ioctl() +struct dl_recv_control_t { + uint32 dl_primitive; + uint32 dl_flags; + uint32 dl_truncation_length; +}; + +union DL_primitives { + uint32 dl_primitive; + dl_info_req_t info_req; + dl_info_ack_t info_ack; + dl_bind_req_t bind_req; + dl_bind_ack_t bind_ack; + dl_error_ack_t error_ack; + dl_ok_ack_t ok_ack; + dl_unitdata_req_t unitdata_req; + dl_unitdata_ind_t unitdata_ind; + dl_uderror_ind_t uderror_ind; + dl_subs_bind_req_t subs_bind_req; + dl_subs_bind_ack_t subs_bind_ack; + dl_subs_unbind_req_t subs_unbind_req; + dl_enabmulti_req_t enabmulti_req; + dl_disabmulti_req_t disabmulti_req; + dl_phys_addr_req_t phys_addr_req; + dl_phys_addr_ack_t phys_addr_ack; +}; + +#ifdef PRAGMA_ALIGN_SUPPORTED +#pragma options align=mac68k +#endif + +// Packet headers +struct EnetPacketHeader { + uint8 fDestAddr[6]; + uint8 fSourceAddr[6]; + uint16 fProto; +} PACKED__; + +struct T8022Header { + uint8 fDSAP; + uint8 fSSAP; + uint8 fCtrl; +} PACKED__; + +struct T8022SNAPHeader { + uint8 fDSAP; + uint8 fSSAP; + uint8 fCtrl; + uint8 fSNAP[k8022SNAPLength]; +} PACKED__; + +struct T8022FullPacketHeader { + EnetPacketHeader fEnetPart; + T8022SNAPHeader f8022Part; +} PACKED__; + +struct T8022AddressStruct { + uint8 fHWAddr[6]; + uint16 fSAP; + uint8 fSNAP[k8022SNAPLength]; +} PACKED__; + +#ifdef PRAGMA_ALIGN_SUPPORTED +#pragma options align=reset +#endif + +#endif diff --git a/SheepShaver/src/include/macos_util.h b/SheepShaver/src/include/macos_util.h new file mode 100644 index 00000000..73c522b0 --- /dev/null +++ b/SheepShaver/src/include/macos_util.h @@ -0,0 +1,379 @@ +/* + * macos_util.h - MacOS definitions/utility functions + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 MACOS_UTIL_H +#define MACOS_UTIL_H + +#include "cpu_emulation.h" + + +/* + * General definitions + */ + +struct Point { + int16 v; + int16 h; +}; + +struct Rect { + int16 top; + int16 left; + int16 bottom; + int16 right; +}; + + +/* + * Queues + */ + +enum { // Queue types + dummyType = 0, + vType = 1, + ioQType = 2, + drvQType = 3, + evType = 4, + fsQType = 5, + sIQType = 6, + dtQType = 7, + nmType = 8 +}; + +enum { // QElem struct + qLink = 0, + qType = 4, + qData = 6 +}; + +enum { // QHdr struct + qFlags = 0, + qHead = 2, + qTail = 6 +}; + + +/* + * Definitions for Deferred Task Manager + */ + +enum { // DeferredTask struct + dtFlags = 6, + dtAddr = 8, + dtParam = 12, + dtReserved = 16 +}; + + +/* + * Definitions for Device Manager + */ + +// Error codes +enum { + noErr = 0, + controlErr = -17, /* I/O System Errors */ + statusErr = -18, /* I/O System Errors */ + readErr = -19, /* I/O System Errors */ + writErr = -20, /* I/O System Errors */ + badUnitErr = -21, /* I/O System Errors */ + unitEmptyErr = -22, /* I/O System Errors */ + openErr = -23, /* I/O System Errors */ + closErr = -24, /* I/O System Errors */ + abortErr = -27, /* IO call aborted by KillIO */ + notOpenErr = -28, /* Driver not open */ + dskFulErr = -34, /* disk full */ + nsvErr = -35, /* no such volume */ + ioErr = -36, /* I/O error (bummers) */ + bdNamErr = -37, /* bad name */ + fnOpnErr = -38, /* file not open */ + eofErr = -39, /* End-of-file encountered */ + posErr = -40, /* tried to position to before start of file (r/w) */ + tmfoErr = -42, /* too many files open */ + fnfErr = -43, /* file not found */ + wPrErr = -44, /* diskette is write protected. */ + fLckdErr = -45, /* file is locked */ + fBsyErr = -47, /* file busy, dir not empty */ + dupFNErr = -48, /* duplicate filename already exists */ + paramErr = -50, /* error in user parameter list */ + rfNumErr = -51, /* bad ioRefNum */ + permErr = -54, /* permission error */ + nsDrvErr = -56, /* no such driver number */ + extFSErr = -58, /* external file system */ + noDriveErr = -64, /* drive not installed */ + offLinErr = -65, /* r/w requested for an off-line drive */ + noNybErr = -66, /* couldn't find 5 nybbles in 200 tries */ + noAdrMkErr = -67, /* couldn't find valid addr mark */ + dataVerErr = -68, /* read verify compare failed */ + badCksmErr = -69, /* addr mark checksum didn't check */ + badBtSlpErr = -70, /* bad addr mark bit slip nibbles */ + noDtaMkErr = -71, /* couldn't find a data mark header */ + badDCksum = -72, /* bad data mark checksum */ + badDBtSlp = -73, /* bad data mark bit slip nibbles */ + wrUnderrun = -74, /* write underrun occurred */ + cantStepErr = -75, /* step handshake failed */ + tk0BadErr = -76, /* track 0 detect doesn't change */ + initIWMErr = -77, /* unable to initialize IWM */ + twoSideErr = -78, /* tried to read 2nd side on a 1-sided drive */ + spdAdjErr = -79, /* unable to correctly adjust disk speed */ + seekErr = -80, /* track number wrong on address mark */ + sectNFErr = -81, /* sector number never found on a track */ + fmt1Err = -82, /* can't find sector 0 after track format */ + fmt2Err = -83, /* can't get enough sync */ + verErr = -84, /* track failed to verify */ + memFullErr = -108, + dirNFErr = -120 /* directory not found */ +}; + +// Misc constants +enum { + goodbye = -1, /* heap being reinitialized */ + + ioInProgress = 1, /* predefined value of ioResult while I/O is pending */ + aRdCmd = 2, /* low byte of ioTrap for Read calls */ + aWrCmd = 3, /* low byte of ioTrap for Write calls */ + asyncTrpBit = 10, /* trap word modifier */ + noQueueBit = 9, /* trap word modifier */ + + dReadEnable = 0, /* set if driver responds to read requests */ + dWritEnable = 1, /* set if driver responds to write requests */ + dCtlEnable = 2, /* set if driver responds to control requests */ + dStatEnable = 3, /* set if driver responds to status requests */ + dNeedGoodBye = 4, /* set if driver needs time for performing periodic tasks */ + dNeedTime = 5, /* set if driver needs time for performing periodic tasks */ + dNeedLock = 6, /* set if driver must be locked in memory as soon as it is opened */ + + dOpened = 5, /* driver is open */ + dRAMBased = 6, /* dCtlDriver is a handle (1) or pointer (0) */ + drvrActive = 7, /* driver is currently processing a request */ + + rdVerify = 64, + + fsCurPerm = 0, // Whatever is currently allowed + fsRdPerm = 1, // Exclusive read + fsWrPerm = 2, // Exclusive write + fsRdWrPerm = 3, // Exclusive read/write + fsRdWrShPerm = 4, // Shared read/write + + fsAtMark = 0, // At current mark + fsFromStart = 1, // Set mark rel to BOF + fsFromLEOF = 2, // Set mark rel to logical EOF + fsFromMark = 3, // Set mark rel to current mark + + sony = 0, + hard20 = 1 +}; + +enum { /* Large Volume Constants */ + kWidePosOffsetBit = 8, + kMaximumBlocksIn4GB = 0x007FFFFF +}; + +enum { // IOParam struct + ioTrap = 6, + ioCmdAddr = 8, + ioCompletion = 12, + ioResult = 16, + ioNamePtr = 18, + ioVRefNum = 22, + ioRefNum = 24, + ioVersNum = 26, + ioPermssn = 27, + ioMisc = 28, + ioBuffer = 32, + ioReqCount = 36, + ioActCount = 40, + ioPosMode = 44, + ioPosOffset = 46, + ioWPosOffset = 46, // Wide positioning offset when ioPosMode has kWidePosOffsetBit set + SIZEOF_IOParam = 50 +}; + +enum { // CntrlParam struct + csCode = 26, + csParam = 28 +}; + +enum { // DrvSts struct + dsTrack = 0, + dsWriteProt = 2, + dsDiskInPlace = 3, + dsInstalled = 4, + dsSides = 5, + dsQLink = 6, + dsQType = 10, + dsQDrive = 12, + dsQRefNum = 14, + dsQFSID = 16, + dsTwoSideFmt = 18, + dsNewIntf = 19, + dsDiskErrs = 20, + dsMFMDrive = 22, + dsMFMDisk = 23, + dsTwoMegFmt = 24 +}; + +enum { // DrvSts2 struct + dsDriveSize = 18, + dsDriveS1 = 20, + dsDriveType = 22, + dsDriveManf = 24, + dsDriveChar = 26, + dsDriveMisc = 28, + SIZEOF_DrvSts = 30 +}; + +enum { // DCtlEntry struct + dCtlDriver = 0, + dCtlFlags = 4, + dCtlQHdr = 6, + dCtlPosition = 16, + dCtlStorage = 20, + dCtlRefNum = 24, + dCtlCurTicks = 26, + dCtlWindow = 30, + dCtlDelay = 34, + dCtlEMask = 36, + dCtlMenu = 38, + dCtlSlot = 40, + dCtlSlotId = 41, + dCtlDevBase = 42, + dCtlOwner = 46, + dCtlExtDev = 50, + dCtlFillByte = 51, + dCtlNodeID = 52 +}; + + +/* + * Definitions for native Device Manager + */ + +// Registry EntryID +struct RegEntryID { + uint32 contents[4]; +}; + +// Command codes +enum { + kOpenCommand = 0, + kCloseCommand = 1, + kReadCommand = 2, + kWriteCommand = 3, + kControlCommand = 4, + kStatusCommand = 5, + kKillIOCommand = 6, + kInitializeCommand = 7, /* init driver and device*/ + kFinalizeCommand = 8, /* shutdown driver and device*/ + kReplaceCommand = 9, /* replace an old driver*/ + kSupersededCommand = 10, /* prepare to be replaced by a new driver*/ + kSuspendCommand = 11, /* prepare driver to go to sleep*/ + kResumeCommand = 12 /* wake up sleeping driver*/ +}; + +// Command kinds +enum { + kSynchronousIOCommandKind = 0x00000001, + kAsynchronousIOCommandKind = 0x00000002, + kImmediateIOCommandKind = 0x00000004 +}; + + +/* + * Definitions for Mixed Mode Manager + */ + +typedef uint32 ProcInfoType; +typedef int8 ISAType; +typedef uint16 RoutineFlagsType; +typedef long (*ProcPtr)(); +typedef uint8 RDFlagsType; + +struct RoutineRecord { + ProcInfoType procInfo; /* calling conventions */ + int8 reserved1; /* Must be 0 */ + ISAType ISA; /* Instruction Set Architecture */ + RoutineFlagsType routineFlags; /* Flags for each routine */ + ProcPtr procDescriptor; /* Where is the thing weÕre calling? */ + uint32 reserved2; /* Must be 0 */ + uint32 selector; /* For dispatched routines, the selector */ +}; + +struct RoutineDescriptor { + uint16 goMixedModeTrap; /* Our A-Trap */ + int8 version; /* Current Routine Descriptor version */ + RDFlagsType routineDescriptorFlags; /* Routine Descriptor Flags */ + uint32 reserved1; /* Unused, must be zero */ + uint8 reserved2; /* Unused, must be zero */ + uint8 selectorInfo; /* If a dispatched routine, calling convention, else 0 */ + uint16 routineCount; /* Number of routines in this RD */ + RoutineRecord routineRecords[1]; /* The individual routines */ +}; + +#define BUILD_PPC_ROUTINE_DESCRIPTOR(procInfo, procedure) \ + { \ + 0xAAFE, /* Mixed Mode A-Trap */ \ + 7, /* version */ \ + 0, /* RD Flags - not dispatched */ \ + 0, /* reserved 1 */ \ + 0, /* reserved 2 */ \ + 0, /* selector info */ \ + 0, /* number of routines */ \ + { /* It's an array */ \ + { /* It's a struct */ \ + (procInfo), /* the ProcInfo */ \ + 0, /* reserved */ \ + 1, /* ISA and RTA */ \ + 0 | /* Flags - it's absolute addr */\ + 0 | /* It's prepared */ \ + 4, /* Always use native ISA */ \ + (ProcPtr)(procedure), /* the procedure */ \ + 0, /* reserved */ \ + 0 /* Not dispatched */ \ + } \ + } \ + } + + +// Functions +extern void MacOSUtilReset(void); +extern void Enqueue(uint32 elem, uint32 list); // Enqueue QElem to list +extern int FindFreeDriveNumber(int num); // Find first free drive number, starting at "num" +extern void MountVolume(void *fh); // Mount volume with given file handle (see sys.h) +extern void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size); // Calculate disk image file layout given file size and first 256 data bytes +extern void *FindLibSymbol(char *lib, char *sym); // Find symbol in shared library +extern void InitCallUniversalProc(void); // Init CallUniversalProc() +extern long CallUniversalProc(void *upp, uint32 info); // CallUniversalProc() +extern uint32 TimeToMacTime(time_t t); // Convert time_t value to MacOS time + +// Construct four-character-code from string +#define FOURCC(a,b,c,d) (((uint32)(a) << 24) | ((uint32)(b) << 16) | ((uint32)(c) << 8) | (uint32)(d)) + +// Emulator identification codes (4 and 2 characters) +const uint32 EMULATOR_ID_4 = 0x62616168; // 'baah' +const uint16 EMULATOR_ID_2 = 0x6261; // 'ba' + +// Test if basic MacOS initializations (of the ROM) are done +static inline bool HasMacStarted(void) +{ + return ReadMacInt32(0xcfc) == FOURCC('W','L','S','C'); // Mac warm start flag +} + +#endif diff --git a/SheepShaver/src/include/main.h b/SheepShaver/src/include/main.h new file mode 100644 index 00000000..4a595524 --- /dev/null +++ b/SheepShaver/src/include/main.h @@ -0,0 +1,76 @@ +/* + * main.h - Emulation core + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 MAIN_H +#define MAIN_H + +// Global variables +extern void *TOC; // TOC pointer +extern uint32 KernelDataAddr; // Address of Kernel Data +extern uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM +extern uint32 PVR; // Theoretical PVR +extern int64 CPUClockSpeed; // Processor clock speed (Hz) +extern int64 BusClockSpeed; // Bus clock speed (Hz) + +#ifdef __BEOS__ +extern system_info SysInfo; // System information +#endif + +// 68k register structure (for Execute68k()) +struct M68kRegisters { + uint32 d[8]; + uint32 a[8]; +}; + + +// Functions +extern void Dump68kRegs(M68kRegisters *r); // Dump 68k registers +extern void MakeExecutable(int dummy, void *start, uint32 length); // Make code executable +extern void PatchAfterStartup(void); // Patches after system startup +extern void QuitEmulator(void); // Quit emulator (must only be called from main thread) +extern void ErrorAlert(const char *text); // Display error alert +extern void WarningAlert(const char *text); // Display warning alert +extern bool ChoiceAlert(const char *text, const char *pos, const char *neg); // Display choice alert + +// Mutexes (non-recursive) +struct B2_mutex; +extern B2_mutex *B2_create_mutex(void); +extern void B2_lock_mutex(B2_mutex *mutex); +extern void B2_unlock_mutex(B2_mutex *mutex); +extern void B2_delete_mutex(B2_mutex *mutex); + +// Interrupt flags +enum { + INTFLAG_VIA = 1, // 60.15Hz VBL + INTFLAG_SERIAL = 2, // Serial driver + INTFLAG_ETHER = 4, // Ethernet driver + INTFLAG_AUDIO = 16, // Audio block read + INTFLAG_TIMER = 32, // Time Manager + INTFLAG_ADB = 64 // ADB +}; + +extern volatile uint32 InterruptFlags; // Currently pending interrupts +extern void SetInterruptFlag(uint32); +extern void ClearInterruptFlag(uint32); +extern void TriggerInterrupt(void); // Trigger SIGUSR1 interrupt in emulator thread +extern void DisableInterrupt(void); // Disable SIGUSR1 interrupt (can be nested) +extern void EnableInterrupt(void); // Enable SIGUSR1 interrupt (can be nested) + +#endif diff --git a/SheepShaver/src/include/name_registry.h b/SheepShaver/src/include/name_registry.h new file mode 100644 index 00000000..a417e31e --- /dev/null +++ b/SheepShaver/src/include/name_registry.h @@ -0,0 +1,26 @@ +/* + * name_registry.h - Name Registry handling + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 NAME_REGISTRY_H +#define NAME_REGISTRY_H + +extern void PatchNameRegistry(void); + +#endif diff --git a/SheepShaver/src/include/prefs_editor.h b/SheepShaver/src/include/prefs_editor.h new file mode 100644 index 00000000..54daaf34 --- /dev/null +++ b/SheepShaver/src/include/prefs_editor.h @@ -0,0 +1,30 @@ +/* + * prefs_editor.h - Preferences editor + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 PREFS_EDITOR_H +#define PREFS_EDITOR_H + +#ifdef __BEOS__ +extern void PrefsEditor(uint32 msg); +#else +extern bool PrefsEditor(void); +#endif + +#endif diff --git a/SheepShaver/src/include/rom_patches.h b/SheepShaver/src/include/rom_patches.h new file mode 100644 index 00000000..c0916410 --- /dev/null +++ b/SheepShaver/src/include/rom_patches.h @@ -0,0 +1,40 @@ +/* + * rom_patches.h - ROM patches + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 ROM_PATCHES_H +#define ROM_PATCHES_H + +// ROM types +enum { + ROMTYPE_TNT, + ROMTYPE_ALCHEMY, + ROMTYPE_ZANZIBAR, + ROMTYPE_GAZELLE, + ROMTYPE_NEWWORLD +}; +extern int ROMType; + +extern bool PatchROM(void); +extern void InstallDrivers(void); + +extern void AddSifter(uint32 type, int16 id); +extern bool FindSifter(uint32 type, int16 id); + +#endif diff --git a/SheepShaver/src/include/rsrc_patches.h b/SheepShaver/src/include/rsrc_patches.h new file mode 100644 index 00000000..7634244b --- /dev/null +++ b/SheepShaver/src/include/rsrc_patches.h @@ -0,0 +1,27 @@ +/* + * rsrc_patches.h - Resource patches + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 RSRC_PATCHES_H +#define RSRC_PATCHES_H + +extern void CheckLoad(uint32 type, int16 id, uint16 *p, uint32 size); +extern void PatchNativeResourceManager(void); + +#endif diff --git a/SheepShaver/src/include/user_strings.h b/SheepShaver/src/include/user_strings.h new file mode 100644 index 00000000..f5fbdd9d --- /dev/null +++ b/SheepShaver/src/include/user_strings.h @@ -0,0 +1,161 @@ +/* + * user_strings.h - Localizable strings + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 USER_STRINGS_H +#define USER_STRINGS_H + +// Common string numbers +enum { + // General messages + STR_ABOUT_TEXT1 = 0, + STR_ABOUT_TEXT2, + STR_READING_ROM_FILE, + STR_SHELL_ERROR_PREFIX, + STR_GUI_ERROR_PREFIX, + STR_ERROR_ALERT_TITLE, + STR_SHELL_WARNING_PREFIX, + STR_GUI_WARNING_PREFIX, + STR_WARNING_ALERT_TITLE, + STR_NOTICE_ALERT_TITLE, + STR_ABOUT_TITLE, + STR_OK_BUTTON, + STR_START_BUTTON, + STR_QUIT_BUTTON, + STR_CANCEL_BUTTON, + STR_IGNORE_BUTTON, + + // Error messages + STR_NOT_ENOUGH_MEMORY_ERR = 1000, + STR_NO_KERNEL_DATA_ERR, + STR_NO_RAM_AREA_ERR, + STR_NO_ROM_FILE_ERR, + STR_RAM_HIGHER_THAN_ROM_ERR, + STR_ROM_FILE_READ_ERR, + STR_ROM_SIZE_ERR, + STR_UNSUPPORTED_ROM_TYPE_ERR, + STR_POWER_INSTRUCTION_ERR, + STR_MEM_ACCESS_ERR, + STR_MEM_ACCESS_READ, + STR_MEM_ACCESS_WRITE, + STR_UNKNOWN_SEGV_ERR, + STR_NO_NAME_REGISTRY_ERR, + STR_FULL_SCREEN_ERR, + STR_SCSI_BUFFER_ERR, + STR_SCSI_SG_FULL_ERR, + + // Warning messages + STR_SMALL_RAM_WARN = 2000, + STR_VOLUME_IS_MOUNTED_WARN, + STR_CANNOT_UNMOUNT_WARN, + STR_CREATE_VOLUME_WARN, + + // Preferences window + STR_PREFS_TITLE = 3000, + STR_PREFS_MENU = 3020, + STR_PREFS_ITEM_ABOUT, + STR_PREFS_ITEM_START, + STR_PREFS_ITEM_ZAP_PRAM, + STR_PREFS_ITEM_QUIT, + + // Volumes pane + STR_VOLUMES_PANE_TITLE = 3200, + STR_ADD_VOLUME_BUTTON, + STR_CREATE_VOLUME_BUTTON, + STR_REMOVE_VOLUME_BUTTON, + STR_ADD_VOLUME_PANEL_BUTTON, + STR_CREATE_VOLUME_PANEL_BUTTON, + STR_BOOTDRIVER_CTRL, + STR_BOOT_ANY_LAB, + STR_BOOT_CDROM_LAB, + STR_NOCDROM_CTRL, + STR_EXTFS_CTRL, + STR_ADD_VOLUME_TITLE, + STR_CREATE_VOLUME_TITLE, + STR_HARDFILE_SIZE_CTRL, + + // Graphics pane + STR_GRAPHICS_SOUND_PANE_TITLE = 3300, + STR_FRAMESKIP_CTRL, + STR_REF_5HZ_LAB, + STR_REF_7_5HZ_LAB, + STR_REF_10HZ_LAB, + STR_REF_15HZ_LAB, + STR_REF_30HZ_LAB, + STR_REF_60HZ_LAB, + STR_GFXACCEL_CTRL, + STR_8_BIT_CTRL, + STR_16_BIT_CTRL, + STR_32_BIT_CTRL, + STR_W_640x480_CTRL, + STR_W_800x600_CTRL, + STR_640x480_CTRL, + STR_800x600_CTRL, + STR_1024x768_CTRL, + STR_1152x900_CTRL, + STR_1280x1024_CTRL, + STR_1600x1200_CTRL, + STR_VIDEO_MODE_CTRL, + STR_FULLSCREEN_CTRL, + STR_NOSOUND_CTRL, + + // Serial/Network pane + STR_SERIAL_NETWORK_PANE_TITLE = 3400, + STR_SERPORTA_CTRL, + STR_SERPORTB_CTRL, + STR_NONET_CTRL, + STR_ETHERNET_IF_CTRL, + + // Memory/Misc pane + STR_MEMORY_MISC_PANE_TITLE = 3500, + STR_RAMSIZE_SLIDER, + STR_RAMSIZE_FMT, + STR_IGNORESEGV_CTRL, + STR_IDLEWAIT_CTRL, + STR_ROM_FILE_CTRL, + + // Mac window + STR_WINDOW_TITLE = 4000, + STR_WINDOW_TITLE_FROZEN, + STR_WINDOW_MENU = 4050, + STR_WINDOW_ITEM_ABOUT, + STR_WINDOW_ITEM_REFRESH, + STR_WINDOW_ITEM_MOUNT, + + // Audio + STR_SOUND_IN_NAME = 6000, + + // External file system + STR_EXTFS_NAME = 7000, + STR_EXTFS_VOLUME_NAME +}; + +// Common and platform-specific string definitions +struct user_string_def { + int num; + const char *str; +}; + +extern user_string_def common_strings[]; +extern user_string_def platform_strings[]; + +// Fetch pointer to string, given the string number +extern const char *GetString(int num); + +#endif diff --git a/SheepShaver/src/include/version.h b/SheepShaver/src/include/version.h new file mode 100644 index 00000000..61ec5049 --- /dev/null +++ b/SheepShaver/src/include/version.h @@ -0,0 +1,27 @@ +/* + * version.h - Version information + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 VERSION_H +#define VERSION_H + +const int VERSION_MAJOR = 2; +const int VERSION_MINOR = 2; + +#endif diff --git a/SheepShaver/src/include/video.h b/SheepShaver/src/include/video.h new file mode 100644 index 00000000..ef08a4ef --- /dev/null +++ b/SheepShaver/src/include/video.h @@ -0,0 +1,113 @@ +/* + * video.h - Video/graphics emulation + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * 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 VIDEO_H +#define VIDEO_H + +extern bool VideoActivated(void); +extern bool VideoSnapshot(int xsize, int ysize, uint8 *p); + +extern int16 VideoDoDriverIO(void *spaceID, void *commandID, void *commandContents, uint32 commandCode, uint32 commandKind); + +// System specific and internal functions/data +struct VideoInfo { + int viType; // Screen/Window + uint32 viRowBytes; // width of each row in memory + uint16 viXsize,viYsize; // Window + uint32 viAppleMode; // Screen Color Depth + uint32 viAppleID; // Screen DisplayID +}; + +extern struct VideoInfo VModes[]; // List of available video modes + +enum { // viAppleMode + APPLE_1_BIT = 0x80, + APPLE_2_BIT, + APPLE_4_BIT, + APPLE_8_BIT, + APPLE_16_BIT, + APPLE_32_BIT +}; + +enum { // viAppleID + APPLE_640x480 = 0x81, + APPLE_W_640x480, + APPLE_800x600, + APPLE_W_800x600, + APPLE_1024x768, + APPLE_1152x900, + APPLE_1280x1024, + APPLE_1600x1200, + APPLE_ID_MIN = APPLE_640x480, + APPLE_ID_MAX = APPLE_1600x1200 +}; + +enum { // Display type + DIS_INVALID, + DIS_SCREEN, + DIS_WINDOW +}; + +extern bool video_activated; // Flag: video display activated, mouse and keyboard data valid +extern uint32 screen_base; // Frame buffer base address +extern int cur_mode; // Number of current video mode (index in VModes array) +extern int display_type; // Current display type (see above) +extern rgb_color mac_pal[256]; +extern uint8 remap_mac_be[256]; +extern uint8 MacCursor[68]; + +struct GammaTbl; + +struct VidLocals{ + uint16 saveMode; + uint32 saveData; + uint16 savePage; + uint32 saveBaseAddr; + GammaTbl *gammaTable; // Current gamma table + uint32 maxGammaTableSize; // Biggest gamma table allocated + uint32 saveVidParms; + bool luminanceMapping; // Luminance mapping on/off + int32 cursorX; // Hardware cursor state. Unused, but must be remembered + int32 cursorY; + uint32 cursorVisible; + uint32 cursorSet; + uint32 vslServiceID; // VSL interrupt service ID + bool interruptsEnabled; // VBL interrupts on/off + uint32 regEntryID[4]; +}; + +extern VidLocals *private_data; // Pointer to driver local variables (there is only one display, so this is ok) + +extern bool VideoInit(void); +extern void VideoExit(void); +extern void VideoVBL(void); +extern void VideoInstallAccel(void); +extern void VideoQuitFullScreen(void); + +extern void video_set_palette(void); +extern void video_set_cursor(void); +extern int16 video_mode_change(VidLocals *csSave, uint32 ParamPtr); + +extern int16 VSLDoInterruptService(uint32 arg1); +extern void NQDMisc(uint32 arg1, void *arg2); + +extern bool keyfile_valid; + +#endif diff --git a/SheepShaver/src/include/video_defs.h b/SheepShaver/src/include/video_defs.h new file mode 100644 index 00000000..b8a3ec8f --- /dev/null +++ b/SheepShaver/src/include/video_defs.h @@ -0,0 +1,381 @@ +/* + * video_defs.h - MacOS types and structures for video + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * 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 VIDEO_DEFS_H +#define VIDEO_DEFS_H + +#include "macos_util.h" + + +/* + * Definitions for Display Manager + */ + +/* csMode values describing pixel depth in VDSwitchInfo */ +enum { + firstVidMode=128, // first depth mode, representing lowest supported + // pixel depth + secondVidMode, thirdVidMode, fourthVidMode, fifthVidMode, sixthVidMode + // following modes represent pixel depths in ascending + // order +}; + +/* csDisplayType values in VDDisplayConnectInfoRec */ +enum { + kUnknownConnect=1, // reserved + kPanelTFTConnect, // fixed-in-place LCS (TFT, aka "active matrix") panels + kFixedModeCRTConnect, // very limited displays + kMultiModeCRT1Connect, // 12" optional, 13" default, 16" required + kMultiModeCRT2Connect, // 12" optional, 13" req., 16" def., 19" req. + kMultiModeCRT3Connect, // 12" optional, 13" req., 16" req., 19" req.,21" def. + kMultiModeCRT4Connect, // expansion to large multimode (not yet implemented) + kModelessConnect, // expansion to modeless model (not yet implemented) + kFullPageConnect, // 640x818 (to get 8bpp in 512K case) and + // 640x870 (nothing else supported) + kVGAConnect, // 640x480 VGA default -- nothing else req. + kNTSCConnect, // NTSC ST(default), FF, STconv, FFconv + kPALConnect, // PAL ST(default), FF, STconv, FFconv + kHRConnect, // 640x400 (to get 8bpp in 256K case) and + // 640x480 (nothing else supported) + kPanelFSTNConnect // fixed-in-place LCD FSTN (aka "supertwist") panels +}; + +/* csConnectFlags values in VDDisplayConnectInfoRec */ +enum { + kAllModesValid=0, // all display modes not deleted by PrimaryInit code + // are optional + kAllModesSafe, // all display modes not deleted by PrimaryInit code + // are required; is you set this bit, set the + // kAllModesValid bit, too + kHasDirectConnect=3, // for future expansions, setting this bit means that + // your driver can talk directly to the display + // (e.g. there is a serial data link via sense lines) + kIsMonoDev, // this display does not support color + kUncertainConnect // there may not be a display; Monitors control panel + // makes the user confirm some operations--like moving + // the menu bar-- when this bit is set +}; + +/* csTimingFormat value in VDTimingInfoRec */ +#define kDeclROMtables FOURCC('d','e','c','l') // use information in this record instead of looking + // in the decl. ROM for timing info; used for patching + // existing card without updating declaration ROM + +/* csTimingData values in VDTimingInfoRec */ +enum { + timingUnknown = 0, // unknown timing + timingApple_512x384_60hz = 130, /* 512x384 (60 Hz) Rubik timing. */ + timingApple_560x384_60hz = 135, /* 560x384 (60 Hz) Rubik-560 timing. */ + timingApple_640x480_67hz = 140, /* 640x480 (67 Hz) HR timing. */ + timingApple_640x400_67hz = 145, /* 640x400 (67 Hz) HR-400 timing. */ + timingVESA_640x480_60hz = 150, /* 640x480 (60 Hz) VGA timing. */ + timingVESA_640x480_72hz = 152, /* 640x480 (72 Hz) VGA timing. */ + timingVESA_640x480_75hz = 154, /* 640x480 (75 Hz) VGA timing. */ + timingVESA_640x480_85hz = 158, /* 640x480 (85 Hz) VGA timing. */ + timingGTF_640x480_120hz = 159, /* 640x480 (120 Hz) VESA Generalized Timing Formula */ + timingApple_640x870_75hz = 160, /* 640x870 (75 Hz) FPD timing.*/ + timingApple_640x818_75hz = 165, /* 640x818 (75 Hz) FPD-818 timing.*/ + timingApple_832x624_75hz = 170, /* 832x624 (75 Hz) GoldFish timing.*/ + timingVESA_800x600_56hz = 180, /* 800x600 (56 Hz) SVGA timing. */ + timingVESA_800x600_60hz = 182, /* 800x600 (60 Hz) SVGA timing. */ + timingVESA_800x600_72hz = 184, /* 800x600 (72 Hz) SVGA timing. */ + timingVESA_800x600_75hz = 186, /* 800x600 (75 Hz) SVGA timing. */ + timingVESA_800x600_85hz = 188, /* 800x600 (85 Hz) SVGA timing. */ + timingVESA_1024x768_60hz = 190, /* 1024x768 (60 Hz) VESA 1K-60Hz timing. */ + timingVESA_1024x768_70hz = 200, /* 1024x768 (70 Hz) VESA 1K-70Hz timing. */ + timingVESA_1024x768_75hz = 204, /* 1024x768 (75 Hz) VESA 1K-75Hz timing (very similar to timingApple_1024x768_75hz). */ + timingVESA_1024x768_85hz = 208, /* 1024x768 (85 Hz) VESA timing. */ + timingApple_1024x768_75hz = 210, /* 1024x768 (75 Hz) Apple 19" RGB. */ + timingApple_1152x870_75hz = 220, /* 1152x870 (75 Hz) Apple 21" RGB. */ + timingVESA_1280x960_75hz = 250, /* 1280x960 (75 Hz) */ + timingVESA_1280x960_60hz = 252, /* 1280x960 (60 Hz) */ + timingVESA_1280x960_85hz = 254, /* 1280x960 (85 Hz) */ + timingVESA_1280x1024_60hz = 260, /* 1280x1024 (60 Hz) */ + timingVESA_1280x1024_75hz = 262, /* 1280x1024 (75 Hz) */ + timingVESA_1280x1024_85hz = 268, /* 1280x1024 (85 Hz) */ + timingVESA_1600x1200_60hz = 280, /* 1600x1200 (60 Hz) VESA proposed timing. */ + timingVESA_1600x1200_65hz = 282, /* 1600x1200 (65 Hz) VESA proposed timing. */ + timingVESA_1600x1200_70hz = 284, /* 1600x1200 (70 Hz) VESA proposed timing. */ + timingVESA_1600x1200_75hz = 286, /* 1600x1200 (75 Hz) VESA proposed timing. */ + timingVESA_1600x1200_80hz = 288, /* 1600x1200 (80 Hz) VESA proposed timing (pixel clock is 216 Mhz dot clock). */ + timingSMPTE240M_60hz = 400, /* 60Hz V, 33.75KHz H, interlaced timing, 16:9 aspect, typical resolution of 1920x1035. */ + timingFilmRate_48hz = 410 /* 48Hz V, 25.20KHz H, non-interlaced timing, typical resolution of 640x480. */ +}; + +/* csTimingFlags values in VDTimingInfoRec */ +enum { + kModeValid=0, // this display mode is optional + kModeSafe, // this display mode is required; if you set this + // bit, you should also set the kModeValid bit + kModeDefault, // this display mode is the default for the attached + // display; if you set this bit, you should also set + // the kModeSafe and kModeValid bits + kShowModeNow, // show this mode in Monitors control panel; useful + // for SVGA modes + kModeNotResize, + kModeRequiresPan +}; + +/* code for Display Manager control request */ +enum { + cscReset=0, + cscKillIO, + cscSetMode, + cscSetEntries, + cscSetGamma, + cscGrayPage, + cscGrayScreen=5, + cscSetGray, + cscSetInterrupt, + cscDirectSetEntries, + cscSetDefaultMode, + cscSwitchMode, // switch to another display mode + cscSetSync, + cscSavePreferredConfiguration=16, + cscSetHardwareCursor=22, + cscDrawHardwareCursor, + cscSetConvolution, + cscSetPowerState, + cscPrivateControlCall, // Takes a VDPrivateSelectorDataRec + cscSetMultiConnect, // From a GDI point of view, this call should be implemented completely in the HAL and not at all in the core. + cscSetClutBehavior, // Takes a VDClutBehavior + cscUnusedCall=127 // This call used to expend the scrn resource. Its imbedded data contains more control info +}; + +/* Constants for the GetNextResolution call */ + +enum { + kDisplayModeIDCurrent = 0x00, /* Reference the Current DisplayModeID */ + kDisplayModeIDInvalid = (long)0xFFFFFFFF, /* A bogus DisplayModeID in all cases */ + kDisplayModeIDFindFirstResolution = (long)0xFFFFFFFE, /* Used in cscGetNextResolution to reset iterator */ + kDisplayModeIDNoMoreResolutions = (long)0xFFFFFFFD /* Used in cscGetNextResolution to indicate End Of List */ +}; + +/* codes for Display Manager status requests */ +enum { + cscGetMode=2, + cscGetEntries, + cscGetPageCnt, + cscGetPages=4, // This is what C&D 2 calls it. + cscGetPageBase, + cscGetBaseAddr=5, // This is what C&D 2 calls it. + cscGetGray, + cscGetInterrupt, + cscGetGamma, + cscGetDefaultMode, + cscGetCurMode, // save the current display mode + cscGetSync, + cscGetConnection, // return information about display capabilities of + // connected display + cscGetModeTiming, // return scan timings data for a display mode + cscGetModeBaseAddress, // Return base address information about a particular mode + cscGetScanProc, // QuickTime scan chasing routine + cscGetPreferredConfiguration, + cscGetNextResolution, + cscGetVideoParameters, + cscGetGammaInfoList =20, + cscRetrieveGammaTable, + cscSupportsHardwareCursor, + cscGetHardwareCursorDrawState, + cscGetConvolution, + cscGetPowerState, + cscPrivateStatusCall, // Takes a VDPrivateSelectorDataRec + cscGetDDCBlock, // Takes a VDDDCBlockRec + cscGetMultiConnect, // From a GDI point of view, this call should be implemented completely in the HAL and not at all in the core. + cscGetClutBehavior // Takes a VDClutBehavior +}; + +enum { // VDSwitchInfo struct + csMode = 0, + csData = 2, + csPage = 6, + csBaseAddr = 8 +}; + +enum { // VDSetEntry struct + csTable = 0, // Pointer to ColorSpec[] + csStart = 4, + csCount = 6 +}; + +struct ColorSpec { + uint16 value; + uint16 red; + uint16 green; + uint16 blue; +}; + +enum { // VDVideoParametersInfo struct + csDisplayModeID = 0, + csDepthMode = 4, + csVPBlockPtr = 6, + csPageCount = 10, + csDeviceType = 14 +}; + +enum { // VPBlock struct + vpBaseOffset = 0, + vpRowBytes = 4, + vpBounds = 6, + vpVersion = 14, + vpPackType = 16, + vpPackSize = 18, + vpHRes = 22, + vpVRes = 26, + vpPixelType = 30, + vpPixelSize = 32, + vpCmpCount = 34, + vpCmpSize = 36, + vpPlaneBytes = 38 +}; + +enum { // VDDisplayConnectInfo struct + csDisplayType = 0, + csConnectTaggedType = 2, + csConnectTaggedData = 3, + csConnectFlags = 4, + csDisplayComponent = 8, + csConnectReserved = 12 +}; + +enum { // VDTimingInfo struct + csTimingMode = 0, + csTimingReserved = 4, + csTimingFormat = 8, + csTimingData = 12, + csTimingFlags = 16 +}; + +enum { // VDResolutionInfo struct + csPreviousDisplayModeID = 0, + csRIDisplayModeID = 4, + csHorizontalPixels = 8, + csVerticalLines = 12, + csRefreshRate = 16, + csMaxDepthMode = 20, + csResolutionFlags = 22 +}; + +enum { // VDDrawHardwareCursor/VDHardwareCursorDrawState struct + csCursorX = 0, + csCursorY = 4, + csCursorVisible = 8, + csCursorSet = 12 +}; + +struct GammaTbl { + uint16 gVersion; + uint16 gType; + uint16 gFormulaSize; + uint16 gChanCnt; + uint16 gDataCnt; + uint16 gDataWidth; + uint16 gFormulaData[1]; +}; + +enum { + kCursorImageMajorVersion = 0x0001, + kCursorImageMinorVersion = 0x0000 +}; + +enum { // CursorImage struct + ciMajorVersion = 0, + ciMinorVersion = 2, + ciCursorPixMap = 4, // Handle to PixMap + ciCursorBitMask = 8 // Handle to BitMap +}; + + +/* + * Structures for graphics acceleration + */ + +typedef void *CTabHandle; + +// Parameter block passed to acceleration hooks +struct accl_params { + uint32 unknown0[3]; + + uint32 transfer_mode; + uint32 pen_mode; + + uint32 unknown1[2]; + + uint32 fore_pen; + uint32 back_pen; + + uint32 unknown2[3]; + + uint32 src_base_addr; + uint32 src_row_bytes; + int16 src_bounds[4]; + uint32 src_unknown1; + uint32 src_pixel_type; + uint32 src_pixel_size; + uint32 src_cmp_count; + uint32 src_cmp_size; + CTabHandle src_pm_table; + uint32 src_unknown2; + uint32 src_unknown3; + uint32 src_unknown4; + + uint32 dest_base_addr; + uint32 dest_row_bytes; + int16 dest_bounds[4]; + uint32 dest_unknown1; + uint32 dest_pixel_type; + uint32 dest_pixel_size; + uint32 dest_cmp_count; + uint32 dest_cmp_size; + CTabHandle dest_pm_table; + uint32 dest_unknown2; + uint32 dest_unknown3; + uint32 dest_unknown4; + + uint32 unknown3[13]; + + int16 src_rect[4]; + int16 dest_rect[4]; + + uint32 unknown4[38]; + + void (*draw_proc)(accl_params *); + // Argument for accl_sync_hook at offset 0x4f8 +}; + +// Hook info for NQDMisc +struct accl_hook_info { + bool (*draw_func)(accl_params *); + bool (*sync_func)(void *); + uint32 code; +}; + +// Hook function index +enum { + ACCL_BITBLT, + ACCL_BLTMASK, + ACCL_FILLRECT, + ACCL_FILLMASK + // 4: bitblt + // 5: lines + // 6: fill +}; + +#endif diff --git a/SheepShaver/src/include/xlowmem.h b/SheepShaver/src/include/xlowmem.h new file mode 100644 index 00000000..be5b5816 --- /dev/null +++ b/SheepShaver/src/include/xlowmem.h @@ -0,0 +1,58 @@ +/* + * xlowmem.h - Definitions for extra Low Memory globals (0x2800..) + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 XLOWMEM_H +#define XLOWMEM_H + +// Modes for XLM_RUN_MODE +#define MODE_68K 0 // 68k emulator active +#define MODE_NATIVE 1 // Switched to native mode +#define MODE_EMUL_OP 2 // 68k emulator active, within EMUL_OP routine + +#define XLM_SIGNATURE 0x2800 // SheepShaver signature +#define XLM_KERNEL_DATA 0x2804 // Pointer to Kernel Data +#define XLM_TOC 0x2808 // TOC pointer of emulator +#define XLM_SHEEP_OBJ 0x280c // Pointer to SheepShaver object +#define XLM_RUN_MODE 0x2810 // Current run mode, see enum above +#define XLM_68K_R25 0x2814 // Contents of the 68k emulator's r25 (which contains the interrupt level), saved upon entering EMUL_OP mode, used by Execute68k() and the USR1 signal handler +#define XLM_IRQ_NEST 0x2818 // Interrupt disable nesting counter (>0: disabled) +#define XLM_PVR 0x281c // Theoretical PVR +#define XLM_BUS_CLOCK 0x2820 // Bus clock speed in Hz (for DriverServicesLib patch) +#define XLM_EMUL_RETURN_PROC 0x2824 // Pointer to EMUL_RETURN routine +#define XLM_EXEC_RETURN_PROC 0x2828 // Pointer to EXEC_RETURN routine +#define XLM_EMUL_OP_PROC 0x282c // Pointer to EMUL_OP routine +#define XLM_EMUL_RETURN_STACK 0x2830 // Stack pointer for EMUL_RETURN +#define XLM_RES_LIB_TOC 0x2834 // TOC pointer of Resources library +#define XLM_GET_RESOURCE 0x2838 // Pointer to native GetResource() routine +#define XLM_GET_1_RESOURCE 0x283c // Pointer to native Get1Resource() routine +#define XLM_GET_IND_RESOURCE 0x2840 // Pointer to native GetIndResource() routine +#define XLM_GET_1_IND_RESOURCE 0x2844 // Pointer to native Get1IndResource() routine +#define XLM_R_GET_RESOURCE 0x2848 // Pointer to native RGetResource() routine +#define XLM_EXEC_RETURN_OPCODE 0x284c // EXEC_RETURN opcode for Execute68k() + +#define XLM_ETHER_INIT 0x28c0 // Pointer to ethernet InitStreamModule() function +#define XLM_ETHER_TERM 0x28c4 // Pointer to ethernet TerminateStreamModule() function +#define XLM_ETHER_OPEN 0x28c8 // Pointer to ethernet ether_open() function +#define XLM_ETHER_CLOSE 0x28cc // Pointer to ethernet ether_close() function +#define XLM_ETHER_WPUT 0x28d0 // Pointer to ethernet ether_wput() function +#define XLM_ETHER_RSRV 0x28d4 // Pointer to ethernet ether_rsrv() function +#define XLM_VIDEO_DOIO 0x28d8 // Pointer to video DoDriverIO() function + +#endif diff --git a/SheepShaver/src/macos_util.cpp b/SheepShaver/src/macos_util.cpp new file mode 100644 index 00000000..70f50215 --- /dev/null +++ b/SheepShaver/src/macos_util.cpp @@ -0,0 +1,306 @@ +/* + * macos_util.cpp - MacOS definitions/utility functions + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include "cpu_emulation.h" +#include "main.h" +#include "sony.h" +#include "disk.h" +#include "cdrom.h" +#include "xlowmem.h" +#include "emul_op.h" +#include "macos_util.h" + +#define DEBUG 0 +#include "debug.h" + + +// Function pointers +typedef long (*cu_ptr)(void *, uint32); +static uint32 cu_tvect = 0; +static inline long CallUniversal(void *arg1, uint32 arg2) +{ + return (long)CallMacOS2(cu_ptr, cu_tvect, arg1, arg2); +} +typedef int16 (*gsl_ptr)(char *, uint32, uint32, uint32 *, void **, char *); +static uint32 gsl_tvect = 0; +static inline int16 GetSharedLibrary(char *arg1, uint32 arg2, uint32 arg3, uint32 *arg4, void **arg5, char *arg6) +{ + return (int16)CallMacOS6(gsl_ptr, gsl_tvect, arg1, arg2, arg3, arg4, arg5, arg6); +} +typedef int16 (*fs_ptr)(uint32, char *, void **, uint32 *); +static uint32 fs_tvect = 0; +static inline int16 FindSymbol(uint32 arg1, char *arg2, void **arg3, uint32 *arg4) +{ + return (int16)CallMacOS4(fs_ptr, fs_tvect, arg1, arg2, arg3, arg4); +} +typedef int16 (*cc_ptr)(uint32 *); +static uint32 cc_tvect = 0; +static inline int16 CloseConnection(uint32 *arg1) +{ + return (int16)CallMacOS1(cc_ptr, cc_tvect, arg1); +} + + +/* + * Reset MacOS utilities + */ + +void MacOSUtilReset(void) +{ + cu_tvect = 0; + gsl_tvect = 0; + fs_tvect = 0; + cc_tvect = 0; +} + + +/* + * Enqueue QElem to list + */ + +void Enqueue(uint32 elem, uint32 list) +{ + WriteMacInt32(elem + qLink, 0); + if (!ReadMacInt32(list + qTail)) { + WriteMacInt32(list + qHead, elem); + WriteMacInt32(list + qTail, elem); + } else { + WriteMacInt32(ReadMacInt32(list + qTail) + qLink, elem); + WriteMacInt32(list + qTail, elem); + } +} + + +/* + * Find first free drive number, starting at num + */ + +static bool is_drive_number_free(int num) +{ + uint32 e = ReadMacInt32(0x308 + qHead); + while (e) { + uint32 d = e - dsQLink; + if ((int)ReadMacInt16(d + dsQDrive) == num) + return false; + e = ReadMacInt32(e + qLink); + } + return true; +} + +int FindFreeDriveNumber(int num) +{ + while (!is_drive_number_free(num)) + num++; + return num; +} + + +/* + * Mount volume with given file handle (call this function when you are unable to + * do automatic media change detection and the user has to press a special key + * or something to mount a volume; this function will check if there's really a + * volume in the drive with SysIsDiskInserted(); volumes which are present on startup + * are automatically mounted) + */ + +void MountVolume(void *fh) +{ + SonyMountVolume(fh) || DiskMountVolume(fh) || CDROMMountVolume(fh); +} + + +/* + * Calculate disk image file layout given file size and first 256 data bytes + */ + +void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) +{ + if (size == 419284 || size == 838484) { + // 400K/800K DiskCopy image, 84 byte header + start_byte = 84; + real_size = (size - 84) & ~0x1ff; + } else { + // 0..511 byte header + start_byte = size & 0x1ff; + real_size = size - start_byte; + } +} + + +/* + * Find symbol in shared library (using CFM) + * lib and sym must be Pascal strings! + */ + +void *FindLibSymbol(char *lib, char *sym) +{ + uint32 conn_id = 0; + void *main_addr = NULL; + char err[256] = ""; + uint32 *sym_addr = NULL; + uint32 sym_class = 0; + + D(bug("FindLibSymbol %s in %s...\n", sym+1, lib+1)); + + if (*(uint32 *)XLM_RUN_MODE == MODE_EMUL_OP) { + M68kRegisters r; + + // Find shared library + static const uint16 proc1[] = { + 0x558f, // subq.l #2,a7 + 0x2f08, // move.l a0,-(a7) + 0x2f3c, 0x7077, 0x7063, // move.l #'pwpc',-(a7) + 0x2f3c, 0, 1, // move.l #kReferenceCFrag,-(a7) + 0x2f09, // move.l a1,-(a7) + 0x2f0a, // move.l a2,-(a7) + 0x2f0b, // move.l a3,-(a7) + 0x3f3c, 1, // (GetSharedLibrary) + 0xaa5a, // CFMDispatch + 0x301f, // move.w (a7)+,d0 + M68K_RTS + }; + r.a[0] = (uint32)lib; + r.a[1] = (uint32)&conn_id; + r.a[2] = (uint32)&main_addr; + r.a[3] = (uint32)err; + Execute68k((uint32)proc1, &r); + D(bug(" GetSharedLibrary: ret %d, connection ID %ld, main %p\n", (int16)r.d[0], conn_id, main_addr)); + if (r.d[0]) + return NULL; + + // Find symbol + static const uint16 proc2[] = { + 0x558f, // subq.l #2,a7 + 0x2f00, // move.l d0,-(a7) + 0x2f08, // move.l a0,-(a7) + 0x2f09, // move.l a1,-(a7) + 0x2f0a, // move.l a2,-(a7) + 0x3f3c, 5, // (FindSymbol) + 0xaa5a, // CFMDispatch + 0x301f, // move.w (a7)+,d0 + M68K_RTS + }; + r.d[0] = conn_id; + r.a[0] = (uint32)sym; + r.a[1] = (uint32)&sym_addr; + r.a[2] = (uint32)&sym_class; + Execute68k((uint32)proc2, &r); + D(bug(" FindSymbol: ret %d, sym_addr %p, sym_class %ld\n", (int16)r.d[0], sym_addr, sym_class)); +//!! CloseConnection()? + if (r.d[0]) + return NULL; + else + return sym_addr; + + } else { + + if (GetSharedLibrary == NULL || FindSymbol == NULL) { + printf("FATAL: FindLibSymbol() called too early\n"); + return 0; + } + int16 res; + res = GetSharedLibrary(lib, FOURCC('p','w','p','c'), 1, &conn_id, &main_addr, err); + D(bug(" GetSharedLibrary: ret %d, connection ID %ld, main %p\n", res, conn_id, main_addr)); + if (res) + return NULL; + res = FindSymbol(conn_id, sym, (void **)&sym_addr, &sym_class); + D(bug(" FindSymbol: ret %d, sym_addr %p, sym_class %ld\n", res, sym_addr, sym_class)); +//!!?? CloseConnection(&conn_id); + if (res) + return NULL; + else + return sym_addr; + } +} + + +/* + * Find CallUniversalProc() TVector + */ + +void InitCallUniversalProc() +{ + cu_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\021CallUniversalProc"); + D(bug("CallUniversalProc TVECT at %08lx\n", cu_tvect)); + if (cu_tvect == 0) { + printf("FATAL: Can't find CallUniversalProc()\n"); + QuitEmulator(); + } + + gsl_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\020GetSharedLibrary"); + D(bug("GetSharedLibrary TVECT at %08lx\n", gsl_tvect)); + if (gsl_tvect == 0) { + printf("FATAL: Can't find GetSharedLibrary()\n"); + QuitEmulator(); + } + + fs_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\012FindSymbol"); + D(bug("FindSymbol TVECT at %08lx\n", fs_tvect)); + if (fs_tvect == 0) { + printf("FATAL: Can't find FindSymbol()\n"); + QuitEmulator(); + } + + cc_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\017CloseConnection"); + D(bug("CloseConnection TVECT at %08lx\n", cc_tvect)); + if (cc_tvect == 0) { + printf("FATAL: Can't find CloseConnection()\n"); + QuitEmulator(); + } +} + + +/* + * CallUniversalProc + */ + +long CallUniversalProc(void *upp, uint32 info) +{ + if (cu_tvect == 0) { + printf("FATAL: CallUniversalProc() called too early\n"); + return 0; + } + return CallUniversal(upp, info); +} + + +/* + * Convert time_t value to MacOS time (seconds since 1.1.1904) + */ + +uint32 TimeToMacTime(time_t t) +{ + // This code is taken from glibc 2.2 + + // Convert to number of seconds elapsed since 1-Jan-1904 + struct tm *local = localtime(&t); + const int TM_EPOCH_YEAR = 1900; + const int MAC_EPOCH_YEAR = 1904; + int a4 = ((local->tm_year + TM_EPOCH_YEAR) >> 2) - !(local->tm_year & 3); + int b4 = (MAC_EPOCH_YEAR >> 2) - !(MAC_EPOCH_YEAR & 3); + int a100 = a4 / 25 - (a4 % 25 < 0); + int b100 = b4 / 25 - (b4 % 25 < 0); + int a400 = a100 >> 2; + int b400 = b100 >> 2; + int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); + uint32 days = local->tm_yday + 365 * (local->tm_year - 4) + intervening_leap_days; + return local->tm_sec + 60 * (local->tm_min + 60 * (local->tm_hour + 24 * days)); +} diff --git a/SheepShaver/src/name_registry.cpp b/SheepShaver/src/name_registry.cpp new file mode 100644 index 00000000..9660e4a6 --- /dev/null +++ b/SheepShaver/src/name_registry.cpp @@ -0,0 +1,290 @@ +/* + * name_registry.cpp - Name Registry handling + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "sysdeps.h" +#include "name_registry.h" +#include "main.h" +#include "macos_util.h" +#include "user_strings.h" + +#define DEBUG 0 +#include "debug.h" + + +// Function pointers +typedef int16 (*rcec_ptr)(const RegEntryID *, const char *, RegEntryID *); +static uint32 rcec_tvect = 0; +static inline int16 RegistryCStrEntryCreate(const RegEntryID *arg1, const char *arg2, RegEntryID *arg3) +{ + return (int16)CallMacOS3(rcec_ptr, rcec_tvect, arg1, arg2, arg3); +} +typedef int16 (*rpc_ptr)(const RegEntryID *, const char *, const void *, uint32); +static uint32 rpc_tvect = 0; +static inline int16 RegistryPropertyCreate(const RegEntryID *arg1, const char *arg2, const void *arg3, uint32 arg4) +{ + return (int16)CallMacOS4(rpc_ptr, rpc_tvect, arg1, arg2, arg3, arg4); +} +#define RegistryPropertyCreateStr(e,n,s) RegistryPropertyCreate(e,n,s,strlen(s)+1) + +// Video driver stub +static const uint8 video_driver[] = { +#include "VideoDriverStub.i" +}; + +// Ethernet driver stub +static const uint8 ethernet_driver[] = { +#include "EthernetDriverStub.i" +}; + + +/* + * Patch Name Registry during startup + */ + +static void patch_name_registry(void) +{ + uint32 u32; + D(bug("Patching Name Registry...")); + + // Create "device-tree" + RegEntryID device_tree; + if (!RegistryCStrEntryCreate(NULL, "Devices:device-tree", &device_tree)) { + u32 = BusClockSpeed; + RegistryPropertyCreate(&device_tree, "clock-frequency", &u32, 4); + RegistryPropertyCreateStr(&device_tree, "model", "Power Macintosh"); + + // Create "AAPL,ROM" + RegEntryID aapl_rom; + if (!RegistryCStrEntryCreate(&device_tree, "AAPL,ROM", &aapl_rom)) { + RegistryPropertyCreateStr(&aapl_rom, "device_type", "rom"); + uint32 reg[2] = {ROM_BASE, ROM_SIZE}; + RegistryPropertyCreate(&aapl_rom, "reg", ®, 8); + } + + // Create "PowerPC,60x" + RegEntryID power_pc; + char *str; + switch (PVR >> 16) { + case 1: // 601 + str = "PowerPC,601"; + break; + case 3: // 603 + str = "PowerPC,603"; + break; + case 4: // 604 + str = "PowerPC,604"; + break; + case 6: // 603e + str = "PowerPC,603e"; + break; + case 7: // 603ev + str = "PowerPC,603ev"; + break; + case 8: // 750 + str = "PowerPC,750"; + break; + case 9: // 604e + str = "PowerPC,604e"; + break; + case 10: // 604ev5 + str = "PowerPC,604ev"; + break; + case 50: // 821 + str = "PowerPC,821"; + break; + case 80: // 860 + str = "PowerPC,860"; + break; + default: + str = "PowerPC,???"; + break; + } + if (!RegistryCStrEntryCreate(&device_tree, str, &power_pc)) { + u32 = CPUClockSpeed; + RegistryPropertyCreate(&power_pc, "clock-frequency", &u32, 4); + RegistryPropertyCreate(&power_pc, "cpu-version", &PVR, 4); + RegistryPropertyCreateStr(&power_pc, "device_type", "cpu"); + switch (PVR >> 16) { + case 1: // 601 + u32 = 64; + RegistryPropertyCreate(&power_pc, "d-cache-block-size", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "d-cache-sets", &u32, 4); + u32 = 0x8000; + RegistryPropertyCreate(&power_pc, "d-cache-size", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "i-cache-block-size", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "i-cache-sets", &u32, 4); + u32 = 0x8000; + RegistryPropertyCreate(&power_pc, "i-cache-size", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "tlb-sets", &u32, 4); + u32 = 256; + RegistryPropertyCreate(&power_pc, "tlb-size", &u32, 4); + break; + case 3: // 603 + u32 = 32; + RegistryPropertyCreate(&power_pc, "d-cache-block-size", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "d-cache-sets", &u32, 4); + u32 = 0x2000; + RegistryPropertyCreate(&power_pc, "d-cache-size", &u32, 4); + u32 = 32; + RegistryPropertyCreate(&power_pc, "i-cache-block-size", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "i-cache-sets", &u32, 4); + u32 = 0x2000; + RegistryPropertyCreate(&power_pc, "i-cache-size", &u32, 4); + u32 = 32; + RegistryPropertyCreate(&power_pc, "tlb-sets", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "tlb-size", &u32, 4); + break; + case 4: // 604 + u32 = 32; + RegistryPropertyCreate(&power_pc, "d-cache-block-size", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "d-cache-sets", &u32, 4); + u32 = 0x4000; + RegistryPropertyCreate(&power_pc, "d-cache-size", &u32, 4); + u32 = 32; + RegistryPropertyCreate(&power_pc, "i-cache-block-size", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "i-cache-sets", &u32, 4); + u32 = 0x4000; + RegistryPropertyCreate(&power_pc, "i-cache-size", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "tlb-sets", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "tlb-size", &u32, 4); + break; + case 6: // 603e + case 7: // 603ev + u32 = 32; + RegistryPropertyCreate(&power_pc, "d-cache-block-size", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "d-cache-sets", &u32, 4); + u32 = 0x4000; + RegistryPropertyCreate(&power_pc, "d-cache-size", &u32, 4); + u32 = 32; + RegistryPropertyCreate(&power_pc, "i-cache-block-size", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "i-cache-sets", &u32, 4); + u32 = 0x4000; + RegistryPropertyCreate(&power_pc, "i-cache-size", &u32, 4); + u32 = 32; + RegistryPropertyCreate(&power_pc, "tlb-sets", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "tlb-size", &u32, 4); + break; + case 8: // 750 + u32 = 32; + RegistryPropertyCreate(&power_pc, "d-cache-block-size", &u32, 4); + u32 = 256; + RegistryPropertyCreate(&power_pc, "d-cache-sets", &u32, 4); + u32 = 0x8000; + RegistryPropertyCreate(&power_pc, "d-cache-size", &u32, 4); + u32 = 32; + RegistryPropertyCreate(&power_pc, "i-cache-block-size", &u32, 4); + u32 = 256; + RegistryPropertyCreate(&power_pc, "i-cache-sets", &u32, 4); + u32 = 0x8000; + RegistryPropertyCreate(&power_pc, "i-cache-size", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "tlb-sets", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "tlb-size", &u32, 4); + break; + case 9: // 604e + case 10: // 604ev5 + u32 = 32; + RegistryPropertyCreate(&power_pc, "d-cache-block-size", &u32, 4); + u32 = 256; + RegistryPropertyCreate(&power_pc, "d-cache-sets", &u32, 4); + u32 = 0x8000; + RegistryPropertyCreate(&power_pc, "d-cache-size", &u32, 4); + u32 = 32; + RegistryPropertyCreate(&power_pc, "i-cache-block-size", &u32, 4); + u32 = 256; + RegistryPropertyCreate(&power_pc, "i-cache-sets", &u32, 4); + u32 = 0x8000; + RegistryPropertyCreate(&power_pc, "i-cache-size", &u32, 4); + u32 = 64; + RegistryPropertyCreate(&power_pc, "tlb-sets", &u32, 4); + u32 = 128; + RegistryPropertyCreate(&power_pc, "tlb-size", &u32, 4); + break; + default: + break; + } + u32 = 32; + RegistryPropertyCreate(&power_pc, "reservation-granularity", &u32, 4); + uint32 reg[2] = {0, 0}; + RegistryPropertyCreate(&power_pc, "reg", ®, 8); + } + + // Create "memory" + RegEntryID memory; + if (!RegistryCStrEntryCreate(&device_tree, "memory", &memory)) { + uint32 reg[2] = {RAMBase, RAMSize}; + RegistryPropertyCreateStr(&memory, "device_type", "memory"); + RegistryPropertyCreate(&memory, "reg", ®, 8); + } + + // Create "video" + RegEntryID video; + if (!RegistryCStrEntryCreate(&device_tree, "video", &video)) { + RegistryPropertyCreateStr(&video, "AAPL,connector", "monitor"); + RegistryPropertyCreateStr(&video, "device_type", "display"); + RegistryPropertyCreate(&video, "driver,AAPL,MacOS,PowerPC", &video_driver, sizeof(video_driver)); + RegistryPropertyCreateStr(&video, "model", "SheepShaver Video"); + } + + // Create "ethernet" + RegEntryID ethernet; + if (!RegistryCStrEntryCreate(&device_tree, "ethernet", ðernet)) { + RegistryPropertyCreateStr(ðernet, "AAPL,connector", "ethernet"); + RegistryPropertyCreateStr(ðernet, "device_type", "network"); + RegistryPropertyCreate(ðernet, "driver,AAPL,MacOS,PowerPC", ðernet_driver, sizeof(ethernet_driver)); + // local-mac-address + // max-frame-size 2048 + } + } + D(bug("done.\n")); +} + +void PatchNameRegistry(void) +{ + // Find RegistryCStrEntryCreate() and RegistryPropertyCreate() TVECTs + rcec_tvect = (uint32)FindLibSymbol("\017NameRegistryLib", "\027RegistryCStrEntryCreate"); + D(bug("RegistryCStrEntryCreate TVECT at %08x\n", rcec_tvect)); + rpc_tvect = (uint32)FindLibSymbol("\017NameRegistryLib", "\026RegistryPropertyCreate"); + D(bug("RegistryPropertyCreate TVECT at %08x\n", rpc_tvect)); + if (rcec_tvect == 0 || rpc_tvect == 0) { + ErrorAlert(GetString(STR_NO_NAME_REGISTRY_ERR)); + QuitEmulator(); + } + + // Main routine must be executed in PPC mode + ExecutePPC(patch_name_registry); +} diff --git a/SheepShaver/src/prefs_items.cpp b/SheepShaver/src/prefs_items.cpp new file mode 100644 index 00000000..f732de5c --- /dev/null +++ b/SheepShaver/src/prefs_items.cpp @@ -0,0 +1,75 @@ +/* + * prefs_items.cpp - Common preferences items + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" + +#include "sys.h" +#include "prefs.h" + + +// Common preferences items (those which exist on all platforms) +prefs_desc common_prefs_items[] = { + {"disk", TYPE_STRING, true, "device/file name of Mac volume"}, + {"floppy", TYPE_STRING, true, "device/file name of Mac floppy drive"}, + {"cdrom", TYPE_STRING, true, "device/file names of Mac CD-ROM drive"}, + {"extfs", TYPE_STRING, false, "root path of ExtFS"}, + {"scsi0", TYPE_STRING, false, "SCSI target for Mac SCSI ID 0"}, + {"scsi1", TYPE_STRING, false, "SCSI target for Mac SCSI ID 1"}, + {"scsi2", TYPE_STRING, false, "SCSI target for Mac SCSI ID 2"}, + {"scsi3", TYPE_STRING, false, "SCSI target for Mac SCSI ID 3"}, + {"scsi4", TYPE_STRING, false, "SCSI target for Mac SCSI ID 4"}, + {"scsi5", TYPE_STRING, false, "SCSI target for Mac SCSI ID 5"}, + {"scsi6", TYPE_STRING, false, "SCSI target for Mac SCSI ID 6"}, + {"windowmodes", TYPE_INT32, false, "bitmap of allowed window video modes"}, + {"screenmodes", TYPE_INT32, false, "bitmap of allowed fullscreen video modes"}, + {"seriala", TYPE_STRING, false, "device name of Mac serial port A"}, + {"serialb", TYPE_STRING, false, "device name of Mac serial port B"}, + {"rom", TYPE_STRING, false, "path of ROM file"}, + {"bootdrive", TYPE_INT32, false, "boot drive number"}, + {"bootdriver", TYPE_INT32, false, "boot driver number"}, + {"ramsize", TYPE_INT32, false, "size of Mac RAM in bytes"}, + {"frameskip", TYPE_INT32, false, "number of frames to skip in refreshed video modes"}, + {"gfxaccel", TYPE_BOOLEAN, false, "turn on QuickDraw acceleration"}, + {"nocdrom", TYPE_BOOLEAN, false, "don't install CD-ROM driver"}, + {"nonet", TYPE_BOOLEAN, false, "don't use Ethernet"}, + {"nosound", TYPE_BOOLEAN, false, "don't enable sound output"}, + {"nogui", TYPE_BOOLEAN, false, "disable GUI"}, + {"ignoresegv", TYPE_BOOLEAN, false, "ignore illegal memory accesses"}, + {NULL, TYPE_END, false, NULL} // End of list +}; + +/* + * Set default values for preferences items + */ + +void AddPrefsDefaults(void) +{ + SysAddSerialPrefs(); + PrefsAddInt32("bootdriver", 0); + PrefsAddInt32("bootdrive", 0); + PrefsAddInt32("ramsize", 16 * 1024 * 1024); + PrefsAddInt32("frameskip", 8); + PrefsAddBool("gfxaccel", true); + PrefsAddBool("nocdrom", false); + PrefsAddBool("nonet", false); + PrefsAddBool("nosound", false); + PrefsAddBool("nogui", false); + PrefsAddBool("ignoresegv", true); +} diff --git a/SheepShaver/src/rom_patches.cpp b/SheepShaver/src/rom_patches.cpp new file mode 100644 index 00000000..5db990f7 --- /dev/null +++ b/SheepShaver/src/rom_patches.cpp @@ -0,0 +1,2087 @@ +/* + * rom_patches.cpp - ROM patches + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 + */ + +/* + * TODO: + * IRQ_NEST must be handled atomically + * Don't use r1 in extra routines + */ + +#include + +#include "sysdeps.h" +#include "rom_patches.h" +#include "main.h" +#include "prefs.h" +#include "cpu_emulation.h" +#include "emul_op.h" +#include "xlowmem.h" +#include "sony.h" +#include "disk.h" +#include "cdrom.h" +#include "audio.h" +#include "audio_defs.h" +#include "serial.h" +#include "macos_util.h" + +#define DEBUG 0 +#include "debug.h" + + +// 68k breakpoint address +//#define M68K_BREAK_POINT 0x29e0 // BootMe +//#define M68K_BREAK_POINT 0x2a1e // Boot block code returned +//#define M68K_BREAK_POINT 0x3150 // CritError +//#define M68K_BREAK_POINT 0x187ce // Unimplemented trap + +// PowerPC breakpoint address +//#define POWERPC_BREAK_POINT 0x36e6c0 // 68k emulator start + +#define DISABLE_SCSI 1 + + +// Other ROM addresses +const uint32 CHECK_LOAD_PATCH_SPACE = 0x2f7f00; +const uint32 PUT_SCRAP_PATCH_SPACE = 0x2f7f80; +const uint32 GET_SCRAP_PATCH_SPACE = 0x2f7fc0; +const uint32 ADDR_MAP_PATCH_SPACE = 0x2f8000; + +// Global variables +int ROMType; // ROM type +static uint32 sony_offset; // Offset of .Sony driver resource + +// Prototypes +static bool patch_nanokernel_boot(void); +static bool patch_68k_emul(void); +static bool patch_nanokernel(void); +static bool patch_68k(void); + + +/* + * Search ROM for byte string, return ROM offset (or 0) + */ + +static uint32 find_rom_data(uint32 start, uint32 end, const uint8 *data, uint32 data_len) +{ + uint32 ofs = start; + while (ofs < end) { + if (!memcmp((void *)(ROM_BASE + ofs), data, data_len)) + return ofs; + ofs++; + } + return 0; +} + + +/* + * Search ROM resource by type/ID, return ROM offset of resource data + */ + +static uint32 rsrc_ptr = 0; + +// id = 4711 means "find any ID" +static uint32 find_rom_resource(uint32 s_type, int16 s_id = 4711, bool cont = false) +{ + uint32 *lp = (uint32 *)(ROM_BASE + 0x1a); + uint32 x = ntohl(*lp); + uint8 *bp = (uint8 *)(ROM_BASE + x + 5); + uint32 header_size = *bp; + + if (!cont) + rsrc_ptr = x; + else if (rsrc_ptr == 0) + return 0; + + for (;;) { + lp = (uint32 *)(ROM_BASE + rsrc_ptr); + rsrc_ptr = ntohl(*lp); + if (rsrc_ptr == 0) + break; + + rsrc_ptr += header_size; + + lp = (uint32 *)(ROM_BASE + rsrc_ptr + 4); + uint32 data = ntohl(*lp); lp++; + uint32 type = ntohl(*lp); lp++; + int16 id = ntohs(*(int16 *)lp); + if (type == s_type && (id == s_id || s_id == 4711)) + return data; + } + return 0; +} + + +/* + * Search offset of A-Trap routine in ROM + */ + +static uint32 find_rom_trap(uint16 trap) +{ + uint32 *lp = (uint32 *)(ROM_BASE + 0x22); + lp = (uint32 *)(ROM_BASE + ntohl(*lp)); + + if (trap > 0xa800) + return ntohl(lp[trap & 0x3ff]); + else + return ntohl(lp[(trap & 0xff) + 0x400]); +} + + +/* + * List of audio sifters installed in ROM and System file + */ + +struct sift_entry { + uint32 type; + int16 id; +}; +static sift_entry sifter_list[32]; +static int num_sifters; + +void AddSifter(uint32 type, int16 id) +{ + if (FindSifter(type, id)) + return; + D(bug(" adding sifter type %c%c%c%c (%08x), id %d\n", type >> 24, (type >> 16) & 0xff, (type >> 8) & 0xff, type & 0xff, type, id)); + sifter_list[num_sifters].type = type; + sifter_list[num_sifters].id = id; + num_sifters++; +} + +bool FindSifter(uint32 type, int16 id) +{ + for (int i=0; i> 8, SonyDriverFlags & 0xff, 0, 0, 0, 0, 0, 0, + 0x00, 0x18, // Open() offset + 0x00, 0x1c, // Prime() offset + 0x00, 0x20, // Control() offset + 0x00, 0x2c, // Status() offset + 0x00, 0x52, // Close() offset + 0x05, 0x2e, 0x53, 0x6f, 0x6e, 0x79, // ".Sony" + + // Open() + M68K_EMUL_OP_SONY_OPEN >> 8, M68K_EMUL_OP_SONY_OPEN & 0xff, + 0x4e, 0x75, // rts + + // Prime() + M68K_EMUL_OP_SONY_PRIME >> 8, M68K_EMUL_OP_SONY_PRIME & 0xff, + 0x60, 0x0e, // bra IOReturn + + // Control() + M68K_EMUL_OP_SONY_CONTROL >> 8, M68K_EMUL_OP_SONY_CONTROL & 0xff, + 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) + 0x66, 0x04, // bne IOReturn + 0x4e, 0x75, // rts + + // Status() + M68K_EMUL_OP_SONY_STATUS >> 8, M68K_EMUL_OP_SONY_STATUS & 0xff, + + // IOReturn + 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 + 0x08, 0x01, 0x00, 0x09, // btst #9,d1 + 0x67, 0x0c, // beq 1 + 0x4a, 0x40, // tst.w d0 + 0x6f, 0x02, // ble 2 + 0x42, 0x40, // clr.w d0 + 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) + 0x4e, 0x75, // rts + 0x4a, 0x40, //1 tst.w d0 + 0x6f, 0x04, // ble 3 + 0x42, 0x40, // clr.w d0 + 0x4e, 0x75, // rts + 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(sp) + 0x4e, 0x75, // rts + + // Close() + 0x70, 0xe8, // moveq #-24,d0 + 0x4e, 0x75 // rts +}; + +static const uint8 disk_driver[] = { // Generic disk driver + // Driver header + DiskDriverFlags >> 8, DiskDriverFlags & 0xff, 0, 0, 0, 0, 0, 0, + 0x00, 0x18, // Open() offset + 0x00, 0x1c, // Prime() offset + 0x00, 0x20, // Control() offset + 0x00, 0x2c, // Status() offset + 0x00, 0x52, // Close() offset + 0x05, 0x2e, 0x44, 0x69, 0x73, 0x6b, // ".Disk" + + // Open() + M68K_EMUL_OP_DISK_OPEN >> 8, M68K_EMUL_OP_DISK_OPEN & 0xff, + 0x4e, 0x75, // rts + + // Prime() + M68K_EMUL_OP_DISK_PRIME >> 8, M68K_EMUL_OP_DISK_PRIME & 0xff, + 0x60, 0x0e, // bra IOReturn + + // Control() + M68K_EMUL_OP_DISK_CONTROL >> 8, M68K_EMUL_OP_DISK_CONTROL & 0xff, + 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) + 0x66, 0x04, // bne IOReturn + 0x4e, 0x75, // rts + + // Status() + M68K_EMUL_OP_DISK_STATUS >> 8, M68K_EMUL_OP_DISK_STATUS & 0xff, + + // IOReturn + 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 + 0x08, 0x01, 0x00, 0x09, // btst #9,d1 + 0x67, 0x0c, // beq 1 + 0x4a, 0x40, // tst.w d0 + 0x6f, 0x02, // ble 2 + 0x42, 0x40, // clr.w d0 + 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) + 0x4e, 0x75, // rts + 0x4a, 0x40, //1 tst.w d0 + 0x6f, 0x04, // ble 3 + 0x42, 0x40, // clr.w d0 + 0x4e, 0x75, // rts + 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(sp) + 0x4e, 0x75, // rts + + // Close() + 0x70, 0xe8, // moveq #-24,d0 + 0x4e, 0x75 // rts +}; + +static const uint8 cdrom_driver[] = { // CD-ROM driver + // Driver header + CDROMDriverFlags >> 8, CDROMDriverFlags & 0xff, 0, 0, 0, 0, 0, 0, + 0x00, 0x1c, // Open() offset + 0x00, 0x20, // Prime() offset + 0x00, 0x24, // Control() offset + 0x00, 0x30, // Status() offset + 0x00, 0x56, // Close() offset + 0x08, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x43, 0x44, 0x00, // ".AppleCD" + + // Open() + M68K_EMUL_OP_CDROM_OPEN >> 8, M68K_EMUL_OP_CDROM_OPEN & 0xff, + 0x4e, 0x75, // rts + + // Prime() + M68K_EMUL_OP_CDROM_PRIME >> 8, M68K_EMUL_OP_CDROM_PRIME & 0xff, + 0x60, 0x0e, // bra IOReturn + + // Control() + M68K_EMUL_OP_CDROM_CONTROL >> 8, M68K_EMUL_OP_CDROM_CONTROL & 0xff, + 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) + 0x66, 0x04, // bne IOReturn + 0x4e, 0x75, // rts + + // Status() + M68K_EMUL_OP_CDROM_STATUS >> 8, M68K_EMUL_OP_CDROM_STATUS & 0xff, + + // IOReturn + 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 + 0x08, 0x01, 0x00, 0x09, // btst #9,d1 + 0x67, 0x0c, // beq 1 + 0x4a, 0x40, // tst.w d0 + 0x6f, 0x02, // ble 2 + 0x42, 0x40, // clr.w d0 + 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) + 0x4e, 0x75, // rts + 0x4a, 0x40, //1 tst.w d0 + 0x6f, 0x04, // ble 3 + 0x42, 0x40, // clr.w d0 + 0x4e, 0x75, // rts + 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(sp) + 0x4e, 0x75, // rts + + // Close() + 0x70, 0xe8, // moveq #-24,d0 + 0x4e, 0x75 // rts +}; + +#ifdef __linux__ +static uint32 serial_nothing_tvect[2] = {(uint32)SerialNothing, 0}; +static uint32 serial_open_tvect[2] = {(uint32)SerialOpen, 0}; +static uint32 serial_prime_in_tvect[2] = {(uint32)SerialPrimeIn, 0}; +static uint32 serial_prime_out_tvect[2] = {(uint32)SerialPrimeOut, 0}; +static uint32 serial_control_tvect[2] = {(uint32)SerialControl, 0}; +static uint32 serial_status_tvect[2] = {(uint32)SerialStatus, 0}; +static uint32 serial_close_tvect[2] = {(uint32)SerialClose, 0}; +#endif + +static const uint32 ain_driver[] = { // .AIn driver header + 0x4d000000, 0x00000000, + 0x00200040, 0x00600080, + 0x00a0042e, 0x41496e00, + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_nothing_tvect, +#else + 0x00010004, (uint32)SerialNothing, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_prime_in_tvect, +#else + 0x00010004, (uint32)SerialPrimeIn, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_control_tvect, +#else + 0x00010004, (uint32)SerialControl, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_status_tvect, +#else + 0x00010004, (uint32)SerialStatus, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_nothing_tvect, +#else + 0x00010004, (uint32)SerialNothing, +#endif + 0x00000000, 0x00000000, +}; + +static const uint32 aout_driver[] = { // .AOut driver header + 0x4d000000, 0x00000000, + 0x00200040, 0x00600080, + 0x00a0052e, 0x414f7574, + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_open_tvect, +#else + 0x00010004, (uint32)SerialOpen, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_prime_out_tvect, +#else + 0x00010004, (uint32)SerialPrimeOut, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_control_tvect, +#else + 0x00010004, (uint32)SerialControl, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_status_tvect, +#else + 0x00010004, (uint32)SerialStatus, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_close_tvect, +#else + 0x00010004, (uint32)SerialClose, +#endif + 0x00000000, 0x00000000, +}; + +static const uint32 bin_driver[] = { // .BIn driver header + 0x4d000000, 0x00000000, + 0x00200040, 0x00600080, + 0x00a0042e, 0x42496e00, + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_nothing_tvect, +#else + 0x00010004, (uint32)SerialNothing, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_prime_in_tvect, +#else + 0x00010004, (uint32)SerialPrimeIn, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_control_tvect, +#else + 0x00010004, (uint32)SerialControl, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_status_tvect, +#else + 0x00010004, (uint32)SerialStatus, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_nothing_tvect, +#else + 0x00010004, (uint32)SerialNothing, +#endif + 0x00000000, 0x00000000, +}; + +static const uint32 bout_driver[] = { // .BOut driver header + 0x4d000000, 0x00000000, + 0x00200040, 0x00600080, + 0x00a0052e, 0x424f7574, + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_open_tvect, +#else + 0x00010004, (uint32)SerialOpen, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_prime_out_tvect, +#else + 0x00010004, (uint32)SerialPrimeOut, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_control_tvect, +#else + 0x00010004, (uint32)SerialControl, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_status_tvect, +#else + 0x00010004, (uint32)SerialStatus, +#endif + 0x00000000, 0x00000000, + 0xaafe0700, 0x00000000, + 0x00000000, 0x00179822, +#ifdef __linux__ + 0x00010004, (uint32)serial_close_tvect, +#else + 0x00010004, (uint32)SerialClose, +#endif + 0x00000000, 0x00000000, +}; + +static const uint8 adbop_patch[] = { // Call ADBOp() completion procedure + // The completion procedure may call ADBOp() again! + 0x40, 0xe7, // move sr,-(sp) + 0x00, 0x7c, 0x07, 0x00, // ori #$0700,sr + M68K_EMUL_OP_ADBOP >> 8, M68K_EMUL_OP_ADBOP & 0xff, + 0x48, 0xe7, 0x70, 0xf0, // movem.l d1-d3/a0-a3,-(sp) + 0x26, 0x48, // move.l a0,a3 + 0x4a, 0xab, 0x00, 0x04, // tst.l 4(a3) + 0x67, 0x00, 0x00, 0x18, // beq 1 + 0x20, 0x53, // move.l (a3),a0 + 0x22, 0x6b, 0x00, 0x04, // move.l 4(a3),a1 + 0x24, 0x6b, 0x00, 0x08, // move.l 8(a3),a2 + 0x26, 0x78, 0x0c, 0xf8, // move.l $cf8,a3 + 0x4e, 0x91, // jsr (a1) + 0x70, 0x00, // moveq #0,d0 + 0x60, 0x00, 0x00, 0x04, // bra 2 + 0x70, 0xff, //1 moveq #-1,d0 + 0x4c, 0xdf, 0x0f, 0x0e, //2 movem.l (sp)+,d1-d3/a0-a3 + 0x46, 0xdf, // move (sp)+,sr + 0x4e, 0x75 // rts +}; + + +/* + * Install ROM patches (RAMBase and KernelDataAddr must be set) + */ + +bool PatchROM(void) +{ + // Print ROM info + D(bug("Checksum: %08lx\n", ntohl(*(uint32 *)ROM_BASE))); + D(bug("Version: %04x\n", ntohs(*(uint16 *)(ROM_BASE + 8)))); + D(bug("Sub Version: %04x\n", ntohs(*(uint16 *)(ROM_BASE + 18)))); + D(bug("Nanokernel ID: %s\n", (char *)ROM_BASE + 0x30d064)); + D(bug("Resource Map at %08lx\n", ntohl(*(uint32 *)(ROM_BASE + 26)))); + D(bug("Trap Tables at %08lx\n\n", ntohl(*(uint32 *)(ROM_BASE + 34)))); + + // Detect ROM type + if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot TNT", 8)) + ROMType = ROMTYPE_TNT; + else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Alchemy", 12)) + ROMType = ROMTYPE_ALCHEMY; + else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Zanzibar", 13)) + ROMType = ROMTYPE_ZANZIBAR; + else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Gazelle", 12)) + ROMType = ROMTYPE_GAZELLE; + else if (!memcmp((void *)(ROM_BASE + 0x30d064), "NewWorld", 8)) + ROMType = ROMTYPE_NEWWORLD; + else + return false; + + // Apply patches + if (!patch_nanokernel_boot()) return false; + if (!patch_68k_emul()) return false; + if (!patch_nanokernel()) return false; + if (!patch_68k()) return false; + +#ifdef M68K_BREAK_POINT + // Install 68k breakpoint + uint16 *wp = (uint16 *)(ROM_BASE + M68K_BREAK_POINT); + *wp++ = htons(M68K_EMUL_BREAK); + *wp = htons(M68K_EMUL_RETURN); +#endif + +#ifdef POWERPC_BREAK_POINT + // Install PowerPC breakpoint + uint32 *lp = (uint32 *)(ROM_BASE + POWERPC_BREAK_POINT); + *lp = htonl(0); +#endif + + // Copy 68k emulator to 2MB boundary + memcpy((void *)(ROM_BASE + ROM_SIZE), (void *)(ROM_BASE + ROM_SIZE - 0x100000), 0x100000); + return true; +} + + +/* + * Nanokernel boot routine patches + */ + +static bool patch_nanokernel_boot(void) +{ + uint32 *lp; + + // ROM boot structure patches + lp = (uint32 *)(ROM_BASE + 0x30d000); + lp[0x9c >> 2] = htonl(KernelDataAddr); // LA_InfoRecord + lp[0xa0 >> 2] = htonl(KernelDataAddr); // LA_KernelData + lp[0xa4 >> 2] = htonl(KernelDataAddr + 0x1000); // LA_EmulatorData + lp[0xa8 >> 2] = htonl(ROM_BASE + 0x480000); // LA_DispatchTable + lp[0xac >> 2] = htonl(ROM_BASE + 0x460000); // LA_EmulatorCode + lp[0x360 >> 2] = htonl(0); // Physical RAM base (? on NewWorld ROM, this contains -1) + lp[0xfd8 >> 2] = htonl(ROM_BASE + 0x2a); // 68k reset vector + + // Skip SR/BAT/SDR init + if (ROMType == ROMTYPE_GAZELLE || ROMType == ROMTYPE_NEWWORLD) { + lp = (uint32 *)(ROM_BASE + 0x310000); + *lp++ = htonl(POWERPC_NOP); + *lp = htonl(0x38000000); + } + static const uint32 sr_init_loc[] = {0x3101b0, 0x3101b0, 0x3101b0, 0x3101ec, 0x310200}; + lp = (uint32 *)(ROM_BASE + 0x310008); + *lp = htonl(0x48000000 | (sr_init_loc[ROMType] - 8) & 0xffff); // b ROM_BASE+0x3101b0 + lp = (uint32 *)(ROM_BASE + sr_init_loc[ROMType]); + *lp++ = htonl(0x80200000 + XLM_KERNEL_DATA); // lwz r1,(pointer to Kernel Data) + *lp++ = htonl(0x3da0dead); // lis r13,0xdead (start of kernel memory) + *lp++ = htonl(0x3dc00010); // lis r14,0x0010 (size of page table) + *lp = htonl(0x3de00010); // lis r15,0x0010 (size of kernel memory) + + // Don't read PVR + static const uint32 pvr_loc[] = {0x3103b0, 0x3103b4, 0x3103b4, 0x310400, 0x310438}; + lp = (uint32 *)(ROM_BASE + pvr_loc[ROMType]); + *lp = htonl(0x81800000 + XLM_PVR); // lwz r12,(theoretical PVR) + + // Set CPU specific data (even if ROM doesn't have support for that CPU) + lp = (uint32 *)(ROM_BASE + pvr_loc[ROMType]); + if (ntohl(lp[6]) != 0x2c0c0001) + return false; + uint32 ofs = ntohl(lp[7]) & 0xffff; + D(bug("ofs %08lx\n", ofs)); + lp[8] = htonl((ntohl(lp[8]) & 0xffff) | 0x48000000); // beq -> b + uint32 loc = (ntohl(lp[8]) & 0xffff) + (uint32)(lp+8) - ROM_BASE; + D(bug("loc %08lx\n", loc)); + lp = (uint32 *)(ROM_BASE + ofs + 0x310000); + switch (PVR >> 16) { + case 1: // 601 + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x8000); // Data cache size + lp[2] = htonl(0x8000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00010040); // Unified caches/Inst cache line size + lp[5] = htonl(0x00400020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00080008); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x01000002); // TLB total size/TLB assoc + break; + case 3: // 603 + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x2000); // Data cache size + lp[2] = htonl(0x2000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00000020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00020002); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x00400002); // TLB total size/TLB assoc + break; + case 4: // 604 + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x4000); // Data cache size + lp[2] = htonl(0x4000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00000020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00040004); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x00800002); // TLB total size/TLB assoc + break; +// case 5: // 740? + case 6: // 603e + case 7: // 603ev + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x4000); // Data cache size + lp[2] = htonl(0x4000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00000020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00040004); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x00400002); // TLB total size/TLB assoc + break; + case 8: // 750 + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x8000); // Data cache size + lp[2] = htonl(0x8000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00000020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00080008); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x00800002); // TLB total size/TLB assoc + break; + case 9: // 604e + case 10: // 604ev5 + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x8000); // Data cache size + lp[2] = htonl(0x8000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00000020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00040004); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x00800002); // TLB total size/TLB assoc + break; +// case 11: // X704? + case 12: // ??? + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x8000); // Data cache size + lp[2] = htonl(0x8000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00000020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00080008); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x00800002); // TLB total size/TLB assoc + break; + case 13: // ??? + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x8000); // Data cache size + lp[2] = htonl(0x8000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00000020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00080008); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x01000004); // TLB total size/TLB assoc + break; +// case 50: // 821 +// case 80: // 860 + case 96: // ??? + lp[0] = htonl(0x1000); // Page size + lp[1] = htonl(0x8000); // Data cache size + lp[2] = htonl(0x8000); // Inst cache size + lp[3] = htonl(0x00200020); // Coherency block size/Reservation granule size + lp[4] = htonl(0x00010020); // Unified caches/Inst cache line size + lp[5] = htonl(0x00200020); // Data cache line size/Data cache block size touch + lp[6] = htonl(0x00200020); // Inst cache block size/Data cache block size + lp[7] = htonl(0x00080008); // Inst cache assoc/Data cache assoc + lp[8] = htonl(0x00800004); // TLB total size/TLB assoc + break; + default: + printf("WARNING: Unknown CPU type\n"); + break; + } + + // Don't set SPRG3, don't test MQ + lp = (uint32 *)(ROM_BASE + loc + 0x20); + *lp++ = htonl(POWERPC_NOP); + lp++; + *lp++ = htonl(POWERPC_NOP); + lp++; + *lp = htonl(POWERPC_NOP); + + // Don't read MSR + lp = (uint32 *)(ROM_BASE + loc + 0x40); + *lp = htonl(0x39c00000); // li r14,0 + + // Don't write to DEC + lp = (uint32 *)(ROM_BASE + loc + 0x70); + *lp++ = htonl(POWERPC_NOP); + loc = (ntohl(lp[0]) & 0xffff) + (uint32)lp - ROM_BASE; + D(bug("loc %08lx\n", loc)); + + // Don't set SPRG3 + lp = (uint32 *)(ROM_BASE + loc + 0x2c); + *lp = htonl(POWERPC_NOP); + + // Don't read PVR + static const uint32 pvr_ofs[] = {0x138, 0x138, 0x138, 0x140, 0x148}; + lp = (uint32 *)(ROM_BASE + loc + pvr_ofs[ROMType]); + *lp = htonl(0x82e00000 + XLM_PVR); // lwz r23,(theoretical PVR) + lp = (uint32 *)(ROM_BASE + loc + 0x170); + if (ntohl(*lp) == 0x7eff42a6) // NewWorld ROM + *lp = htonl(0x82e00000 + XLM_PVR); // lwz r23,(theoretical PVR) + lp = (uint32 *)(ROM_BASE + 0x313134); + if (ntohl(*lp) == 0x7e5f42a6) + *lp = htonl(0x82400000 + XLM_PVR); // lwz r18,(theoretical PVR) + lp = (uint32 *)(ROM_BASE + 0x3131f4); + if (ntohl(*lp) == 0x7e5f42a6) // NewWorld ROM + *lp = htonl(0x82400000 + XLM_PVR); // lwz r18,(theoretical PVR) + + // Don't read SDR1 + static const uint32 sdr1_ofs[] = {0x174, 0x174, 0x174, 0x17c, 0x19c}; + lp = (uint32 *)(ROM_BASE + loc + sdr1_ofs[ROMType]); + *lp++ = htonl(0x3d00dead); // lis r8,0xdead (pointer to page table) + *lp++ = htonl(0x3ec0001f); // lis r22,0x001f (size of page table) + *lp = htonl(POWERPC_NOP); + + // Don't clear page table + static const uint32 pgtb_ofs[] = {0x198, 0x198, 0x198, 0x1a0, 0x1c4}; + lp = (uint32 *)(ROM_BASE + loc + pgtb_ofs[ROMType]); + *lp = htonl(POWERPC_NOP); + + // Don't invalidate TLB + static const uint32 tlb_ofs[] = {0x1a0, 0x1a0, 0x1a0, 0x1a8, 0x1cc}; + lp = (uint32 *)(ROM_BASE + loc + tlb_ofs[ROMType]); + *lp = htonl(POWERPC_NOP); + + // Don't create RAM descriptor table + static const uint32 desc_ofs[] = {0x350, 0x350, 0x350, 0x358, 0x37c}; + lp = (uint32 *)(ROM_BASE + loc + desc_ofs[ROMType]); + *lp = htonl(POWERPC_NOP); + + // Don't load SRs and BATs + static const uint32 sr_ofs[] = {0x3d8, 0x3d8, 0x3d8, 0x3e0, 0x404}; + lp = (uint32 *)(ROM_BASE + loc + sr_ofs[ROMType]); + *lp = htonl(POWERPC_NOP); + + // Don't mess with SRs + static const uint32 sr2_ofs[] = {0x312118, 0x312118, 0x312118, 0x312118, 0x3121b4}; + lp = (uint32 *)(ROM_BASE + sr2_ofs[ROMType]); + *lp = htonl(POWERPC_BLR); + + // Don't check performance monitor + static const uint32 pm_ofs[] = {0x313148, 0x313148, 0x313148, 0x313148, 0x313218}; + lp = (uint32 *)(ROM_BASE + pm_ofs[ROMType]); + while (ntohl(*lp) != 0x7e58eba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e78eaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e59eba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e79eaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e5aeba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e7aeaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e5beba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e7beaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e5feba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e7feaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e5ceba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e7ceaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e5deba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e7deaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e5eeba6) lp++; + *lp++ = htonl(POWERPC_NOP); + while (ntohl(*lp) != 0x7e7eeaa6) lp++; + *lp++ = htonl(POWERPC_NOP); + + // Jump to 68k emulator + static const uint32 jump68k_ofs[] = {0x40c, 0x40c, 0x40c, 0x414, 0x438}; + lp = (uint32 *)(ROM_BASE + loc + jump68k_ofs[ROMType]); + *lp++ = htonl(0x80610634); // lwz r3,0x0634(r1) (pointer to Emulator Data) + *lp++ = htonl(0x8081119c); // lwz r4,0x119c(r1) (pointer to opcode table) + *lp++ = htonl(0x80011184); // lwz r0,0x1184(r1) (pointer to emulator init routine) + *lp++ = htonl(0x7c0903a6); // mtctr r0 + *lp = htonl(POWERPC_BCTR); + return true; +} + + +/* + * 68k emulator patches + */ + +static bool patch_68k_emul(void) +{ + uint32 *lp; + uint32 base; + + // Overwrite twi instructions + static const uint32 twi_loc[] = {0x36e680, 0x36e6c0, 0x36e6c0, 0x36e6c0, 0x36e740}; + base = twi_loc[ROMType]; + lp = (uint32 *)(ROM_BASE + base); + *lp++ = htonl(0x48000000 + 0x36f900 - base); // b 0x36f900 (Emulator start) + *lp++ = htonl(0x48000000 + 0x36fa00 - base - 4); // b 0x36fa00 (Mixed mode) + *lp++ = htonl(0x48000000 + 0x36fb00 - base - 8); // b 0x36fb00 (Reset/FC1E opcode) + *lp++ = htonl(0x48000000 + 0x36fc00 - base - 12); // FE0A opcode + *lp++ = htonl(POWERPC_ILLEGAL); // Interrupt + *lp++ = htonl(POWERPC_ILLEGAL); // ? + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp++ = htonl(POWERPC_ILLEGAL); + *lp = htonl(POWERPC_ILLEGAL); + +#if EMULATED_PPC + // Install EMUL_RETURN, EXEC_RETURN and EMUL_OP opcodes + lp = (uint32 *)(ROM_BASE + 0x380000 + (M68K_EMUL_RETURN << 3)); + *lp++ = htonl(POWERPC_EMUL_OP); + *lp++ = htonl(0x4bf66e80); // b 0x366084 + *lp++ = htonl(POWERPC_EMUL_OP | 1); + *lp++ = htonl(0x4bf66e78); // b 0x366084 + for (int i=0; i> 16)); // lis r0,xxx + *lp++ = htonl(0x60000000 + ((ROM_BASE + 0x46d0a4) & 0xffff)); // ori r0,r0,xxx + *lp++ = htonl(0x7c0903a6); // mtctr r0 + *lp = htonl(POWERPC_BCTR); // bctr + return true; +} + + +/* + * Nanokernel patches + */ + +static bool patch_nanokernel(void) +{ + uint32 *lp; + + // Patch Mixed Mode trap + lp = (uint32 *)(ROM_BASE + 0x313c90); // Don't translate virtual->physical + while (ntohl(*lp) != 0x3ba10320) lp++; + lp++; + *lp++ = htonl(0x7f7fdb78); // mr r31,r27 + lp++; + *lp = htonl(POWERPC_NOP); + + lp = (uint32 *)(ROM_BASE + 0x313c3c); // Don't activate PPC exception table + while (ntohl(*lp) != 0x39010420) lp++; + *lp++ = htonl(0x39000000 + MODE_NATIVE); // li r8,MODE_NATIVE + *lp = htonl(0x91000000 + XLM_RUN_MODE); // stw r8,XLM_RUN_MODE + + lp = (uint32 *)(ROM_BASE + 0x312e88); // Don't modify MSR to turn on FPU + while (ntohl(*lp) != 0x556b04e2) lp++; + lp -= 4; + *lp++ = htonl(POWERPC_NOP); + lp++; + *lp++ = htonl(POWERPC_NOP); + lp++; + *lp = htonl(POWERPC_NOP); + + lp = (uint32 *)(ROM_BASE + 0x312b3c); // Always save FPU state + while (ntohl(*lp) != 0x81010668) lp++; + lp--; + *lp = htonl(0x48000000 | (ntohl(*lp) & 0xffff)); // bl 0x00312e88 + + lp = (uint32 *)(ROM_BASE + 0x312b44); // Don't read DEC + while (ntohl(*lp) != 0x7ff602a6) lp++; + *lp = htonl(0x3be00000); // li r31,0 + + lp = (uint32 *)(ROM_BASE + 0x312b50); // Don't write DEC + while (ntohl(*lp) != 0x7d1603a6) lp++; +#if 1 + *lp++ = htonl(POWERPC_NOP); + *lp = htonl(POWERPC_NOP); +#else + *lp++ = htonl(0x39000040); // li r8,0x40 + *lp = htonl(0x990600e4); // stb r8,0xe4(r6) +#endif + + lp = (uint32 *)(ROM_BASE + 0x312b9c); // Always restore FPU state + while (ntohl(*lp) != 0x7c00092d) lp++; + lp--; + *lp = htonl(0x48000000 | (ntohl(*lp) & 0xffff)); // bl 0x00312ddc + + lp = (uint32 *)(ROM_BASE + 0x312a68); // Don't activate 68k exception table + while (ntohl(*lp) != 0x39010360) lp++; + *lp++ = htonl(0x39000000 + MODE_68K); // li r8,MODE_68K + *lp = htonl(0x91000000 + XLM_RUN_MODE); // stw r8,XLM_RUN_MODE + + // Patch 68k emulator trap routine + lp = (uint32 *)(ROM_BASE + 0x312994); // Always restore FPU state + while (ntohl(*lp) != 0x39260040) lp++; + lp--; + *lp = htonl(0x48000000 | (ntohl(*lp) & 0xffff)); // bl 0x00312dd4 + + lp = (uint32 *)(ROM_BASE + 0x312dd8); // Don't modify MSR to turn on FPU + while (ntohl(*lp) != 0x810600e4) lp++; + lp--; + *lp++ = htonl(POWERPC_NOP); + lp += 2; + *lp++ = htonl(POWERPC_NOP); + lp++; + *lp++ = htonl(POWERPC_NOP); + *lp++ = htonl(POWERPC_NOP); + *lp = htonl(POWERPC_NOP); + + // Patch trap return routine + lp = (uint32 *)(ROM_BASE + 0x312c20); + while (ntohl(*lp) != 0x7d5a03a6) lp++; + *lp++ = htonl(0x7d4903a6); // mtctr r10 + *lp++ = htonl(0x7daff120); // mtcr r13 + *lp = htonl(0x48000000 + 0x8000 - (((uint32)lp - ROM_BASE) & 0xffff)); // b ROM_BASE+0x318000 + uint32 xlp = ((uint32)(lp+1) - ROM_BASE) & 0xffff; + + lp = (uint32 *)(ROM_BASE + 0x312c50); // Replace rfi + while (ntohl(*lp) != 0x4c000064) lp++; + *lp = htonl(POWERPC_BCTR); + + lp = (uint32 *)(ROM_BASE + 0x318000); + *lp++ = htonl(0x81400000 + XLM_IRQ_NEST); // lwz r10,XLM_IRQ_NEST + *lp++ = htonl(0x394affff); // subi r10,r10,1 + *lp++ = htonl(0x91400000 + XLM_IRQ_NEST); // stw r10,XLM_IRQ_NEST + *lp = htonl(0x48000000 + ((xlp - 0x800c) & 0x03fffffc)); // b ROM_BASE+0x312c2c +/* + // Disable FE0A/FE06 opcodes + lp = (uint32 *)(ROM_BASE + 0x3144ac); + *lp++ = htonl(POWERPC_NOP); + *lp += 8; +*/ + return true; +} + + +/* + * 68k boot routine patches + */ + +static bool patch_68k(void) +{ + uint32 *lp; + uint16 *wp; + uint8 *bp; + uint32 base; + + // Remove 68k RESET instruction + static const uint8 reset_dat[] = {0x4e, 0x70}; + if ((base = find_rom_data(0xc8, 0x120, reset_dat, sizeof(reset_dat))) == 0) return false; + D(bug("reset %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp = htons(M68K_NOP); + + // Fake reading PowerMac ID (via Universal) + static const uint8 powermac_id_dat[] = {0x45, 0xf9, 0x5f, 0xff, 0xff, 0xfc, 0x20, 0x12, 0x72, 0x00}; + if ((base = find_rom_data(0xe000, 0x15000, powermac_id_dat, sizeof(powermac_id_dat))) == 0) return false; + D(bug("powermac_id %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x203c); // move.l #id,d0 + *wp++ = htons(0); +// if (ROMType == ROMTYPE_NEWWORLD) +// *wp++ = htons(0x3035); // (PowerMac 9500 ID) +// else + *wp++ = htons(0x3020); // (PowerMac 9500 ID) + *wp++ = htons(0xb040); // cmp.w d0,d0 + *wp = htons(0x4ed6); // jmp (a6) + + // Patch UniversalInfo + if (ROMType == ROMTYPE_NEWWORLD) { + static const uint8 univ_info_dat[] = {0x3f, 0xff, 0x04, 0x00}; + if ((base = find_rom_data(0x14000, 0x16000, univ_info_dat, sizeof(univ_info_dat))) == 0) return false; + D(bug("universal_info %08lx\n", base)); + lp = (uint32 *)(ROM_BASE + base - 0x14); + lp[0x00 >> 2] = htonl(ADDR_MAP_PATCH_SPACE - (base - 0x14)); + lp[0x10 >> 2] = htonl(0xcc003d11); // Make it like the PowerMac 9500 UniversalInfo + lp[0x14 >> 2] = htonl(0x3fff0401); + lp[0x18 >> 2] = htonl(0x0300001c); + lp[0x1c >> 2] = htonl(0x000108c4); + lp[0x24 >> 2] = htonl(0xc301bf26); + lp[0x28 >> 2] = htonl(0x00000861); + lp[0x58 >> 2] = htonl(0x30200000); + lp[0x60 >> 2] = htonl(0x0000003d); + } else if (ROMType == ROMTYPE_ZANZIBAR) { + base = 0x12b70; + lp = (uint32 *)(ROM_BASE + base - 0x14); + lp[0x00 >> 2] = htonl(ADDR_MAP_PATCH_SPACE - (base - 0x14)); + lp[0x10 >> 2] = htonl(0xcc003d11); // Make it like the PowerMac 9500 UniversalInfo + lp[0x14 >> 2] = htonl(0x3fff0401); + lp[0x18 >> 2] = htonl(0x0300001c); + lp[0x1c >> 2] = htonl(0x000108c4); + lp[0x24 >> 2] = htonl(0xc301bf26); + lp[0x28 >> 2] = htonl(0x00000861); + lp[0x58 >> 2] = htonl(0x30200000); + lp[0x60 >> 2] = htonl(0x0000003d); + } + + // Construct AddrMap for NewWorld ROM + if (ROMType == ROMTYPE_NEWWORLD || ROMType == ROMTYPE_ZANZIBAR) { + lp = (uint32 *)(ROM_BASE + ADDR_MAP_PATCH_SPACE); + memset(lp - 10, 0, 0x128); + lp[-10] = htonl(0x0300001c); + lp[-9] = htonl(0x000108c4); + lp[-4] = htonl(0x00300000); + lp[-2] = htonl(0x11010000); + lp[-1] = htonl(0xf8000000); + lp[0] = htonl(0xffc00000); + lp[2] = htonl(0xf3016000); + lp[3] = htonl(0xf3012000); + lp[4] = htonl(0xf3012000); + lp[24] = htonl(0xf3018000); + lp[25] = htonl(0xf3010000); + lp[34] = htonl(0xf3011000); + lp[38] = htonl(0xf3015000); + lp[39] = htonl(0xf3014000); + lp[43] = htonl(0xf3000000); + lp[48] = htonl(0xf8000000); + } + + // Don't initialize VIA (via Universal) + static const uint8 via_init_dat[] = {0x08, 0x00, 0x00, 0x02, 0x67, 0x00, 0x00, 0x2c, 0x24, 0x68, 0x00, 0x08}; + if ((base = find_rom_data(0xe000, 0x15000, via_init_dat, sizeof(via_init_dat))) == 0) return false; + D(bug("via_init %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 4); + *wp = htons(0x6000); // bra + + static const uint8 via_init2_dat[] = {0x24, 0x68, 0x00, 0x08, 0x00, 0x12, 0x00, 0x30, 0x4e, 0x71}; + if ((base = find_rom_data(0xa000, 0x10000, via_init2_dat, sizeof(via_init2_dat))) == 0) return false; + D(bug("via_init2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp = htons(0x4ed6); // jmp (a6) + + static const uint8 via_init3_dat[] = {0x22, 0x68, 0x00, 0x08, 0x28, 0x3c, 0x20, 0x00, 0x01, 0x00}; + if ((base = find_rom_data(0xa000, 0x10000, via_init3_dat, sizeof(via_init3_dat))) == 0) return false; + D(bug("via_init3 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp = htons(0x4ed6); // jmp (a6) + + // Don't RunDiags, get BootGlobs pointer directly + if (ROMType == ROMTYPE_NEWWORLD) { + static const uint8 run_diags_dat[] = {0x60, 0xff, 0x00, 0x0c}; + if ((base = find_rom_data(0x110, 0x128, run_diags_dat, sizeof(run_diags_dat))) == 0) return false; + D(bug("run_diags %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x4df9); // lea xxx,a6 + *wp++ = htons((RAMBase + RAMSize - 0x1c) >> 16); + *wp = htons((RAMBase + RAMSize - 0x1c) & 0xffff); + } else { + static const uint8 run_diags_dat[] = {0x74, 0x00, 0x2f, 0x0e}; + if ((base = find_rom_data(0xd0, 0xf0, run_diags_dat, sizeof(run_diags_dat))) == 0) return false; + D(bug("run_diags %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base - 6); + *wp++ = htons(0x4df9); // lea xxx,a6 + *wp++ = htons((RAMBase + RAMSize - 0x1c) >> 16); + *wp = htons((RAMBase + RAMSize - 0x1c) & 0xffff); + } + + // Replace NVRAM routines + static const uint8 nvram1_dat[] = {0x48, 0xe7, 0x01, 0x0e, 0x24, 0x68, 0x00, 0x08, 0x08, 0x83, 0x00, 0x1f}; + if ((base = find_rom_data(0x7000, 0xc000, nvram1_dat, sizeof(nvram1_dat))) == 0) return false; + D(bug("nvram1 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(M68K_EMUL_OP_XPRAM1); + *wp = htons(M68K_RTS); + + if (ROMType == ROMTYPE_NEWWORLD) { + static const uint8 nvram2_dat[] = {0x48, 0xe7, 0x1c, 0xe0, 0x4f, 0xef, 0xff, 0xb4}; + if ((base = find_rom_data(0xa000, 0xd000, nvram2_dat, sizeof(nvram2_dat))) == 0) return false; + D(bug("nvram2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(M68K_EMUL_OP_XPRAM2); + *wp = htons(0x4ed3); // jmp (a3) + + static const uint8 nvram3_dat[] = {0x48, 0xe7, 0xdc, 0xe0, 0x4f, 0xef, 0xff, 0xb4}; + if ((base = find_rom_data(0xa000, 0xd000, nvram3_dat, sizeof(nvram3_dat))) == 0) return false; + D(bug("nvram3 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(M68K_EMUL_OP_XPRAM3); + *wp = htons(0x4ed3); // jmp (a3) + + static const uint8 nvram4_dat[] = {0x4e, 0x56, 0xff, 0xa8, 0x48, 0xe7, 0x1f, 0x38, 0x16, 0x2e, 0x00, 0x13}; + if ((base = find_rom_data(0xa000, 0xd000, nvram4_dat, sizeof(nvram4_dat))) == 0) return false; + D(bug("nvram4 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 16); + *wp++ = htons(0x1a2e); // move.b ($000f,a6),d5 + *wp++ = htons(0x000f); + *wp++ = htons(M68K_EMUL_OP_NVRAM3); + *wp++ = htons(0x4cee); // movem.l ($ff88,a6),d3-d7/a2-a4 + *wp++ = htons(0x1cf8); + *wp++ = htons(0xff88); + *wp++ = htons(0x4e5e); // unlk a6 + *wp = htons(M68K_RTS); + + static const uint8 nvram5_dat[] = {0x0c, 0x80, 0x03, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x70, 0x00, 0x21, 0xf8, 0x02, 0x0c, 0x01, 0xe4}; + if ((base = find_rom_data(0xa000, 0xd000, nvram5_dat, sizeof(nvram5_dat))) == 0) return false; + D(bug("nvram5 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 6); + *wp = htons(M68K_NOP); + + static const uint8 nvram6_dat[] = {0x2f, 0x0a, 0x24, 0x48, 0x4f, 0xef, 0xff, 0xa0, 0x20, 0x0f}; + if ((base = find_rom_data(0x9000, 0xb000, nvram6_dat, sizeof(nvram6_dat))) == 0) return false; + D(bug("nvram6 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x7000); // moveq #0,d0 + *wp++ = htons(0x2080); // move.l d0,(a0) + *wp++ = htons(0x4228); // clr.b 4(a0) + *wp++ = htons(0x0004); + *wp = htons(M68K_RTS); + + static const uint8 nvram7_dat[] = {0x42, 0x2a, 0x00, 0x04, 0x4f, 0xef, 0x00, 0x60, 0x24, 0x5f, 0x4e, 0x75, 0x4f, 0xef, 0xff, 0xa0, 0x20, 0x0f}; + base = find_rom_data(0x9000, 0xb000, nvram7_dat, sizeof(nvram7_dat)); + if (base) { + D(bug("nvram7 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 12); + *wp = htons(M68K_RTS); + } + } else { + static const uint8 nvram2_dat[] = {0x4e, 0xd6, 0x06, 0x41, 0x13, 0x00}; + if ((base = find_rom_data(0x7000, 0xb000, nvram2_dat, sizeof(nvram2_dat))) == 0) return false; + D(bug("nvram2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 2); + *wp++ = htons(M68K_EMUL_OP_XPRAM2); + *wp = htons(0x4ed3); // jmp (a3) + + static const uint32 nvram3_loc[] = {0x582f0, 0xa0a0, 0x7e50, 0xa1d0, 0}; + wp = (uint16 *)(ROM_BASE + nvram3_loc[ROMType]); + *wp++ = htons(0x202f); // move.l 4(sp),d0 + *wp++ = htons(0x0004); + *wp++ = htons(M68K_EMUL_OP_NVRAM1); + if (ROMType == ROMTYPE_ZANZIBAR || ROMType == ROMTYPE_GAZELLE) + *wp = htons(M68K_RTS); + else { + *wp++ = htons(0x1f40); // move.b d0,8(sp) + *wp++ = htons(0x0008); + *wp++ = htons(0x4e74); // rtd #4 + *wp = htons(0x0004); + } + + static const uint32 nvram4_loc[] = {0x58460, 0xa0f0, 0x7f40, 0xa220, 0}; + wp = (uint16 *)(ROM_BASE + nvram4_loc[ROMType]); + if (ROMType == ROMTYPE_ZANZIBAR || ROMType == ROMTYPE_GAZELLE) { + *wp++ = htons(0x202f); // move.l 4(sp),d0 + *wp++ = htons(0x0004); + *wp++ = htons(0x122f); // move.b 11(sp),d1 + *wp++ = htons(0x000b); + *wp++ = htons(M68K_EMUL_OP_NVRAM2); + *wp = htons(M68K_RTS); + } else { + *wp++ = htons(0x202f); // move.l 6(sp),d0 + *wp++ = htons(0x0006); + *wp++ = htons(0x122f); // move.b 4(sp),d1 + *wp++ = htons(0x0004); + *wp++ = htons(M68K_EMUL_OP_NVRAM2); + *wp++ = htons(0x4e74); // rtd #6 + *wp = htons(0x0006); + } + } + + // Fix MemTop/BootGlobs during system startup + static const uint8 mem_top_dat[] = {0x2c, 0x6c, 0xff, 0xec, 0x2a, 0x4c, 0xdb, 0xec, 0xff, 0xf4}; + if ((base = find_rom_data(0x120, 0x180, mem_top_dat, sizeof(mem_top_dat))) == 0) return false; + D(bug("mem_top %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(M68K_EMUL_OP_FIX_MEMTOP); + *wp = htons(M68K_NOP); + + // Don't initialize SCC (via 0x1ac) + static const uint8 scc_init_dat[] = {0x48, 0xe7, 0x38, 0xfe}; + if ((base = find_rom_data(0x190, 0x1f0, scc_init_dat, sizeof(scc_init_dat))) == 0) return false; + D(bug("scc_init %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base - 2); + wp = (uint16 *)(ROM_BASE + ntohs(*wp) + base - 2); + *wp++ = htons(M68K_EMUL_OP_RESET); + *wp = htons(M68K_RTS); + + // Don't EnableExtCache (via 0x1f6) and don't DisableIntSources(via 0x1fc) + static const uint8 ext_cache_dat[] = {0x4e, 0x7b, 0x00, 0x02}; + if ((base = find_rom_data(0x1d0, 0x230, ext_cache_dat, sizeof(ext_cache_dat))) == 0) return false; + D(bug("ext_cache %08lx\n", base)); + lp = (uint32 *)(ROM_BASE + base + 6); + wp = (uint16 *)(ROM_BASE + ntohl(*lp) + base + 6); + *wp = htons(M68K_RTS); + lp = (uint32 *)(ROM_BASE + base + 12); + wp = (uint16 *)(ROM_BASE + ntohl(*lp) + base + 12); + *wp = htons(M68K_RTS); + + // Fake CPU speed test (SetupTimeK) + static const uint8 timek_dat[] = {0x0c, 0x38, 0x00, 0x04, 0x01, 0x2f, 0x6d, 0x3c}; + if ((base = find_rom_data(0x400, 0x500, timek_dat, sizeof(timek_dat))) == 0) return false; + D(bug("timek %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x31fc); // move.w #xxx,TimeDBRA + *wp++ = htons(100); + *wp++ = htons(0x0d00); + *wp++ = htons(0x31fc); // move.w #xxx,TimeSCCDBRA + *wp++ = htons(100); + *wp++ = htons(0x0d02); + *wp++ = htons(0x31fc); // move.w #xxx,TimeSCSIDBRA + *wp++ = htons(100); + *wp++ = htons(0x0b24); + *wp++ = htons(0x31fc); // move.w #xxx,TimeRAMDBRA + *wp++ = htons(100); + *wp++ = htons(0x0cea); + *wp = htons(M68K_RTS); + + // Relocate jump tables ($2000..) + static const uint8 jump_tab_dat[] = {0x41, 0xfa, 0x00, 0x0e, 0x21, 0xc8, 0x20, 0x10, 0x4e, 0x75}; + if ((base = find_rom_data(0x3000, 0x6000, jump_tab_dat, sizeof(jump_tab_dat))) == 0) return false; + D(bug("jump_tab %08lx\n", base)); + lp = (uint32 *)(ROM_BASE + base + 16); + for (;;) { + D(bug(" %08lx\n", (uint32)lp - ROM_BASE)); + while ((ntohl(*lp) & 0xff000000) == 0xff000000) { + *lp = htonl((ntohl(*lp) & (ROM_SIZE-1)) + ROM_BASE); + lp++; + } + while (!ntohl(*lp)) lp++; + if (ntohl(*lp) != 0x41fa000e) + break; + lp += 4; + } + + // Create SysZone at start of Mac RAM (SetSysAppZone, via 0x22a) + static const uint8 sys_zone_dat[] = {0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x00}; + if ((base = find_rom_data(0x600, 0x900, sys_zone_dat, sizeof(sys_zone_dat))) == 0) return false; + D(bug("sys_zone %08lx\n", base)); + lp = (uint32 *)(ROM_BASE + base); + *lp++ = htonl(RAMBase ? RAMBase : 0x3000); + *lp = htonl(RAMBase ? RAMBase + 0x1800 : 0x4800); + + // Set boot stack at RAMBase+4MB and fix logical/physical RAM size (CompBootStack) + // The RAM size fix must be done after InitMemMgr! + static const uint8 boot_stack_dat[] = {0x08, 0x38, 0x00, 0x06, 0x24, 0x0b}; + if ((base = find_rom_data(0x580, 0x800, boot_stack_dat, sizeof(boot_stack_dat))) == 0) return false; + D(bug("boot_stack %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x207c); // move.l #RAMBase+0x3ffffe,a0 + *wp++ = htons((RAMBase + 0x3ffffe) >> 16); + *wp++ = htons((RAMBase + 0x3ffffe) & 0xffff); + *wp++ = htons(M68K_EMUL_OP_FIX_MEMSIZE); + *wp = htons(M68K_RTS); + + // Get PowerPC page size (InitVMemMgr, via 0x240) + static const uint8 page_size_dat[] = {0x20, 0x30, 0x81, 0xf2, 0x5f, 0xff, 0xef, 0xd8, 0x00, 0x10}; + if ((base = find_rom_data(0xb000, 0x12000, page_size_dat, sizeof(page_size_dat))) == 0) return false; + D(bug("page_size %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x203c); // move.l #$1000,d0 + *wp++ = htons(0); + *wp++ = htons(0x1000); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + + // Gestalt PowerPC page size, RAM size (InitGestalt, via 0x25c) + static const uint8 page_size2_dat[] = {0x26, 0x79, 0x5f, 0xff, 0xef, 0xd8, 0x25, 0x6b, 0x00, 0x10, 0x00, 0x1e}; + if ((base = find_rom_data(0x50000, 0x70000, page_size2_dat, sizeof(page_size2_dat))) == 0) return false; + D(bug("page_size2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x257c); // move.l #$1000,$1e(a2) + *wp++ = htons(0); + *wp++ = htons(0x1000); + *wp++ = htons(0x001e); + *wp++ = htons(0x157c); // move.b #PVR,$1d(a2) + *wp++ = htons(PVR >> 16); + *wp++ = htons(0x001d); + *wp++ = htons(0x263c); // move.l #RAMSize,d3 + *wp++ = htons(RAMSize >> 16); + *wp++ = htons(RAMSize & 0xffff); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + if (ROMType == ROMTYPE_NEWWORLD) + wp = (uint16 *)(ROM_BASE + base + 0x4a); + else + wp = (uint16 *)(ROM_BASE + base + 0x28); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + + // Gestalt CPU/bus clock speed (InitGestalt, via 0x25c) + if (ROMType == ROMTYPE_ZANZIBAR) { + wp = (uint16 *)(ROM_BASE + 0x5d87a); + *wp++ = htons(0x203c); // move.l #Hz,d0 + *wp++ = htons(BusClockSpeed >> 16); + *wp++ = htons(BusClockSpeed & 0xffff); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + wp = (uint16 *)(ROM_BASE + 0x5d888); + *wp++ = htons(0x203c); // move.l #Hz,d0 + *wp++ = htons(CPUClockSpeed >> 16); + *wp++ = htons(CPUClockSpeed & 0xffff); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + } + + // Don't write to GC interrupt mask register (via 0x262) + if (ROMType != ROMTYPE_NEWWORLD) { + static const uint8 gc_mask_dat[] = {0x83, 0xa8, 0x00, 0x24, 0x4e, 0x71}; + if ((base = find_rom_data(0x13000, 0x20000, gc_mask_dat, sizeof(gc_mask_dat))) == 0) return false; + D(bug("gc_mask %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + wp = (uint16 *)(ROM_BASE + base + 0x40); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + wp = (uint16 *)(ROM_BASE + base + 0x78); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + wp = (uint16 *)(ROM_BASE + base + 0x96); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + + static const uint8 gc_mask2_dat[] = {0x02, 0xa8, 0x00, 0x00, 0x00, 0x80, 0x00, 0x24}; + if ((base = find_rom_data(0x13000, 0x20000, gc_mask2_dat, sizeof(gc_mask2_dat))) == 0) return false; + D(bug("gc_mask2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + for (int i=0; i<5; i++) { + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + wp += 2; + } + if (ROMType == ROMTYPE_ZANZIBAR) { + for (int i=0; i<6; i++) { + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + wp += 2; + } + } + } + + // Don't initialize Cuda (via 0x274) + static const uint8 cuda_init_dat[] = {0x08, 0xa9, 0x00, 0x04, 0x16, 0x00, 0x4e, 0x71, 0x13, 0x7c, 0x00, 0x84, 0x1c, 0x00, 0x4e, 0x71}; + if ((base = find_rom_data(0xa000, 0x12000, cuda_init_dat, sizeof(cuda_init_dat))) == 0) return false; + D(bug("cuda_init %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + + // Patch GetCPUSpeed (via 0x27a) (some ROMs have two of them) + static const uint8 cpu_speed_dat[] = {0x20, 0x30, 0x81, 0xf2, 0x5f, 0xff, 0xef, 0xd8, 0x00, 0x04, 0x4c, 0x7c}; + if ((base = find_rom_data(0x6000, 0x9000, cpu_speed_dat, sizeof(cpu_speed_dat))) == 0) return false; + D(bug("cpu_speed %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x203c); // move.l #(MHz<<16)|MHz,d0 + *wp++ = htons(CPUClockSpeed / 1000000); + *wp++ = htons(CPUClockSpeed / 1000000); + *wp = htons(M68K_RTS); + if ((base = find_rom_data(base, 0x9000, cpu_speed_dat, sizeof(cpu_speed_dat))) != 0) { + D(bug("cpu_speed2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x203c); // move.l #(MHz<<16)|MHz,d0 + *wp++ = htons(CPUClockSpeed / 1000000); + *wp++ = htons(CPUClockSpeed / 1000000); + *wp = htons(M68K_RTS); + } + + // Don't poke VIA in InitTimeMgr (via 0x298) + static const uint8 time_via_dat[] = {0x40, 0xe7, 0x00, 0x7c, 0x07, 0x00, 0x28, 0x78, 0x01, 0xd4, 0x43, 0xec, 0x10, 0x00}; + if ((base = find_rom_data(0x30000, 0x40000, time_via_dat, sizeof(time_via_dat))) == 0) return false; + D(bug("time_via %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x4cdf); // movem.l (sp)+,d0-d5/a0-a4 + *wp++ = htons(0x1f3f); + *wp = htons(M68K_RTS); + + // Don't read from 0xff800000 (Name Registry, Open Firmware?) (via 0x2a2) + // Remove this if FE03 works!! + static const uint8 open_firmware_dat[] = {0x2f, 0x79, 0xff, 0x80, 0x00, 0x00, 0x00, 0xfc}; + if ((base = find_rom_data(0x48000, 0x58000, open_firmware_dat, sizeof(open_firmware_dat))) == 0) return false; + D(bug("open_firmware %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x2f7c); // move.l #deadbeef,0xfc(a7) + *wp++ = htons(0xdead); + *wp++ = htons(0xbeef); + *wp = htons(0x00fc); + wp = (uint16 *)(ROM_BASE + base + 0x1a); + *wp++ = htons(M68K_NOP); // (FE03 opcode, tries to jump to 0xdeadbeef) + *wp = htons(M68K_NOP); + + // Don't EnableExtCache (via 0x2b2) + static const uint8 ext_cache2_dat[] = {0x4f, 0xef, 0xff, 0xec, 0x20, 0x4f, 0x10, 0xbc, 0x00, 0x01, 0x11, 0x7c, 0x00, 0x1b}; + if ((base = find_rom_data(0x13000, 0x20000, ext_cache2_dat, sizeof(ext_cache2_dat))) == 0) return false; + D(bug("ext_cache2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp = htons(M68K_RTS); + + // Don't install Time Manager task for 60Hz interrupt (Enable60HzInts, via 0x2b8) + if (ROMType == ROMTYPE_NEWWORLD) { + static const uint8 tm_task_dat[] = {0x30, 0x3c, 0x4e, 0x2b, 0xa9, 0xc9}; + if ((base = find_rom_data(0x2e0, 0x320, tm_task_dat, sizeof(tm_task_dat))) == 0) return false; + D(bug("tm_task %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 28); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + } else { + static const uint8 tm_task_dat[] = {0x20, 0x3c, 0x73, 0x79, 0x73, 0x61}; + if ((base = find_rom_data(0x280, 0x300, tm_task_dat, sizeof(tm_task_dat))) == 0) return false; + D(bug("tm_task %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base - 6); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + } + + // Don't read PVR from 0x5fffef80 in DriverServicesLib (via 0x316) + if (ROMType != ROMTYPE_NEWWORLD) { + uint32 dsl_offset = find_rom_resource(FOURCC('n','l','i','b'), -16401); + if (ROMType == ROMTYPE_ZANZIBAR) { + static const uint8 dsl_pvr_dat[] = {0x40, 0x82, 0x00, 0x40, 0x38, 0x60, 0xef, 0x80, 0x3c, 0x63, 0x60, 0x00, 0x80, 0x83, 0x00, 0x00, 0x54, 0x84, 0x84, 0x3e}; + if ((base = find_rom_data(dsl_offset, dsl_offset + 0x6000, dsl_pvr_dat, sizeof(dsl_pvr_dat))) == 0) return false; + } else { + static const uint8 dsl_pvr_dat[] = {0x3b, 0xc3, 0x00, 0x00, 0x30, 0x84, 0xff, 0xa0, 0x40, 0x82, 0x00, 0x44, 0x80, 0x84, 0xef, 0xe0, 0x54, 0x84, 0x84, 0x3e}; + if ((base = find_rom_data(dsl_offset, dsl_offset + 0x6000, dsl_pvr_dat, sizeof(dsl_pvr_dat))) == 0) return false; + } + D(bug("dsl_pvr %08lx\n", base)); + lp = (uint32 *)(ROM_BASE + base + 12); + *lp = htonl(0x3c800000 | (PVR >> 16)); // lis r4,PVR + + // Don't read bus clock from 0x5fffef88 in DriverServicesLib (via 0x316) + if (ROMType == ROMTYPE_ZANZIBAR) { + static const uint8 dsl_bus_dat[] = {0x81, 0x07, 0x00, 0x00, 0x39, 0x20, 0x42, 0x40, 0x81, 0x62, 0xff, 0x20}; + if ((base = find_rom_data(dsl_offset, dsl_offset + 0x6000, dsl_bus_dat, sizeof(dsl_bus_dat))) == 0) return false; + D(bug("dsl_bus %08lx\n", base)); + lp = (uint32 *)(ROM_BASE + base); + *lp = htonl(0x81000000 + XLM_BUS_CLOCK); // lwz r8,(bus clock speed) + } else { + static const uint8 dsl_bus_dat[] = {0x80, 0x83, 0xef, 0xe8, 0x80, 0x62, 0x00, 0x10, 0x7c, 0x04, 0x03, 0x96}; + if ((base = find_rom_data(dsl_offset, dsl_offset + 0x6000, dsl_bus_dat, sizeof(dsl_bus_dat))) == 0) return false; + D(bug("dsl_bus %08lx\n", base)); + lp = (uint32 *)(ROM_BASE + base); + *lp = htonl(0x80800000 + XLM_BUS_CLOCK); // lwz r4,(bus clock speed) + } + } + + // Don't open InterruptTreeTNT in MotherBoardHAL init in DriverServicesLib init + if (ROMType == ROMTYPE_ZANZIBAR) { + lp = (uint32 *)(ROM_BASE + find_rom_resource(FOURCC('n','l','i','b'), -16408) + 0x16c); + *lp = htonl(0x38600000); // li r3,0 + } + + // Patch Name Registry + static const uint8 name_reg_dat[] = {0x70, 0xff, 0xab, 0xeb}; + if ((base = find_rom_data(0x300, 0x380, name_reg_dat, sizeof(name_reg_dat))) == 0) return false; + D(bug("name_reg %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp = htons(M68K_EMUL_OP_NAME_REGISTRY); + +#if DISABLE_SCSI + // Fake SCSI Manager + // Remove this if SCSI Manager works!! + static const uint8 scsi_mgr_a_dat[] = {0x4e, 0x56, 0x00, 0x00, 0x20, 0x3c, 0x00, 0x00, 0x04, 0x0c, 0xa7, 0x1e}; + static const uint8 scsi_mgr_b_dat[] = {0x4e, 0x56, 0x00, 0x00, 0x2f, 0x0c, 0x20, 0x3c, 0x00, 0x00, 0x04, 0x0c, 0xa7, 0x1e}; + if ((base = find_rom_data(0x1c000, 0x28000, scsi_mgr_a_dat, sizeof(scsi_mgr_a_dat))) == 0) { + if ((base = find_rom_data(0x1c000, 0x28000, scsi_mgr_b_dat, sizeof(scsi_mgr_b_dat))) == 0) return false; + } + D(bug("scsi_mgr %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x21fc); // move.l #xxx,0x624 (SCSIAtomic) + *wp++ = htons((ROM_BASE + base + 18) >> 16); + *wp++ = htons((ROM_BASE + base + 18) & 0xffff); + *wp++ = htons(0x0624); + *wp++ = htons(0x21fc); // move.l #xxx,0xe54 (SCSIDispatch) + *wp++ = htons((ROM_BASE + base + 22) >> 16); + *wp++ = htons((ROM_BASE + base + 22) & 0xffff); + *wp++ = htons(0x0e54); + *wp++ = htons(M68K_RTS); + *wp++ = htons(M68K_EMUL_OP_SCSI_ATOMIC); + *wp++ = htons(M68K_RTS); + *wp++ = htons(M68K_EMUL_OP_SCSI_DISPATCH); + *wp = htons(0x4ed0); // jmp (a0) + wp = (uint16 *)(ROM_BASE + base + 0x20); + *wp++ = htons(0x7000); // moveq #0,d0 + *wp = htons(M68K_RTS); +#endif + +#if DISABLE_SCSI + // Don't access SCSI variables + // Remove this if SCSI Manager works!! + if (ROMType == ROMTYPE_NEWWORLD) { + static const uint8 scsi_var_dat[] = {0x70, 0x01, 0xa0, 0x89, 0x4a, 0x6e, 0xfe, 0xac, 0x4f, 0xef, 0x00, 0x10, 0x66, 0x00}; + if ((base = find_rom_data(0x1f500, 0x1f600, scsi_var_dat, sizeof(scsi_var_dat))) != 0) { + D(bug("scsi_var %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 12); + *wp = htons(0x6000); // bra + } + + static const uint8 scsi_var2_dat[] = {0x4e, 0x56, 0xfc, 0x58, 0x48, 0xe7, 0x1f, 0x38}; + if ((base = find_rom_data(0x1f700, 0x1f800, scsi_var2_dat, sizeof(scsi_var2_dat))) != 0) { + D(bug("scsi_var2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x7000); // moveq #0,d0 + *wp = htons(M68K_RTS); // bra + } + } +#endif + + // Don't wait in ADBInit (via 0x36c) + static const uint8 adb_init_dat[] = {0x08, 0x2b, 0x00, 0x05, 0x01, 0x5d, 0x66, 0xf8}; + if ((base = find_rom_data(0x31000, 0x3d000, adb_init_dat, sizeof(adb_init_dat))) == 0) return false; + D(bug("adb_init %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 6); + *wp = htons(M68K_NOP); + + // Modify check in InitResources() so that addresses >0x80000000 work + static const uint8 init_res_dat[] = {0x4a, 0xb8, 0x0a, 0x50, 0x6e, 0x20}; + if ((base = find_rom_data(0x78000, 0x8c000, init_res_dat, sizeof(init_res_dat))) == 0) return false; + D(bug("init_res %08lx\n", base)); + bp = (uint8 *)(ROM_BASE + base + 4); + *bp = 0x66; + + // Modify vCheckLoad() so that we can patch resources (68k Resource Manager) + static const uint8 check_load_dat[] = {0x20, 0x78, 0x07, 0xf0, 0x4e, 0xd0}; + if ((base = find_rom_data(0x78000, 0x8c000, check_load_dat, sizeof(check_load_dat))) == 0) return false; + D(bug("check_load %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(M68K_JMP); + *wp++ = htons((ROM_BASE + CHECK_LOAD_PATCH_SPACE) >> 16); + *wp = htons((ROM_BASE + CHECK_LOAD_PATCH_SPACE) & 0xffff); + wp = (uint16 *)(ROM_BASE + CHECK_LOAD_PATCH_SPACE); + *wp++ = htons(0x2f03); // move.l d3,-(a7) + *wp++ = htons(0x2078); // move.l $07f0,a0 + *wp++ = htons(0x07f0); + *wp++ = htons(M68K_JSR_A0); + *wp++ = htons(M68K_EMUL_OP_CHECKLOAD); + *wp = htons(M68K_RTS); + + // Replace .Sony driver + sony_offset = find_rom_resource(FOURCC('D','R','V','R'), 4); + if (ROMType == ROMTYPE_ZANZIBAR || ROMType == ROMTYPE_NEWWORLD) + sony_offset = find_rom_resource(FOURCC('D','R','V','R'), 4, true); // First DRVR 4 is .MFMFloppy + if (sony_offset == 0) { + sony_offset = find_rom_resource(FOURCC('n','d','r','v'), -20196); // NewWorld 1.6 has "PCFloppy" ndrv + if (sony_offset == 0) + return false; + lp = (uint32 *)(ROM_BASE + rsrc_ptr + 8); + *lp = htonl(FOURCC('D','R','V','R')); + wp = (uint16 *)(ROM_BASE + rsrc_ptr + 12); + *wp = htons(4); + } + D(bug("sony_offset %08lx\n", sony_offset)); + memcpy((void *)(ROM_BASE + sony_offset), sony_driver, sizeof(sony_driver)); + + // Install .Disk and .AppleCD drivers + memcpy((void *)(ROM_BASE + sony_offset + 0x100), disk_driver, sizeof(disk_driver)); + memcpy((void *)(ROM_BASE + sony_offset + 0x200), cdrom_driver, sizeof(cdrom_driver)); + + // Install serial drivers + memcpy((void *)(ROM_BASE + sony_offset + 0x300), ain_driver, sizeof(ain_driver)); + memcpy((void *)(ROM_BASE + sony_offset + 0x400), aout_driver, sizeof(aout_driver)); + memcpy((void *)(ROM_BASE + sony_offset + 0x500), bin_driver, sizeof(bin_driver)); + memcpy((void *)(ROM_BASE + sony_offset + 0x600), bout_driver, sizeof(bout_driver)); + + // Copy icons to ROM + SonyDiskIconAddr = ROM_BASE + sony_offset + 0x800; + memcpy((void *)(ROM_BASE + sony_offset + 0x800), SonyDiskIcon, sizeof(SonyDiskIcon)); + SonyDriveIconAddr = ROM_BASE + sony_offset + 0xa00; + memcpy((void *)(ROM_BASE + sony_offset + 0xa00), SonyDriveIcon, sizeof(SonyDriveIcon)); + DiskIconAddr = ROM_BASE + sony_offset + 0xc00; + memcpy((void *)(ROM_BASE + sony_offset + 0xc00), DiskIcon, sizeof(DiskIcon)); + CDROMIconAddr = ROM_BASE + sony_offset + 0xe00; + memcpy((void *)(ROM_BASE + sony_offset + 0xe00), CDROMIcon, sizeof(CDROMIcon)); + + // Patch driver install routine + static const uint8 drvr_install_dat[] = {0xa7, 0x1e, 0x21, 0xc8, 0x01, 0x1c, 0x4e, 0x75}; + if ((base = find_rom_data(0xb00, 0xd00, drvr_install_dat, sizeof(drvr_install_dat))) == 0) return false; + D(bug("drvr_install %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base + 8); + *wp++ = htons(M68K_EMUL_OP_INSTALL_DRIVERS); + *wp = htons(M68K_RTS); + + // Don't install serial drivers from ROM + if (ROMType == ROMTYPE_ZANZIBAR || ROMType == ROMTYPE_NEWWORLD) { + wp = (uint16 *)(ROM_BASE + find_rom_resource(FOURCC('S','E','R','D'), 0)); + *wp = htons(M68K_RTS); + } else { + wp = (uint16 *)(ROM_BASE + find_rom_resource(FOURCC('s','l','0','5'), 2) + 0xc4); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp = htons(0x7000); // moveq #0,d0 + wp = (uint16 *)(ROM_BASE + find_rom_resource(FOURCC('s','l','0','5'), 2) + 0x8ee); + *wp = htons(M68K_NOP); + } + uint32 nsrd_offset = find_rom_resource(FOURCC('n','s','r','d'), 1); + if (nsrd_offset) { + lp = (uint32 *)(ROM_BASE + rsrc_ptr + 8); + *lp = htonl(FOURCC('x','s','r','d')); + } + + // Replace ADBOp() + memcpy((void *)(ROM_BASE + find_rom_trap(0xa07c)), adbop_patch, sizeof(adbop_patch)); + + // Replace Time Manager + wp = (uint16 *)(ROM_BASE + find_rom_trap(0xa058)); + *wp++ = htons(M68K_EMUL_OP_INSTIME); + *wp = htons(M68K_RTS); + wp = (uint16 *)(ROM_BASE + find_rom_trap(0xa059)); + *wp++ = htons(0x40e7); // move sr,-(sp) + *wp++ = htons(0x007c); // ori #$0700,sr + *wp++ = htons(0x0700); + *wp++ = htons(M68K_EMUL_OP_RMVTIME); + *wp++ = htons(0x46df); // move (sp)+,sr + *wp = htons(M68K_RTS); + wp = (uint16 *)(ROM_BASE + find_rom_trap(0xa05a)); + *wp++ = htons(0x40e7); // move sr,-(sp) + *wp++ = htons(0x007c); // ori #$0700,sr + *wp++ = htons(0x0700); + *wp++ = htons(M68K_EMUL_OP_PRIMETIME); + *wp++ = htons(0x46df); // move (sp)+,sr + *wp = htons(M68K_RTS); + wp = (uint16 *)(ROM_BASE + find_rom_trap(0xa093)); + *wp++ = htons(M68K_EMUL_OP_MICROSECONDS); + *wp = htons(M68K_RTS); + + // Disable Egret Manager + static const uint8 egret_dat[] = {0x2f, 0x30, 0x81, 0xe2, 0x20, 0x10, 0x00, 0x18}; + if ((base = find_rom_data(0xa000, 0x10000, egret_dat, sizeof(egret_dat))) == 0) return false; + D(bug("egret %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + *wp++ = htons(0x7000); + *wp = htons(M68K_RTS); + + // Don't call FE0A opcode in Shutdown Manager + static const uint8 shutdown_dat[] = {0x40, 0xe7, 0x00, 0x7c, 0x07, 0x00, 0x48, 0xe7, 0x3f, 0x00, 0x2c, 0x00, 0x2e, 0x01}; + if ((base = find_rom_data(0x30000, 0x40000, shutdown_dat, sizeof(shutdown_dat))) == 0) return false; + D(bug("shutdown %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); + if (ROMType == ROMTYPE_ZANZIBAR) + *wp = htons(M68K_RTS); + else + wp[-2] = htons(0x6000); // bra + + // Patch PowerOff() + wp = (uint16 *)(ROM_BASE + find_rom_trap(0xa05b)); // PowerOff() + *wp = htons(M68K_EMUL_RETURN); + + // Patch VIA interrupt handler + static const uint8 via_int_dat[] = {0x70, 0x7f, 0xc0, 0x29, 0x1a, 0x00, 0xc0, 0x29, 0x1c, 0x00}; + if ((base = find_rom_data(0x13000, 0x1c000, via_int_dat, sizeof(via_int_dat))) == 0) return false; + D(bug("via_int %08lx\n", base)); + uint32 level1_int = ROM_BASE + base; + wp = (uint16 *)level1_int; // Level 1 handler + *wp++ = htons(0x7002); // moveq #2,d0 (60Hz interrupt) + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp++ = htons(M68K_NOP); + *wp = htons(M68K_NOP); + + static const uint8 via_int2_dat[] = {0x13, 0x7c, 0x00, 0x02, 0x1a, 0x00, 0x4e, 0x71, 0x52, 0xb8, 0x01, 0x6a}; + if ((base = find_rom_data(0x10000, 0x18000, via_int2_dat, sizeof(via_int2_dat))) == 0) return false; + D(bug("via_int2 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); // 60Hz handler + *wp++ = htons(M68K_EMUL_OP_IRQ); + *wp++ = htons(0x4a80); // tst.l d0 + *wp++ = htons(0x6700); // beq xxx + *wp = htons(0xffe8); + + if (ROMType == ROMTYPE_NEWWORLD) { + static const uint8 via_int3_dat[] = {0x48, 0xe7, 0xf0, 0xf0, 0x76, 0x01, 0x60, 0x26}; + if ((base = find_rom_data(0x15000, 0x18000, via_int3_dat, sizeof(via_int3_dat))) == 0) return false; + D(bug("via_int3 %08lx\n", base)); + wp = (uint16 *)(ROM_BASE + base); // CHRP level 1 handler + *wp++ = htons(M68K_JMP); + *wp++ = htons((level1_int - 12) >> 16); + *wp = htons((level1_int - 12) & 0xffff); + } + + // Patch PutScrap() for clipboard exchange with host OS + uint32 put_scrap = find_rom_trap(0xa9fe); // PutScrap() + wp = (uint16 *)(ROM_BASE + PUT_SCRAP_PATCH_SPACE); + *wp++ = htons(M68K_EMUL_OP_PUT_SCRAP); + *wp++ = htons(M68K_JMP); + *wp++ = htons((ROM_BASE + put_scrap) >> 16); + *wp++ = htons((ROM_BASE + put_scrap) & 0xffff); + lp = (uint32 *)(ROM_BASE + 0x22); + lp = (uint32 *)(ROM_BASE + ntohl(*lp)); + lp[0xa9fe & 0x3ff] = htonl(PUT_SCRAP_PATCH_SPACE); + + // Patch GetScrap() for clipboard exchange with host OS + uint32 get_scrap = find_rom_trap(0xa9fd); // GetScrap() + wp = (uint16 *)(ROM_BASE + GET_SCRAP_PATCH_SPACE); + *wp++ = htons(M68K_EMUL_OP_GET_SCRAP); + *wp++ = htons(M68K_JMP); + *wp++ = htons((ROM_BASE + get_scrap) >> 16); + *wp++ = htons((ROM_BASE + get_scrap) & 0xffff); + lp = (uint32 *)(ROM_BASE + 0x22); + lp = (uint32 *)(ROM_BASE + ntohl(*lp)); + lp[0xa9fd & 0x3ff] = htonl(GET_SCRAP_PATCH_SPACE); + +#if __BEOS__ + // Patch SynchIdleTime() + if (PrefsFindBool("idlewait")) { + wp = (uint16 *)(ROM_BASE + find_rom_trap(0xabf7) + 4); // SynchIdleTime() + D(bug("SynchIdleTime at %08lx\n", wp)); + if (ntohs(*wp) == 0x2078) { + *wp++ = htons(M68K_EMUL_OP_IDLE_TIME); + *wp = htons(M68K_NOP); + } else { + D(bug("SynchIdleTime patch not installed\n")); + } + } +#endif + + // Construct list of all sifters used by sound components in ROM + D(bug("Searching for sound components with type sdev in ROM\n")); + uint32 thing = find_rom_resource(FOURCC('t','h','n','g')); + while (thing) { + thing += ROM_BASE; + D(bug(" found %c%c%c%c %c%c%c%c\n", ReadMacInt8(thing), ReadMacInt8(thing + 1), ReadMacInt8(thing + 2), ReadMacInt8(thing + 3), ReadMacInt8(thing + 4), ReadMacInt8(thing + 5), ReadMacInt8(thing + 6), ReadMacInt8(thing + 7))); + if (ReadMacInt32(thing) == FOURCC('s','d','e','v') && ReadMacInt32(thing + 4) == FOURCC('s','i','n','g')) { + WriteMacInt32(thing + 4, FOURCC('a','w','g','c')); + D(bug(" found sdev component at offset %08x in ROM\n", thing)); + AddSifter(ReadMacInt32(thing + componentResType), ReadMacInt16(thing + componentResID)); + if (ReadMacInt32(thing + componentPFCount)) + AddSifter(ReadMacInt32(thing + componentPFResType), ReadMacInt16(thing + componentPFResID)); + } + thing = find_rom_resource(FOURCC('t','h','n','g'), 4711, true); + } + + // Patch component code + D(bug("Patching sifters in ROM\n")); + for (int i=0; i +#include +#include + +#include "sysdeps.h" +#include "rsrc_patches.h" +#include "cpu_emulation.h" +#include "emul_op.h" +#include "xlowmem.h" +#include "macos_util.h" +#include "rom_patches.h" +#include "main.h" +#include "audio.h" + +#define DEBUG 0 +#include "debug.h" + + +// Sound input driver +static const uint8 sound_input_driver[] = { // .AppleSoundInput driver header + // Driver header + 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x24, // Open() offset + 0x00, 0x28, // Prime() offset + 0x00, 0x2c, // Control() offset + 0x00, 0x38, // Status() offset + 0x00, 0x5e, // Close() offset + 0x10, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x00, // ".AppleSoundInput" + + // Open() + M68K_EMUL_OP_SOUNDIN_OPEN >> 8, M68K_EMUL_OP_SOUNDIN_OPEN & 0xff, + 0x4e, 0x75, // rts + + // Prime() + M68K_EMUL_OP_SOUNDIN_PRIME >> 8, M68K_EMUL_OP_SOUNDIN_PRIME & 0xff, + 0x60, 0x0e, // bra IOReturn + + // Control() + M68K_EMUL_OP_SOUNDIN_CONTROL >> 8, M68K_EMUL_OP_SOUNDIN_CONTROL & 0xff, + 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) + 0x66, 0x04, // bne IOReturn + 0x4e, 0x75, // rts + + // Status() + M68K_EMUL_OP_SOUNDIN_STATUS >> 8, M68K_EMUL_OP_SOUNDIN_STATUS & 0xff, + + // IOReturn + 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 + 0x08, 0x01, 0x00, 0x09, // btst #9,d1 + 0x67, 0x0c, // beq 1 + 0x4a, 0x40, // tst.w d0 + 0x6f, 0x02, // ble 2 + 0x42, 0x40, // clr.w d0 + 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) + 0x4e, 0x75, // rts + 0x4a, 0x40, //1 tst.w d0 + 0x6f, 0x04, // ble 3 + 0x42, 0x40, // clr.w d0 + 0x4e, 0x75, // rts + 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(sp) + 0x4e, 0x75, // rts + + // Close() + M68K_EMUL_OP_SOUNDIN_CLOSE >> 8, M68K_EMUL_OP_SOUNDIN_CLOSE & 0xff, + 0x4e, 0x75, // rts +}; + + +/* + * Search resource for byte string, return offset (or 0) + */ + +static uint32 find_rsrc_data(const uint8 *rsrc, uint32 max, const uint8 *search, uint32 search_len, uint32 ofs = 0) +{ + while (ofs < max - search_len) { + if (!memcmp(rsrc + ofs, search, search_len)) + return ofs; + ofs++; + } + return 0; +} + + +/* + * Resource patches via vCheckLoad + */ + +void CheckLoad(uint32 type, int16 id, uint16 *p, uint32 size) +{ + uint16 *p16; + uint32 base; + D(bug("vCheckLoad %c%c%c%c (%08x) ID %d, data %p, size %d\n", type >> 24, (type >> 16) & 0xff, (type >> 8) & 0xff, type & 0xff, type, id, p, size)); + + // Don't modify resources in ROM + if ((uint32)p >= ROM_BASE && (uint32)p <= (ROM_BASE + ROM_SIZE)) + return; + + if (type == FOURCC('b','o','o','t') && id == 3) { + D(bug("boot 3 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0x2e49) { + // Set boot stack pointer (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1, 8.0, 8.1, 8.5, 8.6) + p[0] = M68K_EMUL_OP_FIX_BOOTSTACK; + D(bug(" patch 1 applied\n")); + } else if (p[0] == 0x4267 && p[1] == 0x3f01 && p[2] == 0x3f2a && p[3] == 0x0006 && p[4] == 0x6100) { + // Check when ntrb 17 is installed (for native Resource Manager patch) (7.5.3, 7.5.5) + p[7] = M68K_EMUL_OP_NTRB_17_PATCH3; + D(bug(" patch 2 applied\n")); + } else if (p[0] == 0x3f2a && p[1] == 0x0006 && p[2] == 0x3f2a && p[3] == 0x0002 && p[4] == 0x6100) { + // Check when ntrb 17 is installed (for native Resource Manager patch) (7.6, 7.6.1, 8.0, 8.1) + p[7] = M68K_EMUL_OP_NTRB_17_PATCH; + D(bug(" patch 3 applied\n")); + } else if (p[0] == 0x3f2a && p[1] == 0x0006 && p[2] == 0x3f2a && p[3] == 0x0002 && p[4] == 0x61ff) { + // Check when ntrb 17 is installed (for native Resource Manager patch) (8.5, 8.6) + p[8] = M68K_EMUL_OP_NTRB_17_PATCH; + D(bug(" patch 4 applied\n")); + } else if (p[0] == 0x0c39 && p[1] == 0x0001 && p[2] == 0xf800 && p[3] == 0x0008 && p[4] == 0x6f00) { + // Don't read from 0xf8000008 (8.5 with Zanzibar ROM, 8.6) + p[0] = M68K_NOP; + p[1] = M68K_NOP; + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[4] = 0x6000; // bra + D(bug(" patch 5 applied\n")); + } else if (p[0] == 0x2f3c && p[1] == 0x6b72 && p[2] == 0x6e6c && p[3] == 0x4267 && p[4] == 0xa9a0 && p[5] == 0x265f && p[6] == 0x200b && p[7] == 0x6700) { + // Don't replace nanokernel ("krnl" resource) (8.6) + p[0] = M68K_NOP; + p[1] = M68K_NOP; + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[4] = M68K_NOP; + p[7] = 0x6000; // bra + D(bug(" patch 6 applied\n")); + } else if (p[0] == 0xa8fe && p[1] == 0x3038 && p[2] == 0x017a && p[3] == 0x0c40 && p[4] == 0x8805 && p[5] == 0x6710) { + // No SCSI (calls via 0x205c jump vector which is not initialized in NewWorld ROM 1.6) (8.6) + if (ROMType == ROMTYPE_NEWWORLD) { + p[5] = 0x6010; // bra + D(bug(" patch 7 applied\n")); + } + } + p++; + } + + } else if (type == FOURCC('g','n','l','d') && id == 0) { + D(bug("gnld 0 found\n")); + + // Patch native Resource Manager after ntrbs are installed (7.5.2) + static const uint8 dat[] = {0x4e, 0xba, 0x00, 0x9e, 0x3e, 0x00, 0x50, 0x4f, 0x67, 0x04}; + base = find_rsrc_data((uint8 *)p, size, dat, sizeof(dat)); + if (base) { + p16 = (uint16 *)((uint32)p + base + 6); + *p16 = htons(M68K_EMUL_OP_NTRB_17_PATCH2); + D(bug(" patch 1 applied\n")); + } + + } else if (type == FOURCC('p','t','c','h') && id == 420) { + D(bug("ptch 420 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0xa030 && p[1] == 0x5240 && p[2] == 0x303c && p[3] == 0x0100 && p[4] == 0xc06e && p[5] == 0xfef6) { + // Disable VM (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1) + p[1] = M68K_NOP; + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[4] = M68K_NOP; + p[5] = M68K_NOP; + p[6] = M68K_NOP; + p[7] = M68K_NOP; + p[8] = M68K_NOP; + p[9] = M68K_NOP; + p[10] = M68K_NOP; + p[11] = M68K_NOP; + D(bug(" patch 1 applied\n")); + break; + } else if (p[0] == 0xa030 && p[1] == 0x5240 && p[2] == 0x7000 && p[3] == 0x302e && p[4] == 0xfef6 && p[5] == 0x323c && p[6] == 0x0100) { + // Disable VM (8.0, 8.1) + p[8] = M68K_NOP; + p[15] = M68K_NOP; + D(bug(" patch 2 applied\n")); + break; + } else if (p[0] == 0xa030 && p[1] == 0x5240 && p[2] == 0x7000 && p[3] == 0x302e && p[4] == 0xfecc && p[5] == 0x323c && p[6] == 0x0100) { + // Disable VM (8.5, 8.6) + p[8] = M68K_NOP; + p[15] = M68K_NOP; + D(bug(" patch 3 applied\n")); + break; + } + p++; + } + + } else if (type == FOURCC('g','p','c','h') && id == 16) { + D(bug("gpch 16 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0x6700 && p[13] == 0x7013 && p[14] == 0xfe0a) { + // Don't call FE0A in Shutdown Manager (7.6.1, 8.0, 8.1, 8.5) + p[0] = 0x6000; + D(bug(" patch 1 applied\n")); + break; + } + p++; + } + + } else if (type == FOURCC('g','p','c','h') && id == 650) { + D(bug("gpch 650 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0x6600 && p[1] == 0x001a && p[2] == 0x2278 && p[3] == 0x0134) { + // We don't have SonyVars (7.5.2) + p[0] = 0x6000; + D(bug(" patch 1 applied\n")); + } else if (p[0] == 0x6618 && p[1] == 0x2278 && p[2] == 0x0134) { + // We don't have SonyVars (7.5.3) + p[-6] = M68K_NOP; + p[-3] = M68K_NOP; + p[0] = 0x6018; + D(bug(" patch 2 applied\n")); + } else if (p[0] == 0x666e && p[1] == 0x2278 && p[2] == 0x0134) { + // We don't have SonyVars (7.5.5) + p[-6] = M68K_NOP; + p[-3] = M68K_NOP; + p[0] = 0x606e; + D(bug(" patch 3 applied\n")); + } else if (p[0] == 0x6400 && p[1] == 0x011c && p[2] == 0x2278 && p[3] == 0x0134) { + // We don't have SonyVars (7.6.1, 8.0, 8.1, 8.5, 8.6) + p[0] = 0x6000; + D(bug(" patch 4 applied\n")); + } else if (p[0] == 0x6400 && p[1] == 0x00e6 && p[2] == 0x2278 && p[3] == 0x0134) { + // We don't have SonyVars (7.6) + p[0] = 0x6000; + D(bug(" patch 5 applied\n")); + } + p++; + } + + } else if (type == FOURCC('g','p','c','h') && id == 655) { + D(bug("gpch 655 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0x83a8 && p[1] == 0x0024 && p[2] == 0x4e71) { + // Don't write to GC interrupt mask (7.6, 7.6.1, 8.0, 8.1 with Zanzibar ROM) + p[0] = M68K_NOP; + p[1] = M68K_NOP; + D(bug(" patch 1 applied\n")); + } else if (p[0] == 0x207c && p[1] == 0xf300 && p[2] == 0x0034) { + // Don't read PowerMac ID (7.6, 7.6.1, 8.0, 8.1 with Zanzibar ROM) + p[0] = 0x303c; // move.w #id,d0 + p[1] = 0x3020; + p[2] = M68K_RTS; + D(bug(" patch 2 applied\n")); + } else if (p[0] == 0x13fc && p[1] == 0x0081 && p[2] == 0xf130 && p[3] == 0xa030) { + // Don't write to hardware (7.6, 7.6.1, 8.0, 8.1 with Zanzibar ROM) + p[0] = M68K_NOP; + p[1] = M68K_NOP; + p[2] = M68K_NOP; + p[3] = M68K_NOP; + D(bug(" patch 3 applied\n")); + } else if (p[0] == 0x4e56 && p[1] == 0x0000 && p[2] == 0x227c && p[3] == 0xf800 && p[4] == 0x0000) { + // OpenFirmare? (7.6.1, 8.0, 8.1 with Zanzibar ROM) + p[0] = M68K_RTS; + D(bug(" patch 4 applied\n")); + } else if (p[0] == 0x4e56 && p[1] == 0xfffc && p[2] == 0x48e7 && p[3] == 0x0300 && p[4] == 0x598f && p[5] == 0x2eb8 && p[6] == 0x01dc) { + // Don't write to SCC (7.6.1, 8.0, 8.1 with Zanzibar ROM) + p[0] = M68K_RTS; + D(bug(" patch 5 applied\n")); + } else if (p[0] == 0x4e56 && p[1] == 0x0000 && p[2] == 0x227c && p[3] == 0xf300 && p[4] == 0x0034) { + // Don't write to GC (7.6.1, 8.0, 8.1 with Zanzibar ROM) + p[0] = M68K_RTS; + D(bug(" patch 6 applied\n")); + } else if (p[0] == 0x40e7 && p[1] == 0x007c && p[2] == 0x0700 && p[3] == 0x48e7 && p[4] == 0x00c0 && p[5] == 0x2078 && p[6] == 0x0dd8 && p[7] == 0xd1e8 && p[8] == 0x0044 && p[9] == 0x8005 && p[11] == 0x93c8 && p[12] == 0x2149 && p[13] == 0x0024) { + // Don't replace NVRAM routines (7.6, 7.6.1, 8.0, 8.1 with Zanzibar ROM) + p[0] = M68K_RTS; + D(bug(" patch 7 applied\n")); + } else if (p[0] == 0x207c && p[1] == 0x50f1 && p[2] == 0xa101 && (p[3] == 0x08d0 || p[3] == 0x0890)) { + // Don't write to 0x50f1a101 (8.1 with Zanzibar ROM) + p[3] = M68K_NOP; + p[4] = M68K_NOP; + D(bug(" patch 8 applied\n")); + } + p++; + } + + } else if (type == FOURCC('g','p','c','h') && id == 750) { + D(bug("gpch 750 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0xf301 && p[1] == 0x9100 && p[2] == 0x0c11 && p[3] == 0x0044) { + // Don't read from 0xf3019100 (MACE ENET) (7.6, 7.6.1, 8.0, 8.1) + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[4] = 0x6026; + D(bug(" patch 1 applied\n")); + } else if (p[0] == 0x41e8 && p[1] == 0x0374 && p[2] == 0xfc1e) { + // Don't call FC1E opcode (7.6, 7.6.1, 8.0, 8.1, 8.5, 8.6) + p[2] = M68K_NOP; + D(bug(" patch 2 applied\n")); + } else if (p[0] == 0x700a && p[1] == 0xfe0a) { + // Don't call FE0A opcode (7.6, 7.6.1, 8.0, 8.1, 8.5, 8.6) + p[1] = 0x7000; + D(bug(" patch 3 applied\n")); + } + p++; + } + + } else if (type == FOURCC('g','p','c','h') && id == 999) { + D(bug("gpch 999 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0xf301 && p[1] == 0x9100 && p[2] == 0x0c11 && p[3] == 0x0044) { + // Don't read from 0xf3019100 (MACE ENET) (8.5, 8.6) + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[4] = 0x6026; + D(bug(" patch 1 applied\n")); + } + p++; + } + + } else if (type == FOURCC('g','p','c','h') && id == 3000) { + D(bug("gpch 3000 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0xf301 && p[1] == 0x9100 && p[2] == 0x0c11 && p[3] == 0x0044) { + // Don't read from 0xf3019100 (MACE ENET) (8.1 with NewWorld ROM) + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[4] = 0x6026; + D(bug(" patch 1 applied\n")); + } + p++; + } + + } else if (type == FOURCC('l','t','l','k') && id == 0) { + D(bug("ltlk 0 found\n")); +#if 1 + size >>= 1; + while (size--) { + if (p[0] == 0xc2fc && p[1] == 0x0fa0 && p[2] == 0x82c5) { + // Prevent division by 0 in speed test (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1, 8.0, 8.1) + p[2] = 0x7200; + WriteMacInt32(0x1d8, 0x2c00); + WriteMacInt32(0x1dc, 0x2c00); + D(bug(" patch 1 applied\n")); + } else if (p[0] == 0x1418 && p[1] == 0x84c1) { + // Prevent division by 0 (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1, 8.0, 8.1) + p[1] = 0x7400; + D(bug(" patch 2 applied\n")); + } else if (p[0] == 0x2678 && p[1] == 0x01dc && p[2] == 0x3018 && p[3] == 0x6708 && p[4] == 0x1680 && p[5] == 0xe058 && p[6] == 0x1680) { + // Don't write to SCC (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1, 8.0, 8.1) + p[4] = M68K_NOP; + p[6] = M68K_NOP; + D(bug(" patch 3 applied\n")); + } else if (p[0] == 0x2278 && p[1] == 0x01dc && p[2] == 0x12bc && p[3] == 0x0006 && p[4] == 0x4e71 && p[5] == 0x1292) { + // Don't write to SCC (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1, 8.0, 8.1) + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[5] = M68K_NOP; + D(bug(" patch 4 applied\n")); + } else if (p[0] == 0x2278 && p[1] == 0x01dc && p[2] == 0x12bc && p[3] == 0x0003 && p[4] == 0x4e71 && p[5] == 0x1281) { + // Don't write to SCC (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1, 8.0, 8.1) + p[2] = M68K_NOP; + p[3] = M68K_NOP; + p[5] = M68K_NOP; + D(bug(" patch 5 applied\n")); + } else if (p[0] == 0x0811 && p[1] == 0x0000 && p[2] == 0x51c8 && p[3] == 0xfffa) { + // Don't test SCC (7.5.2, 7.5.3, 7.5.5, 7.6, 7.6.1, 8.0, 8.1) + p[0] = M68K_NOP; + p[1] = M68K_NOP; + D(bug(" patch 6 applied\n")); + } else if (p[0] == 0x4a2a && p[1] == 0x063e && p[2] == 0x66fa) { + // Don't wait for SCC (7.5.2, 7.5.3, 7.5.5) + p[2] = M68K_NOP; + D(bug(" patch 7 applied\n")); + } else if (p[0] == 0x4a2a && p[1] == 0x03a6 && p[2] == 0x66fa) { + // Don't wait for SCC (7.6, 7.6.1, 8.0, 8.1) + p[2] = M68K_NOP; + D(bug(" patch 8 applied\n")); + } + p++; + } +#else + // Disable LocalTalk + p[0] = M68K_JMP_A0; + p[1] = 0x7000; // moveq #0,d0 + p[2] = M68K_RTS; + D(bug(" patch 1 applied\n")); +#endif + + } else if (type == FOURCC('n','s','r','d') && id == 1) { + D(bug("nsrd 1 found\n")); + if (p[(0x378 + 0x570) >> 1] == 0x7c08 && p[(0x37a + 0x570) >> 1] == 0x02a6) { + // Don't overwrite our serial drivers (8.0, 8.1) + p[(0x378 + 0x570) >> 1] = 0x4e80; // blr + p[(0x37a + 0x570) >> 1] = 0x0020; + D(bug(" patch 1 applied\n")); + } else if (p[(0x378 + 0x6c0) >> 1] == 0x7c08 && p[(0x37a + 0x6c0) >> 1] == 0x02a6) { + // Don't overwrite our serial drivers (8.5, 8.6) + p[(0x378 + 0x6c0) >> 1] = 0x4e80; // blr + p[(0x37a + 0x6c0) >> 1] = 0x0020; + D(bug(" patch 2 applied\n")); + } + + } else if (type == FOURCC('c','i','t','t') && id == 45) { + D(bug("citt 45 found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0x203c && p[1] == 0x0100 && p[2] == 0x0000 && p[3] == 0xc0ae && p[4] == 0xfffc) { + // Don't replace SCSI Manager (8.1, 8.5, 8.6) + p[5] = (p[5] & 0xff) | 0x6000; // beq + D(bug(" patch 1 applied\n")); + break; + } + p++; + } + + } else if (type == FOURCC('t','h','n','g')) { + // Collect info about used audio sifters + uint32 c_type = 0[(uint32 *)p]; + uint32 sub_type = 1[(uint32 *)p]; + if (c_type == FOURCC('s','d','e','v') && sub_type == FOURCC('s','i','n','g')) { + 1[(uint32 *)p] = FOURCC('a','w','g','c'); + D(bug("thng %d, type %c%c%c%c (%08x), sub type %c%c%c%c (%08x), data %p\n", id, c_type >> 24, (c_type >> 16) & 0xff, (c_type >> 8) & 0xff, c_type & 0xff, c_type, sub_type >> 24, (sub_type >> 16) & 0xff, (sub_type >> 8) & 0xff, sub_type & 0xff, sub_type, p)); + AddSifter(*(uint32 *)(((uint32)p)+20), p[12]); + if (p[28]) // componentPFCount + AddSifter(*(uint32 *)(((uint32)p)+62), p[33]); + } + + } else if (type == FOURCC('s','i','f','t') || type == FOURCC('n','i','f','t')) { + // Patch audio sifters + if (FindSifter(type, id)) { + D(bug("sifter found\n")); + p[0] = 0x4e56; p[1] = 0x0000; // link a6,#0 + p[2] = 0x48e7; p[3] = 0x8018; // movem.l d0/a3-a4,-(a7) + p[4] = 0x266e; p[5] = 0x000c; // movea.l $c(a6),a3 + p[6] = 0x286e; p[7] = 0x0008; // movea.l $8(a6),a4 + p[8] = M68K_EMUL_OP_AUDIO_DISPATCH; + p[9] = 0x2d40; p[10] = 0x0010; // move.l d0,$10(a6) + p[11] = 0x4cdf; p[12] = 0x1801; // movem.l (a7)+,d0/a3-a4 + p[13] = 0x4e5e; // unlk a6 + p[14] = 0x4e74; p[15] = 0x0008; // rtd #8 + D(bug(" patch applied\n")); + } + + } else if (type == FOURCC('D','R','V','R') && (id == -16501 || id == -16500)) { + D(bug("DRVR -16501/-16500 found\n")); + // Install sound input driver + memcpy(p, sound_input_driver, sizeof(sound_input_driver)); + D(bug(" patch 1 applied\n")); + + } else if (type == FOURCC('I','N','I','T') && id == 1 && size == (2416 >> 1)) { + D(bug("INIT 1 (size 2416) found\n")); + size >>= 1; + while (size--) { + if (p[0] == 0x247c && p[1] == 0xf301 && p[2] == 0x9000) { + // Prevent "MacOS Licensing Extension" from accessing hardware (7.6) + p[22] = 0x6028; + D(bug(" patch 1 applied\n")); + break; + } + p++; + } + } +} + + +/* + * Native Resource Manager patches + */ + +#ifdef __BEOS__ +static +#endif +void check_load_invoc(uint32 type, int16 id, uint16 **h) +{ + if (h == NULL) + return; + uint16 *p = *h; + if (p == NULL) + return; + uint32 size = ((uint32 *)p)[-2] & 0xffffff; + + CheckLoad(type, id, p, size); +} + +#ifdef __BEOS__ +static asm void **get_resource(register uint32 type, register int16 id) +{ + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/ID + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_RESOURCE + lwz r2,XLM_RES_LIB_TOC + mtctr r0 + bctrl + lwz r2,XLM_TOC // Get TOC + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr +} + +static asm void **get_1_resource(register uint32 type, register int16 id) +{ + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/ID + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_1_RESOURCE + lwz r2,XLM_RES_LIB_TOC + mtctr r0 + bctrl + lwz r2,XLM_TOC // Get TOC + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr +} + +static asm void **get_ind_resource(register uint32 type, register int16 index) +{ + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/index + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_IND_RESOURCE + lwz r2,XLM_RES_LIB_TOC + mtctr r0 + bctrl + lwz r2,XLM_TOC // Get TOC + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr +} + +static asm void **get_1_ind_resource(register uint32 type, register int16 index) +{ + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/index + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_GET_1_IND_RESOURCE + lwz r2,XLM_RES_LIB_TOC + mtctr r0 + bctrl + lwz r2,XLM_TOC // Get TOC + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr +} + +static asm void **r_get_resource(register uint32 type, register int16 id) +{ + // Create stack frame + mflr r0 + stw r0,8(r1) + stwu r1,-(56+12)(r1) + + // Save type/ID + stw r3,56(r1) + stw r4,56+4(r1) + + // Call old routine + lwz r0,XLM_R_GET_RESOURCE + lwz r2,XLM_RES_LIB_TOC + mtctr r0 + bctrl + lwz r2,XLM_TOC // Get TOC + stw r3,56+8(r1) // Save handle + + // Call CheckLoad + lwz r3,56(r1) + lwz r4,56+4(r1) + lwz r5,56+8(r1) + bl check_load_invoc + lwz r3,56+8(r1) // Restore handle + + // Return to caller + lwz r0,56+12+8(r1) + mtlr r0 + addi r1,r1,56+12 + blr +} +#else +// Routines in asm_linux.S +extern "C" void get_resource(void); +extern "C" void get_1_resource(void); +extern "C" void get_ind_resource(void); +extern "C" void get_1_ind_resource(void); +extern "C" void r_get_resource(void); +#endif + +void PatchNativeResourceManager(void) +{ + D(bug("PatchNativeResourceManager\n")); + + // Patch native GetResource() + uint32 **upp = *(uint32 ***)0x1480; + if (((uint32)upp & 0xffc00000) == ROM_BASE) + return; + uint32 *tvec = upp[5]; + D(bug(" GetResource() entry %08x, TOC %08x\n", tvec[0], tvec[1])); + *(uint32 *)XLM_RES_LIB_TOC = tvec[1]; + *(uint32 *)XLM_GET_RESOURCE = tvec[0]; +#ifdef __BEOS__ + uint32 *tvec2 = (uint32 *)get_resource; + tvec[0] = tvec2[0]; + tvec[1] = tvec2[1]; +#else + tvec[0] = (uint32)get_resource; +#endif + + // Patch native Get1Resource() + upp = *(uint32 ***)0xe7c; + tvec = upp[5]; + D(bug(" Get1Resource() entry %08x, TOC %08x\n", tvec[0], tvec[1])); + *(uint32 *)XLM_GET_1_RESOURCE = tvec[0]; +#ifdef __BEOS__ + tvec2 = (uint32 *)get_1_resource; + tvec[0] = tvec2[0]; + tvec[1] = tvec2[1]; +#else + tvec[0] = (uint32)get_1_resource; +#endif + + // Patch native GetIndResource() + upp = *(uint32 ***)0x1474; + tvec = upp[5]; + D(bug(" GetIndResource() entry %08x, TOC %08x\n", tvec[0], tvec[1])); + *(uint32 *)XLM_GET_IND_RESOURCE = tvec[0]; +#ifdef __BEOS__ + tvec2 = (uint32 *)get_ind_resource; + tvec[0] = tvec2[0]; + tvec[1] = tvec2[1]; +#else + tvec[0] = (uint32)get_ind_resource; +#endif + + // Patch native Get1IndResource() + upp = *(uint32 ***)0xe38; + tvec = upp[5]; + D(bug(" Get1IndResource() entry %08x, TOC %08x\n", tvec[0], tvec[1])); + *(uint32 *)XLM_GET_1_IND_RESOURCE = tvec[0]; +#ifdef __BEOS__ + tvec2 = (uint32 *)get_1_ind_resource; + tvec[0] = tvec2[0]; + tvec[1] = tvec2[1]; +#else + tvec[0] = (uint32)get_1_ind_resource; +#endif + + // Patch native RGetResource() + upp = *(uint32 ***)0xe30; + tvec = upp[5]; + D(bug(" RGetResource() entry %08x, TOC %08x\n", tvec[0], tvec[1])); + *(uint32 *)XLM_R_GET_RESOURCE = tvec[0]; +#ifdef __BEOS__ + tvec2 = (uint32 *)r_get_resource; + tvec[0] = tvec2[0]; + tvec[1] = tvec2[1]; +#else + tvec[0] = (uint32)r_get_resource; +#endif +} diff --git a/SheepShaver/src/serial.cpp b/SheepShaver/src/serial.cpp new file mode 100644 index 00000000..85c9b24b --- /dev/null +++ b/SheepShaver/src/serial.cpp @@ -0,0 +1,308 @@ +/* + * serial.cpp - Serial device driver + * + * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "sysdeps.h" +#include "main.h" +#include "macos_util.h" +#include "serial.h" +#include "serial_defs.h" + +#define DEBUG 0 +#include "debug.h" + + +// Global variables +SERDPort *the_serd_port[2]; + +// Function pointers from imported functions +typedef int16 (*iocommandiscomplete_ptr)(uint32, int16); +static iocommandiscomplete_ptr IOCommandIsComplete; + + +/* + * Empty function (AIn/BIn Open/Close) + */ + +int16 SerialNothing(uint32 pb, uint32 dce) +{ + return noErr; +} + + +/* + * Driver Open() routine (output side only) + */ + +int16 SerialOpen(uint32 pb, uint32 dce) +{ + D(bug("SerialOpen pb %08lx, dce %08lx\n", pb, dce)); + + // Get IOCommandIsComplete function + IOCommandIsComplete = (iocommandiscomplete_ptr)FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete"); + D(bug("IOCommandIsComplete TVECT at %08lx\n", (uint32)IOCommandIsComplete)); + if (IOCommandIsComplete == NULL) { + printf("FATAL: SerialOpen(): Can't find IOCommandIsComplete()\n"); + return openErr; + } + + // Do nothing if port is already open + SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1]; + if (the_port->is_open) + return noErr; + + // Init variables + the_port->read_pending = the_port->write_pending = false; + the_port->read_done = the_port->write_done = false; + the_port->cum_errors = 0; + + // Open port + int16 res = the_port->open(ReadMacInt16(0x1fc + ((-(int16)ReadMacInt16(dce + dCtlRefNum)-6) & 2))); + if (res) + return res; + + // Allocate Deferred Task structures + uint32 input_dt = the_port->input_dt = (uint32)the_port->dt_store; + uint32 output_dt = the_port->output_dt = (uint32)the_port->dt_store + SIZEOF_serdt; + D(bug(" input_dt %08lx, output_dt %08lx\n", input_dt, output_dt)); + + WriteMacInt16(input_dt + qType, dtQType); + WriteMacInt32(input_dt + dtAddr, input_dt + serdtCode); + WriteMacInt32(input_dt + dtParam, input_dt + serdtResult); + // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1) + WriteMacInt16(input_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result) + WriteMacInt16(input_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce) + WriteMacInt32(input_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0 + WriteMacInt16(input_dt + serdtCode + 8, 0x4ed0); // jmp (a0) + + WriteMacInt16(output_dt + qType, dtQType); + WriteMacInt32(output_dt + dtAddr, output_dt + serdtCode); + WriteMacInt32(output_dt + dtParam, output_dt + serdtResult); + // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1) + WriteMacInt16(output_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result) + WriteMacInt16(output_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce) + WriteMacInt32(output_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0 + WriteMacInt16(output_dt + serdtCode + 8, 0x4ed0); // jmp (a0) + + the_port->is_open = true; + return noErr; +} + + +/* + * Driver Prime() routines + */ + +int16 SerialPrimeIn(uint32 pb, uint32 dce) +{ + D(bug("SerialPrimeIn pb %08lx, dce %08lx\n", pb, dce)); + int16 res; + + SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1]; + if (!the_port->is_open) + res = notOpenErr; + else { + if (the_port->read_pending) { + printf("FATAL: SerialPrimeIn() called while request is pending\n"); + res = readErr; + } else + res = the_port->prime_in(pb, dce); + } + + if (ReadMacInt16(pb + ioTrap) & 0x0200) + if (res > 0) { + WriteMacInt16(pb + ioResult, 0); + return 0; // Command in progress + } else { + WriteMacInt16(pb + ioResult, res); + return res; + } + else + if (res > 0) + return 0; // Command in progress + else { + IOCommandIsComplete(pb, res); + return res; + } +} + +int16 SerialPrimeOut(uint32 pb, uint32 dce) +{ + D(bug("SerialPrimeOut pb %08lx, dce %08lx\n", pb, dce)); + int16 res; + + SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1]; + if (!the_port->is_open) + res = notOpenErr; + else { + if (the_port->write_pending) { + printf("FATAL: SerialPrimeOut() called while request is pending\n"); + res = writErr; + } else + res = the_port->prime_out(pb, dce); + } + + if (ReadMacInt16(pb + ioTrap) & 0x0200) + if (res > 0) { + WriteMacInt16(pb + ioResult, 0); + return 0; // Command in progress + } else { + WriteMacInt16(pb + ioResult, res); + return res; + } + else + if (res > 0) + return 0; // Command in progress + else { + IOCommandIsComplete(pb, res); + return res; + } +} + + +/* + * Driver Control() routine + */ + +int16 SerialControl(uint32 pb, uint32 dce) +{ + uint16 code = ReadMacInt16(pb + csCode); + D(bug("SerialControl %d, pb %08lx, dce %08lx\n", code, pb, dce)); + int16 res; + + SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1]; + if (!the_port->is_open) + res = notOpenErr; + else { + switch (code) { + case kSERDSetPollWrite: + res = noErr; + break; + default: + res = the_port->control(pb, dce, code); + break; + } + } + + if (code == 1) + return res; + else if (ReadMacInt16(pb + ioTrap) & 0x0200) { + WriteMacInt16(pb + ioResult, res); + return res; + } else { + IOCommandIsComplete(pb, res); + return res; + } +} + + +/* + * Driver Status() routine + */ + +int16 SerialStatus(uint32 pb, uint32 dce) +{ + uint16 code = ReadMacInt16(pb + csCode); + D(bug("SerialStatus %d, pb %08lx, dce %08lx\n", code, pb, dce)); + int16 res; + + SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1]; + if (!the_port->is_open) + res = notOpenErr; + else { + switch (code) { + case kSERDVersion: + WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver + res = noErr; + break; + + case 0x8000: + WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver + WriteMacInt16(pb + csParam + 4, 0x1997); // Date of serial driver + WriteMacInt16(pb + csParam + 6, 0x0616); + res = noErr; + break; + + default: + res = the_port->status(pb, dce, code); + break; + } + } + + if (ReadMacInt16(pb + ioTrap) & 0x0200) { + WriteMacInt16(pb + ioResult, res); + return res; + } else { + IOCommandIsComplete(pb, res); + return res; + } +} + + +/* + * Driver Close() routine + */ + +int16 SerialClose(uint32 pb, uint32 dce) +{ + D(bug("SerialClose pb %08lx, dce %08lx\n", pb, dce)); + + // Close port if open + SERDPort *the_port = the_serd_port[(-(int16)ReadMacInt16(dce + dCtlRefNum)-6) >> 1]; + if (the_port->is_open) { + int16 res = the_port->close(); + the_port->is_open = false; + return res; + } else + return noErr; +} + + +/* + * Serial interrupt - Prime command completed, activate deferred tasks to call IODone + */ + +void SerialInterrupt(void) +{ + D(bug("SerialIRQ\n")); + + // Port 0 + if (the_serd_port[0]->is_open) { + if (the_serd_port[0]->read_pending && the_serd_port[0]->read_done) { + Enqueue(the_serd_port[0]->input_dt, 0xd92); + the_serd_port[0]->read_pending = the_serd_port[0]->read_done = false; + } + if (the_serd_port[0]->write_pending && the_serd_port[0]->write_done) { + Enqueue(the_serd_port[0]->output_dt, 0xd92); + the_serd_port[0]->write_pending = the_serd_port[0]->write_done = false; + } + } + + // Port 1 + if (the_serd_port[1]->is_open) { + if (the_serd_port[1]->read_pending && the_serd_port[1]->read_done) { + Enqueue(the_serd_port[1]->input_dt, 0xd92); + the_serd_port[1]->read_pending = the_serd_port[1]->read_done = false; + } + if (the_serd_port[1]->write_pending && the_serd_port[1]->write_done) { + Enqueue(the_serd_port[1]->output_dt, 0xd92); + the_serd_port[1]->write_pending = the_serd_port[1]->write_done = false; + } + } +} diff --git a/SheepShaver/src/timer.cpp b/SheepShaver/src/timer.cpp new file mode 100644 index 00000000..d9d041d7 --- /dev/null +++ b/SheepShaver/src/timer.cpp @@ -0,0 +1,432 @@ +/* + * timer.cpp - Time Manager emulation + * + * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * + * 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 + */ + +/* + * TODO: Prime(0) + */ + +#include "sysdeps.h" +#include "timer.h" +#include "macos_util.h" +#include "main.h" +#include "cpu_emulation.h" + +#define DEBUG 0 +#include "debug.h" + + +#if __BEOS__ +#define PRECISE_TIMING 1 +#else +#define PRECISE_TIMING 0 +#endif + +#define TM_QUEUE 0 // Enable TMQueue management (doesn't work) + + +// Definitions for Time Manager +enum { // TMTask struct + tmAddr = 6, + tmCount = 10, + tmWakeUp = 14, + tmReserved = 18 +}; + + +// Array of additional info for each installed TMTask +struct TMDesc { + uint32 task; // Mac address of associated TMTask + tm_time_t wakeup; // Time this task is scheduled for execution + bool in_use; // Flag: descriptor in use +}; + +const int NUM_DESCS = 64; // Maximum number of descriptors +static TMDesc desc[NUM_DESCS]; + +#if PRECISE_TIMING +static thread_id timer_thread = -1; +static bool thread_active = true; +static volatile tm_time_t wakeup_time = 0x7fffffffffffffff; +static sem_id wakeup_time_sem = -1; +static int32 timer_func(void *arg); +#endif + + +/* + * Allocate descriptor for given TMTask in list + */ + +static int alloc_desc(uint32 tm) +{ + // Search for first free descriptor + for (int i=0; i 0) { + status_t l; + thread_active = false; + suspend_thread(timer_thread); + resume_thread(timer_thread); + wait_for_thread(timer_thread, &l); + delete_sem(wakeup_time_sem); + } +#endif +} + + +/* + * Emulator reset, remove all timer tasks + */ + +void TimerReset(void) +{ + // Mark all descriptors as inactive + for (int i=0; i= 0) + printf("WARNING: InsTime(): Task re-inserted\n"); + else { + int i = alloc_desc(tm); + if (i < 0) + printf("FATAL: InsTime(): No free Time Manager descriptor\n"); + } + return 0; +} + + +/* + * Remove timer task + */ + +int16 RmvTime(uint32 tm) +{ + D(bug("RmvTime %08lx\n", tm)); + + // Find descriptor + int i = find_desc(tm); + if (i < 0) { + printf("WARNING: RmvTime(%08lx): Descriptor not found\n", tm); + return 0; + } + + // Task active? +#if PRECISE_TIMING + while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ; + suspend_thread(timer_thread); +#endif + if (ReadMacInt16(tm + qType) & 0x8000) { + + // Yes, make task inactive and remove it from the Time Manager queue + WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); + dequeue_tm(tm); +#if PRECISE_TIMING + // Look for next task to be called and set wakeup_time + wakeup_time = 0x7fffffffffffffff; + for (int j=0; j +#include + +#include "sysdeps.h" +#include "video.h" +#include "video_defs.h" +#include "main.h" +#include "adb.h" +#include "macos_util.h" +#include "user_strings.h" +#include "version.h" + +#define DEBUG 0 +#include "debug.h" + + +// Global variables +bool video_activated = false; // Flag: video display activated, mouse and keyboard data valid +uint32 screen_base = 0; // Frame buffer base address +int cur_mode; // Number of current video mode (index in VModes array) +int display_type = DIS_INVALID; // Current display type +rgb_color mac_pal[256]; +uint8 remap_mac_be[256]; +uint8 MacCursor[68] = {16, 1}; // Mac cursor image + + +bool keyfile_valid; // Flag: Keyfile is valid, enable full-screen modes + + +/* + * Video mode information (constructed by VideoInit()) + */ + +struct VideoInfo VModes[64]; + + +/* + * Driver local variables + */ + +VidLocals *private_data = NULL; // Pointer to driver local variables (there is only one display, so this is ok) + +static long save_conf_id = APPLE_W_640x480; +static long save_conf_mode = APPLE_8_BIT; + + +// Function pointers of imported functions +typedef int16 (*iocic_ptr)(void *, int16); +static uint32 iocic_tvect = 0; +static inline int16 IOCommandIsComplete(void *arg1, int16 arg2) +{ + return (int16)CallMacOS2(iocic_ptr, iocic_tvect, arg1, arg2); +} +typedef int16 (*vslnewis_ptr)(void *, uint32, uint32 *); +static uint32 vslnewis_tvect = 0; +static inline int16 VSLNewInterruptService(void *arg1, uint32 arg2, uint32 *arg3) +{ + return (int16)CallMacOS3(vslnewis_ptr, vslnewis_tvect, arg1, arg2, arg3); +} +typedef int16 (*vsldisposeis_ptr)(uint32); +static uint32 vsldisposeis_tvect = 0; +static inline int16 VSLDisposeInterruptService(uint32 arg1) +{ + return (int16)CallMacOS1(vsldisposeis_ptr, vsldisposeis_tvect, arg1); +} +typedef int16 (*vsldois_ptr)(uint32); +static uint32 vsldois_tvect = 0; +int16 VSLDoInterruptService(uint32 arg1) +{ + return (int16)CallMacOS1(vsldois_ptr, vsldois_tvect, arg1); +} +typedef void (*nqdmisc_ptr)(uint32, void *); +static uint32 nqdmisc_tvect = 0; +void NQDMisc(uint32 arg1, void *arg2) +{ + CallMacOS2(nqdmisc_ptr, nqdmisc_tvect, arg1, arg2); +} + + +// Prototypes +static int16 set_gamma(VidLocals *csSave, uint32 gamma); + + +/* + * Tell whether window/screen is activated or not (for mouse/keyboard polling) + */ + +bool VideoActivated(void) +{ + return video_activated; +} + + +/* + * Create RGB snapshot of current screen + */ + +bool VideoSnapshot(int xsize, int ysize, uint8 *p) +{ + if (display_type == DIS_WINDOW) { + uint8 *screen = (uint8 *)private_data->saveBaseAddr; + uint32 row_bytes = VModes[cur_mode].viRowBytes; + uint32 y2size = VModes[cur_mode].viYsize; + uint32 x2size = VModes[cur_mode].viXsize; + for (int j=0;jsaveBaseAddr = screen_base; + csSave->saveData = VModes[cur_mode].viAppleID;// First mode ... + csSave->saveMode = VModes[cur_mode].viAppleMode; + csSave->savePage = 0; + csSave->saveVidParms = 0; // Add the right table + csSave->gammaTable = NULL; // No gamma table yet + csSave->maxGammaTableSize = 0; + csSave->luminanceMapping = false; + csSave->cursorX = 0; + csSave->cursorY = 0; + csSave->cursorVisible = 0; + csSave->cursorSet = 0; + + // Activate default gamma table + set_gamma(csSave, 0); + + // Install and activate interrupt service + csSave->vslServiceID = 0; + VSLNewInterruptService(csSave->regEntryID, FOURCC('v','b','l',' '), &(csSave->vslServiceID)); + D(bug(" Interrupt ServiceID %08lx\n", csSave->vslServiceID)); + csSave->interruptsEnabled = true; + + return noErr; +} + + +/* + * Video driver control routine + */ + +static int16 set_gamma(VidLocals *csSave, uint32 gamma) +{ + GammaTbl *clientGamma = (GammaTbl *)gamma; + GammaTbl *gammaTable = csSave->gammaTable; + + if (clientGamma == NULL) { + + // No gamma table supplied, build linear ramp + uint32 linearRampSize = sizeof(GammaTbl) + 256 - 2; + uint8 *correctionData; + + // Allocate new gamma table if existing gamma table is smaller than required. + if (linearRampSize > csSave->maxGammaTableSize) { + delete[] csSave->gammaTable; + csSave->gammaTable = (GammaTbl *)new uint8[linearRampSize]; + csSave->maxGammaTableSize = linearRampSize; + gammaTable = csSave->gammaTable; + } + + gammaTable->gVersion = 0; // A version 0 style of the GammaTbl structure + gammaTable->gType = 0; // Frame buffer hardware invariant + gammaTable->gFormulaSize = 0; // No formula data, just correction data + gammaTable->gChanCnt = 1; // Apply same correction to Red, Green, & Blue + gammaTable->gDataCnt = 256; // gDataCnt == 2^^gDataWidth + gammaTable->gDataWidth = 8; // 8 bits of significant data per entry + + // Find the starting address of the correction data. This can be computed by starting at + // the address of gFormula[0] and adding the gFormulaSize. + correctionData = (uint8 *)((uint32)&gammaTable->gFormulaData[0] + gammaTable->gFormulaSize); + + // Build the linear ramp + for (int i=0; igDataCnt; i++) + *correctionData++ = i; + + } else { + + // User supplied a gamma table, so make sure it is a valid one + if (clientGamma->gVersion != 0) + return paramErr; + if (clientGamma->gType != 0) + return paramErr; + if ((clientGamma->gChanCnt != 1) && (clientGamma->gChanCnt != 3)) + return paramErr; + if (clientGamma->gDataWidth > 8) + return paramErr; + if (clientGamma->gDataCnt != (1 << clientGamma->gDataWidth)) + return paramErr; + + uint32 tableSize = sizeof(GammaTbl) // fixed size header + + clientGamma->gFormulaSize // add formula size + + clientGamma->gChanCnt * clientGamma->gDataCnt // assume 1 byte/entry + - 2; // correct gFormulaData[0] counted twice + + // Allocate new gamma table if existing gamma table is smaller than required. + if (tableSize > csSave->maxGammaTableSize) { + delete[] csSave->gammaTable; + csSave->gammaTable = (GammaTbl *)new uint8[tableSize]; + csSave->maxGammaTableSize = tableSize; + gammaTable = csSave->gammaTable; + } + + // Copy gamma table header + *gammaTable = *clientGamma; + + // Copy the formula data (if any) + uint8 *newData = (uint8 *)&gammaTable->gFormulaData[0]; // Point to newGamma's formula data + uint8 *clientData = (uint8 *)&clientGamma->gFormulaData[0]; // Point to clientGamma's formula data + for (int i=0; igFormulaSize; i++) + *newData++ = *clientData++; + + // Copy the correction data. Convientiently, after copying the formula data, the 'newData' + // pointer and the 'clientData' pointer are pointing to the their respective starting points + // of their correction data. + for (int i=0; igChanCnt; i++) + for (int j=0; jgDataCnt; j++) + *newData++ = *clientData++; + } + return noErr; +} + +static int16 VideoControl(uint32 pb, VidLocals *csSave) +{ + int16 code = ReadMacInt16(pb + csCode); + D(bug("VideoControl %d: ", code)); + uint32 param = ReadMacInt32(pb + csParam); + switch (code) { + + case cscReset: // VidReset + D(bug("VidReset\n")); + return controlErr; + + case cscKillIO: // VidKillIO + D(bug("VidKillIO\n")); + return controlErr; + + case cscSetMode: // SetVidMode + D(bug("SetVidMode\n")); + D(bug("mode:%04x page:%04x \n", ReadMacInt16(param + csMode), + ReadMacInt16(param + csPage))); + WriteMacInt32(param + csData, csSave->saveData); + return video_mode_change(csSave, param); + + case cscSetEntries: { // SetEntries + D(bug("SetEntries\n")); + if (VModes[cur_mode].viAppleMode > APPLE_8_BIT) return controlErr; + ColorSpec *s_pal = (ColorSpec *)Mac2HostAddr(ReadMacInt32(param + csTable)); + int16 start = ReadMacInt16(param + csStart); + int16 count = ReadMacInt16(param + csCount); + if (s_pal == NULL || count > 256) return controlErr; + + // Preparations for gamma correction + bool do_gamma = false; + uint8 *red_gamma = NULL; + uint8 *green_gamma = NULL; + uint8 *blue_gamma = NULL; + int gamma_data_width = 0; + if (display_type == DIS_SCREEN && csSave->gammaTable != NULL) { // Windows are gamma-corrected by BeOS + do_gamma = true; + GammaTbl *gamma = csSave->gammaTable; + gamma_data_width = gamma->gDataWidth; + red_gamma = (uint8 *)&gamma->gFormulaData + gamma->gFormulaSize; + if (gamma->gChanCnt == 1) { + green_gamma = blue_gamma = red_gamma; + } else { + green_gamma = red_gamma + gamma->gDataCnt; + blue_gamma = red_gamma + 2 * gamma->gDataCnt; + } + } + + // Set palette + rgb_color *d_pal; + if (start == -1) { // Indexed + for (int i=0; i<=count; i++) { + d_pal = &(mac_pal[(*s_pal).value]); + uint8 red = (*s_pal).red >> 8; + uint8 green = (*s_pal).green >> 8; + uint8 blue = (*s_pal).blue >> 8; + if (csSave->luminanceMapping) + red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; + if (do_gamma) { + red = red_gamma[red >> (8 - gamma_data_width)]; + green = green_gamma[green >> (8 - gamma_data_width)]; + blue = blue_gamma[blue >> (8 - gamma_data_width)]; + } + (*d_pal).red = red; + (*d_pal).green = green; + (*d_pal).blue = blue; + s_pal++; + } + } else { // Sequential + d_pal = &(mac_pal[start]); + for (int i=0; i<=count; i++) { + uint8 red = (*s_pal).red >> 8; + uint8 green = (*s_pal).green >> 8; + uint8 blue = (*s_pal).blue >> 8; + if (csSave->luminanceMapping) + red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; + if (do_gamma) { + red = red_gamma[red >> (8 - gamma_data_width)]; + green = green_gamma[green >> (8 - gamma_data_width)]; + blue = blue_gamma[blue >> (8 - gamma_data_width)]; + } + (*d_pal).red = red; + (*d_pal).green = green; + (*d_pal).blue = blue; + d_pal++; s_pal++; + } + } + video_set_palette(); + return noErr; + } + + case cscSetGamma: // SetGamma + D(bug("SetGamma\n")); + return set_gamma(csSave, ReadMacInt32(param)); + + case cscGrayPage: { // GrayPage + D(bug("GrayPage\n")); + uint32 *screen = (uint32 *)csSave->saveBaseAddr; + uint32 pattern; + uint32 row_bytes = VModes[cur_mode].viRowBytes; + switch (VModes[cur_mode].viAppleMode) { + case APPLE_8_BIT: + pattern=0xff00ff00; + for (int i=0;i>2);j++) + screen[j] = pattern; + pattern = ~pattern; + screen = (uint32 *)((uint32)screen + row_bytes); + } + break; + case APPLE_16_BIT: + pattern=0xffff0000; + for (int i=0;i>1);j++) + screen[j]=pattern; + pattern = ~pattern; + screen = (uint32 *)((uint32)screen + row_bytes); + } + break; + case APPLE_32_BIT: + pattern=0xffffffff; + for (int i=0;iluminanceMapping = ReadMacInt8(param); + return noErr; + + case cscSetInterrupt: // SetInterrupt + D(bug("SetInterrupt\n")); + csSave->interruptsEnabled = !ReadMacInt8(param); + return noErr; + + case cscDirectSetEntries: // DirectSetEntries + D(bug("DirectSetEntries\n")); + return controlErr; + + case cscSetDefaultMode: // SetDefaultMode + D(bug("SetDefaultMode\n")); + return controlErr; + + case cscSwitchMode: + D(bug("cscSwitchMode (Display Manager support) \nMode:%02x ID:%04x Page:%d\n", + ReadMacInt16(param + csMode), ReadMacInt32(param + csData), ReadMacInt16(param + csPage))); + return video_mode_change(csSave, param); + + case cscSavePreferredConfiguration: + D(bug("SavePreferredConfiguration\n")); + save_conf_id = ReadMacInt32(param + csData); + save_conf_mode = ReadMacInt16(param + csMode); + return noErr; + + case cscSetHardwareCursor: { +// D(bug("SetHardwareCursor\n")); + csSave->cursorSet = false; + bool changed = false; + + // Get cursor data even on a screen, to set the right cursor image when switching back to a window + // Image + uint32 cursor = ReadMacInt32(param); // Pointer to CursorImage + uint32 pmhandle = ReadMacInt32(cursor + ciCursorPixMap); + if (pmhandle == 0 || ReadMacInt32(pmhandle) == 0) + return controlErr; + uint32 pixmap = ReadMacInt32(pmhandle); + if (memcmp(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32)) { + memcpy(MacCursor + 4, Mac2HostAddr(ReadMacInt32(pixmap)), 32); + changed = true; + } + + // Mask + uint32 bmhandle = ReadMacInt32(cursor + ciCursorBitMask); + if (bmhandle == 0 || ReadMacInt32(bmhandle) == 0) + return controlErr; + uint32 bitmap = ReadMacInt32(bmhandle); + if (memcmp(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32)) { + memcpy(MacCursor + 4 + 32, Mac2HostAddr(ReadMacInt32(bitmap)), 32); + changed = true; + } + + // Hotspot (!! this doesn't work) + MacCursor[2] = ReadMacInt8(0x885); + MacCursor[3] = ReadMacInt8(0x887); + + // Set new cursor image + if (display_type == DIS_SCREEN) + return controlErr; + if (changed) + video_set_cursor(); + + csSave->cursorSet = true; + return noErr; + } + + case cscDrawHardwareCursor: +// D(bug("DrawHardwareCursor\n")); + csSave->cursorX = ReadMacInt32(param + csCursorX); + csSave->cursorY = ReadMacInt32(param + csCursorY); + csSave->cursorVisible = ReadMacInt32(param + csCursorVisible); + return noErr; + + case 43: { // Driver Gestalt + uint32 sel = ReadMacInt32(pb + csParam); + D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel)); + switch (sel) { + case FOURCC('v','e','r','s'): + WriteMacInt32(pb + csParam + 4, 0x01008000); + break; + case FOURCC('i','n','t','f'): + WriteMacInt32(pb + csParam + 4, FOURCC('c','a','r','d')); + break; + case FOURCC('s','y','n','c'): + WriteMacInt32(pb + csParam + 4, 0x01000000); + break; + default: + return statusErr; + }; + return noErr; + } + + default: + D(bug(" unknown control code %d\n", code)); + return controlErr; + } +} + + +/* + * Video driver status routine + */ + +// Search for given AppleID in mode table +static bool has_mode(uint32 id) +{ + VideoInfo *p = VModes; + while (p->viType != DIS_INVALID) { + if (p->viAppleID == id) + return true; + p++; + } + return false; +} + +// Find maximum depth for given AppleID +static uint32 max_depth(uint32 id) +{ + uint32 max = APPLE_1_BIT; + VideoInfo *p = VModes; + while (p->viType != DIS_INVALID) { + if (p->viAppleID == id && p->viAppleMode > max) + max = p->viAppleMode; + p++; + } + return max; +} + +static int16 VideoStatus(uint32 pb, VidLocals *csSave) +{ + int16 code = ReadMacInt16(pb + csCode); + D(bug("VideoStatus %d: ", code)); + uint32 param = ReadMacInt32(pb + csParam); + switch (code) { + + case cscGetMode: // GetMode + D(bug("GetMode\n")); + WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr); + WriteMacInt16(param + csMode, csSave->saveMode); + WriteMacInt16(param + csPage, csSave->savePage); + D(bug("return: mode:%04x page:%04x ", ReadMacInt16(param + csMode), + ReadMacInt16(param + csPage))); + D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr))); + return noErr; + + case cscGetEntries: { // GetEntries + D(bug("GetEntries\n")); + ColorSpec *d_pal = (ColorSpec *)Mac2HostAddr(ReadMacInt32(param + csTable)); + int16 start = ReadMacInt16(param + csStart); + int16 count = ReadMacInt16(param + csCount); + rgb_color *s_pal; + if ((VModes[cur_mode].viAppleMode == APPLE_32_BIT)|| + (VModes[cur_mode].viAppleMode == APPLE_16_BIT)) { + D(bug("ERROR: GetEntries in direct mode \n")); + return statusErr; + } + if (start >= 0) { // indexed get + s_pal = &(mac_pal[start]); + for (uint16 i=0;isaveBaseAddr); + return noErr; + + case cscGetGray: // GetGray + D(bug("GetGray\n")); + WriteMacInt8(param, csSave->luminanceMapping ? 1 : 0); + return noErr; + + case cscGetInterrupt: // GetInterrupt + D(bug("GetInterrupt\n")); + WriteMacInt8(param, csSave->interruptsEnabled ? 0 : 1); + return noErr; + + case cscGetGamma: // GetGamma + D(bug("GetGamma\n")); + WriteMacInt32(param, (uint32)csSave->gammaTable); + return statusErr; + + case cscGetDefaultMode: // GetDefaultMode + D(bug("GetDefaultMode\n")); + return statusErr; + + case cscGetCurMode: // GetCurMode + D(bug("GetCurMode\n")); + WriteMacInt16(param + csMode, csSave->saveMode); + WriteMacInt32(param + csData, csSave->saveData); + WriteMacInt16(param + csPage, csSave->savePage); + WriteMacInt32(param + csBaseAddr, csSave->saveBaseAddr); + + D(bug("return: mode:%04x ID:%08lx page:%04x ", ReadMacInt16(param + csMode), + ReadMacInt32(param + csData), ReadMacInt16(param + csPage))); + D(bug("base adress %08lx\n", ReadMacInt32(param + csBaseAddr))); + return noErr; + + case cscGetConnection: // GetConnection + D(bug("GetConnection\n")); + WriteMacInt16(param + csDisplayType, kMultiModeCRT3Connect); + WriteMacInt8(param + csConnectTaggedType, 6); + WriteMacInt8(param + csConnectTaggedData, 0x23); + WriteMacInt32(param + csConnectFlags, (1<saveData; + break; + case kDisplayModeIDFindFirstResolution: + work_id = APPLE_ID_MIN; + while (!has_mode(work_id)) + work_id ++; + break; + default: + if (!has_mode(work_id)) + return paramErr; + work_id++; + while (!has_mode(work_id)) { + work_id++; + if (work_id > APPLE_ID_MAX) { + WriteMacInt32(param + csRIDisplayModeID, kDisplayModeIDNoMoreResolutions); + return noErr; + } + } + break; + } + WriteMacInt32(param + csRIDisplayModeID, work_id); + WriteMacInt16(param + csMaxDepthMode, max_depth(work_id)); + switch (work_id) { + case APPLE_640x480: + WriteMacInt32(param + csHorizontalPixels, 640); + WriteMacInt32(param + csVerticalLines, 480); + WriteMacInt32(param + csRefreshRate, 75<<16); + break; + case APPLE_W_640x480: + WriteMacInt32(param + csHorizontalPixels, 640); + WriteMacInt32(param + csVerticalLines, 480); + WriteMacInt32(param + csRefreshRate, 60<<16); + break; + case APPLE_800x600: + WriteMacInt32(param + csHorizontalPixels, 800); + WriteMacInt32(param + csVerticalLines, 600); + WriteMacInt32(param + csRefreshRate, 75<<16); + break; + case APPLE_W_800x600: + WriteMacInt32(param + csHorizontalPixels, 800); + WriteMacInt32(param + csVerticalLines, 600); + WriteMacInt32(param + csRefreshRate, 60<<16); + break; + case APPLE_1024x768: + WriteMacInt32(param + csHorizontalPixels, 1024); + WriteMacInt32(param + csVerticalLines, 768); + WriteMacInt32(param + csRefreshRate, 75<<16); + break; + case APPLE_1152x900: + WriteMacInt32(param + csHorizontalPixels, 1152); + WriteMacInt32(param + csVerticalLines, 900); + WriteMacInt32(param + csRefreshRate, 75<<16); + break; + case APPLE_1280x1024: + WriteMacInt32(param + csHorizontalPixels, 1280); + WriteMacInt32(param + csVerticalLines, 1024); + WriteMacInt32(param + csRefreshRate, 75<<16); + break; + case APPLE_1600x1200: + WriteMacInt32(param + csHorizontalPixels, 1600); + WriteMacInt32(param + csVerticalLines, 1200); + WriteMacInt32(param + csRefreshRate, 75<<16); + break; + } + return noErr; + } + + case cscGetVideoParameters: // GetVideoParameters + D(bug("GetVideoParameters ID:%08lx Depth:%04x\n", + ReadMacInt32(param + csDisplayModeID), + ReadMacInt16(param + csDepthMode))); + + // find right video mode + for (int i=0; VModes[i].viType!=DIS_INVALID; i++) { + if ((ReadMacInt16(param + csDepthMode) == VModes[i].viAppleMode) && + (ReadMacInt32(param + csDisplayModeID) == VModes[i].viAppleID)) { + uint32 vpb = ReadMacInt32(param + csVPBlockPtr); + WriteMacInt32(vpb + vpBaseOffset, 0); + WriteMacInt16(vpb + vpRowBytes, VModes[i].viRowBytes); + WriteMacInt16(vpb + vpBounds, 0); + WriteMacInt16(vpb + vpBounds + 2, 0); + WriteMacInt16(vpb + vpBounds + 4, VModes[i].viYsize); + WriteMacInt16(vpb + vpBounds + 6, VModes[i].viXsize); + WriteMacInt16(vpb + vpVersion, 0); // Pixel Map version number + WriteMacInt16(vpb + vpPackType, 0); + WriteMacInt32(vpb + vpPackSize, 0); + WriteMacInt32(vpb + vpHRes, 0x00480000); // horiz res of the device (ppi) + WriteMacInt32(vpb + vpVRes, 0x00480000); // vert res of the device (ppi) + switch (VModes[i].viAppleMode) { + case APPLE_1_BIT: + WriteMacInt16(vpb + vpPixelType, 0); + WriteMacInt16(vpb + vpPixelSize, 1); + WriteMacInt16(vpb + vpCmpCount, 1); + WriteMacInt16(vpb + vpCmpSize, 1); + WriteMacInt32(param + csDeviceType, 0); // CLUT + break; + case APPLE_2_BIT: + WriteMacInt16(vpb + vpPixelType, 0); + WriteMacInt16(vpb + vpPixelSize, 2); + WriteMacInt16(vpb + vpCmpCount, 1); + WriteMacInt16(vpb + vpCmpSize, 2); + WriteMacInt32(param + csDeviceType, 0); // CLUT + break; + case APPLE_4_BIT: + WriteMacInt16(vpb + vpPixelType, 0); + WriteMacInt16(vpb + vpPixelSize, 4); + WriteMacInt16(vpb + vpCmpCount, 1); + WriteMacInt16(vpb + vpCmpSize, 4); + WriteMacInt32(param + csDeviceType, 0); // CLUT + break; + case APPLE_8_BIT: + WriteMacInt16(vpb + vpPixelType, 0); + WriteMacInt16(vpb + vpPixelSize, 8); + WriteMacInt16(vpb + vpCmpCount, 1); + WriteMacInt16(vpb + vpCmpSize, 8); + WriteMacInt32(param + csDeviceType, 0); // CLUT + break; + case APPLE_16_BIT: + WriteMacInt16(vpb + vpPixelType, 0x10); + WriteMacInt16(vpb + vpPixelSize, 16); + WriteMacInt16(vpb + vpCmpCount, 3); + WriteMacInt16(vpb + vpCmpSize, 5); + WriteMacInt32(param + csDeviceType, 2); // DIRECT + break; + case APPLE_32_BIT: + WriteMacInt16(vpb + vpPixelType, 0x10); + WriteMacInt16(vpb + vpPixelSize, 32); + WriteMacInt16(vpb + vpCmpCount, 3); + WriteMacInt16(vpb + vpCmpSize, 8); + WriteMacInt32(param + csDeviceType, 2); // DIRECT + break; + } + WriteMacInt32(param + csPageCount, 1); + return noErr; + } + } + return paramErr; + + case cscGetModeTiming: + D(bug("GetModeTiming mode %08lx\n", ReadMacInt32(param + csTimingMode))); + WriteMacInt32(param + csTimingFormat, kDeclROMtables); + WriteMacInt32(param + csTimingFlags, (1<cursorX); + WriteMacInt32(param + csCursorY, csSave->cursorY); + WriteMacInt32(param + csCursorVisible, csSave->cursorVisible); + WriteMacInt32(param + csCursorSet, csSave->cursorSet); + return noErr; + + default: + D(bug(" unknown status code %d\n", code)); + return statusErr; + } +} + + +/* + * Video driver close routine + */ + +static int16 VideoClose(uint32 pb, VidLocals *csSave) +{ + D(bug("VideoClose\n")); + + // Delete interrupt service + csSave->interruptsEnabled = false; + VSLDisposeInterruptService(csSave->vslServiceID); + + return noErr; +} + + +/* + * Native (PCI) driver entry + */ + +int16 VideoDoDriverIO(void *spaceID, void *commandID, void *commandContents, uint32 commandCode, uint32 commandKind) +{ +// D(bug("VideoDoDriverIO space %p, command %p, contents %p, code %d, kind %d\n", spaceID, commandID, commandContents, commandCode, commandKind)); + int16 err = noErr; + + switch (commandCode) { + case kInitializeCommand: + case kReplaceCommand: + if (private_data != NULL) // Might be left over from a reboot + delete private_data->gammaTable; + delete private_data; + + iocic_tvect = (uint32)FindLibSymbol("\021DriverServicesLib", "\023IOCommandIsComplete"); + D(bug("IOCommandIsComplete TVECT at %08lx\n", iocic_tvect)); + if (iocic_tvect == 0) { + printf("FATAL: VideoDoDriverIO(): Can't find IOCommandIsComplete()\n"); + err = -1; + break; + } + vslnewis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\026VSLNewInterruptService"); + D(bug("VSLNewInterruptService TVECT at %08lx\n", vslnewis_tvect)); + if (vslnewis_tvect == 0) { + printf("FATAL: VideoDoDriverIO(): Can't find VSLNewInterruptService()\n"); + err = -1; + break; + } + vsldisposeis_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\032VSLDisposeInterruptService"); + D(bug("VSLDisposeInterruptService TVECT at %08lx\n", vsldisposeis_tvect)); + if (vsldisposeis_tvect == 0) { + printf("FATAL: VideoDoDriverIO(): Can't find VSLDisposeInterruptService()\n"); + err = -1; + break; + } + vsldois_tvect = (uint32)FindLibSymbol("\020VideoServicesLib", "\025VSLDoInterruptService"); + D(bug("VSLDoInterruptService TVECT at %08lx\n", vsldois_tvect)); + if (vsldois_tvect == 0) { + printf("FATAL: VideoDoDriverIO(): Can't find VSLDoInterruptService()\n"); + err = -1; + break; + } + nqdmisc_tvect = (uint32)FindLibSymbol("\014InterfaceLib", "\007NQDMisc"); + D(bug("NQDMisc TVECT at %08lx\n", nqdmisc_tvect)); + if (nqdmisc_tvect == 0) { + printf("FATAL: VideoDoDriverIO(): Can't find NQDMisc()\n"); + err = -1; + break; + } + + private_data = new VidLocals; + private_data->gammaTable = NULL; + memcpy(private_data->regEntryID, (uint8 *)commandContents + 2, 16); // DriverInitInfo.deviceEntry + private_data->interruptsEnabled = false; // Disable interrupts + break; + + case kFinalizeCommand: + case kSupersededCommand: + if (private_data != NULL) + delete private_data->gammaTable; + delete private_data; + private_data = NULL; + break; + + case kOpenCommand: + err = VideoOpen((uint32)commandContents, private_data); + break; + + case kCloseCommand: + err = VideoClose((uint32)commandContents, private_data); + break; + + case kControlCommand: + err = VideoControl((uint32)commandContents, private_data); + break; + + case kStatusCommand: + err = VideoStatus((uint32)commandContents, private_data); + break; + + case kReadCommand: + case kWriteCommand: + break; + + case kKillIOCommand: + err = abortErr; + break; + + default: + err = paramErr; + break; + } + + if (commandKind == kImmediateIOCommandKind) + return err; + else + return IOCommandIsComplete(commandID, err); +}