From 29076d4cefbd55d06cd6b82b22f069766bcc19a2 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Sat, 23 Jun 2012 14:16:37 +0200 Subject: [PATCH] gnuboy: initial 1.0.3 import (last official release) --- COPYING | 339 +++ INSTALL | 81 + Makefile.dos | 29 + Makefile.in | 70 + Makefile.nix | 64 + Makefile.win | 31 + README | 199 ++ Rules | 31 + Version | 5 + asm/i386/asm.h | 35 + asm/i386/asmnames.h | 41 + asm/i386/cpu.s | 2430 ++++++++++++++++++++ asm/i386/lcd.s | 290 +++ asm/i386/refresh.s | 285 +++ configure | 4095 ++++++++++++++++++++++++++++++++++ configure.in | 259 +++ cpu.c | 878 ++++++++ cpu.h | 36 + cpucore.h | 290 +++ cpuregs.h | 56 + debug.c | 689 ++++++ defs.h | 36 + docs/CHANGES | 322 +++ docs/CONFIG | 645 ++++++ docs/CREDITS | 65 + docs/FAQ | 90 + docs/HACKING | 472 ++++ docs/LIBERTY | 6 + docs/README.old | 355 +++ docs/WHATSNEW | 386 ++++ emu.c | 110 + etc/classic.rc | 41 + etc/filters.rc | 43 + etc/laguna.pgp | 30 + etc/palettes.rc | 97 + etc/sample.rc | 49 + events.c | 60 + exports.c | 43 + fastmem.c | 54 + fastmem.h | 99 + fb.h | 35 + hw.c | 182 ++ hw.h | 40 + inflate.c | 512 +++++ input.h | 140 ++ install-sh | 238 ++ keytable.c | 156 ++ lcd.c | 868 +++++++ lcd.h | 57 + lcdc.c | 179 ++ loader.c | 395 ++++ loader.h | 28 + main.c | 323 +++ mem.c | 576 +++++ mem.h | 79 + newsound.c | 57 + noise.h | 532 +++++ palette.c | 150 ++ path.c | 52 + pcm.h | 21 + rc.h | 63 + rccmds.c | 194 ++ rcfile.c | 46 + rckeys.c | 86 + rcvars.c | 235 ++ refresh.c | 177 ++ regs.h | 181 ++ rtc.c | 130 ++ rtc.h | 25 + save.c | 286 +++ sound.c | 463 ++++ sound.h | 36 + split.c | 58 + sys/dos/dos.c | 85 + sys/dummy/nojoy.c | 22 + sys/dummy/nosound.c | 43 + sys/linux/fbdev.c | 283 +++ sys/linux/joy.c | 93 + sys/linux/kb.c | 135 ++ sys/linux/matrox.h | 36 + sys/nix/config.h.in | 22 + sys/nix/map.c | 85 + sys/nix/nix.c | 104 + sys/oss/oss.c | 104 + sys/pc/keymap.c | 141 ++ sys/sdl/keymap.c | 87 + sys/sdl/sdl.c | 510 +++++ sys/svga/svgalib.c | 246 ++ sys/thinlib/keymap.c | 141 ++ sys/thinlib/lib/Makefile | 100 + sys/thinlib/lib/thinlib.h | 67 + sys/thinlib/lib/thintest.cpp | 287 +++ sys/thinlib/lib/tl_bmp.c | 99 + sys/thinlib/lib/tl_bmp.h | 47 + sys/thinlib/lib/tl_djgpp.h | 34 + sys/thinlib/lib/tl_dpp.c | 191 ++ sys/thinlib/lib/tl_dpp.h | 35 + sys/thinlib/lib/tl_event.c | 140 ++ sys/thinlib/lib/tl_event.h | 80 + sys/thinlib/lib/tl_int.c | 262 +++ sys/thinlib/lib/tl_int.h | 31 + sys/thinlib/lib/tl_joy.c | 204 ++ sys/thinlib/lib/tl_joy.h | 31 + sys/thinlib/lib/tl_key.c | 125 ++ sys/thinlib/lib/tl_key.h | 146 ++ sys/thinlib/lib/tl_log.c | 59 + sys/thinlib/lib/tl_log.h | 23 + sys/thinlib/lib/tl_main.c | 179 ++ sys/thinlib/lib/tl_mouse.c | 223 ++ sys/thinlib/lib/tl_mouse.h | 40 + sys/thinlib/lib/tl_prof.c | 25 + sys/thinlib/lib/tl_prof.h | 21 + sys/thinlib/lib/tl_sb.c | 1050 +++++++++ sys/thinlib/lib/tl_sb.h | 35 + sys/thinlib/lib/tl_sound.c | 120 + sys/thinlib/lib/tl_sound.h | 48 + sys/thinlib/lib/tl_timer.c | 138 ++ sys/thinlib/lib/tl_timer.h | 25 + sys/thinlib/lib/tl_types.h | 61 + sys/thinlib/lib/tl_vesa.c | 401 ++++ sys/thinlib/lib/tl_vesa.h | 29 + sys/thinlib/lib/tl_vga.c | 381 ++++ sys/thinlib/lib/tl_vga.h | 32 + sys/thinlib/lib/tl_video.c | 140 ++ sys/thinlib/lib/tl_video.h | 41 + sys/thinlib/thinlib.c | 375 ++++ sys/windows/gameboy.ico | Bin 0 -> 2238 bytes sys/windows/resource.rc | 3 + sys/windows/windows.c | 77 + sys/x11/keymap.c | 96 + sys/x11/xlib.c | 524 +++++ 131 files changed, 27998 insertions(+) create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile.dos create mode 100644 Makefile.in create mode 100644 Makefile.nix create mode 100644 Makefile.win create mode 100644 README create mode 100644 Rules create mode 100644 Version create mode 100644 asm/i386/asm.h create mode 100644 asm/i386/asmnames.h create mode 100644 asm/i386/cpu.s create mode 100644 asm/i386/lcd.s create mode 100644 asm/i386/refresh.s create mode 100755 configure create mode 100644 configure.in create mode 100644 cpu.c create mode 100644 cpu.h create mode 100644 cpucore.h create mode 100644 cpuregs.h create mode 100644 debug.c create mode 100644 defs.h create mode 100644 docs/CHANGES create mode 100644 docs/CONFIG create mode 100644 docs/CREDITS create mode 100644 docs/FAQ create mode 100644 docs/HACKING create mode 100644 docs/LIBERTY create mode 100644 docs/README.old create mode 100644 docs/WHATSNEW create mode 100644 emu.c create mode 100644 etc/classic.rc create mode 100644 etc/filters.rc create mode 100644 etc/laguna.pgp create mode 100644 etc/palettes.rc create mode 100644 etc/sample.rc create mode 100644 events.c create mode 100644 exports.c create mode 100644 fastmem.c create mode 100644 fastmem.h create mode 100644 fb.h create mode 100644 hw.c create mode 100644 hw.h create mode 100644 inflate.c create mode 100644 input.h create mode 100755 install-sh create mode 100644 keytable.c create mode 100644 lcd.c create mode 100644 lcd.h create mode 100644 lcdc.c create mode 100644 loader.c create mode 100644 loader.h create mode 100644 main.c create mode 100644 mem.c create mode 100644 mem.h create mode 100644 newsound.c create mode 100644 noise.h create mode 100644 palette.c create mode 100644 path.c create mode 100644 pcm.h create mode 100644 rc.h create mode 100644 rccmds.c create mode 100644 rcfile.c create mode 100644 rckeys.c create mode 100644 rcvars.c create mode 100644 refresh.c create mode 100644 regs.h create mode 100644 rtc.c create mode 100644 rtc.h create mode 100644 save.c create mode 100644 sound.c create mode 100644 sound.h create mode 100644 split.c create mode 100644 sys/dos/dos.c create mode 100644 sys/dummy/nojoy.c create mode 100644 sys/dummy/nosound.c create mode 100644 sys/linux/fbdev.c create mode 100644 sys/linux/joy.c create mode 100644 sys/linux/kb.c create mode 100644 sys/linux/matrox.h create mode 100644 sys/nix/config.h.in create mode 100644 sys/nix/map.c create mode 100644 sys/nix/nix.c create mode 100644 sys/oss/oss.c create mode 100644 sys/pc/keymap.c create mode 100644 sys/sdl/keymap.c create mode 100644 sys/sdl/sdl.c create mode 100644 sys/svga/svgalib.c create mode 100644 sys/thinlib/keymap.c create mode 100644 sys/thinlib/lib/Makefile create mode 100644 sys/thinlib/lib/thinlib.h create mode 100644 sys/thinlib/lib/thintest.cpp create mode 100644 sys/thinlib/lib/tl_bmp.c create mode 100644 sys/thinlib/lib/tl_bmp.h create mode 100644 sys/thinlib/lib/tl_djgpp.h create mode 100644 sys/thinlib/lib/tl_dpp.c create mode 100644 sys/thinlib/lib/tl_dpp.h create mode 100644 sys/thinlib/lib/tl_event.c create mode 100644 sys/thinlib/lib/tl_event.h create mode 100644 sys/thinlib/lib/tl_int.c create mode 100644 sys/thinlib/lib/tl_int.h create mode 100644 sys/thinlib/lib/tl_joy.c create mode 100644 sys/thinlib/lib/tl_joy.h create mode 100644 sys/thinlib/lib/tl_key.c create mode 100644 sys/thinlib/lib/tl_key.h create mode 100644 sys/thinlib/lib/tl_log.c create mode 100644 sys/thinlib/lib/tl_log.h create mode 100644 sys/thinlib/lib/tl_main.c create mode 100644 sys/thinlib/lib/tl_mouse.c create mode 100644 sys/thinlib/lib/tl_mouse.h create mode 100644 sys/thinlib/lib/tl_prof.c create mode 100644 sys/thinlib/lib/tl_prof.h create mode 100644 sys/thinlib/lib/tl_sb.c create mode 100644 sys/thinlib/lib/tl_sb.h create mode 100644 sys/thinlib/lib/tl_sound.c create mode 100644 sys/thinlib/lib/tl_sound.h create mode 100644 sys/thinlib/lib/tl_timer.c create mode 100644 sys/thinlib/lib/tl_timer.h create mode 100644 sys/thinlib/lib/tl_types.h create mode 100644 sys/thinlib/lib/tl_vesa.c create mode 100644 sys/thinlib/lib/tl_vesa.h create mode 100644 sys/thinlib/lib/tl_vga.c create mode 100644 sys/thinlib/lib/tl_vga.h create mode 100644 sys/thinlib/lib/tl_video.c create mode 100644 sys/thinlib/lib/tl_video.h create mode 100644 sys/thinlib/thinlib.c create mode 100644 sys/windows/gameboy.ico create mode 100644 sys/windows/resource.rc create mode 100644 sys/windows/windows.c create mode 100644 sys/x11/keymap.c create mode 100644 sys/x11/xlib.c diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 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/INSTALL b/INSTALL new file mode 100644 index 0000000..afd42ee --- /dev/null +++ b/INSTALL @@ -0,0 +1,81 @@ + +GNUBOY INSTALLATION + + + *NIX SYSTEMS + +One or more of the following is required to compile on *nix: X, SDL, +svgalib, or Linux fbcon. Since basically everyone has X, this should +not be a problem. Please note that the SDL and fbcon ports are the +most functional, however. In the future, Sun console may also be +supported. + +The best and easiest way to build gnuboy for *nix is with the +configure script: + + ./configure + make + make install + +By default, heavy optimization and asm cpu and graphics cores will be +used if available on your platform. For information on compiletime +options related to performance and debugging, type: + + ./configure --help + +Alternatively, if you don't like the GNU configure script, you may +copy the Makefile.nix to Makefile and edit it by hand to work with +your system. Make sure you uncomment -DIS_LITTLE_ENDIAN if your cpu is +little endian. Please note that not everything is supported when +compiling this way, and that it should only be done as a last resort. +The generic Makefile.nix may be removed in the future since it's extra +work to maintain. + +Running make should produce the binaries xgnuboy, fbgnuboy, sgnuboy +and/or sdlgnuboy, depending on the availability of the various +interface libraries on your host. The install target will install +these to $(prefix)/bin, where prefix is specified to configure in the +usual way. The default prefix is of course /usr/local/. + +Binary packages may be available for some platforms, but they are +usually not quite up to date, and are not built or supported by the +gnuboy team. + +Binary package maintainers should be aware that, by default, gnuboy +will be built with optimizations specific to the exact host cpu it's +being compiled on, and may not work on older models. If you want your +binaries to work with older systems too, run configure with the +--disable-arch option to disable architecture specific compiler flags. + + + WINDOWS + +Mingw32 and the SDL development files are required to compile gnuboy +for Windows. They may be obtained from www.mingw.org and +www.libsdl.org, respectively. + +Just copy Makefile.mingw32 to Makefile and run make. When done, put +the resulting gnuboy.exe wherever you wish to install it. + +Precompiled binaries are also available for Windows; check the site +from which you obtained gnuboy to see if it provides copies. + + + DOS + +You'll need djgpp to use the included Makefile. Theoretically it +shouldn't be hard to port the dos-specific modules to work with other +compilers, but I see no reason why it should be necessary. + +Since all DOS systems are basically alike, just copy Makefile.dos to +Makefile and type "make" to compile gnuboy. No configuration should be +necessary. If you do have build problems, let us know. + +After compiling, place gnuboy.exe wherever you want. + +Precompiled binaries are also available for DOS; check the site from +which you obtained gnuboy to see if it provides copies. + + + + diff --git a/Makefile.dos b/Makefile.dos new file mode 100644 index 0000000..0b61f20 --- /dev/null +++ b/Makefile.dos @@ -0,0 +1,29 @@ + + +AS = $(CC) +LD = $(CC) + +CFLAGS = -O3 -fstrength-reduce -fomit-frame-pointer -I./asm/i386 +ASFLAGS = -x assembler-with-cpp +LDFLAGS = -s + +THIN_NAMES = tl_main tl_log tl_timer tl_key tl_mouse tl_joy tl_dpp tl_event \ + tl_bmp tl_vesa tl_vga tl_video tl_sb tl_sound tl_int +THIN_OBJS = $(THIN_NAMES:%=sys/thinlib/lib/%.o) + +SYS_DEFS = -DIS_LITTLE_ENDIAN -DALLOW_UNALIGNED_IO -DALT_PATH_SEP -DUSE_ASM + +SYS_INCS = -I./sys/dos -I./sys/thinlib/lib +SYS_OBJS = sys/dos/dos.o sys/thinlib/thinlib.o sys/thinlib/keymap.o $(THIN_OBJS) \ + asm/i386/cpu.o asm/i386/lcd.o asm/i386/refresh.o + +all: gnuboy.exe + +include Rules + +gnuboy.exe: $(OBJS) $(SYS_OBJS) + $(LD) $(CFLAGS) $(LDFLAGS) $(OBJS) $(SYS_OBJS) -o $@ + +clean: + rm -f gnuboy.exe gmon.out *.o sys/*.o sys/dos/*.o sys/pc/*.o asm/i386/*.o \ + sys/thinlib/*.o sys/thinlib/*.exe sys/thinlib/*.o \ No newline at end of file diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..58e49a3 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,70 @@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ + +CC = @CC@ +LD = $(CC) +AS = $(CC) +INSTALL = @INSTALL@ + +CFLAGS = @CFLAGS@ +LDFLAGS = $(CFLAGS) @LDFLAGS@ +ASFLAGS = $(CFLAGS) + +TARGETS = @TARGETS@ + +ASM_OBJS = @ASM_OBJS@ + +SYS_DEFS = @DEFS@ @ENDIAN@ @ASM@ @SYS_DEFS@ +SYS_OBJS = sys/nix/nix.o $(ASM_OBJS) +SYS_INCS = -I/usr/local/include @XINCS@ -I./sys/nix + +FB_OBJS = @FB_OBJS@ @JOY@ @SOUND@ +FB_LIBS = + +SVGA_OBJS = sys/svga/svgalib.o sys/pc/keymap.o @JOY@ @SOUND@ +SVGA_LIBS = -L/usr/local/lib -lvga + +SDL_OBJS = sys/sdl/sdl.o sys/sdl/keymap.o +SDL_LIBS = @SDL_LIBS@ +SDL_CFLAGS = @SDL_CFLAGS@ + +X11_OBJS = sys/x11/xlib.o sys/x11/keymap.o @JOY@ @SOUND@ +X11_LIBS = @XLIBS@ -lX11 -lXext + +all: $(TARGETS) + +include Rules + +fbgnuboy: $(OBJS) $(SYS_OBJS) $(FB_OBJS) + $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(FB_OBJS) -o $@ $(FB_LIBS) + +sgnuboy: $(OBJS) $(SYS_OBJS) $(SVGA_OBJS) + $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SVGA_OBJS) -o $@ $(SVGA_LIBS) + +sdlgnuboy: $(OBJS) $(SYS_OBJS) $(SDL_OBJS) + $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SDL_OBJS) -o $@ $(SDL_LIBS) + +sys/sdl/sdl.o: sys/sdl/sdl.c + $(MYCC) $(SDL_CFLAGS) -c $< -o $@ + +sys/sdl/keymap.o: sys/sdl/keymap.c + $(MYCC) $(SDL_CFLAGS) -c $< -o $@ + +xgnuboy: $(OBJS) $(SYS_OBJS) $(X11_OBJS) + $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(X11_OBJS) -o $@ $(X11_LIBS) + +install: all + $(INSTALL) -d $(bindir) + $(INSTALL) -m 755 $(TARGETS) $(bindir) + +clean: + rm -f *gnuboy gmon.out *.o sys/*.o sys/*/*.o asm/*/*.o + +distclean: clean + rm -f config.* sys/nix/config.h Makefile + + + + diff --git a/Makefile.nix b/Makefile.nix new file mode 100644 index 0000000..3f22450 --- /dev/null +++ b/Makefile.nix @@ -0,0 +1,64 @@ +# +# Makefile.nix +# +# This is a *bare minimum* makefile for building gnuboy on *nix systems. +# If you have trouble with the configure script you can try using this, +# but *please* try the configure script first. This file is mostly +# unmaintained and may break. +# +# If you *do* insist on using this makefile, you at least need to check +# SYS_DEFS below and uncomment -DIS_LITTLE_ENDIAN if your system is +# little endian. Also, you may want to enable the OSS sound module if +# your system supports it. +# + +prefix = /usr/local +bindir = /bin + +CC = gcc +AS = $(CC) +LD = $(CC) +INSTALL = /bin/install -c + +CFLAGS = -O3 +LDFLAGS = +ASFLAGS = + +SYS_DEFS = #-DIS_LITTLE_ENDIAN +ASM_OBJS = +#SND_OBJS = sys/oss/oss.o +SND_OBJS = sys/dummy/nosound.o +JOY_OBJS = sys/dummy/nojoy.o + +TARGETS = xgnuboy + +SYS_OBJS = sys/nix/nix.o $(ASM_OBJS) $(SND_OBJS) $(JOY_OBJS) +SYS_INCS = -I/usr/local/include -I/usr/X11R6/include -I./sys/nix + +X11_OBJS = sys/x11/xlib.o sys/x11/keymap.o +X11_LIBS = -L/usr/X11R6/lib -lX11 -lXext + +all: $(TARGETS) + +include Rules + +xgnuboy: $(OBJS) $(SYS_OBJS) $(X11_OBJS) + $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(X11_OBJS) -o $@ $(X11_LIBS) + +install: all + $(INSTALL) -m 755 $(TARGETS) $(prefix)$(bindir) + +clean: + rm -f *gnuboy gmon.out *.o sys/*.o sys/*/*.o asm/*/*.o + + + + + + + + + + + + diff --git a/Makefile.win b/Makefile.win new file mode 100644 index 0000000..c52c905 --- /dev/null +++ b/Makefile.win @@ -0,0 +1,31 @@ + +CC = gcc +AS = $(CC) +LD = $(CC) + +CFLAGS = -O3 -I./asm/i386 -Dmain=SDL_main +LDFLAGS = -s -lmingw32 -lSDLmain -lSDL +ASFLAGS = -x assembler-with-cpp + +SYS_DEFS = -DIS_LITTLE_ENDIAN -DALT_PATH_SEP -DUSE_ASM +ASM_OBJS = asm/i386/cpu.o asm/i386/lcd.o asm/i386/refresh.o +#SND_OBJS = sys/dummy/nosound.o + +SYS_OBJS = $(ASM_OBJS) $(SND_OBJS) sys/windows/windows.o sys/windows/resource.o +SYS_INCS = -I./sys/windows + +SDL_OBJS = sys/sdl/sdl.o sys/sdl/keymap.o +SDL_LIBS = -lSDL + +all: gnuboy + +include Rules + +%.o: %.rc + windres -o $@ $< + +gnuboy: $(OBJS) $(SYS_OBJS) $(SDL_OBJS) + $(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SDL_OBJS) -o $@ $(SDL_LIBS) + +clean: + rm -f gnuboy.exe *.o sys/*.o sys/*/*.o asm/*/*.o diff --git a/README b/README new file mode 100644 index 0000000..f10a5f0 --- /dev/null +++ b/README @@ -0,0 +1,199 @@ + +GNUBOY README + + + INTRO + +Welcome to gnuboy, one of the few pieces of Free Software to emulate +the Game Boy handheld game console. Written in ANSI C with a few +optional assembler optimizations for particular cpus, gnuboy supports +a wide range of host systems, and has been tested successfully on: + + GNU/Linux + FreeBSD + OpenBSD + BeOS + Linux/390 (IBM S/390 Mainframe) + SunOS/Sun Ultra60 + IRIX/SGI O2 + IRIX/SGI Indy + AIX/Unknown + DR-DOS + MS-DOS + Windows DOS box + Windows 9x/NT/2k + +Additionally, gnuboy should run on any other *nix variants that have +ANSI C compilers and that are remotely POSIX compliant. As gnuboy is +Free Software, you're welcome to fix any problems you encounter +building it for a particular system, or to port it to entirely new +systems. + + + EMULATION + +gnuboy emulates nearly all aspects of the (Color) Gameboy, including +all of the following and much more: + + Full GBZ80 instruction set. + Scanline-based LCD engine. + Ten sprites per scanline limit. + Support for all CGB graphics extensions. + Sprite DMA, HDMA, and GDMA. + All four sound channels including digital samples. + MBC1, MBC2, MBC3 (including clock), and MBC5 mappers. + Wave pattern memory corruption when sound channel 3 is played. + Pad, timer, divide counter, and other basic hardware registers. + CGB double-speed CPU mode. + +Aspects not emulated at this time include: + +* Serial IO (link cable). + Undocumented 'extra' ram in OAM space on Gameboy Color. + All Super Gameboy extensions. +* GBC, HuC1, and HuC3 IR ports. +* Obscure mappers such as TAMA5. + Sorting sprites by X coordinate in DMG mode. + HALT instruction skipping in DMG mode. + CPU stalls during HDMA and GDMA. + +Only the two marked by * are known to affect the playability of +actual games or demos; the rest are just listed for completeness' +sake. + + + FEATURES + +In addition to basic emulation, gnuboy provides the following +features: + + Highly flexible keybinding and configuration subsystem. + State saving and loading at any point. + Very precise timing/synchronization, preserved across save/load. + Joystick support on Linux, DOS, and all SDL-based ports. + Fully customizable palettes for DMG games. + Screen scaling by a factor of 2, 3, or 4 in all ports. + Hardware-based screen scaling on platforms where it's available. + Debug traces to stdout. + Dynamic palette allocation when run in 256-color modes... + OR simulated 3/3/2 bits per channel in 256-color modes. + +For information on configuring and using these features, see the +additional documentation in the "docs" directory. + + + COMPATIBILITY + +Out of over 300 results reported by testers, all games are known to +work perfectly on gnuboy with the following exceptions: + + Fighting Phoenix (Japanese) may or may not work since it uses the + HuC1 memory controller, which is not implemented properly. There has + been no report either way so far. + + Pocket Bomberman (Japanese version, which uses HuC1) runs, but can + be made to crash if the player jumps into the ceiling in the first + level. It's not clear whether this bug is MBC-related, something + else, or an actual bug in the original game. + + Monster Go! Go! Go! (Japanese) is unplayable. The cause of the + problem is not fully known, but it's either a very bad dump or it's + using some sort of specialized MBC that's not documented. + + Final Fantasy Adventure has visual problems with the fade between + screens. Does not affect gameplay. + + Bubble Bobble 2 has some minor tile glitches right before gameplay + actually begins. Cause unknown. Does not affect gameplay. + + Alone in the Dark is reported to have minor visual glitches. I + haven't seen it myself so I can't judge their severity. + + Both new Zelda games are reported to have a visual glitch at the + beginning of the game, and on certain other screens. I haven't seen + the problem myself, but supposedly it impacts gameplay to some + extent. + +Please report any other incompatibilities discovered directly to +gnuboy@unix-fu.org, so that they can be documented and hopefully +fixed. + + + FUTURE / WISHLIST + +Here's a brief list of what may appear in gnuboy in the future: + + Screenshots. + Integrated debugger. + Super Gameboy support. + Serial link over the internet. + Serial link to a real Gameboy with a custom cable. + Configurable color filters to provide more authentic LCD look. + Custom colorization of DMG games on a per-tile basis. + Support for more colorspaces in the hardware scaler. + Recording audio. + GBS player built from the same source tree. + Full recording and playback of emulation. + So-called "high level emulation" of certain typical dumb loops. + +Features that are not likely to appear soon or at all include: + + Rumble support - this would be nice, but SDL doesn't seem to support + force-feedback yet. We'll see about it in the long-term though. + + Eagle/2xSaI/etc. - probably not feasible since these libraries don't + appear to be compatible with the terms of the GPL. We might work on + our own interpolation engine eventually, but that's low priority. + + GUI/GUI-like features - such things are best handled by external + front-ends. We might eventually add a mechanism for external + programs to communicate with gnuboy and reconfigure it while it's + running, however. + + Plugins - NO! The way I see it, plugins are just an attempt to work + around the GPL. In any case, even if you are adding plugin support + yourself, you are bound by the terms of the GPL when linking ANY + code to gnuboy, including dynamic-linked modules. However we'd + rather not deal with this mess to begin with. + + Compressed ROMs/Saves - this one is very iffy. On most systems, this + is redundant; *nix users can just pipe the rom through a + decompression program, and Windows users can just double-click or + drag files from their favorite GUI unzipper program. Linking to zlib + isn't really acceptable since it's massively bloated and we don't + want to include it with gnuboy or add external dependencies. We may, + however, write our own tiny decompressor to use at some point. + +Ideas and suggestions for other features are welcome, but won't +necessarily be used. You're of course also free to add features +yourself, and if they fit well into the main tree they may eventually +get included in the official release. See the file HACKING for more +details on modifying and/or contributing. + + + THANKS + +Thanks goes out to everyone who's expressed interest in gnuboy by +writing -- users, porters, authors of other emulators, and so forth. +Apologies if we don't get a personal response out to everyone, but +either way, consider your feedback appreciated. + + + EPILOGUE + +OK, that looks like about it. More to come, stick around... + + + + -Laguna + + + + + + + + + + + diff --git a/Rules b/Rules new file mode 100644 index 0000000..4afd76a --- /dev/null +++ b/Rules @@ -0,0 +1,31 @@ + +include Version + +OBJS = lcd.o refresh.o lcdc.o palette.o cpu.o mem.o rtc.o hw.o sound.o \ + events.o keytable.o \ + loader.o save.o debug.o emu.o main.o \ + rccmds.o rckeys.o rcvars.o rcfile.o exports.o \ + split.o path.o inflate.o + +INCS = -I. + +MYCC = $(CC) $(CFLAGS) $(INCS) $(SYS_INCS) $(SYS_DEFS) +MYAS = $(AS) $(ASFLAGS) $(INCS) $(SYS_INCS) $(SYS_DEFS) + +main.o: Version + +.c.o: + $(MYCC) -c $< -o $@ + +.s.o: + $(MYAS) -c $< -o $@ + + + + + + + + + + diff --git a/Version b/Version new file mode 100644 index 0000000..0b12c42 --- /dev/null +++ b/Version @@ -0,0 +1,5 @@ +#define VERSION "1.0.3" /* +VERSION = 1.0.3 +# */ + + diff --git a/asm/i386/asm.h b/asm/i386/asm.h new file mode 100644 index 0000000..17f6db2 --- /dev/null +++ b/asm/i386/asm.h @@ -0,0 +1,35 @@ + + +#ifndef __ASM_H__ +#define __ASM_H__ + + + +#define ASM_CPU_EMULATE +#define ASM_CPU_STEP + +#define ASM_REFRESH_1 +#define ASM_REFRESH_2 +#define ASM_REFRESH_3 +#define ASM_REFRESH_4 + +#define ASM_REFRESH_1_2X +#define ASM_REFRESH_2_2X +#define ASM_REFRESH_4_2X + +#define ASM_REFRESH_1_3X +#define ASM_REFRESH_2_3X +#define ASM_REFRESH_4_3X + +#define ASM_REFRESH_4_4X + +#define ASM_UPDATEPATPIX + +#define ASM_BG_SCAN_COLOR + + + +#endif /* __ASM_H__ */ + + + diff --git a/asm/i386/asmnames.h b/asm/i386/asmnames.h new file mode 100644 index 0000000..37c6453 --- /dev/null +++ b/asm/i386/asmnames.h @@ -0,0 +1,41 @@ + + +#define cpu _cpu +#define hw _hw +#define ram _ram +#define mbc _mbc +#define lcd _lcd +#define scan _scan +#define patpix _patpix +#define anydirty _anydirty +#define patdirty _patdirty +#define cpu_emulate _cpu_emulate +#define cpu_step _cpu_step +#define lcdc_trans _lcdc_trans +#define debug_trace _debug_trace +#define updatepatpix _updatepatpix +#define debug_disassemble _debug_disassemble +#define bg_scan_color _bg_scan_color +#define refresh_1 _refresh_1 +#define refresh_2 _refresh_2 +#define refresh_3 _refresh_3 +#define refresh_4 _refresh_4 +#define refresh_1_2x _refresh_1_2x +#define refresh_2_2x _refresh_2_2x +#define refresh_3_2x _refresh_3_2x +#define refresh_4_2x _refresh_4_2x +#define refresh_1_3x _refresh_1_3x +#define refresh_2_3x _refresh_2_3x +#define refresh_3_3x _refresh_3_3x +#define refresh_4_3x _refresh_4_3x +#define refresh_1_4x _refresh_1_4x +#define refresh_2_4x _refresh_2_4x +#define refresh_3_4x _refresh_3_4x +#define refresh_4_4x _refresh_4_4x +#define mem_read _mem_read +#define mem_write _mem_write +#define cpu_idle _cpu_idle +#define die _die +#define printf _printf + + diff --git a/asm/i386/cpu.s b/asm/i386/cpu.s new file mode 100644 index 0000000..3665019 --- /dev/null +++ b/asm/i386/cpu.s @@ -0,0 +1,2430 @@ + + # i386 asm cpu core + # optimized for 486/pentium/k6 + + # global register usage: + # %bl - flags + # %bh - A + # %bp - PC + # %esi - number of cycles we have left + # %edi - number of cycles used by current instruction + +#include "asmnames.h" + + .set PC, cpu + .set SP, cpu+4 + .set BC, cpu+8 + .set DE, cpu+12 + .set HL, cpu+16 + .set AF, cpu+20 + + .set B, cpu+9 + .set C, cpu+8 + .set D, cpu+13 + .set E, cpu+12 + .set H, cpu+17 + .set L, cpu+16 + .set A, cpu+21 + .set F, cpu+20 + + .set IME, cpu+24 + .set IMA, cpu+28 + + .set speed, cpu+32 + .set halt, cpu+36 + .set div, cpu+40 + .set tim, cpu+44 + .set lcdc, cpu+48 + .set snd, cpu+52 + + .set regs, ram + + .set rmap, mbc+32 + .set wmap, mbc+96 + + .set DIV, ram+4 + .set TIMA, ram+5 + .set TMA, ram+6 + .set TAC, ram+7 + + .set IF, ram+0x0f + .set IE, ram+0xff + .set KEY1, ram+0x4d + + + .text + .p2align 5 + +debug: + .string "debug: 0x%08X\n" +invalid: + .string "invalid opcode 0x%02X\n" + + # x86 flags - 01=carry, 10=half, 40=zero + # (bit 0) (bit 4) (bit 6) + # gbz80 flags - 10=carry, 20=half, 40=neg, 80=zero + # (bit 4) (bit 5) (bit 6) (bit 7) + +addflagtable: + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0x80, 0x90, 0x80, 0x90, 0x80, 0x90, 0x80, 0x90 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + .byte 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0, 0xA0, 0xB0 + +subflagtable: + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x40, 0x50, 0x40, 0x50, 0x40, 0x50, 0x40, 0x50 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0x60, 0x70, 0x60, 0x70, 0x60, 0x70, 0x60, 0x70 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0, 0xC0, 0xD0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + .byte 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0 + +incflagtable: + .byte 0xa0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + +decflagtable: + .byte 192, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + .byte 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 96 + + +cycles_table: + .byte 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1 + .byte 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1 + .byte 3, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1 + .byte 3, 3, 2, 2, 1, 3, 3, 3, 3, 2, 2, 2, 1, 1, 2, 1 + .byte 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1 + .byte 5, 3, 4, 4, 6, 4, 2, 4, 5, 4, 4, 1, 6, 6, 2, 4 + .byte 5, 3, 4, 0, 6, 4, 2, 4, 5, 4, 4, 0, 6, 0, 2, 4 + .byte 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4 + .byte 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4 + +cb_cycles_table: + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 + .byte 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 + .byte 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 + .byte 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + .byte 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2 + + + +optable: + # 00 + .long __NOP, __LD_BC_IMM, __LD_$BC_A, __INC_BC + .long __INC_B, __DEC_B, __LD_B_IMM, __RLCA + .long __LD_$IMM_SP, __ADD_BC, __LD_A_$BC, __DEC_BC + .long __INC_C, __DEC_C, __LD_C_IMM, __RRCA + # 10 + .long __STOP, __LD_DE_IMM, __LD_$DE_A, __INC_DE + .long __INC_D, __DEC_D, __LD_D_IMM, __RLA + .long __JR, __ADD_DE, __LD_A_$DE, __DEC_DE + .long __INC_E, __DEC_E, __LD_E_IMM, __RRA + # 20 + .long __JR_NZ, __LD_HL_IMM, __LDI_$HL_A, __INC_HL + .long __INC_H, __DEC_H, __LD_H_IMM, __DAA + .long __JR_Z, __ADD_HL, __LDI_A_$HL, __DEC_HL + .long __INC_L, __DEC_L, __LD_L_IMM, __CPL + # 30 + .long __JR_NC, __LD_SP_IMM, __LDD_$HL_A, __INC_SP + .long __INC_$HL, __DEC_$HL, __LD_$HL_IMM, __SCF + .long __JR_C, __ADD_SP, __LDD_A_$HL, __DEC_SP + .long __INC_A, __DEC_A, __LD_A_IMM, __CCF + # 40 + .long __LD_B_B, __LD_B_C, __LD_B_D, __LD_B_E + .long __LD_B_H, __LD_B_L, __LD_B_$HL, __LD_B_A + .long __LD_C_B, __LD_C_C, __LD_C_D, __LD_C_E + .long __LD_C_H, __LD_C_L, __LD_C_$HL, __LD_C_A + # 50 + .long __LD_D_B, __LD_D_C, __LD_D_D, __LD_D_E + .long __LD_D_H, __LD_D_L, __LD_D_$HL, __LD_D_A + .long __LD_E_B, __LD_E_C, __LD_E_D, __LD_E_E + .long __LD_E_H, __LD_E_L, __LD_E_$HL, __LD_E_A + # 60 + .long __LD_H_B, __LD_H_C, __LD_H_D, __LD_H_E + .long __LD_H_H, __LD_H_L, __LD_H_$HL, __LD_H_A + .long __LD_L_B, __LD_L_C, __LD_L_D, __LD_L_E + .long __LD_L_H, __LD_L_L, __LD_L_$HL, __LD_L_A + # 70 + .long __LD_$HL_B, __LD_$HL_C, __LD_$HL_D, __LD_$HL_E + .long __LD_$HL_H, __LD_$HL_L, __HALT, __LD_$HL_A + .long __LD_A_B, __LD_A_C, __LD_A_D, __LD_A_E + .long __LD_A_H, __LD_A_L, __LD_A_$HL, __LD_A_A + # 80 + .long __ADD_B, __ADD_C, __ADD_D, __ADD_E + .long __ADD_H, __ADD_L, __ADD_$HL, __ADD_A + .long __ADC_B, __ADC_C, __ADC_D, __ADC_E + .long __ADC_H, __ADC_L, __ADC_$HL, __ADC_A + # 90 + .long __SUB_B, __SUB_C, __SUB_D, __SUB_E + .long __SUB_H, __SUB_L, __SUB_$HL, __SUB_A + .long __SBC_B, __SBC_C, __SBC_D, __SBC_E + .long __SBC_H, __SBC_L, __SBC_$HL, __SBC_A + # A0 + .long __AND_B, __AND_C, __AND_D, __AND_E + .long __AND_H, __AND_L, __AND_$HL, __AND_A + .long __XOR_B, __XOR_C, __XOR_D, __XOR_E + .long __XOR_H, __XOR_L, __XOR_$HL, __XOR_A + # B0 + .long __OR_B, __OR_C, __OR_D, __OR_E + .long __OR_H, __OR_L, __OR_$HL, __OR_A + .long __CP_B, __CP_C, __CP_D, __CP_E + .long __CP_H, __CP_L, __CP_$HL, __CP_A + # C0 + .long __RET_NZ, __POP_BC, __JP_NZ, __JP + .long __CALL_NZ, __PUSH_BC, __ADD_IMM, __RST_00 + .long __RET_Z, __RET, __JP_Z, __CB_OPS + .long __CALL_Z, __CALL, __ADC_IMM, __RST_08 + # D0 + .long __RET_NC, __POP_DE, __JP_NC, __INVALID + .long __CALL_NC, __PUSH_DE, __SUB_IMM, __RST_10 + .long __RET_C, __RETI, __JP_C, __INVALID + .long __CALL_C, __INVALID, __SBC_IMM, __RST_18 + # E0 + .long __LDH_$IMM_A, __POP_HL, __LDH_$C_A, __INVALID + .long __INVALID, __PUSH_HL, __AND_IMM, __RST_20 + .long __ADD_SP_IMM, __JP_HL, __LD_$IMM_A, __INVALID + .long __INVALID, __INVALID, __XOR_IMM, __RST_28 + # F0 + .long __LDH_A_$IMM, __POP_AF, __LDH_A_$C, __DI + .long __INVALID, __PUSH_AF, __OR_IMM, __RST_30 + .long __LD_HL_SP_IMM, __LD_SP_HL, __LD_A_$IMM, __EI + .long __INVALID, __INVALID, __CP_IMM, __RST_38 + + +cb_optable: + .long __RLC_B, __RLC_C, __RLC_D, __RLC_E + .long __RLC_H, __RLC_L, __RLC_$HL, __RLC_A + .long __RRC_B, __RRC_C, __RRC_D, __RRC_E + .long __RRC_H, __RRC_L, __RRC_$HL, __RRC_A + .long __RL_B, __RL_C, __RL_D, __RL_E + .long __RL_H, __RL_L, __RL_$HL, __RL_A + .long __RR_B, __RR_C, __RR_D, __RR_E + .long __RR_H, __RR_L, __RR_$HL, __RR_A + .long __SLA_B, __SLA_C, __SLA_D, __SLA_E + .long __SLA_H, __SLA_L, __SLA_$HL, __SLA_A + .long __SRA_B, __SRA_C, __SRA_D, __SRA_E + .long __SRA_H, __SRA_L, __SRA_$HL, __SRA_A + .long __SWAP_B, __SWAP_C, __SWAP_D, __SWAP_E + .long __SWAP_H, __SWAP_L, __SWAP_$HL, __SWAP_A + .long __SRL_B, __SRL_C, __SRL_D, __SRL_E + .long __SRL_H, __SRL_L, __SRL_$HL, __SRL_A + .long __BIT_0_B, __BIT_0_C, __BIT_0_D, __BIT_0_E + .long __BIT_0_H, __BIT_0_L, __BIT_0_$HL, __BIT_0_A + .long __BIT_1_B, __BIT_1_C, __BIT_1_D, __BIT_1_E + .long __BIT_1_H, __BIT_1_L, __BIT_1_$HL, __BIT_1_A + .long __BIT_2_B, __BIT_2_C, __BIT_2_D, __BIT_2_E + .long __BIT_2_H, __BIT_2_L, __BIT_2_$HL, __BIT_2_A + .long __BIT_3_B, __BIT_3_C, __BIT_3_D, __BIT_3_E + .long __BIT_3_H, __BIT_3_L, __BIT_3_$HL, __BIT_3_A + .long __BIT_4_B, __BIT_4_C, __BIT_4_D, __BIT_4_E + .long __BIT_4_H, __BIT_4_L, __BIT_4_$HL, __BIT_4_A + .long __BIT_5_B, __BIT_5_C, __BIT_5_D, __BIT_5_E + .long __BIT_5_H, __BIT_5_L, __BIT_5_$HL, __BIT_5_A + .long __BIT_6_B, __BIT_6_C, __BIT_6_D, __BIT_6_E + .long __BIT_6_H, __BIT_6_L, __BIT_6_$HL, __BIT_6_A + .long __BIT_7_B, __BIT_7_C, __BIT_7_D, __BIT_7_E + .long __BIT_7_H, __BIT_7_L, __BIT_7_$HL, __BIT_7_A + .long __RES_0_B, __RES_0_C, __RES_0_D, __RES_0_E + .long __RES_0_H, __RES_0_L, __RES_0_$HL, __RES_0_A + .long __RES_1_B, __RES_1_C, __RES_1_D, __RES_1_E + .long __RES_1_H, __RES_1_L, __RES_1_$HL, __RES_1_A + .long __RES_2_B, __RES_2_C, __RES_2_D, __RES_2_E + .long __RES_2_H, __RES_2_L, __RES_2_$HL, __RES_2_A + .long __RES_3_B, __RES_3_C, __RES_3_D, __RES_3_E + .long __RES_3_H, __RES_3_L, __RES_3_$HL, __RES_3_A + .long __RES_4_B, __RES_4_C, __RES_4_D, __RES_4_E + .long __RES_4_H, __RES_4_L, __RES_4_$HL, __RES_4_A + .long __RES_5_B, __RES_5_C, __RES_5_D, __RES_5_E + .long __RES_5_H, __RES_5_L, __RES_5_$HL, __RES_5_A + .long __RES_6_B, __RES_6_C, __RES_6_D, __RES_6_E + .long __RES_6_H, __RES_6_L, __RES_6_$HL, __RES_6_A + .long __RES_7_B, __RES_7_C, __RES_7_D, __RES_7_E + .long __RES_7_H, __RES_7_L, __RES_7_$HL, __RES_7_A + .long __SET_0_B, __SET_0_C, __SET_0_D, __SET_0_E + .long __SET_0_H, __SET_0_L, __SET_0_$HL, __SET_0_A + .long __SET_1_B, __SET_1_C, __SET_1_D, __SET_1_E + .long __SET_1_H, __SET_1_L, __SET_1_$HL, __SET_1_A + .long __SET_2_B, __SET_2_C, __SET_2_D, __SET_2_E + .long __SET_2_H, __SET_2_L, __SET_2_$HL, __SET_2_A + .long __SET_3_B, __SET_3_C, __SET_3_D, __SET_3_E + .long __SET_3_H, __SET_3_L, __SET_3_$HL, __SET_3_A + .long __SET_4_B, __SET_4_C, __SET_4_D, __SET_4_E + .long __SET_4_H, __SET_4_L, __SET_4_$HL, __SET_4_A + .long __SET_5_B, __SET_5_C, __SET_5_D, __SET_5_E + .long __SET_5_H, __SET_5_L, __SET_5_$HL, __SET_5_A + .long __SET_6_B, __SET_6_C, __SET_6_D, __SET_6_E + .long __SET_6_H, __SET_6_L, __SET_6_$HL, __SET_6_A + .long __SET_7_B, __SET_7_C, __SET_7_D, __SET_7_E + .long __SET_7_H, __SET_7_L, __SET_7_$HL, __SET_7_A + + + +daa_table: + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + .byte 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 + + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + .byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0 + + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + .byte 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA + + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + .byte 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A + +daa_carry_table: + .byte 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 + .byte 00, 00, 00, 00, 00, 00, 00, 00, 16, 16, 00, 00, 00, 00, 00, 00 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + .byte 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 00, 16 + +zflag_table: + .byte 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + +int_mask_table: + .byte ~0, ~1, ~2, ~1, ~4, ~1, ~2, ~1 + .byte ~8, ~1, ~2, ~1, ~4, ~1, ~2, ~1 + .byte ~16, ~1, ~2, ~1, ~4, ~1, ~2, ~1 + .byte ~8, ~1, ~2, ~1, ~4, ~1, ~2, ~1 + +int_vec_table: + .long 0x00, 0x40, 0x48, 0x40, 0x50, 0x40, 0x48, 0x40 + .long 0x58, 0x40, 0x48, 0x40, 0x50, 0x40, 0x48, 0x40 + .long 0x60, 0x40, 0x48, 0x40, 0x50, 0x40, 0x48, 0x40 + .long 0x58, 0x40, 0x48, 0x40, 0x50, 0x40, 0x48, 0x40 + + + .macro _print arg=0 + pushf + pusha + movl \arg, %eax + pushl %eax + pushl $debug + call printf + addl $8, %esp + popa + popf + .endm + + .macro _trace + testb $1, debug_trace + jz .Lnotrace\@ + pushl %eax + pushl %ecx + pushl %edx + movl %ebx, AF + movl %ebp, PC + movl $1, %eax + pushl %eax + pushl %ebp + call debug_disassemble + addl $8, %esp + popl %edx + popl %ecx + popl %eax +.Lnotrace\@: + .endm + + + # all macros preserve %ebp, %ebx, %esi, and %edi + + + # write to addr %eax, upper bytes must be zero + # source byte passed in %dl + .macro _writeb + movl %eax, %ecx + shrl $12, %eax + movl wmap(,%eax,4), %eax + testl %eax,%eax + jnz .Lusemap\@ + pushl %edx + pushl %ecx + call mem_write + addl $8,%esp + jmp .Lfinish\@ +.Lusemap\@: + movb %dl, (%eax,%ecx) +.Lfinish\@: + .endm + + # read from addr %eax, upper bytes must be zero + # result in %al, upper bytes filled with 0 automagically + .macro _readb + movl %eax, %ecx + shrl $12, %eax + movl rmap(,%eax,4), %edx + testl %edx,%edx + jnz .Lusemap\@ + pushl %ecx + call mem_read + popl %ecx + jmp .Lfinish\@ +.Lusemap\@: + movb (%edx,%ecx),%al +.Lfinish\@: + .endm + + # read signed byte from addr %eax, upper bytes must be zero + # result in %eax + .macro _readbs + movl %eax, %ecx + shrl $12, %eax + movl rmap(,%eax,4), %edx + testl %edx,%edx + jnz .Lusemap\@ + pushl %ecx + call mem_read + movsbl %al, %eax + popl %ecx + jmp .Lfinish\@ +.Lusemap\@: + movsbl (%edx,%ecx),%eax +.Lfinish\@: + .endm + + # fetch from PC + # result in %al, upper bytes filled with 0 automagically + .macro _fetch + movl %ebp, %eax + movl %ebp, %ecx + shrl $12, %eax + incw %bp + movl rmap(,%eax,4), %edx + testl %edx,%edx + jnz .Lusemap\@ + pushl %ecx + call mem_read + popl %ecx + jmp .Lfinish\@ +.Lusemap\@: + movb (%edx,%ecx),%al +.Lfinish\@: + .endm + + # fetch signed byte from PC + # result in %eax + .macro _fetchs + movl %ebp, %eax + movl %ebp, %ecx + shrl $12, %eax + incw %bp + movl rmap(,%eax,4), %edx + testl %edx,%edx + jnz .Lusemap\@ + pushl %ecx + call mem_read + popl %ecx + movsbl %al, %eax + jmp .Lfinish\@ +.Lusemap\@: + movsbl (%edx,%ecx),%eax +.Lfinish\@: + .endm + + # fetch word from PC + # result in %ax, padded with zeros + .macro _fetchw + movl %ebp, %eax + movl %ebp, %edx + shrl $12, %eax + incl %edx + movl %ebp, %ecx + testl $0xfff, %edx + jz .Lunaligned\@ + movl rmap(,%eax,4), %edx + testl %edx, %edx + jnz .Lusemap\@ +.Lunaligned\@: + incl %ebp + pushl %ecx + call mem_read + pushl %eax + pushl %ebp + incl %ebp + call mem_read + popl %ecx + popl %ecx + movb %al, %ah + movb %cl, %al + popl %ecx + andl $0xffff, %ebp + jmp .Lfinish\@ +.Lusemap\@: + movw (%edx,%ecx),%ax + addw $2, %bp +.Lfinish\@: + .endm + + # read word from %eax, upper byte must be zero + # result in %ax, padded with zeros + .macro _readw + movl %eax, %edx + shrl $12, %eax + movl %edx, %ecx + incl %edx + testl $0xfff, %edx + jz .Lunaligned\@ + movl rmap(,%eax,4), %edx + testl %edx, %edx + jnz .Lusemap\@ +.Lunaligned\@: + pushl %ecx + pushl %ecx + call mem_read + popl %ecx + popl %ecx + incl %ecx + pushl %eax + pushl %ecx + call mem_read + popl %ecx + popl %ecx + movb %al, %ah + movb %cl, %al + jmp .Lfinish\@ +.Lusemap\@: + movw (%edx,%ecx),%ax +.Lfinish\@: + .endm + + # write word to addr %eax, upper bytes must be zero + # source byte passed in %dx + .macro _writew + movl %eax, %ecx + shrl $12, %eax + pushl %edx + movl %ecx, %edx + incl %edx + testl $0xfff, %edx + jz .Lunaligned\@ + movl wmap(,%eax,4), %edx + testl %edx, %edx + jnz .Lusemap\@ +.Lunaligned\@: + popl %edx + pushl %edx + pushl %ecx + pushl %edx + pushl %ecx + call mem_write + popl %ecx + popl %ecx + popl %ecx + popl %edx + incl %ecx + shrl $8, %edx + pushl %edx + pushl %ecx + call mem_write + addl $8, %esp + jmp .Lfinish\@ +.Lusemap\@: + popl %eax + movw %ax, (%edx,%ecx) +.Lfinish\@: + .endm + + + .macro _end + jmp opdone + .endm + + .macro _endnz + jnz opdone + .endm + + .macro _endz + jz opdone + .endm + + + .macro _LD dst=B, src=B + movb \src, %al + movb %al, \dst + _end + .endm + + .macro _ld_from_hl dst=B + movl HL, %eax + _readb + movb %al, \dst + .endm + + .macro _ld_to_hl src=B + movl HL, %eax + movb \src, %dl + _writeb + .endm + + .macro _ld_from_imm dst=B + _fetch + movb %al, \dst + .endm + + .macro _push + movl %eax, %edx + movl SP, %eax + subw $2, %ax + movl %eax, SP + _writew + .endm + + .macro _pop + movl SP, %eax + _readw + addw $2, SP + .endm + + .macro _JR + movl %ebp, %eax + _readbs + incl %eax + addw %ax, %bp + .endm + + .macro _JP + _fetchw + movl %eax, %ebp + .endm + + .macro _CALL + movl %ebp, %eax + addl $2, %eax + _push + _JP + .endm + + .macro _RET + _pop + movl %eax, %ebp + .endm + + .macro _NOJR + incw %bp + decl %edi + .endm + + .macro _NOJP + addw $2, %bp + decl %edi + .endm + + .macro _NOCALL + addw $2, %bp + subl $3, %edi + .endm + + .macro _NORET + subl $3, %edi + .endm + + # Use %dl to pass memory values to inc + .macro _INC reg=B, instr=incb, table=incflagtable + xorl %eax, %eax + \instr \reg + movb \reg, %al + andb $0x1f, %bl + orb \table(%eax), %bl + .endm + + .macro _DEC reg=B + _INC \reg, decb, decflagtable + .endm + + .macro _INCW reg=HL + incw \reg + _end + .endm + + .macro _DECW reg=HL + decw \reg + _end + .endm + + .macro _ADD instr=addb, table=addflagtable + \instr %al, %bh + lahf + xorl %ecx, %ecx + movb %ah, %cl + movb \table(%ecx), %bl + .endm + + .macro _SUB + _ADD subb, subflagtable + .endm + + .macro _ADC instr=adcb, table=addflagtable + rolb $4, %bl + _ADD \instr, \table + .endm + + .macro _SBC + _ADC sbbb, subflagtable + .endm + + .macro _CP + _ADD cmpb, subflagtable + .endm + + .macro _ADDW + movl HL, %edx + addb %al, %dl + adcb %ah, %dh + lahf + movl %edx, HL + movb $0, %dh + movb %ah, %dl + andb $0x8f, %bl + movb addflagtable(%edx), %al + andb $0x70, %al + orb %al, %bl + .endm + + .macro _ADDSP dst=SP + movl SP, %edx + addb %al, %dl + adcb %ah, %dh + lahf + movl %edx, \dst + movb $0, %dh + movb %ah, %dl + andb $0x0f, %bl + movb addflagtable(%edx), %al + andb $0x70, %al + orb %al, %bl + .endm + + .macro _AND + movb $0x20, %bl + andb %al, %bh + _endnz + orb $0x80, %bl + .endm + + .macro _OR instr=orb + \instr %al, %bh + setzb %bl + rorb $1, %bl + .endm + + .macro _XOR + _OR xorb + .endm + + + + .macro _RLCA instr=rolb + movb $0, %bl + \instr $1, %bh + rcrb $4, %bl + .endm + + .macro _RRCA + _RLCA rorb + .endm + + .macro _RLA instr=rclb + rolb $4, %bl + movb $0, %bl + \instr $1, %bh + rcrb $4, %bl + .endm + + .macro _RRA + _RLA rcrb + .endm + + .macro _RLC reg=B, instr=rolb + xorl %eax, %eax + movb \reg, %al + xorb %bl, %bl + \instr $1, %al + rcrb $4, %bl + movb %al, \reg + orb zflag_table(%eax), %bl + .endm + + .macro _RRC reg=B + _RLC \reg, rorb + .endm + + .macro _RL reg=B, instr=rclb + xorl %eax, %eax + andb $0x10, %bl + movb \reg, %al + rclb $4, %bl + \instr $1, %al + rcrb $4, %bl + movb %al, \reg + orb zflag_table(%eax), %bl + .endm + + .macro _RR reg=B + _RL \reg, rcrb + .endm + + .macro _SLA reg=B instr=shlb + movb $0, %cl + \instr $1, \reg + setz %bl + rcrb $4, %cl + rorb $1, %bl + orb %cl, %bl + .endm + + .macro _SRA reg=B + _SLA \reg, sarb + .endm + + .macro _SRL reg=B + _SLA \reg, shrb + .endm + + .macro _SWAP reg=B + movb \reg, %al + xorb %bl, %bl + rolb $4, %al + testb %al, %al + movb %al, \reg + _endnz + orb $0x80, %bl + _end + .endm + + .macro _SWAP_A + xorb %bl, %bl + rolb $4, %bh + testb %bh, %bh + _endnz + orb $0x80, %bl + _end + .endm + + .macro _SWAP_MEM + movl HL, %eax + _readb + movb %al, %dl + xorb %bl, %bl + rolb $4, %dl + movl HL, %eax + testb %dl, %dl + jnz .Lnonzero\@ + orb $0x80, %bl +.Lnonzero\@: + _writeb + _end + .endm + + .macro _BIT bit=0, reg=B + andb $0x1f, %bl + movb \reg, %al + orb $0x20, %bl + testb $(1<<\bit), %al + _endnz + orb $0x80, %bl + _end + .endm + + .macro _BIT_MEM bit=0 + movl HL, %eax + _readb + _BIT \bit, %al + .endm + + .macro _RES bit=0, reg=B + andb $(~(1<<\bit)), \reg + _end + .endm + + .macro _RES_MEM bit=0 + movl HL, %eax + _readb + movb %al, %dl + movl HL, %eax + andb $(~(1<<\bit)), %dl + _writeb + _end + .endm + + .macro _SET bit=0, reg=B + orb $(1<<\bit), \reg + _end + .endm + + .macro _SET_MEM bit=0 + movl HL, %eax + _readb + movb %al, %dl + movl HL, %eax + orb $(1<<\bit), %dl + _writeb + _end + .endm + + + + .macro _DAA + xorl %eax, %eax + movb %bl, %ah + andb $0x70, %ah + movb %bh, %al + shrb $4, %ah + xorl %ecx, %ecx + movb daa_table(%eax), %cl + andb $0x4f, %bl + addb %cl, %al + shrb $2, %cl + xorb %ah, %ah + movb %al, %bh + orb daa_carry_table(%ecx), %bl + orb zflag_table(%eax), %bl + .endm + + + + + + + + + .macro _make_bit_ops reg=B, op=BIT, bit=0, u=_ +__\op\u\bit\u\reg: + _\op \bit, \reg + .endm + + .macro _make_cb_ops reg=B +__RLC_\reg: + _RLC \reg + _end +__RRC_\reg: + _RRC \reg + _end +__RL_\reg: + _RL \reg + _end +__RR_\reg: + _RR \reg + _end +__SLA_\reg: + _SLA \reg + _end +__SRA_\reg: + _SRA \reg + _end +__SWAP_\reg: + _SWAP \reg +__SRL_\reg: + _SRL \reg + _end + _make_bit_ops \reg, BIT, 0 + _make_bit_ops \reg, BIT, 1 + _make_bit_ops \reg, BIT, 2 + _make_bit_ops \reg, BIT, 3 + _make_bit_ops \reg, BIT, 4 + _make_bit_ops \reg, BIT, 5 + _make_bit_ops \reg, BIT, 6 + _make_bit_ops \reg, BIT, 7 + _make_bit_ops \reg, RES, 0 + _make_bit_ops \reg, RES, 1 + _make_bit_ops \reg, RES, 2 + _make_bit_ops \reg, RES, 3 + _make_bit_ops \reg, RES, 4 + _make_bit_ops \reg, RES, 5 + _make_bit_ops \reg, RES, 6 + _make_bit_ops \reg, RES, 7 + _make_bit_ops \reg, SET, 0 + _make_bit_ops \reg, SET, 1 + _make_bit_ops \reg, SET, 2 + _make_bit_ops \reg, SET, 3 + _make_bit_ops \reg, SET, 4 + _make_bit_ops \reg, SET, 5 + _make_bit_ops \reg, SET, 6 + _make_bit_ops \reg, SET, 7 + .endm + + .macro _make_cb_hl_op op=RLC suf=_$HL mem=_MEM +__\op\suf: + movl HL, %eax + _readb + movb %al, %dl + _\op %dl + movl HL, %eax + _writeb + _end + .endm + + .macro _make_cb_hl_bit_op op=BIT bit=0 u=_ suf=_$HL mem=_MEM +__\op\u\bit\suf: + _\op\mem \bit + .endm + + + + + .text + .p2align 5 + + .globl cpu_emulate + .globl cpu_step + +__INVALID: + pushl %eax + pushl $invalid + call die + + +__LD_B_C: + _LD B,C +__LD_B_D: + _LD B,D +__LD_B_E: + _LD B,E +__LD_B_H: + _LD B,H +__LD_B_L: + _LD B,L +__LD_B_A: + movb %bh, B + _end +__LD_C_B: + _LD C,B +__LD_C_D: + _LD C,D +__LD_C_E: + _LD C,E +__LD_C_H: + _LD C,H +__LD_C_L: + _LD C,L +__LD_C_A: + movb %bh, C + _end +__LD_D_B: + _LD D,B +__LD_D_C: + _LD D,C +__LD_D_E: + _LD D,E +__LD_D_H: + _LD D,H +__LD_D_L: + _LD D,L +__LD_D_A: + movb %bh, D + _end +__LD_E_B: + _LD E,B +__LD_E_C: + _LD E,C +__LD_E_D: + _LD E,D +__LD_E_H: + _LD E,H +__LD_E_L: + _LD E,L +__LD_E_A: + movb %bh, E + _end +__LD_H_B: + _LD H,B +__LD_H_C: + _LD H,C +__LD_H_D: + _LD H,D +__LD_H_E: + _LD H,E +__LD_H_L: + _LD H,L +__LD_H_A: + movb %bh, H + _end +__LD_L_B: + _LD L,B +__LD_L_C: + _LD L,C +__LD_L_D: + _LD L,D +__LD_L_E: + _LD L,E +__LD_L_H: + _LD L,H +__LD_L_A: + movb %bh, L + _end +__LD_A_B: + movb B, %bh + _end +__LD_A_C: + movb C, %bh + _end +__LD_A_D: + movb D, %bh + _end +__LD_A_E: + movb E, %bh + _end +__LD_A_H: + movb H, %bh + _end +__LD_A_L: + movb L, %bh + _end + + +__LD_$HL_B: + _ld_to_hl B + _end +__LD_$HL_C: + _ld_to_hl C + _end +__LD_$HL_D: + _ld_to_hl D + _end +__LD_$HL_E: + _ld_to_hl E + _end +__LD_$HL_H: + _ld_to_hl H + _end +__LD_$HL_L: + _ld_to_hl L + _end +__LD_$HL_A: + _ld_to_hl %bh + _end + +__LD_B_$HL: + _ld_from_hl B + _end +__LD_C_$HL: + _ld_from_hl C + _end +__LD_D_$HL: + _ld_from_hl D + _end +__LD_E_$HL: + _ld_from_hl E + _end +__LD_H_$HL: + _ld_from_hl H + _end +__LD_L_$HL: + _ld_from_hl L + _end +__LD_A_$HL: + _ld_from_hl %bh + _end + + +__LD_$BC_A: + movl BC, %eax + movb %bh, %dl + _writeb + _end +__LD_A_$BC: + movl BC, %eax + _readb + movb %al, %bh + _end +__LD_$DE_A: + movl DE, %eax + movb %bh, %dl + _writeb + _end +__LD_A_$DE: + movl DE, %eax + _readb + movb %al, %bh + _end + +__LDI_$HL_A: + _ld_to_hl %bh + _INCW HL +__LDI_A_$HL: + _ld_from_hl %bh + _INCW HL +__LDD_$HL_A: + _ld_to_hl %bh + _DECW HL +__LDD_A_$HL: + _ld_from_hl %bh + _DECW HL + + +__FETCH: + _fetch + ret + +__LD_B_IMM: + call __FETCH + movb %al, B + _end +__LD_C_IMM: + call __FETCH + movb %al, C + _end +__LD_D_IMM: + call __FETCH + movb %al, D + _end +__LD_E_IMM: + call __FETCH + movb %al, E + _end +__LD_H_IMM: + call __FETCH + movb %al, H + _end +__LD_L_IMM: + call __FETCH + movb %al, L + _end +__LD_$HL_IMM: + call __FETCH + movb %al, %dl + movl HL, %eax + _writeb + _end +__LD_A_IMM: + call __FETCH + movb %al, %bh + _end + + +__FETCHW: + _fetchw + ret + +__LD_BC_IMM: + call __FETCHW + movl %eax, BC + _end +__LD_DE_IMM: + call __FETCHW + movl %eax, DE + _end +__LD_HL_IMM: + call __FETCHW + movl %eax, HL + _end +__LD_SP_IMM: + call __FETCHW + movl %eax, SP + _end + + + +__LD_$IMM_SP: + _fetchw + movl SP, %edx + _writew + _end +__LD_SP_HL: + movl HL, %eax + movl %eax, SP + _end +__LD_HL_SP_IMM: + _fetchs + _ADDSP HL + _end + + + + +__LD_$IMM_A: + _fetchw + movb %bh, %dl + _writeb + _end +__LD_A_$IMM: + _fetchw + _readb + movb %al, %bh + _end + + + +__LDH_$IMM_A: + _fetch + movb $0xff, %ah + movb %bh, %dl + _writeb + _end +__LDH_A_$IMM: + _fetch + movb $0xff, %ah + _readb + movb %al, %bh + _end +__LDH_$C_A: + movl $0xff00, %eax + movb C, %al + movb %bh, %dl + _writeb + _end +__LDH_A_$C: + movl $0xff00, %eax + movb C, %al + _readb + movb %al, %bh + _end + + + +__ADD_IMM: + _fetch + jmp __ADD +__ADD_$HL: + movl HL, %eax + _readb + jmp __ADD +__ADD_B: + movb B, %al + jmp __ADD +__ADD_C: + movb C, %al + jmp __ADD +__ADD_D: + movb D, %al + jmp __ADD +__ADD_E: + movb E, %al + jmp __ADD +__ADD_H: + movb H, %al + jmp __ADD +__ADD_L: + movb L, %al + jmp __ADD +__ADD_A: + movb %bh, %al +__ADD: + _ADD + _end + +__ADC_IMM: + _fetch + jmp __ADC +__ADC_$HL: + movl HL, %eax + _readb + jmp __ADC +__ADC_B: + movb B, %al + jmp __ADC +__ADC_C: + movb C, %al + jmp __ADC +__ADC_D: + movb D, %al + jmp __ADC +__ADC_E: + movb E, %al + jmp __ADC +__ADC_H: + movb H, %al + jmp __ADC +__ADC_L: + movb L, %al + jmp __ADC +__ADC_A: + movb %bh, %al +__ADC: + _ADC + _end + +__SUB_IMM: + _fetch + jmp __SUB +__SUB_$HL: + movl HL, %eax + _readb + jmp __SUB +__SUB_B: + movb B, %al + jmp __SUB +__SUB_C: + movb C, %al + jmp __SUB +__SUB_D: + movb D, %al + jmp __SUB +__SUB_E: + movb E, %al + jmp __SUB +__SUB_H: + movb H, %al + jmp __SUB +__SUB_L: + movb L, %al + jmp __SUB +__SUB_A: + movb %bh, %al +__SUB: + _SUB + _end + +__SBC_IMM: + _fetch + jmp __SBC +__SBC_$HL: + movl HL, %eax + _readb + jmp __SBC +__SBC_B: + movb B, %al + jmp __SBC +__SBC_C: + movb C, %al + jmp __SBC +__SBC_D: + movb D, %al + jmp __SBC +__SBC_E: + movb E, %al + jmp __SBC +__SBC_H: + movb H, %al + jmp __SBC +__SBC_L: + movb L, %al + jmp __SBC +__SBC_A: + movb %bh, %al +__SBC: + _SBC + _end + +__AND_IMM: + _fetch + jmp __AND +__AND_$HL: + movl HL, %eax + _readb + jmp __AND +__AND_B: + movb B, %al + jmp __AND +__AND_C: + movb C, %al + jmp __AND +__AND_D: + movb D, %al + jmp __AND +__AND_E: + movb E, %al + jmp __AND +__AND_H: + movb H, %al + jmp __AND +__AND_L: + movb L, %al + jmp __AND +__AND_A: + movb %bh, %al +__AND: + _AND + _end + +__XOR_IMM: + _fetch + jmp __XOR +__XOR_$HL: + movl HL, %eax + _readb + jmp __XOR +__XOR_B: + movb B, %al + jmp __XOR +__XOR_C: + movb C, %al + jmp __XOR +__XOR_D: + movb D, %al + jmp __XOR +__XOR_E: + movb E, %al + jmp __XOR +__XOR_H: + movb H, %al + jmp __XOR +__XOR_L: + movb L, %al + jmp __XOR +__XOR_A: + movb %bh, %al +__XOR: + _XOR + _end + +__OR_IMM: + _fetch + jmp __OR +__OR_$HL: + movl HL, %eax + _readb + jmp __OR +__OR_B: + movb B, %al + jmp __OR +__OR_C: + movb C, %al + jmp __OR +__OR_D: + movb D, %al + jmp __OR +__OR_E: + movb E, %al + jmp __OR +__OR_H: + movb H, %al + jmp __OR +__OR_L: + movb L, %al + jmp __OR +__OR_A: + movb %bh, %al +__OR: + _OR + _end + +__CP_IMM: + _fetch + jmp __CP +__CP_$HL: + movl HL, %eax + _readb + jmp __CP +__CP_B: + movb B, %al + jmp __CP +__CP_C: + movb C, %al + jmp __CP +__CP_D: + movb D, %al + jmp __CP +__CP_E: + movb E, %al + jmp __CP +__CP_H: + movb H, %al + jmp __CP +__CP_L: + movb L, %al + jmp __CP +__CP_A: + movb %bh, %al +__CP: + _CP + _end + + +__ADD_BC: + movl BC, %eax + jmp __ADDW +__ADD_DE: + movl DE, %eax + jmp __ADDW +__ADD_SP: + movl SP, %eax + jmp __ADDW +__ADD_HL: + movl HL, %eax +__ADDW: + _ADDW + _end + + + +__INC_B: + _INC B + _end +__INC_C: + _INC C + _end +__INC_D: + _INC D + _end +__INC_E: + _INC E + _end +__INC_H: + _INC H + _end +__INC_L: + _INC L + _end +__INC_$HL: + movl HL, %eax + _readb + movb %al, %dl + _INC %dl + movl HL, %eax + _writeb + _end +__INC_A: + _INC %bh + _end + + +__DEC_B: + _DEC B + _end +__DEC_C: + _DEC C + _end +__DEC_D: + _DEC D + _end +__DEC_E: + _DEC E + _end +__DEC_H: + _DEC H + _end +__DEC_L: + _DEC L + _end +__DEC_$HL: + movl HL, %eax + _readb + movb %al, %dl + _DEC %dl + movl HL, %eax + _writeb + _end +__DEC_A: + _DEC %bh + _end + + + +__INC_BC: + _INCW BC +__INC_DE: + _INCW DE +__INC_HL: + _INCW HL +__INC_SP: + _INCW SP +__DEC_BC: + _DECW BC +__DEC_DE: + _DECW DE +__DEC_HL: + _DECW HL +__DEC_SP: + _DECW SP + + + +__ADD_SP_IMM: + _fetchs + _ADDSP + _end + + + +__RLCA: + _RLCA + _end +__RRCA: + _RRCA + _end +__RLA: + _RLA + _end +__RRA: + _RRA + _end + + +__DAA: + _DAA + _end + + +__SCF: + andb $0x8f, %bl + orb $0x10, %bl + _end +__CCF: + andb $0x9f, %bl + xorb $0x10, %bl + _end + +__CPL: + orb $0x60, %bl + xorb $-1, %bh + _end + + +__EI: + movl $1, IMA + _end +__DI: + xorl %eax,%eax + movl %eax, halt + movl %eax, IME + movl %eax, IMA + _end + + +__PUSH_BC: + movl BC, %eax + jmp __PUSH +__PUSH_DE: + movl DE, %eax + jmp __PUSH +__PUSH_HL: + movl HL, %eax + jmp __PUSH +__PUSH_AF: + movl %ebx, %eax +__PUSH: + _push + _end + +__POP_BC: + _pop + movl %eax, BC + _end +__POP_DE: + _pop + movl %eax, DE + _end +__POP_HL: + _pop + movl %eax, HL + _end +__POP_AF: + _pop + movl %eax, %ebx + _end + + + + + +__JR_NZ: + testb $0x80, %bl + jz __JR + _NOJR + _end + +__JR_Z: + testb $0x80, %bl + jnz __JR + _NOJR + _end + +__JR_NC: + testb $0x10, %bl + jz __JR + _NOJR + _end + +__JR_C: + testb $0x10, %bl + jnz __JR + _NOJR + _end + +__JR: + _JR + _end + + + +__JP_HL: + movl HL, %eax + movl %eax, %ebp + _end + +__JP_NZ: + testb $0x80, %bl + jz __JP + _NOJP + _end + +__JP_Z: + testb $0x80, %bl + jnz __JP + _NOJP + _end + +__JP_NC: + testb $0x10, %bl + jz __JP + _NOJP + _end + +__JP_C: + testb $0x10, %bl + jnz __JP + _NOJP + _end + +__JP: + _JP + _end + + + +__CALL_NZ: + testb $0x80, %bl + jz __CALL + _NOCALL + _end + +__CALL_Z: + testb $0x80, %bl + jnz __CALL + _NOCALL + _end + +__CALL_NC: + testb $0x10, %bl + jz __CALL + _NOCALL + _end + +__CALL_C: + testb $0x10, %bl + jnz __CALL + _NOCALL + _end + +__CALL: + _CALL + _end + + + + +__RET_NZ: + testb $0x80, %bl + jz __RET + _NORET + _end + +__RET_Z: + testb $0x80, %bl + jnz __RET + _NORET + _end + +__RET_NC: + testb $0x10, %bl + jz __RET + _NORET + _end + +__RET_C: + testb $0x10, %bl + jnz __RET + _NORET + _end + +__RETI: + movl $1, %eax + movl %eax, IME + movl %eax, IMA +__RET: + _RET + _end + + +__RST_00: + movl $0x00, %eax + jmp __RST +__RST_08: + movl $0x08, %eax + jmp __RST +__RST_10: + movl $0x10, %eax + jmp __RST +__RST_18: + movl $0x18, %eax + jmp __RST +__RST_20: + movl $0x20, %eax + jmp __RST +__RST_28: + movl $0x28, %eax + jmp __RST +__RST_30: + movl $0x30, %eax + jmp __RST +__RST_38: + movl $0x38, %eax +__RST: + pushl %eax + movl %ebp, %eax + _push + popl %ebp + _end + + + + + +__HALT: + movl $1, %eax + movl %eax, halt + _end + +__STOP: + movb KEY1, %al + testb $1, %al + jz .Loldstop + movb speed, %ah + xorb $1, %ah + movb %ah, speed + shlb $7, %ah + andb $0x7e, %al + orb %ah, %al + movb %al, KEY1 +.Loldstop: + incw %bp + _end + + +__CB_OPS: + _fetch + xorl %ecx, %ecx + movb cb_cycles_table(%eax), %cl + movl %ecx, %edi + jmp *cb_optable(,%eax,4) + + + + + + + _make_cb_ops B + _make_cb_ops C + _make_cb_ops D + _make_cb_ops E + _make_cb_ops H + _make_cb_ops L + +__RLC_A: + _RLC %bh + _end +__RRC_A: + _RRC %bh + _end +__RL_A: + _RL %bh + _end +__RR_A: + _RR %bh + _end +__SLA_A: + _SLA %bh + _end +__SRA_A: + _SRA %bh + _end +__SWAP_A: + _SWAP_A +__SRL_A: + _SRL %bh + _end +__BIT_0_A: _BIT 0, %bh +__BIT_1_A: _BIT 1, %bh +__BIT_2_A: _BIT 2, %bh +__BIT_3_A: _BIT 3, %bh +__BIT_4_A: _BIT 4, %bh +__BIT_5_A: _BIT 5, %bh +__BIT_6_A: _BIT 6, %bh +__BIT_7_A: _BIT 7, %bh +__RES_0_A: _RES 0, %bh +__RES_1_A: _RES 1, %bh +__RES_2_A: _RES 2, %bh +__RES_3_A: _RES 3, %bh +__RES_4_A: _RES 4, %bh +__RES_5_A: _RES 5, %bh +__RES_6_A: _RES 6, %bh +__RES_7_A: _RES 7, %bh +__SET_0_A: _SET 0, %bh +__SET_1_A: _SET 1, %bh +__SET_2_A: _SET 2, %bh +__SET_3_A: _SET 3, %bh +__SET_4_A: _SET 4, %bh +__SET_5_A: _SET 5, %bh +__SET_6_A: _SET 6, %bh +__SET_7_A: _SET 7, %bh + + _make_cb_hl_op RLC + _make_cb_hl_op RRC + _make_cb_hl_op RL + _make_cb_hl_op RR + _make_cb_hl_op SLA + _make_cb_hl_op SRA +__SWAP_$HL: + _SWAP_MEM + _make_cb_hl_op SRL + + _make_cb_hl_bit_op BIT, 0 + _make_cb_hl_bit_op BIT, 1 + _make_cb_hl_bit_op BIT, 2 + _make_cb_hl_bit_op BIT, 3 + _make_cb_hl_bit_op BIT, 4 + _make_cb_hl_bit_op BIT, 5 + _make_cb_hl_bit_op BIT, 6 + _make_cb_hl_bit_op BIT, 7 + + _make_cb_hl_bit_op RES, 0 + _make_cb_hl_bit_op RES, 1 + _make_cb_hl_bit_op RES, 2 + _make_cb_hl_bit_op RES, 3 + _make_cb_hl_bit_op RES, 4 + _make_cb_hl_bit_op RES, 5 + _make_cb_hl_bit_op RES, 6 + _make_cb_hl_bit_op RES, 7 + + _make_cb_hl_bit_op SET, 0 + _make_cb_hl_bit_op SET, 1 + _make_cb_hl_bit_op SET, 2 + _make_cb_hl_bit_op SET, 3 + _make_cb_hl_bit_op SET, 4 + _make_cb_hl_bit_op SET, 5 + _make_cb_hl_bit_op SET, 6 + _make_cb_hl_bit_op SET, 7 + + .text + .p2align 5 + +cpu_emulate: + pushl %ebp + pushl %ebx + pushl %esi + pushl %edi + + movl AF, %ebx + movl PC, %ebp + movl 20(%esp), %esi + cmpl $0, %esi + jle .Ldone + +.Lnext: + movl halt, %eax + andl IME, %eax + jnz .Lidle + +.Ldoop: + # check for pending interrupts + movl IME, %eax + testl %eax, %eax + jz .Lnoint + movb IF, %cl + movb IE, %al + andb %cl, %al + jnz .Lint + +.Lnoint: + # update interrupt master enable + movl IMA, %eax + movl %eax, IME +.Lendint: + + _trace + + _fetch + xorl %ecx, %ecx + movb cycles_table(%eax), %cl + movl %ecx, %edi + jmp *optable(,%eax,4) + +__NOP: +__LD_B_B: +__LD_C_C: +__LD_D_D: +__LD_E_E: +__LD_H_H: +__LD_L_L: +__LD_A_A: +opdone: + shll $1, %edi + + # advance div + movl %edi, %ecx + movb div, %al + addl %ecx, %ecx + movb DIV, %ah + addl %ecx, %eax + movb %al, div + movb %ah, DIV + + # advance timer + movb TAC, %cl + testb $0x04, %cl + jnz .Ltimer +.Lendtimer: + + movb speed, %cl + shrl %cl, %edi + + # advance lcdc + subl %edi, lcdc + jg .Lnolcdc + call lcdc_trans +.Lnolcdc: + + # increment sound cycle counter + addl %edi, snd + + # count off cycles used + subl %edi, %esi + jg .Lnext + jmp .Ldone + + +.Lint: + # throw an interrupt + xorl %edx, %edx + movb int_mask_table(%eax), %ch + movl %edx, IMA + andb %ch, %cl + movl %edx, IME + movb %cl, IF + movl int_vec_table(,%eax,4), %edx + movl %ebp, %eax + movl %edx, %ebp + _push + jmp .Lendint + + +.Ltimer: + xorb $0xff, %cl + movl %edi, %eax + incb %cl + movl tim, %edx + andb $0x03, %cl + addb %cl, %cl + + shll %cl, %eax + addl %eax, %edx + movl %edx, tim + cmpl $512, %edx + jl .Lendtimer + + xorl %eax, %eax + movl %edx, %ecx + movb TIMA, %al + shrl $9, %ecx + andl $0x1ff, %edx + addl %ecx, %eax + movl %edx, tim + movb %al, TIMA + cmpl $256, %eax + jl .Lendtimer + + movb $4, %cl + xorl %edx, %edx + orb %cl, IF + movl $256, %ecx + movb TMA, %dl + subl $256, %eax + subl %edx, %ecx +.Ltimermod: + subl %ecx, %eax + jnc .Ltimermod + movb %al, TIMA + jmp .Lendtimer + +.Ldone: + movl %ebx, AF + movl %ebp, PC + movl 20(%esp), %eax + subl %esi, %eax + + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + + +.Lidle: + pushl %esi + call cpu_idle + popl %ecx + testl %eax, %eax + jz .Ldoop + + subl %eax, %esi + jg .Lnext + jmp .Ldone + + + + +cpu_step: + movl 20(%esp), %edx + movl halt, %eax + andl IME, %eax + jz .Lruncpu + pushl %edx + pushl %edx + call cpu_idle + popl %edx + popl %edx + subl %eax, %edx + jnz .Lruncpu + ret +.Lruncpu: + pushl $1 + call cpu_emulate + popl %edx + ret + + + + + + + + diff --git a/asm/i386/lcd.s b/asm/i386/lcd.s new file mode 100644 index 0000000..6e8a87c --- /dev/null +++ b/asm/i386/lcd.s @@ -0,0 +1,290 @@ + +#include "asmnames.h" + + .set vram, lcd + .set buf, scan+512 + .set pal1, scan+768 + .set pal2, scan+896 + .set pal4, scan+1024 + + .set bg, scan + .set buf, scan+512 + .set u, scan+1792+24 + .set v, scan+1792+28 + .set wx, scan+1792+32 + + .data + .balign 4 + + + .text + .balign 32 + +debug: .string "%08x\n" + + .macro _print arg=0 + pushf + pusha + movl \arg, %eax + pushl %eax + pushl $debug + call printf + addl $8, %esp + popa + popf + .endm + + .macro _patexpand k=0 + movw (%esi,%ecx,2), %ax + andl $(0x0101<<\k), %eax + addb $0xff, %al + sbbb %bl, %bl + addb $0xff, %ah + sbbb %bh, %bh + andl $0x0201, %ebx + orb %bh, %bl + movb %bl, patpix+7-\k(%ebp,%ecx,8) + .endm + + .macro _fastswap k=0 + movl patpix+(16*\k)(%ebp), %eax + movl patpix+4+(16*\k)(%ebp), %ebx + movl patpix+8+(16*\k)(%ebp), %ecx + movl patpix+12+(16*\k)(%ebp), %edx + bswap %eax + bswap %ebx + bswap %ecx + bswap %edx + movl %eax, patpix+1024*64+4+(16*\k)(%ebp) + movl %ebx, patpix+1024*64+(16*\k)(%ebp) + movl %ecx, patpix+1024*64+12+(16*\k)(%ebp) + movl %edx, patpix+1024*64+8+(16*\k)(%ebp) + .endm + + + + .globl updatepatpix +updatepatpix: + movb anydirty, %al + testb %al, %al + jnz .Lupdatepatpix + ret + +.Lupdatepatpix: + pushl %ebp + pushl %ebx + pushl %esi + pushl %edi + + movl $895, %edi +.Lmainloop: + cmpl $511, %edi + jnz .Lnoskip + movl $383, %edi +.Lnoskip: + movb patdirty(%edi), %al + testb %al, %al + jnz .Lpatdirty + decl %edi + jnl .Lmainloop + jmp .Lend +.Lpatdirty: + movb $0, %al + movb %al, patdirty(%edi) + movl %edi, %eax + movl $vram, %esi + shll $4, %eax + addl %eax, %esi + + movl $7, %ecx + movl %edi, %ebp + shll $6, %ebp +.Lexpandline: + _patexpand 0 + _patexpand 1 + _patexpand 2 + _patexpand 3 + _patexpand 4 + _patexpand 5 + _patexpand 6 + _patexpand 7 + decl %ecx + jnl .Lexpandline + + _fastswap 0 + _fastswap 1 + _fastswap 2 + _fastswap 3 + + movl patpix(%ebp), %eax + movl patpix+4(%ebp), %ebx + movl patpix+8(%ebp), %ecx + movl patpix+12(%ebp), %edx + movl %eax, patpix+2048*64+56(%ebp) + movl %ebx, patpix+2048*64+60(%ebp) + movl %ecx, patpix+2048*64+48(%ebp) + movl %edx, patpix+2048*64+52(%ebp) + movl patpix+16(%ebp), %eax + movl patpix+20(%ebp), %ebx + movl patpix+24(%ebp), %ecx + movl patpix+28(%ebp), %edx + movl %eax, patpix+2048*64+40(%ebp) + movl %ebx, patpix+2048*64+44(%ebp) + movl %ecx, patpix+2048*64+32(%ebp) + movl %edx, patpix+2048*64+36(%ebp) + movl patpix+32(%ebp), %eax + movl patpix+36(%ebp), %ebx + movl patpix+40(%ebp), %ecx + movl patpix+44(%ebp), %edx + movl %eax, patpix+2048*64+24(%ebp) + movl %ebx, patpix+2048*64+28(%ebp) + movl %ecx, patpix+2048*64+16(%ebp) + movl %edx, patpix+2048*64+20(%ebp) + movl patpix+48(%ebp), %eax + movl patpix+52(%ebp), %ebx + movl patpix+56(%ebp), %ecx + movl patpix+60(%ebp), %edx + movl %eax, patpix+2048*64+8(%ebp) + movl %ebx, patpix+2048*64+12(%ebp) + movl %ecx, patpix+2048*64(%ebp) + movl %edx, patpix+2048*64+4(%ebp) + + movl patpix+1024*64(%ebp), %eax + movl patpix+1024*64+4(%ebp), %ebx + movl patpix+1024*64+8(%ebp), %ecx + movl patpix+1024*64+12(%ebp), %edx + movl %eax, patpix+3072*64+56(%ebp) + movl %ebx, patpix+3072*64+60(%ebp) + movl %ecx, patpix+3072*64+48(%ebp) + movl %edx, patpix+3072*64+52(%ebp) + movl patpix+1024*64+16(%ebp), %eax + movl patpix+1024*64+20(%ebp), %ebx + movl patpix+1024*64+24(%ebp), %ecx + movl patpix+1024*64+28(%ebp), %edx + movl %eax, patpix+3072*64+40(%ebp) + movl %ebx, patpix+3072*64+44(%ebp) + movl %ecx, patpix+3072*64+32(%ebp) + movl %edx, patpix+3072*64+36(%ebp) + movl patpix+1024*64+32(%ebp), %eax + movl patpix+1024*64+36(%ebp), %ebx + movl patpix+1024*64+40(%ebp), %ecx + movl patpix+1024*64+44(%ebp), %edx + movl %eax, patpix+3072*64+24(%ebp) + movl %ebx, patpix+3072*64+28(%ebp) + movl %ecx, patpix+3072*64+16(%ebp) + movl %edx, patpix+3072*64+20(%ebp) + movl patpix+1024*64+48(%ebp), %eax + movl patpix+1024*64+52(%ebp), %ebx + movl patpix+1024*64+56(%ebp), %ecx + movl patpix+1024*64+60(%ebp), %edx + movl %eax, patpix+3072*64+8(%ebp) + movl %ebx, patpix+3072*64+12(%ebp) + movl %ecx, patpix+3072*64(%ebp) + movl %edx, patpix+3072*64+4(%ebp) + + decl %edi + jnl .Lmainloop +.Lend: + movb $0, %al + movb %al, anydirty + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + + + + .globl bg_scan_color +bg_scan_color: + movb wx, %ch + cmpb $0, %ch + jb .Lbsc_done_nopop + pushl %ebx + pushl %ebp + pushl %esi + pushl %edi + movl v, %eax + movl $bg, %esi + movl $buf, %edi + leal patpix(,%eax,8), %ebp + movl (%esi), %eax + movl u, %ebx + shll $6, %eax + movb $-8, %cl + addl %ebx, %eax + addb %bl, %cl + movb 4(%esi), %bl + addl $8, %esi + addb %cl, %ch +.Lbsc_preloop: + movb (%ebp,%eax), %dl + incl %eax + orb %bl, %dl + movb %dl, (%edi) + incl %edi + incb %cl + jnz .Lbsc_preloop + cmpb $0, %ch + jb .Lbsc_done + subb $8, %ch +.Lbsc_loop: + movl (%esi), %eax + movl 4(%esi), %edx + shll $6, %eax + movb %dl, %dh + addl $8, %esi + movl %edx, %ebx + rorl $16, %edx + orl %edx, %ebx + movl (%ebp,%eax), %edx + orl %ebx, %edx + movl %edx, (%edi) + movl 4(%ebp,%eax), %edx + orl %ebx, %edx + movl %edx, 4(%edi) + addl $8, %edi + subb $8, %ch + jae .Lbsc_loop + addb $8, %ch + jz .Lbsc_done + movl (%esi), %eax + shll $6, %eax + movb 4(%esi), %bl +.Lbsc_postloop: + movb (%ebp,%eax), %dl + incl %eax + orb %bl, %dl + movb %dl, (%edi) + incl %edi + decb %ch + jnz .Lbsc_postloop +.Lbsc_done: + popl %edi + popl %esi + popl %ebp + popl %ebx +.Lbsc_done_nopop: + ret + + + + + + + + + + + + + + + + + + + + + + diff --git a/asm/i386/refresh.s b/asm/i386/refresh.s new file mode 100644 index 0000000..2d09196 --- /dev/null +++ b/asm/i386/refresh.s @@ -0,0 +1,285 @@ + + +#include "asmnames.h" + + .text + + .macro _enter + pushl %ebx + pushl %ebp + pushl %esi + pushl %edi + movl 20(%esp), %edi + movl 24(%esp), %esi + movl 28(%esp), %ebp + movl 32(%esp), %ecx + xorl %eax, %eax + xorl %ebx, %ebx + .endm + + .macro _leave + popl %edi + popl %esi + popl %ebp + popl %ebx + ret + .endm + + + .globl refresh_1 +refresh_1: + _enter + subl $4, %esi + subl $4, %edi + shrl $2, %ecx +.Lrefresh_1: + movb 2(%esi,%ecx,4), %al + movb 3(%esi,%ecx,4), %bl + movb (%ebp, %eax), %dl + movb (%esi,%ecx,4), %al + movb (%ebp, %ebx), %dh + movb 1(%esi,%ecx,4), %bl + rorl $16, %edx + movb (%ebp, %eax), %dl + movb (%ebp, %ebx), %dh + movl %edx, (%edi,%ecx,4) + decl %ecx + jnz .Lrefresh_1 + _leave + + .globl refresh_2 +refresh_2: + _enter + subl $2, %esi + subl $4, %edi + shrl $1, %ecx +.Lrefresh_2: + movb 1(%esi,%ecx,2), %al + movb (%esi,%ecx,2), %bl + movw (%ebp,%eax,2), %dx + rorl $16, %edx + movw (%ebp,%ebx,2), %dx + movl %edx, (%edi,%ecx,4) + decl %ecx + jnz .Lrefresh_2 + _leave + + .globl refresh_3 +refresh_3: + _enter + subl $2, %esi + leal (%ecx,%ecx,2), %edx + shrl $1, %ecx + addl %edx, %edi +.Lrefresh_3: + movb (%esi,%ecx,2), %al + subl $6, %edi + movb 1(%esi,%ecx,2), %bl + movl (%ebp,%eax,4), %edx + movb %dl, (%edi) + movb 2(%ebp,%eax,4), %dl + movb %dh, 1(%edi) + movb %dl, 2(%edi) + movl (%ebp,%ebx,4), %edx + movb %dl, 3(%edi) + movb 2(%ebp,%ebx,4), %dl + movb %dh, 4(%edi) + movb %dl, 5(%edi) + decl %ecx + jnz .Lrefresh_3 + _leave + + .globl refresh_4 +refresh_4: + _enter + subl $2, %esi + subl $8, %edi + shrl $1, %ecx +.Lrefresh_4: + movb (%esi,%ecx,2), %al + movb 1(%esi,%ecx,2), %bl + movl (%ebp,%eax,4), %edx + movl %edx, (%edi,%ecx,8) + movl (%ebp,%ebx,4), %edx + movl %edx, 4(%edi,%ecx,8) + decl %ecx + jnz .Lrefresh_4 + _leave + + + + .globl refresh_1_2x +refresh_1_2x: + _enter + subl $2, %esi + subl $4, %edi + shrl $1, %ecx +.Lrefresh_1_2x: + movb 1(%esi,%ecx,2), %al + movb (%esi,%ecx,2), %bl + movb (%ebp,%eax), %al + movb %al, %dl + movb %al, %dh + movb (%ebp,%ebx), %bl + rorl $16, %edx + movb %bl, %dl + movb %bl, %dh + movl %edx, (%edi,%ecx,4) + decl %ecx + jnz .Lrefresh_1_2x + _leave + + + + + .globl refresh_2_2x +refresh_2_2x: + _enter + subl $2, %esi + subl $8, %edi + shrl $1, %ecx +.Lrefresh_2_2x: + movb (%esi,%ecx,2), %al + movb 1(%esi,%ecx,2), %bl + movw (%ebp,%eax,2), %dx + rorl $16, %edx + movw (%ebp,%eax,2), %dx + movl %edx, (%edi,%ecx,8) + movw (%ebp,%ebx,2), %dx + rorl $16, %edx + movw (%ebp,%ebx,2), %dx + movl %edx, 4(%edi,%ecx,8) + decl %ecx + jnz .Lrefresh_2_2x + _leave + + + + .globl refresh_4_2x +refresh_4_2x: + _enter + subl $2, %esi + subl $16, %edi +.Lrefresh_4_2x: + movb (%esi,%ecx), %al + movb 1(%esi,%ecx), %bl + movl (%ebp,%eax,4), %edx + movl %edx, (%edi,%ecx,8) + movl %edx, 4(%edi,%ecx,8) + movl (%ebp,%ebx,4), %edx + movl %edx, 8(%edi,%ecx,8) + movl %edx, 12(%edi,%ecx,8) + subl $2, %ecx + jnz .Lrefresh_4_2x + _leave + + + + + .globl refrsh_1_3x +refresh_1_3x: + _enter + leal (%ecx,%ecx,2), %edx + shrl $1, %ecx + addl %edx, %edi + subl $2, %esi +.Lrefresh_1_3x: + movb (%esi,%ecx,2), %al + subl $6, %edi + movb 1(%esi,%ecx,2), %bl + movb (%ebp,%eax,2), %dl + movb %dl, (%edi) + movb %dl, 1(%edi) + movb %dl, 2(%edi) + movb (%ebp,%ebx,2), %dl + movb %dl, 3(%edi) + movb %dl, 4(%edi) + movb %dl, 5(%edi) + decl %ecx + jnz .Lrefresh_1_3x + _leave + + + .globl refresh_2_3x +refresh_2_3x: + _enter + shll $1, %ecx + addl %ecx, %edi + addl %ecx, %edi + addl %ecx, %edi + shrl $2, %ecx + subl $2, %esi +.Lrefresh_2_3x: + movb (%esi,%ecx,2), %al + subl $12, %edi + movb 1(%esi,%ecx,2), %bl + movw (%ebp,%eax,2), %dx + movw %dx, (%edi) + movw %dx, 2(%edi) + movw %dx, 4(%edi) + movw (%ebp,%ebx,2), %dx + movw %dx, 6(%edi) + movw %dx, 8(%edi) + movw %dx, 10(%edi) + decl %ecx + jnz .Lrefresh_2_3x + _leave + + + + .globl refresh_4_3x +refresh_4_3x: + _enter + shll $2, %ecx + addl %ecx, %edi + addl %ecx, %edi + addl %ecx, %edi + shrl $3, %ecx + subl $2, %esi +.Lrefresh_4_3x: + movb (%esi,%ecx,2), %al + subl $24, %edi + movb 1(%esi,%ecx,2), %bl + movl (%ebp,%eax,4), %edx + movl %edx, (%edi) + movl %edx, 4(%edi) + movl %edx, 8(%edi) + movl (%ebp,%ebx,4), %edx + movl %edx, 12(%edi) + movl %edx, 16(%edi) + movl %edx, 20(%edi) + decl %ecx + jnz .Lrefresh_4_3x + _leave + + + .globl refresh_4_4x +refresh_4_4x: + _enter + shll $4, %ecx + addl %ecx, %edi + shrl $5, %ecx + subl $2, %esi +.Lrefresh_4_4x: + movb (%esi,%ecx,2), %al + subl $32, %edi + movb 1(%esi,%ecx,2), %bl + movl (%ebp,%eax,4), %edx + movl %edx, (%edi) + movl %edx, 4(%edi) + movl %edx, 8(%edi) + movl %edx, 12(%edi) + movl (%ebp,%ebx,4), %edx + movl %edx, 16(%edi) + movl %edx, 20(%edi) + movl %edx, 24(%edi) + movl %edx, 28(%edi) + decl %ecx + jnz .Lrefresh_4_4x + _leave + + + + + + diff --git a/configure b/configure new file mode 100755 index 0000000..d9272be --- /dev/null +++ b/configure @@ -0,0 +1,4095 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by Autoconf 2.52. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Name of the executable. +as_me=`echo "$0" |sed 's,.*[\\/],,'` + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +# NLS nuisances. +$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } +$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } +$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } +$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } +$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } +$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } +$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } +$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; } + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +cross_compiling=no +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +ac_unique_file="cpu.c" + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: should be removed in autoconf 3.0. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat < if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +EOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue + cd $ac_subdir + # A "../" for each directory in /$ac_subdir. + ac_dots=`echo $ac_subdir | + sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'` + + case $srcdir in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_subdir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure.gnu; then + echo + $SHELL $ac_sub_srcdir/configure.gnu --help=recursive + elif test -f $ac_sub_srcdir/configure; then + echo + $SHELL $ac_sub_srcdir/configure --help=recursive + elif test -f $ac_sub_srcdir/configure.ac || + test -f $ac_sub_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\EOF + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +EOF + exit 0 +fi +exec 5>config.log +cat >&5 </dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +PATH = $PATH + +_ASUNAME +} >&5 + +cat >&5 <\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + ac_sep=" " ;; + *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg" + ac_sep=" " ;; + esac + # Get rid of the leading space. +done + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + echo >&5 + echo "## ----------------- ##" >&5 + echo "## Cache variables. ##" >&5 + echo "## ----------------- ##" >&5 + echo >&5 + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} >&5 + sed "/^$/d" confdefs.h >conftest.log + if test -s conftest.log; then + echo >&5 + echo "## ------------ ##" >&5 + echo "## confdefs.h. ##" >&5 + echo "## ------------ ##" >&5 + echo >&5 + cat conftest.log >&5 + fi + (echo; echo) >&5 + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" >&5 + echo "$as_me: exit $exit_status" >&5 + rm -rf conftest* confdefs* core core.* *.core conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:841: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + cat "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:852: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:860: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:876: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:880: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:886: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:888: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:890: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. It doesn't matter if + # we pass some twice (in addition to the command line arguments). + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + *) ac_configure_args="$ac_configure_args $ac_var=$ac_new_val" + ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:909: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:911: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac +echo "#! $SHELL" >conftest.sh +echo "exit 0" >>conftest.sh +chmod +x conftest.sh +if { (echo "$as_me:931: PATH=\".;.\"; conftest.sh") >&5 + (PATH=".;."; conftest.sh) 2>&5 + ac_status=$? + echo "$as_me:934: \$? = $ac_status" >&5 + (exit $ac_status); }; then + ac_path_separator=';' +else + ac_path_separator=: +fi +PATH_SEPARATOR="$ac_path_separator" +rm -f conftest.sh + +CFLAGS="$CFLAGS" + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:953: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="${ac_tool_prefix}gcc" +echo "$as_me:968: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:976: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:979: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:988: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="gcc" +echo "$as_me:1003: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:1011: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:1014: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:1027: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="${ac_tool_prefix}cc" +echo "$as_me:1042: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:1050: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:1053: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:1062: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="cc" +echo "$as_me:1077: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:1085: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:1088: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:1101: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue +fi +ac_cv_prog_CC="cc" +echo "$as_me:1121: found $ac_dir/$ac_word" >&5 +break +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" ${1+"$@"} + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:1143: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:1146: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:1157: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_CC="$ac_tool_prefix$ac_prog" +echo "$as_me:1172: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:1180: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:1183: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:1196: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_ac_ct_CC="$ac_prog" +echo "$as_me:1211: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:1219: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:1222: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + +test -z "$CC" && { { echo "$as_me:1234: error: no acceptable cc found in \$PATH" >&5 +echo "$as_me: error: no acceptable cc found in \$PATH" >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:1239:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:1242: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:1245: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:1247: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:1250: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:1252: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:1255: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line 1259 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:1275: checking for C compiler default output" >&5 +echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:1278: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:1281: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. +for ac_file in `ls a.exe conftest.exe 2>/dev/null; + ls a.out conftest 2>/dev/null; + ls a.* conftest.* 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + a.out ) # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool --akim. + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:1304: error: C compiler cannot create executables" >&5 +echo "$as_me: error: C compiler cannot create executables" >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:1310: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:1315: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:1321: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1324: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:1331: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:1339: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:1346: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:1348: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:1351: checking for executable suffix" >&5 +echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6 +if { (eval echo "$as_me:1353: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:1356: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:1372: error: cannot compute EXEEXT: cannot compile and link" >&5 +echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:1378: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:1384: checking for object suffix" >&5 +echo $ECHO_N "checking for object suffix... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 1390 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:1402: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1405: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:1417: error: cannot compute OBJEXT: cannot compile" >&5 +echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:1424: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:1428: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 1434 "configure" +#include "confdefs.h" + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1449: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1452: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1455: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1458: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:1470: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:1476: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 1482 "configure" +#include "confdefs.h" + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1494: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1497: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1500: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1503: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_prog_cc_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:1513: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1540: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1543: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1546: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1549: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + ''\ + '#include ' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line 1561 "configure" +#include "confdefs.h" +#include +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1574: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1577: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1580: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1583: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line 1593 "configure" +#include "confdefs.h" +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1605: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1608: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1611: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1614: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:1646: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line 1667 "configure" +#include "confdefs.h" +#include + Syntax error +_ACEOF +if { (eval echo "$as_me:1672: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1678: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line 1701 "configure" +#include "confdefs.h" +#include +_ACEOF +if { (eval echo "$as_me:1705: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1711: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:1748: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line 1758 "configure" +#include "confdefs.h" +#include + Syntax error +_ACEOF +if { (eval echo "$as_me:1763: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1769: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line 1792 "configure" +#include "confdefs.h" +#include +_ACEOF +if { (eval echo "$as_me:1796: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:1802: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:1830: error: C preprocessor \"$CPP\" fails sanity check" >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:1858: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:1878: checking for a BSD compatible install" >&5 +echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_IFS=$IFS; IFS=$ac_path_separator + for ac_dir in $PATH; do + IFS=$ac_save_IFS + # Account for people who put trailing slashes in PATH elements. + case $ac_dir/ in + / | ./ | .// | /cC/* \ + | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \ + | /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if $as_executable_p "$ac_dir/$ac_prog"; then + if test $ac_prog = install && + grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:1927: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +test "$cross_compiling" = "yes" || +echo "$as_me:1939: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +#line 1947 "configure" +#include "confdefs.h" +#include +#include + +int +main () +{ +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1964: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1967: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:1970: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:1973: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +#line 1977 "configure" +#include "confdefs.h" +#include +#include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:1994: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:1997: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:2000: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2003: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_c_bigendian=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { { echo "$as_me:2019: error: cannot run test program while cross compiling" >&5 +echo "$as_me: error: cannot run test program while cross compiling" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +#line 2024 "configure" +#include "confdefs.h" +int +main () +{ + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:2040: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:2043: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:2045: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2048: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_c_bigendian=yes +fi +rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:2061: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6 +if test $ac_cv_c_bigendian = yes; then + +cat >>confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + +test "$ac_cv_c_bigendian" = "no" && ENDIAN="-DIS_LITTLE_ENDIAN" + +for ac_func in usleep +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:2076: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2082 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +char (*f) (); + +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +f = $ac_func; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:2113: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:2116: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:2119: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2122: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:2132: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2150 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +char (*f) (); + +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +f = $ac_func; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:2181: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:2184: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:2187: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2190: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:2200: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <&5 +echo "$as_me: error: your system must support either usleep or select" >&2;} + { (exit 1); exit 1; }; } + +fi +done + +fi +done + +LIBS="$LIBS -L/usr/local/lib -L/usr/X11R6/lib" + +# Check whether --with-fb or --without-fb was given. +if test "${with_fb+set}" = set; then + withval="$with_fb" + +else + with_fb=yes +fi; + +# Check whether --with-svgalib or --without-svgalib was given. +if test "${with_svgalib+set}" = set; then + withval="$with_svgalib" + +else + with_svgalib=yes +fi; + +# Check whether --with-sdl or --without-sdl was given. +if test "${with_sdl+set}" = set; then + withval="$with_sdl" + +else + with_sdl=yes +fi; + +SOUND="" +JOY="" + +case `uname -s` in +Linux) +SYS_DEFS=-DIS_LINUX + +for ac_header in sys/soundcard.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:2255: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2261 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2265: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2271: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2290: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2309 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2313: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2319: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2338: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2358 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2362: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2368: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2387: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2410 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2414: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2420: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2439: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2462 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2466: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2472: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2491: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for vga_init in -lvga... $ECHO_C" >&6 +if test "${ac_cv_lib_vga_vga_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lvga $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 2521 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vga_init (); +int +main () +{ +vga_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:2540: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:2543: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:2546: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2549: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_vga_vga_init=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_vga_vga_init=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:2560: result: $ac_cv_lib_vga_vga_init" >&5 +echo "${ECHO_T}$ac_cv_lib_vga_vga_init" >&6 +if test $ac_cv_lib_vga_vga_init = yes; then + +for ac_header in vga.h vgakeyboard.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:2567: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2573 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2577: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2583: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2602: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo "$as_me: WARNING: svgalib found but headers are missing!!" >&2;} +with_svgalib=no + +fi +done + +else + with_svgalib=no +fi + +fi + +if test "$with_sdl" != "no" ; then +# Extract the first word of "sdl-config", so it can be a program name with args. +set dummy sdl-config; ac_word=$2 +echo "$as_me:2627: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_SDL_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$SDL_CONFIG"; then + ac_cv_prog_SDL_CONFIG="$SDL_CONFIG" # Let the user override the test. +else + ac_save_IFS=$IFS; IFS=$ac_path_separator +ac_dummy="$PATH" +for ac_dir in $ac_dummy; do + IFS=$ac_save_IFS + test -z "$ac_dir" && ac_dir=. + $as_executable_p "$ac_dir/$ac_word" || continue +ac_cv_prog_SDL_CONFIG="yes" +echo "$as_me:2642: found $ac_dir/$ac_word" >&5 +break +done + +fi +fi +SDL_CONFIG=$ac_cv_prog_SDL_CONFIG +if test -n "$SDL_CONFIG"; then + echo "$as_me:2650: result: $SDL_CONFIG" >&5 +echo "${ECHO_T}$SDL_CONFIG" >&6 +else + echo "$as_me:2653: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test "$SDL_CONFIG" ; then +SDL_LIBS="`sdl-config --libs`" +SDL_CFLAGS="`sdl-config --cflags`" +old_incs="$INCS" +INCS="$INCS $SDL_CFLAGS" +echo "$as_me:2662: checking for SDL_Init in -lSDL" >&5 +echo $ECHO_N "checking for SDL_Init in -lSDL... $ECHO_C" >&6 +if test "${ac_cv_lib_SDL_SDL_Init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lSDL $SDL_LIBS $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 2670 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char SDL_Init (); +int +main () +{ +SDL_Init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:2689: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:2692: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:2695: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2698: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_SDL_SDL_Init=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_SDL_SDL_Init=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:2709: result: $ac_cv_lib_SDL_SDL_Init" >&5 +echo "${ECHO_T}$ac_cv_lib_SDL_SDL_Init" >&6 +if test $ac_cv_lib_SDL_SDL_Init = yes; then + +for ac_header in SDL/SDL.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:2716: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 2722 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:2726: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2732: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:2751: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo "$as_me: WARNING: SDL found but headers are missing!!" >&2;} +with_sdl=no + +fi +done + +else + with_sdl=no +fi + +INCS="$old_incs" +else +with_sdl=no +fi +fi + +echo "$as_me:2777: checking for X" >&5 +echo $ECHO_N "checking for X... $ECHO_C" >&6 + +# Check whether --with-x or --without-x was given. +if test "${with_x+set}" = set; then + withval="$with_x" + +fi; +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then + # Both variables are already set. + have_x=yes + else + if test "${ac_cv_have_x+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -fr conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + # Make sure to not put "make" in the Imakefile rules, since we grep it out. + cat >Imakefile <<'EOF' +acfindx: + @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' +EOF + if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl; do + if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && + test -f $ac_im_libdir/libX11.$ac_extension; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /lib) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -fr conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Intrinsic.h. + # First, try using that file with no special directory specified. + cat >conftest.$ac_ext <<_ACEOF +#line 2874 "configure" +#include "confdefs.h" +#include +_ACEOF +if { (eval echo "$as_me:2878: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:2884: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # We can compile using X headers with no special include directory. +ac_x_includes= +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Intrinsic.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lXt $LIBS" + cat >conftest.$ac_ext <<_ACEOF +#line 2917 "configure" +#include "confdefs.h" +#include +int +main () +{ +XtMalloc (0) + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:2929: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:2932: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:2935: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:2938: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +LIBS=$ac_save_LIBS +for ac_dir in `echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/libXt.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +if test "$ac_x_includes" = no || test "$ac_x_libraries" = no; then + # Didn't find X anywhere. Cache the known absence of X. + ac_cv_have_x="have_x=no" +else + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" +fi +fi + + fi + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + echo "$as_me:2976: result: $have_x" >&5 +echo "${ECHO_T}$have_x" >&6 + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes \ + ac_x_includes=$x_includes ac_x_libraries=$x_libraries" + echo "$as_me:2986: result: libraries $x_libraries, headers $x_includes" >&5 +echo "${ECHO_T}libraries $x_libraries, headers $x_includes" >&6 +fi + +if test "$no_x" != "yes" ; then +with_x=yes + +echo "$as_me:2993: checking for XShmCreateImage in -lXext" >&5 +echo $ECHO_N "checking for XShmCreateImage in -lXext... $ECHO_C" >&6 +if test "${ac_cv_lib_Xext_XShmCreateImage+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lXext $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line 3001 "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char XShmCreateImage (); +int +main () +{ +XShmCreateImage (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:3020: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:3023: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:3026: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:3029: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_Xext_XShmCreateImage=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_Xext_XShmCreateImage=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:3040: result: $ac_cv_lib_Xext_XShmCreateImage" >&5 +echo "${ECHO_T}$ac_cv_lib_Xext_XShmCreateImage" >&6 +if test $ac_cv_lib_Xext_XShmCreateImage = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 3060 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:3064: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:3070: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:3089: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 +echo "${ECHO_T}enabling selected compiler warnings" >&6 +CFLAGS="$CFLAGS -ansi -pedantic -Wall -Wno-implicit -Wno-long-long" ;; +*) +echo "$as_me:3155: result: disabling warnings for non-gcc compiler" >&5 +echo "${ECHO_T}disabling warnings for non-gcc compiler" >&6 ;; +esac +fi + +if test "$enable_debug" = yes ; then +echo "$as_me:3161: result: including debugging symbols" >&5 +echo "${ECHO_T}including debugging symbols" >&6 +CFLAGS="$CFLAGS -g" +fi + +if test "$enable_profile" = yes ; then +echo "$as_me:3167: result: enabling performance profiling" >&5 +echo "${ECHO_T}enabling performance profiling" >&6 +CFLAGS="$CFLAGS -pg" +fi + +if test "$enable_arch" = yes ; then +if test `uname -s` = Linux -a -f /proc/cpuinfo ; then +case `grep "model name" /proc/cpuinfo` in +*AMD-K6*) enable_arch=k6 ;; +*Pentium*Pro*|*Pentium\ I*|*Klamath*) enable_arch=i686 ;; +*Pentium*|*586*) enable_arch=i586 ;; +*486*) enable_arch=i486 ;; +*386*) enable_arch=i386 ;; +*) enable_arch=no ;; +esac +else +enable_arch=no +#case `uname -m` in +#i686) enable_arch=i686 ;; +#i586) enable_arch=i586 ;; +#i486) enable_arch=i486 ;; +#i386) enable_arch=i386 ;; +#*) enable_arch=no ;; +#esac +fi +fi + +case `$CC --version` in + +2.9*|3.*) + +case "$enable_arch" in +k6|i686|i586|i486|i386) CFLAGS="$CFLAGS -march=$enable_arch" ;; +no) ;; +*) { echo "$as_me:3201: WARNING: unknown architecture $enable_arch" >&5 +echo "$as_me: WARNING: unknown architecture $enable_arch" >&2;} ;; +esac ;; + +*) + +case "$enable_arch" in +k6|i686|i586) { echo "$as_me:3208: WARNING: your compiler is too old to support $enable_arch optimizations" >&5 +echo "$as_me: WARNING: your compiler is too old to support $enable_arch optimizations" >&2;} ;; +i486) CFLAGS="$CFLAGS -m486" ;; +i386) CFLAGS="$CFLAGS -m386" ;; +no) ;; +*) { echo "$as_me:3213: WARNING: unknown architecture $enable_arch" >&5 +echo "$as_me: WARNING: unknown architecture $enable_arch" >&2;} ;; +esac ;; + +esac + +case "$enable_optimize" in +yes|full) +echo "$as_me:3221: result: producing heavily optimized code" >&5 +echo "${ECHO_T}producing heavily optimized code" >&6 + +CFLAGS="$CFLAGS -O3" + +case `uname -m` in +i?86) CFLAGS="$CFLAGS -DALLOW_UNALIGNED_IO" ;; +esac + +#case `$CC --version` in +#2.9*|3.*) +CFLAGS="$CFLAGS -fstrength-reduce -fthread-jumps \ + -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop \ + -fexpensive-optimizations -fforce-mem -fforce-addr" +#;; +#*) +#AC_MSG_WARN(your compiler is too old for fancy optimizations) +#;; +#esac + +if test "$enable_debug" != yes -a "$enable_profile" != yes ; then +CFLAGS="$CFLAGS -fomit-frame-pointer" +LDFLAGS="$LDFLAGS -s" +fi ;; + +low) + +echo "$as_me:3248: result: using minimal optimizations" >&5 +echo "${ECHO_T}using minimal optimizations" >&6 +CFLAGS="$CFLAGS -O3" ;; + +esac + +if test "$enable_asm" = yes ; then +case `uname -m` in +i?86) +echo "$as_me:3257: result: using optimized i386 cores" >&5 +echo "${ECHO_T}using optimized i386 cores" >&6 +ASM="-DUSE_ASM -I./asm/i386" ; ASM_OBJS="asm/i386/cpu.o asm/i386/lcd.o asm/i386/refresh.s" ;; +*) +echo "$as_me:3261: result: no optimized asm core available for \`uname -m\`" >&5 +echo "${ECHO_T}no optimized asm core available for \`uname -m\`" >&6 ;; +esac +fi + +ac_config_headers="$ac_config_headers sys/nix/config.h" + +ac_config_files="$ac_config_files Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overriden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if cmp -s $cache_file confcache; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:3348: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +SHELL=\${CONFIG_SHELL-$SHELL} +ac_cs_invocation="\$0 \$@" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Name of the executable. +as_me=`echo "$0" |sed 's,.*[\\/],,'` + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +# NLS nuisances. +$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } +$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } +$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } +$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } +$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } +$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } +$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } +$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; } + +exec 6>&1 + +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\EOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." +EOF + +cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + shift + set dummy "$ac_option" "$ac_optarg" ${1+"$@"} + shift + ;; + -*);; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_need_defaults=false;; + esac + + case $1 in + # Handling of the options. +EOF +cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:3521: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + shift + CONFIG_FILES="$CONFIG_FILES $1" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + shift + CONFIG_HEADERS="$CONFIG_HEADERS $1" + ac_need_defaults=false;; + + # This is an error. + -*) { { echo "$as_me:3540: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +exec 5>>config.log +cat >&5 << _ACEOF + +## ----------------------- ## +## Running config.status. ## +## ----------------------- ## + +This file was extended by $as_me 2.52, executed with + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + > $ac_cs_invocation +on `(hostname || uname -n) 2>/dev/null | sed 1q` + +_ACEOF +EOF + +cat >>$CONFIG_STATUS <<\EOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "sys/nix/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS sys/nix/config.h" ;; + *) { { echo "$as_me:3577: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/cs$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + +EOF + +cat >>$CONFIG_STATUS <\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@DEFS@,$DEFS,;t t +s,@LIBS@,$LIBS,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CPP@,$CPP,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@SDL_CONFIG@,$SDL_CONFIG,;t t +s,@SYS_DEFS@,$SYS_DEFS,;t t +s,@ENDIAN@,$ENDIAN,;t t +s,@SOUND@,$SOUND,;t t +s,@JOY@,$JOY,;t t +s,@ASM@,$ASM,;t t +s,@ASM_OBJS@,$ASM_OBJS,;t t +s,@FB_OBJS@,$FB_OBJS,;t t +s,@SDL_CFLAGS@,$SDL_CFLAGS,;t t +s,@SDL_LIBS@,$SDL_LIBS,;t t +s,@TARGETS@,$TARGETS,;t t +s,@XINCS@,$XINCS,;t t +s,@XLIBS@,$XLIBS,;t t +CEOF + +EOF + + cat >>$CONFIG_STATUS <<\EOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +EOF +cat >>$CONFIG_STATUS <<\EOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || mkdir "$as_incr_dir" + ;; + esac +done; } + + ac_dir_suffix="/`echo $ac_dir|sed 's,^\./,,'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo "$ac_dir_suffix" | sed 's,/[^/]*,../,g'` + else + ac_dir_suffix= ac_dots= + fi + + case $srcdir in + .) ac_srcdir=. + if test -z "$ac_dots"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_dots | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_dots$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_dots$srcdir ;; + esac + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_dots$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:3796: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated automatically by config.status. */ + configure_input="Generated automatically from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:3814: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:3827: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +EOF +cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +EOF +cat >>$CONFIG_STATUS <<\EOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:3888: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:3899: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:3912: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +EOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\EOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\(\([^ (][^ (]*\)([^)]*)\)[ ]*\(.*\)$,${ac_dA}\2${ac_dB}\1${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +EOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\EOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +EOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if egrep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # egrep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\EOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated automatically by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated automatically by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated automatically by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + { echo "$as_me:4029: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || mkdir "$as_incr_dir" + ;; + esac +done; } + + fi + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +EOF + +cat >>$CONFIG_STATUS <<\EOF + +{ (exit 0); exit 0; } +EOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + exec 5>/dev/null + $SHELL $CONFIG_STATUS || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..f42907a --- /dev/null +++ b/configure.in @@ -0,0 +1,259 @@ + +AC_INIT(cpu.c) + +CFLAGS="$CFLAGS" + +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL + + +test "$cross_compiling" = "yes" || AC_C_BIGENDIAN +test "$ac_cv_c_bigendian" = "no" && ENDIAN="-DIS_LITTLE_ENDIAN" + + + +AC_CHECK_FUNCS(usleep, ,[ +AC_CHECK_FUNCS(select, ,[ +AC_MSG_ERROR(your system must support either usleep or select) +])]) + + + + +LIBS="$LIBS -L/usr/local/lib -L/usr/X11R6/lib" + + + + + +AC_ARG_WITH(fb, [ --with-fb build framebuffer device interface], [], [with_fb=yes]) +AC_ARG_WITH(svgalib, [ --with-svgalib build Linux svgalib interface], [], [with_svgalib=yes]) +AC_ARG_WITH(sdl, [ --with-sdl build SDL interface], [], [with_sdl=yes]) + + + + + +SOUND="" +JOY="" + +case `uname -s` in +Linux) +SYS_DEFS=-DIS_LINUX +AC_CHECK_HEADERS(sys/soundcard.h, [SOUND=sys/oss/oss.o]) +AC_CHECK_HEADERS(linux/joystick.h, [JOY=sys/linux/joy.o]) +test "$with_fb" = "no" || AC_CHECK_HEADERS(linux/fb.h, [with_fb=linux]) +;; +FreeBSD) +SYS_DEFS=-DIS_FBSD +AC_CHECK_HEADERS(machine/soundcard.h, [SOUND=sys/oss/oss.o]) +;; +OpenBSD) +SYS_DEFS=-DIS_OBSD +AC_CHECK_HEADERS(soundcard.h, [SOUND=sys/oss/oss.o]) +;; +esac + +test "$SOUND" || SOUND=sys/dummy/nosound.o +test "$JOY" || JOY=sys/dummy/nojoy.o + + + + + + +case "$with_fb" in +linux) FB_OBJS="sys/linux/fbdev.o sys/linux/kb.o sys/pc/keymap.o" ;; +*) FB_OBJS="" ; with_fb=no ;; +esac + +if test "$with_svgalib" != "no" ; then +AC_CHECK_LIB(vga, vga_init, [ +AC_CHECK_HEADERS(vga.h vgakeyboard.h, ,[ +AC_MSG_WARN(svgalib found but headers are missing!!) +with_svgalib=no +])], [with_svgalib=no]) +fi + +if test "$with_sdl" != "no" ; then +AC_CHECK_PROG(SDL_CONFIG, sdl-config, yes) +if test "$SDL_CONFIG" ; then +SDL_LIBS="`sdl-config --libs`" +SDL_CFLAGS="`sdl-config --cflags`" +old_incs="$INCS" +INCS="$INCS $SDL_CFLAGS" +AC_CHECK_LIB(SDL, SDL_Init, [ +AC_CHECK_HEADERS(SDL/SDL.h, ,[ +AC_MSG_WARN(SDL found but headers are missing!!) +with_sdl=no +])], [with_sdl=no], $SDL_LIBS) +INCS="$old_incs" +else +with_sdl=no +fi +fi + +AC_PATH_X + +if test "$no_x" != "yes" ; then +with_x=yes +AC_CHECK_LIB(Xext, XShmCreateImage) +AC_CHECK_HEADERS(sys/ipc.h sys/shm.h X11/extensions/XShm.h) +test "$x_includes" && XINCS="-I$x_includes" +test "$x_libraries" && XLIBS="-L$x_libraries" +else +with_x=no +fi + + + +test "$with_x" = "no" || TARGETS="$TARGETS xgnuboy" +test "$with_fb" = "no" || TARGETS="$TARGETS fbgnuboy" +test "$with_svgalib" = "no" || TARGETS="$TARGETS sgnuboy" +test "$with_sdl" = "no" || TARGETS="$TARGETS sdlgnuboy" + + + + + + + + + + +AC_ARG_ENABLE(warnings, [ --enable-warnings enable selected compiler warnings], [], [enable_warnings=yes]) +AC_ARG_ENABLE(debug, [ --enable-debug include debugging symbols], []) +AC_ARG_ENABLE(profile, [ --enable-profile enable performance profiling], []) +AC_ARG_ENABLE(arch, [ --enable-arch compile for specific host cpu architecture], [], [enable_arch=yes]) +AC_ARG_ENABLE(optimize, [ --enable-optimize=LEVEL select optimization level (full,low,none)], [], [enable_optimize=yes]) +AC_ARG_ENABLE(asm, [ --enable-asm use hand-optimized asm cores], [], [enable_asm=yes]) + + +if test "$enable_warnings" = yes ; then +case "$CC" in *gcc*) +AC_MSG_RESULT(enabling selected compiler warnings) +CFLAGS="$CFLAGS -ansi -pedantic -Wall -Wno-implicit -Wno-long-long" ;; +*) +AC_MSG_RESULT(disabling warnings for non-gcc compiler) ;; +esac +fi + +if test "$enable_debug" = yes ; then +AC_MSG_RESULT(including debugging symbols) +CFLAGS="$CFLAGS -g" +fi + +if test "$enable_profile" = yes ; then +AC_MSG_RESULT(enabling performance profiling) +CFLAGS="$CFLAGS -pg" +fi + +if test "$enable_arch" = yes ; then +if test `uname -s` = Linux -a -f /proc/cpuinfo ; then +case `grep "model name" /proc/cpuinfo` in +*AMD-K6*) enable_arch=k6 ;; +*Pentium*Pro*|*Pentium\ I*|*Klamath*) enable_arch=i686 ;; +*Pentium*|*586*) enable_arch=i586 ;; +*486*) enable_arch=i486 ;; +*386*) enable_arch=i386 ;; +*) enable_arch=no ;; +esac +else +enable_arch=no +#case `uname -m` in +#i686) enable_arch=i686 ;; +#i586) enable_arch=i586 ;; +#i486) enable_arch=i486 ;; +#i386) enable_arch=i386 ;; +#*) enable_arch=no ;; +#esac +fi +fi + + +case `$CC --version` in + +2.9*|3.*) + +case "$enable_arch" in +k6|i686|i586|i486|i386) CFLAGS="$CFLAGS -march=$enable_arch" ;; +no) ;; +*) AC_MSG_WARN(unknown architecture $enable_arch) ;; +esac ;; + +*) + +case "$enable_arch" in +k6|i686|i586) AC_MSG_WARN(your compiler is too old to support $enable_arch optimizations) ;; +i486) CFLAGS="$CFLAGS -m486" ;; +i386) CFLAGS="$CFLAGS -m386" ;; +no) ;; +*) AC_MSG_WARN(unknown architecture $enable_arch) ;; +esac ;; + +esac + + +case "$enable_optimize" in +yes|full) +AC_MSG_RESULT(producing heavily optimized code) + +CFLAGS="$CFLAGS -O3" + +case `uname -m` in +i?86) CFLAGS="$CFLAGS -DALLOW_UNALIGNED_IO" ;; +esac + +#case `$CC --version` in +#2.9*|3.*) +CFLAGS="$CFLAGS -fstrength-reduce -fthread-jumps \ + -fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop \ + -fexpensive-optimizations -fforce-mem -fforce-addr" +#;; +#*) +#AC_MSG_WARN(your compiler is too old for fancy optimizations) +#;; +#esac + +if test "$enable_debug" != yes -a "$enable_profile" != yes ; then +CFLAGS="$CFLAGS -fomit-frame-pointer" +LDFLAGS="$LDFLAGS -s" +fi ;; + +low) + +AC_MSG_RESULT(using minimal optimizations) +CFLAGS="$CFLAGS -O3" ;; + +esac + +if test "$enable_asm" = yes ; then +case `uname -m` in +i?86) +AC_MSG_RESULT(using optimized i386 cores) +ASM="-DUSE_ASM -I./asm/i386" ; ASM_OBJS="asm/i386/cpu.o asm/i386/lcd.o asm/i386/refresh.s" ;; +*) +AC_MSG_RESULT(no optimized asm core available for `uname -m`) ;; +esac +fi + + +AC_SUBST(SYS_DEFS) +AC_SUBST(ENDIAN) +AC_SUBST(SOUND) +AC_SUBST(JOY) +AC_SUBST(ASM) +AC_SUBST(ASM_OBJS) +AC_SUBST(FB_OBJS) +AC_SUBST(SDL_CFLAGS) +AC_SUBST(SDL_LIBS) +AC_SUBST(TARGETS) +AC_SUBST(XINCS) +AC_SUBST(XLIBS) + +AC_CONFIG_HEADER(sys/nix/config.h) +AC_OUTPUT(Makefile) + + + diff --git a/cpu.c b/cpu.c new file mode 100644 index 0000000..8dd5559 --- /dev/null +++ b/cpu.c @@ -0,0 +1,878 @@ + + + + +#include "defs.h" +#include "regs.h" +#include "hw.h" +#include "cpu.h" +#include "mem.h" +#include "fastmem.h" +#include "cpuregs.h" +#include "cpucore.h" + +#ifdef USE_ASM +#include "asm.h" +#endif + + +struct cpu cpu; + + + + +#define ZFLAG(n) ( (n) ? 0 : FZ ) + + +#define PUSH(w) ( (SP -= 2), (writew(xSP, (w))) ) +#define POP(w) ( ((w) = readw(xSP)), (SP += 2) ) + + +#define FETCH_OLD ( mbc.rmap[PC>>12] \ +? mbc.rmap[PC>>12][PC++] \ +: mem_read(PC++) ) + +#define FETCH (readb(PC++)) + + +#define INC(r) { ((r)++); \ +F = (F & (FL|FC)) | incflag_table[(r)]; } + +#define DEC(r) { ((r)--); \ +F = (F & (FL|FC)) | decflag_table[(r)]; } + +#define INCW(r) ( (r)++ ) + +#define DECW(r) ( (r)-- ) + +#define ADD(n) { \ +W(acc) = (un16)A + (un16)(n); \ +F = (ZFLAG(LB(acc))) \ +| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ +| (HB(acc) << 4); \ +A = LB(acc); } + +#define ADC(n) { \ +W(acc) = (un16)A + (un16)(n) + (un16)((F&FC)>>4); \ +F = (ZFLAG(LB(acc))) \ +| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ +| (HB(acc) << 4); \ +A = LB(acc); } + +#define ADDW(n) { \ +DW(acc) = (un32)HL + (un32)(n); \ +F = (F & (FZ)) \ +| (FH & ((H ^ ((n)>>8) ^ HB(acc)) << 1)) \ +| (acc.b[HI][LO] << 4); \ +HL = W(acc); } + +#define ADDSP(n) { \ +DW(acc) = (un32)SP + (un32)(n8)(n); \ +F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \ +| (acc.b[HI][LO] << 4); \ +SP = W(acc); } + +#define LDHLSP(n) { \ +DW(acc) = (un32)SP + (un32)(n8)(n); \ +F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \ +| (acc.b[HI][LO] << 4); \ +HL = W(acc); } + +#define CP(n) { \ +W(acc) = (un16)A - (un16)(n); \ +F = FN \ +| (ZFLAG(LB(acc))) \ +| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ +| ((un8)(-(n8)HB(acc)) << 4); } + +#define SUB(n) { CP((n)); A = LB(acc); } + +#define SBC(n) { \ +W(acc) = (un16)A - (un16)(n) - (un16)((F&FC)>>4); \ +F = FN \ +| (ZFLAG((n8)LB(acc))) \ +| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ +| ((un8)(-(n8)HB(acc)) << 4); \ +A = LB(acc); } + +#define AND(n) { A &= (n); \ +F = ZFLAG(A) | FH; } + +#define XOR(n) { A ^= (n); \ +F = ZFLAG(A); } + +#define OR(n) { A |= (n); \ +F = ZFLAG(A); } + +#define RLCA(r) { (r) = ((r)>>7) | ((r)<<1); \ +F = (((r)&0x01)<<4); } + +#define RRCA(r) { (r) = ((r)<<7) | ((r)>>1); \ +F = (((r)&0x80)>>3); } + +#define RLA(r) { \ +LB(acc) = (((r)&0x80)>>3); \ +(r) = ((r)<<1) | ((F&FC)>>4); \ +F = LB(acc); } + +#define RRA(r) { \ +LB(acc) = (((r)&0x01)<<4); \ +(r) = ((r)>>1) | ((F&FC)<<3); \ +F = LB(acc); } + +#define RLC(r) { RLCA(r); F |= ZFLAG(r); } +#define RRC(r) { RRCA(r); F |= ZFLAG(r); } +#define RL(r) { RLA(r); F |= ZFLAG(r); } +#define RR(r) { RRA(r); F |= ZFLAG(r); } + +#define SLA(r) { \ +LB(acc) = (((r)&0x80)>>3); \ +(r) <<= 1; \ +F = ZFLAG((r)) | LB(acc); } + +#define SRA(r) { \ +LB(acc) = (((r)&0x01)<<4); \ +(r) = (un8)(((n8)(r))>>1); \ +F = ZFLAG((r)) | LB(acc); } + +#define SRL(r) { \ +LB(acc) = (((r)&0x01)<<4); \ +(r) >>= 1; \ +F = ZFLAG((r)) | LB(acc); } + +#define CPL(r) { \ +(r) = ~(r); \ +F |= (FH|FN); } + +#define SCF { F = (F & (FZ)) | FC; } + +#define CCF { F = (F & (FZ|FC)) ^ FC; } + +#define DAA { \ +A += (LB(acc) = daa_table[((((int)F)&0x70)<<4) | A]); \ +F = (F & (FN)) | ZFLAG(A) | daa_carry_table[LB(acc)>>2]; } + +#define SWAP(r) { \ +(r) = swap_table[(r)]; \ +F = ZFLAG((r)); } + +#define BIT(n,r) { F = (F & FC) | ZFLAG(((r) & (1 << (n)))) | FH; } +#define RES(n,r) { (r) &= ~(1 << (n)); } +#define SET(n,r) { (r) |= (1 << (n)); } + +#define CB_REG_CASES(r, n) \ +case 0x00|(n): RLC(r); break; \ +case 0x08|(n): RRC(r); break; \ +case 0x10|(n): RL(r); break; \ +case 0x18|(n): RR(r); break; \ +case 0x20|(n): SLA(r); break; \ +case 0x28|(n): SRA(r); break; \ +case 0x30|(n): SWAP(r); break; \ +case 0x38|(n): SRL(r); break; \ +case 0x40|(n): BIT(0, r); break; \ +case 0x48|(n): BIT(1, r); break; \ +case 0x50|(n): BIT(2, r); break; \ +case 0x58|(n): BIT(3, r); break; \ +case 0x60|(n): BIT(4, r); break; \ +case 0x68|(n): BIT(5, r); break; \ +case 0x70|(n): BIT(6, r); break; \ +case 0x78|(n): BIT(7, r); break; \ +case 0x80|(n): RES(0, r); break; \ +case 0x88|(n): RES(1, r); break; \ +case 0x90|(n): RES(2, r); break; \ +case 0x98|(n): RES(3, r); break; \ +case 0xA0|(n): RES(4, r); break; \ +case 0xA8|(n): RES(5, r); break; \ +case 0xB0|(n): RES(6, r); break; \ +case 0xB8|(n): RES(7, r); break; \ +case 0xC0|(n): SET(0, r); break; \ +case 0xC8|(n): SET(1, r); break; \ +case 0xD0|(n): SET(2, r); break; \ +case 0xD8|(n): SET(3, r); break; \ +case 0xE0|(n): SET(4, r); break; \ +case 0xE8|(n): SET(5, r); break; \ +case 0xF0|(n): SET(6, r); break; \ +case 0xF8|(n): SET(7, r); break; + + +#define ALU_CASES(base, imm, op, label) \ +case (imm): b = FETCH; goto label; \ +case (base): b = B; goto label; \ +case (base)+1: b = C; goto label; \ +case (base)+2: b = D; goto label; \ +case (base)+3: b = E; goto label; \ +case (base)+4: b = H; goto label; \ +case (base)+5: b = L; goto label; \ +case (base)+6: b = readb(HL); goto label; \ +case (base)+7: b = A; \ +label: op(b); break; + + + + + + + + +#define JR ( PC += 1+(n8)readb(PC) ) +#define JP ( PC = readw(PC) ) + +#define CALL ( PUSH(PC+2), JP ) + +#define NOJR ( clen--, PC++ ) +#define NOJP ( clen--, PC+=2 ) +#define NOCALL ( clen-=3, PC+=2 ) +#define NORET ( clen-=3 ) + +#define RST(n) { PUSH(PC); PC = (n); } + +#define RET ( POP(PC) ) + +#define EI ( IMA = 1 ) +#define DI ( cpu.halt = IMA = IME = 0 ) + + + +#define PRE_INT ( DI, PUSH(PC) ) +#define THROW_INT(n) ( (IF &= ~(1<<(n))), (PC = 0x40+((n)<<3)) ) + + + + +void cpu_reset() +{ + cpu.speed = 0; + cpu.halt = 0; + cpu.div = 0; + cpu.tim = 0; + cpu.lcdc = 40; + + IME = 0; + IMA = 0; + + PC = 0x0100; + SP = 0xFFFE; + AF = 0x01B0; + BC = 0x0013; + DE = 0x00D8; + HL = 0x014D; + + if (hw.cgb) A = 0x11; + if (hw.gba) B = 0x01; +} + + +void div_advance(int cnt) +{ + cpu.div += (cnt<<1); + if (cpu.div >= 256) + { + R_DIV += (cpu.div >> 8); + cpu.div &= 0xff; + } +} + +void timer_advance(int cnt) +{ + int unit, tima; + + if (!(R_TAC & 0x04)) return; + + unit = ((-R_TAC) & 3) << 1; + cpu.tim += (cnt<= 512) + { + tima = R_TIMA + (cpu.tim >> 9); + cpu.tim &= 0x1ff; + if (tima >= 256) + { + hw_interrupt(IF_TIMER, IF_TIMER); + hw_interrupt(0, IF_TIMER); + } + while (tima >= 256) + tima = tima - 256 + R_TMA; + R_TIMA = tima; + } +} + +void lcdc_advance(int cnt) +{ + cpu.lcdc -= cnt; + if (cpu.lcdc <= 0) lcdc_trans(); +} + +void sound_advance(int cnt) +{ + cpu.snd += cnt; +} + +void cpu_timers(int cnt) +{ + div_advance(cnt << cpu.speed); + timer_advance(cnt << cpu.speed); + lcdc_advance(cnt); + sound_advance(cnt); +} + +int cpu_idle(int max) +{ + int cnt, unit; + + if (!(cpu.halt && IME)) return 0; + if (R_IF & R_IE) + { + cpu.halt = 0; + return 0; + } + + /* Make sure we don't miss lcdc status events! */ + if ((R_IE & (IF_VBLANK | IF_STAT)) && (max > cpu.lcdc)) + max = cpu.lcdc; + + /* If timer interrupt cannot happen, this is very simple! */ + if (!((R_IE & IF_TIMER) && (R_TAC & 0x04))) + { + cpu_timers(max); + return max; + } + + /* Figure out when the next timer interrupt will happen */ + unit = ((-R_TAC) & 3) << 1; + cnt = (511 - cpu.tim + (1<> unit; + cnt += (255 - R_TIMA) << (9 - unit); + + if (max < cnt) + cnt = max; + + cpu_timers(cnt); + return cnt; +} + +#ifndef ASM_CPU_EMULATE + +extern int debug_trace; + +int cpu_emulate(int cycles) +{ + int i; + byte op, cbop; + int clen; + static union reg acc; + static byte b; + static word w; + + i = cycles; +next: + if ((clen = cpu_idle(i))) + { + i -= clen; + if (i > 0) goto next; + return cycles-i; + } + + if (IME && (IF & IE)) + { + PRE_INT; + switch ((byte)(IF & IE)) + { + case 0x01: case 0x03: case 0x05: case 0x07: + case 0x09: case 0x0B: case 0x0D: case 0x0F: + case 0x11: case 0x13: case 0x15: case 0x17: + case 0x19: case 0x1B: case 0x1D: case 0x1F: + THROW_INT(0); break; + case 0x02: case 0x06: case 0x0A: case 0x0E: + case 0x12: case 0x16: case 0x1A: case 0x1E: + THROW_INT(1); break; + case 0x04: case 0x0C: case 0x14: case 0x1C: + THROW_INT(2); break; + case 0x08: case 0x18: + THROW_INT(3); break; + case 0x10: + THROW_INT(4); break; + } + } + IME = IMA; + + if (debug_trace) debug_disassemble(PC, 1); + op = FETCH; + clen = cycles_table[op]; + + switch(op) + { + case 0x00: /* NOP */ + case 0x40: /* LD B,B */ + case 0x49: /* LD C,C */ + case 0x52: /* LD D,D */ + case 0x5B: /* LD E,E */ + case 0x64: /* LD H,H */ + case 0x6D: /* LD L,L */ + case 0x7F: /* LD A,A */ + break; + + case 0x41: /* LD B,C */ + B = C; break; + case 0x42: /* LD B,D */ + B = D; break; + case 0x43: /* LD B,E */ + B = E; break; + case 0x44: /* LD B,H */ + B = H; break; + case 0x45: /* LD B,L */ + B = L; break; + case 0x46: /* LD B,(HL) */ + B = readb(xHL); break; + case 0x47: /* LD B,A */ + B = A; break; + + case 0x48: /* LD C,B */ + C = B; break; + case 0x4A: /* LD C,D */ + C = D; break; + case 0x4B: /* LD C,E */ + C = E; break; + case 0x4C: /* LD C,H */ + C = H; break; + case 0x4D: /* LD C,L */ + C = L; break; + case 0x4E: /* LD C,(HL) */ + C = readb(xHL); break; + case 0x4F: /* LD C,A */ + C = A; break; + + case 0x50: /* LD D,B */ + D = B; break; + case 0x51: /* LD D,C */ + D = C; break; + case 0x53: /* LD D,E */ + D = E; break; + case 0x54: /* LD D,H */ + D = H; break; + case 0x55: /* LD D,L */ + D = L; break; + case 0x56: /* LD D,(HL) */ + D = readb(xHL); break; + case 0x57: /* LD D,A */ + D = A; break; + + case 0x58: /* LD E,B */ + E = B; break; + case 0x59: /* LD E,C */ + E = C; break; + case 0x5A: /* LD E,D */ + E = D; break; + case 0x5C: /* LD E,H */ + E = H; break; + case 0x5D: /* LD E,L */ + E = L; break; + case 0x5E: /* LD E,(HL) */ + E = readb(xHL); break; + case 0x5F: /* LD E,A */ + E = A; break; + + case 0x60: /* LD H,B */ + H = B; break; + case 0x61: /* LD H,C */ + H = C; break; + case 0x62: /* LD H,D */ + H = D; break; + case 0x63: /* LD H,E */ + H = E; break; + case 0x65: /* LD H,L */ + H = L; break; + case 0x66: /* LD H,(HL) */ + H = readb(xHL); break; + case 0x67: /* LD H,A */ + H = A; break; + + case 0x68: /* LD L,B */ + L = B; break; + case 0x69: /* LD L,C */ + L = C; break; + case 0x6A: /* LD L,D */ + L = D; break; + case 0x6B: /* LD L,E */ + L = E; break; + case 0x6C: /* LD L,H */ + L = H; break; + case 0x6E: /* LD L,(HL) */ + L = readb(xHL); break; + case 0x6F: /* LD L,A */ + L = A; break; + + case 0x70: /* LD (HL),B */ + b = B; goto __LD_HL; + case 0x71: /* LD (HL),C */ + b = C; goto __LD_HL; + case 0x72: /* LD (HL),D */ + b = D; goto __LD_HL; + case 0x73: /* LD (HL),E */ + b = E; goto __LD_HL; + case 0x74: /* LD (HL),H */ + b = H; goto __LD_HL; + case 0x75: /* LD (HL),L */ + b = L; goto __LD_HL; + case 0x77: /* LD (HL),A */ + b = A; + __LD_HL: + writeb(xHL,b); + break; + + case 0x78: /* LD A,B */ + A = B; break; + case 0x79: /* LD A,C */ + A = C; break; + case 0x7A: /* LD A,D */ + A = D; break; + case 0x7B: /* LD A,E */ + A = E; break; + case 0x7C: /* LD A,H */ + A = H; break; + case 0x7D: /* LD A,L */ + A = L; break; + case 0x7E: /* LD A,(HL) */ + A = readb(xHL); break; + + case 0x01: /* LD BC,imm */ + BC = readw(xPC); PC += 2; break; + case 0x11: /* LD DE,imm */ + DE = readw(xPC); PC += 2; break; + case 0x21: /* LD HL,imm */ + HL = readw(xPC); PC += 2; break; + case 0x31: /* LD SP,imm */ + SP = readw(xPC); PC += 2; break; + + case 0x02: /* LD (BC),A */ + writeb(xBC, A); break; + case 0x0A: /* LD A,(BC) */ + A = readb(xBC); break; + case 0x12: /* LD (DE),A */ + writeb(xDE, A); break; + case 0x1A: /* LD A,(DE) */ + A = readb(xDE); break; + + case 0x22: /* LDI (HL),A */ + writeb(xHL, A); HL++; break; + case 0x2A: /* LDI A,(HL) */ + A = readb(xHL); HL++; break; + case 0x32: /* LDD (HL),A */ + writeb(xHL, A); HL--; break; + case 0x3A: /* LDD A,(HL) */ + A = readb(xHL); HL--; break; + + case 0x06: /* LD B,imm */ + B = FETCH; break; + case 0x0E: /* LD C,imm */ + C = FETCH; break; + case 0x16: /* LD D,imm */ + D = FETCH; break; + case 0x1E: /* LD E,imm */ + E = FETCH; break; + case 0x26: /* LD H,imm */ + H = FETCH; break; + case 0x2E: /* LD L,imm */ + L = FETCH; break; + case 0x36: /* LD (HL),imm */ + b = FETCH; writeb(xHL, b); break; + case 0x3E: /* LD A,imm */ + A = FETCH; break; + + case 0x08: /* LD (imm),SP */ + writew(readw(xPC), SP); PC += 2; break; + case 0xEA: /* LD (imm),A */ + writeb(readw(xPC), A); PC += 2; break; + + case 0xE0: /* LDH (imm),A */ + writehi(FETCH, A); break; + case 0xE2: /* LDH (C),A */ + writehi(C, A); break; + case 0xF0: /* LDH A,(imm) */ + A = readhi(FETCH); break; + case 0xF2: /* LDH A,(C) (undocumented) */ + A = readhi(C); break; + + + case 0xF8: /* LD HL,SP+imm */ + b = FETCH; LDHLSP(b); break; + case 0xF9: /* LD SP,HL */ + SP = HL; break; + case 0xFA: /* LD A,(imm) */ + A = readb(readw(xPC)); PC += 2; break; + + ALU_CASES(0x80, 0xC6, ADD, __ADD) + ALU_CASES(0x88, 0xCE, ADC, __ADC) + ALU_CASES(0x90, 0xD6, SUB, __SUB) + ALU_CASES(0x98, 0xDE, SBC, __SBC) + ALU_CASES(0xA0, 0xE6, AND, __AND) + ALU_CASES(0xA8, 0xEE, XOR, __XOR) + ALU_CASES(0xB0, 0xF6, OR, __OR) + ALU_CASES(0xB8, 0xFE, CP, __CP) + + case 0x09: /* ADD HL,BC */ + w = BC; goto __ADDW; + case 0x19: /* ADD HL,DE */ + w = DE; goto __ADDW; + case 0x39: /* ADD HL,SP */ + w = SP; goto __ADDW; + case 0x29: /* ADD HL,HL */ + w = HL; + __ADDW: + ADDW(w); + break; + + case 0x04: /* INC B */ + INC(B); break; + case 0x0C: /* INC C */ + INC(C); break; + case 0x14: /* INC D */ + INC(D); break; + case 0x1C: /* INC E */ + INC(E); break; + case 0x24: /* INC H */ + INC(H); break; + case 0x2C: /* INC L */ + INC(L); break; + case 0x34: /* INC (HL) */ + b = readb(xHL); + INC(b); + writeb(xHL, b); + break; + case 0x3C: /* INC A */ + INC(A); break; + + case 0x03: /* INC BC */ + INCW(BC); break; + case 0x13: /* INC DE */ + INCW(DE); break; + case 0x23: /* INC HL */ + INCW(HL); break; + case 0x33: /* INC SP */ + INCW(SP); break; + + case 0x05: /* DEC B */ + DEC(B); break; + case 0x0D: /* DEC C */ + DEC(C); break; + case 0x15: /* DEC D */ + DEC(D); break; + case 0x1D: /* DEC E */ + DEC(E); break; + case 0x25: /* DEC H */ + DEC(H); break; + case 0x2D: /* DEC L */ + DEC(L); break; + case 0x35: /* DEC (HL) */ + b = readb(xHL); + DEC(b); + writeb(xHL, b); + break; + case 0x3D: /* DEC A */ + DEC(A); break; + + case 0x0B: /* DEC BC */ + DECW(BC); break; + case 0x1B: /* DEC DE */ + DECW(DE); break; + case 0x2B: /* DEC HL */ + DECW(HL); break; + case 0x3B: /* DEC SP */ + DECW(SP); break; + + case 0x07: /* RLCA */ + RLCA(A); break; + case 0x0F: /* RRCA */ + RRCA(A); break; + case 0x17: /* RLA */ + RLA(A); break; + case 0x1F: /* RRA */ + RRA(A); break; + + case 0x27: /* DAA */ + DAA; break; + case 0x2F: /* CPL */ + CPL(A); break; + + case 0x18: /* JR */ + __JR: + JR; break; + case 0x20: /* JR NZ */ + if (!(F&FZ)) goto __JR; NOJR; break; + case 0x28: /* JR Z */ + if (F&FZ) goto __JR; NOJR; break; + case 0x30: /* JR NC */ + if (!(F&FC)) goto __JR; NOJR; break; + case 0x38: /* JR C */ + if (F&FC) goto __JR; NOJR; break; + + case 0xC3: /* JP */ + __JP: + JP; break; + case 0xC2: /* JP NZ */ + if (!(F&FZ)) goto __JP; NOJP; break; + case 0xCA: /* JP Z */ + if (F&FZ) goto __JP; NOJP; break; + case 0xD2: /* JP NC */ + if (!(F&FC)) goto __JP; NOJP; break; + case 0xDA: /* JP C */ + if (F&FC) goto __JP; NOJP; break; + case 0xE9: /* JP HL */ + PC = HL; break; + + case 0xC9: /* RET */ + __RET: + RET; break; + case 0xC0: /* RET NZ */ + if (!(F&FZ)) goto __RET; NORET; break; + case 0xC8: /* RET Z */ + if (F&FZ) goto __RET; NORET; break; + case 0xD0: /* RET NC */ + if (!(F&FC)) goto __RET; NORET; break; + case 0xD8: /* RET C */ + if (F&FC) goto __RET; NORET; break; + case 0xD9: /* RETI */ + IME = IMA = 1; goto __RET; + + case 0xCD: /* CALL */ + __CALL: + CALL; break; + case 0xC4: /* CALL NZ */ + if (!(F&FZ)) goto __CALL; NOCALL; break; + case 0xCC: /* CALL Z */ + if (F&FZ) goto __CALL; NOCALL; break; + case 0xD4: /* CALL NC */ + if (!(F&FC)) goto __CALL; NOCALL; break; + case 0xDC: /* CALL C */ + if (F&FC) goto __CALL; NOCALL; break; + + case 0xC7: /* RST 0 */ + b = 0x00; goto __RST; + case 0xCF: /* RST 8 */ + b = 0x08; goto __RST; + case 0xD7: /* RST 10 */ + b = 0x10; goto __RST; + case 0xDF: /* RST 18 */ + b = 0x18; goto __RST; + case 0xE7: /* RST 20 */ + b = 0x20; goto __RST; + case 0xEF: /* RST 28 */ + b = 0x28; goto __RST; + case 0xF7: /* RST 30 */ + b = 0x30; goto __RST; + case 0xFF: /* RST 38 */ + b = 0x38; + __RST: + RST(b); break; + + case 0xC1: /* POP BC */ + POP(BC); break; + case 0xC5: /* PUSH BC */ + PUSH(BC); break; + case 0xD1: /* POP DE */ + POP(DE); break; + case 0xD5: /* PUSH DE */ + PUSH(DE); break; + case 0xE1: /* POP HL */ + POP(HL); break; + case 0xE5: /* PUSH HL */ + PUSH(HL); break; + case 0xF1: /* POP AF */ + POP(AF); break; + case 0xF5: /* PUSH AF */ + PUSH(AF); break; + + case 0xE8: /* ADD SP,imm */ + b = FETCH; ADDSP(b); break; + + case 0xF3: /* DI */ + DI; break; + case 0xFB: /* EI */ + EI; break; + + case 0x37: /* SCF */ + SCF; break; + case 0x3F: /* CCF */ + CCF; break; + + case 0x10: /* STOP */ + PC++; + if (R_KEY1 & 1) + { + cpu.speed = cpu.speed ^ 1; + R_KEY1 = (R_KEY1 & 0x7E) | (cpu.speed << 7); + break; + } + /* NOTE - we do not implement dmg STOP whatsoever */ + break; + + case 0x76: /* HALT */ + cpu.halt = 1; + break; + + case 0xCB: /* CB prefix */ + cbop = FETCH; + clen = cb_cycles_table[cbop]; + switch (cbop) + { + CB_REG_CASES(B, 0); + CB_REG_CASES(C, 1); + CB_REG_CASES(D, 2); + CB_REG_CASES(E, 3); + CB_REG_CASES(H, 4); + CB_REG_CASES(L, 5); + CB_REG_CASES(A, 7); + default: + b = readb(xHL); + switch(cbop) + { + CB_REG_CASES(b, 6); + } + if ((cbop & 0xC0) != 0x40) /* exclude BIT */ + writeb(xHL, b); + break; + } + break; + + default: + die( + "invalid opcode 0x%02X at address 0x%04X, rombank = %d\n", + op, (PC-1) & 0xffff, mbc.rombank); + break; + } + + clen <<= 1; + div_advance(clen); + timer_advance(clen); + clen >>= cpu.speed; + lcdc_advance(clen); + sound_advance(clen); + + i -= clen; + if (i > 0) goto next; + return cycles-i; +} + +#endif /* ASM_CPU_EMULATE */ + + +#ifndef ASM_CPU_STEP + +int cpu_step(int max) +{ + int cnt; + if ((cnt = cpu_idle(max))) return cnt; + return cpu_emulate(1); +} + +#endif /* ASM_CPU_STEP */ + + + + + + + + + + + + diff --git a/cpu.h b/cpu.h new file mode 100644 index 0000000..085181c --- /dev/null +++ b/cpu.h @@ -0,0 +1,36 @@ + + +#ifndef __CPU_H__ +#define __CPU_H__ + + + +#include "defs.h" + + +union reg +{ + byte b[2][2]; + word w[2]; + un32 d; /* padding for alignment, carry */ +}; + +struct cpu +{ + union reg pc, sp, bc, de, hl, af; + int ime, ima; + int speed; + int halt; + int div, tim; + int lcdc; + int snd; +}; + +extern struct cpu cpu; + + + + +#endif + + diff --git a/cpucore.h b/cpucore.h new file mode 100644 index 0000000..934bd1e --- /dev/null +++ b/cpucore.h @@ -0,0 +1,290 @@ + +#include "defs.h" + + +const static byte cycles_table[256] = +{ + 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, + 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, + 3, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, + 3, 3, 2, 2, 1, 3, 3, 3, 3, 2, 2, 2, 1, 1, 2, 1, + + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, + + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, + + 5, 3, 4, 4, 6, 4, 2, 4, 5, 4, 4, 1, 6, 6, 2, 4, + 5, 3, 4, 0, 6, 4, 2, 4, 5, 4, 4, 0, 6, 0, 2, 4, + 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4, + 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4, +}; + +const static byte cb_cycles_table[256] = +{ + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, + + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, +}; + + + +const static byte zflag_table[256] = +{ + FZ, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const static byte incflag_table[256] = +{ + FZ|FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const static byte decflag_table[256] = +{ + FZ|FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH, + FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH +}; + +const static byte swap_table[256] = +{ + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF, +}; + +const static byte daa_table[4096] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, +}; + +const static byte daa_carry_table[64] = +{ + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, FC, FC, 00, 00, 00, 00, 00, 00, + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, 00, FC, +}; + + + + + + + + + + + + diff --git a/cpuregs.h b/cpuregs.h new file mode 100644 index 0000000..0d09908 --- /dev/null +++ b/cpuregs.h @@ -0,0 +1,56 @@ + + +#ifndef __CPUREGS_H__ + +#define __CPUREGS_H__ + + + +#include "defs.h" +#include "cpu.h" + +#define LB(r) ((r).b[LO][LO]) +#define HB(r) ((r).b[LO][HI]) +#define W(r) ((r).w[LO]) +#define DW(r) ((r).d) + +#define A HB(cpu.af) +#define F LB(cpu.af) +#define B HB(cpu.bc) +#define C LB(cpu.bc) +#define D HB(cpu.de) +#define E LB(cpu.de) +#define H HB(cpu.hl) +#define L LB(cpu.hl) + +#define AF W(cpu.af) +#define BC W(cpu.bc) +#define DE W(cpu.de) +#define HL W(cpu.hl) + +#define PC W(cpu.pc) +#define SP W(cpu.sp) + +#define xAF DW(cpu.af) +#define xBC DW(cpu.bc) +#define xDE DW(cpu.de) +#define xHL DW(cpu.hl) + +#define xPC DW(cpu.pc) +#define xSP DW(cpu.sp) + +#define IMA cpu.ima +#define IME cpu.ime +#define IF R_IF +#define IE R_IE + +#define FZ 0x80 +#define FN 0x40 +#define FH 0x20 +#define FC 0x10 +#define FL 0x0F /* low unused portion of flags */ + + +#endif /* __CPUREGS_H__ */ + + diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..2569891 --- /dev/null +++ b/debug.c @@ -0,0 +1,689 @@ + + +#include +#include + +#include "defs.h" +#include "cpu.h" +#include "mem.h" +#include "fastmem.h" +#include "regs.h" +#include "rc.h" + +#include "cpuregs.h" + + +static char *mnemonic_table[256] = +{ + "NOP", + "LD BC,%w", + "LD (BC),A", + "INC BC", + "INC B", + "DEC B", + "LD B,%b", + "RLCA", + "LD (%w),SP", + "ADD HL,BC", + "LD A,(BC)", + "DEC BC", + "INC C", + "DEC C", + "LD C,%b", + "RRCA", + "STOP", + "LD DE,%w", + "LD (DE),A", + "INC DE", + "INC D", + "DEC D", + "LD D,%b", + "RLA", + "JR %o", + "ADD HL,DE", + "LD A,(DE)", + "DEC DE", + "INC E", + "DEC E", + "LD E,%b", + "RRA", + "JR NZ,%o", + "LD HL,%w", + "LD (HLI),A", + "INC HL", + "INC H", + "DEC H", + "LD H,%b", + "DAA", + "JR Z,%o", + "ADD HL,HL", + "LD A,(HLI)", + "DEC HL", + "INC L", + "DEC L", + "LD L,%b", + "CPL", + "JR NC,%o", + "LD SP,%w", + "LD (HLD),A", + "INC SP", + "INC (HL)", + "DEC (HL)", + "LD (HL),%b", + "SCF", + "JR C,%o", + "ADD HL,SP", + "LD A,(HLD)", + "DEC SP", + "INC A", + "DEC A", + "LD A,%b", + "CCF", + "LD B,B", + "LD B,C", + "LD B,D", + "LD B,E", + "LD B,H", + "LD B,L", + "LD B,(HL)", + "LD B,A", + "LD C,B", + "LD C,C", + "LD C,D", + "LD C,E", + "LD C,H", + "LD C,L", + "LD C,(HL)", + "LD C,A", + "LD D,B", + "LD D,C", + "LD D,D", + "LD D,E", + "LD D,H", + "LD D,L", + "LD D,(HL)", + "LD D,A", + "LD E,B", + "LD E,C", + "LD E,D", + "LD E,E", + "LD E,H", + "LD E,L", + "LD E,(HL)", + "LD E,A", + "LD H,B", + "LD H,C", + "LD H,D", + "LD H,E", + "LD H,H", + "LD H,L", + "LD H,(HL)", + "LD H,A", + "LD L,B", + "LD L,C", + "LD L,D", + "LD L,E", + "LD L,H", + "LD L,L", + "LD L,(HL)", + "LD L,A", + "LD (HL),B", + "LD (HL),C", + "LD (HL),D", + "LD (HL),E", + "LD (HL),H", + "LD (HL),L", + "HALT", + "LD (HL),A", + "LD A,B", + "LD A,C", + "LD A,D", + "LD A,E", + "LD A,H", + "LD A,L", + "LD A,(HL)", + "LD A,A", + "ADD A,B", + "ADD A,C", + "ADD A,D", + "ADD A,E", + "ADD A,H", + "ADD A,L", + "ADD A,(HL)", + "ADD A,A", + "ADC A,B", + "ADC A,C", + "ADC A,D", + "ADC A,E", + "ADC A,H", + "ADC A,L", + "ADC A,(HL)", + "ADC A", + "SUB B", + "SUB C", + "SUB D", + "SUB E", + "SUB H", + "SUB L", + "SUB (HL)", + "SUB A", + "SBC A,B", + "SBC A,C", + "SBC A,D", + "SBC A,E", + "SBC A,H", + "SBC A,L", + "SBC A,(HL)", + "SBC A,A", + "AND B", + "AND C", + "AND D", + "AND E", + "AND H", + "AND L", + "AND (HL)", + "AND A", + "XOR B", + "XOR C", + "XOR D", + "XOR E", + "XOR H", + "XOR L", + "XOR (HL)", + "XOR A", + "OR B", + "OR C", + "OR D", + "OR E", + "OR H", + "OR L", + "OR (HL)", + "OR A", + "CP B", + "CP C", + "CP D", + "CP E", + "CP H", + "CP L", + "CP (HL)", + "CP A", + "RET NZ", + "POP BC", + "JP NZ,%w", + "JP %w", + "CALL NZ,%w", + "PUSH BC", + "ADD A,%b", + "RST 0h", + "RET Z", + "RET", + "JP Z,%w", + NULL, + "CALL Z,%w", + "CALL %w", + "ADC A,%b", + "RST 8h", + "RET NC", + "POP DE", + "JP NC,%w", + NULL, + "CALL NC,%w", + "PUSH DE", + "SUB %b", + "RST 10h", + "RET C", + "RETI", + "JP C,%w", + NULL, + "CALL C,%w", + NULL, + "SBC A,%b", + "RST 18h", + "LD (FF00+%b),A", + "POP HL", + "LD (FF00+C),A", + NULL, + NULL, + "PUSH HL", + "AND %b", + "RST 20h", + "ADD SP,%o", + "JP HL", + "LD (%w),A", + NULL, + NULL, + NULL, + "XOR %b", + "RST 28h", + "LD A,(FF00+%b)", + "POP AF", + "LD A,(FF00+C)", + "DI", + NULL, + "PUSH AF", + "OR %b", + "RST 30h", + "LD HL,SP%o", + "LD SP,HL", + "LD A,(%w)", + "EI", + NULL, + NULL, + "CP %b", + "RST 38h" +}; + +static char *cb_mnemonic_table[256] = +{ + "RLC B", + "RLC C", + "RLC D", + "RLC E", + "RLC H", + "RLC L", + "RLC (HL)", + "RLC A", + "RRC B", + "RRC C", + "RRC D", + "RRC E", + "RRC H", + "RRC L", + "RRC (HL)", + "RRC A", + "RL B", + "RL C", + "RL D", + "RL E", + "RL H", + "RL L", + "RL (HL)", + "RL A", + "RR B", + "RR C", + "RR D", + "RR E", + "RR H", + "RR L", + "RR (HL)", + "RR A", + "SLA B", + "SLA C", + "SLA D", + "SLA E", + "SLA H", + "SLA L", + "SLA (HL)", + "SLA A", + "SRA B", + "SRA C", + "SRA D", + "SRA E", + "SRA H", + "SRA L", + "SRA (HL)", + "SRA A", + "SWAP B", + "SWAP C", + "SWAP D", + "SWAP E", + "SWAP H", + "SWAP L", + "SWAP (HL)", + "SWAP A", + "SRL B", + "SRL C", + "SRL D", + "SRL E", + "SRL H", + "SRL L", + "SRL (HL)", + "SRL A", + "BIT 0,B", + "BIT 0,C", + "BIT 0,D", + "BIT 0,E", + "BIT 0,H", + "BIT 0,L", + "BIT 0,(HL)", + "BIT 0,A", + "BIT 1,B", + "BIT 1,C", + "BIT 1,D", + "BIT 1,E", + "BIT 1,H", + "BIT 1,L", + "BIT 1,(HL)", + "BIT 1,A", + "BIT 2,B", + "BIT 2,C", + "BIT 2,D", + "BIT 2,E", + "BIT 2,H", + "BIT 2,L", + "BIT 2,(HL)", + "BIT 2,A", + "BIT 3,B", + "BIT 3,C", + "BIT 3,D", + "BIT 3,E", + "BIT 3,H", + "BIT 3,L", + "BIT 3,(HL)", + "BIT 3,A", + "BIT 4,B", + "BIT 4,C", + "BIT 4,D", + "BIT 4,E", + "BIT 4,H", + "BIT 4,L", + "BIT 4,(HL)", + "BIT 4,A", + "BIT 5,B", + "BIT 5,C", + "BIT 5,D", + "BIT 5,E", + "BIT 5,H", + "BIT 5,L", + "BIT 5,(HL)", + "BIT 5,A", + "BIT 6,B", + "BIT 6,C", + "BIT 6,D", + "BIT 6,E", + "BIT 6,H", + "BIT 6,L", + "BIT 6,(HL)", + "BIT 6,A", + "BIT 7,B", + "BIT 7,C", + "BIT 7,D", + "BIT 7,E", + "BIT 7,H", + "BIT 7,L", + "BIT 7,(HL)", + "BIT 7,A", + "RES 0,B", + "RES 0,C", + "RES 0,D", + "RES 0,E", + "RES 0,H", + "RES 0,L", + "RES 0,(HL)", + "RES 0,A", + "RES 1,B", + "RES 1,C", + "RES 1,D", + "RES 1,E", + "RES 1,H", + "RES 1,L", + "RES 1,(HL)", + "RES 1,A", + "RES 2,B", + "RES 2,C", + "RES 2,D", + "RES 2,E", + "RES 2,H", + "RES 2,L", + "RES 2,(HL)", + "RES 2,A", + "RES 3,B", + "RES 3,C", + "RES 3,D", + "RES 3,E", + "RES 3,H", + "RES 3,L", + "RES 3,(HL)", + "RES 3,A", + "RES 4,B", + "RES 4,C", + "RES 4,D", + "RES 4,E", + "RES 4,H", + "RES 4,L", + "RES 4,(HL)", + "RES 4,A", + "RES 5,B", + "RES 5,C", + "RES 5,D", + "RES 5,E", + "RES 5,H", + "RES 5,L", + "RES 5,(HL)", + "RES 5,A", + "RES 6,B", + "RES 6,C", + "RES 6,D", + "RES 6,E", + "RES 6,H", + "RES 6,L", + "RES 6,(HL)", + "RES 6,A", + "RES 7,B", + "RES 7,C", + "RES 7,D", + "RES 7,E", + "RES 7,H", + "RES 7,L", + "RES 7,(HL)", + "RES 7,A", + "SET 0,B", + "SET 0,C", + "SET 0,D", + "SET 0,E", + "SET 0,H", + "SET 0,L", + "SET 0,(HL)", + "SET 0,A", + "SET 1,B", + "SET 1,C", + "SET 1,D", + "SET 1,E", + "SET 1,H", + "SET 1,L", + "SET 1,(HL)", + "SET 1,A", + "SET 2,B", + "SET 2,C", + "SET 2,D", + "SET 2,E", + "SET 2,H", + "SET 2,L", + "SET 2,(HL)", + "SET 2,A", + "SET 3,B", + "SET 3,C", + "SET 3,D", + "SET 3,E", + "SET 3,H", + "SET 3,L", + "SET 3,(HL)", + "SET 3,A", + "SET 4,B", + "SET 4,C", + "SET 4,D", + "SET 4,E", + "SET 4,H", + "SET 4,L", + "SET 4,(HL)", + "SET 4,A", + "SET 5,B", + "SET 5,C", + "SET 5,D", + "SET 5,E", + "SET 5,H", + "SET 5,L", + "SET 5,(HL)", + "SET 5,A", + "SET 6,B", + "SET 6,C", + "SET 6,D", + "SET 6,E", + "SET 6,H", + "SET 6,L", + "SET 6,(HL)", + "SET 6,A", + "SET 7,B", + "SET 7,C", + "SET 7,D", + "SET 7,E", + "SET 7,H", + "SET 7,L", + "SET 7,(HL)", + "SET 7,A" +}; + +static byte operand_count[256] = +{ + 1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 2, 1, + 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1, + 1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 1, 2, 1, + 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, + 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1 +}; + + +/* replace with a real interactive debugger eventually... */ + +int debug_trace = 0; + +rcvar_t debug_exports[] = +{ + RCV_BOOL("trace", &debug_trace), + RCV_END +}; + +void debug_disassemble(addr a, int c) +{ + static int i, j, k; + static byte code; + static byte ops[3]; + static int opaddr; + static char mnemonic[256]; + static char *pattern; + + if (!debug_trace) return; + while (c > 0) + { + k = 0; + opaddr = a; + code = ops[k++] = readb(a); a++; + if (code != 0xCB) + { + pattern = mnemonic_table[code]; + if (!pattern) + pattern = "***INVALID***"; + } + else + { + code = ops[k++] = readb(a); a++; + pattern = cb_mnemonic_table[code]; + } + i = j = 0; + while (pattern[i]) + { + if (pattern[i] == '%') + { + switch (pattern[++i]) + { + case 'B': + case 'b': + ops[k] = readb(a); a++; + j += sprintf(mnemonic + j, + "%02Xh", ops[k++]); + break; + case 'W': + case 'w': + ops[k] = readb(a); a++; + ops[k+1] = readb(a); a++; + j += sprintf(mnemonic + j, "%04Xh", + ((ops[k+1] << 8) | ops[k])); + k += 2; + break; + case 'O': + case 'o': + ops[k] = readb(a); a++; + j += sprintf(mnemonic + j, "%+d", + (n8)(ops[k++])); + break; + } + i++; + } + else + { + mnemonic[j++] = pattern[i++]; + } + } + mnemonic[j] = 0; + printf("%04X ", opaddr); + switch (operand_count[ops[0]]) { + case 1: + printf("%02X ", ops[0]); + break; + case 2: + printf("%02X %02X ", ops[0], ops[1]); + break; + case 3: + printf("%02X %02X %02X ", ops[0], ops[1], ops[2]); + break; + } + printf("%-16.16s", mnemonic); + printf( + " SP=%04X.%04X BC=%04X.%02X.%02X DE=%04X.%02X " + "HL=%04X.%02X A=%02X F=%02X %c%c%c%c%c", + SP, readw(SP), + BC, readb(BC), readb(0xFF00 | C), + DE, readb(DE), + HL, readb(HL), A, + F, (IME ? 'I' : '-'), + ((F & 0x80) ? 'Z' : '-'), + ((F & 0x40) ? 'N' : '-'), + ((F & 0x20) ? 'H' : '-'), + ((F & 0x10) ? 'C' : '-') + ); + printf( + " IE=%02X IF=%02X LCDC=%02X STAT=%02X LY=%02X LYC=%02X", + R_IE, R_IF, R_LCDC, R_STAT, R_LY, R_LYC + ); + printf("\n"); + fflush(stdout); + c--; + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/defs.h b/defs.h new file mode 100644 index 0000000..ddbeae3 --- /dev/null +++ b/defs.h @@ -0,0 +1,36 @@ + + + +#ifndef __DEFS_H__ +#define __DEFS_H__ + + + +#ifdef IS_LITTLE_ENDIAN +#define LO 0 +#define HI 1 +#else +#define LO 1 +#define HI 0 +#endif + + +typedef unsigned char byte; + +typedef unsigned char un8; +typedef unsigned short un16; +typedef unsigned int un32; + +typedef signed char n8; +typedef signed short n16; +typedef signed int n32; + +typedef un16 word; +typedef word addr; + + + + + +#endif + diff --git a/docs/CHANGES b/docs/CHANGES new file mode 100644 index 0000000..2d934c1 --- /dev/null +++ b/docs/CHANGES @@ -0,0 +1,322 @@ + +GNUBOY CHANGES FILE -- detailed list of all changes made + + Each release is labelled with the date it appeared; unreleased + versions are listed without a date stamp for purely historical + reasons. When checking what's changed since the last release, be + sure to look over intermediate unreleased versions as well. + + For an easy-to-read user-oriented list of major changes in each + release, please refer to the file WHATSNEW. + + +1.0.3 +fixed a typo in the SDL keymap file that kept . from working +added support for binding keys to the ' key +fixed bug related in nix.c's sys_checkdir that made it always demand writable +fixed loader.c since it depended on this bug +removed the literal newlines inside the copyright string in main.c +removed some parentheses in save.c's macros +(these were perfectly valid but caused problems with a broken compiler, lcc) +added return-type prototypes for strdup since it's not always in string.h +(many of the above were old bugfixes sent in by Damian M Gryski) +added slow, primitive support for gzipped rom files +(thanks to David Madore for the portable inflate code taken from his quine) +various minor source cleanups +more preliminary work on the fast register/himem io routines (not used yet) +fixed HuC3 emulation, according to TGB's sources +added hacks to work around HuC3's IR port not being implemented +(Robopon Sun and Star now seem to run fine) +fixed a few sound inconsistencies after loading a savestate +various fixes to keybinding system and X11 keymap +integrated Jonathan Gevaryahu's color filter +added "gbamode" rcvar to unlock gba-only features in some cgb games +(this has NOTHING to do with gba emulation!) +fixed DMG sprite sorting code! it's now enabled by default +reverted mistaken CGB wave pattern "fix" in 1.0.2 +don't always reset sound positions on sound init (is this correct?) + +1.0.2 (2001-09-18) +fixed bugs in rc_setvar calls in sys_initpath +fixed multiple definition of cpu struct in cpu.h +corrected behavior of ch1 sweep function when freq is written during sweep +emulated wave pattern corruption to fool "emulator-detectors" +updated savestate code to handle these changes, incremented minor version +(this should not affect compatibility with old savestates) +fixed major bugs in sound channel 4 +perfected channel 4 output sequence to sound like a real Gameboy +(much thanks goes out to Lord Nightmare for all his hard work on this!) +default channel 3 square wave is no longer 4 octaves too high +make DI cancel pending HALT...is this correct? (fixes Konami Collection #1) +fixed reversed stereo channels +tweaked frequency cutoff points that prevent aliasing +corrected default wave pattern (noise) when running in dmg mode +fixed sound reset bug that messed up pitch after pausing in Bubble Ghost +added new sample palettes +fixed major interrupt/HALT bug that kept Amazing Penguin from running +fixed sound channel 3 length regiser (info in gbspec.txt is bogus) +tweaked volume of channel 4 +removed FFL3 tile glitch from the known bugs in the README +(it was caused by a bad dump and/or hacked rom, not a bug in gnuboy) +added emulation of DMG STAT register write bug (causes interrupt) +(this fixes Legend of Zerd and perhaps one or two other games) + +1.0.1 (2001-07-09) +fixed problem in "make install" if dest dir doesn't exist +cleaned up some compiler warnings +fixed a problem with --bindir= not working in the autoconf process +renamed several things from mingw32 to just plain windows +fixed lots of keys that were still missing on the SDL port + +1.0.0 (2001-06-29) +renamed Makefile.mingw32 to Makefile.win to be 8.3 filename friendly +finally fixed up configure to work around broken gcc 2.96 on Redhat 7, et al +added lots of new documentation +added autoconf option to disable cpu-specific code generation +minor improvements to matroxfb hardware scaling code +cleaned up some old deprecated variables + +0.9.15 +various preparations for 1.0 release +cleaned up nix.c to remove old code and prevent errors on some systems +fixed Makefile.nix to be usable but minimal + +0.9.14 +changed default dmg palette to be less yellow +changed default keybindings not to use modifier keys +moved vid_begin to after doevents in emu.c +(this should fix alt+enter fullscreen toggle not working on windows) +changed --help, etc to use stdout rather than stderr +auto-loading config files on a per-rom basis + +0.9.13 (2001-04-09) +added matroxfb YUV scaling support +moved lcd_refreshline from the 3->0 stat change to the 2->3 one +(this fixes a slight visual glitch in Alleyway) +experimental: no LYC=LY interrupt during VBLANK...? +fixed emulation bug (RL/RR) in asm cpu core that broke Montezuma's Return +fixed some minor bugs in the matrox scaler register settings +fixed SWAP (HL) instruction in the asm core (fixes Pokemon Yellow) +added more assembly language scalers for performance + +0.9.12 (2001-04-02) +started adding HuC3 MBC support +removed some code that was accidentally left in that broke dos/win builds +fixed a bug in SDL joystick support -- thanks Ralf Hoffmann +unused bits in VBK register should be 1, not 0 -- this broke Binary Chaos +fixed bug that kept dmg palette from restoring properly after loading savestate +integrated hardware YUV scaling w/SDL thanks to Magnus Damm +SDL code now turns off fb.enabled when window is iconified +HDMA timing correction back in 0.9.6 broke Wacky Races; it's disabled for now + +0.9.11 (2001-04-01) +fixed bug that kept video mode setting from working with svgalib +implemented program counter skip after STOP instruction (konami collections) +fixed SDL hardware surface support -- thanks Dave Kiddell +also fixed another bug in gnuboy graphics code related to that problem +removed sdl_hwsurface rcvar (no longer needed) +changed SDL code to use SDL_Flip rather than SDL_UpdateRect - much faster +most ports now can auto-choose screen size for given scale if no vmode is given +optional shm sync skipping for x11 -- boost performance but looses frames +lots of new scaling stuff +allow HDMA while LCDC is off -- fixes Worms Armageddon +correct initial values for HDMA regs -- fixes first hang in Turok 3 +major timer fixes!! fixes second hang in Turok 3 + +0.9.10 (2001-03-26) +hopefully fixed issue with X header locations affecting some users +rewrote refresh_* functions to be faster and more flexible +added scale-by-two versions of the above, including super-fast asm versions +implemented primitive but fully functional scale-by-two mode +added vmode rcvar to set the video mode +disabled dmg sprite sorting by default because it doesn't seem to work right +removed deprecated rcvars from various display modules +heavily updated README +changed VBLANK timings slightly - seems to fix Daedalian Opus +enlarged OSS dma output buffer slightly; this may reduce occurance of underruns +cleaned up all warnings +fixed bug that prevented reading from OAM +fixed all compiler warnings except implicit functions +found and fixed a few minor bugs in the process +added spacebar to SDL keymap +up to 16 joystick buttons are now supported w/linux and SDL +added sdl_hwsurface rcvar to turn hardware surface back on +added static palette mode +quick and dirty hack to make super rc pro-am work +fixed bug that made OAM unreadable + +0.9.9 (2001-03-23) +removed some unused code from mingw32.c, fixed some bugs there too +fixed a bad sound bug in sdl.c +eliminated sound pops at startup with SDL +eliminaed compiletime error about SDL_DISABLE on SDL ver < 1.1.8 +integrated new fully-thinlib-based DOS code from Matthew Conte +added surface locking to SDL code; maybe this will fix windows+fullscreen? +fixed serious bug in savestate loading (call mem_updatemap on load) +new asm -- significant speed boosts for color games on older machines +removed SDL_HWSURFACE from SDL code - this should fix fullscreen on windows +disabled surface locking calls for now +properly initialize default path on DOS +added SDL_ANYFORMAT to SDL flags so we can natively support all color depths + +0.9.8 (2001-03-07) +enabled support for dmg sprite sorting; not sure it works yet +added "sprsort" rcvar to toggle this since it's usually not needed +fixed a potential crash that could happen if sound init failed on dos +added native SDL sound support +fixed lots of bugs in the SDL port +removed stupid sys_realtime() function in favor of the simple ANSI C time() +roms can now be loaded from stdin by specifying - as the rom name +removed lots of useless bloat from system interface modules +take advantage of ANSI atexit() to simplify termination logic +hide mouse cursor with SDL +SDL fullscreen mode +optional alt+enter fullscreen toggle for SDL +SDL rcvars sdl_fullscreen and sdl_altenter to control these features +changed bswapl to bswap in asm to make it work on mingw32 +added ram size code 05 for 4 banks, this seems to make Pokemon Crystal work +backed out hack for Altered Space and W&W because it broke other games +new code to make them work, hopefully this time it's right +now we give an error on unknown rom/ram size to prevent crashing +integrated Windows port by mewse + +0.9.7 (2001-02-27) +added support for mono sound +initial work on implementing sound blaster output on dos +fixed envelope bug that made notes trail off (or amplify) too fast +integrated dos sound support contributed by Matthew Conte using his thinlib +added Matthew Conte to CREDITS +tried to fix strange occasional keyboard misbehavior on dos +build stripped binaries by default if debugging and profiling are off + +0.9.6 +updated the INSTALL file +fixed something stupid that broke building SDL joystick support on non-Linux +added Mattias Wadman to the CREDITS +fixed VBLANK timing slightly; now altered space and wizards & warriors work +reverted change; it breaks other games +new trick that might fix things... +fixed bug in command line parsing that kept --savename=- from working +fixed warning in oss.c +fixed an old bug in HDMA/HBLANK that only recently became apparent +vesa support on dos is now working! + +0.9.5 (2001-02-22) +added Ralf to the CREDITS, apologies for the prior omission +show name from rom header in window title on X11 and SDL +fixed bug that made highcolor screen flicker +(this used to glitch sfalpha, but for some reason its ok now) +updated README +fixed cap on sound 3 frequency to eliminate bogus beeps +began work on optimizing memory io in the C code +updated HACKING slightly +got new fast memory io functions integrated! +moved all of high memory (registers, wave pattern, stack) to one array +(eventually this will make memory io faster) +changed savestate format, but old saves should still load fine +(hopefully new format makes more sense) +began implementing fast access to high memory +discovered that low bits of the flags register don't exist +optimized instruction emulation accordingly +a few optimizations to the outer asm cpu loop +fixed off-by-one error in C graphics code that made far right column blank +added slow, experimental 24bpp (packed, unaligned) video support +improved the configure script, now --without-* works +use sdl-config instead of explicit -lpthread to support more systems +removed stupid section directives from the asm +got the asm cores working on dos! +oss sound support *might* work on freebsd and openbsd now +SDL joystick code has been integrated, but I haven't tested it +fixed bug in new savestate code +added David Lau to the CREDITS (SDL joystick support) +GNU make should no longer be required to compile + +0.9.4 (2001-02-18) +various changes to lots of the system interface organization +separation of linux fb and keyboard handling code into two modules +integrated linux joystick support contributed by Ralf Hoffmann +dummy joystick code for systems without real support yet +fixed HDMA; now DKC runs perfectly + +0.9.3 +explicit link of SDL target with -lpthread, tell me if this causes problems +better cpu detection in configure script +more big fixes in sweep, and now it's actually tested, so it SHOULD work (!) +implemented default wave ram pattern +added linux fbcon display support - very functional +fix to allow new custom palette to take effect after loading dmg savestates + +0.9.2 (2001-02-12) +mbc3 rtc support, including save and resync across sessions +updated README +implemented sound channel 4 +fixed yet another bug in sweep (!!) +fixed nasty aliasing when sound frequency was higher than sample rate permits +finally, all sound registers can be adjusted while sound is being produced +made it so the proper shutdown functions actually get called on exit +added SDL port by Damian M Gryski, should be auto-detected by configure +added Damian to the CREDITS file +cleaned up sound code to minimize the amount of state data kept +added sound and rtc status to savestates; this won't break old saves +changed lots of lookup tables to const + +0.9.1 (2001-02-11) +fixed yet another critical bug in sweep +fixed STAT interrupt bug +added support for changing more sound params while sound is active +fixed yet another major bug in envelope for channel 2 +fixed bug in HDMA, but DKC still fails +updated README, HACKING +made samplerate and sound (on/off) configurable rcvars +changed command line parsing to make setting bools more intuitive +added --showvars to list all available rcvars + +0.9.0 +fixed bugs in sweep and envelope functions +added sound channel 3 + +0.8.5 +various minor optimizations in the C code +same in the i386 asm cpu core +initial work on sound framework +oss sound output for use on *nix +dummy sound output for use on systems without sound +sound channels 1 and 2 + +0.8.4 (2001-02-06) +updated README to cover new features +fixed off-by-one-line visual error introduced in 0.8.2 +gbspec.txt is wrong, ram size code 0 != no ram, big suprise... (!) +workaround for undocumented 512 byte ram size, won't necessarily work +changes in saved state format +slight improvements to asm cpu core +cleaned up HDMA code +removed outdated comments +more changes to lcdc/cpu timing interaction, fixing harmless bugs +this may slightly impact performance, i'll compensate later +hopefully fixed bug in svgalib interface that corrupted console on exit +updated HACKING to reflect new code, detail more internals +workaround for a bug that would never happen but could lock the emulator +fixed another visual glitch introduced in 0.8.2 +optimized i386 cpu.s to keep PC in a register at all times + +0.8.3 +changed install dir from $prefix/games to $prefix/bin +fixed major bug in ramsize lookup table (!) +updated HACKING to note that it's outdated +implemented saved states! + +0.8.2 (2001-02-03) +rewrote lcdc state behavior completely, fixed lots of compat issues +implemented serial io failure for roms that need it, fixed more compat +now, mk1, sml2, and alleyway are all fixed! +additions to input.h and keytable.c to allow future joystick support + +0.8.1 +fixed stupid timer interrupt bug in asm cpu core +renamed screen to fb so as not to conflict with allegro symbol names + +0.8.0 (2001-02-01) +initial release + + diff --git a/docs/CONFIG b/docs/CONFIG new file mode 100644 index 0000000..a25a941 --- /dev/null +++ b/docs/CONFIG @@ -0,0 +1,645 @@ + +GUIDE TO CONFIGURING GNUBOY + + +[ P A R T I ] + OVERVIEW + +There are two major ways of configuring the way gnuboy behaves at +runtime: setting the values of variables, and binding commands to keys +and joystick buttons. Each can be done either on the command line, or +from a config (rc) file. + +If you don't want to read all this detailed info, look at the sample +rc files provided, then browse back through this file to clarify +anything that seems confusing. You might also skip down to Part II if +you're already familiar with the syntax of gnuboy rc files and such; +the second part explains the configurable variables which you can play +with. + + + WHAT HAPPENS AT STARTUP + +When gnuboy is started, it first processes gnuboy.rc, the primary +configuration file. On *nix systems, gnuboy will initially look for +its rc files in ~/.gnuboy, or if that fails, the present working +directory. On DOS and Windows, the current directory will be searched +first, followed by the directory containing the gnuboy executable. + +After finishing with gnuboy.rc, gnuboy next looks for an rc file with +the same base name as the rom to be loaded. For example, if the name +of the rom is mygame.gb, gnuboy will process mygame.rc, if it exists. +This allows you to configure different preferences on a per-rom +basis. The locations searched for the rom-specific rc file are the +same as those searched for gnuboy.rc, unless gnuboy.rc has changed the +search path (see below for more info). + +Finally, options on the command line are processed. The command line +will override any settings in the auto-loaded rc files. This is a good +place for options that you just want to use occasionally, but not on a +regular basis. + +After all of the above is finished, gnuboy loads the rom and starts +emulation. + + + RC FILES + +The rc files gnuboy uses are plain text files, with one command on +each line. Lines that start with # are treated as comments, that is to +say they are ignored, and blank lines are ignored as well. + +There are three major types of commands. + + + RC FILES -- SETTING VARIABLES + +First of all, there is the "set" command, which is used for setting +the values of variables. For example, + + set scale 2 + +will set the screen scaling factor to 2. If you need to include a +space in the value of a variable, you can do something like this: + + set savename "I like spaces in my filenames" + +and then your save files will be named something like: + + I like spaces in my filenames.sav + I like spaces in my filenames.000 + I like spaces in my filenames.001 + I like spaces in my filenames.002 + etc. + +Finally, some variables allow multiple numbers to be given. For +example, to set the video mode to 640x480, 16bpp, you might do +something like this: + + set vmode 640 480 16 + +Observe that each number is separate, and there are no quotation marks +used. + + + RC FILES -- KEYBINDINGS + +Next, we have commands that deal with key and joystick bindings. These +are fairly simple. + +The "unbindall" command removes all existing keybindings -- be +careful! -- and its main use is for people who want to redefine their +keyboard controls entirely and throw away the defaults. Be warned that +if you unbind the quit key and don't bind a new key for quitting, you +may be unable to exit gnuboy cleanly! + +The "unbind" command is similar, but it only unbinds one key at a +time. For example, to unbind the "space" key, use this command: + + unbind space + +See below for a list of key names to use with unbind. + +Now we get to the main useful keybinding command: "bind". For example, +if you want the "tab" key to perform the Gameboy "select" button +function, use the following bind command: + + bind tab +select + +The significance of the + sign will be explained below. As with the +"set" command, quotation marks can be used with bind if the command +needs to contain spaces. + + + KEY NAMES FOR BINDINGS + +When using the bind and unbind commands, you need to tell gnuboy which +key you wish to affect. Most of the keys that correspond to a +character you can type can just be referenced by that character. For +example, the alphabetical keys are bound by the lowercase letter they +represent, and the numeral keys (on the main keyboard, not the numeric +keypad) can be bound by their numeral. Other keys require a name. Some +are really obvious: + + shift, ctrl, alt, up, down, right, left + enter, tab, space, home, end, esc, pause + f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12 + +Others are a bit less obvious but still should make sense. Some of +these can also be referenced by other names; read the source file +keytable.c for a full list: + + bs Backspace + ins Insert + del Delete + prior Page Up + next Page Down + caps Caps Lock + numlock Num Lock + scroll Scroll Lock + minus - or _ + equals = or + + tilde ` or ~ + slash / or ? + bslash \ or | + semi ; or : + quote ' or " + +The numeric keypad is referenced as follows + + num0-num9 Numeral keys 0-9 (on keypad) + numplus Numeric keypad + + numminus Numeric keypad - + nummul Numeric keypad * + numdiv Numeric keypad / + numdot Numeric keypad . + numenter Numeric keypad Enter key + +Joystick buttons and directions also have names for binding, and they +are bound just like ordinary keys. Their names are as follows: + + joyup Joystick up + joydown Joystick down + joyleft Joystick left + joyright Joystick right + joy0-joy15 Joystick buttons + +The way joystick buttons are numbered varies from one joystick to +another. Experiment to find the names that are right for the buttons +you want to use. + + + RC FILES -- THE SOURCE COMMAND + +The "source" command simply causes gnuboy to process another rc file +before resuming processing of the current one. It is useful for +splitting up your config into multiple parts, perhaps one file +auto-generated by a front-end and another hand-customized. Use of this +command is very simple: + + source myfile.rc + +will perform all the commands in myfile.rc. Note that the source +command also provides a method for binding multiple commands to a +single key. For example, simply + + bind f1 "source f1stuff.rc" + +and then f1stuff.rc will be run whenever you press F1. + + + RC FILES -- ACTION COMMANDS + +Finally, we have rc commands that perform actions. These commands are +probably only useful when bound to a key, and might cause unexpected +behavior or even crashes if used by themselves in an rc file loaded at +startup. + +First of all, the "quit" command should be obvious. It simply exits +the emulator. If the rom that's loaded uses battery backed save ram or +realtime clock, these files will automatically be saved at exit. + +The "reset" command should also be fairly obvious. It acts as a reset +button, restarting execution of the loaded rom at the beginning, as if +you turned the Gameboy power off and back on. + +Slightly more interesting are the "savestate" and "loadstate" +commands. These are used for saving and resuming "saved state" files, +which allow you to save the exact status of the emulation environment +and restore it later, effectively letting you "save game" at any point +in any game. If a number is specified after either of those commands, +the indicated save slot number is used. Otherwise, the slot set in the +"saveslot" variable will be used. See the information on variables +below for more info. + +Most importantly, we have the action commands that control the +emulated Gameboy input pad. They are described below: + + + COMMANDS THAT BEGIN WITH A PLUS SIGN + +Normally, gnuboy only performs the command bound to a key when the key +is pressed; nothing happens when it is released. But for some things, +particularly the Gameboy pad buttons, it's important for something to +happen when the bound key is released. This is the purpose of commands +that begin with a + sign. When a key is released, gnuboy checks to see +if the bound command begins with +, and if so, it changes the + to - +and performs the resulting command. This causes the Gameboy pad +buttons to go back to their normal state when the keys bound to them +are released. + +The Gameboy pad commands, which should be self-explanatory, are as +follows: + + +a, +b, +start, +select, +up, +down, +left, +right + +If you're at all familiar with Quake's config system, this should all +be clear. + + + THE GNUBOY COMMAND LINE + +Additional rc files to process, variable settings, and keybindings can +be specified on the command line when gnuboy is run. + +Processing an extra config file is simple: + + gnuboy --source myfile.rc game.gb + +Specifying an extra rc file on the command line like this is +especially useful for frontends, which may want to put all the options +they set in one rc file so they don't have to pass a super-long +command line to gnuboy. + +Binding keys is also pretty simple. Just use something like: + + gnuboy --bind tab +select game.gb + +Setting variables is where things get a bit more complicated. For +on/off (boolean) settings, you can just do something like + + gnuboy --no-sound game.gb + +to turn a variable (sound) off, i.e. set it to 0. Likewise, boolean +variables can be turned on via something like + + gnuboy --rgb332 game.gb + +which turns the "rgb332" variable on (see below for information on +what it does). + +For other variables where you actually want to set a number or a +string, use this form: + + gnuboy --savename=mygame2 game.gb + +Finally, for variables with multiple numbers to be set, you can +separate them by commas as follows: + + gnuboy --vmode=512,384,32 + +to avoid having to quote the spaces. + + +[ P A R T I I ] + GUIDE TO CONFIGURABLE VARIABLES + +What follows is a detailed explanation of most of the configuration +variables available for your tweaking. They are organized by what part +of gnuboy's behavior they affect -- graphics, sound, emulation, and so +on. + +Some variables may or may not be available depending on how gnuboy was +built. For example, if you built gnuboy on a system without sound +support, some variables related to sound may not exist for you, and +attempts to set them will be silently ignored. In most cases, it's +noted in the documentation when variables might not be available. + +Also, there are a few highly system-specific variables, such as names +of devices to use for video and sound on *nix systems. These are +listed separately at the end, and it should go without saying that +they will not be available on all builds of gnuboy. + + + VIDEO AND GRAPHICS SETTINGS + +Since this is everyone's favorite thing to customize, video seems a +good place to start. + + + SCREEN SCALING + +There are a number of variables that control how gnuboy scales the +display. The most basic is the "scale" option, which is just the +factor to scale by. For example + + set scale 2 + +will double the size of the display. Set the scale factor to 1 for no +scaling. + +There are two ways gnuboy can go about doing scaling. The preferable +way is to use your computer's graphics hardware to do all the work. +This cuts down on the amount of CPU time consumed and provides +filtering to smooth out the blocky pixels, but it's not available on +all systems. The other way is for gnuboy to scale the screen itself. + +Normally gnuboy will choose hardware scaling automatically if it's +available, but if you want to force it on or off, you can set the +option "yuv" (for hardware YUV-colorspace scaling) to 1 or 0. Yes, +this option is poorly named, and is likely to change in future +versions of gnuboy. + +On one display platform, Linux fbcon, it's possible to disable the +interpolation filter in the hardware scaling. To do this, set the +variable "yuvinterp" to 0. Some users who like a crisper display may +prefer this setting, especially on video cards that make the picture +look "muddy" when they scale it. Unfortunately SDL does not seem to +provide such an option, so interpolation is always enabled on the SDL +based ports. + +When hardware scaling is disabled or not available, gnuboy will do its +own scaling. However, the scale factor is limited to 1, 2, 3, or 4. +Also, when performing its own scaling, gnuboy defaults to leaving some +scanlines blank. This saves a lot of CPU time and allows gnuboy to run +full speed on slower systems. You can configure what portion gets +filled in with the "density" variable. For example. + + set scale 4 + set density 4 + +will give you 4x scaling with no blank scanlines. Keep in mind that a +fairly fast computer (at least 400 MHz or so on x86, or something +comparable on other types of CPUs) is required to run fullspeed with +this setting. In general, "density" is the number of lines that get +filled in, so set it the same as "scale" if you want everything filled +in, or lower if you need more speed. + + + VIDEO MODE + +The variable for setting the desired video mode is called "vmode", and +it's made up of three parts: width, height, and bits-per-pixel. For +example, to set 640x480x16bpp mode, use + + set vmode 640 480 16 + +By default gnuboy will enable hardware scaling and try to scale to the +entire screen size if a video mode at least 320x288 is specified. If +you don't want this behavior, set the "yuv" option (see above) to 0. +Also, if you're setting the "scale" variable to do scaling, you +probably don't need to use the "vmode" option, since gnuboy will +try to automatically pick a mode that fits the scale. It's there in +case you need it, though. + +Note that the DOS port is not yet capable of auto-choosing a video +mode, so if you want anything but the default 320x200x8bpp you'll have +to set "vmode" yourself. Also, not all ports are capable of all modes. +Experiment to find what works for you. Video mode selection is a +little bit messy and confusing at this time, and we hope to improve it +a good deal in the future. + + + FULLSCREEN VIDEO + +Some versions of gnuboy provide both fullscreen and windowed +operation. The variable "fullscreen" can be set to 1 or 0 to enable or +disable fullscreen mode. Also, the variable "altenter" can be set to +enable or disable switching between fullscreen and windowed mode at +runtime with the Alt+Enter key combination. Unfortunately, this does +not yet work on Windows; we hope to fix this limitation in the +future. + + + DMG PALETTE SELECTION + +gnuboy allows you to set the palette used for grayscale when running +DMG (original mono Gameboy) roms. There are four variables for this +purpose, allowing the background, window, and both sprite palettes to +be colored differently. Each one is made up of four numbers, the color +to use for each shade of gray, from lightest to darkest. Colors are +represented as 24bit numbers, with red in the low (rightmost) places +and blue in the upper (leftmost) places. Although you could specify +colors in decimal (base 10) if you really wanted, they'd be very +difficult to read, so it's preferable to use hex (base 16). + +For example, to set the background to shades of white, the window to +shades of red, and the sprite palettes to shades of green and blue, +you could use: + + set dmg_bgp 0xffffff 0xaaaaaa 0x555555 0x000000 + set dmg_wndp 0x0000ff 0x0000aa 0x000055 0x000000 + set dmg_obp0 0x00ff00 0x00aa00 0x005500 0x000000 + set dmg_obp1 0xff0000 0xaa0000 0x550000 0x000000 + +This will of course look rather ugly, but it does the job illustrating +how you set various colors. + +For more extensive examples, see the sample file palette.rc included +with gnuboy, which provides a number of sample palettes to try. + + + RGB MODE WITH ONLY 256 COLORS + +Normally when run in 256-color (8bpp) modes, gnuboy will dynamically +allocate colors in the palette as they're needed. However, on the +Gameboy Color, it's possible to have well over 1000 colors on the +screen at a time, and in games that make use of these "hicolor" +tricks, gnuboy will run out of colors and things will look bad. + +If you prefer, you can set the "rgb332" variable: + + set rgb332 1 + +This tells gnuboy that instead of using 256-color mode as a +palette-based mode, you want it to setup a static palette and pretend +8bpp is just a really low quality "truecolor" mode, with only 3 bits +of precision in red and green, and only 2 bits of precision in blue. +In general this will make most games look worse, since colors have to +be approximated fairly poorly and since smooth color gradients are not +possible, but it will make "hicolor" Gameboy Color games look a good +deal better. Also, rgb332 mode should run slightly faster since it +avoids the overhead in dynamic palette allocation. + +If you have to run at 8bpp mode, try it with and without this option +and see which way you like better. Of course, the better solution, if +at all possible, is to use 16bpp or higher mode, but that may run too +slowly on older computers. + + + COLOR FILTERING + +Optionally, gnuboy can filter screen colors to make them look more +washed out or faded like on a real GBC. To enable this feature, + + set colorfilter 1 + +By default, gnuboy will not apply the filter when running DMG (mono) +games, since many of the sample palettes are already designed to +immitate a Gameboy LCD. If you would like to have the filter also take +effect when running in DMG mode, + + set filterdmg 1 + +You can also customize the filter parameters to get different color +effects from the default ones. See the sample file filters.rc for +examples. + + + SPRITE SORTING + +Normally sprites are sorted and prioritized according to their x +coordinate when in DMG mode. However, this takes a little bit of extra +cpu time, and it's not needed by most DMG games, so it can be disabled +as follows: + + set sprsort 0 + +Note that although sprite sorting was disabled in previous releases +because it was not working properly, it now works great, so unless you +really need to maximize performance, you should probably leave it +enabled. + + + SOUND OPTIONS + +Fortunately sound is a lot simpler than video. At this time, there are +no fancy interpolation or filtering options, only your basic audio +parameters. + +To enable or disable sound, set the "sound" variable to 1 or 0. By +default, it's enabled. + +To enable or disable stereo sound, set the "stereo" variable to 1 or +0. It defaults to 1 on most ports, but since stereo sometimes fails +to work properly on DOS, it's disabled by default on the DOS port. +Disabling stereo in no way improves performance, so it should only be +done if stereo mode causes a problem on your computer. + +To set the audio sampling rate, use the "samplerate" variable. The +default is 44100 Hz. Setting this lower can improve performance. For +example, if you have a really slow computer, you might use: + + set samplerate 8000 + +Keep in mind that this will sound really really bad. + + + FILESYSTEM OPTIONS + +There are a good deal of options that affect where and how files are +saved and loaded by gnuboy. First, there's "rcpath", which specifies +where gnuboy searches for rc files. The default depends on your +operating system; see the beginning of this file for details. + +The search path for rc files can contain multiple directories. +Normally, the list is separated by colons (:), but on DOS and Windows +the colon is used for drive letters, so semicolon (;) must be used +instead. Here are some examples, first for *nix: + + set rcpath "/home/laguna/.gnuboy:/usr/local/etc/gnuboy" + set rcpath "." + +and for DOS/Windows: + + set rcpath "c:/gnuboy;." + set rcpath "c:/Program Files/Gnuboy" + +If you really insist on using backslashes on DOS or Windows, you'll +have to double them up, since the backslash normally means "treat the +next character literally." For example, + + set rcpath "c:\\gnuboy" + +This is untested, and your milage may vary. I recommend just using +forward slashes and keeping things simple. + + + SAVE RELATED OPTIONS + +These are all fairly simple, so I'll just list them quickly, then give +a couple examples. + + savedir - directory to store saved games (SRAM and savestates) in + savename - base filename to use for saves + saveslot - which savestate slot to use + forcebatt - always save SRAM even on carts that don't have battery + nobatt - never save SRAM + syncrtc - resync the realtime clock for elapsed time when loading + +The "savename" variable is particularly useful if you wish to have +more than one save associated with a particular rom. Just do something +like: + + gnuboy --savename=mygame2 mygame.gb + +and the save files will be called mygame2.sav, mygame2.000, etc rather +than just mygame.sav, etc. + +The "saveslot" variable is normally just changed by keybindings, so +you can pick a savestate slot while you're playing a game. However, if +you for example prefer that the default slot at startup be 1 rather +than 0, you can use: + + set saveslot 1 + +The "forcebatt" and "nobatt" options are fairly self-explanatory and +not very useful, except perhaps for debugging or use with corrupted +roms. + +The "syncrtc" option needs a bit of explanation. Some roms, notably +Pokemon ones and Harvest Moon, use a realtime clock to keep track of +the time of day even when they're not running. Since gnuboy is just an +emulator, it can't work like a real cartridge and make things like +this keep happening while the emulator is not running. However, it can +resync the Gameboy realtime clock based on your computer's clock when +it starts. This is what the "syncrtc" option does. By default it's +enabled. If you disable it, then no time will seem to have elapsed +between when you exit the emulator once and when you start it again +the next time. + + + JOYSTICK OPTIONS + +So far there is just one joystick option, "joy", used to enable or +disable joystick support. + + + DEBUGGING OPTIONS + +These probably won't be useful to most people, but if you're trying to +debug a homebrew game you're writing or fix a bug in gnuboy they might +be of help: + +The "trace" variable, if enabled, dumps a full execution trace to +stdout. Be prepared for at least 20 megs of logs to look through at +minimum, and more like 150 megs if you want enough to find anything +useful. Redirecting stdout to a file is a must! + +The "sprdebug" variable is used to see how many sprites are visible +per line. Try it and see! + + + PLATFORM-SPECIFIC OPTIONS + +On certain *nix systems, you may need to specify device nodes to use +if the defaults don't work: + + oss_device - Open Sound System "DSP" device + fb_device - Video framebuffer device + joy_device - Joystick device + +The Linux fbcon version of gnuboy does not support the "vmode" option +yet, but it can set the mode for you by running the "fbset" program, +if you have it. Just set the "fb_mode" variable to the exact name of +the mode you want in /etc/fb.modes. For example, + + set fb_mode 640x480-90 + +You can also override the default color depth with the "fb_depth" +variable. + +The DOS port of gnuboy has support for real console system gamepads +via the "Directpad Pro" (DPP) connector. To enable this feature, set +"dpp" to 1, set "dpp_port" to the IO port number the pad is connected +to (e.g. 0x378 -- be sure to prefix it with 0x for hex!!), and set +"dpp_pad" to the number of the pad you want to use. This code has not +been heavily tested, so it may or may not work for you. Be sure to get +the port number right or bad things may happen! + + + CONCLUSION + +Well, that's about it for configuration. Hopefully this document +clears up a lot of the confusion about what you can and can't +configure in gnuboy yet, and how you go about doing it. Again, check +the sample.rc, palette.rc, and classic.rc files for lots of examples +of how rc files work. + +As always, more info will come as time passes on. Keep on the lookout +for new releases and more features. Thank you for flying gnuboy and +have a nice day. + + + + - Laguna diff --git a/docs/CREDITS b/docs/CREDITS new file mode 100644 index 0000000..cbabf76 --- /dev/null +++ b/docs/CREDITS @@ -0,0 +1,65 @@ + + +Gilgamesh -- +concept +research +testing +debug and tools coding +website and build maintainence +publicity +dos and windows builds + +Laguna -- +design +main program +asm optimizations +documentation +publicity + +Damian M Gryski -- +SDL port +various bugfix patches + +Ralf Hoffmann -- +Linux joystick code +SDL joystick bugfix + +David Lau -- +SDL joystick code + +Mattias Wadman -- +help with OpenBSD portability issues +LCDC behavior information + +Matthew Conte -- +DOS sound code +thinlib + +Markus F.X.J. Oberhumer -- +SDL fullscreen code + +Dave Kiddell -- +Windows port (SDL+mingw32) +SDL bugfixes + +Magnus Damm -- +YUV colorspace code +SDL YUV hardware scaling support + +Gerd Knorr -- +fbtv, from which mga accel code was taken + +Jonathan Gevaryahu AKA Lord Nightmare -- +tons of help improving sound emulation! +color filter code and default filter values +misc debugging support + +Neil Stevens -- +collecting samples for sound channel 4 (noise) + +David Madore -- +public domain "inflate" decompressor + +Hii (author of TGB) -- +lots of info on various memory mappers + diff --git a/docs/FAQ b/docs/FAQ new file mode 100644 index 0000000..479121d --- /dev/null +++ b/docs/FAQ @@ -0,0 +1,90 @@ + +GNUBOY FREQUENTLY ASKED QUESTIONS + + +Q: How do I configure gnuboy? + +A: You can specify various options to gnuboy by means of "rcvars", +either on the command line or in your gnuboy.rc file. To set rcvars +from the command line, just use --varname=value, or --no-varname to +turn off yes/no options. If you wish to use a gnuboy.rc file, create +it with any text editor and save it in ~/.gnuboy (for *nix systems) or +the same directory as gnuboy.exe (for DOS/Windows systems). In this +file you can set rcvars with lines of the form "set varname value". +See the sample.rc file included for examples. + + +Q: Are you planning to add serial cable (gamelink) emulation? + +A: Yes, read the wishlist in the README. At this time we don't have +all the technical information to emulate it 100% correctly, so if you +think you can help us find the info, get in touch. + + +Q: gnuboy is too slow. How can I make it run faster? + +A: You can try turning the sampling rate for sound down (for example, +--samplerate=22050) or disabling sound entirely (--no-sound). Also, +running at 8bpp with --rgb565 enabled will result in the highest video +performance at the expense of some color quality. Of course, gnuboy is +very fast, and shouldn't need any performance tweaks as long as your +system is at least as fast as a Pentium/120. + + +Q: Why did the keybindings change in 1.0? + +A: Even though lots of emulators do it, we figured it wasn't a very +good idea to use modifier keys for the controls, since some systems +may be configured to trap these for other uses. This especially became +a problem after adding support for Alt+Enter to toggle fullscreen. If +you want to go back to the old bindings and don't want to configure +them yourself, you can find all the old settings (including the old +default palette) in classic.rc. Just copy and paste to your gnuboy.rc. + + +Q: Will gnuboy ever support recording and playback? + +A: We get this question fairly often, and I'm never sure how to answer +it. We are planning to support recording audio output before too +terribly long, but whether full demo recording and playback will ever +be supported is uncertain. We'll keep it in mind for the future, +though. + + +Q: Why doesn't gnuboy do anything when I run it? + +A: You need to specify the name of the ROM to load on the command +line. One way to do this on Windows is to drag the ROM file onto +gnuboy.exe (or a shortcut to it). Associating *.gb and *.gbc with +gnuboy also works. Of course, you can also just use the run command on +the start menu, or open a dos prompt. Unix users of course are +expected to know how to run programs. + + +Q: gnuboy doesn't run on WinNT/2k!! + +A: Set the following environment variables before running: + SDL_VIDEODRIVER=windib + SDL_AUDIODRIVER=waveout +Doing so should fix problems with other SDL programs too. If it still +doesn't work, let us know. Your milage may vary; some people have +reported that this doesn't help. + + +Q: Why is sound pitch off by about 1% in gnuboy? + +A: You have a very good ear. It's a rounding issue that won't be +outright fixed for a while. If you want a workaround, set the sample +rate to a power of two (for example 32768 works well) on the command +line or in your gnuboy.rc. + + +Q: Why does sound have ugly static noise on Windows? + +A: This is a bug in SDL's DirectSound support. Try setting the +environment variable: + SDL_AUDIODRIVER=waveout +before running gnuboy. Hopefully this won't cause any problems. + + + diff --git a/docs/HACKING b/docs/HACKING new file mode 100644 index 0000000..3efd85e --- /dev/null +++ b/docs/HACKING @@ -0,0 +1,472 @@ + +HACKING ON THE GNUBOY SOURCE TREE + + + BASIC INFO + +In preparation for the first release, I'm putting together a simple +document to aid anyone interested in playing around with or improving +the gnuboy source. First of all, before working on anything, you +should know my policies as maintainer. I'm happy to accept contributed +code, but there are a few guidelines: + +* Obviously, all code must be able to be distributed under the GNU +GPL. This means that your terms of use for the code must be equivalent +to or weaker than those of the GPL. Public domain and MIT-style +licenses are perfectly fine for new code that doesn't incorporate +existing parts of gnuboy, e.g. libraries, but anything derived from or +built upon the GPL'd code can only be distributed under GPL. When in +doubt, read COPYING. + +* Please stick to a coding and naming convention similar to the +existing code. I can reformat contributions if I need to when +integrating them, but it makes it much easier if that's already done +by the coder. In particular, indentions are a single tab (char 9), and +all symbols are all lowercase, except for macros which are all +uppercase. + +* All code must be completely deterministic and consistent across all +platforms. this results in the two following rules... + +* No floating point code whatsoever. Use fixed point or better yet +exact analytical integer methods as opposed to any approximation. + +* No threads. Emulation with threads is a poor approximation if done +sloppily, and it's slow anyway even if done right since things must be +kept synchronous. Also, threads are not portable. Just say no to +threads. + +* All non-portable code belongs in the sys/ or asm/ trees. #ifdef +should be avoided except for general conditionally-compiled code, as +opposed to little special cases for one particular cpu or operating +system. (i.e. #ifdef USE_ASM is ok, #ifdef __i386__ is NOT!) + +* That goes for *nix code too. gnuboy is written in ANSI C, and I'm +not going to go adding K&R function declarations or #ifdef's to make +sure the standard library is functional. If your system is THAT +broken, fix the system, don't "fix" the emulator. + +* Please no feature-creep. If something can be done through an +external utility or front-end, or through clever use of the rc +subsystem, don't add extra code to the main program. + +* On that note, the modules in the sys/ tree serve the singular +purpose of implementing calls necessary to get input and display +graphics (and eventually sound). Unlike in poorly-designed emulators, +they are not there to give every different target platform its own gui +and different set of key bindings. + +* Furthermore, the main loop is not in the platform-specific code, and +it will never be. Windows people, put your code that would normally go +in a message loop in ev_refresh and/or sys_sleep! + +* Commented code is welcome but not required. + +* I prefer asm in AT&T syntax (the style used by *nix assemblers and +likewise DJGPP) as opposed to Intel/NASM/etc style. If you really must +use a different style, I can convert it, but I don't want to add extra +dependencies on nonstandard assemblers to the build process. Also, +portable C versions of all code should be available. + +* Have fun with it. If my demands stifle your creativity, feel free to +fork your own projects. I can always adapt and merge code later if +your rogue ideas are good enough. :) + +OK, enough of that. Now for the fun part... + + + THE SOURCE TREE STRUCTURE + +[documentation] +README - general information related to using gnuboy +INSTALL - compiling and installation instructions +HACKING - this file, obviously +COPYING - the gnu gpl, grants freedom under condition of preseving it + +[build files] +Version - doubles as a C and makefile include, identifies version number +Rules - generic build rules to be included by makefiles +Makefile.* - system-specific makefiles +configure* - script for generating *nix makefiles + +[non-portable code] +sys/*/* - hardware and software platform-specific code +asm/*/* - optimized asm versions of some code, not used yet +asm/*/asm.h - header specifying which functions are replaced by asm +asm/i386/asmnames.h - #defines to fix _ prefix brain damage on DOS/Windows + +[main emulator stuff] +main.c - entry point, event handler...basically a mess +loader.c - handles file io for rom and ram +emu.c - another mess, basically the frame loop that calls state.c +debug.c - currently just cpu trace, eventually interactive debugging +hw.c - interrupt generation, gamepad state, dma, etc. +mem.c - memory mapper, read and write operations +fastmem.h - short static functions that will inline for fast memory io +regs.h - macros for accessing hardware registers +save.c - savestate handling + +[cpu subsystem] +cpu.c - main cpu emulation +cpuregs.h - macros for cpu registers and flags +cpucore.h - data tables for cpu emulation +asm/i386/cpu.s - entire cpu core, rewritten in asm + +[graphics subsystem] +fb.h - abstract framebuffer definition, extern from platform-specifics +lcd.c - main control of refresh procedure +lcd.h - vram, palette, and internal structures for refresh +asm/i386/lcd.s - asm versions of a few critical functions +lcdc.c - lcdc phase transitioning + +[input subsystem] +input.h - internal keycode definitions, etc. +keytables.c - translations between key names and internal keycodes +events.c - event queue + +[resource/config subsystem] +rc.h - structure defs +rccmds.c - command parser/processor +rcvars.c - variable exports and command to set rcvars +rckeys.c - keybindingds + +[misc code] +path.c - path searching +split.c - general purpose code to split strings into argv-style arrays + + + OVERVIEW OF PROGRAM FLOW + +The initial entry point main() main.c, which will process the command +line, call the system/video initialization routines, load the +rom/sram, and pass control to the main loop in emu.c. Note that the +system-specific main() hook has been removed since it is not needed. + +There have been significant changes to gnuboy's main loop since the +original 0.8.0 release. The former state.c is no more, and the new +code that takes its place, in lcdc.c, is now called from the cpu loop, +which although slightly unfortunate for performance reasons, is +necessary to handle some strange special cases. + +Still, unlike some emulators, gnuboy's main loop is not the cpu +emulation loop. Instead, a main loop in emu.c which handles video +refresh, polling events, sleeping between frames, etc. calls +cpu_emulate passing it an idea number of cycles to run. The actual +number of cycles for which the cpu runs will vary slightly depending +on the length of the final instruction processed, but it should never +be more than 8 or 9 beyond the ideal cycle count passed, and the +actual number will be returned to the calling function in case it +needs this information. The cpu code now takes care of all timer and +lcdc events in its main loop, so the caller no longer needs to be +aware of such things. + +Note that all cycle counts are measured in CGB double speed MACHINE +cycles (2**21 Hz), NOT hardware clock cycles (2**23 Hz). This is +necessary because the cpu speed can be switched between single and +double speed during a single call to cpu_emulate. When running in +single speed or DMG mode, all instruction lengths are doubled. + +As for the LCDC state, things are much simpler now. No more huge +glorious state table, no more P/Q/R, just a couple simple functions. +Aside from the number of cycles left before the next state change, all +the state information fits nicely in the locations the Game Boy itself +provides for it -- the LCDC, STAT, and LY registers. + +If the special cases for the last line of VBLANK look strange to you, +good. There's some weird stuff going on here. According to documents +I've found, LY changes from 153 to 0 early in the last line, then +remains at 0 until the end of the first visible scanline. I don't +recall finding any roms that rely on this behavior, but I implemented +it anyway. + +That covers the basics. As for flow of execution, here's a simplified +call tree that covers most of the significant function calls taking +place in normal operation: + + main sys/ + \_ real_main main.c + |_ sys_init sys/ + |_ vid_init sys/ + |_ loader_init loader.c + |_ emu_reset emu.c + \_ emu_run emu.c + |_ cpu_emulate cpu.c + | |_ div_advance cpu.c * + | |_ timer_advance cpu.c * + | |_ lcdc_advance cpu.c * + | | \_ lcdc_trans lcdc.c + | | |_ lcd_refreshline lcd.c + | | |_ stat_change lcdc.c + | | | \_ lcd_begin lcd.c + | | \_ stat_trigger lcdc.c + | \_ sound_advance cpu.c * + |_ vid_end sys/ + |_ sys_elapsed sys/ + |_ sys_sleep sys/ + |_ vid_begin sys/ + \_ doevents main.c + + (* included in cpu.c so they can inline; also in cpu.s) + + + MEMORY READ/WRITE MAP + +Whenever possible, gnuboy avoids emulating memory reads and writes +with a function call. To this end, two pointer tables are kept -- one +for reading, the other for writing. They are indexed by bits 12-15 of +the address in Game Boy memory space, and yield a base pointer from +which the whole address can be used as an offset to access Game Boy +memory with no function calls whatsoever. For regions that cannot be +accessed without function calls, the pointer in the table is NULL. + +For example, reading from address addr can be accomplished by testing +to make sure mbc.rmap[addr>>12] is not NULL, then simply reading +mbc.rmap[addr>>12][addr]. + +And for the disbelievers in this optimization, here are some numbers +to compare. First, FFL2 with memory tables disabled: + + % cumulative self self total + time seconds seconds calls us/call us/call name + 28.69 0.57 0.57 refresh_2 + 13.17 0.84 0.26 4307863 0.06 0.06 mem_read + 11.63 1.07 0.23 cpu_emulate + +Now, with memory tables enabled: + + 38.86 0.66 0.66 refresh_2 + 8.42 0.80 0.14 156380 0.91 0.91 spr_enum + 6.76 0.91 0.11 483134 0.24 1.31 lcdc_trans + 6.16 1.02 0.10 cpu_emulate + . + . + . + 0.59 1.61 0.01 216497 0.05 0.05 mem_read + +As you can see, not only does mem_read take up (proportionally) 1/20 +as much time, since it is rarely called, but the main cpu loop in +cpu_emulate also runs considerably faster with all the function call +overhead and cache misses avoided. + +These tests were performed on K6-2/450 with the assembly cores +enabled; your milage may vary. Regardless, however, I think it's clear +that using the address mapping tables is quite a worthwhile +optimization. + + + LCD RENDERING CORE DESIGN + +The LCD core presently used in gnuboy is very much a high-level one, +performing the task of rasterizing scanlines as many independent steps +rather than one big loop, as is often seen in other emulators and the +original gnuboy LCD core. In some ways, this is a bit of a tradeoff -- +there's a good deal of overhead in rebuilding the tile pattern cache +for roms that change their tile patterns frequently, such as full +motion video demos. Even still, I consider the method we're presently +using far superior to generating the output display directly from the +gameboy tiledata -- in the vast majority of roms, tiles are changed so +infrequently that the overhead is irrelevant. Even if the tiles are +changed rapidly, the only chance for overhead beyond what would be +present in a monolithic rendering loop lies in (host cpu) cache misses +and the possibility that we might (tile pattern) cache a tile that has +changed but that will never actually be used, or that will only be +used in one orientation (horizontally and vertically flipped versions +of all tiles are cached as well). Such tile caching issues could be +addressed in the long term if they cause a problem, but I don't see it +hurting performance too significantly at the present. As for host cpu +cache miss issues, I find that putting multiple data decoding and +rendering steps together in a single loop harms performance much more +significantly than building a 256k (pattern) cache table, on account +of interfering with branch prediction, register allocation, and so on. + +Well, with those justifications given, let's proceed to the steps +involved in rendering a scanline: + +updatepatpix() - updates tile pattern cache. + +tilebuf() - reads gb tile memory according to its complicated tile +addressing system which can be changed via the LCDC register, and +outputs nice linear arrays of the actual tile indices used in the +background and window on the present line. + +Before continuing, let me explain the output format used by the +following functions. There is a byte array scan.buf, accessible by +macro as BUF, which is the output buffer for the line. The structure +of this array is simple: it is composed of 6 bpp gameboy color +numbers, where the bits 0-1 are the color number from the tile, bits +2-4 are the (cgb or dmg) palette index, and bit 5 is 0 for background +or window, 1 for sprite. + +What is the justification for using a strange format like this, rather +than raw host color numbers for output? Well, believe it or not, it +improves performance. It's already necessary to have the gameboy color +numbers available for use in sprite priority. And, when running in +mono gb mode, building this output data is VERY fast -- it's just a +matter of doing 64 bit copies from the tile pattern cache to the +output buffer. + +Furthermore, using a unified output format like this eliminates the +need to have separate rendering functions for each host color depth or +mode. We just call a one-line function to apply a palette to the +output buffer as we copy it to the video display, and we're done. And, +if you're not convinced about performance, just do some profiling. +You'll see that the vast majority of the graphics time is spent in the +one-line copy function (render_[124] depending on bytes per pixel), +even when using the fast asm versions of those routines. That is to +say, any overhead in the following functions is for all intents and +purposes irrelevant to performance. With that said, here they are: + +bg_scan() - expands the background layer to the output buffer. + +wnd_scan() - expands the window layer. + +spr_scan() - expands the sprites. Note that this requires spr_enum() +to have been called already to build a list of which sprites are +visible on the current scanline and sort them by priority. + +It should be noted that the background and window functions also have +color counterparts, which are considerably slower due to merging of +palette data. At this point, they're staying down around 8% time +according to the profiler, so I don't see a major need to rewrite them +anytime soon. It should be considered, however, that a different +intermediate format could be used for gbc, or that asm versions of +these two routines could be written, in the long term. + +Finally, some notes on palettes. You may be wondering why the 6 bpp +intermediate output can't be used directly on 256-color display +targets. After all, that would give a huge performance boost. The +problem, however, is that the gameboy palette can change midscreen, +whereas none of the presently targetted host systems can handle such a +thing, much less do it portably. For color roms, using our own +internal color mappings in addition to the host system palette is +essential. For details on how this is accomplished, read palette.c. + +Now, in the long term, it MAY be possible to use the 6 bpp color +"almost" directly for mono roms. Note that I say almost. The idea is +this. Using the color number as an index into a table is slow. It +takes an extra read and causes various pipeline stalls depending on +the host cpu architecture. But, since there are relatively few +possible mono palettes, it may actually be possible to set up the host +palette in a clever way so as to cover all the possibilities, then use +some fancy arithmetic or bit-twiddling to convert without a lookup +table -- and this could presumably be done 4 pixels at a time with +32bit operations. This area remains to be explored, but if it works, +it might end up being the last hurdle to getting realtime emulation +working on very low-end systems like i486. + + + SOUND + +Rather than processing sound after every few instructions (and thus +killing the cache coherency), we update sound in big chunks. Yet this +in no way affects precise sound timing, because sound_mix is always +called before reading or writing a sound register, and at the end of +each frame. + +The main sound module interfaces with the system-specific code through +one structure, pcm, and a few functions: pcm_init, pcm_close, and +pcm_submit. While the first two should be obvious, pcm_submit needs +some explaining. Whenever realtime sound output is operational, +pcm_submit is responsible for timing, and should not return until it +has successfully processed all the data in its input buffer (pcm.buf). +On *nix sound devices, this typically means just waiting for the write +syscall to return, but on systems such as DOS where low level IO must +be handled in the program, pcm_submit needs to delay until the current +position in the DMA buffer has advanced sufficiently to make space for +the new samples, then copy them. + +For special sound output implementations like write-to-file or the +dummy sound device, pcm_submit should write the data immediately and +return 0, indicating to the caller that other methods must be used for +timing. On real sound devices that are presently functional, +pcm_submit should return 1, regardless of whether it buffered or +actually wrote the sound data. + +And yes, for unices without OSS, we hope to add piped audio output +soon. Perhaps Sun audio device and a few others as well. + + + OPTIMIZED ASSEMBLY CODE + +A lot can be said on this matter. Nothing has been said yet. + + + INTERACTIVE DEBUGGER + +Apologies, there is no interactive debugger in gnuboy at present. I'm +still working out the design for it. In the long run, it should be +integrated with the rc subsystem, kinda like a cross between gdb and +Quake's ever-famous console. Whether it will require a terminal device +or support the graphical display remains to be determined. + +In the mean time, you can use the debug trace code already +implemented. Just "set trace 1" from your gnuboy.rc or the command +line. Read debug.c for info on how to interpret the output, which is +condensed as much as possible and not quite self-explanatory. + + + PORTING + +On all systems on which it is available, the gnu compiler should +probably be used. Writing code specific to non-free compilers makes it +impossible for free software users to actively contribute. On the +other hand, compiler-specific code should always be kept to a minimum, +to make porting to or from non-gnu compilers easier. + +Porting to new cpu architectures should not be necessary. Just make +sure you unset IS_LITTLE_ENDIAN in the makefiles to enable the big +endian default if the target system is big endian. If you do have +problems building on certain cpus, however, let us know. Eventually, +we will also want asm cpu and graphics code for popular host cpus, but +this can wait, since the c code should be sufficiently fast on most +platforms. + +The bulk of porting efforts will probably be spent on adding support +for new operating systems, and on systems with multiple video (or +sound, once that's implemented) architectures, new interfaces for +those. In general, the operating system interface code goes in a +directory under sys/ named for the os (e.g. sys/nix/ for *nix +systems), and display interfaces likewise go in their respective +directories under sys/ (e.g. sys/x11/ for the x window system +interface). + +For guidelines in writing new system and display interface modules, i +recommend reading the files in the sys/dos/, sys/svga/, and sys/nix/ +directories. These are some of the simpler versions (aside from the +tricky dos keyboard handling), as opposed to all the mess needed for +x11 support. + +Also, please be aware that the existing system and display interface +modules are somewhat primitive; they are designed to be as quick and +sloppy as possible while still functioning properly. Eventually they +will be greatly improved. + +Finally, remember your obligations under the GNU GPL. If you produce +any binaries that are compiled strictly from the source you received, +and you intend to release those, you *must* also release the exact +sources you used to produce those binaries. This is not pseudo-free +software like Snes9x where binaries usually appear before the latest +source, and where the source only compiles on one or two platforms; +this is true free software, and the source to all binaries always +needs to be available at the same time or sooner than the +corresponding binaries, if binaries are to be released at all. This of +course applies to all releases, not just new ports, but from +experience i find that ports people usually need the most reminding. + + + EPILOGUE + +That's it for now. More info will eventually follow. Happy hacking! + + + + + + + + + + + + + diff --git a/docs/LIBERTY b/docs/LIBERTY new file mode 100644 index 0000000..07b6ee3 --- /dev/null +++ b/docs/LIBERTY @@ -0,0 +1,6 @@ + +LIBERTY + +For the true meaning of liberty, please visit the the Foundation's +philosopy page at http://www.gnu.org/philosophy/philosophy.html. + diff --git a/docs/README.old b/docs/README.old new file mode 100644 index 0000000..7e25655 --- /dev/null +++ b/docs/README.old @@ -0,0 +1,355 @@ + +GNUBOY README + + + INTRO + +Welcome to gnuboy, one of the few pieces of Free Software to emulate +the Game Boy handheld game console. Written in ANSI C with a few +optional assembler optimizations for particular cpus, gnuboy supports +a wide range of host systems, and has been tested successfully on: + + GNU/Linux + FreeBSD + OpenBSD + BeOS + Linux/390 (IBM S/390 Mainframe) + SunOS/Sun Ultra60 + IRIX/SGI O2 + IRIX/SGI Indy + AIX/Unknown + DR-DOS + MS-DOS + Windows DOS box + Windows 9x/NT/2k + +Additionally, gnuboy should run on any other *nix variants that have +ANSI C compilers and that are remotely POSIX compliant. As gnuboy is +Free Software, you're welcome to fix any problems you encounter +building it for a particular system, or to port it to entirely new +systems. + +For build instructions, see the file INSTALL. For information on the +structure of the source tree, program flow, design decisions and +guidelines, porting, and so on, read HACKING. + + + GENERAL USAGE + +Just pass the name of the rom to load on the command line. Default +keybindings are as follows: + + esc - exit + arrow keys - d-pad + alt - a + ctrl - b + space - select + enter - start + 0-9 - select savestate slot + ins - save current state + del - return to saved state + + joypad - d-pad + joy0 - b + joy1 - a + joy2 - select + joy3 - start + +(Note: joystick is not available on all platforms at this time.) + +If you want to change these or other options, you should create a +gnuboy.rc file. See the system-specific info below for where to put +it. + +The rc subsystem is very similar to Quake's console in many +respects. You have commands and variables. First, the commands: + + quit - exit gnuboy (saving sram) + reset - reset to powerup state + source - process another rc file + set - set a variable's value + bind - bind keys + unbind - remove a keybinding + unbindall - remove all keybindings + savestate - save current state + loadstate - return to saved state + +Additionally, each gameboy pad button has two commands, one to press +it, and another to release it -- for example, +start and -start. When +a key is bound to one of these commands that starts with a +, it will +perform the corresponding - command when it's released, as expected. + +Here's a list of the + commands, though they should be obvious: + + +start +select +a +b +up +down +left +right + +Now for the variables. To set any of the rc variables, just put the +command of the form "set variable value" in your gnuboy.rc or other rc +file. Some of the more interesting variables are: + + rcpath - search path for loading extra rc files + savedir - the directory where save files will be stored + savename - base of filename to use for sram and savestates + forcedmg - set to 1/true/yes to force color roms to play mono + framelen - delay in microseconds between frames + framecount - run only the given number of frames, then exit + + dmg_bgp - specify 4 custom colors to be used for mono background + dmg_wndp - same thing, but for the window layer + dmg_obp0 - and for sprite palette 0 + dmg_obp1 - and sprite palette 1 + + scale - factor for screen scaling; currently only 1 and 2 work + density - density level for screen scaling; see description below + + sprsort - x-sort sprites for correctness on dmg roms + + syncrtc - fake elapsed time on rtc since last session at startup + + trace - output a complete cpu trace to stdout + sprdebug - display bars indicating sprite count per line + +There are a few others which may or not be useful. Also, certain +system and display targets have their own variables, which will be +described in the relevant sections below. For more info on how the +variables work, read the source. + +For sample rc files, look in the etc/ directory. + +Finally, to display help, version, or copying information, use the +--help, --version, or --copying options respectively on the gnuboy +command line. + + + USAGE - *NIX SYSTEMS + +The file gnuboy.rc should be placed in ~/.gnuboy/. If it is not found +in this location, the current working directory will be +searched. The following defaults will be used: + + rcpath - ~/.gnuboy:. + savedir - ~/.gnuboy/saves + +If you don't like these, override them with gnuboy.rc. + +There are presently four *nix targets supported: X11, SDL, and Linux +fbcon and svgalib. In the future other fb devices (such as the Sun +console) should be supported as well. + +If you have problems with gnuboy running too slowly on svgalib, turn +off the vsync option, i.e. set vsync 0. Putting --no-vsync on the +command line works as well. At this point svgalib is the only one that +supports vsync, so it's a non-issue on the others. + + + USAGE - DOS and Windows + +Place your gnuboy.rc in the same directory as gnuboy.exe. You need to +specify a save directory in it; otherwise the working directory will +be used, which is probably not what you want. For example, if you've +installed gnuboy.exe in c:/gnuboy, and you want your saves to be +stored in c:/gnuboy/saves, place the following in a plain text file +called gnuboy.rc in c:/gnuboy. + + set savedir c:/gnuboy/saves + +By default stereo sound is disabled on DOS since it doesn't work right +on some of the systems we've tested; to enable it, add the following +line to your gnuboy.rc: + + set stereo 1 + + + VIDEO MODES + +Now all the display targets except Linux fbcon support the uniform +"vmode" rcvar to set the video mode. From the rc file, you can specify +a video mode like this (for 640x480, 16bpp): + + set vmode 640 480 16 + +Or you can specify the mode on the command line, as + + --vmode=640,480,16 + +If the requested video mode is not available, gnuboy may either give +an error message or use a similar available mode. + + + SCREEN SCALING + +Scaling by integral factors 1-4 is now supported. Just set the rcvar +"scale" to the desired scaling factor. Most of the display targets +will automatically choose a video mode appropriate to the chosen +scale, but DOS and Linux fbcon users should be aware they they need to +set the mode manually, as described above. Of course, if you prefer, +you can always set it manually. + +By default, for performance reasons, vertical scaling will not be +fully dense but will leave some blank scanlines. This behavior can be +adjusted by means of the "density" rcvar. Density 0, the default, +skips every other line. Nonzero values N fill in the first N copies of +the scanline, and leave the remaining scale-N scanlines blank. So, if +you want a fully filled in display (and the worst performance), you +should set density to the same value as scale. + +Please be aware that this code is still slightly experimental, and the +ways of configuring scaling may change considerably in the next few +releases. + + + HARDWARE ACCELERATED YUV-SPACE SCREEN SCALING + +If you're using the SDL display target and your video card/driver +supports it, hardware screen scaling is available. This feature +provides scaling to any size with almost no cpu usage! It's enabled by +default if the screen resolution is set to 320x288 or higher; manually +set the "yuv" rcvar to 0 or 1 to force it off or on, respectively. + +Scaling will be performed to fill the entire requested video mode. +For example, to scale to 640x480, either add the following line to +your gnuboy.rc: + + set vmode 640 480 + +or put --vmode=640,480 on the command line. A better alternative is to +just request a particular scale, for example with: + + set scale 4 + +or --scale=4 on the command line; this way the gameboy's near 1:1 +aspect ratio won't become distorted. + + + SOUND SUPPORT + +At this point all features are implemented and everything should be +right, so any incorrect sound output should be treated as a bug, which +we'll try to fix as soon as possible. + + + JOYSTICK AND GAMEPAD SUPPORT + +At this time, the Linux and SDL joystick devices are the only ones +supported. We hope to have DOS joystick support soon. + +Binding joystick controls works the same way as for the keyboard. Just +use the key names joyup, joydown, joyright, joyleft, joy0, joy1, joy2, +etc. Default bindings should probably be ok for most users, except +that A/B might be backwards on some gamepads. + + + PERFORMANCE + +Here are some performance estimates i've gathered (given in percent +cpu utilization, running at full 60 fps)... + + Optimized C Assembly + AMD K6-2/450 12% 8% + Pentium/75 (too slow) 70% + SGI O2 25% (no asm) + SGI Indy 70% (no asm) + Sun Ultra60 3-20% (no asm) + IBM S/390 about 0.3% (no asm) + +Note that these figures were computed before sound was implemented. +Until the sound code is further optimized, gnuboy may run somewhat +slower than these numbers suggest. + + + SUPPORTED MEMORY BANK CONTROLLERS (MBCS) + +At this time, gnuboy supports MBC1, MBC2, MBC3 (including realtime +clock), and MBC5 (including the version with rumble support, although +that functionality is omitted). + + + GRAPHICS SUPPORT + +Color Gameboy roms are supported completely, including so-called +"highcolor" tricks. Yes, even in 256-color mode, although in games +that use too many colors on one screen, the later ones will only be +approximated. Use a 16 bpp (or higher) display mode if this is a +problem. + +Alternatively, for games that look bad in 256 color mode, you can +run in simulated 3/3/2 bits per channel truecolor. Just set the +variable rgb332 to something nonzero (or just putting --rgb332 on the +command line will work). Color precision is lost somewhat, especially +in smooth gradients, but for the most part it looks very good. + +Much care has been put into ensuring that the lcd timings and +interrupts behave as closely to the real hardware as possible. A few +features remain unimplemented, such as reduced length HBLANK depending +on the number of sprites visible on the scanline, but the vast +majority of display tricks used in current roms work fine. + +We do, however, lack information on proper GDMA timings, which could +theoretically cause problems for some roms. If you can provide us with +accurate information, please do! + + + COMPATIBILITY + +Eventually I'll put detailed information here. For now, just see known +bugs for the few cases where roms fails. + + + KNOWN BUGS + +The portal between the temple and the Talon in FFL3 is glitched and +the game freezes for a second or two building the incorrect animation +when entering those screens. + +GDMA finishes instantly, whereas it should take time. Making it take +time breaks Wacky Races, last I checked, so apparently the documents I +have on GDMA timing are incorrect. Same goes for HDMA. Good +information would be much appreciated. + +The main loop in emu_run is very sloppy and not quite right, but it +works. + +Sound mixing is taking way too much cpu time. I have some ideas for +fixing this, and I plan to write optimized assembly code for sound +eventually. If it's a problem try turning down the sample rate. + +YUV-space hardware scaling only supports the common "YUY2" mode so +far. More modes will be added in the future. + + + REPORTING OR FIXING BUGS + +Found a bug not mentioned above, or better yet, fixed one? Send bug +reports or patches to gnuboy@starfox.org. Please be aware that +distribution of any code based on gnuboy must follow the provisions of +the GPL, so if you don't agree to this, don't send code to us or +anyone else. Let us know if you wish to be included in the credits. + +For guidelines regarding code contributions, see the file HACKING. + +Please be aware that evaluating contributed code and figuring out if +or how to work it in can take time. If we haven't done anything with +your code yet, please be patient. + + + THANKS + +Thanks goes out to everyone who's expressed interest in gnuboy by +writing -- users, porters, authors of other emulators, and so forth. +Apologies if we don't get a personal response out to everyone, but +either way, consider your feedback well appreciated. + + + EPILOGUE + +OK, that looks like about it. More to come, stick around... + + + + -Laguna + + + + + + diff --git a/docs/WHATSNEW b/docs/WHATSNEW new file mode 100644 index 0000000..75e964e --- /dev/null +++ b/docs/WHATSNEW @@ -0,0 +1,386 @@ + +* WHAT'S NEW * + + Here you will find a summary of the changes made in each released + version of gnuboy, organized from an end-user perspective. + Webmasters, please use this file as a basis for announcing new + versions; the CHANGES file is too technical and unorganized. + + + +RELEASE 1.0.3 + +All ANSI C incompatibilities should be fixed. Please report any that +remain. + +Various bugs encountered when building gnuboy on strange compilers +have been fixed. + +Internal support for decompressing gzipped roms now exists in a +minimal form. The inflate code used is taken from a quine +(self-reproducing program) written by David Madore and placed in the +public domain. This code is very portable but is rather slow and may +crash when given invalid data; however, there should be no impact on +security. Currently only gzip files (not pkzip files) are supported. + +HuC3 emultaion has been fixed to some extent. Robopon Sun and Star are +both playable now, but many features of the HuC3 are still not +implemented. + +Color filtering to make gnuboy look much more like a real CGB is now +included, thanks to the work of Jonathan Gevaryahu. + +A new rcvar "gbamode" has been added to unlock the GBA-only features +present in some newer CGB games. (This has nothing to do with GBA +emulation, which gnuboy does not do and will not do in the future.) + +Sprite sorting in DMG mode has been fixed. This should improve things +in various DMG games where sprites previously overlapped in the wrong +order. + + + +RELEASE 1.0.2 + +A minor problem in the frequency sweep function on sound channel 1 was +fixed, correcting the sound of the ice beam and metroid encounter +sound in Metroid 2. + +Sound channel 3 waveform data is now trashed when the sound is +played. This makes it more difficult for games and demos to detect +that they are running on an emulator. + +The channel 3 waveform is now properly initialized in both DMG and CGB +modes. Before it was incorrectly initialized to have frequency 16 +times too high, and the initial "random noise" pattern exhibited by +DMG wasn't emulated. R-Type now sounds much better. + +The sound length register for channel 3 now works properly, fixing the +title screen music in MegaMan 2. No thanks to gbspec.txt for having +blatently wrong info about this matter. + +Major problems with sound quality on channel 4 (noise) have been +fixed, and the pseudorandom sequence has been replaced to very closely +resemble that of a real Gameboy, thanks to the hard work of Lord +Nightmare. All these changes make a significant improvement in many +games, notably Metroid 2, Final Fantasy Legend II and III, Camp +Deadly, and Wario Land. + +Stereo channels are no longer backwards. + +The DMG STAT register write bug, which causes an interrupt if the STAT +register is written while in HBLANK or VBLANK, is now emulated. This +fixes Legend of Zerd and probably any other DMG game that will not run +on a real Gameboy Color. + +A hack/potential fix for a problem that kept Konami Collection Vol 1 +from working has been put in place. + +A major interrupt bug that prevented Amazing Penguin from running has +been fixed. + +Several bugs that could have resulted in crashes under strange +circumstances have been fixed. + +Other minor sound issues have been tweaked or fixed. + + + +RELEASE 1.0.1 + + BUGS FIXED + +Keys that didn't work in the SDL-based ports have now been fixed. +The --bindir= option to the configure script now works properly. +Running "make install" no longer fails when the destination directory +doesn't already exist. +Various minor cleanups. + + + +RELEASE 1.0.0 + + NEW FEATURES + +Auto-loading rc files on a per-rom basis. +Less intense yellow in the default mono palette. +Default keybindings no longer use modifier keys. +Lots of new documentation. +Hardware scaling on matroxfb now looks better. + + BUGS FIXED + +Disabled some useless optimizations to work around a bug in gcc 2.96, which +despite being a broken compiler has become rather popular since Redhat +decided to package it without sufficient testing. This will fix the problems +lots of people have reported when compiling. +Added --disable-arch option to configure to prevent the binaries built from +being dependent on the exact host cpu they're built on. This will allow +distro maintainers to build packages that work even on older cpus. + + + +RELEASE 0.9.13 + + NEW FEATURES + +Hardware scaling support on fbcon with matroxfb. + + PERFORMANCE + +Now all software scaling code has assembly implementations. + + COMPATIBILITY + +Invalid opcode crash in Montezuma's Return has been fixed. +Visual glitches in Pokemon Yellow are now fixed. + + BUGS FIXED + +Line refresh was taking place too late, causing visual glitch in Alleyway. +Flags behavior on the RL, RR, RLC, and RRC opcodes was completely bogus in the +asm cpu core. Miracle it didn't break more things. Should be correct now. +The SWAP (HL) instruction in the asm cpu core was nonfunctional. + + + +RELEASE 0.9.12 + + NEW FEATURES + +Hardware YUV scaling with full interpolation on systems that support it, +using SDL -- thanks goes to Magnus Damm. + + COMPATIBILITY + +Binary Chaos no longer has graphical glitches, and is fully playable. +Wacky Races now displays correctly again (broken since 0.9.7). + + BUGS FIXED + +Some test code was left in cpu.s, breaking DOS/Windows builds and +slowing things down across the board. +SDL joystick code was generating bogus release events. +Unused bits of VBK register were 0's; they should be 1's. +DMG palette was not being restored correctly after loading savestates. + + + +RELEASE 0.9.11 + + NEW FEATURES + +Most ports can auto-choose screen size appropriate to scale given. +Scaling to 2x, 3x, and 4x is now possible at all color depths. + + PERFORMANCE + +SDL port should run considerably faster than before at hires modes. +New X11 rcvar "x_shmsync" can be turned off for performance boost, +but it can result in heavy shearing and skipped frames. +The new scaling code is slightly faster than before. + + COMPATIBILITY + +Konami Collection (GBC) series now works in color mode. +Worms Armageddon is now playable, might still have some glitches though. +Turok 3 no longer hangs at startup and seems fully playable. +Sound samples that played too slow in many games now sound correct. + + BUGS FIXED + +Video mode setting was not working with svgalib. +Undocumented behavior - STOP instruction causes PC to skip forward. +SDL hardware surface mode is now always on and should always work fine. +More undocumented behavior - HDMA can occur while LCDC is off...? +HDMA5 register was not being initialized correctly on reset. +Timer was running at half the speed it should when in high-speed mode. + + + +RELEASE 0.9.10 + + NEW FEATURES + +Primitive but fast and fully functional scale-by-two support. +New rcvar "vmode" sets video mode in all the targets that support it. +Now up to 16 joystick buttons can be used, as opposed to 8 before. +Static palette mode (rcvar "rgb332"), which can make highcolor games +look better when run at 8bpp by faking a 3/3/2 color channel mode. + + COMPATIBILITY + +Added a quick hack to fake serial I/O so that Super RC Pro-Am works. +Spiderman's web is now visible in Spiderman GBC. + + PERFORMANCE + +New refresh code blits lines slightly faster. +Added sdl_hwsurface rcvar to turn hardware surface on for speed boost, +disabled by default because it crashes on Windows. + + BUGS FIXED + +Hopefully fixed issue with X header locations affecting some users. +DMG sprite sorting isn't working right. It's now disabled by default. +VBLANK timings have been changed slightly to fix Daedalian Opus. +Fixed various minor bugs found by enabling compiler warnings. +Spacebar was not working with SDL. Fixed. +Fixed bug that made OAM unreadable. + + + +RELEASE 0.9.9 + + NEW FEATURES + +DOS port is now entirely thinlib-based. Should be more robust, featureful. +For example, custom video modes such as 256x224 are available. + + PERFORMANCE + +New asm routines for displaying the background layer on color games. +This results in a significant performance boost low-end machines (~P75). +SDL code no longer fakes 16bpp but uses the native color depth. + + BUGS FIXED + +SDL gnuboy no longer produces random pops in sound at startup. +Mono/stereo should now be handled correctly in the SDL code. +Eliminated compiletime error about SDL_DISABLE on SDL ver < 1.1.8. +Serious bug -- loading savestates was not updating the memory bank map -- +resulted in bogus behavior after loading in certain situations. +Scrapped SDL_HWSURFACE to make fullscreen work on Windows. + + + +RELEASE 0.9.8 + + NEW FEATURES + +Native SDL sound support. This means sound will work on BeOS and Windows. +Sprites are priority sorted on DMG games by default now. +ROMs can be loaded from stdin using "-" as the filename. +SDL port now runs fullscreen by default. Set sdl_fullscreen to 0 to disable. +SDL port now supports alt+enter fullscreen toggle. +Integrated Windows port by mewse (using SDL and mingw32). + + COMPATIBILITY + +Added support for undocumented ram size 05 (presumably 256 kbit). +This fixes the crash with Pokemon Crystal. +Removed hacks for Altered Space and W&W because they break other games. +Added new VBLANK code that should fix them again without breaking other stuff. + + BUGS FIXED + +SDL keyboard handler was not accepting the numeral keys. +SDL video was messed up bad when it couldn't get a true 160x144 display. +Loading a ROM with bogus ROM/RAM size headers used to crash the program. + + + +RELEASE 0.9.7 + + NEW FEATURES + +DOS sound support! +VESA video modes on DOS! +Mono sound for cards that don't support stereo. + + COMPATIBILITY + +Altered Space and Wizards & Warriors now run. +Change was made to VBLANK behavior; hopefully it doesn't break other games. + + BUGS FIXED + +Envelope length was being computed wrong. +HDMA was incorrectly taking place all at once. +Command line parsing incorrectly changed - to _ in places it shouldn't. +SDL joystick support was not building correctly on non-Linux systems. + + + +RELEASE 0.9.5 + + NEW FEATURES + +Showing the name from the ROM header in X11 and SDL titlebars. +The various targets can be disabled at compiletime with --without-* options. +OSS sound support might work on FreeBSD and OpenBSD but is untested. +SDL joystick support. +GNU make no longer required to compile. + + OPTIMIZATIONS + +Flags handling in the C and asm cpu cores should be faster. +Word-at-a-time memory I/O is now done more efficiently. + + BUGS FIXED + +Highcolor screens no longer flicker. +Misplaced high-pitched beeps in sound have been removed, again. +C graphics code was misaligning the screen by one pixel. Fixed. + + + +RELEASE 0.9.4 + + NEW FEATURES + +Linux fbcon display support. +Linux joystick device support. + + COMPATIBILITY + +HDMA now works in DKC and Lemmings Color. +Default wave pattern is now supported. + + + +RELEASE 0.9.2 + + NEW FEATURES + +SDL port! +Sound channel 4. +MBC3 RTC support. + + COMPATIBILITY + +Sound is now properly handled in savestates. +Pokemon Silver and Gold should now be playable. + + BUGS FIXED + +Another bug in sweep. +Nasty aliasing from extremely high sound frequencies. + + + +RELEASE 0.9.1 + + NEW FEATURES + +Experimental sound support! +Better command line parsing. +Added --showvars command line option. +Various optimizations. + + BUGS FIXED + +HDMA bug. +LCDC STAT interrupt bug. + + + +NOTE: Earlier releases have not yet been documented in this file. +Hopefully they'll be added eventually, at least for the sake of +completing the records. + + + + + + diff --git a/emu.c b/emu.c new file mode 100644 index 0000000..544526d --- /dev/null +++ b/emu.c @@ -0,0 +1,110 @@ + + + +#include "defs.h" +#include "regs.h" +#include "hw.h" +#include "cpu.h" +#include "mem.h" +#include "lcd.h" +#include "rc.h" + + +static int framelen = 16743; +static int framecount; + +rcvar_t emu_exports[] = +{ + RCV_INT("framelen", &framelen), + RCV_INT("framecount", &framecount), + RCV_END +}; + + + + + + + +void emu_init() +{ + +} + + +/* + * emu_reset is called to initialize the state of the emulated + * system. It should set cpu registers, hardware registers, etc. to + * their appropriate values at powerup time. + */ + +void emu_reset() +{ + hw_reset(); + lcd_reset(); + cpu_reset(); + mbc_reset(); + sound_reset(); +} + + + + + +void emu_step() +{ + cpu_emulate(cpu.lcdc); +} + + + +/* This mess needs to be moved to another module; it's just here to + * make things work in the mean time. */ + +void *sys_timer(); + +void emu_run() +{ + void *timer = sys_timer(); + int delay; + + vid_begin(); + lcd_begin(); + for (;;) + { + cpu_emulate(2280); + while (R_LY > 0 && R_LY < 144) + emu_step(); + + vid_end(); + rtc_tick(); + sound_mix(); + if (!pcm_submit()) + { + delay = framelen - sys_elapsed(timer); + sys_sleep(delay); + sys_elapsed(timer); + } + doevents(); + vid_begin(); + if (framecount) { if (!--framecount) die("finished\n"); } + + if (!(R_LCDC & 0x80)) + cpu_emulate(32832); + + while (R_LY > 0) /* wait for next frame */ + emu_step(); + } +} + + + + + + + + + + + + diff --git a/etc/classic.rc b/etc/classic.rc new file mode 100644 index 0000000..f9a9618 --- /dev/null +++ b/etc/classic.rc @@ -0,0 +1,41 @@ +# +# classic.rc - change keybindings, palette, etc +# to match the old pre-1.0 settings. +# + +unbindall + +bind esc quit +bind up +up +bind down +down +bind left +left +bind right +right +bind alt +a +bind ctrl +b +bind enter +start +bind space +select +bind joyup +up +bind joydown +down +bind joyleft +left +bind joyright +right +bind joy0 +b +bind joy1 +a +bind joy2 +select +bind joy3 +start +bind 1 "set saveslot 1" +bind 2 "set saveslot 2" +bind 3 "set saveslot 3" +bind 4 "set saveslot 4" +bind 5 "set saveslot 5" +bind 6 "set saveslot 6" +bind 7 "set saveslot 7" +bind 8 "set saveslot 8" +bind 9 "set saveslot 9" +bind 0 "set saveslot 0" +bind ins savestate +bind del loadstate + +set dmg_bgp 0x78f0f0 0x58b8b8 0x487878 0x184848 +set dmg_wndp 0x78f0f0 0x58b8b8 0x487878 0x184848 +set dmg_obp0 0x78f0f0 0x58b8b8 0x487878 0x184848 +set dmg_obp1 0x78f0f0 0x58b8b8 0x487878 0x184848 diff --git a/etc/filters.rc b/etc/filters.rc new file mode 100644 index 0000000..5fbdc35 --- /dev/null +++ b/etc/filters.rc @@ -0,0 +1,43 @@ + +# +# Explanation of the filters: +# +# If, for example, red is set to "a b c d", +# where a, b, c, and d are four numbers, +# then the output red value for a given input +# color will be computed as follows: +# +# output_red = ( a * input_red + +# b * input_green + +# c * input_blue ) / 256 + d +# +# So, a, b, and c are scale factors +# (out of 256) for how much weight the input +# red, green, and blue components have in the +# output color, and d is a constant base +# value for the output. +# +# Below are some sample filters, which should +# make everything more clear. +# + +# Default filter as of 1.0.3 +set red 195 25 0 35 +set green 25 170 25 35 +set blue 25 60 125 40 + +# Do-nothing filer +set red 256 0 0 0 +set green 0 256 0 0 +set blue 0 0 256 0 + +# Lighten the display uniformly +set red 128 0 0 128 +set green 0 128 0 128 +set blue 0 0 128 128 + +# Grayscale +set red 85 85 85 0 +set green 85 85 85 0 +set blue 85 85 85 0 + diff --git a/etc/laguna.pgp b/etc/laguna.pgp new file mode 100644 index 0000000..b6bb9d3 --- /dev/null +++ b/etc/laguna.pgp @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.1 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +mQGiBDp47IARBACeZ/JuuNwArXaMl+9DGG0BSMPv1qJUYNdDqFREg60GDZRrChAV +WhSgpZ/NmSNAS8p4AYTtKIIrb0rMbNnEiaPqjftBFFe2JJ52fXsEosw3xk/v556E +spAdimPPnng7z6hb4QZitrtco5SxfKUAkZzBVJbZRYCuLu4XHZcbooLshwCg5Jb9 +Wr6ha8LPNh/nL39J0dDki2UD/RQKzlJWctiSc7jGgCy49GABOb5BiI07cUdOkfwL +eDUS+x/O6Dx8pxmwZJMw9LVOlIHhCwwSlT03Rh7bG6l7sWTuij+HFfSYe4UAgj/E +Vi6n5j8efNcc61x8NMvrZxuyBwomxKX9y9m1OOxKSpcxFTW2to7YGn9JUXsvSoOV +O2dtBACVazyx6Up+8FVKBzM+W4XW1n5em9dqzDbuxAUwvQ7PpC3lP4OJfiyk1ZcX +US0bs4Hu8CyitLTm+UIY7+Yfjov5Iye5gjZ4/KnTQndT9uPPmpBNE1xNfrRsaM2j +ZYt4rRAUvExKmVUE/x2Z5FxGHmCgw6u/2DEzS/yR8B5sk7SjFrQbTGFndW5hIDxn +bnVib3lAc3RhcmZveC5vcmc+iFYEExECABYFAjp47IEECwoEAwMVAwIDFgIBAheA +AAoJEBc0OAlJqLdjGNMAn0JBGXpsfdwPpDJlnU8C0hVxLGZyAKCderbZzS1YXkdB +WXwkqXuvZ6mjZLkCDQQ6eOyhEAgAwtcGa52r71LZJryOkpE/spACxlCfQyAIrQFC +bT9h5aJ5uzmUe8F8446Ex+yGqk+uvxLKFuIpO8iqkbKoVEPC0lneH/1msV8begii +sz9VjFD+HEtbmSWU9SG5/Dzf6GV6anSWanzP+kZ9rDX6GgUyxy1LSJSUjyTOaxy2 ++jSrbaf/HDmG7NVuRy40Yql2fgpvC8zrb5C3kjUY5c4CZTUnTSdE7xlDD2d4+xL/ +3KA2JFTU98kKVp23nn7NVfaQbUCg7mqa3iEjTS5WbRH+yaLga4s0WfNXjadbCjfl +jR5ZtnfPfm4dNNtSpbNf8AYL0H6R/dW9d3NtL8785XoqAwREgwADBQgAiWBsrxYC +gImk6tycqUyeHKf2y+jwoXYGkNc1gM2uMcAeculE/q8eA9chF+aL3fkGr4/JsVUL +FGD6cc5Uz+QSFZQNU522SVAa8kqM+GiuFm7vszn3j3Y4KaLAYTb6tr/Zi4BymGqg +oPEcAhvCGX/CcktFaU21pFDihrmete3j6SrGYSISWtVP9v1SDg+ooXw6FnrT46kd +8skCCTEEEA9tfwSOxyNKuAIA0BWQuskmRwaovJSswusZ7VfDojTQm7dthLobj6A1 +l9I9mssTElKKslx0dGDyJ1mCrLtBzNHV1br0rck9rGVcJD6K5s5D8wgyhoYPe3NZ +8K4jAiogvnaiRIhGBBgRAgAGBQI6eOyhAAoJEBc0OAlJqLdjMWYAoLYCWUmd21fl +YHa2CuCBshplXI9sAKCXSy1eGBA1a9LQUhH6JoYJ1e6WpQ== +=cjF6 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/etc/palettes.rc b/etc/palettes.rc new file mode 100644 index 0000000..c77d925 --- /dev/null +++ b/etc/palettes.rc @@ -0,0 +1,97 @@ +# +# palettes.rc - lots of sample dmg palettes +# copy the one you want to use into your gnuboy.rc +# + + +# New default palette for version 1.0. +set dmg_bgp 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C +set dmg_wndp 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C +set dmg_obp0 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C +set dmg_obp1 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C + +# Old default palette from 0.8.0 thru 0.9.13. +# This was designed for use on a laptop display, +# so it's probably way too yellowish. +set dmg_bgp 0x78f0f0 0x58b8b8 0x487878 0x184848 +set dmg_wndp 0x78f0f0 0x58b8b8 0x487878 0x184848 +set dmg_obp0 0x78f0f0 0x58b8b8 0x487878 0x184848 +set dmg_obp1 0x78f0f0 0x58b8b8 0x487878 0x184848 + +# Old dim grayscale. +set dmg_bgp 0xc0c0c0 0x808080 0x404040 0x000000 +set dmg_wndp 0xc0c0c0 0x808080 0x404040 0x000000 +set dmg_obp0 0xc0c0c0 0x808080 0x404040 0x000000 +set dmg_obp1 0xc0c0c0 0x808080 0x404040 0x000000 + +# Light grayscale. +set dmg_bgp 0xffffff 0xc0c0c0 0x808080 0x404040 +set dmg_wndp 0xffffff 0xc0c0c0 0x808080 0x404040 +set dmg_obp0 0xffffff 0xc0c0c0 0x808080 0x404040 +set dmg_obp1 0xffffff 0xc0c0c0 0x808080 0x404040 + +# Full contrast grayscale. +set dmg_bgp 0xffffff 0xaaaaaa 0x555555 0x000000 +set dmg_wndp 0xffffff 0xaaaaaa 0x555555 0x000000 +set dmg_obp0 0xffffff 0xaaaaaa 0x555555 0x000000 +set dmg_obp1 0xffffff 0xaaaaaa 0x555555 0x000000 + +# Debug palette. +# Each of the four layers is colored differently, +# making it easier to debug visual glitches in roms +# that use them all together cleverly. +set dmg_bgp 0xf898c8 0xf83098 0xc80060 0x600030 +set dmg_wndp 0xd0c0c0 0xa88080 0x785050 0x382828 +set dmg_obp0 0x9898f8 0x3030f8 0x0000c8 0x000060 +set dmg_obp1 0xc8f898 0x98f830 0x60c800 0x306000 + +# Sprites standout. +# Similar to above, but the colors are more subdued and +# the window and background are the same. This palette +# may actually be suitable for playing some games... +set dmg_bgp 0xd0c0c0 0xa88080 0x785050 0x382828 +set dmg_wndp 0xd0c0c0 0xa88080 0x785050 0x382828 +set dmg_obp0 0xc8e0f8 0x90a8e8 0x4878a8 0x183850 +set dmg_obp1 0x98b8f8 0x3050f8 0x2040a8 0x002060 + +# LCD yellows and grays. +# An earlier version of the new default palette. +set dmg_bgp 0x88e0f0 0x68a8b8 0x586878 0x283838 +set dmg_wndp 0x88e0f0 0x68a8b8 0x586878 0x283838 +set dmg_obp0 0x88e0f0 0x68a8b8 0x586878 0x283838 +set dmg_obp1 0x88e0f0 0x68a8b8 0x586878 0x283838 + +# LCD yellowscale. +# And another similar one. +set dmg_bgp 0x88e0f0 0x68a8b8 0x486878 0x203838 +set dmg_wndp 0x88e0f0 0x68a8b8 0x486878 0x203838 +set dmg_obp0 0x88e0f0 0x68a8b8 0x486878 0x203838 +set dmg_obp1 0x88e0f0 0x68a8b8 0x486878 0x203838 + +# Slightly colorful. +# Not just a plain lightness gradient, but some change +# in hue as well. Looks ok with some games; designed in +# particular for the FFL series. +set dmg_bgp 0x98e0f8 0x78a0c0 0x747080 0x604038 +set dmg_wndp 0x98e0f8 0x78a0c0 0x747080 0x604038 +set dmg_obp0 0x98e0f8 0x78a0c0 0x747080 0x604038 +set dmg_obp1 0x98e0f8 0x78a0c0 0x747080 0x604038 + +# Optionally use these with the above palette to make +# sprites stand out a bit. +set dmg_obp0 0x98e0f8 0x5090c0 0x507898 0x583838 +set dmg_obp1 0x98e0f8 0x5090c0 0x686078 0x383838 + +# R-Type 1 palette from R-Type DX +set dmg_bgp 0xc0ffff 0x408080 0x204040 0x000000 +set dmg_wndp 0xc0ffff 0x408080 0x204040 0x000000 +set dmg_obp0 0xc0ffff 0x408080 0x204040 0x000000 +set dmg_obp1 0xc0ffff 0x408080 0x204040 0x000000 + + + + + + + + diff --git a/etc/sample.rc b/etc/sample.rc new file mode 100644 index 0000000..8cbd699 --- /dev/null +++ b/etc/sample.rc @@ -0,0 +1,49 @@ +# +# Sample rc file for gnuboy +# +# You may want to rename this to gnuboy.rc to use it. +# Lines that begin with # are comments. +# + + +# Some keybindings + +bind q quit +bind r reset + +bind d +a +bind s +b + +# Normal speed/fast forward +# Note that these only work with sound disabled +bind - "set framelen 16743" +bind + "set framelen 0" + + +# Set video mode to 400x300x16bpp +set vmode 400 300 16 + + +# Enable full 2x screen scaling +# This will not work if your video mode is smaller than 320x288! +set scale 2 +set density 2 + + +# Enable stereo sound. Doesn't work on all systems +#set stereo true + + +# Path settings for DOS port - uncomment to use them! + +#set rcpath c:/gnuboy +#set savedir c:/gnuboy/saves + + + + +# +# You get the idea by now... +# See the README for more information on rc commands and vars. +# + diff --git a/events.c b/events.c new file mode 100644 index 0000000..c6ee954 --- /dev/null +++ b/events.c @@ -0,0 +1,60 @@ +/* + * events.c + * + * Event queue. + */ + + +#include "input.h" + + +char keystates[MAX_KEYS]; +int nkeysdown; + +#define MAX_EVENTS 32 + +static event_t eventqueue[MAX_EVENTS]; +static int eventhead, eventpos; + + +int ev_postevent(event_t *ev) +{ + int nextevent; + nextevent = (eventhead+1)%MAX_EVENTS; + if (nextevent == eventpos) + return 0; + eventqueue[eventhead] = *ev; + eventhead = nextevent; + return 1; +} + +int ev_getevent(event_t *ev) +{ + if (eventpos == eventhead) + { + ev->type = EV_NONE; + return 0; + } + *ev = eventqueue[eventpos]; + eventpos = (eventpos+1)%MAX_EVENTS; + if (ev->type == EV_PRESS) + { + keystates[ev->code] = 1; + nkeysdown++; + } + if (ev->type == EV_RELEASE) + { + keystates[ev->code] = 0; + nkeysdown--; + if (nkeysdown < 0) nkeysdown = 0; + } + return 1; +} + + + + + + + + diff --git a/exports.c b/exports.c new file mode 100644 index 0000000..d958143 --- /dev/null +++ b/exports.c @@ -0,0 +1,43 @@ + + +#include + +#include "rc.h" + +extern rcvar_t rcfile_exports[], emu_exports[], loader_exports[], + lcd_exports[], rtc_exports[], debug_exports[], sound_exports[], + vid_exports[], joy_exports[], pcm_exports[]; + + +rcvar_t *sources[] = +{ + rcfile_exports, + emu_exports, + loader_exports, + lcd_exports, + rtc_exports, + debug_exports, + sound_exports, + vid_exports, + joy_exports, + pcm_exports, + NULL +}; + + +void init_exports() +{ + rcvar_t **s = sources; + + while (*s) + rc_exportvars(*(s++)); +} + + +void show_exports() +{ + int i, j; + for (i = 0; sources[i]; i++) + for (j = 0; sources[i][j].name; j++) + printf("%s\n", sources[i][j].name); +} diff --git a/fastmem.c b/fastmem.c new file mode 100644 index 0000000..531ead7 --- /dev/null +++ b/fastmem.c @@ -0,0 +1,54 @@ + + +#include "fastmem.h" + + +#define D 0 /* direct */ +#define C 1 /* direct cgb-only */ +#define R 2 /* io register */ +#define S 3 /* sound register */ +#define W 4 /* wave pattern */ + +#define F 0xFF /* fail */ + +const byte himask[256]; + +const byte hi_rmap[256] = +{ + 0, 0, R, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, + S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, C, 0, C, + 0, C, C, C, C, C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, C, C, C, C, 0, 0, 0, 0, + C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const byte hi_wmap[256] = +{ + R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, + S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, + S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, + S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, + R, R, R, R, R, R, R, R, R, R, R, R, 0, R, 0, R, + 0, C, C, C, C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, R, R, R, R, 0, 0, 0, 0, + R, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, R +}; + + +void sound_write(); +static void no_write() +{ +} + diff --git a/fastmem.h b/fastmem.h new file mode 100644 index 0000000..33c93e4 --- /dev/null +++ b/fastmem.h @@ -0,0 +1,99 @@ + +#ifndef __FASTMEM_H__ +#define __FASTMEM_H__ + + +#include "defs.h" +#include "mem.h" + + +static byte readb(int a) +{ + byte *p = mbc.rmap[a>>12]; + if (p) return p[a]; + else return mem_read(a); +} + +static void writeb(int a, byte b) +{ + byte *p = mbc.wmap[a>>12]; + if (p) p[a] = b; + else mem_write(a, b); +} + +static int readw(int a) +{ + if ((a+1) & 0xfff) + { + byte *p = mbc.rmap[a>>12]; + if (p) + { +#ifdef IS_LITTLE_ENDIAN +#ifndef ALLOW_UNALIGNED_IO + if (a&1) return p[a] | (p[a+1]<<8); +#endif + return *(word *)(p+a); +#else + return p[a] | (p[a+1]<<8); +#endif + } + } + return mem_read(a) | (mem_read(a+1)<<8); +} + +static void writew(int a, int w) +{ + if ((a+1) & 0xfff) + { + byte *p = mbc.wmap[a>>12]; + if (p) + { +#ifdef IS_LITTLE_ENDIAN +#ifndef ALLOW_UNALIGNED_IO + if (a&1) + { + p[a] = w; + p[a+1] = w >> 8; + return; + } +#endif + *(word *)(p+a) = w; + return; +#else + p[a] = w; + p[a+1] = w >> 8; + return; +#endif + } + } + mem_write(a, w); + mem_write(a+1, w>>8); +} + +static byte readhi(int a) +{ + return readb(a | 0xff00); +} + +static void writehi(int a, byte b) +{ + writeb(a | 0xff00, b); +} + +#if 0 +static byte readhi(int a) +{ + byte (*rd)() = hi_read[a]; + return rd ? rd(a) : (ram.hi[a] | himask[a]); +} + +static void writehi(int a, byte b) +{ + byte (*wr)() = hi_write[a]; + if (wr) wr(a, b); + else ram.hi[a] = b & ~himask[a]; +} +#endif + + +#endif diff --git a/fb.h b/fb.h new file mode 100644 index 0000000..97d16ae --- /dev/null +++ b/fb.h @@ -0,0 +1,35 @@ + + +#ifndef __FB_H__ +#define __FB_H__ + + +#include "defs.h" + + + +struct fb +{ + byte *ptr; + int w, h; + int pelsize; + int pitch; + int indexed; + struct + { + int l, r; + } cc[4]; + int yuv; + int enabled; + int dirty; +}; + + +extern struct fb fb; + + +#endif + + + + diff --git a/hw.c b/hw.c new file mode 100644 index 0000000..b507f4d --- /dev/null +++ b/hw.c @@ -0,0 +1,182 @@ + + + +#include "defs.h" +#include "cpu.h" +#include "hw.h" +#include "regs.h" +#include "lcd.h" +#include "mem.h" +#include "fastmem.h" + + +struct hw hw; + + + +/* + * hw_interrupt changes the virtual interrupt lines included in the + * specified mask to the values the corresponding bits in i take, and + * in doing so, raises the appropriate bit of R_IF for any interrupt + * lines that transition from low to high. + */ + +void hw_interrupt(byte i, byte mask) +{ + byte oldif = R_IF; + i &= 0x1F & mask; + R_IF |= i & (hw.ilines ^ i); + + /* FIXME - is this correct? not sure the docs understand... */ + if ((R_IF & (R_IF ^ oldif) & R_IE) && cpu.ime) cpu.halt = 0; + /* if ((i & (hw.ilines ^ i) & R_IE) && cpu.ime) cpu.halt = 0; */ + /* if ((i & R_IE) && cpu.ime) cpu.halt = 0; */ + + hw.ilines &= ~mask; + hw.ilines |= i; +} + + +/* + * hw_dma performs plain old memory-to-oam dma, the original dmg + * dma. Although on the hardware it takes a good deal of time, the cpu + * continues running during this mode of dma, so no special tricks to + * stall the cpu are necessary. + */ + +void hw_dma(byte b) +{ + int i; + addr a; + + a = ((addr)b) << 8; + for (i = 0; i < 160; i++, a++) + lcd.oam.mem[i] = readb(a); +} + + + +void hw_hdma_cmd(byte c) +{ + int cnt; + addr sa; + int da; + + /* Begin or cancel HDMA */ + if ((hw.hdma|c) & 0x80) + { + hw.hdma = c; + R_HDMA5 = c & 0x7f; + return; + } + + /* Perform GDMA */ + sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); + da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); + cnt = ((int)c)+1; + /* FIXME - this should use cpu time! */ + /*cpu_timers(102 * cnt);*/ + cnt <<= 4; + while (cnt--) + writeb(da++, readb(sa++)); + R_HDMA1 = sa >> 8; + R_HDMA2 = sa & 0xF0; + R_HDMA3 = 0x1F & (da >> 8); + R_HDMA4 = da & 0xF0; + R_HDMA5 = 0xFF; +} + + +void hw_hdma() +{ + int cnt; + addr sa; + int da; + + sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); + da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); + cnt = 16; + while (cnt--) + writeb(da++, readb(sa++)); + R_HDMA1 = sa >> 8; + R_HDMA2 = sa & 0xF0; + R_HDMA3 = 0x1F & (da >> 8); + R_HDMA4 = da & 0xF0; + R_HDMA5--; + hw.hdma--; +} + + +/* + * pad_refresh updates the P1 register from the pad states, generating + * the appropriate interrupts (by quickly raising and lowering the + * interrupt line) if a transition has been made. + */ + +void pad_refresh() +{ + byte oldp1; + oldp1 = R_P1; + R_P1 &= 0x30; + R_P1 |= 0xc0; + if (!(R_P1 & 0x10)) + R_P1 |= (hw.pad & 0x0F); + if (!(R_P1 & 0x20)) + R_P1 |= (hw.pad >> 4); + R_P1 ^= 0x0F; + if (oldp1 & ~R_P1 & 0x0F) + { + hw_interrupt(IF_PAD, IF_PAD); + hw_interrupt(0, IF_PAD); + } +} + + +/* + * These simple functions just update the state of a button on the + * pad. + */ + +void pad_press(byte k) +{ + if (hw.pad & k) + return; + hw.pad |= k; + pad_refresh(); +} + +void pad_release(byte k) +{ + if (!(hw.pad & k)) + return; + hw.pad &= ~k; + pad_refresh(); +} + +void pad_set(byte k, int st) +{ + st ? pad_press(k) : pad_release(k); +} + +void hw_reset() +{ + hw.ilines = hw.pad = 0; + + memset(ram.hi, 0, sizeof ram.hi); + + R_P1 = 0xFF; + R_LCDC = 0x91; + R_BGP = 0xFC; + R_OBP0 = 0xFF; + R_OBP1 = 0xFF; + R_SVBK = 0x01; + R_HDMA5 = 0xFF; + R_VBK = 0xFE; +} + + + + + + + diff --git a/hw.h b/hw.h new file mode 100644 index 0000000..f425efc --- /dev/null +++ b/hw.h @@ -0,0 +1,40 @@ + + + +#ifndef __HW_H__ +#define __HW_H__ + + +#include "defs.h" + + +#define PAD_RIGHT 0x01 +#define PAD_LEFT 0x02 +#define PAD_UP 0x04 +#define PAD_DOWN 0x08 +#define PAD_A 0x10 +#define PAD_B 0x20 +#define PAD_SELECT 0x40 +#define PAD_START 0x80 + +#define IF_VBLANK 0x01 +#define IF_STAT 0x02 +#define IF_TIMER 0x04 +#define IF_SERIAL 0x08 +#define IF_PAD 0x10 + +struct hw +{ + byte ilines; + byte pad; + int cgb, gba; + int hdma; +}; + + +extern struct hw hw; + + +#endif + + diff --git a/inflate.c b/inflate.c new file mode 100644 index 0000000..5079f49 --- /dev/null +++ b/inflate.c @@ -0,0 +1,512 @@ + +/* Slightly modified from its original form so as not to exit the + * program on errors. The resulting file remains in the public + * domain for all to use. */ + +/* --- GZIP file format uncompression routines --- */ + +/* The following routines (notably the unzip()) function below + * uncompress gzipped data. They are terribly slow at the task, but + * it is presumed that they work reasonably well. They don't do any + * error checking, but they're probably not too vulnerable to buggy + * data either. Another important limitation (but it would be pretty + * easy to get around) is that the data must reside in memory, it is + * not read as a stream. They have been very little tested. Anyway, + * whatever these functions are good for, I put them in the public + * domain. -- David Madore 1999/11/21 */ + +static unsigned int +peek_bits (const unsigned char *data, long p, int q) + /* Read q bits starting from bit p from the data pointed to by + * data. Data is in little-endian format. */ +{ + unsigned int answer; + int cnt; /* Number of bits already placed in answer */ + char ob, lb; /* Offset and length of bit field within current byte */ + + answer = 0; + for ( cnt=0 ; cnt q ) + lb = q-cnt; + answer |= ((unsigned int)((data[(p+cnt)/8]>>ob)&((1U<>(maxbits-size_table[j])) == code_table[j] ) ) + { + *p += size_table[j]; + return j; + } + } + return -1; +} + +/* I don't know what these should be. The rfc1951 doesn't seem to say + * (it only mentions them in the last paragraph of section 3.2.1). 15 + * is almost certainly safe, and it is the largest I can put given the + * constraints on the size of integers in the C standard. */ +#define CLEN_MAXBITS 15 +#define HLIT_MAXBITS 15 +#define HDIST_MAXBITS 15 + +/* The magical table sizes... */ +#define CLEN_TSIZE 19 +#define HLIT_TSIZE 288 +#define HDIST_TSIZE 30 + +static int +get_tables (const unsigned char *data, long *p, + char hlit_size_table[HLIT_TSIZE], + unsigned int hlit_code_table[HLIT_TSIZE], + char hdist_size_table[HDIST_TSIZE], + unsigned int hdist_code_table[HDIST_TSIZE]) + /* Fill the Huffman tables (first the code lengths table, and + * then, using it, the literal/length table and the distance + * table). See section 3.2.7 of rfc1951 for details. */ +{ + char hlit, hdist, hclen; + const int clen_weird_tangle[CLEN_TSIZE] + = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + char clen_size_table[CLEN_TSIZE]; + unsigned int clen_code_table[CLEN_TSIZE]; + int j; + unsigned int b; + int remainder; /* See note at end of section 3.2.7 of rfc1951. */ + char rem_val; + + hlit = read_bits (data, p, 5); + hdist = read_bits (data, p, 5); + hclen = read_bits (data, p, 4); + for ( j=0 ; j<4+hclen ; j++ ) + clen_size_table[clen_weird_tangle[j]] + = read_bits (data, p, 3); + for ( ; j= 257 ) + /* Back reference */ + { + unsigned int bb; + unsigned int length, dist; + unsigned int l; + + switch ( b ) + { + case 257: length = 3; break; + case 258: length = 4; break; + case 259: length = 5; break; + case 260: length = 6; break; + case 261: length = 7; break; + case 262: length = 8; break; + case 263: length = 9; break; + case 264: length = 10; break; + case 265: length = 11 + read_bits (data, p, 1); break; + case 266: length = 13 + read_bits (data, p, 1); break; + case 267: length = 15 + read_bits (data, p, 1); break; + case 268: length = 17 + read_bits (data, p, 1); break; + case 269: length = 19 + read_bits (data, p, 2); break; + case 270: length = 23 + read_bits (data, p, 2); break; + case 271: length = 27 + read_bits (data, p, 2); break; + case 272: length = 31 + read_bits (data, p, 2); break; + case 273: length = 35 + read_bits (data, p, 3); break; + case 274: length = 43 + read_bits (data, p, 3); break; + case 275: length = 51 + read_bits (data, p, 3); break; + case 276: length = 59 + read_bits (data, p, 3); break; + case 277: length = 67 + read_bits (data, p, 4); break; + case 278: length = 83 + read_bits (data, p, 4); break; + case 279: length = 99 + read_bits (data, p, 4); break; + case 280: length = 115 + read_bits (data, p, 4); break; + case 281: length = 131 + read_bits (data, p, 5); break; + case 282: length = 163 + read_bits (data, p, 5); break; + case 283: length = 195 + read_bits (data, p, 5); break; + case 284: length = 227 + read_bits (data, p, 5); break; + case 285: length = 258; break; + default: + return -1; + } + bb = decode_one (data, p, hdist_size_table, HDIST_TSIZE, + hdist_code_table, HDIST_MAXBITS); + switch ( bb ) + { + case 0: dist = 1; break; + case 1: dist = 2; break; + case 2: dist = 3; break; + case 3: dist = 4; break; + case 4: dist = 5 + read_bits (data, p, 1); break; + case 5: dist = 7 + read_bits (data, p, 1); break; + case 6: dist = 9 + read_bits (data, p, 2); break; + case 7: dist = 13 + read_bits (data, p, 2); break; + case 8: dist = 17 + read_bits (data, p, 3); break; + case 9: dist = 25 + read_bits (data, p, 3); break; + case 10: dist = 33 + read_bits (data, p, 4); break; + case 11: dist = 49 + read_bits (data, p, 4); break; + case 12: dist = 65 + read_bits (data, p, 5); break; + case 13: dist = 97 + read_bits (data, p, 5); break; + case 14: dist = 129 + read_bits (data, p, 6); break; + case 15: dist = 193 + read_bits (data, p, 6); break; + case 16: dist = 257 + read_bits (data, p, 7); break; + case 17: dist = 385 + read_bits (data, p, 7); break; + case 18: dist = 513 + read_bits (data, p, 8); break; + case 19: dist = 769 + read_bits (data, p, 8); break; + case 20: dist = 1025 + read_bits (data, p, 9); break; + case 21: dist = 1537 + read_bits (data, p, 9); break; + case 22: dist = 2049 + read_bits (data, p, 10); break; + case 23: dist = 3073 + read_bits (data, p, 10); break; + case 24: dist = 4097 + read_bits (data, p, 11); break; + case 25: dist = 6145 + read_bits (data, p, 11); break; + case 26: dist = 8193 + read_bits (data, p, 12); break; + case 27: dist = 12289 + read_bits (data, p, 12); break; + case 28: dist = 16385 + read_bits (data, p, 13); break; + case 29: dist = 24577 + read_bits (data, p, 13); break; + default: + return -1; + } + for ( l=0 ; l +#include + +#include "input.h" + +/* keytable - Mapping of key names to codes, and back. A single code + can have more than one name, in which case the first will be used + when saving config, but any may be used in setting config. */ + +keytable_t keytable[] = +{ + { "shift", K_SHIFT }, + { "ctrl", K_CTRL }, + { "alt", K_ALT }, + { "up", K_UP }, + { "down", K_DOWN }, + { "right", K_RIGHT }, + { "left", K_LEFT }, + { "enter", K_ENTER }, + { "tab", K_TAB }, + { "space", K_SPACE }, + { "bs", K_BS }, + { "backspace", K_BS }, /* dup */ + { "del", K_DEL }, + { "delete", K_DEL }, /* dup */ + { "ins", K_INS }, + { "insert", K_INS }, /* dup */ + { "home", K_HOME }, + { "end", K_END }, + { "prior", K_PRIOR }, + { "next", K_NEXT }, + { "pgup", K_PRIOR }, /* duplicate for pgup/pgdn fans */ + { "pgdn", K_NEXT }, /* ditto */ + { "esc", K_ESC }, + { "escape", K_ESC }, /* dup */ + { "pause", K_PAUSE }, + { "caps", K_CAPS }, + { "capslock", K_CAPS }, /* dup */ + { "numlock", K_NUMLOCK }, + { "scroll", K_SCROLL }, + + { "minus", K_MINUS }, + { "_", K_MINUS }, /* dup */ + { "equals", K_EQUALS }, + { "plus", K_EQUALS }, /* dup */ + { "+", K_EQUALS }, /* dup */ + { "tilde", K_TILDE }, + { "backquote", K_TILDE }, /* dup */ + { "`", K_TILDE }, /* dup */ + { "slash", K_SLASH }, + { "question", K_SLASH }, /* dup */ + { "?", K_SLASH }, /* dup */ + { "bslash", K_BSLASH }, + { "backslash", K_BSLASH }, /* dup */ + { "pipe", K_BSLASH }, /* dup */ + { "|", K_BSLASH }, /* dup */ + { "semi", K_SEMI }, + { "semicolon", K_SEMI }, /* dup */ + { "quote", K_QUOTE }, + + { "f1", K_F1 }, + { "f2", K_F2 }, + { "f3", K_F3 }, + { "f4", K_F4 }, + { "f5", K_F5 }, + { "f6", K_F6 }, + { "f7", K_F7 }, + { "f8", K_F8 }, + { "f9", K_F9 }, + { "f10", K_F10 }, + { "f11", K_F11 }, + { "f12", K_F12 }, + + { "num0", K_NUM0 }, + { "num1", K_NUM1 }, + { "num2", K_NUM2 }, + { "num3", K_NUM3 }, + { "num4", K_NUM4 }, + { "num5", K_NUM5 }, + { "num6", K_NUM6 }, + { "num7", K_NUM7 }, + { "num8", K_NUM8 }, + { "num9", K_NUM9 }, + { "numplus", K_NUMPLUS }, + { "numminus", K_NUMMINUS }, + { "nummul", K_NUMMUL }, + { "numdiv", K_NUMDIV }, + { "numdot", K_NUMDOT }, + { "numenter", K_NUMENTER }, + + /* Note that these are not presently used... */ + { "mouse0", K_MOUSE0 }, + { "mouse1", K_MOUSE1 }, + { "mouse2", K_MOUSE2 }, + { "mouse3", K_MOUSE3 }, + { "mouse4", K_MOUSE4 }, + + { "joyleft", K_JOYLEFT }, + { "joyright", K_JOYRIGHT }, + { "joyup", K_JOYUP }, + { "joydown", K_JOYDOWN }, + + { "joy0", K_JOY0 }, + { "joy1", K_JOY1 }, + { "joy2", K_JOY2 }, + { "joy3", K_JOY3 }, + { "joy4", K_JOY4 }, + { "joy5", K_JOY5 }, + { "joy6", K_JOY6 }, + { "joy7", K_JOY7 }, + { "joy8", K_JOY8 }, + { "joy9", K_JOY9 }, + { "joy10", K_JOY10 }, + { "joy11", K_JOY11 }, + { "joy12", K_JOY12 }, + { "joy13", K_JOY13 }, + { "joy14", K_JOY14 }, + { "joy15", K_JOY15 }, + + { NULL, 0 } +}; + +int k_keycode(char *name) +{ + keytable_t *key; + + for (key = keytable; key->name; key++) + if (!strcasecmp(key->name, name)) + return key->code; + if (strlen(name) == 1) + return tolower(name[0]); + return 0; +} + +char *k_keyname(int code) +{ + keytable_t *key; + + for (key = keytable; key->name; key++) + if (key->code == code) + return key->name; + return NULL; +} + + + + + + + diff --git a/lcd.c b/lcd.c new file mode 100644 index 0000000..71d138e --- /dev/null +++ b/lcd.c @@ -0,0 +1,868 @@ + + + +#include "defs.h" +#include "regs.h" +#include "hw.h" +#include "mem.h" +#include "lcd.h" +#include "rc.h" +#include "fb.h" +#ifdef USE_ASM +#include "asm.h" +#endif + +struct lcd lcd; + +struct scan scan; + +#define BG (scan.bg) +#define WND (scan.wnd) +#define BUF (scan.buf) +#define PRI (scan.pri) + +#define PAL1 (scan.pal1) +#define PAL2 (scan.pal2) +#define PAL4 (scan.pal4) + +#define VS (scan.vs) /* vissprites */ +#define NS (scan.ns) + +#define L (scan.l) /* line */ +#define X (scan.x) /* screen position */ +#define Y (scan.y) +#define S (scan.s) /* tilemap position */ +#define T (scan.t) +#define U (scan.u) /* position within tile */ +#define V (scan.v) +#define WX (scan.wx) +#define WY (scan.wy) +#define WT (scan.wt) +#define WV (scan.wv) + +byte patpix[4096][8][8]; +byte patdirty[1024]; +byte anydirty; + +static int scale = 1; +static int density = 0; + +static int rgb332; + +static int sprsort = 1; +static int sprdebug; + +#define DEF_PAL { 0x98d0e0, 0x68a0b0, 0x60707C, 0x2C3C3C } + +static int dmg_pal[4][4] = { DEF_PAL, DEF_PAL, DEF_PAL, DEF_PAL }; + +static int usefilter, filterdmg; +static int filter[3][4] = { + { 195, 25, 0, 35 }, + { 25, 170, 25, 35 }, + { 25, 60, 125, 40 } +}; + +rcvar_t lcd_exports[] = +{ + RCV_INT("scale", &scale), + RCV_INT("density", &density), + RCV_BOOL("rgb332", &rgb332), + RCV_VECTOR("dmg_bgp", dmg_pal[0], 4), + RCV_VECTOR("dmg_wndp", dmg_pal[1], 4), + RCV_VECTOR("dmg_obp0", dmg_pal[2], 4), + RCV_VECTOR("dmg_obp1", dmg_pal[3], 4), + RCV_BOOL("sprsort", &sprsort), + RCV_BOOL("sprdebug", &sprdebug), + RCV_BOOL("colorfilter", &usefilter), + RCV_BOOL("filterdmg", &filterdmg), + RCV_VECTOR("red", filter[0], 4), + RCV_VECTOR("green", filter[1], 4), + RCV_VECTOR("blue", filter[2], 4), + RCV_END +}; + +static byte *vdest; + +#ifdef ALLOW_UNALIGNED_IO /* long long is ok since this is i386-only anyway? */ +#define MEMCPY8(d, s) ((*(long long *)(d)) = (*(long long *)(s))) +#else +#define MEMCPY8(d, s) memcpy((d), (s), 8) +#endif + + + + +#ifndef ASM_UPDATEPATPIX +void updatepatpix() +{ + int i, j, k; + int a, c; + byte *vram = lcd.vbank[0]; + + if (!anydirty) return; + for (i = 0; i < 1024; i++) + { + if (i == 384) i = 512; + if (i == 896) break; + if (!patdirty[i]) continue; + patdirty[i] = 0; + for (j = 0; j < 8; j++) + { + a = ((i<<4) | (j<<1)); + for (k = 0; k < 8; k++) + { + c = vram[a] & (1<> 3) + 1; + + if (hw.cgb) + { + if (R_LCDC & 0x10) + for (i = cnt; i > 0; i--) + { + *(tilebuf++) = *tilemap + | (((int)*attrmap & 0x08) << 6) + | (((int)*attrmap & 0x60) << 5); + *(tilebuf++) = (((int)*attrmap & 0x07) << 2); + attrmap += *wrap + 1; + tilemap += *(wrap++) + 1; + } + else + for (i = cnt; i > 0; i--) + { + *(tilebuf++) = (256 + ((n8)*tilemap)) + | (((int)*attrmap & 0x08) << 6) + | (((int)*attrmap & 0x60) << 5); + *(tilebuf++) = (((int)*attrmap & 0x07) << 2); + attrmap += *wrap + 1; + tilemap += *(wrap++) + 1; + } + } + else + { + if (R_LCDC & 0x10) + for (i = cnt; i > 0; i--) + { + *(tilebuf++) = *(tilemap++); + tilemap += *(wrap++); + } + else + for (i = cnt; i > 0; i--) + { + *(tilebuf++) = (256 + ((n8)*(tilemap++))); + tilemap += *(wrap++); + } + } + + if (WX >= 160) return; + + base = ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5); + tilemap = lcd.vbank[0] + base; + attrmap = lcd.vbank[1] + base; + tilebuf = WND; + cnt = ((160 - WX) >> 3) + 1; + + if (hw.cgb) + { + if (R_LCDC & 0x10) + for (i = cnt; i > 0; i--) + { + *(tilebuf++) = *(tilemap++) + | (((int)*attrmap & 0x08) << 6) + | (((int)*attrmap & 0x60) << 5); + *(tilebuf++) = (((int)*(attrmap++)&7) << 2); + } + else + for (i = cnt; i > 0; i--) + { + *(tilebuf++) = (256 + ((n8)*(tilemap++))) + | (((int)*attrmap & 0x08) << 6) + | (((int)*attrmap & 0x60) << 5); + *(tilebuf++) = (((int)*(attrmap++)&7) << 2); + } + } + else + { + if (R_LCDC & 0x10) + for (i = cnt; i > 0; i--) + *(tilebuf++) = *(tilemap++); + else + for (i = cnt; i > 0; i--) + *(tilebuf++) = (256 + ((n8)*(tilemap++))); + } +} + + +void bg_scan() +{ + int cnt; + byte *src, *dest; + int *tile; + + if (WX <= 0) return; + cnt = WX; + tile = BG; + dest = BUF; + + src = patpix[*(tile++)][V] + U; + memcpy(dest, src, 8-U); + dest += 8-U; + cnt -= 8-U; + if (cnt <= 0) return; + while (cnt >= 8) + { + src = patpix[*(tile++)][V]; + MEMCPY8(dest, src); + dest += 8; + cnt -= 8; + } + src = patpix[*tile][V]; + while (cnt--) + *(dest++) = *(src++); +} + +void wnd_scan() +{ + int cnt; + byte *src, *dest; + int *tile; + + if (WX >= 160) return; + cnt = 160 - WX; + tile = WND; + dest = BUF + WX; + + while (cnt >= 8) + { + src = patpix[*(tile++)][WV]; + MEMCPY8(dest, src); + dest += 8; + cnt -= 8; + } + src = patpix[*tile][WV]; + while (cnt--) + *(dest++) = *(src++); +} + +static void blendcpy(byte *dest, byte *src, byte b, int cnt) +{ + while (cnt--) *(dest++) = *(src++) | b; +} + +static int priused(void *attr) +{ + un32 *a = attr; + return (int)((a[0]|a[1]|a[2]|a[3]|a[4]|a[5]|a[6]|a[7])&0x80808080); +} + +void bg_scan_pri() +{ + int cnt, i; + byte *src, *dest; + + if (WX <= 0) return; + i = S; + cnt = WX; + dest = PRI; + src = lcd.vbank[1] + ((R_LCDC&0x08)?0x1C00:0x1800) + (T<<5); + + if (!priused(src)) + { + memset(dest, 0, cnt); + return; + } + + memset(dest, src[i++&31]&128, 8-U); + dest += 8-U; + cnt -= 8-U; + if (cnt <= 0) return; + while (cnt >= 8) + { + memset(dest, src[i++&31]&128, 8); + dest += 8; + cnt -= 8; + } + memset(dest, src[i&31]&128, cnt); +} + +void wnd_scan_pri() +{ + int cnt, i; + byte *src, *dest; + + if (WX >= 160) return; + i = 0; + cnt = 160 - WX; + dest = PRI + WX; + src = lcd.vbank[1] + ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5); + + if (!priused(src)) + { + memset(dest, 0, cnt); + return; + } + + while (cnt >= 8) + { + memset(dest, src[i++]&128, 8); + dest += 8; + cnt -= 8; + } + memset(dest, src[i]&128, cnt); +} + +#ifndef ASM_BG_SCAN_COLOR +void bg_scan_color() +{ + int cnt; + byte *src, *dest; + int *tile; + + if (WX <= 0) return; + cnt = WX; + tile = BG; + dest = BUF; + + src = patpix[*(tile++)][V] + U; + blendcpy(dest, src, *(tile++), 8-U); + dest += 8-U; + cnt -= 8-U; + if (cnt <= 0) return; + while (cnt >= 8) + { + src = patpix[*(tile++)][V]; + blendcpy(dest, src, *(tile++), 8); + dest += 8; + cnt -= 8; + } + src = patpix[*(tile++)][V]; + blendcpy(dest, src, *(tile++), cnt); +} +#endif + +void wnd_scan_color() +{ + int cnt; + byte *src, *dest; + int *tile; + + if (WX >= 160) return; + cnt = 160 - WX; + tile = WND; + dest = BUF + WX; + + while (cnt >= 8) + { + src = patpix[*(tile++)][WV]; + blendcpy(dest, src, *(tile++), 8); + dest += 8; + cnt -= 8; + } + src = patpix[*(tile++)][WV]; + blendcpy(dest, src, *(tile++), cnt); +} + +static void recolor(byte *buf, byte fill, int cnt) +{ + while (cnt--) *(buf++) |= fill; +} + +void spr_count() +{ + int i; + struct obj *o; + + NS = 0; + if (!(R_LCDC & 0x02)) return; + + o = lcd.oam.obj; + + for (i = 40; i; i--, o++) + { + if (L >= o->y || L + 16 < o->y) + continue; + if (L + 8 >= o->y && !(R_LCDC & 0x04)) + continue; + if (++NS == 10) break; + } +} + +void spr_enum() +{ + int i, j; + struct obj *o; + struct vissprite ts[10]; + int v, pat; + int l, x; + + NS = 0; + if (!(R_LCDC & 0x02)) return; + + o = lcd.oam.obj; + + for (i = 40; i; i--, o++) + { + if (L >= o->y || L + 16 < o->y) + continue; + if (L + 8 >= o->y && !(R_LCDC & 0x04)) + continue; + VS[NS].x = (int)o->x - 8; + v = L - (int)o->y + 16; + if (hw.cgb) + { + pat = o->pat | (((int)o->flags & 0x60) << 5) + | (((int)o->flags & 0x08) << 6); + VS[NS].pal = 32 + ((o->flags & 0x07) << 2); + } + else + { + pat = o->pat | (((int)o->flags & 0x60) << 5); + VS[NS].pal = 32 + ((o->flags & 0x10) >> 2); + } + VS[NS].pri = (o->flags & 0x80) >> 7; + if ((R_LCDC & 0x04)) + { + pat &= ~1; + if (v >= 8) + { + v -= 8; + pat++; + } + if (o->flags & 0x40) pat ^= 1; + } + VS[NS].buf = patpix[pat][v]; + if (++NS == 10) break; + } + if (!sprsort || hw.cgb) return; + /* not quite optimal but it finally works! */ + for (i = 0; i < NS; i++) + { + l = 0; + x = VS[0].x; + for (j = 1; j < NS; j++) + { + if (VS[j].x < x) + { + l = j; + x = VS[j].x; + } + } + ts[i] = VS[l]; + VS[l].x = 160; + } + memcpy(VS, ts, sizeof VS); +} + +void spr_scan() +{ + int i, x; + byte pal, b, ns = NS; + byte *src, *dest, *bg, *pri; + struct vissprite *vs; + static byte bgdup[256]; + + if (!ns) return; + + memcpy(bgdup, BUF, 256); + vs = &VS[ns-1]; + + for (; ns; ns--, vs--) + { + x = vs->x; + if (x >= 160) continue; + if (x <= -8) continue; + if (x < 0) + { + src = vs->buf - x; + dest = BUF; + i = 8 + x; + } + else + { + src = vs->buf; + dest = BUF + x; + if (x > 152) i = 160 - x; + else i = 8; + } + pal = vs->pal; + if (vs->pri) + { + bg = bgdup + (dest - BUF); + while (i--) + { + b = src[i]; + if (b && !(bg[i]&3)) dest[i] = pal|b; + } + } + else if (hw.cgb) + { + bg = bgdup + (dest - BUF); + pri = PRI + (dest - BUF); + while (i--) + { + b = src[i]; + if (b && (!pri[i] || !(bg[i]&3))) + dest[i] = pal|b; + } + } + else while (i--) if (src[i]) dest[i] = pal|src[i]; + /* else while (i--) if (src[i]) dest[i] = 31 + ns; */ + } + if (sprdebug) for (i = 0; i < NS; i++) BUF[i<<1] = 36; +} + + + + + + +void lcd_begin() +{ + if (fb.indexed) + { + if (rgb332) pal_set332(); + else pal_expire(); + } + while (scale * 160 > fb.w || scale * 144 > fb.h) scale--; + vdest = fb.ptr + ((fb.w*fb.pelsize)>>1) + - (80*fb.pelsize) * scale + + ((fb.h>>1) - 72*scale) * fb.pitch; + WY = R_WY; +} + +void lcd_refreshline() +{ + int i; + byte scalebuf[160*4*4], *dest; + + if (!fb.enabled) return; + + if (!(R_LCDC & 0x80)) + return; /* should not happen... */ + + updatepatpix(); + + L = R_LY; + X = R_SCX; + Y = (R_SCY + L) & 0xff; + S = X >> 3; + T = Y >> 3; + U = X & 7; + V = Y & 7; + + WX = R_WX - 7; + if (WY>L || WY<0 || WY>143 || WX<-7 || WX>159 || !(R_LCDC&0x20)) + WX = 160; + WT = (L - WY) >> 3; + WV = (L - WY) & 7; + + spr_enum(); + + tilebuf(); + if (hw.cgb) + { + bg_scan_color(); + wnd_scan_color(); + if (NS) + { + bg_scan_pri(); + wnd_scan_pri(); + } + } + else + { + bg_scan(); + wnd_scan(); + recolor(BUF+WX, 0x04, 160-WX); + } + spr_scan(); + + if (fb.dirty) memset(fb.ptr, 0, fb.pitch * fb.h); + fb.dirty = 0; + if (density > scale) density = scale; + if (scale == 1) density = 1; + + dest = (density != 1) ? scalebuf : vdest; + + switch (scale) + { + case 0: + case 1: + switch (fb.pelsize) + { + case 1: + refresh_1(dest, BUF, PAL1, 160); + break; + case 2: + refresh_2(dest, BUF, PAL2, 160); + break; + case 3: + refresh_3(dest, BUF, PAL4, 160); + break; + case 4: + refresh_4(dest, BUF, PAL4, 160); + break; + } + break; + case 2: + switch (fb.pelsize) + { + case 1: + refresh_2(dest, BUF, PAL2, 160); + break; + case 2: + refresh_4(dest, BUF, PAL4, 160); + break; + case 3: + refresh_3_2x(dest, BUF, PAL4, 160); + break; + case 4: + refresh_4_2x(dest, BUF, PAL4, 160); + break; + } + break; + case 3: + switch (fb.pelsize) + { + case 1: + refresh_3(dest, BUF, PAL4, 160); + break; + case 2: + refresh_2_3x(dest, BUF, PAL2, 160); + break; + case 3: + refresh_3_3x(dest, BUF, PAL4, 160); + break; + case 4: + refresh_4_3x(dest, BUF, PAL4, 160); + break; + } + break; + case 4: + switch (fb.pelsize) + { + case 1: + refresh_4(dest, BUF, PAL4, 160); + break; + case 2: + refresh_4_2x(dest, BUF, PAL4, 160); + break; + case 3: + refresh_3_4x(dest, BUF, PAL4, 160); + break; + case 4: + refresh_4_4x(dest, BUF, PAL4, 160); + break; + } + break; + default: + break; + } + + if (density != 1) + { + for (i = 0; i < scale; i++) + { + if ((i < density) || ((density <= 0) && !(i&1))) + memcpy(vdest, scalebuf, 160 * fb.pelsize * scale); + vdest += fb.pitch; + } + } + else vdest += fb.pitch * scale; +} + + + + + + + +static void updatepalette(int i) +{ + int c, r, g, b, y, u, v, rr, gg; + + c = (lcd.pal[i<<1] | ((int)lcd.pal[(i<<1)|1] << 8)) & 0x7FFF; + r = (c & 0x001F) << 3; + g = (c & 0x03E0) >> 2; + b = (c & 0x7C00) >> 7; + r |= (r >> 5); + g |= (g >> 5); + b |= (b >> 5); + + if (usefilter && (filterdmg || hw.cgb)) + { + rr = ((r * filter[0][0] + g * filter[0][1] + b * filter[0][2]) >> 8) + filter[0][3]; + gg = ((r * filter[1][0] + g * filter[1][1] + b * filter[1][2]) >> 8) + filter[1][3]; + b = ((r * filter[2][0] + g * filter[2][1] + b * filter[2][2]) >> 8) + filter[2][3]; + r = rr; + g = gg; + } + + if (fb.yuv) + { + y = (((r * 263) + (g * 516) + (b * 100)) >> 10) + 16; + u = (((r * 450) - (g * 377) - (b * 73)) >> 10) + 128; + v = (((r * -152) - (g * 298) + (b * 450)) >> 10) + 128; + if (y < 0) y = 0; if (y > 255) y = 255; + if (u < 0) u = 0; if (u > 255) u = 255; + if (v < 0) v = 0; if (v > 255) v = 255; + PAL4[i] = (y<> fb.cc[0].r) << fb.cc[0].l; + g = (g >> fb.cc[1].r) << fb.cc[1].l; + b = (b >> fb.cc[2].r) << fb.cc[2].l; + c = r|g|b; + + switch (fb.pelsize) + { + case 1: + PAL1[i] = c; + PAL2[i] = (c<<8) | c; + PAL4[i] = (c<<24) | (c<<16) | (c<<8) | c; + break; + case 2: + PAL2[i] = c; + PAL4[i] = (c<<16) | c; + break; + case 3: + case 4: + PAL4[i] = c; + break; + } +} + +void pal_write(int i, byte b) +{ + if (lcd.pal[i] == b) return; + lcd.pal[i] = b; + updatepalette(i>>1); +} + +void pal_write_dmg(int i, int mapnum, byte d) +{ + int j; + int *cmap = dmg_pal[mapnum]; + int c, r, g, b; + + if (hw.cgb) return; + + /* if (mapnum >= 2) d = 0xe4; */ + for (j = 0; j < 8; j += 2) + { + c = cmap[(d >> j) & 3]; + r = (c & 0xf8) >> 3; + g = (c & 0xf800) >> 6; + b = (c & 0xf80000) >> 9; + c = r|g|b; + /* FIXME - handle directly without faking cgb */ + pal_write(i+j, c & 0xff); + pal_write(i+j+1, c >> 8); + } +} + +void vram_write(int a, byte b) +{ + lcd.vbank[R_VBK&1][a] = b; + if (a >= 0x1800) return; + patdirty[((R_VBK&1)<<9)+(a>>4)] = 1; + anydirty = 1; +} + +void vram_dirty() +{ + anydirty = 1; + memset(patdirty, 1, sizeof patdirty); +} + +void pal_dirty() +{ + int i; + if (!hw.cgb) + { + pal_write_dmg(0, 0, R_BGP); + pal_write_dmg(8, 1, R_BGP); + pal_write_dmg(64, 2, R_OBP0); + pal_write_dmg(72, 3, R_OBP1); + } + for (i = 0; i < 64; i++) + updatepalette(i); +} + +void lcd_reset() +{ + memset(&lcd, 0, sizeof lcd); + lcd_begin(); + vram_dirty(); + pal_dirty(); +} + + + + + + + + + + + + + + + + diff --git a/lcd.h b/lcd.h new file mode 100644 index 0000000..b062534 --- /dev/null +++ b/lcd.h @@ -0,0 +1,57 @@ + + +#ifndef __LCD_H__ +#define __LCD_H__ + +#include "defs.h" + +struct vissprite +{ + byte *buf; + int x; + byte pal, pri, pad[6]; +}; + +struct scan +{ + int bg[64]; + int wnd[64]; + byte buf[256]; + byte pal1[128]; + un16 pal2[64]; + un32 pal4[64]; + byte pri[256]; + struct vissprite vs[16]; + int ns, l, x, y, s, t, u, v, wx, wy, wt, wv; +}; + +struct obj +{ + byte y; + byte x; + byte pat; + byte flags; +}; + +struct lcd +{ + byte vbank[2][8192]; + union + { + byte mem[256]; + struct obj obj[40]; + } oam; + byte pal[128]; +}; + +extern struct lcd lcd; +extern struct scan scan; + + + + + +#endif + + + diff --git a/lcdc.c b/lcdc.c new file mode 100644 index 0000000..b0baa10 --- /dev/null +++ b/lcdc.c @@ -0,0 +1,179 @@ + + +#include + +#include "defs.h" +#include "hw.h" +#include "cpu.h" +#include "regs.h" + + +#define C (cpu.lcdc) + + +/* + * stat_trigger updates the STAT interrupt line to reflect whether any + * of the conditions set to be tested (by bits 3-6 of R_STAT) are met. + * This function should be called whenever any of the following occur: + * 1) LY or LYC changes. + * 2) A state transition affects the low 2 bits of R_STAT (see below). + * 3) The program writes to the upper bits of R_STAT. + * stat_trigger also updates bit 2 of R_STAT to reflect whether LY=LYC. + */ + +void stat_trigger() +{ + static const int condbits[4] = { 0x08, 0x30, 0x20, 0x00 }; + int flag = 0; + + if ((R_LY < 0x91) && (R_LY == R_LYC)) + { + R_STAT |= 0x04; + if (R_STAT & 0x40) flag = IF_STAT; + } + else R_STAT &= ~0x04; + + if (R_STAT & condbits[R_STAT&3]) flag = IF_STAT; + + if (!(R_LCDC & 0x80)) flag = 0; + + hw_interrupt(flag, IF_STAT); +} + +void stat_write(byte b) +{ + R_STAT = (R_STAT & 0x07) | (b & 0x78); + if (!hw.cgb && !(R_STAT & 2)) /* DMG STAT write bug => interrupt */ + hw_interrupt(IF_STAT, IF_STAT); + stat_trigger(); +} + + +/* + * stat_change is called when a transition results in a change to the + * LCD STAT condition (the low 2 bits of R_STAT). It raises or lowers + * the VBLANK interrupt line appropriately and calls stat_trigger to + * update the STAT interrupt line. + */ + +static void stat_change(int stat) +{ + stat &= 3; + R_STAT = (R_STAT & 0x7C) | stat; + + if (stat != 1) hw_interrupt(0, IF_VBLANK); + /* hw_interrupt((stat == 1) ? IF_VBLANK : 0, IF_VBLANK); */ + stat_trigger(); +} + + +void lcdc_change(byte b) +{ + byte old = R_LCDC; + R_LCDC = b; + if ((R_LCDC ^ old) & 0x80) /* lcd on/off change */ + { + R_LY = 0; + stat_change(2); + C = 40; + lcd_begin(); + } +} + + +void lcdc_trans() +{ + if (!(R_LCDC & 0x80)) + { + while (C <= 0) + { + switch ((byte)(R_STAT & 3)) + { + case 0: + case 1: + stat_change(2); + C += 40; + break; + case 2: + stat_change(3); + C += 86; + break; + case 3: + stat_change(0); + if (hw.hdma & 0x80) + hw_hdma(); + else + C += 102; + break; + } + return; + } + } + while (C <= 0) + { + switch ((byte)(R_STAT & 3)) + { + case 1: + if (!(hw.ilines & IF_VBLANK)) + { + C += 218; + hw_interrupt(IF_VBLANK, IF_VBLANK); + break; + } + if (R_LY == 0) + { + lcd_begin(); + stat_change(2); + C += 40; + break; + } + else if (R_LY < 152) + C += 228; + else if (R_LY == 152) + C += 28; + else + { + R_LY = -1; + C += 200; + } + R_LY++; + stat_trigger(); + break; + case 2: + lcd_refreshline(); + stat_change(3); + C += 86; + break; + case 3: + stat_change(0); + if (hw.hdma & 0x80) + hw_hdma(); + /* FIXME -- how much of the hblank does hdma use?? */ + /* else */ + C += 102; + break; + case 0: + if (++R_LY >= 144) + { + if (cpu.halt) + { + hw_interrupt(IF_VBLANK, IF_VBLANK); + C += 228; + } + else C += 10; + stat_change(1); + break; + } + stat_change(2); + C += 40; + break; + } + } +} + + + + + + + diff --git a/loader.c b/loader.c new file mode 100644 index 0000000..b884048 --- /dev/null +++ b/loader.c @@ -0,0 +1,395 @@ + + +#include "defs.h" +#include "regs.h" +#include "mem.h" +#include "hw.h" +#include "rtc.h" +#include "rc.h" + +#include +#include +#include + +char *strdup(); + +static int mbc_table[256] = +{ + 0, 1, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 3, 3, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, MBC_RUMBLE, MBC_RUMBLE, MBC_RUMBLE, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MBC_HUC3, MBC_HUC1 +}; + +static int rtc_table[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0 +}; + +static int batt_table[256] = +{ + 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, + 0 +}; + +static int romsize_table[256] = +{ + 2, 4, 8, 16, 32, 64, 128, 256, 512, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 128, 128, 128 + /* 0, 0, 72, 80, 96 -- actual values but bad to use these! */ +}; + +static int ramsize_table[256] = +{ + 1, 1, 1, 4, 16, + 4 /* FIXME - what value should this be?! */ +}; + + +static char *romfile; +static char *sramfile; +static char *rtcfile; +static char *saveprefix; + +static char *savename; +static char *savedir; + +static int saveslot; + +static int forcebatt, nobatt; +static int forcedmg, gbamode; + +static int memfill = -1, memrand = -1; + + +static void initmem(void *mem, int size) +{ + char *p = mem; + if (memrand >= 0) + { + srand(memrand ? memrand : time(0)); + while(size--) *(p++) = rand(); + } + else if (memfill >= 0) + memset(p, memfill, size); +} + +static byte *loadfile(FILE *f, int *len) +{ + int c, l = 0, p = 0; + byte *d = 0, buf[512]; + + for(;;) + { + c = fread(buf, 1, sizeof buf, f); + if (c <= 0) break; + l += c; + d = realloc(d, l); + if (!d) return 0; + memcpy(d+p, buf, c); + p += c; + } + *len = l; + return d; +} + +static byte *inf_buf; +static int inf_pos, inf_len; + +static void inflate_callback(byte b) +{ + if (inf_pos >= inf_len) + { + inf_len += 512; + inf_buf = realloc(inf_buf, inf_len); + if (!inf_buf) die("out of memory inflating file @ %d bytes\n", inf_pos); + } + inf_buf[inf_pos++] = b; +} + +static byte *decompress(byte *data, int *len) +{ + unsigned long pos = 0; + if (data[0] != 0x1f || data[1] != 0x8b) + return data; + inf_buf = 0; + inf_pos = inf_len = 0; + if (unzip(data, &pos, inflate_callback) < 0) + return data; + *len = inf_pos; + return inf_buf; +} + + +int rom_load() +{ + FILE *f; + byte c, *data, *header; + int len = 0, rlen; + + if (strcmp(romfile, "-")) f = fopen(romfile, "rb"); + else f = stdin; + if (!f) die("cannot open rom file: %s\n", romfile); + + data = loadfile(f, &len); + header = data = decompress(data, &len); + + memcpy(rom.name, header+0x0134, 16); + if (rom.name[14] & 0x80) rom.name[14] = 0; + if (rom.name[15] & 0x80) rom.name[15] = 0; + rom.name[16] = 0; + + c = header[0x0147]; + mbc.type = mbc_table[c]; + mbc.batt = (batt_table[c] && !nobatt) || forcebatt; + rtc.batt = rtc_table[c]; + mbc.romsize = romsize_table[header[0x0148]]; + mbc.ramsize = ramsize_table[header[0x0149]]; + + if (!mbc.romsize) die("unknown ROM size %02X\n", header[0x0148]); + if (!mbc.ramsize) die("unknown SRAM size %02X\n", header[0x0149]); + + rlen = 16384 * mbc.romsize; + rom.bank = realloc(data, rlen); + if (rlen > len) memset(rom.bank[0]+len, 0xff, rlen - len); + + ram.sbank = malloc(8192 * mbc.ramsize); + + initmem(ram.sbank, 8192 * mbc.ramsize); + initmem(ram.ibank, 4096 * 8); + + mbc.rombank = 1; + mbc.rambank = 0; + + c = header[0x0143]; + hw.cgb = ((c == 0x80) || (c == 0xc0)) && !forcedmg; + hw.gba = (hw.cgb && gbamode); + + if (strcmp(romfile, "-")) fclose(f); + + return 0; +} + +int sram_load() +{ + FILE *f; + + if (!mbc.batt || !sramfile || !*sramfile) return -1; + + /* Consider sram loaded at this point, even if file doesn't exist */ + ram.loaded = 1; + + f = fopen(sramfile, "rb"); + if (!f) return -1; + fread(ram.sbank, 8192, mbc.ramsize, f); + fclose(f); + + return 0; +} + + +int sram_save() +{ + FILE *f; + + /* If we crash before we ever loaded sram, DO NOT SAVE! */ + if (!mbc.batt || !sramfile || !ram.loaded || !mbc.ramsize) + return -1; + + f = fopen(sramfile, "wb"); + if (!f) return -1; + fwrite(ram.sbank, 8192, mbc.ramsize, f); + fclose(f); + + return 0; +} + + +void state_save(int n) +{ + FILE *f; + char *name; + + if (n < 0) n = saveslot; + if (n < 0) n = 0; + name = malloc(strlen(saveprefix) + 5); + sprintf(name, "%s.%03d", saveprefix, n); + + if ((f = fopen(name, "wb"))) + { + savestate(f); + fclose(f); + } + free(name); +} + + +void state_load(int n) +{ + FILE *f; + char *name; + + if (n < 0) n = saveslot; + if (n < 0) n = 0; + name = malloc(strlen(saveprefix) + 5); + sprintf(name, "%s.%03d", saveprefix, n); + + if ((f = fopen(name, "rb"))) + { + loadstate(f); + fclose(f); + vram_dirty(); + pal_dirty(); + sound_dirty(); + mem_updatemap(); + } + free(name); +} + +void rtc_save() +{ + FILE *f; + if (!rtc.batt) return; + if (!(f = fopen(rtcfile, "wb"))) return; + rtc_save_internal(f); + fclose(f); +} + +void rtc_load() +{ + FILE *f; + if (!rtc.batt) return; + if (!(f = fopen(rtcfile, "r"))) return; + rtc_load_internal(f); + fclose(f); +} + + +void loader_unload() +{ + sram_save(); + if (romfile) free(romfile); + if (sramfile) free(sramfile); + if (saveprefix) free(saveprefix); + if (rom.bank) free(rom.bank); + if (ram.sbank) free(ram.sbank); + romfile = sramfile = saveprefix = 0; + rom.bank = 0; + ram.sbank = 0; + mbc.type = mbc.romsize = mbc.ramsize = mbc.batt = 0; +} + +static char *base(char *s) +{ + char *p; + p = strrchr(s, '/'); + if (p) return p+1; + return s; +} + +static char *ldup(char *s) +{ + int i; + char *n, *p; + p = n = malloc(strlen(s)); + for (i = 0; s[i]; i++) if (isalnum(s[i])) *(p++) = tolower(s[i]); + *p = 0; + return n; +} + +static void cleanup() +{ + sram_save(); + rtc_save(); + /* IDEA - if error, write emergency savestate..? */ +} + +void loader_init(char *s) +{ + char *name, *p; + + sys_checkdir(savedir, 1); /* needs to be writable */ + + romfile = s; + rom_load(); + vid_settitle(rom.name); + if (savename && *savename) + { + if (savename[0] == '-' && savename[1] == 0) + name = ldup(rom.name); + else name = strdup(savename); + } + else if (romfile && *base(romfile) && strcmp(romfile, "-")) + { + name = strdup(base(romfile)); + p = strchr(name, '.'); + if (p) *p = 0; + } + else name = ldup(rom.name); + + saveprefix = malloc(strlen(savedir) + strlen(name) + 2); + sprintf(saveprefix, "%s/%s", savedir, name); + + sramfile = malloc(strlen(saveprefix) + 5); + strcpy(sramfile, saveprefix); + strcat(sramfile, ".sav"); + + rtcfile = malloc(strlen(saveprefix) + 5); + strcpy(rtcfile, saveprefix); + strcat(rtcfile, ".rtc"); + + sram_load(); + rtc_load(); + + atexit(cleanup); +} + +rcvar_t loader_exports[] = +{ + RCV_STRING("savedir", &savedir), + RCV_STRING("savename", &savename), + RCV_INT("saveslot", &saveslot), + RCV_BOOL("forcebatt", &forcebatt), + RCV_BOOL("nobatt", &nobatt), + RCV_BOOL("forcedmg", &forcedmg), + RCV_BOOL("gbamode", &gbamode), + RCV_INT("memfill", &memfill), + RCV_INT("memrand", &memrand), + RCV_END +}; + + + + + + + + + diff --git a/loader.h b/loader.h new file mode 100644 index 0000000..fd68f44 --- /dev/null +++ b/loader.h @@ -0,0 +1,28 @@ + + +#ifndef __LOADER_H__ +#define __LOADER_H__ + + +typedef struct loader_s +{ + char *rom; + char *base; + char *sram; + char *state; + int ramloaded; +} loader_t; + + +extern loader_t loader; + + +int rom_load(); +int sram_load(); +int sram_save(); + + + +#endif + + diff --git a/main.c b/main.c new file mode 100644 index 0000000..3c2c84c --- /dev/null +++ b/main.c @@ -0,0 +1,323 @@ + + + + + + +#include +#include +#include + +char *strdup(); + +#include +#include + +#include "input.h" +#include "rc.h" + + +#include "Version" + + +static char *defaultconfig[] = +{ + "bind esc quit", + "bind up +up", + "bind down +down", + "bind left +left", + "bind right +right", + "bind d +a", + "bind s +b", + "bind enter +start", + "bind space +select", + "bind tab +select", + "bind joyup +up", + "bind joydown +down", + "bind joyleft +left", + "bind joyright +right", + "bind joy0 +b", + "bind joy1 +a", + "bind joy2 +select", + "bind joy3 +start", + "bind 1 \"set saveslot 1\"", + "bind 2 \"set saveslot 2\"", + "bind 3 \"set saveslot 3\"", + "bind 4 \"set saveslot 4\"", + "bind 5 \"set saveslot 5\"", + "bind 6 \"set saveslot 6\"", + "bind 7 \"set saveslot 7\"", + "bind 8 \"set saveslot 8\"", + "bind 9 \"set saveslot 9\"", + "bind 0 \"set saveslot 0\"", + "bind ins savestate", + "bind del loadstate", + "source gnuboy.rc", + NULL +}; + + +static void banner() +{ + printf("\ngnuboy " VERSION "\n"); +} + +static void copyright() +{ + banner(); + printf( +"Copyright (C) 2000-2001 Laguna and Gilgamesh\n" +"Portions contributed by other authors; see CREDITS for details.\n" +"\n" +"This program is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n" +"\n"); +} + +static void usage(char *name) +{ + copyright(); + printf("Type %s --help for detailed help.\n\n", name); + exit(1); +} + +static void copying() +{ + copyright(); + exit(0); +} + +static void help(char *name) +{ + banner(); + printf("Usage: %s [options] romfile\n", name); + printf("\n" +" --source FILE read rc commands from FILE\n" +" --bind KEY COMMAND bind KEY to perform COMMAND\n" +" --VAR=VALUE set rc variable VAR to VALUE\n" +" --VAR set VAR to 1 (turn on boolean options)\n" +" --no-VAR set VAR to 0 (turn off boolean options)\n" +" --showvars list all available rc variables\n" +" --help display this help and exit\n" +" --version output version information and exit\n" +" --copying show copying permissions\n" +""); + exit(0); +} + + +static void version(char *name) +{ + printf("%s-" VERSION "\n", name); + exit(0); +} + + +void doevents() +{ + event_t ev; + int st; + + ev_poll(); + while (ev_getevent(&ev)) + { + if (ev.type != EV_PRESS && ev.type != EV_RELEASE) + continue; + st = (ev.type != EV_RELEASE); + rc_dokey(ev.code, st); + } +} + + + + +static void shutdown() +{ + vid_close(); + pcm_close(); +} + +void die(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static int bad_signals[] = +{ + /* These are all standard, so no need to #ifdef them... */ + SIGINT, SIGSEGV, SIGTERM, SIGFPE, SIGABRT, SIGILL, +#ifdef SIGQUIT + SIGQUIT, +#endif +#ifdef SIGPIPE + SIGPIPE, +#endif + 0 +}; + +static void fatalsignal(int s) +{ + die("Signal %d\n", s); +} + +static void catch_signals() +{ + int i; + for (i = 0; bad_signals[i]; i++) + signal(bad_signals[i], fatalsignal); +} + + + +static char *base(char *s) +{ + char *p; + p = strrchr(s, '/'); + if (p) return p+1; + return s; +} + + +int main(int argc, char *argv[]) +{ + int i; + char *opt, *arg, *cmd, *s, *rom = 0; + + /* Avoid initializing video if we don't have to */ + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "--help")) + help(base(argv[0])); + else if (!strcmp(argv[i], "--version")) + version(base(argv[0])); + else if (!strcmp(argv[i], "--copying")) + copying(); + else if (!strcmp(argv[i], "--bind")) i += 2; + else if (!strcmp(argv[i], "--source")) i++; + else if (!strcmp(argv[i], "--showvars")) + { + show_exports(); + exit(0); + } + else if (argv[i][0] == '-' && argv[i][1] == '-'); + else if (argv[i][0] == '-' && argv[i][1]); + else rom = argv[i]; + } + + if (!rom) usage(base(argv[0])); + + /* If we have special perms, drop them ASAP! */ + vid_preinit(); + + init_exports(); + + s = strdup(argv[0]); + sys_sanitize(s); + sys_initpath(s); + + for (i = 0; defaultconfig[i]; i++) + rc_command(defaultconfig[i]); + + cmd = malloc(strlen(rom) + 11); + sprintf(cmd, "source %s", rom); + s = strchr(cmd, '.'); + if (s) *s = 0; + strcat(cmd, ".rc"); + rc_command(cmd); + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "--bind")) + { + if (i + 2 >= argc) die("missing arguments to bind\n"); + cmd = malloc(strlen(argv[i+1]) + strlen(argv[i+2]) + 9); + sprintf(cmd, "bind %s \"%s\"", argv[i+1], argv[i+2]); + rc_command(cmd); + free(cmd); + i += 2; + } + else if (!strcmp(argv[i], "--source")) + { + if (i + 1 >= argc) die("missing argument to source\n"); + cmd = malloc(strlen(argv[i+1]) + 6); + sprintf(cmd, "source %s", argv[++i]); + rc_command(cmd); + free(cmd); + } + else if (!strncmp(argv[i], "--no-", 5)) + { + opt = strdup(argv[i]+5); + while ((s = strchr(opt, '-'))) *s = '_'; + cmd = malloc(strlen(opt) + 7); + sprintf(cmd, "set %s 0", opt); + rc_command(cmd); + free(cmd); + free(opt); + } + else if (argv[i][0] == '-' && argv[i][1] == '-') + { + opt = strdup(argv[i]+2); + if ((s = strchr(opt, '='))) + { + *s = 0; + arg = s+1; + } + else arg = "1"; + while ((s = strchr(opt, '-'))) *s = '_'; + while ((s = strchr(arg, ','))) *s = ' '; + + cmd = malloc(strlen(opt) + strlen(arg) + 6); + sprintf(cmd, "set %s %s", opt, arg); + + rc_command(cmd); + free(cmd); + free(opt); + } + /* short options not yet implemented */ + else if (argv[i][0] == '-' && argv[i][1]); + } + + /* FIXME - make interface modules responsible for atexit() */ + atexit(shutdown); + catch_signals(); + vid_init(); + pcm_init(); + + rom = strdup(rom); + sys_sanitize(rom); + + loader_init(rom); + + emu_reset(); + emu_run(); + + /* never reached */ + return 0; +} + + + + + + + + + + + diff --git a/mem.c b/mem.c new file mode 100644 index 0000000..edcb4f1 --- /dev/null +++ b/mem.c @@ -0,0 +1,576 @@ + + +#include + +#include "defs.h" +#include "hw.h" +#include "regs.h" +#include "mem.h" +#include "rtc.h" +#include "lcd.h" + +struct mbc mbc; +struct rom rom; +struct ram ram; + + +/* + * In order to make reads and writes efficient, we keep tables + * (indexed by the high nibble of the address) specifying which + * regions can be read/written without a function call. For such + * ranges, the pointer in the map table points to the base of the + * region in host system memory. For ranges that require special + * processing, the pointer is NULL. + * + * mem_updatemap is called whenever bank changes or other operations + * make the old maps potentially invalid. + */ + +void mem_updatemap() +{ + int n; + byte **map; + + map = mbc.rmap; + map[0x0] = rom.bank[0]; + map[0x1] = rom.bank[0]; + map[0x2] = rom.bank[0]; + map[0x3] = rom.bank[0]; + if (mbc.rombank < mbc.romsize) + { + map[0x4] = rom.bank[mbc.rombank] - 0x4000; + map[0x5] = rom.bank[mbc.rombank] - 0x4000; + map[0x6] = rom.bank[mbc.rombank] - 0x4000; + map[0x7] = rom.bank[mbc.rombank] - 0x4000; + } + else map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL; + if (0 && (R_STAT & 0x03) == 0x03) + { + map[0x8] = NULL; + map[0x9] = NULL; + } + else + { + map[0x8] = lcd.vbank[R_VBK & 1] - 0x8000; + map[0x9] = lcd.vbank[R_VBK & 1] - 0x8000; + } + if (mbc.enableram && !(rtc.sel&8)) + { + map[0xA] = ram.sbank[mbc.rambank] - 0xA000; + map[0xB] = ram.sbank[mbc.rambank] - 0xA000; + } + else map[0xA] = map[0xB] = NULL; + map[0xC] = ram.ibank[0] - 0xC000; + n = R_SVBK & 0x07; + map[0xD] = ram.ibank[n?n:1] - 0xD000; + map[0xE] = ram.ibank[0] - 0xE000; + map[0xF] = NULL; + + map = mbc.wmap; + map[0x0] = map[0x1] = map[0x2] = map[0x3] = NULL; + map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL; + map[0x8] = map[0x9] = NULL; + if (mbc.enableram && !(rtc.sel&8)) + { + map[0xA] = ram.sbank[mbc.rambank] - 0xA000; + map[0xB] = ram.sbank[mbc.rambank] - 0xA000; + } + else map[0xA] = map[0xB] = NULL; + map[0xC] = ram.ibank[0] - 0xC000; + n = R_SVBK & 0x07; + map[0xD] = ram.ibank[n?n:1] - 0xD000; + map[0xE] = ram.ibank[0] - 0xE000; + map[0xF] = NULL; +} + + +/* + * ioreg_write handles output to io registers in the FF00-FF7F,FFFF + * range. It takes the register number (low byte of the address) and a + * byte value to be written. + */ + +void ioreg_write(byte r, byte b) +{ + if (!hw.cgb) + { + switch (r) + { + case RI_VBK: + case RI_BCPS: + case RI_OCPS: + case RI_BCPD: + case RI_OCPD: + case RI_SVBK: + case RI_KEY1: + case RI_HDMA1: + case RI_HDMA2: + case RI_HDMA3: + case RI_HDMA4: + case RI_HDMA5: + return; + } + } + + switch(r) + { + case RI_TIMA: + case RI_TMA: + case RI_TAC: + case RI_SCY: + case RI_SCX: + case RI_WY: + case RI_WX: + REG(r) = b; + break; + case RI_BGP: + if (R_BGP == b) break; + pal_write_dmg(0, 0, b); + pal_write_dmg(8, 1, b); + R_BGP = b; + break; + case RI_OBP0: + if (R_OBP0 == b) break; + pal_write_dmg(64, 2, b); + R_OBP0 = b; + break; + case RI_OBP1: + if (R_OBP1 == b) break; + pal_write_dmg(72, 3, b); + R_OBP1 = b; + break; + case RI_IF: + case RI_IE: + REG(r) = b & 0x1F; + break; + case RI_P1: + REG(r) = b; + pad_refresh(); + break; + case RI_SC: + /* FIXME - this is a hack for stupid roms that probe serial */ + if ((b & 0x81) == 0x81) + { + R_SB = 0xff; + hw_interrupt(IF_SERIAL, IF_SERIAL); + hw_interrupt(0, IF_SERIAL); + } + R_SC = b; /* & 0x7f; */ + break; + case RI_DIV: + REG(r) = 0; + break; + case RI_LCDC: + lcdc_change(b); + break; + case RI_STAT: + stat_write(b); + break; + case RI_LYC: + REG(r) = b; + stat_trigger(); + break; + case RI_VBK: + REG(r) = b | 0xFE; + mem_updatemap(); + break; + case RI_BCPS: + R_BCPS = b & 0xBF; + R_BCPD = lcd.pal[b & 0x3F]; + break; + case RI_OCPS: + R_OCPS = b & 0xBF; + R_OCPD = lcd.pal[64 + (b & 0x3F)]; + break; + case RI_BCPD: + R_BCPD = b; + pal_write(R_BCPS & 0x3F, b); + if (R_BCPS & 0x80) R_BCPS = (R_BCPS+1) & 0xBF; + break; + case RI_OCPD: + R_OCPD = b; + pal_write(64 + (R_OCPS & 0x3F), b); + if (R_OCPS & 0x80) R_OCPS = (R_OCPS+1) & 0xBF; + break; + case RI_SVBK: + REG(r) = b & 0x07; + mem_updatemap(); + break; + case RI_DMA: + hw_dma(b); + break; + case RI_KEY1: + REG(r) = (REG(r) & 0x80) | (b & 0x01); + break; + case RI_HDMA1: + REG(r) = b; + break; + case RI_HDMA2: + REG(r) = b & 0xF0; + break; + case RI_HDMA3: + REG(r) = b & 0x1F; + break; + case RI_HDMA4: + REG(r) = b & 0xF0; + break; + case RI_HDMA5: + hw_hdma_cmd(b); + break; + } + switch (r) + { + case RI_BGP: + case RI_OBP0: + case RI_OBP1: + /* printf("palette reg %02X write %02X at LY=%02X\n", r, b, R_LY); */ + case RI_HDMA1: + case RI_HDMA2: + case RI_HDMA3: + case RI_HDMA4: + case RI_HDMA5: + /* printf("HDMA %d: %02X\n", r - RI_HDMA1 + 1, b); */ + break; + } + /* printf("reg %02X => %02X (%02X)\n", r, REG(r), b); */ +} + + +byte ioreg_read(byte r) +{ + switch(r) + { + case RI_SC: + r = R_SC; + R_SC &= 0x7f; + return r; + case RI_P1: + case RI_SB: + case RI_DIV: + case RI_TIMA: + case RI_TMA: + case RI_TAC: + case RI_LCDC: + case RI_STAT: + case RI_SCY: + case RI_SCX: + case RI_LY: + case RI_LYC: + case RI_BGP: + case RI_OBP0: + case RI_OBP1: + case RI_WY: + case RI_WX: + case RI_IE: + case RI_IF: + return REG(r); + case RI_VBK: + case RI_BCPS: + case RI_OCPS: + case RI_BCPD: + case RI_OCPD: + case RI_SVBK: + case RI_KEY1: + case RI_HDMA1: + case RI_HDMA2: + case RI_HDMA3: + case RI_HDMA4: + case RI_HDMA5: + if (hw.cgb) return REG(r); + default: + return 0xff; + } +} + + + +/* + * Memory bank controllers typically intercept write attempts to + * 0000-7FFF, using the address and byte written as instructions to + * change rom or sram banks, control special hardware, etc. + * + * mbc_write takes an address (which should be in the proper range) + * and a byte value written to the address. + */ + +void mbc_write(int a, byte b) +{ + byte ha = (a>>12); + + /* printf("mbc %d: rom bank %02X -[%04X:%02X]-> ", mbc.type, mbc.rombank, a, b); */ + switch (mbc.type) + { + case MBC_MBC1: + switch (ha & 0xE) + { + case 0x0: + mbc.enableram = ((b & 0x0F) == 0x0A); + break; + case 0x2: + if ((b & 0x1F) == 0) b = 0x01; + mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F); + break; + case 0x4: + if (mbc.model) + { + mbc.rambank = b & 0x03; + break; + } + mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5); + break; + case 0x6: + mbc.model = b & 0x1; + break; + } + break; + case MBC_MBC2: /* is this at all right? */ + if ((a & 0x0100) == 0x0000) + { + mbc.enableram = ((b & 0x0F) == 0x0A); + break; + } + if ((a & 0xE100) == 0x2100) + { + mbc.rombank = b & 0x0F; + break; + } + break; + case MBC_MBC3: + switch (ha & 0xE) + { + case 0x0: + mbc.enableram = ((b & 0x0F) == 0x0A); + break; + case 0x2: + if ((b & 0x7F) == 0) b = 0x01; + mbc.rombank = b & 0x7F; + break; + case 0x4: + rtc.sel = b & 0x0f; + mbc.rambank = b & 0x03; + break; + case 0x6: + rtc_latch(b); + break; + } + break; + case MBC_RUMBLE: + switch (ha & 0xF) + { + case 0x4: + case 0x5: + /* FIXME - save high bit as rumble state */ + /* mask off high bit */ + b &= 0x7; + break; + } + /* fall thru */ + case MBC_MBC5: + switch (ha & 0xF) + { + case 0x0: + case 0x1: + mbc.enableram = ((b & 0x0F) == 0x0A); + break; + case 0x2: + if ((b & 0xFF) == 0) b = 0x01; + mbc.rombank = (mbc.rombank & 0x100) | (b & 0xFF); + break; + case 0x3: + mbc.rombank = (mbc.rombank & 0xFF) | ((int)(b&1)<<8); + break; + case 0x4: + case 0x5: + mbc.rambank = b & 0x0f; + break; + } + break; + case MBC_HUC1: /* FIXME - this is all guesswork -- is it right??? */ + switch (ha & 0xE) + { + case 0x0: + mbc.enableram = ((b & 0x0F) == 0x0A); + break; + case 0x2: + if ((b & 0x1F) == 0) b = 0x01; + mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F); + break; + case 0x4: + if (mbc.model) + { + mbc.rambank = b & 0x03; + break; + } + mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5); + break; + case 0x6: + mbc.model = b & 0x1; + break; + } + break; + case MBC_HUC3: + switch (ha & 0xE) + { + case 0x0: + mbc.enableram = ((b & 0x0F) == 0x0A); + break; + case 0x2: + b &= 0x7F; + mbc.rombank = b ? b : 1; + break; + case 0x4: + rtc.sel = b & 0x0f; + mbc.rambank = b & 0x03; + break; + case 0x6: + rtc_latch(b); + break; + } + break; + } + mbc.rombank &= (mbc.romsize - 1); + mbc.rambank &= (mbc.ramsize - 1); + /* printf("%02X\n", mbc.rombank); */ + mem_updatemap(); +} + + +/* + * mem_write is the basic write function. Although it should only be + * called when the write map contains a NULL for the requested address + * region, it accepts writes to any address. + */ + +void mem_write(int a, byte b) +{ + int n; + byte ha = (a>>12) & 0xE; + + /* printf("write to 0x%04X: 0x%02X\n", a, b); */ + switch (ha) + { + case 0x0: + case 0x2: + case 0x4: + case 0x6: + mbc_write(a, b); + break; + case 0x8: + /* if ((R_STAT & 0x03) == 0x03) break; */ + vram_write(a & 0x1FFF, b); + break; + case 0xA: + if (!mbc.enableram) break; + if (rtc.sel&8) + { + rtc_write(b); + break; + } + ram.sbank[mbc.rambank][a & 0x1FFF] = b; + break; + case 0xC: + if ((a & 0xF000) == 0xC000) + { + ram.ibank[0][a & 0x0FFF] = b; + break; + } + n = R_SVBK & 0x07; + ram.ibank[n?n:1][a & 0x0FFF] = b; + break; + case 0xE: + if (a < 0xFE00) + { + mem_write(a & 0xDFFF, b); + break; + } + if ((a & 0xFF00) == 0xFE00) + { + /* if (R_STAT & 0x02) break; */ + if (a < 0xFEA0) lcd.oam.mem[a & 0xFF] = b; + break; + } + /* return writehi(a & 0xFF, b); */ + if (a >= 0xFF10 && a <= 0xFF3F) + { + sound_write(a & 0xFF, b); + break; + } + if ((a & 0xFF80) == 0xFF80 && a != 0xFFFF) + { + ram.hi[a & 0xFF] = b; + break; + } + ioreg_write(a & 0xFF, b); + } +} + + +/* + * mem_read is the basic read function...not useful for much anymore + * with the read map, but it's still necessary for the final messy + * region. + */ + +byte mem_read(int a) +{ + int n; + byte ha = (a>>12) & 0xE; + + /* printf("read %04x\n", a); */ + switch (ha) + { + case 0x0: + case 0x2: + return rom.bank[0][a]; + case 0x4: + case 0x6: + return rom.bank[mbc.rombank][a & 0x3FFF]; + case 0x8: + /* if ((R_STAT & 0x03) == 0x03) return 0xFF; */ + return lcd.vbank[R_VBK&1][a & 0x1FFF]; + case 0xA: + if (!mbc.enableram && mbc.type == MBC_HUC3) + return 0x01; + if (!mbc.enableram) + return 0xFF; + if (rtc.sel&8) + return rtc.regs[rtc.sel&7]; + return ram.sbank[mbc.rambank][a & 0x1FFF]; + case 0xC: + if ((a & 0xF000) == 0xC000) + return ram.ibank[0][a & 0x0FFF]; + n = R_SVBK & 0x07; + return ram.ibank[n?n:1][a & 0x0FFF]; + case 0xE: + if (a < 0xFE00) return mem_read(a & 0xDFFF); + if ((a & 0xFF00) == 0xFE00) + { + /* if (R_STAT & 0x02) return 0xFF; */ + if (a < 0xFEA0) return lcd.oam.mem[a & 0xFF]; + return 0xFF; + } + /* return readhi(a & 0xFF); */ + if (a == 0xFFFF) return REG(0xFF); + if (a >= 0xFF10 && a <= 0xFF3F) + return sound_read(a & 0xFF); + if ((a & 0xFF80) == 0xFF80) + return ram.hi[a & 0xFF]; + return ioreg_read(a & 0xFF); + } + return 0xff; /* not reached */ +} + +void mbc_reset() +{ + mbc.rombank = 1; + mbc.rambank = 0; + mbc.enableram = 0; + mem_updatemap(); +} + + + + + + + diff --git a/mem.h b/mem.h new file mode 100644 index 0000000..29caa68 --- /dev/null +++ b/mem.h @@ -0,0 +1,79 @@ + +#ifndef __MEM_H__ +#define __MEM_H__ + + +#include "defs.h" + + + +#define MBC_NONE 0 +#define MBC_MBC1 1 +#define MBC_MBC2 2 +#define MBC_MBC3 3 +#define MBC_MBC5 5 +#define MBC_RUMBLE 15 +#define MBC_HUC1 0xC1 +#define MBC_HUC3 0xC3 + +struct mbc +{ + int type; + int model; + int rombank; + int rambank; + int romsize; + int ramsize; + int enableram; + int batt; + byte *rmap[0x10], *wmap[0x10]; +}; + +struct rom +{ + byte (*bank)[16384]; + char name[20]; +}; + +struct ram +{ + byte hi[256]; + byte ibank[8][4096]; + byte (*sbank)[8192]; + int loaded; +}; + + +extern struct mbc mbc; +extern struct rom rom; +extern struct ram ram; + + + + + +void mem_updatemap(); +void ioreg_write(byte r, byte b); +void mbc_write(int a, byte b); +void mem_write(int a, byte b); +byte mem_read(int a); + + + +#define READB(a) ( mbc.rmap[(a)>>12] \ +? mbc.rmap[(a)>>12][(a)] \ +: mem_read((a)) ) +#define READW(a) ( READB((a)) | ((word)READB((a)+1)<<8) ) + +#define WRITEB(a, b) ( mbc.wmap[(a)>>12] \ +? ( mbc.wmap[(a)>>12][(a)] = (b) ) \ +: ( mem_write((a), (b)), (b) ) ) +#define WRITEW(a, w) ( WRITEB((a), (w)&0xFF), WRITEB((a)+1, (w)>>8) ) + + + + +#endif + + + diff --git a/newsound.c b/newsound.c new file mode 100644 index 0000000..0ae04da --- /dev/null +++ b/newsound.c @@ -0,0 +1,57 @@ +/* + * new sound core for 1.1.x + */ + + + +enum sevcode +{ + SEV_S1E, + SEV_S2E, + SEV_S3E, + SEV_S4E, + SEV_S1L, + SEV_S2L, + SEV_S3L, + SEV_S4L, + SEV_SW, + SEV_WAV +}; + + +struct sev +{ + int prev, next; + int time; +}; + + + +static struct sev *sevs; + + + +void sound_mix(int cycles) +{ + +} + + +void sound_update(int force) +{ + int now = 0; + + for (;;) + { + if (sevs->time > cpu.snd) break; + + } +} + + + + + + + + diff --git a/noise.h b/noise.h new file mode 100644 index 0000000..037499e --- /dev/null +++ b/noise.h @@ -0,0 +1,532 @@ + +#ifndef __NOISE_H__ +#define __NOISE_H__ + + +#include "defs.h" + +static byte noise7[] = +{ + 0xfd,0xf3,0xd7,0x0d,0xd3,0x15,0x82,0xf1, + 0xdb,0x25,0x21,0x39,0x68,0x8c,0xd5,0x00, +}; + +static byte noise15[] = +{ + 0xff,0xfd,0xff,0xf3,0xff,0xd7,0xff,0x0f, + 0xfd,0xdf,0xf3,0x3f,0xd5,0x7f,0x00,0xfd, + 0xfd,0xf3,0xf3,0xd7,0xd7,0x0f,0x0d,0xdd, + 0xd3,0x33,0x15,0x55,0x80,0x02,0xff,0xf1, + 0xff,0xdb,0xff,0x27,0xfd,0x2f,0xf1,0x1f, + 0xd9,0xbf,0x2a,0x7d,0x02,0xf1,0xf1,0xdb, + 0xdb,0x27,0x25,0x2d,0x21,0x11,0x39,0x99, + 0x6a,0xa8,0x80,0x0c,0xff,0xd5,0xff,0x03, + 0xfd,0xf7,0xf3,0xcf,0xd7,0x5f,0x0c,0x3d, + 0xd7,0x73,0x0c,0xd5,0xd5,0x03,0x01,0xf5, + 0xfb,0xc3,0xe7,0x77,0xac,0xce,0x15,0x5b, + 0x80,0x26,0xff,0x29,0xfd,0x0b,0xf1,0xc7, + 0xdb,0x6f,0x24,0x9d,0x24,0xb1,0x24,0x59, + 0x26,0x29,0x2b,0x09,0x05,0xc9,0xe3,0x4b, + 0xb4,0x46,0x46,0x6a,0x6a,0x82,0x80,0xf0, + 0xfd,0xdd,0xf3,0x33,0xd5,0x57,0x00,0x0d, + 0xff,0xd3,0xff,0x17,0xfd,0x8f,0xf2,0xdf, + 0xd1,0x3f,0x19,0x7d,0xa8,0xf2,0x0d,0xd3, + 0xd3,0x17,0x15,0x8d,0x82,0xd2,0xf1,0x11, + 0xd9,0x9b,0x2a,0xa5,0x00,0x21,0xff,0x3b, + 0xfd,0x67,0xf0,0xaf,0xdc,0x1f,0x37,0xbd, + 0x4e,0x70,0x5a,0xde,0x21,0x3b,0x39,0x65, + 0x68,0xa0,0x8c,0x3c,0xd7,0x75,0x0c,0xc1, + 0xd5,0x7b,0x00,0xe5,0xfd,0xa3,0xf2,0x37, + 0xd3,0x4f,0x14,0x5d,0x86,0x32,0xeb,0x51, + 0x84,0x1a,0xe7,0xa1,0xae,0x3a,0x1b,0x63, + 0xa4,0xb6,0x24,0x4b,0x26,0x45,0x2a,0x61, + 0x02,0xb9,0xf0,0x6b,0xde,0x87,0x38,0xed, + 0x6d,0x90,0x92,0x9c,0x90,0xb4,0x9c,0x44, + 0xb6,0x64,0x4a,0xa6,0x40,0x2a,0x7f,0x02, + 0xfd,0xf1,0xf3,0xdb,0xd7,0x27,0x0d,0x2d, + 0xd1,0x13,0x19,0x95,0xaa,0x82,0x00,0xf3, + 0xfd,0xd7,0xf3,0x0f,0xd5,0xdf,0x03,0x3d, + 0xf5,0x73,0xc0,0xd7,0x7d,0x0c,0xf1,0xd5, + 0xdb,0x03,0x25,0xf5,0x23,0xc1,0x37,0x79, + 0x4c,0xe8,0x55,0x8e,0x02,0xdb,0xf1,0x27, + 0xd9,0x2f,0x29,0x1d,0x09,0xb1,0xca,0x5b, + 0x42,0x24,0x73,0x26,0xd5,0x29,0x01,0x09, + 0xf9,0xcb,0xeb,0x47,0x84,0x6e,0xe6,0x99, + 0xa8,0xaa,0x0c,0x03,0xd7,0xf7,0x0f,0xcd, + 0xdf,0x53,0x3c,0x15,0x77,0x80,0xce,0xfd, + 0x59,0xf0,0x2b,0xdf,0x07,0x3d,0xed,0x73, + 0x90,0xd6,0x9d,0x08,0xb1,0xcc,0x5b,0x56, + 0x24,0x0b,0x27,0xc5,0x2f,0x61,0x1c,0xb9, + 0xb4,0x6a,0x46,0x82,0x68,0xf2,0x8d,0xd0, + 0xd3,0x1d,0x15,0xb1,0x82,0x5a,0xf2,0x21, + 0xd3,0x3b,0x15,0x65,0x80,0xa2,0xfc,0x31, + 0xf7,0x5b,0xcc,0x27,0x57,0x2c,0x0d,0x17, + 0xd1,0x8f,0x1a,0xdd,0xa1,0x32,0x39,0x53, + 0x68,0x14,0x8f,0x84,0xde,0xe5,0x39,0xa1, + 0x6a,0x38,0x83,0x6c,0xf4,0x95,0xc4,0x83, + 0x64,0xf4,0xa5,0xc4,0x23,0x67,0x34,0xad, + 0x44,0x10,0x67,0x9e,0xae,0xb8,0x18,0x6f, + 0xae,0x9e,0x18,0xbb,0xac,0x66,0x16,0xab, + 0x88,0x06,0xcf,0xe9,0x5f,0x88,0x3e,0xcf, + 0x79,0x5c,0xe8,0x35,0x8f,0x42,0xdc,0x71, + 0x36,0xd9,0x49,0x28,0x49,0x0e,0x49,0xda, + 0x4b,0x22,0x45,0x32,0x61,0x52,0xb8,0x10, + 0x6f,0x9e,0x9e,0xb8,0xb8,0x6c,0x6e,0x96, + 0x98,0x88,0xac,0xcc,0x15,0x57,0x80,0x0e, + 0xff,0xd9,0xff,0x2b,0xfd,0x07,0xf1,0xef, + 0xdb,0x9f,0x26,0xbd,0x28,0x71,0x0e,0xd9, + 0xd9,0x2b,0x29,0x05,0x09,0xe1,0xcb,0xbb, + 0x46,0x64,0x6a,0xa6,0x80,0x28,0xff,0x0d, + 0xfd,0xd3,0xf3,0x17,0xd5,0x8f,0x02,0xdd, + 0xf1,0x33,0xd9,0x57,0x28,0x0d,0x0f,0xd1, + 0xdf,0x1b,0x3d,0xa5,0x72,0x20,0xd3,0x3d, + 0x15,0x71,0x80,0xda,0xfd,0x21,0xf1,0x3b, + 0xd9,0x67,0x28,0xad,0x0c,0x11,0xd7,0x9b, + 0x0e,0xa5,0xd8,0x23,0x2f,0x35,0x1d,0x41, + 0xb0,0x7a,0x5e,0xe2,0x39,0xb3,0x6a,0x54, + 0x82,0x04,0xf3,0xe5,0xd7,0xa3,0x0e,0x35, + 0xdb,0x43,0x24,0x75,0x26,0xc1,0x29,0x79, + 0x08,0xe9,0xcd,0x8b,0x52,0xc4,0x11,0x67, + 0x98,0xae,0xac,0x18,0x17,0xaf,0x8e,0x1e, + 0xdb,0xb9,0x26,0x69,0x2a,0x89,0x00,0xc9, + 0xfd,0x4b,0xf0,0x47,0xde,0x6f,0x3a,0x9d, + 0x60,0xb0,0xbc,0x5c,0x76,0x36,0xcb,0x49, + 0x44,0x48,0x66,0x4e,0xaa,0x58,0x02,0x2f, + 0xf3,0x1f,0xd5,0xbf,0x02,0x7d,0xf2,0xf3, + 0xd1,0xd7,0x1b,0x0d,0xa5,0xd2,0x23,0x13, + 0x35,0x95,0x42,0x80,0x70,0xfe,0xdd,0xf9, + 0x33,0xe9,0x57,0x88,0x0e,0xcf,0xd9,0x5f, + 0x28,0x3d,0x0f,0x71,0xdc,0xdb,0x35,0x25, + 0x41,0x20,0x79,0x3e,0xe9,0x79,0x88,0xea, + 0xcd,0x81,0x52,0xf8,0x11,0xef,0x9b,0x9e, + 0xa6,0xb8,0x28,0x6f,0x0e,0x9d,0xd8,0xb3, + 0x2c,0x55,0x16,0x01,0x8b,0xfa,0xc7,0xe1, + 0x6f,0xb8,0x9e,0x6c,0xba,0x94,0x60,0x86, + 0xbc,0xe8,0x75,0x8e,0xc2,0xd9,0x71,0x28, + 0xd9,0x0d,0x29,0xd1,0x0b,0x19,0xc5,0xab, + 0x62,0x04,0xb3,0xe4,0x57,0xa6,0x0e,0x2b, + 0xdb,0x07,0x25,0xed,0x23,0x91,0x36,0x99, + 0x48,0xa8,0x4c,0x0e,0x57,0xda,0x0f,0x23, + 0xdd,0x37,0x31,0x4d,0x58,0x50,0x2e,0x1f, + 0x1b,0xbd,0xa6,0x72,0x2a,0xd3,0x01,0x15, + 0xf9,0x83,0xea,0xf7,0x81,0xce,0xfb,0x59, + 0xe4,0x2b,0xa7,0x06,0x2d,0xeb,0x13,0x85, + 0x96,0xe2,0x89,0xb0,0xca,0x5d,0x42,0x30, + 0x73,0x5e,0xd4,0x39,0x07,0x69,0xec,0x8b, + 0x94,0xc6,0x85,0x68,0xe0,0x8d,0xbc,0xd2, + 0x75,0x12,0xc1,0x91,0x7a,0x98,0xe0,0xad, + 0xbc,0x12,0x77,0x92,0xce,0x91,0x58,0x98, + 0x2c,0xaf,0x14,0x1d,0x87,0xb2,0xee,0x51, + 0x9a,0x1a,0xa3,0xa0,0x36,0x3f,0x4b,0x7c, + 0x44,0xf6,0x65,0xca,0xa3,0x40,0x34,0x7f, + 0x46,0xfc,0x69,0xf6,0x8b,0xc8,0xc7,0x4d, + 0x6c,0x50,0x96,0x1c,0x8b,0xb4,0xc6,0x45, + 0x6a,0x60,0x82,0xbc,0xf0,0x75,0xde,0xc3, + 0x39,0x75,0x68,0xc0,0x8d,0x7c,0xd0,0xf5, + 0x1d,0xc1,0xb3,0x7a,0x54,0xe2,0x05,0xb3, + 0xe2,0x57,0xb2,0x0e,0x53,0xda,0x17,0x23, + 0x8d,0x36,0xd1,0x49,0x18,0x49,0xae,0x4a, + 0x1a,0x43,0xa2,0x76,0x32,0xcb,0x51,0x44, + 0x18,0x67,0xae,0xae,0x18,0x1b,0xaf,0xa6, + 0x1e,0x2b,0xbb,0x06,0x65,0xea,0xa3,0x80, + 0x36,0xff,0x49,0xfc,0x4b,0xf6,0x47,0xca, + 0x6f,0x42,0x9c,0x70,0xb6,0xdc,0x49,0x36, + 0x49,0x4a,0x48,0x42,0x4e,0x72,0x5a,0xd2, + 0x21,0x13,0x39,0x95,0x6a,0x80,0x80,0xfc, + 0xfd,0xf5,0xf3,0xc3,0xd7,0x77,0x0c,0xcd, + 0xd5,0x53,0x00,0x15,0xff,0x83,0xfe,0xf7, + 0xf9,0xcf,0xeb,0x5f,0x84,0x3e,0xe7,0x79, + 0xac,0xea,0x15,0x83,0x82,0xf6,0xf1,0xc9, + 0xdb,0x4b,0x24,0x45,0x26,0x61,0x2a,0xb9, + 0x00,0x69,0xfe,0x8b,0xf8,0xc7,0xed,0x6f, + 0x90,0x9e,0x9c,0xb8,0xb4,0x6c,0x46,0x96, + 0x68,0x8a,0x8c,0xc0,0xd5,0x7d,0x00,0xf1, + 0xfd,0xdb,0xf3,0x27,0xd5,0x2f,0x01,0x1d, + 0xf9,0xb3,0xea,0x57,0x82,0x0e,0xf3,0xd9, + 0xd7,0x2b,0x0d,0x05,0xd1,0xe3,0x1b,0xb5, + 0xa6,0x42,0x2a,0x73,0x02,0xd5,0xf1,0x03, + 0xd9,0xf7,0x2b,0xcd,0x07,0x51,0xec,0x1b, + 0x97,0xa6,0x8e,0x28,0xdb,0x0d,0x25,0xd1, + 0x23,0x19,0x35,0xa9,0x42,0x08,0x73,0xce, + 0xd7,0x59,0x0c,0x29,0xd7,0x0b,0x0d,0xc5, + 0xd3,0x63,0x14,0xb5,0x84,0x42,0xe6,0x71, + 0xaa,0xda,0x01,0x23,0xf9,0x37,0xe9,0x4f, + 0x88,0x5e,0xce,0x39,0x5b,0x68,0x24,0x8f, + 0x24,0xdd,0x25,0x31,0x21,0x59,0x38,0x29, + 0x6f,0x08,0x9d,0xcc,0xb3,0x54,0x54,0x06, + 0x07,0xeb,0xef,0x87,0x9e,0xee,0xb9,0x98, + 0x6a,0xae,0x80,0x18,0xff,0xad,0xfe,0x13, + 0xfb,0x97,0xe6,0x8f,0xa8,0xde,0x0d,0x3b, + 0xd1,0x67,0x18,0xad,0xac,0x12,0x17,0x93, + 0x8e,0x96,0xd8,0x89,0x2c,0xc9,0x15,0x49, + 0x80,0x4a,0xfe,0x41,0xfa,0x7b,0xe2,0xe7, + 0xb1,0xae,0x5a,0x1a,0x23,0xa3,0x36,0x35, + 0x4b,0x40,0x44,0x7e,0x66,0xfa,0xa9,0xe0, + 0x0b,0xbf,0xc6,0x7f,0x6a,0xfc,0x81,0xf4, + 0xfb,0xc5,0xe7,0x63,0xac,0xb6,0x14,0x4b, + 0x86,0x46,0xea,0x69,0x82,0x8a,0xf0,0xc1, + 0xdd,0x7b,0x30,0xe5,0x5d,0xa0,0x32,0x3f, + 0x53,0x7c,0x14,0xf7,0x85,0xce,0xe3,0x59, + 0xb4,0x2a,0x47,0x02,0x6d,0xf2,0x93,0xd0, + 0x97,0x1c,0x8d,0xb4,0xd2,0x45,0x12,0x61, + 0x92,0xba,0x90,0x60,0x9e,0xbc,0xb8,0x74, + 0x6e,0xc6,0x99,0x68,0xa8,0x8c,0x0c,0xd7, + 0xd5,0x0f,0x01,0xdd,0xfb,0x33,0xe5,0x57, + 0xa0,0x0e,0x3f,0xdb,0x7f,0x24,0xfd,0x25, + 0xf1,0x23,0xd9,0x37,0x29,0x4d,0x08,0x51, + 0xce,0x1b,0x5b,0xa4,0x26,0x27,0x2b,0x2d, + 0x05,0x11,0xe1,0x9b,0xba,0xa6,0x60,0x2a, + 0xbf,0x00,0x7d,0xfe,0xf3,0xf9,0xd7,0xeb, + 0x0f,0x85,0xde,0xe3,0x39,0xb5,0x6a,0x40, + 0x82,0x7c,0xf2,0xf5,0xd1,0xc3,0x1b,0x75, + 0xa4,0xc2,0x25,0x73,0x20,0xd5,0x3d,0x01, + 0x71,0xf8,0xdb,0xed,0x27,0x91,0x2e,0x99, + 0x18,0xa9,0xac,0x0a,0x17,0xc3,0x8f,0x76, + 0xdc,0xc9,0x35,0x49,0x40,0x48,0x7e,0x4e, + 0xfa,0x59,0xe2,0x2b,0xb3,0x06,0x55,0xe2, + 0x03,0x83,0xf6,0xf7,0xc9,0xcf,0x4b,0x5c, + 0x04,0x3e,0x67,0x4e,0xac,0x60,0x17,0x7f, + 0x80,0xfe,0xc1,0xf9,0x7b,0xe8,0xe7,0x87, + 0xae,0xc2,0x19,0x93,0xfc,0x96,0x08,0x8f, + 0xc0,0xe7,0xfc,0x2c,0xf0,0x1d,0xcc,0xc3, + 0x9e,0x70,0x00,0xc0,0x63,0x7f,0x54,0x78, + 0x40,0xfe,0x61,0x9b,0xf3,0x40,0x64,0x3f, + 0x0f,0xf8,0x2c,0xf3,0x3f,0x99,0x83,0x2a, + 0x79,0x07,0xcb,0xe1,0x9f,0xcc,0xce,0x60, + 0x6c,0x00,0x84,0x7c,0x0f,0xf5,0xe8,0xcf, + 0x15,0x66,0x80,0xb0,0xf8,0x5d,0xf4,0x33, + 0x8a,0x57,0x44,0x0c,0x67,0xd6,0xaf,0x08, + 0x1f,0xcf,0xb3,0x5e,0x54,0x3a,0x07,0x63, + 0xec,0xb7,0x94,0x4e,0x86,0x58,0xea,0x2d, + 0x83,0x12,0xf5,0x91,0xc2,0x9b,0x70,0xa4, + 0xdc,0x25,0x37,0x21,0x4d,0x38,0x51,0x6e, + 0x18,0x9b,0xac,0xa6,0x14,0x2b,0x87,0x06, + 0xed,0xe9,0x93,0x8a,0x96,0xc0,0x89,0x7c, + 0xc8,0xf5,0x4d,0xc0,0x53,0x7e,0x14,0xfb, + 0x85,0xe6,0xe3,0xa9,0xb6,0x0a,0x4b,0xc2, + 0x47,0x72,0x6c,0xd2,0x95,0x10,0x81,0x9c, + 0xfa,0xb5,0xe0,0x43,0xbe,0x76,0x7a,0xca, + 0xe1,0x41,0xb8,0x7a,0x6e,0xe2,0x99,0xb0, + 0xaa,0x5c,0x02,0x37,0xf3,0x4f,0xd4,0x5f, + 0x06,0x3d,0xeb,0x73,0x84,0xd6,0xe5,0x09, + 0xa1,0xca,0x3b,0x43,0x64,0x74,0xa6,0xc4, + 0x29,0x67,0x08,0xad,0xcc,0x13,0x57,0x94, + 0x0e,0x87,0xd8,0xef,0x2d,0x9d,0x12,0xb1, + 0x90,0x5a,0x9e,0x20,0xbb,0x3c,0x65,0x76, + 0xa0,0xc8,0x3d,0x4f,0x70,0x5c,0xde,0x35, + 0x3b,0x41,0x64,0x78,0xa6,0xec,0x29,0x97, + 0x0a,0x8d,0xc0,0xd3,0x7d,0x14,0xf1,0x85, + 0xda,0xe3,0x21,0xb5,0x3a,0x41,0x62,0x78, + 0xb2,0xec,0x51,0x96,0x1a,0x8b,0xa0,0xc6, + 0x3d,0x6b,0x70,0x84,0xdc,0xe5,0x35,0xa1, + 0x42,0x38,0x73,0x6e,0xd4,0x99,0x04,0xa9, + 0xe4,0x0b,0xa7,0xc6,0x2f,0x6b,0x1c,0x85, + 0xb4,0xe2,0x45,0xb2,0x62,0x52,0xb2,0x10, + 0x53,0x9e,0x16,0xbb,0x88,0x66,0xce,0xa9, + 0x58,0x08,0x2f,0xcf,0x1f,0x5d,0xbc,0x32, + 0x77,0x52,0xcc,0x11,0x57,0x98,0x0e,0xaf, + 0xd8,0x1f,0x2f,0xbd,0x1e,0x71,0xba,0xda, + 0x61,0x22,0xb9,0x30,0x69,0x5e,0x88,0x38, + 0xcf,0x6d,0x5c,0x90,0x34,0x9f,0x44,0xbc, + 0x64,0x76,0xa6,0xc8,0x29,0x4f,0x08,0x5d, + 0xce,0x33,0x5b,0x54,0x24,0x07,0x27,0xed, + 0x2f,0x91,0x1e,0x99,0xb8,0xaa,0x6c,0x02, + 0x97,0xf0,0x8f,0xdc,0xdf,0x35,0x3d,0x41, + 0x70,0x78,0xde,0xed,0x39,0x91,0x6a,0x98, + 0x80,0xac,0xfc,0x15,0xf7,0x83,0xce,0xf7, + 0x59,0xcc,0x2b,0x57,0x04,0x0d,0xe7,0xd3, + 0xaf,0x16,0x1d,0x8b,0xb2,0xc6,0x51,0x6a, + 0x18,0x83,0xac,0xf6,0x15,0xcb,0x83,0x46, + 0xf4,0x69,0xc6,0x8b,0x68,0xc4,0x8d,0x64, + 0xd0,0xa5,0x1c,0x21,0xb7,0x3a,0x4d,0x62, + 0x50,0xb2,0x1c,0x53,0xb6,0x16,0x4b,0x8a, + 0x46,0xc2,0x69,0x72,0x88,0xd0,0xcd,0x1d, + 0x51,0xb0,0x1a,0x5f,0xa2,0x3e,0x33,0x7b, + 0x54,0xe4,0x05,0xa7,0xe2,0x2f,0xb3,0x1e, + 0x55,0xba,0x02,0x63,0xf2,0xb7,0xd0,0x4f, + 0x1e,0x5d,0xba,0x32,0x63,0x52,0xb4,0x10, + 0x47,0x9e,0x6e,0xba,0x98,0x60,0xae,0xbc, + 0x18,0x77,0xae,0xce,0x19,0x5b,0xa8,0x26, + 0x0f,0x2b,0xdd,0x07,0x31,0xed,0x5b,0x90, + 0x26,0x9f,0x28,0xbd,0x0c,0x71,0xd6,0xdb, + 0x09,0x25,0xc9,0x23,0x49,0x34,0x49,0x46, + 0x48,0x6a,0x4e,0x82,0x58,0xf2,0x2d,0xd3, + 0x13,0x15,0x95,0x82,0x82,0xf0,0xf1,0xdd, + 0xdb,0x33,0x25,0x55,0x20,0x01,0x3f,0xf9, + 0x7f,0xe8,0xff,0x8d,0xfe,0xd3,0xf9,0x17, + 0xe9,0x8f,0x8a,0xde,0xc1,0x39,0x79,0x68, + 0xe8,0x8d,0x8c,0xd2,0xd5,0x11,0x01,0x99, + 0xfa,0xab,0xe0,0x07,0xbf,0xee,0x7f,0x9a, + 0xfe,0xa1,0xf8,0x3b,0xef,0x67,0x9c,0xae, + 0xb4,0x18,0x47,0xae,0x6e,0x1a,0x9b,0xa0, + 0xa6,0x3c,0x2b,0x77,0x04,0xcd,0xe5,0x53, + 0xa0,0x16,0x3f,0x8b,0x7e,0xc4,0xf9,0x65, + 0xe8,0xa3,0x8c,0x36,0xd7,0x49,0x0c,0x49, + 0xd6,0x4b,0x0a,0x45,0xc2,0x63,0x72,0xb4, + 0xd0,0x45,0x1e,0x61,0xba,0xba,0x60,0x62, + 0xbe,0xb0,0x78,0x5e,0xee,0x39,0x9b,0x6a, + 0xa4,0x80,0x24,0xff,0x25,0xfd,0x23,0xf1, + 0x37,0xd9,0x4f,0x28,0x5d,0x0e,0x31,0xdb, + 0x5b,0x24,0x25,0x27,0x21,0x2d,0x39,0x11, + 0x69,0x98,0x8a,0xac,0xc0,0x15,0x7f,0x80, + 0xfe,0xfd,0xf9,0xf3,0xeb,0xd7,0x87,0x0e, + 0xed,0xd9,0x93,0x2a,0x95,0x00,0x81,0xfc, + 0xfb,0xf5,0xe7,0xc3,0xaf,0x76,0x1c,0xcb, + 0xb5,0x46,0x40,0x6a,0x7e,0x82,0xf8,0xf1, + 0xed,0xdb,0x93,0x26,0x95,0x28,0x81,0x0c, + 0xf9,0xd5,0xeb,0x03,0x85,0xf6,0xe3,0xc9, + 0xb7,0x4a,0x4c,0x42,0x56,0x72,0x0a,0xd3, + 0xc1,0x17,0x79,0x8c,0xea,0xd5,0x81,0x02, + 0xf9,0xf1,0xeb,0xdb,0x87,0x26,0xed,0x29, + 0x91,0x0a,0x99,0xc0,0xab,0x7c,0x04,0xf7, + 0xe5,0xcf,0xa3,0x5e,0x34,0x3b,0x47,0x64, + 0x6c,0xa6,0x94,0x28,0x87,0x0c,0xed,0xd5, + 0x93,0x02,0x95,0xf0,0x83,0xdc,0xf7,0x35, + 0xcd,0x43,0x50,0x74,0x1e,0xc7,0xb9,0x6e, + 0x68,0x9a,0x8c,0xa0,0xd4,0x3d,0x07,0x71, + 0xec,0xdb,0x95,0x26,0x81,0x28,0xf9,0x0d, + 0xe9,0xd3,0x8b,0x16,0xc5,0x89,0x62,0xc8, + 0xb1,0x4c,0x58,0x56,0x2e,0x0b,0x1b,0xc5, + 0xa7,0x62,0x2c,0xb3,0x14,0x55,0x86,0x02, + 0xeb,0xf1,0x87,0xda,0xef,0x21,0x9d,0x3a, + 0xb1,0x60,0x58,0xbe,0x2c,0x7b,0x16,0xe5, + 0x89,0xa2,0xca,0x31,0x43,0x58,0x74,0x2e, + 0xc7,0x19,0x6d,0xa8,0x92,0x0c,0x93,0xd4, + 0x97,0x04,0x8d,0xe4,0xd3,0xa5,0x16,0x21, + 0x8b,0x3a,0xc5,0x61,0x60,0xb8,0xbc,0x6c, + 0x76,0x96,0xc8,0x89,0x4c,0xc8,0x55,0x4e, + 0x00,0x5b,0xfe,0x27,0xfb,0x2f,0xe5,0x1f, + 0xa1,0xbe,0x3a,0x7b,0x62,0xe4,0xb1,0xa4, + 0x5a,0x26,0x23,0x2b,0x35,0x05,0x41,0xe0, + 0x7b,0xbe,0xe6,0x79,0xaa,0xea,0x01,0x83, + 0xfa,0xf7,0xe1,0xcf,0xbb,0x5e,0x64,0x3a, + 0xa7,0x60,0x2c,0xbf,0x14,0x7d,0x86,0xf2, + 0xe9,0xd1,0x8b,0x1a,0xc5,0xa1,0x62,0x38, + 0xb3,0x6c,0x54,0x96,0x04,0x8b,0xe4,0xc7, + 0xa5,0x6e,0x20,0x9b,0x3c,0xa5,0x74,0x20, + 0xc7,0x3d,0x6d,0x70,0x90,0xdc,0x9d,0x34, + 0xb1,0x44,0x58,0x66,0x2e,0xab,0x18,0x05, + 0xaf,0xe2,0x1f,0xb3,0xbe,0x56,0x7a,0x0a, + 0xe3,0xc1,0xb7,0x7a,0x4c,0xe2,0x55,0xb2, + 0x02,0x53,0xf2,0x17,0xd3,0x8f,0x16,0xdd, + 0x89,0x32,0xc9,0x51,0x48,0x18,0x4f,0xae, + 0x5e,0x1a,0x3b,0xa3,0x66,0x34,0xab,0x44, + 0x04,0x67,0xe6,0xaf,0xa8,0x1e,0x0f,0xbb, + 0xde,0x67,0x3a,0xad,0x60,0x10,0xbf,0x9c, + 0x7e,0xb6,0xf8,0x49,0xee,0x4b,0x9a,0x46, + 0xa2,0x68,0x32,0x8f,0x50,0xdc,0x1d,0x37, + 0xb1,0x4e,0x58,0x5a,0x2e,0x23,0x1b,0x35, + 0xa5,0x42,0x20,0x73,0x3e,0xd5,0x79,0x00, + 0xe9,0xfd,0x8b,0xf2,0xc7,0xd1,0x6f,0x18, + 0x9d,0xac,0xb2,0x14,0x53,0x86,0x16,0xeb, + 0x89,0x86,0xca,0xe9,0x41,0x88,0x7a,0xce, + 0xe1,0x59,0xb8,0x2a,0x6f,0x02,0x9d,0xf0, + 0xb3,0xdc,0x57,0x36,0x0d,0x4b,0xd0,0x47, + 0x1e,0x6d,0xba,0x92,0x60,0x92,0xbc,0x90, + 0x74,0x9e,0xc4,0xb9,0x64,0x68,0xa6,0x8c, + 0x28,0xd7,0x0d,0x0d,0xd1,0xd3,0x1b,0x15, + 0xa5,0x82,0x22,0xf3,0x31,0xd5,0x5b,0x00, + 0x25,0xff,0x23,0xfd,0x37,0xf1,0x4f,0xd8, + 0x5f,0x2e,0x3d,0x1b,0x71,0xa4,0xda,0x25, + 0x23,0x21,0x35,0x39,0x41,0x68,0x78,0x8e, + 0xec,0xd9,0x95,0x2a,0x81,0x00,0xf9,0xfd, + 0xeb,0xf3,0x87,0xd6,0xef,0x09,0x9d,0xca, + 0xb3,0x40,0x54,0x7e,0x06,0xfb,0xe9,0xe7, + 0x8b,0xae,0xc6,0x19,0x6b,0xa8,0x86,0x0c, + 0xeb,0xd5,0x87,0x02,0xed,0xf1,0x93,0xda, + 0x97,0x20,0x8d,0x3c,0xd1,0x75,0x18,0xc1, + 0xad,0x7a,0x10,0xe3,0x9d,0xb6,0xb2,0x48, + 0x52,0x4e,0x12,0x5b,0x92,0x26,0x93,0x28, + 0x95,0x0c,0x81,0xd4,0xfb,0x05,0xe5,0xe3, + 0xa3,0xb6,0x36,0x4b,0x4a,0x44,0x42,0x66, + 0x72,0xaa,0xd0,0x01,0x1f,0xf9,0xbf,0xea, + 0x7f,0x82,0xfe,0xf1,0xf9,0xdb,0xeb,0x27, + 0x85,0x2e,0xe1,0x19,0xb9,0xaa,0x6a,0x02, + 0x83,0xf0,0xf7,0xdd,0xcf,0x33,0x5d,0x54, + 0x30,0x07,0x5f,0xec,0x3f,0x97,0x7e,0x8c, + 0xf8,0xd5,0xed,0x03,0x91,0xf6,0x9b,0xc8, + 0xa7,0x4c,0x2c,0x57,0x16,0x0d,0x8b,0xd2, + 0xc7,0x11,0x6d,0x98,0x92,0xac,0x90,0x14, + 0x9f,0x84,0xbe,0xe4,0x79,0xa6,0xea,0x29, + 0x83,0x0a,0xf5,0xc1,0xc3,0x7b,0x74,0xe4, + 0xc5,0xa5,0x62,0x20,0xb3,0x3c,0x55,0x76, + 0x00,0xcb,0xfd,0x47,0xf0,0x6f,0xde,0x9f, + 0x38,0xbd,0x6c,0x70,0x96,0xdc,0x89,0x34, + 0xc9,0x45,0x48,0x60,0x4e,0xbe,0x58,0x7a, + 0x2e,0xe3,0x19,0xb5,0xaa,0x42,0x02,0x73, + 0xf2,0xd7,0xd1,0x0f,0x19,0xdd,0xab,0x32, + 0x05,0x53,0xe0,0x17,0xbf,0x8e,0x7e,0xda, + 0xf9,0x21,0xe9,0x3b,0x89,0x66,0xc8,0xa9, + 0x4c,0x08,0x57,0xce,0x0f,0x5b,0xdc,0x27, + 0x37,0x2d,0x4d,0x10,0x51,0x9e,0x1a,0xbb, + 0xa0,0x66,0x3e,0xab,0x78,0x04,0xef,0xe5, + 0x9f,0xa2,0xbe,0x30,0x7b,0x5e,0xe4,0x39, + 0xa7,0x6a,0x2c,0x83,0x14,0xf5,0x85,0xc2, + 0xe3,0x71,0xb4,0xda,0x45,0x22,0x61,0x32, + 0xb9,0x50,0x68,0x1e,0x8f,0xb8,0xde,0x6d, + 0x3a,0x91,0x60,0x98,0xbc,0xac,0x74,0x16, + 0xc7,0x89,0x6e,0xc8,0x99,0x4c,0xa8,0x54, + 0x0e,0x07,0xdb,0xef,0x27,0x9d,0x2e,0xb1, + 0x18,0x59,0xae,0x2a,0x1b,0x03,0xa5,0xf6, + 0x23,0xcb,0x37,0x45,0x4c,0x60,0x56,0xbe, + 0x08,0x7b,0xce,0xe7,0x59,0xac,0x2a,0x17, + 0x03,0x8d,0xf6,0xd3,0xc9,0x17,0x49,0x8c, + 0x4a,0xd6,0x41,0x0a,0x79,0xc2,0xeb,0x71, + 0x84,0xda,0xe5,0x21,0xa1,0x3a,0x39,0x63, + 0x68,0xb4,0x8c,0x44,0xd6,0x65,0x0a,0xa1, + 0xc0,0x3b,0x7f,0x64,0xfc,0xa5,0xf4,0x23, + 0xc7,0x37,0x6d,0x4c,0x90,0x54,0x9e,0x04, + 0xbb,0xe4,0x67,0xa6,0xae,0x28,0x1b,0x0f, + 0xa5,0xde,0x23,0x3b,0x35,0x65,0x40,0xa0, + 0x7c,0x3e,0xf7,0x79,0xcc,0xeb,0x55,0x84, + 0x02,0xe7,0xf1,0xaf,0xda,0x1f,0x23,0xbd, + 0x36,0x71,0x4a,0xd8,0x41,0x2e,0x79,0x1a, + 0xe9,0xa1,0x8a,0x3a,0xc3,0x61,0x74,0xb8, + 0xc4,0x6d,0x66,0x90,0xa8,0x9c,0x0c,0xb7, + 0xd4,0x4f,0x06,0x5d,0xea,0x33,0x83,0x56, + 0xf4,0x09,0xc7,0xcb,0x6f,0x44,0x9c,0x64, + 0xb6,0xa4,0x48,0x26,0x4f,0x2a,0x5d,0x02, + 0x31,0xf3,0x5b,0xd4,0x27,0x07,0x2d,0xed, + 0x13,0x91,0x96,0x9a,0x88,0xa0,0xcc,0x3d, + 0x57,0x70,0x0c,0xdf,0xd5,0x3f,0x01,0x7d, + 0xf8,0xf3,0xed,0xd7,0x93,0x0e,0x95,0xd8, + 0x83,0x2c,0xf5,0x15,0xc1,0x83,0x7a,0xf4, + 0xe1,0xc5,0xbb,0x62,0x64,0xb2,0xa4,0x50, + 0x26,0x1f,0x2b,0xbd,0x06,0x71,0xea,0xdb, + 0x81,0x26,0xf9,0x29,0xe9,0x0b,0x89,0xc6, + 0xcb,0x69,0x44,0x88,0x64,0xce,0xa5,0x58, + 0x20,0x2f,0x3f,0x1d,0x7d,0xb0,0xf2,0x5d, + 0xd2,0x33,0x13,0x55,0x94,0x02,0x87,0xf0, + 0xef,0xdd,0x9f,0x32,0xbd,0x50,0x70,0x1e, + 0xdf,0xb9,0x3e,0x69,0x7a,0x88,0xe0,0xcd, + 0xbd,0x52,0x70,0x12,0xdf,0x91,0x3e,0x99, + 0x78,0xa8,0xec,0x0d,0x97,0xd2,0x8f,0x10, + 0xdd,0x9d,0x32,0xb1,0x50,0x58,0x1e,0x2f, + 0xbb,0x1e,0x65,0xba,0xa2,0x60,0x32,0xbf, + 0x50,0x7c,0x1e,0xf7,0xb9,0xce,0x6b,0x5a, + 0x84,0x20,0xe7,0x3d,0xad,0x72,0x10,0xd3, + 0x9d,0x16,0xb1,0x88,0x5a,0xce,0x21,0x5b, + 0x38,0x25,0x6f,0x20,0x9d,0x3c,0xb1,0x74, + 0x58,0xc6,0x2d,0x6b,0x10,0x85,0x9c,0xe2, + 0xb5,0xb0,0x42,0x5e,0x72,0x3a,0xd3,0x61, + 0x14,0xb9,0x84,0x6a,0xe6,0x81,0xa8,0xfa, + 0x0d,0xe3,0xd3,0xb7,0x16,0x4d,0x8a,0x52, + 0xc2,0x11,0x73,0x98,0xd6,0xad,0x08,0x11, + 0xcf,0x9b,0x5e,0xa4,0x38,0x27,0x6f,0x2c, + 0x9d,0x14,0xb1,0x84,0x5a,0xe6,0x21,0xab, + 0x3a,0x05,0x63,0xe0,0xb7,0xbc,0x4e,0x76, + 0x5a,0xca,0x21,0x43,0x38,0x75,0x6e,0xc0, + 0x99,0x7c,0xa8,0xf4,0x0d,0xc7,0xd3,0x6f, + 0x14,0x9d,0x84,0xb2,0xe4,0x51,0xa6,0x1a, + 0x2b,0xa3,0x06,0x35,0xeb,0x43,0x84,0x76, + 0xe6,0xc9,0xa9,0x4a,0x08,0x43,0xce,0x77, + 0x5a,0xcc,0x21,0x57,0x38,0x0d,0x6f,0xd0, + 0x9f,0x1c,0xbd,0xb4,0x72,0x46,0xd2,0x69, + 0x12,0x89,0x90,0xca,0x9d,0x40,0xb0,0x7c, + 0x5e,0xf6,0x39,0xcb,0x6b,0x44,0x84,0x64, + 0xe6,0xa5,0xa8,0x22,0x0f,0x33,0xdd,0x57, + 0x30,0x0d,0x5f,0xd0,0x3f,0x1f,0x7d,0xbc, + 0xf2,0x75,0xd2,0xc3,0x11,0x75,0x98,0xc2, + 0xad,0x70,0x10,0xdf,0x9d,0x3e,0xb1,0x78, + 0x58,0xee,0x2d,0x9b,0x12,0xa5,0x90,0x22, + 0x9f,0x30,0xbd,0x5c,0x70,0x36,0xdf,0x49, + 0x3c,0x49,0x76,0x48,0xca,0x4d,0x42,0x50, + 0x72,0x1e,0xd3,0xb9,0x16,0x69,0x8a,0x8a, + 0xc0,0xc1,0x7d,0x78,0xf0,0xed,0xdd,0x93, + 0x32,0x95,0x50,0x80,0x1c,0xff,0xb5,0xfe, + 0x43,0xfa,0x77,0xe2,0xcf,0xb1,0x5e,0x58, + 0x3a,0x2f,0x63,0x1c,0xb5,0xb4,0x42,0x46, + 0x72,0x6a,0xd2,0x81,0x10,0xf9,0x9d,0xea, + 0xb3,0x80,0x56,0xfe,0x09,0xfb,0xcb,0xe7, + 0x47,0xac,0x6e,0x16,0x9b,0x88,0xa6,0xcc, + 0x29,0x57,0x08,0x0d,0xcf,0xd3,0x5f,0x14, + 0x3d,0x87,0x72,0xec,0xd1,0x95,0x1a,0x81, + 0xa0,0xfa,0x3d,0xe3,0x73,0xb4,0xd6,0x45, + 0x0a,0x61,0xc2,0xbb,0x70,0x64,0xde,0xa5, + 0x38,0x21,0x6f,0x38,0x9d,0x6c,0xb0,0x94, + 0x5c,0x86,0x3e,0xeb,0x45,0x84,0x62,0xe6, + 0xb1,0xa8,0x5a,0x0e,0x23,0xfb,0x33,0x25, + 0x47,0x20,0x51,0x3e,0x19,0x7f,0xa8,0x66, + 0x0c,0xfb,0xd0,0x07,0x13,0xe5,0x9f,0x83, + 0xce,0x98,0x58,0xcd,0x2e,0x19,0x14,0x39, + 0x86,0x3f,0xff,0x01,0x85,0xff,0xe1,0xe1, + 0xb3,0xfc,0x46,0x63,0x0f,0xf8,0x00,0x53, + 0xbe,0x1f,0xfb,0xc0,0xe6,0x7e,0xbc,0xf0, + 0x01,0xe3,0xc3,0x9f,0xa6,0xcc,0x48,0x7e, + 0x40,0x82,0x9d,0xf2,0xff,0xd6,0x07,0x13, + 0xf5,0x87,0x80,0x0f,0x71,0x9c,0xfd,0x35, + 0x61,0x43,0xf8,0x78,0x7e,0xcf,0x19,0x99, + 0xa8,0x32,0x00,0x53,0xfc,0x17,0xfb,0x8f, + 0xc6,0xdf,0xa9,0x3e,0x09,0x7b,0xc8,0xe7, + 0x4d,0xac,0x52,0x16,0x13,0x8b,0x96,0xc6, + 0x89,0x68,0xc8,0x8d,0x4c,0xd0,0x55,0x1e, + 0x01,0xbb,0xfa,0x67,0xe2,0xaf,0xb0,0x1e, + 0x5f,0xba,0x3e,0x63,0x7a,0xb4,0xe0,0x45, + 0xbe,0x62,0x7a,0xb2,0xe0,0x51,0xbe,0x1a, + 0x7b,0xa2,0xe6,0x31,0xab,0x5a,0x04,0x23, + 0xe7,0x37,0xad,0x4e,0x10,0x5b,0x9e,0x26, + 0xbb,0x28,0x65,0x0e,0xa1,0xd8,0x3b,0x2f, + 0x65,0x1c,0xa1,0xb4,0x3a,0x47,0x62,0x6c, + 0xb2,0x94,0x50,0x86,0x1c,0xeb,0xb5,0x86, + 0x42,0xea,0x71,0x82,0xda,0xf1,0x21,0xd9, + 0x3b,0x29,0x65,0x08,0xa1,0xcc,0x3b,0x57, + 0x64,0x0c,0xa7,0xd4,0x2f,0x07,0x1d,0xed, + 0xb3,0x92,0x56,0x92,0x08,0x93,0xcc,0x97, + 0x54,0x8c,0x04,0xd7,0xe5,0x0f,0xa1,0xde, + 0x3b,0x3b,0x65,0x64,0xa0,0xa4,0x3c,0x27, + 0x77,0x2c,0xcd,0x15,0x51,0x80,0x1a,0xff, + 0xa1,0xfe,0x3b,0xfb,0x67,0xe4,0xaf,0xa4, + 0x1e,0x27,0xbb,0x2e,0x65,0x1a,0xa1,0xa0, + 0x3a,0x3f,0x63,0x7c,0xb4,0xf4,0x45,0xc6, + 0x63,0x6a,0xb4,0x80,0x44,0xfe,0x65,0xfa, + 0xa3,0xe0,0x37,0xbf,0x4e,0x7c,0x5a,0xf6, + 0x21,0xcb,0x3b,0x45,0x64,0x60,0xa6,0xbc, + 0x28,0x77,0x0e,0xcd,0xd9,0x53,0x28,0x15, + 0x0f,0x81,0xde,0xfb,0x39,0xe5,0x6b,0xa0, + 0x86,0x3c,0xeb,0x75,0x84,0xc2,0xe5,0x71, + 0xa0,0xda,0x3d,0x23,0x71,0x34,0xd9,0x45, + 0x28,0x61,0x0e,0xb9,0xd8,0x6b,0x2e,0x85, + 0x18,0xe1,0xad,0xba,0x12,0x63,0x92,0xb6, + 0x90,0x48,0x9e,0x4c,0xba,0x54,0x62,0x06, + 0xb3,0xe8,0x57,0x8e,0x0e,0xdb,0xd9,0x27, + 0x29,0x2d,0x09,0x11,0xc9,0x9b,0x4a,0xa4, + 0x40,0x26,0x7f,0x2a,0xfd,0x01,0xf1,0xfb, + 0xdb,0xe7,0x27,0xad,0x2e,0x11,0x1b,0x99, + 0xa6,0xaa,0x28,0x03,0x0f,0xf5,0xdf,0xc3, + 0x3f,0x75,0x7c,0xc0,0xf5,0x7d,0xc0,0xf3, + 0x7d,0xd4,0xf3,0x05,0xd5,0xe3,0x03,0xb5, + 0xf6,0x43,0xca,0x77,0x42,0xcc,0x71,0x56, + 0xd8,0x09,0x2f,0xc9,0x1f,0x49,0xbc,0x4a, + 0x76,0x42,0xca,0x71,0x42,0xd8,0x71,0x2e, + 0xd9,0x19,0x29,0xa9,0x0a,0x09,0xc3,0xcb, + 0x77,0x44,0xcc,0x65,0x56,0xa0,0x08,0x3f, + 0xcf,0x7f,0x5c,0xfc,0x35,0xf7,0x43,0xcc, + 0x77,0x56,0xcc,0x09,0x57,0xc8,0x0f,0x4f, + 0xdc,0x5f,0x36,0x3d,0x4b,0x70,0x44,0xde, + 0x65,0x3a,0xa1,0x60,0x38,0xbf,0x6c,0x7c, + 0x96,0xf4,0x89,0xc4,0xcb,0x65,0x44,0xa0, + 0x64,0x3e,0xa7,0x78,0x2c,0xef,0x15,0x9d, + 0x82,0xb2,0xf0,0x51,0xde,0x1b,0x3b,0xa5, + 0x66,0x20,0xab,0x3c,0x05,0x77,0xe0,0xcf, + 0xbd,0x5e,0x70,0x3a,0xdf,0x61,0x3c,0xb9, + 0x74,0x68,0xc6,0x8d,0x68,0xd0,0x8d,0x1c, + 0xd1,0xb5,0x1a,0x41,0xa2,0x7a,0x32,0xe3, + 0x51,0xb4,0x1a,0x47,0xa2,0x6e,0x32,0x9b, + 0x50,0xa4,0x1c,0x27,0xb7,0x2e,0x4d,0x1a, + 0x51,0xa2,0x1a,0x33,0xa3,0x56,0x34,0x0b, + 0x47,0xc4,0x6f,0x66,0x9c,0xa8,0xb4,0x0c, + 0x47,0xd6,0x6f,0x0a,0x9d,0xc0,0xb3,0x7c, + 0x54,0xf6,0x05,0xcb,0xe3,0x47,0xb4,0x6e, + 0x46,0x9a,0x68,0xa2,0x8c,0x30,0xd7,0x5d, + 0x0c,0x31,0xd7,0x5b,0x0c,0x25,0xd7,0x23, + 0x0d,0x35,0xd1,0x43,0x18,0x75,0xae,0xc2, + 0x19,0x73,0xa8,0xd6,0x0d,0x0b,0xd1,0xc7, + 0x1b,0x6d,0xa4,0x92,0x24,0x93,0x24,0x95, + 0x24,0x81,0x24,0xf9,0x25,0xe9,0x23,0x89, + 0x36,0xc9,0x49,0x48,0x48,0x4e,0x4e,0x5a, + 0x5a,0x22,0x23,0x33,0x35,0x55,0x40,0x00, +}; + + +#endif + diff --git a/palette.c b/palette.c new file mode 100644 index 0000000..7a335f8 --- /dev/null +++ b/palette.c @@ -0,0 +1,150 @@ + + +#include "defs.h" +#include "fb.h" + + +static byte palmap[32768]; +static byte pallock[256]; +static int palrev[256]; + +/* Course color mapping, for when palette is exhausted. */ +static byte crsmap[4][32768]; +static int crsrev[4][256]; +static const int crsmask[4] = { 0x7BDE, 0x739C, 0x6318, 0x4210 }; + +enum plstatus +{ + pl_unused = 0, + pl_linger, + pl_active, + pl_locked +}; + + +static byte bestmatch(int c) +{ + byte n, best; + int r, g, b; + int r2, g2, b2, c2; + int err, besterr; + + r = (c & 0x001F) << 3; + g = (c & 0x03E0) >> 2; + b = (c & 0x7C00) >> 7; + + best = 0; + besterr = 1024; + for (n = 1; n; n++) + { + c2 = palrev[n]; + r2 = (c2 & 0x001F) << 3; + g2 = (c2 & 0x03E0) >> 2; + b2 = (c2 & 0x7C00) >> 7; + err = abs(r-r2) + abs(b-b2) + abs(g-g2); + if (err < besterr) + { + besterr = err; + best = n; + } + } + return best; +} + +static void makecourse(int c, byte n) +{ + int i; + for (i = 0; i < 4; i++) + { + c &= crsmask[i]; + crsmap[i][c] = n; + crsrev[i][n] = c; + } +} + +static byte findcourse(int c) +{ + int i; + byte n; + for (i = 0; i < 4; i++) + { + c &= crsmask[i]; + n = crsmap[i][c]; + if (crsrev[i][n] == c) + return n; + } + return 0; +} + + +void pal_lock(byte n) +{ + if (!n) return; + if (pallock[n] >= pl_locked) + pallock[n]++; + else pallock[n] = pl_locked; +} + +byte pal_getcolor(int c, int r, int g, int b) +{ + byte n; + static byte l; + n = palmap[c]; + if (n && pallock[n] && palrev[n] == c) + { + pal_lock(n); + return n; + } + for (n = l+1; n != l; n++) + { + if (!n || pallock[n] /* || n < 16 */) continue; + pal_lock(n); + palmap[c] = n; + palrev[n] = c; + makecourse(c, n); + vid_setpal(n, r, g, b); + return (l = n); + } + n = findcourse(c); + pal_lock(n); + return n; +} + +void pal_release(byte n) +{ + if (pallock[n] >= pl_locked) + pallock[n]--; +} + + +void pal_expire() +{ + int i; + for (i = 0; i < 256; i++) + if (pallock[i] && pallock[i] < pl_locked) + pallock[i]--; +} + + +void pal_set332() +{ + int i, r, g, b; + + fb.indexed = 0; + fb.cc[0].r = 5; + fb.cc[1].r = 5; + fb.cc[2].r = 6; + fb.cc[0].l = 0; + fb.cc[1].l = 3; + fb.cc[2].l = 6; + + i = 0; + for (b = 0; b < 4; b++) for (g = 0; g < 8; g++) for (r = 0; r < 8; r++) + vid_setpal(i++, (r<<5)|(r<<2)|(r>>1), + (g<<5)|(g<<2)|(g>>1), (b<<6)|(b<<4)|(b<<2)|b); +} + + + + + diff --git a/path.c b/path.c new file mode 100644 index 0000000..13a87bd --- /dev/null +++ b/path.c @@ -0,0 +1,52 @@ + + + +#include +#include +#include + +char *strdup(); + +#ifdef ALT_PATH_SEP +#define SEP ';' +#else +#define SEP ':' +#endif + +char *path_search(char *name, char *mode, char *path) +{ + FILE *f; + static char *buf; + char *p, *n; + int l; + + if (buf) free(buf); buf = 0; + if (!path || !*path || *name == '/') + return (buf = strdup(name)); + + buf = malloc(strlen(path) + strlen(name) + 2); + + for (p = path; *p; p += l) + { + if (*p == SEP) p++; + n = strchr(p, SEP); + if (n) l = n - p; + else l = strlen(p); + strncpy(buf, p, l); + buf[l] = '/'; + strcpy(buf+l+1, name); + if ((f = fopen(buf, mode))) + { + fclose(f); + return buf; + } + } + return name; +} + + + + + + + diff --git a/pcm.h b/pcm.h new file mode 100644 index 0000000..3719933 --- /dev/null +++ b/pcm.h @@ -0,0 +1,21 @@ + +#ifndef __PCM_H__ +#define __PCM_H__ + + +#include "defs.h" + +struct pcm +{ + int hz, len; + int stereo; + byte *buf; + int pos; +}; + +extern struct pcm pcm; + + +#endif + + diff --git a/rc.h b/rc.h new file mode 100644 index 0000000..7c2be30 --- /dev/null +++ b/rc.h @@ -0,0 +1,63 @@ + + + +#ifndef __RC_H__ +#define __RC_H__ + + + +typedef enum rctype +{ + rcv_end, + rcv_int, + rcv_string, + rcv_vector, + rcv_bool +} rcvtype_t; + + +typedef struct rcvar_s +{ + char *name; + int type; + int len; + void *mem; +} rcvar_t; + +#define RCV_END { 0, rcv_end, 0, 0 } +#define RCV_INT(n,v) { (n), rcv_int, 1, (v) } +#define RCV_STRING(n,v) { (n), rcv_string, 0, (v) } +#define RCV_VECTOR(n,v,l) { (n), rcv_vector, (l), (v) } +#define RCV_BOOL(n,v) { (n), rcv_bool, 1, (v) } + +typedef struct rccmd_s +{ + char *name; + int (*func)(int, char **); +} rccmd_t; + +#define RCC(n,f) { (n), (f) } +#define RCC_END { 0, 0 } + +void rc_export(rcvar_t *v); +void rc_exportvars(rcvar_t *vars); + +int rc_findvar(char *name); + +int rc_setvar_n(int i, int c, char **v); +int rc_setvar(char *name, int c, char **v); + +int rc_getint_n(int i); +int *rc_getvec_n(int i); +char *rc_getstr_n(int i); + +int rc_getint(char *name); +int *rc_getvec(char *name); +char *rc_getstr(char *name); + + +#endif + + + + diff --git a/rccmds.c b/rccmds.c new file mode 100644 index 0000000..2ea68cf --- /dev/null +++ b/rccmds.c @@ -0,0 +1,194 @@ + + + + +#include + +#include "defs.h" +#include "rc.h" +#include "hw.h" + + + +/* + * define the command functions for the controller pad. + */ + +#define CMD_PAD(b, B) \ +static int (cmd_ ## b)(int c, char **v) \ +{ pad_set((PAD_ ## B), v[0][0] == '+'); return 0; } \ +static int (cmd_ ## b)(int c, char **v) + +CMD_PAD(up, UP); +CMD_PAD(down, DOWN); +CMD_PAD(left, LEFT); +CMD_PAD(right, RIGHT); +CMD_PAD(a, A); +CMD_PAD(b, B); +CMD_PAD(start, START); +CMD_PAD(select, SELECT); + + +/* + * the set command is used to set rc-exported variables. + */ + +static int cmd_set(int argc, char **argv) +{ + if (argc < 3) + return -1; + return rc_setvar(argv[1], argc-2, argv+2); +} + + + +/* + * the following commands allow keys to be bound to perform rc commands. + */ + +static int cmd_bind(int argc, char **argv) +{ + if (argc < 3) + return -1; + return rc_bindkey(argv[1], argv[2]); +} + +static int cmd_unbind(int argc, char **argv) +{ + if (argc < 2) + return -1; + return rc_unbindkey(argv[1]); +} + +static int cmd_unbindall() +{ + rc_unbindall(); + return 0; +} + +static int cmd_source(int argc, char **argv) +{ + if (argc < 2) + return -1; + return rc_sourcefile(argv[1]); +} + +static int cmd_quit() +{ + exit(0); + /* NOT REACHED */ +} + +static int cmd_reset() +{ + emu_reset(); + return 0; +} + +static int cmd_savestate(int argc, char **argv) +{ + state_save(argc > 1 ? atoi(argv[1]) : -1); + return 0; +} + +static int cmd_loadstate(int argc, char **argv) +{ + state_load(argc > 1 ? atoi(argv[1]) : -1); + return 0; +} + + + +/* + * table of command names and the corresponding functions to be called + */ + +rccmd_t rccmds[] = +{ + RCC("set", cmd_set), + RCC("bind", cmd_bind), + RCC("unbind", cmd_unbind), + RCC("unbindall", cmd_unbindall), + RCC("source", cmd_source), + RCC("reset", cmd_reset), + RCC("quit", cmd_quit), + RCC("savestate", cmd_savestate), + RCC("loadstate", cmd_loadstate), + + RCC("+up", cmd_up), + RCC("-up", cmd_up), + RCC("+down", cmd_down), + RCC("-down", cmd_down), + RCC("+left", cmd_left), + RCC("-left", cmd_left), + RCC("+right", cmd_right), + RCC("-right", cmd_right), + RCC("+a", cmd_a), + RCC("-a", cmd_a), + RCC("+b", cmd_b), + RCC("-b", cmd_b), + RCC("+start", cmd_start), + RCC("-start", cmd_start), + RCC("+select", cmd_select), + RCC("-select", cmd_select), + + RCC_END +}; + + + + + +int rc_command(char *line) +{ + int i, argc, ret; + char *argv[128], *linecopy; + + linecopy = malloc(strlen(line)+1); + strcpy(linecopy, line); + + argc = splitline(argv, (sizeof argv)/(sizeof argv[0]), linecopy); + if (!argc) + { + free(linecopy); + return -1; + } + + for (i = 0; rccmds[i].name; i++) + { + if (!strcmp(argv[0], rccmds[i].name)) + { + ret = rccmds[i].func(argc, argv); + free(linecopy); + return ret; + } + } + + /* printf("unknown command: %s\n", argv[0]); */ + free(linecopy); + + return -1; +} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rcfile.c b/rcfile.c new file mode 100644 index 0000000..9c7d1a3 --- /dev/null +++ b/rcfile.c @@ -0,0 +1,46 @@ + + + +#include +#include +#include + +#include "defs.h" +#include "rc.h" +#include "hw.h" + + +char *rcpath; + +char *path_search(); + +int rc_sourcefile(char *filename) +{ + FILE *f; + char *name; + char line[256], *p; + + name = path_search(filename, "r", rcpath); + f = fopen(name, "r"); + if (!f) return -1; + + for (;;) + { + if (feof(f)) break; + fgets(line, sizeof line, f); + if ((p = strpbrk(line, "#\r\n"))) + *p = 0; + rc_command(line); + } + fclose(f); + return 0; +} + + +rcvar_t rcfile_exports[] = +{ + RCV_STRING("rcpath", &rcpath), + RCV_END +}; + + diff --git a/rckeys.c b/rckeys.c new file mode 100644 index 0000000..8dc2eba --- /dev/null +++ b/rckeys.c @@ -0,0 +1,86 @@ + + + +#include +#include + +char *strdup(); + +#include "defs.h" +#include "rc.h" +#include "input.h" + + + + +char *keybind[MAX_KEYS]; + + + + +int rc_bindkey(char *keyname, char *cmd) +{ + int key; + char *a; + + key = k_keycode(keyname); + if (!key) return -1; + + a = strdup(cmd); + if (!a) die("out of memory binding key\n"); + + if (keybind[key]) free(keybind[key]); + keybind[key] = a; + + return 0; +} + + + +int rc_unbindkey(char *keyname) +{ + int key; + + key = k_keycode(keyname); + if (!key) return -1; + + if (keybind[key]) free(keybind[key]); + keybind[key] = NULL; + return 0; +} + + +void rc_unbindall() +{ + int i; + + for (i = 0; i < MAX_KEYS; i++) + { + if (keybind[i]) + { + free(keybind[i]); + keybind[i] = NULL; + } + } +} + + + +void rc_dokey(int key, int st) +{ + if (!keybind[key]) return; + if (keybind[key][0] != '+' && !st) return; + + if (st) + rc_command(keybind[key]); + else + { + keybind[key][0] = '-'; + rc_command(keybind[key]); + keybind[key][0] = '+'; + } +} + + + + diff --git a/rcvars.c b/rcvars.c new file mode 100644 index 0000000..8364e89 --- /dev/null +++ b/rcvars.c @@ -0,0 +1,235 @@ + + + + +#include +#include + +char *strdup(); + +#include "defs.h" +#include "rc.h" + + + + + + +static rcvar_t *rcvars; + +static int nvars; + + + + + +void rc_export(rcvar_t *v) +{ + const rcvar_t end = RCV_END; + + if (!v) return; + nvars++; + rcvars = realloc(rcvars, sizeof (rcvar_t) * (nvars+1)); + if (!rcvars) + die("out of memory adding rcvar %s\n", v->name); + rcvars[nvars-1] = *v; + rcvars[nvars] = end; +} + +void rc_exportvars(rcvar_t *vars) +{ + while(vars->type) + rc_export(vars++); +} + + + +int rc_findvar(char *name) +{ + int i; + if (!rcvars) return -1; + for (i = 0; rcvars[i].name; i++) + if (!strcmp(rcvars[i].name, name)) + break; + if (!rcvars[i].name) + return -1; + return i; +} + + +int my_atoi(const char *s) +{ + int a = 0; + if (*s == '0') + { + s++; + if (*s == 'x' || *s == 'X') + { + s++; + while (*s) + { + if (isdigit(*s)) + a = (a<<4) + *s - '0'; + else if (strchr("ABCDEF", *s)) + a = (a<<4) + *s - 'A' + 10; + else if (strchr("abcdef", *s)) + a = (a<<4) + *s - 'a' + 10; + else return a; + s++; + } + return a; + } + while (*s) + { + if (strchr("01234567", *s)) + a = (a<<3) + *s - '0'; + else return a; + s++; + } + return a; + } + if (*s == '-') + { + s++; + for (;;) + { + if (isdigit(*s)) + a = (a*10) + *s - '0'; + else return -a; + s++; + } + } + while (*s) + { + if (isdigit(*s)) + a = (a*10) + *s - '0'; + else return a; + s++; + } + return a; +} + + +int rc_setvar_n(int i, int c, char **v) +{ + int j; + int *n; + char **s; + + switch (rcvars[i].type) + { + case rcv_int: + if (c < 1) return -1; + n = (int *)rcvars[i].mem; + *n = my_atoi(v[0]); + return 0; + case rcv_string: + if (c < 1) return -1; + s = (char **)rcvars[i].mem; + if (*s) free(*s); + *s = strdup(v[0]); + if (!*s) + die("out of memory setting rcvar %s\n", rcvars[i].name); + return 0; + case rcv_vector: + if (c > rcvars[i].len) + c = rcvars[i].len; + for (j = 0; j < c ; j++) + ((int *)rcvars[i].mem)[j] = my_atoi(v[j]); + return 0; + case rcv_bool: + if (c < 1 || atoi(v[0]) || strchr("yYtT", v[0][0])) + *(int *)rcvars[i].mem = 1; + else if (strchr("0nNfF", v[0][0])) + *(int *)rcvars[i].mem = 0; + else + return -1; + return 0; + } + return -1; +} + + +int rc_setvar(char *name, int c, char **v) +{ + int i; + + i = rc_findvar(name); + if (i < 0) return i; + + return rc_setvar_n(i, c, v); +} + + +void *rc_getmem_n(int i) +{ + return rcvars[i].mem; +} + + +void *rc_getmem(char *name) +{ + int i; + i = rc_findvar(name); + if (i < 0) return NULL; + return rcvars[i].mem; +} + +int rc_getint_n(int i) +{ + if (i < 0) return 0; + switch (rcvars[i].type) + { + case rcv_int: + case rcv_bool: + return *(int *)rcvars[i].mem; + } + return 0; +} + +int *rc_getvec_n(int i) +{ + if (i < 0) return NULL; + switch (rcvars[i].type) + { + case rcv_int: + case rcv_bool: + case rcv_vector: + return (int *)rcvars[i].mem; + } + return NULL; +} + +char *rc_getstr_n(int i) +{ + if (i < 0) return 0; + switch (rcvars[i].type) + { + case rcv_string: + return *(char **)rcvars[i].mem; + } + return 0; +} + +int rc_getint(char *name) +{ + return rc_getint_n(rc_findvar(name)); +} + +int *rc_getvec(char *name) +{ + return rc_getvec_n(rc_findvar(name)); +} + +char *rc_getstr(char *name) +{ + return rc_getstr_n(rc_findvar(name)); +} + + + + + + + + diff --git a/refresh.c b/refresh.c new file mode 100644 index 0000000..ef932e7 --- /dev/null +++ b/refresh.c @@ -0,0 +1,177 @@ + + +#include "defs.h" +#include "lcd.h" + +#define BUF (scan.buf) + +#ifdef USE_ASM +#include "asm.h" +#endif + + +#ifndef ASM_REFRESH_1 +void refresh_1(byte *dest, byte *src, byte *pal, int cnt) +{ + while(cnt--) *(dest++) = pal[*(src++)]; +} +#endif + +#ifndef ASM_REFRESH_2 +void refresh_2(un16 *dest, byte *src, un16 *pal, int cnt) +{ + while (cnt--) *(dest++) = pal[*(src++)]; +} +#endif + +#ifndef ASM_REFRESH_3 +void refresh_3(byte *dest, byte *src, un32 *pal, int cnt) +{ + un32 c; + while (cnt--) + { + c = pal[*(src++)]; + *(dest++) = c; + *(dest++) = c>>8; + *(dest++) = c>>16; + } +} +#endif + +#ifndef ASM_REFRESH_4 +void refresh_4(un32 *dest, byte *src, un32 *pal, int cnt) +{ + while (cnt--) *(dest++) = pal[*(src++)]; +} +#endif + + + + +#ifndef ASM_REFRESH_1_2X +void refresh_1_2x(byte *dest, byte *src, byte *pal, int cnt) +{ + byte c; + while (cnt--) + { + c = pal[*(src++)]; + *(dest++) = c; + *(dest++) = c; + } +} +#endif + +#ifndef ASM_REFRESH_2_2X +void refresh_2_2x(un16 *dest, byte *src, un16 *pal, int cnt) +{ + un16 c; + while (cnt--) + { + c = pal[*(src++)]; + *(dest++) = c; + *(dest++) = c; + } +} +#endif + +#ifndef ASM_REFRESH_3_2X +void refresh_3_2x(byte *dest, byte *src, un32 *pal, int cnt) +{ + un32 c; + while (cnt--) + { + c = pal[*(src++)]; + dest[0] = dest[3] = c; + dest[1] = dest[4] = c>>8; + dest[2] = dest[5] = c>>16; + dest += 6; + } +} +#endif + +#ifndef ASM_REFRESH_4_2X +void refresh_4_2x(un32 *dest, byte *src, un32 *pal, int cnt) +{ + un32 c; + while (cnt--) + { + c = pal[*(src++)]; + *(dest++) = c; + *(dest++) = c; + } +} +#endif + +#ifndef ASM_REFRESH_2_3X +void refresh_2_3x(un16 *dest, byte *src, un16 *pal, int cnt) +{ + un16 c; + while (cnt--) + { + c = pal[*(src++)]; + *(dest++) = c; + *(dest++) = c; + *(dest++) = c; + } +} +#endif + +#ifndef ASM_REFRESH_3_3X +void refresh_3_3x(byte *dest, byte *src, un32 *pal, int cnt) +{ + un32 c; + while (cnt--) + { + c = pal[*(src++)]; + dest[0] = dest[3] = dest[6] = c; + dest[1] = dest[4] = dest[7] = c>>8; + dest[2] = dest[5] = dest[8] = c>>16; + dest += 9; + } +} +#endif + +#ifndef ASM_REFRESH_4_3X +void refresh_4_3x(un32 *dest, byte *src, un32 *pal, int cnt) +{ + un32 c; + while (cnt--) + { + c = pal[*(src++)]; + *(dest++) = c; + *(dest++) = c; + *(dest++) = c; + } +} +#endif + +#ifndef ASM_REFRESH_3_4X +void refresh_3_4x(byte *dest, byte *src, un32 *pal, int cnt) +{ + un32 c; + while (cnt--) + { + c = pal[*(src++)]; + dest[0] = dest[3] = dest[6] = dest[9] = c; + dest[1] = dest[4] = dest[7] = dest[10] = c>>8; + dest[2] = dest[5] = dest[8] = dest[11] = c>>16; + dest += 12; + } +} +#endif + +#ifndef ASM_REFRESH_4_4X +void refresh_4_4x(un32 *dest, byte *src, un32 *pal, int cnt) +{ + un32 c; + while (cnt--) + { + c = pal[*(src++)]; + *(dest++) = c; + *(dest++) = c; + *(dest++) = c; + *(dest++) = c; + } +} +#endif + diff --git a/regs.h b/regs.h new file mode 100644 index 0000000..4457fd9 --- /dev/null +++ b/regs.h @@ -0,0 +1,181 @@ + +#ifndef __REGS_H__ +#define __REGS_H__ + + +#include "mem.h" + +/* General internal/io stuff */ + +#define RI_P1 0x00 +#define RI_SB 0x01 +#define RI_SC 0x02 +#define RI_DIV 0x04 +#define RI_TIMA 0x05 +#define RI_TMA 0x06 +#define RI_TAC 0x07 + +#define RI_KEY1 0x4D + +#define RI_RP 0x56 + +#define RI_SVBK 0x70 + + + +/* Interrupts flags */ + +#define RI_IF 0x0F +#define RI_IE 0xFF + + + + +/* LCDC */ + +#define RI_LCDC 0x40 +#define RI_STAT 0x41 +#define RI_SCY 0x42 +#define RI_SCX 0x43 +#define RI_LY 0x44 +#define RI_LYC 0x45 +#define RI_DMA 0x46 +#define RI_BGP 0x47 +#define RI_OBP0 0x48 +#define RI_OBP1 0x49 +#define RI_WY 0x4A +#define RI_WX 0x4B + +#define RI_VBK 0x4F + +#define RI_HDMA1 0x51 +#define RI_HDMA2 0x52 +#define RI_HDMA3 0x53 +#define RI_HDMA4 0x54 +#define RI_HDMA5 0x55 + +#define RI_BCPS 0x68 +#define RI_BCPD 0x69 +#define RI_OCPS 0x6A +#define RI_OCPD 0x6B + + + +/* Sound */ + +#define RI_NR10 0x10 +#define RI_NR11 0x11 +#define RI_NR12 0x12 +#define RI_NR13 0x13 +#define RI_NR14 0x14 +#define RI_NR21 0x16 +#define RI_NR22 0x17 +#define RI_NR23 0x18 +#define RI_NR24 0x19 +#define RI_NR30 0x1A +#define RI_NR31 0x1B +#define RI_NR32 0x1C +#define RI_NR33 0x1D +#define RI_NR34 0x1E +#define RI_NR41 0x20 +#define RI_NR42 0x21 +#define RI_NR43 0x22 +#define RI_NR44 0x23 +#define RI_NR50 0x24 +#define RI_NR51 0x25 +#define RI_NR52 0x26 + + + +#define REG(n) ram.hi[(n)] + + + +/* General internal/io stuff */ + +#define R_P1 REG(RI_P1) +#define R_SB REG(RI_SB) +#define R_SC REG(RI_SC) +#define R_DIV REG(RI_DIV) +#define R_TIMA REG(RI_TIMA) +#define R_TMA REG(RI_TMA) +#define R_TAC REG(RI_TAC) + +#define R_KEY1 REG(RI_KEY1) + +#define R_RP REG(RI_RP) + +#define R_SVBK REG(RI_SVBK) + + + +/* Interrupts flags */ + +#define R_IF REG(RI_IF) +#define R_IE REG(RI_IE) + + + + +/* LCDC */ + +#define R_LCDC REG(RI_LCDC) +#define R_STAT REG(RI_STAT) +#define R_SCY REG(RI_SCY) +#define R_SCX REG(RI_SCX) +#define R_LY REG(RI_LY) +#define R_LYC REG(RI_LYC) +#define R_DMA REG(RI_DMA) +#define R_BGP REG(RI_BGP) +#define R_OBP0 REG(RI_OBP0) +#define R_OBP1 REG(RI_OBP1) +#define R_WY REG(RI_WY) +#define R_WX REG(RI_WX) + +#define R_VBK REG(RI_VBK) + +#define R_HDMA1 REG(RI_HDMA1) +#define R_HDMA2 REG(RI_HDMA2) +#define R_HDMA3 REG(RI_HDMA3) +#define R_HDMA4 REG(RI_HDMA4) +#define R_HDMA5 REG(RI_HDMA5) + +#define R_BCPS REG(RI_BCPS) +#define R_BCPD REG(RI_BCPD) +#define R_OCPS REG(RI_OCPS) +#define R_OCPD REG(RI_OCPD) + + + +/* Sound */ + +#define R_NR10 REG(RI_NR10) +#define R_NR11 REG(RI_NR11) +#define R_NR12 REG(RI_NR12) +#define R_NR13 REG(RI_NR13) +#define R_NR14 REG(RI_NR14) +#define R_NR21 REG(RI_NR21) +#define R_NR22 REG(RI_NR22) +#define R_NR23 REG(RI_NR23) +#define R_NR24 REG(RI_NR24) +#define R_NR30 REG(RI_NR30) +#define R_NR31 REG(RI_NR31) +#define R_NR32 REG(RI_NR32) +#define R_NR33 REG(RI_NR33) +#define R_NR34 REG(RI_NR34) +#define R_NR41 REG(RI_NR41) +#define R_NR42 REG(RI_NR42) +#define R_NR43 REG(RI_NR43) +#define R_NR44 REG(RI_NR44) +#define R_NR50 REG(RI_NR50) +#define R_NR51 REG(RI_NR51) +#define R_NR52 REG(RI_NR52) + + + +#endif + + + + + diff --git a/rtc.c b/rtc.c new file mode 100644 index 0000000..c3f96ec --- /dev/null +++ b/rtc.c @@ -0,0 +1,130 @@ + + + +#include + +#include "defs.h" +#include "mem.h" +#include "rtc.h" +#include "rc.h" + +struct rtc rtc; + +static int syncrtc = 1; + +rcvar_t rtc_exports[] = +{ + RCV_BOOL("syncrtc", &syncrtc), + RCV_END +}; + + +void rtc_latch(byte b) +{ + if ((rtc.latch ^ b) & b & 1) + { + rtc.regs[0] = rtc.s; + rtc.regs[1] = rtc.m; + rtc.regs[2] = rtc.h; + rtc.regs[3] = rtc.d; + rtc.regs[4] = (rtc.d>>9) | (rtc.stop<<6) | (rtc.carry<<7); + rtc.regs[5] = 0xff; + rtc.regs[6] = 0xff; + rtc.regs[7] = 0xff; + } + rtc.latch = b; +} + +void rtc_write(byte b) +{ + /* printf("write %02X: %02X (%d)\n", rtc.sel, b, b); */ + if (!(rtc.sel & 8)) return; + switch (rtc.sel & 7) + { + case 0: + rtc.s = rtc.regs[0] = b; + while (rtc.s >= 60) rtc.s -= 60; + break; + case 1: + rtc.m = rtc.regs[1] = b; + while (rtc.m >= 60) rtc.m -= 60; + break; + case 2: + rtc.h = rtc.regs[2] = b; + while (rtc.h >= 24) rtc.h -= 24; + break; + case 3: + rtc.regs[3] = b; + rtc.d = (rtc.d & 0x100) | b; + break; + case 4: + rtc.regs[4] = b; + rtc.d = (rtc.d & 0xff) | ((b&1)<<9); + rtc.stop = (b>>6)&1; + rtc.carry = (b>>7)&1; + break; + } +} + +void rtc_tick() +{ + if (rtc.stop) return; + if (++rtc.t == 60) + { + if (++rtc.s == 60) + { + if (++rtc.m == 60) + { + if (++rtc.h == 24) + { + if (++rtc.d == 365) + { + rtc.d = 0; + rtc.carry = 1; + } + rtc.h = 0; + } + rtc.m = 0; + } + rtc.s = 0; + } + rtc.t = 0; + } +} + +void rtc_save_internal(FILE *f) +{ + fprintf(f, "%d %d %d %02d %02d %02d %02d\n%d\n", + rtc.carry, rtc.stop, rtc.d, rtc.h, rtc.m, rtc.s, rtc.t, + time(0)); +} + +void rtc_load_internal(FILE *f) +{ + int rt = 0; + fscanf( + f, "%d %d %d %02d %02d %02d %02d\n%d\n", + &rtc.carry, &rtc.stop, &rtc.d, + &rtc.h, &rtc.m, &rtc.s, &rtc.t, &rt); + while (rtc.t >= 60) rtc.t -= 60; + while (rtc.s >= 60) rtc.s -= 60; + while (rtc.m >= 60) rtc.m -= 60; + while (rtc.h >= 24) rtc.h -= 24; + while (rtc.d >= 365) rtc.d -= 365; + rtc.stop &= 1; + rtc.carry &= 1; + if (rt) rt = (time(0) - rt) * 60; + if (syncrtc) while (rt-- > 0) rtc_tick(); +} + + + + + + + + + + + + diff --git a/rtc.h b/rtc.h new file mode 100644 index 0000000..76f5017 --- /dev/null +++ b/rtc.h @@ -0,0 +1,25 @@ + + +#ifndef __RTC_H__ +#define __RTC_H__ + + +struct rtc +{ + int batt; + int sel; + int latch; + int d, h, m, s, t; + int stop, carry; + byte regs[8]; +}; + +extern struct rtc rtc; + + + + +#endif + + + diff --git a/save.c b/save.c new file mode 100644 index 0000000..1dc7905 --- /dev/null +++ b/save.c @@ -0,0 +1,286 @@ + + +#include + +#include "defs.h" +#include "cpu.h" +#include "cpuregs.h" +#include "hw.h" +#include "regs.h" +#include "lcd.h" +#include "rtc.h" +#include "mem.h" +#include "sound.h" + + + +#ifdef IS_LITTLE_ENDIAN +#define LIL(x) (x) +#else +#define LIL(x) ((x<<24)|((x&0xff00)<<8)|((x>>8)&0xff00)|(x>>24)) +#endif + +#define I1(s, p) { 1, s, p } +#define I2(s, p) { 2, s, p } +#define I4(s, p) { 4, s, p } +#define R(r) I1(#r, &R_##r) +#define NOSAVE { -1, "\0\0\0\0", 0 } +#define END { 0, "\0\0\0\0", 0 } + +struct svar +{ + int len; + char key[4]; + void *ptr; +}; + +static int ver; +static int sramblock, iramblock, vramblock; +static int hramofs, hiofs, palofs, oamofs, wavofs; + +struct svar svars[] = +{ + I4("GbSs", &ver), + + I2("PC ", &PC), + I2("SP ", &SP), + I2("BC ", &BC), + I2("DE ", &DE), + I2("HL ", &HL), + I2("AF ", &AF), + + I4("IME ", &cpu.ime), + I4("ima ", &cpu.ima), + I4("spd ", &cpu.speed), + I4("halt", &cpu.halt), + I4("div ", &cpu.div), + I4("tim ", &cpu.tim), + I4("lcdc", &cpu.lcdc), + I4("snd ", &cpu.snd), + + I1("ints", &hw.ilines), + I1("pad ", &hw.pad), + I4("cgb ", &hw.cgb), + I4("gba ", &hw.gba), + + I4("mbcm", &mbc.model), + I4("romb", &mbc.rombank), + I4("ramb", &mbc.rambank), + I4("enab", &mbc.enableram), + I4("batt", &mbc.batt), + + I4("rtcR", &rtc.sel), + I4("rtcL", &rtc.latch), + I4("rtcC", &rtc.carry), + I4("rtcS", &rtc.stop), + I4("rtcd", &rtc.d), + I4("rtch", &rtc.h), + I4("rtcm", &rtc.m), + I4("rtcs", &rtc.s), + I4("rtct", &rtc.t), + I1("rtR8", &rtc.regs[0]), + I1("rtR9", &rtc.regs[1]), + I1("rtRA", &rtc.regs[2]), + I1("rtRB", &rtc.regs[3]), + I1("rtRC", &rtc.regs[4]), + + I4("S1on", &snd.ch[0].on), + I4("S1p ", &snd.ch[0].pos), + I4("S1c ", &snd.ch[0].cnt), + I4("S1ec", &snd.ch[0].encnt), + I4("S1sc", &snd.ch[0].swcnt), + I4("S1sf", &snd.ch[0].swfreq), + + I4("S2on", &snd.ch[1].on), + I4("S2p ", &snd.ch[1].pos), + I4("S2c ", &snd.ch[1].cnt), + I4("S2ec", &snd.ch[1].encnt), + + I4("S3on", &snd.ch[2].on), + I4("S3p ", &snd.ch[2].pos), + I4("S3c ", &snd.ch[2].cnt), + + I4("S4on", &snd.ch[3].on), + I4("S4p ", &snd.ch[3].pos), + I4("S4c ", &snd.ch[3].cnt), + I4("S4ec", &snd.ch[3].encnt), + + I4("hdma", &hw.hdma), + + I4("sram", &sramblock), + I4("iram", &iramblock), + I4("vram", &vramblock), + I4("hi ", &hiofs), + I4("pal ", &palofs), + I4("oam ", &oamofs), + I4("wav ", &wavofs), + + /* NOSAVE is a special code to prevent the rest of the table + * from being saved, used to support old stuff for backwards + * compatibility... */ + NOSAVE, + + /* the following are obsolete as of 0x104 */ + + I4("hram", &hramofs), + + R(P1), R(SB), R(SC), + R(DIV), R(TIMA), R(TMA), R(TAC), + R(IE), R(IF), + R(LCDC), R(STAT), R(LY), R(LYC), + R(SCX), R(SCY), R(WX), R(WY), + R(BGP), R(OBP0), R(OBP1), + R(DMA), + + R(VBK), R(SVBK), R(KEY1), + R(BCPS), R(BCPD), R(OCPS), R(OCPD), + + R(NR10), R(NR11), R(NR12), R(NR13), R(NR14), + R(NR21), R(NR22), R(NR23), R(NR24), + R(NR30), R(NR31), R(NR32), R(NR33), R(NR34), + R(NR41), R(NR42), R(NR43), R(NR44), + R(NR50), R(NR51), R(NR52), + + I1("DMA1", &R_HDMA1), + I1("DMA2", &R_HDMA2), + I1("DMA3", &R_HDMA3), + I1("DMA4", &R_HDMA4), + I1("DMA5", &R_HDMA5), + + END +}; + + +void loadstate(FILE *f) +{ + int i, j; + byte buf[4096]; + un32 (*header)[2] = (un32 (*)[2])buf; + un32 d; + int irl = hw.cgb ? 8 : 2; + int vrl = hw.cgb ? 4 : 2; + int srl = mbc.ramsize << 1; + + ver = hramofs = hiofs = palofs = oamofs = wavofs = 0; + + fseek(f, 0, SEEK_SET); + fread(buf, 4096, 1, f); + + for (j = 0; header[j][0]; j++) + { + for (i = 0; svars[i].ptr; i++) + { + if (header[j][0] != *(un32 *)svars[i].key) + continue; + d = LIL(header[j][1]); + switch (svars[i].len) + { + case 1: + *(byte *)svars[i].ptr = d; + break; + case 2: + *(un16 *)svars[i].ptr = d; + break; + case 4: + *(un32 *)svars[i].ptr = d; + break; + } + break; + } + } + + /* obsolete as of version 0x104 */ + if (hramofs) memcpy(ram.hi+128, buf+hramofs, 127); + + if (hiofs) memcpy(ram.hi, buf+hiofs, sizeof ram.hi); + if (palofs) memcpy(lcd.pal, buf+palofs, sizeof lcd.pal); + if (oamofs) memcpy(lcd.oam.mem, buf+oamofs, sizeof lcd.oam); + + if (wavofs) memcpy(snd.wave, buf+wavofs, sizeof snd.wave); + else memcpy(snd.wave, ram.hi+0x30, 16); /* patch data from older files */ + + fseek(f, iramblock<<12, SEEK_SET); + fread(ram.ibank, 4096, irl, f); + + fseek(f, vramblock<<12, SEEK_SET); + fread(lcd.vbank, 4096, vrl, f); + + fseek(f, sramblock<<12, SEEK_SET); + fread(ram.sbank, 4096, srl, f); +} + +void savestate(FILE *f) +{ + int i; + byte buf[4096]; + un32 (*header)[2] = (un32 (*)[2])buf; + un32 d = 0; + int irl = hw.cgb ? 8 : 2; + int vrl = hw.cgb ? 4 : 2; + int srl = mbc.ramsize << 1; + + ver = 0x105; + iramblock = 1; + vramblock = 1+irl; + sramblock = 1+irl+vrl; + wavofs = 4096 - 784; + hiofs = 4096 - 768; + palofs = 4096 - 512; + oamofs = 4096 - 256; + memset(buf, 0, sizeof buf); + + for (i = 0; svars[i].len > 0; i++) + { + header[i][0] = *(un32 *)svars[i].key; + switch (svars[i].len) + { + case 1: + d = *(byte *)svars[i].ptr; + break; + case 2: + d = *(un16 *)svars[i].ptr; + break; + case 4: + d = *(un32 *)svars[i].ptr; + break; + } + header[i][1] = LIL(d); + } + header[i][0] = header[i][1] = 0; + + memcpy(buf+hiofs, ram.hi, sizeof ram.hi); + memcpy(buf+palofs, lcd.pal, sizeof lcd.pal); + memcpy(buf+oamofs, lcd.oam.mem, sizeof lcd.oam); + memcpy(buf+wavofs, snd.wave, sizeof snd.wave); + + fseek(f, 0, SEEK_SET); + fwrite(buf, 4096, 1, f); + + fseek(f, iramblock<<12, SEEK_SET); + fwrite(ram.ibank, 4096, irl, f); + + fseek(f, vramblock<<12, SEEK_SET); + fwrite(lcd.vbank, 4096, vrl, f); + + fseek(f, sramblock<<12, SEEK_SET); + fwrite(ram.sbank, 4096, srl, f); +} + + + + + + + + + + + + + + + + + + + diff --git a/sound.c b/sound.c new file mode 100644 index 0000000..6e2545a --- /dev/null +++ b/sound.c @@ -0,0 +1,463 @@ + + + +#include "defs.h" +#include "pcm.h" +#include "sound.h" +#include "cpu.h" +#include "hw.h" +#include "regs.h" +#include "rc.h" +#include "noise.h" + + +const static byte dmgwave[16] = +{ + 0xac, 0xdd, 0xda, 0x48, + 0x36, 0x02, 0xcf, 0x16, + 0x2c, 0x04, 0xe5, 0x2c, + 0xac, 0xdd, 0xda, 0x48 +}; + +const static byte cgbwave[16] = +{ + 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, +}; + +const static byte sqwave[4][8] = +{ + { 0, 0,-1, 0, 0, 0, 0, 0 }, + { 0,-1,-1, 0, 0, 0, 0, 0 }, + { -1,-1,-1,-1, 0, 0, 0, 0 }, + { -1, 0, 0,-1,-1,-1,-1,-1 } +}; + +const static int freqtab[8] = +{ + (1<<14)*2, + (1<<14), + (1<<14)/2, + (1<<14)/3, + (1<<14)/4, + (1<<14)/5, + (1<<14)/6, + (1<<14)/7 +}; + +struct snd snd; + +#define RATE (snd.rate) +#define WAVE (snd.wave) /* ram.hi+0x30 */ +#define S1 (snd.ch[0]) +#define S2 (snd.ch[1]) +#define S3 (snd.ch[2]) +#define S4 (snd.ch[3]) + +rcvar_t sound_exports[] = +{ + RCV_END +}; + + +static void s1_freq_d(int d) +{ + if (RATE > (d<<4)) S1.freq = 0; + else S1.freq = (RATE << 17)/d; +} + +static void s1_freq() +{ + s1_freq_d(2048 - (((R_NR14&7)<<8) + R_NR13)); +} + +static void s2_freq() +{ + int d = 2048 - (((R_NR24&7)<<8) + R_NR23); + if (RATE > (d<<4)) S2.freq = 0; + else S2.freq = (RATE << 17)/d; +} + +static void s3_freq() +{ + int d = 2048 - (((R_NR34&7)<<8) + R_NR33); + if (RATE > (d<<3)) S3.freq = 0; + else S3.freq = (RATE << 21)/d; +} + +static void s4_freq() +{ + S4.freq = (freqtab[R_NR43&7] >> (R_NR43 >> 4)) * RATE; + if (S4.freq >> 18) S4.freq = 1<<18; +} + +void sound_dirty() +{ + S1.swlen = ((R_NR10>>4) & 7) << 14; + S1.len = (64-(R_NR11&63)) << 13; + S1.envol = R_NR12 >> 4; + S1.endir = (R_NR12>>3) & 1; + S1.endir |= S1.endir - 1; + S1.enlen = (R_NR12 & 7) << 15; + s1_freq(); + S2.len = (64-(R_NR21&63)) << 13; + S2.envol = R_NR22 >> 4; + S2.endir = (R_NR22>>3) & 1; + S2.endir |= S2.endir - 1; + S2.enlen = (R_NR22 & 7) << 15; + s2_freq(); + S3.len = (256-R_NR31) << 20; + s3_freq(); + S4.len = (64-(R_NR41&63)) << 13; + S4.envol = R_NR42 >> 4; + S4.endir = (R_NR42>>3) & 1; + S4.endir |= S4.endir - 1; + S4.enlen = (R_NR42 & 7) << 15; + s4_freq(); +} + +void sound_off() +{ + memset(&S1, 0, sizeof S1); + memset(&S2, 0, sizeof S2); + memset(&S3, 0, sizeof S3); + memset(&S4, 0, sizeof S4); + R_NR10 = 0x80; + R_NR11 = 0xBF; + R_NR12 = 0xF3; + R_NR14 = 0xBF; + R_NR21 = 0x3F; + R_NR22 = 0x00; + R_NR24 = 0xBF; + R_NR30 = 0x7F; + R_NR31 = 0xFF; + R_NR32 = 0x9F; + R_NR33 = 0xBF; + R_NR41 = 0xFF; + R_NR42 = 0x00; + R_NR43 = 0x00; + R_NR44 = 0xBF; + R_NR50 = 0x77; + R_NR51 = 0xF3; + R_NR52 = 0xF1; + sound_dirty(); +} + +void sound_reset() +{ + memset(&snd, 0, sizeof snd); + if (pcm.hz) snd.rate = (1<<21) / pcm.hz; + else snd.rate = 0; + memcpy(WAVE, hw.cgb ? cgbwave : dmgwave, 16); + memcpy(ram.hi+0x30, WAVE, 16); + sound_off(); +} + + +void sound_mix() +{ + int s, l, r, f, n; + + if (!RATE || cpu.snd < RATE) return; + + for (; cpu.snd >= RATE; cpu.snd -= RATE) + { + l = r = 0; + + if (S1.on) + { + s = sqwave[R_NR11>>6][(S1.pos>>18)&7] & S1.envol; + S1.pos += S1.freq; + if ((R_NR14 & 64) && ((S1.cnt += RATE) >= S1.len)) + S1.on = 0; + if (S1.enlen && (S1.encnt += RATE) >= S1.enlen) + { + S1.encnt -= S1.enlen; + S1.envol += S1.endir; + if (S1.envol < 0) S1.envol = 0; + if (S1.envol > 15) S1.envol = 15; + } + if (S1.swlen && (S1.swcnt += RATE) >= S1.swlen) + { + S1.swcnt -= S1.swlen; + f = S1.swfreq; + n = (R_NR10 & 7); + if (R_NR10 & 8) f -= (f >> n); + else f += (f >> n); + if (f > 2047) + S1.on = 0; + else + { + S1.swfreq = f; + R_NR13 = f; + R_NR14 = (R_NR14 & 0xF8) | (f>>8); + s1_freq_d(2048 - f); + } + } + s <<= 2; + if (R_NR51 & 1) r += s; + if (R_NR51 & 16) l += s; + } + + if (S2.on) + { + s = sqwave[R_NR21>>6][(S2.pos>>18)&7] & S2.envol; + S2.pos += S2.freq; + if ((R_NR24 & 64) && ((S2.cnt += RATE) >= S2.len)) + S2.on = 0; + if (S2.enlen && (S2.encnt += RATE) >= S2.enlen) + { + S2.encnt -= S2.enlen; + S2.envol += S2.endir; + if (S2.envol < 0) S2.envol = 0; + if (S2.envol > 15) S2.envol = 15; + } + s <<= 2; + if (R_NR51 & 2) r += s; + if (R_NR51 & 32) l += s; + } + + if (S3.on) + { + s = WAVE[(S3.pos>>22) & 15]; + if (S3.pos & (1<<21)) s &= 15; + else s >>= 4; + s -= 8; + S3.pos += S3.freq; + if ((R_NR34 & 64) && ((S3.cnt += RATE) >= S3.len)) + S3.on = 0; + if (R_NR32 & 96) s <<= (3 - ((R_NR32>>5)&3)); + else s = 0; + if (R_NR51 & 4) r += s; + if (R_NR51 & 64) l += s; + } + + if (S4.on) + { + if (R_NR43 & 8) s = 1 & (noise7[ + (S4.pos>>20)&15] >> (7-((S4.pos>>17)&7))); + else s = 1 & (noise15[ + (S4.pos>>20)&4095] >> (7-((S4.pos>>17)&7))); + s = (-s) & S4.envol; + S4.pos += S4.freq; + if ((R_NR44 & 64) && ((S4.cnt += RATE) >= S4.len)) + S4.on = 0; + if (S4.enlen && (S4.encnt += RATE) >= S4.enlen) + { + S4.encnt -= S4.enlen; + S4.envol += S4.endir; + if (S4.envol < 0) S4.envol = 0; + if (S4.envol > 15) S4.envol = 15; + } + s += s << 1; + if (R_NR51 & 8) r += s; + if (R_NR51 & 128) l += s; + } + + l *= (R_NR50 & 0x07); + r *= ((R_NR50 & 0x70)>>4); + l >>= 4; + r >>= 4; + + if (l > 127) l = 127; + else if (l < -128) l = -128; + if (r > 127) r = 127; + else if (r < -128) r = -128; + + if (pcm.buf) + { + if (pcm.pos >= pcm.len) + pcm_submit(); + if (pcm.stereo) + { + pcm.buf[pcm.pos++] = l+128; + pcm.buf[pcm.pos++] = r+128; + } + else pcm.buf[pcm.pos++] = ((l+r)>>1)+128; + } + } + R_NR52 = (R_NR52&0xf0) | S1.on | (S2.on<<1) | (S3.on<<2) | (S4.on<<3); +} + + + +byte sound_read(byte r) +{ + sound_mix(); + /* printf("read %02X: %02X\n", r, REG(r)); */ + return REG(r); +} + +void s1_init() +{ + S1.swcnt = 0; + S1.swfreq = ((R_NR14&7)<<8) + R_NR13; + S1.envol = R_NR12 >> 4; + S1.endir = (R_NR12>>3) & 1; + S1.endir |= S1.endir - 1; + S1.enlen = (R_NR12 & 7) << 15; + if (!S1.on) S1.pos = 0; + S1.on = 1; + S1.cnt = 0; + S1.encnt = 0; +} + +void s2_init() +{ + S2.envol = R_NR22 >> 4; + S2.endir = (R_NR22>>3) & 1; + S2.endir |= S2.endir - 1; + S2.enlen = (R_NR22 & 7) << 15; + if (!S2.on) S2.pos = 0; + S2.on = 1; + S2.cnt = 0; + S2.encnt = 0; +} + +void s3_init() +{ + int i; + if (!S3.on) S3.pos = 0; + S3.cnt = 0; + S3.on = R_NR30 >> 7; + if (S3.on) for (i = 0; i < 16; i++) + ram.hi[i+0x30] = 0x13 ^ ram.hi[i+0x31]; +} + +void s4_init() +{ + S4.envol = R_NR42 >> 4; + S4.endir = (R_NR42>>3) & 1; + S4.endir |= S4.endir - 1; + S4.enlen = (R_NR42 & 7) << 15; + S4.on = 1; + S4.pos = 0; + S4.cnt = 0; + S4.encnt = 0; +} + + +void sound_write(byte r, byte b) +{ +#if 0 + static void *timer; + if (!timer) timer = sys_timer(); + printf("write %02X: %02X @ %d\n", r, b, sys_elapsed(timer)); +#endif + + if (!(R_NR52 & 128) && r != RI_NR52) return; + if ((r & 0xF0) == 0x30) + { + if (S3.on) sound_mix(); + if (!S3.on) + WAVE[r-0x30] = ram.hi[r] = b; + return; + } + sound_mix(); + switch (r) + { + case RI_NR10: + R_NR10 = b; + S1.swlen = ((R_NR10>>4) & 7) << 14; + S1.swfreq = ((R_NR14&7)<<8) + R_NR13; + break; + case RI_NR11: + R_NR11 = b; + S1.len = (64-(R_NR11&63)) << 13; + break; + case RI_NR12: + R_NR12 = b; + S1.envol = R_NR12 >> 4; + S1.endir = (R_NR12>>3) & 1; + S1.endir |= S1.endir - 1; + S1.enlen = (R_NR12 & 7) << 15; + break; + case RI_NR13: + R_NR13 = b; + s1_freq(); + break; + case RI_NR14: + R_NR14 = b; + s1_freq(); + if (b & 128) s1_init(); + break; + case RI_NR21: + R_NR21 = b; + S2.len = (64-(R_NR21&63)) << 13; + break; + case RI_NR22: + R_NR22 = b; + S2.envol = R_NR22 >> 4; + S2.endir = (R_NR22>>3) & 1; + S2.endir |= S2.endir - 1; + S2.enlen = (R_NR22 & 7) << 15; + break; + case RI_NR23: + R_NR23 = b; + s2_freq(); + break; + case RI_NR24: + R_NR24 = b; + s2_freq(); + if (b & 128) s2_init(); + break; + case RI_NR30: + R_NR30 = b; + if (!(b & 128)) S3.on = 0; + break; + case RI_NR31: + R_NR31 = b; + S3.len = (256-R_NR31) << 13; + break; + case RI_NR32: + R_NR32 = b; + break; + case RI_NR33: + R_NR33 = b; + s3_freq(); + break; + case RI_NR34: + R_NR34 = b; + s3_freq(); + if (b & 128) s3_init(); + break; + case RI_NR41: + R_NR41 = b; + S4.len = (64-(R_NR41&63)) << 13; + break; + case RI_NR42: + R_NR42 = b; + S4.envol = R_NR42 >> 4; + S4.endir = (R_NR42>>3) & 1; + S4.endir |= S4.endir - 1; + S4.enlen = (R_NR42 & 7) << 15; + break; + case RI_NR43: + R_NR43 = b; + s4_freq(); + break; + case RI_NR44: + R_NR44 = b; + if (b & 128) s4_init(); + break; + case RI_NR50: + R_NR50 = b; + break; + case RI_NR51: + R_NR51 = b; + break; + case RI_NR52: + R_NR52 = b; + if (!(R_NR52 & 128)) + sound_off(); + break; + default: + return; + } +} + + + + diff --git a/sound.h b/sound.h new file mode 100644 index 0000000..2056f80 --- /dev/null +++ b/sound.h @@ -0,0 +1,36 @@ + + +#ifndef __SOUND_H__ +#define __SOUND_H__ + + +struct sndchan +{ + int on; + unsigned pos; + int cnt, encnt, swcnt; + int len, enlen, swlen; + int swfreq; + int freq; + int envol, endir; +}; + + +struct snd +{ + int rate; + struct sndchan ch[4]; + byte wave[16]; +}; + + +extern struct snd snd; + + + + + + +#endif + + diff --git a/split.c b/split.c new file mode 100644 index 0000000..af53d73 --- /dev/null +++ b/split.c @@ -0,0 +1,58 @@ + + +/* + * splitline is a destructive argument parser, much like a very primitive + * form of a shell parser. it supports quotes for embedded spaces and + * literal quotes with the backslash escape. + */ + +char *splitnext(char **pos) +{ + char *a, *d, *s; + + d = s = *pos; + while (*s == ' ' || *s == '\t') s++; + a = s; + while (*s && *s != ' ' && *s != '\t') + { + if (*s == '"') + { + s++; + while (*s && *s != '"') + { + if (*s == '\\') + s++; + if (*s) + *(d++) = *(s++); + } + if (*s == '"') s++; + } + else + { + if (*s == '\\') + s++; + *(d++) = *(s++); + } + } + while (*s == ' ' || *s == '\t') s++; + *d = 0; + *pos = s; + return a; +} + +int splitline(char **argv, int max, char *line) +{ + char *s; + int i; + + s = line; + for (i = 0; *s && i < max + 1; i++) + argv[i] = splitnext(&s); + argv[i] = 0; + return i; +} + + + + + diff --git a/sys/dos/dos.c b/sys/dos/dos.c new file mode 100644 index 0000000..d6b3179 --- /dev/null +++ b/sys/dos/dos.c @@ -0,0 +1,85 @@ +/* + * dos.c + * + * System interface for DOS. + */ + +#include +#include +#include +char *strdup(); +#include +#include +#include +#include +#include + +#define US(n) ( ((long long)(n)) * 1000000 / UCLOCKS_PER_SEC ) + + +void *sys_timer() +{ + uclock_t *cl; + + cl = malloc(sizeof *cl); + *cl = uclock(); + return cl; +} + +int sys_elapsed(uclock_t *cl) +{ + uclock_t now; + int usecs; + + now = uclock(); + usecs = US(now - *cl); + *cl = now; + return usecs; +} + +void sys_sleep(int us) +{ + uclock_t start; + if (us <= 0) return; + start = uclock(); + while(US(uclock()-start) < us); +} + +void sys_checkdir(char *path, int wr) +{ +} + +void sys_initpath(char *exe) +{ + char *buf, *home, *p; + + home = strdup(exe); + p = strrchr(home, '/'); + if (p) *p = 0; + else + { + buf = "."; + rc_setvar("rcpath", 1, &buf); + rc_setvar("savedir", 1, &buf); + return; + } + buf = malloc(strlen(home) + 8); + sprintf(buf, ".;%s/", home); + rc_setvar("rcpath", 1, &buf); + sprintf(buf, "."); + rc_setvar("savedir", 1, &buf); + free(buf); +} + +void sys_sanitize(char *s) +{ + int i; + for (i = 0; s[i]; i++) + if (s[i] == '\\') s[i] = '/'; +} + + + + + + diff --git a/sys/dummy/nojoy.c b/sys/dummy/nojoy.c new file mode 100644 index 0000000..1252194 --- /dev/null +++ b/sys/dummy/nojoy.c @@ -0,0 +1,22 @@ + + +#include "rc.h" + +rcvar_t joy_exports[] = +{ + RCV_END +}; + +void joy_init() +{ +} + +void joy_close() +{ +} + +void joy_poll() +{ +} + + diff --git a/sys/dummy/nosound.c b/sys/dummy/nosound.c new file mode 100644 index 0000000..c899204 --- /dev/null +++ b/sys/dummy/nosound.c @@ -0,0 +1,43 @@ + + + + +#include "defs.h" +#include "pcm.h" +#include "rc.h" + + +struct pcm pcm; + +static byte buf[4096]; + + +rcvar_t pcm_exports[] = +{ + RCV_END +}; + + +void pcm_init() +{ + pcm.hz = 11025; + pcm.buf = buf; + pcm.len = sizeof buf; + pcm.pos = 0; +} + +void pcm_close() +{ + memset(&pcm, 0, sizeof pcm); +} + +int pcm_submit() +{ + pcm.pos = 0; + return 0; +} + + + + + diff --git a/sys/linux/fbdev.c b/sys/linux/fbdev.c new file mode 100644 index 0000000..5fcd1a8 --- /dev/null +++ b/sys/linux/fbdev.c @@ -0,0 +1,283 @@ + +/* + * Support for the Linux framebuffer device + * Copyright 2001 Laguna + * MGA BES code derived from fbtv + * Copyright Gerd Knorr + * This file may be distributed under the terms of the GNU GPL. + */ + + +#include +#include +char *strdup(); +#include +#include +#include +#include +#include + +#include "defs.h" +#include "fb.h" +#include "rc.h" +#include "matrox.h" + +struct fb fb; + + + +#define FBSET_CMD "fbset" +static char *fb_mode; +static int fb_depth; +static int vmode[3]; + +#define FB_DEVICE "/dev/fb0" +static char *fb_device; + +static int fbfd = -1; +static byte *fbmap; +static int maplen; +static byte *mmio; +static int bes; +static int base; +static int use_yuv = -1; +static int use_interp = 1; + +static struct fb_fix_screeninfo fi; +static struct fb_var_screeninfo vi, initial_vi; + +rcvar_t vid_exports[] = +{ + RCV_VECTOR("vmode", &vmode, 3), + RCV_STRING("fb_device", &fb_device), + RCV_STRING("fb_mode", &fb_mode), + RCV_INT("fb_depth", &fb_depth), + RCV_BOOL("yuv", &use_yuv), + RCV_BOOL("yuvinterp", &use_interp), + RCV_END +}; + + + +static void wrio4(int a, int v) +{ +#ifndef IS_LITTLE_ENDIAN + v = (v<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | (v>>24); +#endif + *(int*)(mmio+a) = v; +} + +static void overlay_switch() +{ + int a, b; + + if (!fb.yuv) return; + if (!fb.enabled) + { + if (bes) wrio4(BESCTL, 0); + bes = 0; + return; + } + if (bes) return; + bes = 1; + memset(fbmap, 0, maplen); + + /* color keying (turn it off) */ + mmio[PALWTADD] = XKEYOPMODE; + mmio[X_DATAREG] = 0; + + /* src */ + wrio4(BESA1ORG, base); + wrio4(BESA2ORG, base); + wrio4(BESB1ORG, base); + wrio4(BESB2ORG, base); + wrio4(BESPITCH, 320); + + /* dest */ + a = (vi.xres - vmode[0])>>1; + b = vi.xres - a - 1; + wrio4(BESHCOORD, (a << 16) | (b - 1)); + + /* scale horiz */ + wrio4(BESHISCAL, 320*131072/(b-a) & 0x001ffffc); + wrio4(BESHSRCST, 0 << 16); + wrio4(BESHSRCEND, 320 << 16); + wrio4(BESHSRCLST, 319 << 16); + + /* dest */ + a = (vi.yres - vmode[1])>>1; + b = vi.yres - a - 1; + wrio4(BESVCOORD, (a << 16) | (b - 1)); + + /* scale vert */ + wrio4(BESVISCAL, 144*65536/(b-a) & 0x001ffffc); + wrio4(BESV1WGHT, 0); + wrio4(BESV2WGHT, 0); + wrio4(BESV1SRCLST, 143); + wrio4(BESV2SRCLST, 143); + + /* turn on (enable, horizontal+vertical interpolation filters */ + if (use_interp) + wrio4(BESCTL, 0x50c01); + else + wrio4(BESCTL, 1); + wrio4(BESGLOBCTL, 0x83); +} + +static void overlay_init() +{ + if (!mmio | !use_yuv) return; + if (use_yuv < 0) if ((vmode[0] < 320) || (vmode[1] < 288)) return; + switch (fi.accel) + { +#ifdef FB_ACCEL_MATROX_MGAG200 + case FB_ACCEL_MATROX_MGAG200: +#endif +#ifdef FB_ACCEL_MATROX_MGAG400 + case FB_ACCEL_MATROX_MGAG400: +#endif + break; + default: + return; + } + fb.w = 160; + fb.h = 144; + fb.pitch = 640; + fb.pelsize = 4; + fb.yuv = 1; + fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = fb.cc[3].r = 0; + fb.cc[0].l = 0; + fb.cc[1].l = 24; + fb.cc[2].l = 8; + fb.cc[3].l = 16; + base = vi.yres * vi.xres_virtual * ((vi.bits_per_pixel+7)>>3); + + maplen = base + fb.pitch * fb.h; +} + +static void plain_init() +{ + fb.w = vi.xres; + fb.h = vi.yres; + fb.pelsize = (vi.bits_per_pixel+7)>>3; + fb.pitch = vi.xres_virtual * fb.pelsize; + fb.indexed = fi.visual == FB_VISUAL_PSEUDOCOLOR; + + fb.cc[0].r = 8 - vi.red.length; + fb.cc[1].r = 8 - vi.green.length; + fb.cc[2].r = 8 - vi.blue.length; + fb.cc[0].l = vi.red.offset; + fb.cc[1].l = vi.green.offset; + fb.cc[2].l = vi.blue.offset; + + maplen = fb.pitch * fb.h; +} + +void vid_init() +{ + char cmd[256]; + + kb_init(); + joy_init(); + + if (!fb_device) + if (!(fb_device = getenv("FRAMEBUFFER"))) + fb_device = strdup(FB_DEVICE); + fbfd = open(fb_device, O_RDWR); + if (fbfd < 0) die("cannot open %s\n", fb_device); + + ioctl(fbfd, FBIOGET_VSCREENINFO, &initial_vi); + initial_vi.xoffset = initial_vi.yoffset = 0; + + if (fb_mode) + { + sprintf(cmd, FBSET_CMD " %.80s", fb_mode); + system(cmd); + } + + ioctl(fbfd, FBIOGET_VSCREENINFO, &vi); + if (fb_depth) vi.bits_per_pixel = fb_depth; + vi.xoffset = vi.yoffset = 0; + vi.accel_flags = 0; + vi.activate = FB_ACTIVATE_NOW; + ioctl(fbfd, FBIOPUT_VSCREENINFO, &vi); + ioctl(fbfd, FBIOGET_VSCREENINFO, &vi); + ioctl(fbfd, FBIOGET_FSCREENINFO, &fi); + + if (!vmode[0] || !vmode[1]) + { + int scale = rc_getint("scale"); + if (scale < 1) scale = 1; + vmode[0] = 160 * scale; + vmode[1] = 144 * scale; + } + if (vmode[0] > vi.xres) vmode[0] = vi.xres; + if (vmode[1] > vi.yres) vmode[1] = vi.yres; + + mmio = mmap(0, fi.mmio_len, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, fi.smem_len); + if ((int)mmio == -1) mmio = 0; + + overlay_init(); + + if (!fb.yuv) plain_init(); + + fbmap = mmap(0, maplen, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, 0); + if (!fbmap) die("cannot mmap %s (%d bytes)\n", fb_device, maplen); + + fb.ptr = fbmap + base; + memset(fbmap, 0, maplen); + fb.dirty = 0; + fb.enabled = 1; + + overlay_switch(); +} + +void vid_close() +{ + fb.enabled = 0; + overlay_switch(); + joy_close(); + kb_close(); + ioctl(fbfd, FBIOPUT_VSCREENINFO, &initial_vi); + memset(fbmap, 0, maplen); +} + +void vid_preinit() +{ +} + +void vid_settitle(char *title) +{ +} + +void vid_setpal(int i, int r, int g, int b) +{ + unsigned short rr = r<<8, gg = g<<8, bb = b<<8; + struct fb_cmap cmap; + memset(&cmap, 0, sizeof cmap); + cmap.start = i; + cmap.len = 1; + cmap.red = &rr; + cmap.green = ≫ + cmap.blue = &bb; + ioctl(fbfd, FBIOPUTCMAP, &cmap); +} + +void vid_begin() +{ + overlay_switch(); +} + +void vid_end() +{ + overlay_switch(); +} + +void ev_poll() +{ + kb_poll(); + joy_poll(); +} + + + diff --git a/sys/linux/joy.c b/sys/linux/joy.c new file mode 100644 index 0000000..eacb2a1 --- /dev/null +++ b/sys/linux/joy.c @@ -0,0 +1,93 @@ + +#include +#include +#include +char *strdup(); +#include +#include +#include +#include +#include + +#include "input.h" +#include "rc.h" + +static int usejoy = 1; +static char *joydev; +static int joyfd = -1; +static int pos[2], max[2], min[2]; +static const int axis[2][2] = +{ + { K_JOYLEFT, K_JOYRIGHT }, + { K_JOYUP, K_JOYDOWN } +}; + +rcvar_t joy_exports[] = +{ + RCV_BOOL("joy", &usejoy), + RCV_STRING("joy_device", &joydev), + RCV_END +}; + + + + +void joy_init() +{ + if (!usejoy) return; + if (!joydev) joydev = strdup("/dev/js0"); + joyfd = open(joydev, O_RDONLY|O_NONBLOCK); +} + +void joy_close() +{ + close(joyfd); +} + +void joy_poll() +{ + struct js_event js; + event_t ev; + int n; + + if (joyfd < 0) return; + + while (read(joyfd,&js,sizeof(struct js_event)) == sizeof(struct js_event)) + { + switch(js.type) + { + case JS_EVENT_BUTTON: + ev.type = js.value ? EV_PRESS : EV_RELEASE; + ev.code = K_JOY0 + js.number; + ev_postevent(&ev); + break; + case JS_EVENT_AXIS: + n = js.number & 1; + if (js.value < min[n]) min[n] = js.value; + else if(js.value > max[n]) max[n] = js.value; + ev.code = axis[n][0]; + if(js.value < (min[n]>>2) && js.value < pos[n]) + { + ev.type = EV_PRESS; + ev_postevent(&ev); + } + else if (js.value > pos[n]) + { + ev.type = EV_RELEASE; + ev_postevent(&ev); + } + ev.code = axis[n][1]; + if(js.value > (max[n]>>2) && js.value > pos[n]) + { + ev.type = EV_PRESS; + ev_postevent(&ev); + } + else if (js.value < pos[n]) + { + ev.type = EV_RELEASE; + ev_postevent(&ev); + } + pos[n] = js.value; + } + } +} diff --git a/sys/linux/kb.c b/sys/linux/kb.c new file mode 100644 index 0000000..70661b9 --- /dev/null +++ b/sys/linux/kb.c @@ -0,0 +1,135 @@ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef K_NUMLOCK + +#include "defs.h" +#include "rc.h" +#include "fb.h" +#include "input.h" + + + +#define TTY_DEVICE "/dev/tty" + +static int kbfd = -1; + +static int initial_kbmode; +static struct termios initial_term, term; + +#define SCAN_ALT 56 +#define SCAN_FBASE 58 +static int alt; + +static struct vt_mode vtm, initial_vtm; + +extern int keymap[][2]; + +rcvar_t kb_exports[] = +{ + RCV_END +}; + + +static void vcrelease(int s) +{ + signal(s, vcrelease); + ioctl(kbfd, VT_RELDISP, VT_ACKACQ); +} + +static void vcacquire(int s) +{ + signal(s, vcacquire); + ioctl(kbfd, VT_RELDISP, VT_ACKACQ); + fb.enabled = 1; +} + +void kb_init() +{ + kbfd = open(TTY_DEVICE, O_RDWR); + if (!kbfd) die("no controlling terminal\n"); + fcntl(kbfd, F_SETFL, O_NONBLOCK); + + if (ioctl(kbfd, KDSETMODE, KD_GRAPHICS) < 0) + die("controlling terminal is not the graphics console\n"); + + ioctl(kbfd, KDGKBMODE, &initial_kbmode); + tcgetattr(kbfd, &initial_term); + + term = initial_term; + term.c_lflag &= ~(ICANON | ECHO | ISIG); + term.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); + term.c_cc[VMIN] = 0; + term.c_cc[VTIME] = 0; + tcsetattr(kbfd, TCSAFLUSH, &term); + ioctl(kbfd, KDSKBMODE, K_MEDIUMRAW); + + ioctl(kbfd, VT_GETMODE, &initial_vtm); + + signal(SIGUSR1, vcrelease); + signal(SIGUSR2, vcacquire); + vtm = initial_vtm; + vtm.mode = VT_PROCESS; + vtm.relsig = SIGUSR1; + vtm.acqsig = SIGUSR2; + ioctl(kbfd, VT_SETMODE, &vtm); +} + + +void kb_close() +{ + ioctl(kbfd, VT_SETMODE, &initial_vtm); + ioctl(kbfd, KDSKBMODE, initial_kbmode); + tcsetattr(kbfd, TCSAFLUSH, &initial_term); + ioctl(kbfd, KDSETMODE, KD_TEXT); +} + + +static void vcswitch(int c) +{ + struct vt_stat vts; + ioctl(kbfd, VT_GETSTATE, &vts); + if (c != vts.v_active) + { + ioctl(kbfd, VT_ACTIVATE, c); + fb.enabled = 0; + fb.dirty = 1; + } +} + +void kb_poll() +{ + int i; + event_t ev; + byte k; + int st; + + while (read(kbfd, &k, 1) > 0) + { + st = !(k & 0x80); + k &= 0x7f; + + if (k == SCAN_ALT) alt = st; + if (alt && k > SCAN_FBASE && k < SCAN_FBASE + 10) + vcswitch(k - SCAN_FBASE); + ev.type = st ? EV_PRESS : EV_RELEASE; + for (i = 0; keymap[i][0]; i++) + if (keymap[i][0] == k) + break; + if (!keymap[i][0]) continue; + ev.code = keymap[i][1]; + ev_postevent(&ev); + } +} + diff --git a/sys/linux/matrox.h b/sys/linux/matrox.h new file mode 100644 index 0000000..a1d8911 --- /dev/null +++ b/sys/linux/matrox.h @@ -0,0 +1,36 @@ + + +/* taken from fbtv */ + +#define BES_BASE 0x3d00 +#define BESA1ORG (BES_BASE+0x00) +#define BESA2ORG (BES_BASE+0x04) +#define BESB1ORG (BES_BASE+0x08) +#define BESB2ORG (BES_BASE+0x0c) +#define BESA1CORG (BES_BASE+0x10) +#define BESA2CORG (BES_BASE+0x14) +#define BESB1CORG (BES_BASE+0x18) +#define BESB2CORG (BES_BASE+0x1c) +#define BESCTL (BES_BASE+0x20) +#define BESPITCH (BES_BASE+0x24) +#define BESHCOORD (BES_BASE+0x28) +#define BESVCOORD (BES_BASE+0x2c) +#define BESHISCAL (BES_BASE+0x30) +#define BESVISCAL (BES_BASE+0x34) +#define BESHSRCST (BES_BASE+0x38) +#define BESHSRCEND (BES_BASE+0x3c) + +#define BESV1WGHT (BES_BASE+0x48) +#define BESV2WGHT (BES_BASE+0x4c) +#define BESHSRCLST (BES_BASE+0x50) +#define BESV1SRCLST (BES_BASE+0x54) +#define BESV2SRCLST (BES_BASE+0x58) +#define BESGLOBCTL (BES_BASE+0xc0) +#define BESSTATUS (BES_BASE+0xc4) + +#define PALWTADD 0x3c00 +#define X_DATAREG 0x3c0a +#define XKEYOPMODE 0x51 + + + diff --git a/sys/nix/config.h.in b/sys/nix/config.h.in new file mode 100644 index 0000000..e528ae6 --- /dev/null +++ b/sys/nix/config.h.in @@ -0,0 +1,22 @@ + + +#undef WORDS_BIGENDIAN +#undef SIZEOF_SHORT +#undef SIZEOF_INT +#undef SIZEOF_LONG + +#undef HAVE_USLEEP +#undef HAVE_SELECT + +#undef HAVE_MMAP + +#undef HAVE_LIBXEXT +#undef HAVE_X11_EXTENSIONS_XSHM_H +#undef HAVE_SYS_IPC_H +#undef HAVE_SYS_SHM_H + +#undef HAVE_SYS_SOUNDCARD_H +#undef HAVE_SOUNDCARD_H + + + diff --git a/sys/nix/map.c b/sys/nix/map.c new file mode 100644 index 0000000..1d63e2b --- /dev/null +++ b/sys/nix/map.c @@ -0,0 +1,85 @@ + + +/* + * this code is not yet used. eventually we want to support using mmap + * to map rom and sram into memory, so we don't waste virtual memory. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include +#include +#include +#include + + +#include "defs.h" + + +#define DOTDIR ".gnuboy" + +static char *home, *saves; +static char *romfile, *sramfile, *saveprefix; + +static int mmapped_rom, mmaped_sram; + + +byte *map_rom() +{ + int fd, len; + byte code; + byte *mem; + + fd = open(romfile, O_READ); + lseek(fd, 0x0148, SEEK_SET); + read(fd, &code, 1); + len = loader_romsize(code); + +#ifdef HAVE_MMAP + + mem = mmap(0, len, PROT_READ, +#endif + +} + + + + + +int map_checkdirs() +{ + home = malloc(strlen(getenv("HOME")) + strlen(DOTDIR) + 2); + sprintf(home, "%s/" DOTDIR, getenv(HOME)); + saves = malloc(strlen(home) + 6); + sprintf(saves, "%s/saves", home); + + if (access(saves, X_OK|W_OK)) + { + if (access(home, X_OK|W_OK)) + { + if (!access(home, F_OK)) + die("cannot access %s (%s)\n", home, strerror(errno)); + if (mkdir(home, 0777)) + die("cannot create %s (%s)\n", home, strerror(errno)); + } + if (!access(saves, F_OK)) + die("cannot access %s (%s)\n", home, strerror(errno)); + if (mkdir(saves, 0777)) + die("cannot create %s (%s)\n", saves, strerror(errno)); + } + return 0; +} + + + + + + + + + + diff --git a/sys/nix/nix.c b/sys/nix/nix.c new file mode 100644 index 0000000..dbb024c --- /dev/null +++ b/sys/nix/nix.c @@ -0,0 +1,104 @@ +/* + * nix.c + * + * System interface for *nix systems. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define DOTDIR ".gnuboy" + +#ifndef HAVE_USLEEP +static void my_usleep(unsigned int us) +{ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = us; + select(0, NULL, NULL, NULL, &tv); +} +#endif + +void *sys_timer() +{ + struct timeval *tv; + + tv = malloc(sizeof(struct timeval)); + gettimeofday(tv, NULL); + return tv; +} + +int sys_elapsed(struct timeval *prev) +{ + struct timeval tv; + int secs, usecs; + + gettimeofday(&tv, NULL); + secs = tv.tv_sec - prev->tv_sec; + usecs = tv.tv_usec - prev->tv_usec; + *prev = tv; + if (!secs) return usecs; + return 1000000 + usecs; +} + +void sys_sleep(int us) +{ + if (us <= 0) return; +#ifdef HAVE_USLEEP + usleep(us); +#else + my_usleep(us); +#endif +} + +void sys_checkdir(char *path, int wr) +{ + char *p; + if (access(path, X_OK | (wr ? W_OK : 0))) + { + if (!access(path, F_OK)) + die("cannot access %s: %s\n", path, strerror(errno)); + p = strrchr(path, '/'); + if (!p) die("descended to root trying to create dirs\n"); + *p = 0; + sys_checkdir(path, wr); + *p = '/'; + if (mkdir(path, 0777)) + die("cannot create %s: %s\n", path, strerror(errno)); + } +} + +void sys_initpath() +{ + char *buf, *home = getenv("HOME"); + if (!home) + { + buf = "."; + rc_setvar("rcpath", 1, &buf); + rc_setvar("savedir", 1, &buf); + return; + } + buf = malloc(strlen(home) + strlen(DOTDIR) + 8); + sprintf(buf, "%s/" DOTDIR ":.", home); + rc_setvar("rcpath", 1, &buf); + sprintf(buf, "%s/" DOTDIR "/saves" , home); + rc_setvar("savedir", 1, &buf); + free(buf); +} + +void sys_sanitize(char *s) +{ +} + + + + diff --git a/sys/oss/oss.c b/sys/oss/oss.c new file mode 100644 index 0000000..b8e4d6a --- /dev/null +++ b/sys/oss/oss.c @@ -0,0 +1,104 @@ + + +#include +#include +char *strdup(); +#include +#include +#include + +#ifdef IS_FBSD +#include "machine/soundcard.h" +#define DSP_DEVICE "/dev/dsp" +#endif + +#ifdef IS_OBSD +#include "soundcard.h" +#define DSP_DEVICE "/dev/sound" +#endif + +#ifdef IS_LINUX +#include +#define DSP_DEVICE "/dev/dsp" +#endif + +#include "defs.h" +#include "pcm.h" +#include "rc.h" + +/* FIXME - all this code is VERY basic, improve it! */ + + +struct pcm pcm; + +static int dsp; +static char *dsp_device; +static int stereo = 1; +static int samplerate = 44100; +static int sound = 1; + +rcvar_t pcm_exports[] = +{ + RCV_BOOL("sound", &sound), + RCV_INT("stereo", &stereo), + RCV_INT("samplerate", &samplerate), + RCV_STRING("oss_device", &dsp_device), + RCV_END +}; + + +void pcm_init() +{ + int n; + + if (!sound) + { + pcm.hz = 11025; + pcm.len = 4096; + pcm.buf = malloc(pcm.len); + pcm.pos = 0; + dsp = -1; + return; + } + + if (!dsp_device) dsp_device = strdup(DSP_DEVICE); + dsp = open(dsp_device, O_WRONLY); + + n = 0x80009; + ioctl(dsp, SNDCTL_DSP_SETFRAGMENT, &n); + n = AFMT_U8; + ioctl(dsp, SNDCTL_DSP_SETFMT, &n); + n = stereo; + ioctl(dsp, SNDCTL_DSP_STEREO, &n); + pcm.stereo = n; + n = samplerate; + ioctl(dsp, SNDCTL_DSP_SPEED, &n); + pcm.hz = n; + pcm.len = n / 60; + pcm.buf = malloc(pcm.len); +} + +void pcm_close() +{ + if (pcm.buf) free(pcm.buf); + memset(&pcm, 0, sizeof pcm); + close(dsp); +} + +int pcm_submit() +{ + if (dsp < 0) + { + pcm.pos = 0; + return 0; + } + if (pcm.buf) write(dsp, pcm.buf, pcm.pos); + pcm.pos = 0; + return 1; +} + + + + + + diff --git a/sys/pc/keymap.c b/sys/pc/keymap.c new file mode 100644 index 0000000..7fe201c --- /dev/null +++ b/sys/pc/keymap.c @@ -0,0 +1,141 @@ +/* + * pckeymap.c + * + * Mappings from IBM-PC scancodes to local key codes. + */ + +#include "input.h" + +int keymap[][2] = +{ + { 1, K_ESC }, + { 2, '1' }, + { 3, '2' }, + { 4, '3' }, + { 5, '4' }, + { 6, '5' }, + { 7, '6' }, + { 8, '7' }, + { 9, '8' }, + { 10, '9' }, + { 11, '0' }, + { 12, K_MINUS }, + { 13, K_EQUALS }, + { 14, K_BS }, + { 15, K_TAB }, + + { 16, 'q' }, + { 17, 'w' }, + { 18, 'e' }, + { 19, 'r' }, + { 20, 't' }, + { 21, 'y' }, + { 22, 'u' }, + { 23, 'i' }, + { 24, 'o' }, + { 25, 'p' }, + + { 26, '[' }, + { 27, ']' }, + + { 28, K_ENTER }, + { 29, K_CTRL }, + + { 30, 'a' }, + { 31, 's' }, + { 32, 'd' }, + { 33, 'f' }, + { 34, 'g' }, + { 35, 'h' }, + { 36, 'j' }, + { 37, 'k' }, + { 38, 'l' }, + + { 39, K_SEMI }, + { 40, '\'' }, + { 41, K_TILDE }, + { 42, K_SHIFT }, + { 43, K_BSLASH }, + + { 44, 'z' }, + { 45, 'x' }, + { 46, 'c' }, + { 47, 'v' }, + { 48, 'b' }, + { 49, 'n' }, + { 50, 'm' }, + + { 51, ',' }, + { 52, '.' }, + { 53, '/' }, + + { 54, K_SHIFT }, + + { 55, K_NUMMUL }, + + { 56, K_ALT }, + { 57, ' ' }, + { 58, K_CAPS }, + + { 59, K_F1 }, + { 60, K_F2 }, + { 61, K_F3 }, + { 62, K_F4 }, + { 63, K_F5 }, + { 64, K_F6 }, + { 65, K_F7 }, + { 66, K_F8 }, + { 67, K_F9 }, + { 68, K_F10 }, + + { 69, K_NUMLOCK }, + { 70, K_SCROLL }, + + { 71, K_NUM7 }, + { 72, K_NUM8 }, + { 73, K_NUM9 }, + { 74, K_NUMMINUS }, + { 75, K_NUM4 }, + { 76, K_NUM5 }, + { 77, K_NUM6 }, + { 78, K_NUMPLUS }, + { 79, K_NUM1 }, + { 80, K_NUM2 }, + { 81, K_NUM3 }, + { 82, K_NUM0 }, + { 83, K_NUMDOT }, + + { 87, K_F11 }, + { 88, K_F12 }, + + { 96, K_NUMENTER }, + { 97, K_CTRL }, + { 98, K_NUMDIV }, + { 99, K_SYSRQ }, + + { 100, K_ALT }, + { 101, K_PAUSE }, + { 119, K_PAUSE }, + + { 102, K_HOME }, + { 103, K_UP }, + { 104, K_PRIOR }, + { 105, K_LEFT }, + { 106, K_RIGHT }, + { 107, K_END }, + { 108, K_DOWN }, + { 109, K_NEXT }, + { 110, K_INS }, + { 111, K_DEL }, + + { 0, 0 } +}; + + + + + + + + + diff --git a/sys/sdl/keymap.c b/sys/sdl/keymap.c new file mode 100644 index 0000000..c5c049b --- /dev/null +++ b/sys/sdl/keymap.c @@ -0,0 +1,87 @@ +/* + * sdl_keymap.c + * + * Mappings from SDL keycode to local key codes. + * Stolen from xkeymap.c + * + */ + +#include +#include "input.h" + +int keymap[][2] = { + { SDLK_LSHIFT, K_SHIFT }, + { SDLK_RSHIFT, K_SHIFT }, + { SDLK_LCTRL, K_CTRL }, + { SDLK_RCTRL, K_CTRL }, + { SDLK_LALT, K_ALT }, + { SDLK_RALT, K_ALT }, + { SDLK_LMETA, K_ALT }, + { SDLK_RMETA, K_ALT }, + + { SDLK_UP, K_UP }, + { SDLK_DOWN, K_DOWN }, + { SDLK_RIGHT, K_RIGHT }, + { SDLK_LEFT, K_LEFT }, + { SDLK_RETURN, K_ENTER }, + { SDLK_SPACE, K_SPACE }, + { SDLK_TAB, K_TAB }, + { SDLK_BACKSPACE, K_BS }, + { SDLK_DELETE, K_DEL }, + { SDLK_INSERT, K_INS }, + { SDLK_HOME, K_HOME }, + { SDLK_END, K_END }, + { SDLK_ESCAPE, K_ESC }, + { SDLK_PAUSE, K_PAUSE }, + { SDLK_BREAK, K_PAUSE }, + { SDLK_CAPSLOCK, K_CAPS }, + { SDLK_NUMLOCK, K_NUMLOCK }, + { SDLK_SCROLLOCK, K_SCROLL }, + + { SDLK_MINUS, K_MINUS }, + { SDLK_EQUALS, K_EQUALS }, + + { SDLK_LEFTBRACKET, '[' }, + { SDLK_RIGHTBRACKET, ']' }, + { SDLK_BACKSLASH, K_BSLASH }, + { SDLK_BACKQUOTE, K_TILDE }, + { SDLK_SEMICOLON, K_SEMI }, + { SDLK_QUOTE, K_QUOTE }, + { SDLK_QUOTEDBL, K_QUOTE }, + { SDLK_COMMA, ',' }, + { SDLK_PERIOD, '.' }, + { SDLK_SLASH, '/' }, + + { SDLK_F1, K_F1 }, + { SDLK_F2, K_F2 }, + { SDLK_F3, K_F3 }, + { SDLK_F4, K_F4 }, + { SDLK_F5, K_F5 }, + { SDLK_F6, K_F6 }, + { SDLK_F7, K_F7 }, + { SDLK_F8, K_F8 }, + { SDLK_F9, K_F9 }, + { SDLK_F10, K_F10 }, + { SDLK_F11, K_F11 }, + { SDLK_F12, K_F12 }, + + { SDLK_KP0, K_NUM0 }, + { SDLK_KP1, K_NUM1 }, + { SDLK_KP2, K_NUM2 }, + { SDLK_KP3, K_NUM3 }, + { SDLK_KP4, K_NUM4 }, + { SDLK_KP5, K_NUM5 }, + { SDLK_KP6, K_NUM6 }, + { SDLK_KP7, K_NUM7 }, + { SDLK_KP8, K_NUM8 }, + { SDLK_KP9, K_NUM9 }, + { SDLK_KP_PLUS, K_NUMPLUS }, + { SDLK_KP_MINUS, K_NUMMINUS }, + { SDLK_KP_MULTIPLY, K_NUMMUL }, + { SDLK_KP_DIVIDE, K_NUMDIV }, + { SDLK_KP_PERIOD, K_NUMDOT }, + { SDLK_KP_ENTER, K_NUMENTER }, + + { 0, 0 } +}; + diff --git a/sys/sdl/sdl.c b/sys/sdl/sdl.c new file mode 100644 index 0000000..2350ebd --- /dev/null +++ b/sys/sdl/sdl.c @@ -0,0 +1,510 @@ +/* + * sdl.c + * sdl interfaces -- based on svga.c + * + * (C) 2001 Damian Gryski + * Joystick code contributed by David Lau + * Sound code added by Laguna + * + * Licensed under the GPLv2, or later. + */ + +#include +#include + +#include + + +#include "fb.h" +#include "input.h" +#include "rc.h" + +struct fb fb; + +static int use_yuv = -1; +static int fullscreen = 1; +static int use_altenter = 1; +static int use_joy = 1, sdl_joy_num; +static SDL_Joystick * sdl_joy = NULL; +static const int joy_commit_range = 3276; +static char Xstatus, Ystatus; + +static SDL_Surface *screen; +static SDL_Overlay *overlay; +static SDL_Rect overlay_rect; + +static int vmode[3] = { 0, 0, 16 }; + +rcvar_t vid_exports[] = +{ + RCV_VECTOR("vmode", &vmode, 3), + RCV_BOOL("yuv", &use_yuv), + RCV_BOOL("fullscreen", &fullscreen), + RCV_BOOL("altenter", &use_altenter), + RCV_END +}; + +rcvar_t joy_exports[] = +{ + RCV_BOOL("joy", &use_joy), + RCV_END +}; + +/* keymap - mappings of the form { scancode, localcode } - from sdl/keymap.c */ +extern int keymap[][2]; + +static int mapscancode(SDLKey sym) +{ + /* this could be faster: */ + /* build keymap as int keymap[256], then ``return keymap[sym]'' */ + + int i; + for (i = 0; keymap[i][0]; i++) + if (keymap[i][0] == sym) + return keymap[i][1]; + if (sym >= '0' && sym <= '9') + return sym; + if (sym >= 'a' && sym <= 'z') + return sym; + return 0; +} + + +static void joy_init() +{ + int i; + int joy_count; + + /* Initilize the Joystick, and disable all later joystick code if an error occured */ + if (!use_joy) return; + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK)) + return; + + joy_count = SDL_NumJoysticks(); + + if (!joy_count) + return; + + /* now try and open one. If, for some reason it fails, move on to the next one */ + for (i = 0; i < joy_count; i++) + { + sdl_joy = SDL_JoystickOpen(i); + if (sdl_joy) + { + sdl_joy_num = i; + break; + } + } + + /* make sure that Joystick event polling is a go */ + SDL_JoystickEventState(SDL_ENABLE); +} + +static void overlay_init() +{ + if (!use_yuv) return; + + if (use_yuv < 0) + if (vmode[0] < 320 || vmode[1] < 288) + return; + + overlay = SDL_CreateYUVOverlay(320, 144, SDL_YUY2_OVERLAY, screen); + + if (!overlay) return; + + if (!overlay->hw_overlay || overlay->planes > 1) + { + SDL_FreeYUVOverlay(overlay); + overlay = 0; + return; + } + + SDL_LockYUVOverlay(overlay); + + fb.w = 160; + fb.h = 144; + fb.pelsize = 4; + fb.pitch = overlay->pitches[0]; + fb.ptr = overlay->pixels[0]; + fb.yuv = 1; + fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = fb.cc[3].r = 0; + fb.dirty = 1; + fb.enabled = 1; + + overlay_rect.x = 0; + overlay_rect.y = 0; + overlay_rect.w = vmode[0]; + overlay_rect.h = vmode[1]; + + /* Color channels are 0=Y, 1=U, 2=V, 3=Y1 */ + switch (overlay->format) + { + /* FIXME - support more formats */ + case SDL_YUY2_OVERLAY: + default: + fb.cc[0].l = 0; + fb.cc[1].l = 24; + fb.cc[2].l = 8; + fb.cc[3].l = 16; + break; + } + + SDL_UnlockYUVOverlay(overlay); +} + +void vid_init() +{ + int flags; + + if (!vmode[0] || !vmode[1]) + { + int scale = rc_getint("scale"); + if (scale < 1) scale = 1; + vmode[0] = 160 * scale; + vmode[1] = 144 * scale; + } + + flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE; + + if (fullscreen) + flags |= SDL_FULLSCREEN; + + if (SDL_Init(SDL_INIT_VIDEO)) + die("SDL: Couldn't initialize SDL: %s\n", SDL_GetError()); + + if (!(screen = SDL_SetVideoMode(vmode[0], vmode[1], vmode[2], flags))) + die("SDL: can't set video mode: %s\n", SDL_GetError()); + + SDL_ShowCursor(0); + + joy_init(); + + overlay_init(); + + if (fb.yuv) return; + + SDL_LockSurface(screen); + + fb.w = screen->w; + fb.h = screen->h; + fb.pelsize = screen->format->BytesPerPixel; + fb.pitch = screen->pitch; + fb.indexed = fb.pelsize == 1; + fb.ptr = screen->pixels; + fb.cc[0].r = screen->format->Rloss; + fb.cc[0].l = screen->format->Rshift; + fb.cc[1].r = screen->format->Gloss; + fb.cc[1].l = screen->format->Gshift; + fb.cc[2].r = screen->format->Bloss; + fb.cc[2].l = screen->format->Bshift; + + SDL_UnlockSurface(screen); + + fb.enabled = 1; + fb.dirty = 0; + +} + + +void ev_poll() +{ + event_t ev; + SDL_Event event; + int axisval; + + while (SDL_PollEvent(&event)) + { + switch(event.type) + { + case SDL_ACTIVEEVENT: + if (event.active.state == SDL_APPACTIVE) + fb.enabled = event.active.gain; + break; + case SDL_KEYDOWN: + if ((event.key.keysym.sym == SDLK_RETURN) && (event.key.keysym.mod & KMOD_ALT)) + SDL_WM_ToggleFullScreen(screen); + ev.type = EV_PRESS; + ev.code = mapscancode(event.key.keysym.sym); + ev_postevent(&ev); + break; + case SDL_KEYUP: + ev.type = EV_RELEASE; + ev.code = mapscancode(event.key.keysym.sym); + ev_postevent(&ev); + break; + case SDL_JOYAXISMOTION: + switch (event.jaxis.axis) + { + case 0: /* X axis */ + axisval = event.jaxis.value; + if (axisval > joy_commit_range) + { + if (Xstatus==2) break; + + if (Xstatus==0) + { + ev.type = EV_RELEASE; + ev.code = K_JOYLEFT; + ev_postevent(&ev); + } + + ev.type = EV_PRESS; + ev.code = K_JOYRIGHT; + ev_postevent(&ev); + Xstatus=2; + break; + } + + if (axisval < -(joy_commit_range)) + { + if (Xstatus==0) break; + + if (Xstatus==2) + { + ev.type = EV_RELEASE; + ev.code = K_JOYRIGHT; + ev_postevent(&ev); + } + + ev.type = EV_PRESS; + ev.code = K_JOYLEFT; + ev_postevent(&ev); + Xstatus=0; + break; + } + + /* if control reaches here, the axis is centered, + * so just send a release signal if necisary */ + + if (Xstatus==2) + { + ev.type = EV_RELEASE; + ev.code = K_JOYRIGHT; + ev_postevent(&ev); + } + + if (Xstatus==0) + { + ev.type = EV_RELEASE; + ev.code = K_JOYLEFT; + ev_postevent(&ev); + } + Xstatus=1; + break; + + case 1: /* Y axis*/ + axisval = event.jaxis.value; + if (axisval > joy_commit_range) + { + if (Ystatus==2) break; + + if (Ystatus==0) + { + ev.type = EV_RELEASE; + ev.code = K_JOYUP; + ev_postevent(&ev); + } + + ev.type = EV_PRESS; + ev.code = K_JOYDOWN; + ev_postevent(&ev); + Ystatus=2; + break; + } + + if (axisval < -joy_commit_range) + { + if (Ystatus==0) break; + + if (Ystatus==2) + { + ev.type = EV_RELEASE; + ev.code = K_JOYDOWN; + ev_postevent(&ev); + } + + ev.type = EV_PRESS; + ev.code = K_JOYUP; + ev_postevent(&ev); + Ystatus=0; + break; + } + + /* if control reaches here, the axis is centered, + * so just send a release signal if necisary */ + + if (Ystatus==2) + { + ev.type = EV_RELEASE; + ev.code = K_JOYDOWN; + ev_postevent(&ev); + } + + if (Ystatus==0) + { + ev.type = EV_RELEASE; + ev.code = K_JOYUP; + ev_postevent(&ev); + } + Ystatus=1; + break; + } + break; + case SDL_JOYBUTTONUP: + if (event.jbutton.button>15) break; + ev.type = EV_RELEASE; + ev.code = K_JOY0 + event.jbutton.button; + ev_postevent(&ev); + break; + case SDL_JOYBUTTONDOWN: + if (event.jbutton.button>15) break; + ev.type = EV_PRESS; + ev.code = K_JOY0+event.jbutton.button; + ev_postevent(&ev); + break; + case SDL_QUIT: + exit(1); + break; + default: + break; + } + } +} + +void vid_setpal(int i, int r, int g, int b) +{ + SDL_Color col; + + col.r = r; col.g = g; col.b = b; + + SDL_SetColors(screen, &col, i, 1); +} + +void vid_preinit() +{ +} + +void vid_close() +{ + if (overlay) + { + SDL_UnlockYUVOverlay(overlay); + SDL_FreeYUVOverlay(overlay); + } + else SDL_UnlockSurface(screen); + SDL_Quit(); + fb.enabled = 0; +} + +void vid_settitle(char *title) +{ + SDL_WM_SetCaption(title, title); +} + +void vid_begin() +{ + if (overlay) + { + SDL_LockYUVOverlay(overlay); + fb.ptr = overlay->pixels[0]; + return; + } + SDL_LockSurface(screen); + fb.ptr = screen->pixels; +} + +void vid_end() +{ + if (overlay) + { + SDL_UnlockYUVOverlay(overlay); + if (fb.enabled) + SDL_DisplayYUVOverlay(overlay, &overlay_rect); + return; + } + SDL_UnlockSurface(screen); + if (fb.enabled) SDL_Flip(screen); +} + + + + + +#include "pcm.h" + + +struct pcm pcm; + + +static int sound = 1; +static int samplerate = 44100; +static int stereo = 1; +static volatile int audio_done; + +rcvar_t pcm_exports[] = +{ + RCV_BOOL("sound", &sound), + RCV_INT("stereo", &stereo), + RCV_INT("samplerate", &samplerate), + RCV_END +}; + + +static void audio_callback(void *blah, byte *stream, int len) +{ + memcpy(stream, pcm.buf, len); + audio_done = 1; +} + + +void pcm_init() +{ + int i; + SDL_AudioSpec as; + + if (!sound) return; + + SDL_InitSubSystem(SDL_INIT_AUDIO); + as.freq = samplerate; + as.format = AUDIO_U8; + as.channels = 1 + stereo; + as.samples = samplerate / 60; + for (i = 1; i < as.samples; i<<=1); + as.samples = i; + as.callback = audio_callback; + as.userdata = 0; + if (SDL_OpenAudio(&as, 0) == -1) + return; + + pcm.hz = as.freq; + pcm.stereo = as.channels - 1; + pcm.len = as.size; + pcm.buf = malloc(pcm.len); + pcm.pos = 0; + memset(pcm.buf, 0, pcm.len); + + SDL_PauseAudio(0); +} + +int pcm_submit() +{ + if (!pcm.buf) return 0; + if (pcm.pos < pcm.len) return 1; + while (!audio_done) + SDL_Delay(4); + audio_done = 0; + pcm.pos = 0; + return 1; +} + +void pcm_close() +{ + if (sound) SDL_CloseAudio(); +} + + + + + + diff --git a/sys/svga/svgalib.c b/sys/svga/svgalib.c new file mode 100644 index 0000000..3da1f01 --- /dev/null +++ b/sys/svga/svgalib.c @@ -0,0 +1,246 @@ +/* + * svgalib.c + * + * svgalib interface. + */ + + +#include +#include + +#include +#include + +#include "fb.h" +#include "input.h" +#include "rc.h" + + + +struct fb fb; + + + + +static int vmode[3] = { 0, 0, 8 }; +static int svga_mode; +static int svga_vsync = 1; + +rcvar_t vid_exports[] = +{ + RCV_VECTOR("vmode", vmode, 3), + RCV_INT("vsync", &svga_vsync), + RCV_INT("svga_mode", &svga_mode), + RCV_END +}; + + + +/* keymap - mappings of the form { scancode, localcode } - from pc/keymap.c */ +extern int keymap[][2]; + +static int mapscancode(int scan) +{ + int i; + for (i = 0; keymap[i][0]; i++) + if (keymap[i][0] == scan) + return keymap[i][1]; + return 0; +} + +static void kbhandler(int scan, int state) +{ + event_t ev; + ev.type = state ? EV_PRESS : EV_RELEASE; + ev.code = mapscancode(scan); + ev_postevent(&ev); +} + +int *rc_getvec(); + +static int selectmode() +{ + int i; + int stop; + vga_modeinfo *mi; + int best = -1; + int besterr = 1<<24; + int err; + int *vd; + + vd = vmode; + + stop = vga_lastmodenumber(); + for (i = 0; i <= stop; i++) + { + if (!vga_hasmode(i)) continue; + mi = vga_getmodeinfo(i); + + /* modex is too crappy to deal with */ + if (!mi->bytesperpixel) continue; + + /* so are banked modes */ + if (mi->width * mi->height * mi->bytesperpixel > 65536) + if (!(mi->flags & (IS_LINEAR))) continue; + + /* we can't use modes that are too small */ + if (mi->colors < 256) continue; + if (mi->width < vd[0]) continue; + if (mi->height < vd[1]) continue; + + /* perfect matches always win */ + if (mi->width == vd[0] && mi->height == vd[1] + && (mi->bytesperpixel<<3) == vd[2]) + { + best = i; + break; + } + + /* compare error */ + err = mi->width * mi->height - vd[0] * vd[1] + + abs((mi->bytesperpixel<<3)-vd[2]); + if (err < besterr) + { + best = i; + besterr = err; + } + } + if (best < 0) + die("no suitable modes available\n"); + + return best; +} + + + +void vid_preinit() +{ + vga_init(); +} + +void vid_init() +{ + int m; + vga_modeinfo *mi; + + if (!vmode[0] || !vmode[1]) + { + int scale = rc_getint("scale"); + if (scale < 1) scale = 1; + vmode[0] = 160 * scale; + vmode[1] = 144 * scale; + } + + m = svga_mode; + if (!m) m = selectmode(); + + if (!vga_hasmode(m)) + die("no such video mode: %d\n", m); + + vga_setmode(m); + mi = vga_getmodeinfo(m); + fb.w = mi->width; + fb.h = mi->height; + fb.pelsize = mi->bytesperpixel; + fb.pitch = mi->linewidth; + fb.ptr = vga_getgraphmem(); + fb.enabled = 1; + fb.dirty = 0; + + switch (mi->colors) + { + case 256: + fb.indexed = 1; + fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 8; + fb.cc[0].l = fb.cc[1].l = fb.cc[2].l = 0; + break; + case 32768: + fb.indexed = 0; + fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 3; + fb.cc[0].l = 10; + fb.cc[1].l = 5; + fb.cc[2].l = 0; + break; + case 65536: + fb.indexed = 0; + fb.cc[0].r = fb.cc[2].r = 3; + fb.cc[1].r = 2; + fb.cc[0].l = 11; + fb.cc[1].l = 5; + fb.cc[2].l = 0; + break; + case 16384*1024: + fb.indexed = 0; + fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 0; + fb.cc[0].l = 16; + fb.cc[1].l = 8; + fb.cc[2].l = 0; + break; + } + + keyboard_init(); + keyboard_seteventhandler(kbhandler); + + joy_init(); +} + + +void vid_close() +{ + if (!fb.ptr) return; + memset(&fb, 0, sizeof fb); + joy_close(); + keyboard_close(); + vga_setmode(TEXT); +} + +void vid_settitle(char *title) +{ +} + +void vid_setpal(int i, int r, int g, int b) +{ + vga_setpalette(i, r>>2, g>>2, b>>2); +} + +void vid_begin() +{ + if (svga_vsync) vga_waitretrace(); +} + +void vid_end() +{ +} + +void kb_init() +{ +} + +void kb_close() +{ +} + +void kb_poll() +{ + keyboard_update(); +} + +void ev_poll() +{ + kb_poll(); + joy_poll(); +} + + + + + + + + + + + + + + diff --git a/sys/thinlib/keymap.c b/sys/thinlib/keymap.c new file mode 100644 index 0000000..0ad1870 --- /dev/null +++ b/sys/thinlib/keymap.c @@ -0,0 +1,141 @@ +/* + * pckeymap.c + * + * Mappings from IBM-PC scancodes to local key codes. + */ + +#include "input.h" +#include "thinlib.h" + +int keymap[][2] = +{ + { THIN_KEY_ESC, K_ESC }, + { THIN_KEY_1, '1' }, + { THIN_KEY_2, '2' }, + { THIN_KEY_3, '3' }, + { THIN_KEY_4, '4' }, + { THIN_KEY_5, '5' }, + { THIN_KEY_6, '6' }, + { THIN_KEY_7, '7' }, + { THIN_KEY_8, '8' }, + { THIN_KEY_9, '9' }, + { THIN_KEY_0, '0' }, + { THIN_KEY_MINUS, K_MINUS }, + { THIN_KEY_EQUALS, K_EQUALS }, + { THIN_KEY_BACKSPACE, K_BS }, + { THIN_KEY_TAB, K_TAB }, + + { THIN_KEY_Q, 'q' }, + { THIN_KEY_W, 'w' }, + { THIN_KEY_E, 'e' }, + { THIN_KEY_R, 'r' }, + { THIN_KEY_T, 't' }, + { THIN_KEY_Y, 'y' }, + { THIN_KEY_U, 'u' }, + { THIN_KEY_I, 'i' }, + { THIN_KEY_O, 'o' }, + { THIN_KEY_P, 'p' }, + + { THIN_KEY_OPEN_BRACE, '[' }, + { THIN_KEY_CLOSE_BRACE, ']' }, + + { THIN_KEY_ENTER, K_ENTER }, + { THIN_KEY_LEFT_CTRL, K_CTRL }, + + { THIN_KEY_A, 'a' }, + { THIN_KEY_S, 's' }, + { THIN_KEY_D, 'd' }, + { THIN_KEY_F, 'f' }, + { THIN_KEY_G, 'g' }, + { THIN_KEY_H, 'h' }, + { THIN_KEY_J, 'j' }, + { THIN_KEY_K, 'k' }, + { THIN_KEY_L, 'l' }, + + { THIN_KEY_SEMICOLON, K_SEMI }, + { THIN_KEY_QUOTE, '\'' }, + { THIN_KEY_TILDE, K_TILDE }, + { THIN_KEY_LEFT_SHIFT, K_SHIFT }, + { THIN_KEY_BACKSLASH, K_BSLASH }, + + { THIN_KEY_Z, 'z' }, + { THIN_KEY_X, 'x' }, + { THIN_KEY_C, 'c' }, + { THIN_KEY_V, 'v' }, + { THIN_KEY_B, 'b' }, + { THIN_KEY_N, 'n' }, + { THIN_KEY_M, 'm' }, + + { THIN_KEY_COMMA, ',' }, + { THIN_KEY_PERIOD, '.' }, + { THIN_KEY_SLASH, '/' }, + + { THIN_KEY_RIGHT_SHIFT, K_SHIFT }, + + { THIN_KEY_NUMPAD_MULT, K_NUMMUL }, + + { THIN_KEY_LEFT_ALT, K_ALT }, + { THIN_KEY_SPACE, ' ' }, + { THIN_KEY_CAPS_LOCK, K_CAPS }, + + { THIN_KEY_F1, K_F1 }, + { THIN_KEY_F2, K_F2 }, + { THIN_KEY_F3, K_F3 }, + { THIN_KEY_F4, K_F4 }, + { THIN_KEY_F5, K_F5 }, + { THIN_KEY_F6, K_F6 }, + { THIN_KEY_F7, K_F7 }, + { THIN_KEY_F8, K_F8 }, + { THIN_KEY_F9, K_F9 }, + { THIN_KEY_F10, K_F10 }, + + { THIN_KEY_NUM_LOCK, K_NUMLOCK }, + { THIN_KEY_SCROLL_LOCK, K_SCROLL }, + + { THIN_KEY_NUMPAD_7, K_NUM7 }, + { THIN_KEY_NUMPAD_8, K_NUM8 }, + { THIN_KEY_NUMPAD_9, K_NUM9 }, + { THIN_KEY_NUMPAD_MINUS, K_NUMMINUS }, + { THIN_KEY_NUMPAD_4, K_NUM4 }, + { THIN_KEY_NUMPAD_5, K_NUM5 }, + { THIN_KEY_NUMPAD_6, K_NUM6 }, + { THIN_KEY_NUMPAD_PLUS, K_NUMPLUS }, + { THIN_KEY_NUMPAD_1, K_NUM1 }, + { THIN_KEY_NUMPAD_2, K_NUM2 }, + { THIN_KEY_NUMPAD_3, K_NUM3 }, + { THIN_KEY_NUMPAD_0, K_NUM0 }, + { THIN_KEY_NUMPAD_DECIMAL, K_NUMDOT }, + + { THIN_KEY_F11, K_F11 }, + { THIN_KEY_F12, K_F12 }, + + { THIN_KEY_NUMPAD_ENTER, K_NUMENTER }, + { THIN_KEY_RIGHT_CTRL, K_CTRL }, + { THIN_KEY_NUMPAD_DIV, K_NUMDIV }, + { THIN_KEY_SYSRQ, K_SYSRQ }, + + { THIN_KEY_RIGHT_ALT, K_ALT }, + //{ THIN_KEY_PAUSE, K_PAUSE }, + + { THIN_KEY_HOME, K_HOME }, + { THIN_KEY_UP, K_UP }, + { THIN_KEY_PGUP, K_PRIOR }, + { THIN_KEY_LEFT, K_LEFT }, + { THIN_KEY_RIGHT, K_RIGHT }, + { THIN_KEY_END, K_END }, + { THIN_KEY_DOWN, K_DOWN }, + { THIN_KEY_PGDN, K_NEXT }, + { THIN_KEY_INSERT, K_INS }, + { THIN_KEY_DELETE, K_DEL }, + + { 0, 0 } +}; + + + + + + + + + diff --git a/sys/thinlib/lib/Makefile b/sys/thinlib/lib/Makefile new file mode 100644 index 0000000..8c2f994 --- /dev/null +++ b/sys/thinlib/lib/Makefile @@ -0,0 +1,100 @@ +# +# Makefile +# +# thinlib library makefile +# +# Copyright (C) 2001 Matthew Conte (matt@conte.com) +# +# $Id: $ + +################################ +# Configuration + +CFLAGS = -W -Wall -Werror +DBGCFLAGS = -ggdb -DTHINLIB_DEBUG +OPTCFLAGS = -O3 -fomit-frame-pointer -ffast-math + +# Assembler +ASM = nasm +ASMFLAGS = -f coff + +DBGASMFLAGS = -g + +################################ + +# WANT_DEBUG = TRUE + +################################ + +ifeq "$(WANT_DEBUG)" "TRUE" + CFLAGS += $(DBGCFLAGS) + ASMFLAGS += $(DBGASMFLAGS) +else + CFLAGS += $(OPTCFLAGS) +endif + +################################ + +CFILES = tl_main tl_log tl_timer tl_int tl_key tl_mouse tl_joy \ + tl_dpp tl_bmp tl_vesa tl_vga tl_video tl_sb tl_sound \ + tl_event tl_prof + +CSRCS = $(addsuffix .c, $(CFILES)) +OBJS = $(addsuffix .o, $(CFILES)) + +################################ + +.PHONY = all dep clean + +all: libthin.a thintest.exe + +clean: + rm -f libthin.a thintest.exe $(OBJS) _dep + +thintest.exe: thintest.cpp libthin.a + $(CXX) -o $@ thintest.cpp -L. -lthin + +libthin.a: $(OBJS) + rm -f $@ + ar scru $@ $(OBJS) + +dep: rmdep _dep + +################################ + +rmdep: + @rm -f _dep + @echo "# dep file" > _dep +ifneq "$(CSRCS)" "" + @$(foreach .a, $(CSRCS), $(CC) $(CFLAGS) -MM $(.a) >> _dep;) +endif +ifneq "$(ASMSRCS)" "" + @$(foreach .a, $(ASMSRCS), $(ASM) $(ASMFLAGS) -M $(.a) >> _dep;) +endif + +_dep: +# this is done so that we don't get all the no such file warnings + @echo "# dep file" > _dep +ifneq "$(CSRCS)" "" + @$(foreach .a, $(CSRCS), $(CC) $(CFLAGS) -MM $(.a) >> _dep;) +endif +ifneq "$(ASMSRCS)" "" + @$(foreach .a, $(ASMSRCS), $(ASM) $(ASMFLAGS) -M $(.a) >> _dep;) +endif + +include _dep + +################################ + +%.o: %.cpp + $(CXX) $(CFLAGS) -o $@ -c $< + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $< + +%.o: %.asm + $(ASM) $(ASMFLAGS) -o $@ $< + +################################ + +# $Log: $ diff --git a/sys/thinlib/lib/thinlib.h b/sys/thinlib/lib/thinlib.h new file mode 100644 index 0000000..a33b617 --- /dev/null +++ b/sys/thinlib/lib/thinlib.h @@ -0,0 +1,67 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** thinlib.h +** +** main library header +** +** $Id: $ +*/ + +#ifndef _THINLIB_H_ +#define _THINLIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* types */ +#include "tl_types.h" +#include "tl_log.h" +#include "tl_prof.h" + +/* system */ +#include "tl_djgpp.h" +#include "tl_int.h" +#include "tl_timer.h" + +/* input/events */ +#include "tl_event.h" +#include "tl_key.h" +#include "tl_mouse.h" +#include "tl_joy.h" +#include "tl_dpp.h" + +/* video */ +#include "tl_bmp.h" +#include "tl_video.h" + +/* audio */ +#include "tl_sound.h" + +#define THIN_KEY 0x0001 +#define THIN_MOUSE 0x0002 +#define THIN_JOY 0x0004 +#define THIN_DPP 0x0008 +#define THIN_TIMER 0x0010 +#define THIN_VIDEO 0x0020 +#define THIN_SOUND 0x0040 + + +/* main interface */ +extern int thin_init(int devices); +extern void thin_shutdown(void); + +extern void thin_add_exit(void (*func)(void)); +extern void thin_remove_exit(void (*func)(void)); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !_THINLIB_H */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/thintest.cpp b/sys/thinlib/lib/thintest.cpp new file mode 100644 index 0000000..f8d414c --- /dev/null +++ b/sys/thinlib/lib/thintest.cpp @@ -0,0 +1,287 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of version 2 of the GNU Library General +** Public License as published by the Free Software Foundation. +** +** 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 +** Library General Public License for more details. To obtain a +** copy of the GNU Library General Public License, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Any permitted reproduction of these routines, in whole or in part, +** must bear this legend. +** +** +** thintest.cpp +** +** thinlib test +** $Id: thintest.cpp,v 1.3 2001/03/12 06:06:55 matt Exp $ +*/ + +#include +#include +#include +#include "thinlib.h" + +//#define TEST_STEREO +#define TEST_DPP + +class test +{ +public: + test(); + ~test(); + void run(); + +private: + enum + { + SAMPLE_RATE = 44100, + FRAGSIZE = 256, + VID_WIDTH = 320, + VID_HEIGHT = 240, + VID_BPP = 8 + }; + + int testSound(); + int testVideo(); + int testTimer(); + int testEvents(); +}; + +test::test() +{ + int ret = thin_init(THIN_KEY | THIN_MOUSE | THIN_TIMER + | THIN_VIDEO | THIN_SOUND); + THIN_ASSERT(-1 != ret); +} + +test::~test() +{ + thin_shutdown(); +} + +static void fillbuf(void *user_data, void *buf, int size) +{ + static int pos = 0; + UNUSED(user_data); + + while (size--) + { + *((uint8 *) buf)++ = 127 + (int8)(127.0 * sin(2 * PI * pos / 128)); +#ifdef TEST_STEREO + *((uint8 *) buf)++ = 127 + (int8)(127.0 * cos(2 * PI * pos / 128)); +#endif + pos = (pos + 1) & 1023; + } +} + +int test::testSound() +{ + thinsound_t params; + + params.sample_rate = SAMPLE_RATE; + params.frag_size = FRAGSIZE; +#ifdef TEST_STEREO + params.format = THIN_SOUND_STEREO | THIN_SOUND_8BIT; +#else + params.format = THIN_SOUND_MONO | THIN_SOUND_8BIT; +#endif + params.callback = fillbuf; + params.user_data = NULL; + + if (thin_sound_init(¶ms)) + return -1; + + thin_sound_start(); + thin_sound_stop(); + + return 0; +} + +int test::testVideo() +{ + int i, x, y; + bitmap_t *screen; + bitmap_t *buffer; + + /* set up video */ + if (thin_vid_init(VID_WIDTH, VID_HEIGHT, VID_BPP, 0/*THIN_VIDEO_HWSURFACE*/)) + return -1; + + buffer = thin_bmp_create(VID_WIDTH, VID_HEIGHT, VID_BPP, 0); + if (NULL == buffer) + return -1; + + /* fill it up with something interesting */ + for (y = 0; y < buffer->height; y++) + for (x = 0; x < buffer->width; x++) + buffer->line[y][x] = x ^ y; + + /* blit it out 1000 times */ + for (i = 0; i < 1000; i++) + { + screen = thin_vid_lockwrite(); + if (NULL == screen) + return -1; + + for (y = 0; y < screen->height; y++) + memcpy(screen->line[y], buffer->line[y], screen->width); + + thin_vid_freewrite(-1, NULL); + } + + thin_vid_shutdown(); + + if (1000 != i) + return -1; + + return 0; +} + +static volatile int timer_ticks = 0; +static void timer_handler(void *param) +{ + (void) param; + timer_ticks++; +} +THIN_LOCKED_STATIC_FUNC(timer_handler) + +int test::testTimer() +{ + int last_ticks; + + THIN_LOCK_FUNC(timer_handler); + THIN_LOCK_VAR(timer_ticks); + + /* one second intervals... */ + if (thin_timer_init(60, timer_handler, NULL)) + return -1; + + timer_ticks = last_ticks = 0; + while (timer_ticks <= 60) + { + if (last_ticks != timer_ticks) + { + last_ticks = timer_ticks; + thin_printf("%d 60 hz tick\n", last_ticks); + } + } + + thin_timer_shutdown(); + + return 0; +} + +int test::testEvents() +{ + thin_event_t event; + bool done = false; + + thin_mouse_init(80, 20, 1); + thin_joy_init(); + thin_dpp_init(); + thin_dpp_add(0x378, 0); + + thin_printf("event test: press ESC..."); + + while (!done) + { + thin_event_gather(); + + while (thin_event_get(&event)) + { + switch (event.type) + { + case THIN_KEY_PRESS: + if (event.data.keysym == THIN_KEY_ESC) + done = true; + thin_printf("key press\n"); + break; + + case THIN_KEY_RELEASE: + thin_printf("key release\n"); + break; + + case THIN_MOUSE_MOTION: + thin_printf("mouse motion\n"); + break; + + case THIN_MOUSE_BUTTON_PRESS: + thin_printf("mouse button press\n"); + break; + + case THIN_MOUSE_BUTTON_RELEASE: + thin_printf("mouse button release\n"); + break; + + case THIN_JOY_MOTION: + thin_printf("joy motion\n"); + break; + + case THIN_JOY_BUTTON_PRESS: + thin_printf("joy button press\n"); + break; + + case THIN_JOY_BUTTON_RELEASE: + thin_printf("joy button release\n"); + break; + + default: + break; + } + } + } + + thin_dpp_shutdown(); + thin_joy_shutdown(); + thin_mouse_shutdown(); + + return 0; +} + +void test::run() +{ + if (testSound()) + return; + + if (testVideo()) + return; + + if (testTimer()) + return; + + if (testEvents()) + return; + + thin_printf("\ntest complete.\n"); +} + +int main(void) +{ + test *pTest = new test; + + pTest->run(); + + delete pTest; + + return 0; +} + +/* +** $Log: thintest.cpp,v $ +** Revision 1.3 2001/03/12 06:06:55 matt +** better keyboard driver, support for bit depths other than 8bpp +** +** Revision 1.2 2001/02/01 06:28:26 matt +** thinlib now works under NT/2000 +** +** Revision 1.1 2001/01/15 05:27:43 matt +** initial revision +** +*/ diff --git a/sys/thinlib/lib/tl_bmp.c b/sys/thinlib/lib/tl_bmp.c new file mode 100644 index 0000000..536f725 --- /dev/null +++ b/sys/thinlib/lib/tl_bmp.c @@ -0,0 +1,99 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_bmp.c +** +** Bitmap object manipulation routines +** +** $Id: $ +*/ + +#include +#include +#include + +#include "tl_types.h" +#include "tl_bmp.h" + + +#define BPP_PITCH(pitch, bpp) ((pitch) * (((bpp) + 7) / 8)) + + +/* TODO: you can make this faster. */ +void thin_bmp_clear(const bitmap_t *bitmap, uint8 color) +{ + memset(bitmap->data, color, bitmap->pitch * bitmap->height); +} + +static bitmap_t *_make_bitmap(uint8 *data_addr, bool hw, int width, + int height, int bpp, int pitch, int overdraw) +{ + bitmap_t *bitmap; + int i; + + /* sometimes our data address is zero; for instance, setting + ** video selectors for VESA mode with far pointers. so we + ** don't want to bail out if we're passed a zero address. + */ + + /* Make sure to add in space for line pointers */ + bitmap = malloc(sizeof(bitmap_t) + (sizeof(uint8 *) * height)); + if (NULL == bitmap) + return NULL; + + bitmap->hardware = hw; + bitmap->height = height; + bitmap->width = width; + bitmap->bpp = bpp; + bitmap->data = data_addr; + bitmap->pitch = BPP_PITCH(pitch, bpp); + + /* Set up line pointers */ + bitmap->line[0] = bitmap->data + overdraw; + + for (i = 1; i < height; i++) + bitmap->line[i] = bitmap->line[i - 1] + bitmap->pitch; + + return bitmap; +} + +/* Allocate and initialize a bitmap structure */ +bitmap_t *thin_bmp_create(int width, int height, int bpp, int overdraw) +{ + uint8 *addr; + + /* left and right overdraw */ + int pitch = width + (overdraw * 2); + + /* dword align */ + pitch = (pitch + 3) & ~3; + + addr = malloc(height * BPP_PITCH(pitch, bpp)); + if (NULL == addr) + return NULL; + + return _make_bitmap(addr, false, width, height, bpp, pitch, overdraw); +} + +/* allocate and initialize a hardware bitmap */ +bitmap_t *thin_bmp_createhw(uint8 *addr, int width, int height, int bpp, int pitch) +{ + return _make_bitmap(addr, true, width, height, bpp, pitch, 0); /* zero overdraw */ +} + +/* Deallocate space for a bitmap structure */ +void thin_bmp_destroy(bitmap_t **bitmap) +{ + if (*bitmap) + { + if ((*bitmap)->data && false == (*bitmap)->hardware) + free((*bitmap)->data); + free(*bitmap); + *bitmap = NULL; + } +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_bmp.h b/sys/thinlib/lib/tl_bmp.h new file mode 100644 index 0000000..ec2467c --- /dev/null +++ b/sys/thinlib/lib/tl_bmp.h @@ -0,0 +1,47 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_bmp.h +** +** Bitmap object defines / prototypes +** +** $Id: $ +*/ + +#ifndef _TL_BMP_H_ +#define _TL_BMP_H_ + +#include "tl_types.h" + +/* a bitmap rectangle */ +typedef struct rect_s +{ + int16 x, y; + uint16 w, h; +} rect_t; + +typedef struct rgb_s +{ + int r, g, b; +} rgb_t; + +typedef struct bitmap_s +{ + int width, height, pitch; + int bpp; + bool hardware; /* is data a hardware region? */ + uint8 *data; /* protected */ + uint8 *line[0]; /* will hold line pointers */ +} bitmap_t; + +extern void thin_bmp_clear(const bitmap_t *bitmap, uint8 color); +extern bitmap_t *thin_bmp_create(int width, int height, int bpp, int overdraw); +extern bitmap_t *thin_bmp_createhw(uint8 *addr, int width, int height, int bpp, int pitch); +extern void thin_bmp_destroy(bitmap_t **bitmap); + +#endif /* !_TL_BMP_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_djgpp.h b/sys/thinlib/lib/tl_djgpp.h new file mode 100644 index 0000000..7aa914c --- /dev/null +++ b/sys/thinlib/lib/tl_djgpp.h @@ -0,0 +1,34 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_djgpp.h +** +** djgpp frigs +** +** $Id: $ +*/ + +#ifndef _TL_DJGPP_H_ +#define _TL_DJGPP_H_ + +#include + +/* interface to lock code and data */ +#define THIN_LOCKED_FUNC(x) void x##_end(void) { } +#define THIN_LOCKED_STATIC_FUNC(x) static void x##_end(void) { } +#define THIN_LOCK_DATA(d, s) _go32_dpmi_lock_data(d, s) +#define THIN_LOCK_CODE(c, s) _go32_dpmi_lock_code(c, s) +#define THIN_LOCK_VAR(x) THIN_LOCK_DATA((void *) &x, sizeof(x)) +#define THIN_LOCK_FUNC(x) THIN_LOCK_CODE((void *) x, (long) x##_end - (long) x) + +#include +#define THIN_PHYSICAL_ADDR(x) ((x) + __djgpp_conventional_base) + +extern int thinlib_nearptr; + +#endif /* !_TL_DJGPP_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_dpp.c b/sys/thinlib/lib/tl_dpp.c new file mode 100644 index 0000000..f9cacf2 --- /dev/null +++ b/sys/thinlib/lib/tl_dpp.c @@ -0,0 +1,191 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_dpp.c +** +** DOS DirectPad Pro scanning code, based on code from +** DirectPad Pro (www.ziplabel.com), written by Earle F. Philhower, III +** +** $Id: $ +*/ + +#include + +#include "tl_types.h" +#include "tl_dpp.h" +#include "tl_event.h" + +#define MAX_PADS 5 + +#define NES_PWR (0x80 + 0x40 + 0x20 + 0x10 + 0x08) +#define NES_CLK 1 +#define NES_LAT 2 +#define NES_IN ((inportb(port + 1) & nes_din) ^ xor_val) +#define NES_OUT(v) (outportb(port, (v))) + +static const uint8 din_table[MAX_PADS] = { 0x40, 0x20, 0x10, 0x08, 0x80 }; +static const int xor_table[MAX_PADS] = { 1, 1, 1, 1, 0 }; + +static dpp_t dpp[MAX_PADS]; +static event_id dpp_id; /* event callback id */ + +void _dpp_poll(void) +{ + int i; + int nes_din, port, xor_val; + dpp_t *pad, old; + thin_event_t event; + + for (i = 0; i < MAX_PADS; i++) + { + if (0 == dpp[i].port) + continue; + + nes_din = din_table[i]; + port = dpp[i].port; + xor_val = nes_din * xor_table[i]; + pad = &dpp[i]; + old = *pad; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_LAT + NES_CLK); + NES_OUT(NES_PWR); + pad->a = NES_IN; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_CLK); + NES_OUT(NES_PWR); + pad->b = NES_IN; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_CLK); + NES_OUT(NES_PWR); + pad->select = NES_IN; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_CLK); + NES_OUT(NES_PWR); + pad->start = NES_IN; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_CLK); + NES_OUT(NES_PWR); + pad->up = NES_IN; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_CLK); + NES_OUT(NES_PWR); + pad->down = NES_IN; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_CLK); + NES_OUT(NES_PWR); + pad->left = NES_IN; + + NES_OUT(NES_PWR); + NES_OUT(NES_PWR + NES_CLK); + NES_OUT(NES_PWR); + pad->right = NES_IN; + + NES_OUT(0); /* power down */ + + /* generate some events if necessary */ + if (pad->left != old.left) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_LEFT; + event.data.joy_motion.state = pad->left; + thin_event_add(&event); + } + + if (pad->right != old.right) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_RIGHT; + event.data.joy_motion.state = pad->right; + thin_event_add(&event); + } + + if (pad->up != old.up) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_UP; + event.data.joy_motion.state = pad->up; + thin_event_add(&event); + } + + if (pad->down != old.down) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_DOWN; + event.data.joy_motion.state = pad->down; + thin_event_add(&event); + } + + if (pad->select != old.select) + { + event.type = pad->select ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE; + event.data.joy_button = 2; + thin_event_add(&event); + } + + if (pad->start != old.start) + { + event.type = pad->start ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE; + event.data.joy_button = 3; + thin_event_add(&event); + } + + if (pad->b != old.b) + { + event.type = pad->b ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE; + event.data.joy_button = 0; + thin_event_add(&event); + } + + if (pad->a != old.a) + { + event.type = pad->a ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE; + event.data.joy_button = 1; + thin_event_add(&event); + } + } +} + +void thin_dpp_read(dpp_t *pad, int pad_num) +{ + *pad = dpp[pad_num]; +} + +int thin_dpp_add(uint16 port, int pad_num) +{ + dpp[pad_num].port = port; + + return 0; +} + +int thin_dpp_init(void) +{ + dpp_id = thin_event_add_callback((event_callback_t) _dpp_poll); + if (-1 == dpp_id) + return -1; + + return 0; +} + +void thin_dpp_shutdown(void) +{ + if (-1 != dpp_id) + { + thin_event_remove_callback(dpp_id); + dpp_id = -1; + + memset(dpp, 0, sizeof(dpp)); + } +} + + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_dpp.h b/sys/thinlib/lib/tl_dpp.h new file mode 100644 index 0000000..97cebdc --- /dev/null +++ b/sys/thinlib/lib/tl_dpp.h @@ -0,0 +1,35 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_dpp.h +** +** DOS DirectPad Pro scanning code prototypes +** +** $Id: $ +*/ + +#ifndef _TL_DPP_H_ +#define _TL_DPP_H_ + +#include "tl_types.h" + +typedef struct dpp_s +{ +/* private: */ + uint16 port; /* LPT port */ +/* public: */ + int down, up, left, right; + int b, a, select, start; +} dpp_t; + +extern int thin_dpp_add(uint16 port, int pad_num); +extern int thin_dpp_init(void); +extern void thin_dpp_shutdown(void); +extern void thin_dpp_read(dpp_t *pad, int pad_num); + +#endif /* !_TL_DPP_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_event.c b/sys/thinlib/lib/tl_event.c new file mode 100644 index 0000000..5590b32 --- /dev/null +++ b/sys/thinlib/lib/tl_event.c @@ -0,0 +1,140 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_event.c +** +** event handling routines +** +** $Id: $ +*/ + +#include "tl_types.h" +#include "tl_event.h" +#include "tl_djgpp.h" + + +/* maximum of 8 event handling callbacks */ +#define MAX_CALLBACKS 8 + + +#define EVENT_QUEUE_MAX 256 +#define EVENT_QUEUE_MASK (EVENT_QUEUE_MAX - 1) +#define EVENT_QUEUE_EMPTY (event_queue.head == event_queue.tail) + +typedef struct event_queue_s +{ + int head; + int tail; + thin_event_t event[EVENT_QUEUE_MAX]; +} event_queue_t; + + +static event_queue_t event_queue; +static event_callback_t event_callback[MAX_CALLBACKS]; + + +/* add an event. */ +void thin_event_add(thin_event_t *event) +{ + event_queue.event[event_queue.head] = *event; + event_queue.head = (event_queue.head + 1) & EVENT_QUEUE_MASK; +} +THIN_LOCKED_FUNC(thin_event_add) + + +/* get an event from the event queue. returns 0 if no events. */ +int thin_event_get(thin_event_t *event) +{ + if (EVENT_QUEUE_EMPTY) + { + event->type = THIN_NOEVENT; + return 0; + } + + *event = event_queue.event[event_queue.tail]; + event_queue.tail = (event_queue.tail + 1) & EVENT_QUEUE_MASK; + + return 1; +} + + +/* gather up all pollable events */ +void thin_event_gather(void) +{ + int i; + + for (i = 0; i < MAX_CALLBACKS; i++) + { + if (NULL == event_callback[i]) + return; + + event_callback[i](); + } +} + + +/* return an ID of an event callback */ +event_id thin_event_add_callback(event_callback_t callback) +{ + event_id id; + + for (id = 0; id < MAX_CALLBACKS; id++) + { + if (NULL == event_callback[id]) + break; + } + + /* no event callbacks available */ + if (id == MAX_CALLBACKS) + return (event_id) -1; + + event_callback[id] = callback; + + return id; +} + + +/* remove an event callback */ +void thin_event_remove_callback(event_id id) +{ + THIN_ASSERT(id >= 0 && id < MAX_CALLBACKS); + + if (id < 0 || id >= MAX_CALLBACKS) + return; + + THIN_ASSERT(NULL != event_callback[id]); + + event_callback[id] = NULL; + + /* move all other callbacks down */ + for (; id < MAX_CALLBACKS - 1; id++) + { + event_callback[id] = event_callback[id + 1]; + event_callback[id + 1] = NULL; + } +} + + +/* set up the event handling system */ +void thin_event_init(void) +{ + int i; + + /* some modules call thin_event_add from an ISR, so we must + ** lock everythig that is touched within that function, as + ** well as the code itself. + */ + THIN_LOCK_FUNC(thin_event_add); + THIN_LOCK_VAR(event_queue); + + for (i = 0; i < MAX_CALLBACKS; i++) + event_callback[i] = NULL; + + event_queue.head = event_queue.tail = 0; +} + + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_event.h b/sys/thinlib/lib/tl_event.h new file mode 100644 index 0000000..432f7e7 --- /dev/null +++ b/sys/thinlib/lib/tl_event.h @@ -0,0 +1,80 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_event.h +** +** event handling routines +** +** $Id: $ +*/ + +#ifndef _TL_EVENT_H_ +#define _TL_EVENT_H_ + +typedef void (*event_callback_t)(void); +typedef int event_id; + +enum +{ + THIN_NOEVENT = 0, + THIN_KEY_PRESS, + THIN_KEY_RELEASE, + THIN_MOUSE_MOTION, + THIN_MOUSE_BUTTON_PRESS, + THIN_MOUSE_BUTTON_RELEASE, + THIN_JOY_MOTION, + THIN_JOY_BUTTON_PRESS, + THIN_JOY_BUTTON_RELEASE, + THIN_USER_EVENT, +}; + +enum +{ + THIN_JOY_LEFT, + THIN_JOY_RIGHT, + THIN_JOY_UP, + THIN_JOY_DOWN, +}; + +typedef struct thin_event_s +{ + int type; + union + { + /* keyboard */ + int keysym; + /* mouse motion */ + struct + { + int xpos; + int ypos; + } mouse_motion; + /* mouse button */ + int mouse_button; + /* joy motion */ + struct + { + int dir; + int state; + } joy_motion; + /* joy button */ + int joy_button; + /* user event */ + int user_data; + } data; +} thin_event_t; + +extern void thin_event_add(thin_event_t *event); +extern int thin_event_get(thin_event_t *event); +extern void thin_event_gather(void); +extern event_id thin_event_add_callback(event_callback_t callback); +extern void thin_event_remove_callback(event_id id); +extern void thin_event_init(void); + + +#endif /* !_TL_EVENT_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_int.c b/sys/thinlib/lib/tl_int.c new file mode 100644 index 0000000..cfa771f --- /dev/null +++ b/sys/thinlib/lib/tl_int.c @@ -0,0 +1,262 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_int.c +** +** thinlib interrupt handling. Thanks to Shawn Hargreaves +** and the Allegro project for providing adequate interrupt +** documentation. +** +** $Id: $ +*/ + +#include +#include +#include +#include "thinlib.h" +#include "tl_types.h" +#include "tl_log.h" +#include "tl_djgpp.h" +#include "tl_int.h" + +#define PIC1_PORT 0x21 +#define PIC2_PORT 0xA1 + +/* Interrupt stuff */ +typedef struct intr_s +{ + _go32_dpmi_seginfo old_interrupt; + _go32_dpmi_seginfo new_interrupt; + uint8 irq_vector; + inthandler_t handler; +} intr_t; + +#define MAX_INTR 8 + +static bool pic_modified = false; +static uint8 pic1_mask, pic2_mask; +static uint8 pic1_orig, pic2_orig; + +static intr_t intr[MAX_INTR]; +static bool thin_int_locked = false; + + +#define MAKE_INT_HANDLER(num) \ +static void _int_handler_##num##(void) \ +{ \ + /* chain if necessary */ \ + if (intr[(num)].handler()) \ + { \ + void (*func)() = (void *) intr[(num)].old_interrupt.pm_offset; \ + func(); \ + } \ +} \ +THIN_LOCKED_STATIC_FUNC(_int_handler_##num##); + +MAKE_INT_HANDLER(0) +MAKE_INT_HANDLER(1) +MAKE_INT_HANDLER(2) +MAKE_INT_HANDLER(3) +MAKE_INT_HANDLER(4) +MAKE_INT_HANDLER(5) +MAKE_INT_HANDLER(6) +MAKE_INT_HANDLER(7) + +int thin_int_install(int chan, inthandler_t handler) +{ + int i; + + if (chan < 0)// || chan >= MAX_INTR) + return -1; + + if (NULL == handler) + return -1; + + if (false == thin_int_locked) + { + int i; + + for (i = 0; i < MAX_INTR; i++) + { + intr[i].handler = NULL; + intr[i].irq_vector = 0; + } + + THIN_LOCK_VAR(intr); + THIN_LOCK_FUNC(_int_handler_0); + THIN_LOCK_FUNC(_int_handler_1); + THIN_LOCK_FUNC(_int_handler_2); + THIN_LOCK_FUNC(_int_handler_3); + THIN_LOCK_FUNC(_int_handler_4); + THIN_LOCK_FUNC(_int_handler_5); + THIN_LOCK_FUNC(_int_handler_6); + THIN_LOCK_FUNC(_int_handler_7); + + thin_int_locked = true; + } + + /* find a free slot */ + for (i = 0; i < MAX_INTR; i++) + { + if (NULL == intr[i].handler) + { + intr_t *pintr = &intr[i]; + + pintr->new_interrupt.pm_selector = _go32_my_cs(); + + switch (i) + { + case 0: pintr->new_interrupt.pm_offset = (int) _int_handler_0; break; + case 1: pintr->new_interrupt.pm_offset = (int) _int_handler_1; break; + case 2: pintr->new_interrupt.pm_offset = (int) _int_handler_2; break; + case 3: pintr->new_interrupt.pm_offset = (int) _int_handler_3; break; + case 4: pintr->new_interrupt.pm_offset = (int) _int_handler_4; break; + case 5: pintr->new_interrupt.pm_offset = (int) _int_handler_5; break; + case 6: pintr->new_interrupt.pm_offset = (int) _int_handler_6; break; + case 7: pintr->new_interrupt.pm_offset = (int) _int_handler_7; break; + default: return -1; + } + + pintr->new_interrupt.pm_offset = (int) handler; + + pintr->handler = handler; + pintr->irq_vector = chan; + + _go32_dpmi_get_protected_mode_interrupt_vector(pintr->irq_vector, &pintr->old_interrupt); + _go32_dpmi_allocate_iret_wrapper(&pintr->new_interrupt); + _go32_dpmi_set_protected_mode_interrupt_vector(pintr->irq_vector, &pintr->new_interrupt); + + return 0; + } + } + + return -1; /* none free */ +} + +void thin_int_remove(int chan) +{ + int i; + + for (i = 0; i < MAX_INTR; i++) + { + intr_t *pintr = &intr[i]; + if (pintr->irq_vector == chan && pintr->handler != NULL) + { + _go32_dpmi_set_protected_mode_interrupt_vector(pintr->irq_vector, &pintr->old_interrupt); + _go32_dpmi_free_iret_wrapper(&pintr->new_interrupt); + + pintr->handler = NULL; + pintr->irq_vector = 0; + break; + } + } +} + +/* helper routines for the irq masking */ +static void _irq_exit(void) +{ + if (pic_modified) + { + pic_modified = false; + outportb(0x21, pic1_orig); + outportb(0xA1, pic2_orig); + thin_remove_exit(_irq_exit); + } +} + +static void _irq_init(void) +{ + if (false == pic_modified) + { + pic_modified = true; + + /* read initial PIC values */ + pic1_orig = inportb(0x21); + pic2_orig = inportb(0xA1); + + pic1_mask = 0; + pic2_mask = 0; + + thin_add_exit(_irq_exit); + } +} + + +/* restore original mask for interrupt */ +void thin_irq_restore(int irq) +{ + if (pic_modified) + { + uint8 pic; + + if (irq > 7) + { + pic = inportb(0xA1) & ~(1 << (irq - 8)); + outportb(0xA1, pic | (pic2_orig & (1 << (irq - 8)))); + pic2_mask &= ~(1 << (irq - 8)); + + if (pic2_mask) + return; + + irq = 2; /* restore cascade if no high IRQs remain */ + } + + pic = inportb(0x21) & ~(1 << irq); + outportb(0x21, pic | (pic1_orig & (1 << irq))); + pic1_mask &= ~(1 << irq); + } +} + +/* unmask an interrupt */ +void thin_irq_enable(int irq) +{ + uint8 pic; + + _irq_init(); + + pic = inportb(0x21); + + if (irq > 7) + { + /* unmask cascade (IRQ2) interrupt */ + //outportb(0x21, pic & 0xFB); + outportb(0x21, pic & ~(1 << 2)); + pic = inportb(0xA1); + outportb(0xA1, pic & ~(1 << (irq - 8))); + pic2_mask |= 1 << (irq - 8); + } + else + { + outportb(0x21, pic & ~(1 << irq)); + pic1_mask |= 1 << irq; + } +} + +/* mask an interrupt */ +void thin_irq_disable(int irq) +{ + uint8 pic; + + _irq_init(); + + if (irq > 7) + { + /* PIC 2 */ + pic = inportb(0xA1); + outportb(0xA1, pic & (1 << (irq - 8))); + pic2_mask |= 1 << (irq - 8); + } + else + { + /* PIC 1 */ + pic = inportb(0x21); + outportb(0x21, pic & (1 << irq)); + pic1_mask |= 1 << irq; + } +} + + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_int.h b/sys/thinlib/lib/tl_int.h new file mode 100644 index 0000000..fa4d6e0 --- /dev/null +++ b/sys/thinlib/lib/tl_int.h @@ -0,0 +1,31 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_int.h +** +** interrupt handling stuff +** +** $Id: $ +*/ + +#ifndef _TL_INT_H_ +#define _TL_INT_H_ + +#define THIN_DISABLE_INTS() __asm__ __volatile__ ("cli") +#define THIN_ENABLE_INTS() __asm__ __volatile__ ("sti") + +typedef int (*inthandler_t)(void); + +extern int thin_int_install(int chan, inthandler_t handler); +extern void thin_int_remove(int chan); + +extern void thin_irq_restore(int irq); +extern void thin_irq_enable(int irq); +extern void thin_irq_disable(int irq); + +#endif /* !_TL_INT_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_joy.c b/sys/thinlib/lib/tl_joy.c new file mode 100644 index 0000000..ba220e4 --- /dev/null +++ b/sys/thinlib/lib/tl_joy.c @@ -0,0 +1,204 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_joy.c +** +** DOS joystick reading routines +** +** $Id: $ +*/ + +#include + +#include "tl_types.h" +#include "tl_int.h" +#include "tl_joy.h" +#include "tl_event.h" + +#define JOY_PORT 0x201 +#define JOY_TIMEOUT 10000 + +#define J1_A 0x10 +#define J1_B 0x20 +#define J2_A 0x40 +#define J2_B 0x80 + +#define J1_X 0x01 +#define J1_Y 0x02 +#define J2_X 0x04 +#define J2_Y 0x08 + +#define JOY_CENTER 0xAA +#define JOY_MIN_THRESH 0.7 +#define JOY_MAX_THRESH 1.3 + +static struct joyinfo_s +{ + int id; /* callback ID */ + int x_minthresh, x_maxthresh; + int y_minthresh, y_maxthresh; + int x_read, y_read; + uint8 button_state; + bool disconnected; +} joyinfo; + +static joy_t joystick; + +/* Read data in from joy port */ +static int _portread(void) +{ + /* Set timeout to max number of samples */ + int timeout = JOY_TIMEOUT; + uint8 port_val; + + joyinfo.x_read = 0; + joyinfo.y_read = 0; + + THIN_DISABLE_INTS(); + + /* Clear the latch and request a sample */ + port_val = inportb(JOY_PORT); + outportb(JOY_PORT, port_val); + + do + { + port_val = inportb(JOY_PORT); + if (port_val & J1_X) + joyinfo.x_read++; + if (port_val & J1_Y) + joyinfo.y_read++; + } + while (--timeout && (port_val & 3)); + + joyinfo.button_state = port_val; + + THIN_ENABLE_INTS(); + + if (0 == timeout) + return -1; + else + return 0; +} + +void _poll_joystick(void) +{ + int i; + joy_t old; + thin_event_t event; + + old = joystick; + + if (_portread()) + { + joyinfo.disconnected = true; + return; + } + + /* Calc X axis */ + joystick.left = (joyinfo.x_read < joyinfo.x_minthresh) ? true : false; + joystick.right = (joyinfo.x_read > joyinfo.x_maxthresh) ? true : false; + + /* Calc Y axis */ + joystick.up = (joyinfo.y_read < joyinfo.y_minthresh) ? true : false; + joystick.down = (joyinfo.y_read > joyinfo.y_maxthresh) ? true : false; + + /* Get button status */ + /* note that buttons returned by hardware are inverted logic */ + joystick.button[0] = (joyinfo.button_state & J1_A) ? false : true; + joystick.button[1] = (joyinfo.button_state & J2_A) ? false : true; + joystick.button[2] = (joyinfo.button_state & J1_B) ? false : true; + joystick.button[3] = (joyinfo.button_state & J2_B) ? false : true; + + /* generate some events if necessary */ + if (joystick.left != old.left) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_LEFT; + event.data.joy_motion.state = joystick.left; + thin_event_add(&event); + } + + if (joystick.right != old.right) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_RIGHT; + event.data.joy_motion.state = joystick.right; + thin_event_add(&event); + } + + if (joystick.up != old.up) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_UP; + event.data.joy_motion.state = joystick.up; + thin_event_add(&event); + } + + if (joystick.down != old.down) + { + event.type = THIN_JOY_MOTION; + event.data.joy_motion.dir = THIN_JOY_DOWN; + event.data.joy_motion.state = joystick.down; + thin_event_add(&event); + } + + for (i = 0; i < JOY_MAX_BUTTONS; i++) + { + if (joystick.button[i] != old.button[i]) + { + event.type = joystick.button[i] ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE; + event.data.joy_button = i; + + thin_event_add(&event); + } + } +} + +int thin_joy_read(joy_t *joy) +{ + if (joyinfo.disconnected) + return -1; + + *joy = joystick; + + return 0; +} + +/* Detect presence of joystick */ +int thin_joy_init(void) +{ + joyinfo.disconnected = true; + + if (_portread()) + return -1; + + joyinfo.id = thin_event_add_callback((event_callback_t) _poll_joystick); + if (-1 == joyinfo.id) + return -1; + + joyinfo.disconnected = false; + + /* Set the threshhold */ + joyinfo.x_minthresh = JOY_MIN_THRESH * joyinfo.x_read; + joyinfo.x_maxthresh = JOY_MAX_THRESH * joyinfo.x_read; + joyinfo.y_minthresh = JOY_MIN_THRESH * joyinfo.y_read; + joyinfo.y_maxthresh = JOY_MAX_THRESH * joyinfo.y_read; + + return 0; +} + +void thin_joy_shutdown(void) +{ + joyinfo.disconnected = true; + + if (-1 != joyinfo.id) + { + thin_event_remove_callback(joyinfo.id); + joyinfo.id = -1; + } +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_joy.h b/sys/thinlib/lib/tl_joy.h new file mode 100644 index 0000000..e0656f8 --- /dev/null +++ b/sys/thinlib/lib/tl_joy.h @@ -0,0 +1,31 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_joy.h +** +** DOS joystick reading defines / protos +** +** $Id: $ +*/ + +#ifndef _TL_JOY_H_ +#define _TL_JOY_H_ + +#define JOY_MAX_BUTTONS 4 + +typedef struct joy_s +{ + int left, right, up, down; + int button[JOY_MAX_BUTTONS]; +} joy_t; + +extern void thin_joy_shutdown(void); +extern int thin_joy_init(void); +extern int thin_joy_read(joy_t *joy); + +#endif /* !_TL_JOY_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_key.c b/sys/thinlib/lib/tl_key.c new file mode 100644 index 0000000..12b89d0 --- /dev/null +++ b/sys/thinlib/lib/tl_key.c @@ -0,0 +1,125 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_key.c +** +** DOS keyboard handler +** +** $Id: $ +*/ + +#include +#include +#include +#include + +#include "tl_types.h" +#include "tl_djgpp.h" +#include "tl_key.h" +#include "tl_event.h" + +#define KEYBOARD_INT 0x09 + +/* maybe make this globally accessible? */ +static int key_status[THIN_MAX_KEYS]; +static bool key_repeat = false; +static bool ext_key = false; + +static _go32_dpmi_seginfo old_key_handler; +static _go32_dpmi_seginfo new_key_handler; + + +static const uint8 ext_tab[0x80] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08 - 0x0F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x17 */ + 0, 0, 0, 0, THIN_KEY_NUMPAD_ENTER, THIN_KEY_RIGHT_CTRL, 0, 0, /* 0x10 - 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28 - 0x2F */ + 0, 0, 0, 0, 0, THIN_KEY_NUMPAD_DIV, 0, THIN_KEY_SYSRQ, /* 0x30 - 0x37 */ + THIN_KEY_RIGHT_ALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38 - 0x3F */ + 0, 0, 0, 0, 0, 0, THIN_KEY_BREAK, THIN_KEY_HOME, /* 0x40 - 0x47 */ + THIN_KEY_UP, THIN_KEY_PGUP, 0, THIN_KEY_LEFT, 0, THIN_KEY_RIGHT, 0, THIN_KEY_END, /* 0x48 - 0x4F */ + THIN_KEY_DOWN, THIN_KEY_PGDN, THIN_KEY_INSERT, THIN_KEY_DELETE, /* 0x50 - 0x57 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x67 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78 - 0x7F */ +}; + +/* keyboard ISR */ +static void key_handler(void) +{ + thin_event_t event; + uint8 raw_code, ack_code; + + /* read the key */ + raw_code = inportb(0x60); + ack_code = inportb(0x61); + outportb(0x61, ack_code | 0x80); + outportb(0x61, ack_code); + outportb(0x20, 0x20); + + if (0xE0 == raw_code) + { + ext_key = true; + } + else + { + if (ext_key) + { + ext_key = false; + event.data.keysym = ext_tab[raw_code & 0x7F]; + } + else + { + event.data.keysym = raw_code & 0x7F; + } + + event.type = (raw_code & 0x80) ? THIN_KEY_RELEASE : THIN_KEY_PRESS; + + if (key_repeat || (event.type != key_status[event.data.keysym])) + { + key_status[event.data.keysym] = event.type; + thin_event_add(&event); + } + } +} +THIN_LOCKED_STATIC_FUNC(key_handler) + +void thin_key_set_repeat(bool state) +{ + key_repeat = state; +} + +/* set up variables, lock code/data, set the new handler and save old one */ +int thin_key_init(void) +{ + THIN_LOCK_FUNC(key_handler); + THIN_LOCK_VAR(key_status); + THIN_LOCK_VAR(ext_key); + + _go32_dpmi_get_protected_mode_interrupt_vector(KEYBOARD_INT, &old_key_handler); + new_key_handler.pm_offset = (uint32) key_handler; + new_key_handler.pm_selector = _go32_my_cs(); + _go32_dpmi_allocate_iret_wrapper(&new_key_handler); + _go32_dpmi_set_protected_mode_interrupt_vector(KEYBOARD_INT, &new_key_handler); + + memset(key_status, THIN_KEY_RELEASE, sizeof(key_status)); + + return 0; /* can't fail */ +} + +/* restore old keyboard handler */ +void thin_key_shutdown(void) +{ + _go32_dpmi_set_protected_mode_interrupt_vector(KEYBOARD_INT, &old_key_handler); + _go32_dpmi_free_iret_wrapper(&new_key_handler); +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_key.h b/sys/thinlib/lib/tl_key.h new file mode 100644 index 0000000..ab34032 --- /dev/null +++ b/sys/thinlib/lib/tl_key.h @@ -0,0 +1,146 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_key.h +** +** DOS keyboard handling defines / protos +** +** $Id: $ +*/ + +#ifndef _TL_KEY_H_ +#define _TL_KEY_H_ + +/* Keyboard scancodes */ +#define THIN_KEY_ESC 1 +#define THIN_KEY_1 2 +#define THIN_KEY_2 3 +#define THIN_KEY_3 4 +#define THIN_KEY_4 5 +#define THIN_KEY_5 6 +#define THIN_KEY_6 7 +#define THIN_KEY_7 8 +#define THIN_KEY_8 9 +#define THIN_KEY_9 10 +#define THIN_KEY_0 11 +#define THIN_KEY_MINUS 12 +#define THIN_KEY_EQUALS 13 +#define THIN_KEY_BACKSPACE 14 +#define THIN_KEY_TAB 15 +#define THIN_KEY_Q 16 +#define THIN_KEY_W 17 +#define THIN_KEY_E 18 +#define THIN_KEY_R 19 +#define THIN_KEY_T 20 +#define THIN_KEY_Y 21 +#define THIN_KEY_U 22 +#define THIN_KEY_I 23 +#define THIN_KEY_O 24 +#define THIN_KEY_P 25 +#define THIN_KEY_OPEN_BRACE 26 +#define THIN_KEY_CLOSE_BRACE 27 +#define THIN_KEY_ENTER 28 +#define THIN_KEY_LEFT_CTRL 29 +#define THIN_KEY_A 30 +#define THIN_KEY_S 31 +#define THIN_KEY_D 32 +#define THIN_KEY_F 33 +#define THIN_KEY_G 34 +#define THIN_KEY_H 35 +#define THIN_KEY_J 36 +#define THIN_KEY_K 37 +#define THIN_KEY_L 38 +#define THIN_KEY_SEMICOLON 39 +#define THIN_KEY_QUOTE 40 +#define THIN_KEY_TILDE 41 +#define THIN_KEY_LEFT_SHIFT 42 +#define THIN_KEY_BACKSLASH 43 +#define THIN_KEY_Z 44 +#define THIN_KEY_X 45 +#define THIN_KEY_C 46 +#define THIN_KEY_V 47 +#define THIN_KEY_B 48 +#define THIN_KEY_N 49 +#define THIN_KEY_M 50 +#define THIN_KEY_COMMA 51 +#define THIN_KEY_PERIOD 52 +#define THIN_KEY_SLASH 53 +#define THIN_KEY_RIGHT_SHIFT 54 +#define THIN_KEY_NUMPAD_MULT 55 +#define THIN_KEY_LEFT_ALT 56 +#define THIN_KEY_SPACE 57 +#define THIN_KEY_CAPS_LOCK 58 +#define THIN_KEY_F1 59 +#define THIN_KEY_F2 60 +#define THIN_KEY_F3 61 +#define THIN_KEY_F4 62 +#define THIN_KEY_F5 63 +#define THIN_KEY_F6 64 +#define THIN_KEY_F7 65 +#define THIN_KEY_F8 66 +#define THIN_KEY_F9 67 +#define THIN_KEY_F10 68 +#define THIN_KEY_NUM_LOCK 69 +#define THIN_KEY_SCROLL_LOCK 70 + +#define THIN_KEY_F11 87 +#define THIN_KEY_F12 88 + +#define THIN_KEY_NUMPAD_7 71 +#define THIN_KEY_NUMPAD_8 72 +#define THIN_KEY_NUMPAD_9 73 +#define THIN_KEY_NUMPAD_MINUS 74 +#define THIN_KEY_NUMPAD_4 75 +#define THIN_KEY_NUMPAD_5 76 +#define THIN_KEY_NUMPAD_6 77 +#define THIN_KEY_NUMPAD_PLUS 78 +#define THIN_KEY_NUMPAD_1 79 +#define THIN_KEY_NUMPAD_2 80 +#define THIN_KEY_NUMPAD_3 81 +#define THIN_KEY_NUMPAD_0 82 +#define THIN_KEY_NUMPAD_DECIMAL 83 + +/* TODO: investigate */ +/*#define THIN_KEY_PRINT_SCREEN 84*/ + +/* TODO: are these correct? +** I don't have one of them new winders keyboards. +*/ +#define THIN_KEY_LEFT_WINDOWS 91 +#define THIN_KEY_RIGHT_WINDOWS 92 +#define THIN_KEY_MENU 93 + +/* extended keys */ +#define THIN_KEY_RIGHT_ALT 100 +#define THIN_KEY_RIGHT_CTRL 101 +#define THIN_KEY_NUMPAD_DIV 102 +#define THIN_KEY_NUMPAD_ENTER 103 +#define THIN_KEY_UP 104 +#define THIN_KEY_DOWN 105 +#define THIN_KEY_LEFT 106 +#define THIN_KEY_RIGHT 107 +#define THIN_KEY_INSERT 108 +#define THIN_KEY_HOME 109 +#define THIN_KEY_PGUP 110 +#define THIN_KEY_DELETE 111 +#define THIN_KEY_END 112 +#define THIN_KEY_PGDN 113 + +#define THIN_KEY_BREAK 114 +#define THIN_KEY_SYSRQ 116 + +/* PAUSE generates a ^X sequence... bleh */ +/*#define THIN_KEY_PAUSE 115*/ + +#define THIN_MAX_KEYS 128 + +extern int thin_key_init(void); +extern void thin_key_shutdown(void); +extern void thin_key_set_repeat(bool state); + +#endif /* !_TL_KEY_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_log.c b/sys/thinlib/lib/tl_log.c new file mode 100644 index 0000000..2a92da0 --- /dev/null +++ b/sys/thinlib/lib/tl_log.c @@ -0,0 +1,59 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_log.c +** +** Error logging functions +** +** $Id: $ +*/ + +#include +#include +#include +#include "tl_types.h" +#include "tl_log.h" + +#define MAX_LOG_BUF_SIZE 1024 + +static int (*log_func)(const char *format, ... ) = printf; + +void thin_printf(const char *format, ... ) +{ + /* don't allocate on stack every call */ + static char buffer[MAX_LOG_BUF_SIZE + 1]; + va_list arg; + + va_start(arg, format); + + if (NULL != log_func) + { + vsprintf(buffer, format, arg); + log_func(buffer); + } + + va_end(arg); +} + +void thin_setlogfunc(int (*func)(const char *format, ... )) +{ + log_func = func; +} + +void thin_assert(int expr, int line, const char *file, char *msg) +{ + if (expr) + return; + + if (NULL != msg) + thin_printf("THIN_ASSERT: line %d of %s, %s\n", line, file, msg); + else + thin_printf("THIN_ASSERT: line %d of %s\n", line, file); + + exit(-1); +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_log.h b/sys/thinlib/lib/tl_log.h new file mode 100644 index 0000000..c5d1115 --- /dev/null +++ b/sys/thinlib/lib/tl_log.h @@ -0,0 +1,23 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_log.h +** +** Error logging header file +** +** $Id: $ +*/ + +#ifndef _TL_LOG_H_ +#define _TL_LOG_H_ + +extern void thin_printf(const char *format, ... ); +extern void thin_setlogfunc(int (*logfunc)(const char *string, ... )); +extern void thin_assert(int expr, int line, const char *file, char *msg); + +#endif /* !_TL_LOG_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_main.c b/sys/thinlib/lib/tl_main.c new file mode 100644 index 0000000..8095dc6 --- /dev/null +++ b/sys/thinlib/lib/tl_main.c @@ -0,0 +1,179 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_main.c +** +** main library init / shutdown code +** +** $Id: $ +*/ + +#include "tl_types.h" +#include "thinlib.h" + +#include "tl_timer.h" + +#include "tl_event.h" +#include "tl_key.h" +#include "tl_joy.h" +#include "tl_dpp.h" + +#include "tl_sound.h" +#include "tl_video.h" +#include "tl_djgpp.h" + +#include +#include + +/* our global "near pointer" flag. */ +int thinlib_nearptr = 0; +static int initialized_flags = 0; +static bool shutdown_called = false; + +typedef void (*funcptr_t)(void); +#define MAX_EXIT_FUNCS 32 + +static funcptr_t exit_func[MAX_EXIT_FUNCS]; + +void thin_add_exit(void (*func)(void)) +{ + int i; + + for (i = 0; i < MAX_EXIT_FUNCS; i++) + { + if (NULL == exit_func[i] || func == exit_func[i]) + { + exit_func[i] = func; + break; + } + } +} + +void thin_remove_exit(void (*func)(void)) +{ + int i; + + for (i = 0; i < MAX_EXIT_FUNCS; i++) + { + if (func == exit_func[i]) + { + while (i < MAX_EXIT_FUNCS - 1) + { + exit_func[i] = exit_func[i - 1]; + i++; + } + exit_func[MAX_EXIT_FUNCS - 1] = NULL; + break; + } + } +} + +int thin_init(int devices) +{ + int success = devices; + + /* set up our crt0 flags the way we want them. This might be a + ** bit too late (i.e. crt0.s/stub has already been executed), but + ** we might as well try. + */ + _crt0_startup_flags &= ~_CRT0_FLAG_UNIX_SBRK; + _crt0_startup_flags |= _CRT0_FLAG_NONMOVE_SBRK; + + /* Try to enable near pointers through djgpp's default mechanism. + ** This allows us to manipulate memory-mapped devices (sound cards, + ** video cards, etc.) as if they were regular memory addresses, at + ** the cost of disabling memory protection. Win NT and 2000 strictly + ** disallow near pointers, so we need to flag this. + */ + thinlib_nearptr = __djgpp_nearptr_enable(); + + /* open up event handler */ + thin_event_init(); + + if (devices & THIN_KEY) + { + if (thin_key_init()) + success &= ~THIN_KEY; + } + + if (devices & THIN_JOY) + { + if (thin_joy_init()) + success &= ~THIN_JOY; + } + + if (devices & THIN_DPP) + { + if (thin_dpp_init()) + success &= ~THIN_DPP; + } + + /* THIN_SOUND, THIN_VIDEO, THIN_TIMER implicitly successful.. */ + + initialized_flags = success; + + /* set up our atexit routine */ + atexit(thin_shutdown); + shutdown_called = false; + + return success; +} + +void thin_shutdown(void) +{ + int i; + + /* thin_shutdown is an atexit() registered routine, so make sure + ** that we don't get called multiple times. + */ + if (shutdown_called) + return; + + for (i = MAX_EXIT_FUNCS - 1; i >= 0; i--) + { + if (exit_func[i]) + { + exit_func[i](); + exit_func[i] = NULL; + } + } + + /* not started from thin_init */ + thin_sound_shutdown(); + thin_timer_shutdown(); + thin_vid_shutdown(); + + /* started from thin_init... */ + if (initialized_flags & THIN_KEY) + thin_key_shutdown(); + + if (initialized_flags & THIN_JOY) + thin_joy_shutdown(); + + if (initialized_flags & THIN_DPP) + thin_dpp_shutdown(); + + /* back to memory protection, if need be */ + if (thinlib_nearptr) + __djgpp_nearptr_disable(); + + shutdown_called = true; +} + +/* Reduce size of djgpp executable */ +char **__crt0_glob_function(char *_argument) +{ + UNUSED(_argument); + return (char **) 0; +} + +/* Reduce size of djgpp executable */ +void __crt0_load_environment_file(char *_app_name) +{ + UNUSED(_app_name); +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_mouse.c b/sys/thinlib/lib/tl_mouse.c new file mode 100644 index 0000000..d9a6782 --- /dev/null +++ b/sys/thinlib/lib/tl_mouse.c @@ -0,0 +1,223 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_mouse.c +** +** DOS mouse handling routines +** +** $Id: $ +*/ + +/* TODO: add events to motion/button presses. */ +/* TODO: mouse interrupt based? */ + +#include +#include +#include + +#include "tl_types.h" +#include "tl_mouse.h" +#include "tl_event.h" + +#define MOUSE_FIX 8 // 24.8 fixpoint + +#define MOUSE_INT 0x33 +#define INT_GET_MICKEYS 0x0B +#define INT_GET_BUTTONS 0x03 + +static struct mouse_s +{ + int xpos, ypos; + int xdelta, ydelta; + int maxwidth, maxheight; + int num_buttons; + int delta_shift; + uint8 button; + bool enabled; + event_id id; +} mouse; + +static void _get_mickeys(int *dx, int *dy) +{ + __dpmi_regs r; + + /* get mickeys */ + r.x.ax = INT_GET_MICKEYS; + __dpmi_int(MOUSE_INT, &r); + *dx = (int16) r.x.cx; + *dy = (int16) r.x.dx; +} + +static uint8 _get_buttons(void) +{ + __dpmi_regs r; + uint8 left, middle, right; + + r.x.ax = INT_GET_BUTTONS; + __dpmi_int(MOUSE_INT, &r); + + left = (r.x.bx & 1); + right = ((r.x.bx >> 1) & 1); + middle = ((r.x.bx >> 2) & 1); + + return (right << THIN_MOUSE_RIGHT + | middle << THIN_MOUSE_MIDDLE + | left << THIN_MOUSE_LEFT); +} + +static void _mouse_poll(void) +{ + int mick_x, mick_y; + int old_x, old_y; + int old_button; + + if (false == mouse.enabled) + return; + + _get_mickeys(&mick_x, &mick_y); + + mick_x <<= (MOUSE_FIX - mouse.delta_shift); + mick_y <<= (MOUSE_FIX - mouse.delta_shift); + + old_x = mouse.xpos; + old_y = mouse.ypos; + mouse.xpos += mick_x; + mouse.ypos += mick_y; + + if (mouse.xpos < 0) + mouse.xpos = 0; + else if (mouse.xpos > mouse.maxwidth) + mouse.xpos = mouse.maxwidth; + + if (mouse.ypos < 0) + mouse.ypos = 0; + else if (mouse.ypos > mouse.maxheight) + mouse.ypos = mouse.maxheight; + + mick_x = mouse.xpos - old_x; + mick_y = mouse.ypos - old_y; + mouse.xdelta += mick_x; + mouse.ydelta += mick_y; + + old_button = mouse.button; + mouse.button = _get_buttons(); + + /* if our delta really changed, add an event */ + if (0 != mick_x || 0 != mick_y) + { + thin_event_t event; + + event.type = THIN_MOUSE_MOTION; + event.data.mouse_motion.xpos = mouse.xpos; + event.data.mouse_motion.ypos = mouse.ypos; + + thin_event_add(&event); + } + + /* if button state changed, add applicable events */ + if (old_button != mouse.button) + { + thin_event_t event; + int i; + + for (i = 0; i < THIN_MOUSE_MAX_BUTTONS; i++) + { + /* TODO: this is kind of krunky. a separate event for + ** every button, but return the state of all buttons? + ** bleh. + */ + if ((old_button & (1 << i)) != (mouse.button & (1 << i))) + { + event.type = (mouse.button & (1 << i)) + ? THIN_MOUSE_BUTTON_PRESS : THIN_MOUSE_BUTTON_RELEASE; + event.data.mouse_button = mouse.button; + + thin_event_add(&event); + } + } + } +} + +uint8 thin_mouse_getmotion(int *dx, int *dy) +{ + *dx = mouse.xdelta >> MOUSE_FIX; + *dy = mouse.ydelta >> MOUSE_FIX; + mouse.xdelta = 0; + mouse.ydelta = 0; + return mouse.button; +} + +uint8 thin_mouse_getpos(int *x, int *y) +{ + *x = mouse.xpos >> MOUSE_FIX; + *y = mouse.ypos >> MOUSE_FIX; + return mouse.button; +} + + +void thin_mouse_setrange(int width, int height) +{ + mouse.maxwidth = (width - 1) << MOUSE_FIX; + mouse.maxheight = (height - 1) << MOUSE_FIX; + mouse.xpos = (width / 2) << MOUSE_FIX; + mouse.ypos = (height / 2) << MOUSE_FIX; + mouse.xdelta = 0; + mouse.ydelta = 0; +} + + +void thin_mouse_shutdown(void) +{ + if (-1 != mouse.id) + { + thin_event_remove_callback(mouse.id); + mouse.id = -1; + mouse.enabled = false; + } +} + + +/* Set up mouse, center pointer */ +int thin_mouse_init(int width, int height, int delta_shift) +{ + __dpmi_regs r; + + r.x.ax = 0x00; + __dpmi_int(MOUSE_INT, &r); + + if (0 == r.x.ax) + { + mouse.enabled = false; + mouse.id = -1; + return -1; + } + + mouse.enabled = true; + + mouse.num_buttons = r.x.bx; + if (r.x.bx == 0xFFFF) + mouse.num_buttons = 2; + else if (mouse.num_buttons > 3) + mouse.num_buttons = 3; + + mouse.delta_shift = delta_shift; + + mouse.button = 0; + + thin_mouse_setrange(width, height); + + /* set it up for the event handling */ + mouse.id = thin_event_add_callback((event_callback_t) _mouse_poll); + if (-1 == mouse.id) + { + mouse.enabled = false; + return -1; + } + + return 0; +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_mouse.h b/sys/thinlib/lib/tl_mouse.h new file mode 100644 index 0000000..29a87b7 --- /dev/null +++ b/sys/thinlib/lib/tl_mouse.h @@ -0,0 +1,40 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_mouse.h +** +** DOS mouse handling defines / prototypes +** +** $Id: $ +*/ + +#ifndef _TL_MOUSE_H_ +#define _TL_MOUSE_H_ + +#include "tl_types.h" + +/* mouse buttons */ +enum +{ + THIN_MOUSE_LEFT = 0, + THIN_MOUSE_MIDDLE, + THIN_MOUSE_RIGHT, + THIN_MOUSE_MAX_BUTTONS, +}; + +#define THIN_MOUSE_BUTTON_MASK(x) (1 << (x)) + +extern int thin_mouse_init(int width, int height, int delta_shift); +extern void thin_mouse_shutdown(); + +extern void thin_mouse_setrange(int width, int height); + +extern uint8 thin_mouse_getmotion(int *dx, int *dy); +extern uint8 thin_mouse_getpos(int *x, int *y); + +#endif /* !_TL_MOUSE_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_prof.c b/sys/thinlib/lib/tl_prof.c new file mode 100644 index 0000000..13dc7e2 --- /dev/null +++ b/sys/thinlib/lib/tl_prof.c @@ -0,0 +1,25 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_prof.c +** +** Screen border color profiler nastiness. +** +** $Id: $ +*/ + +#include +#include "tl_types.h" +#include "tl_prof.h" + +void thin_prof_setborder(int pal_index) +{ + inportb(0x3DA); + outportb(0x3C0, 0x31); + outportb(0x3C0, (uint8) pal_index); +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_prof.h b/sys/thinlib/lib/tl_prof.h new file mode 100644 index 0000000..c0e647b --- /dev/null +++ b/sys/thinlib/lib/tl_prof.h @@ -0,0 +1,21 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_prof.h +** +** Screen border color profiler. +** +** $Id: $ +*/ + +#ifndef _TL_PROF_H_ +#define _TL_PROF_H_ + +extern void thin_prof_setborder(int pal_index); + +#endif /* !_TL_PROF_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_sb.c b/sys/thinlib/lib/tl_sb.c new file mode 100644 index 0000000..5d0f49b --- /dev/null +++ b/sys/thinlib/lib/tl_sb.c @@ -0,0 +1,1050 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_sb.c +** +** DOS Sound Blaster routines +** +** Note: the information in this file has been gathered from many +** Internet documents, and from source code written by Ethan Brodsky. +** +** $Id: $ +*/ + +#include +#include +#include +#include +#include + +#include "tl_types.h" +#include "tl_djgpp.h" +#include "tl_int.h" +#include "tl_sb.h" +#include "tl_log.h" + + +/* General defines */ +#define LOW_BYTE(x) (uint8) ((x) & 0xFF) +#define HIGH_BYTE(x) (uint8) ((x) >> 8) + +#define INVALID 0xFFFFFFFF +#define DEFAULT_TIMEOUT 20000 + +#define DETECT_POLL_REPS 1000 + +#define DSP_VERSION_SB_15 0x0200 +#define DSP_VERSION_SB_20 0x0201 +#define DSP_VERSION_SB_PRO 0x0300 +#define DSP_VERSION_SB16 0x0400 + +/* DSP register offsets */ +#define DSP_RESET 0x06 +#define DSP_READ 0x0A +#define DSP_READ_READY 0x0E +#define DSP_WRITE 0x0C +#define DSP_WRITE_BUSY 0x0C +#define DSP_DMA_ACK_8BIT 0x0E +#define DSP_DMA_ACK_16BIT 0x0F +#define DSP_RESET_SUCCESS 0xAA + +/* SB 1.0 commands */ +#define DSP_DMA_TIME_CONST 0x40 +#define DSP_DMA_DAC_8BIT 0x14 +#define DSP_DMA_PAUSE_8BIT 0xD0 +#define DSP_DMA_CONT_8BIT 0xD4 +#define DSP_SPEAKER_ON 0xD1 +#define DSP_SPEAKER_OFF 0xD3 +#define DSP_GET_VERSION 0xE1 + +/* SB 1.5 - Pro commands */ +#define DSP_DMA_BLOCK_SIZE 0x48 +#define DSP_DMA_DAC_AI_8BIT 0x1C /* low-speed autoinit */ +#define DSP_DMA_DAC_HS_8BIT 0x90 /* high-speed autoinit */ + +/* SB16 commands */ +#define DSP_DMA_DAC_RATE 0x41 +#define DSP_DMA_START_16BIT 0xB0 +#define DSP_DMA_START_8BIT 0xC0 +#define DSP_DMA_DAC_MODE 0x06 +#define DSP_DMA_PAUSE_16BIT 0xD5 +#define DSP_DMA_CONT_16BIT 0xD6 +#define DSP_DMA_STOP_8BIT 0xDA + +/* DMA flags */ +#define DSP_DMA_UNSIGNED 0x00 +#define DSP_DMA_SIGNED 0x10 +#define DSP_DMA_MONO 0x00 +#define DSP_DMA_STEREO 0x20 + +/* DMA address/port/command defines */ +#define DMA_MASKPORT_16BIT 0xD4 +#define DMA_MODEPORT_16BIT 0xD6 +#define DMA_CLRPTRPORT_16BIT 0xD8 +#define DMA_ADDRBASE_16BIT 0xC0 +#define DMA_COUNTBASE_16BIT 0XC2 +#define DMA_MASKPORT_8BIT 0x0A +#define DMA_MODEPORT_8BIT 0x0B +#define DMA_CLRPTRPORT_8BIT 0x0C +#define DMA_ADDRBASE_8BIT 0x00 +#define DMA_COUNTBASE_8BIT 0x01 +#define DMA_STOPMASK_BASE 0x04 +#define DMA_STARTMASK_BASE 0x00 +#define DMA_AUTOINIT_MODE 0x58 +#define DMA_ONESHOT_MODE 0x48 + +/* centerline */ +#define SILENCE_SIGNED 0x00 +#define SILENCE_UNSIGNED 0x80 + +/* get the irq vector number from an irq channel */ +#define SB_IRQVEC(chan) ((chan < 8) ? (0x08 + (chan)) : (0x70 + ((chan) - 8))) + + +/* DOS low-memory buffer info */ +static struct +{ + _go32_dpmi_seginfo buffer; + uint32 bufaddr; /* linear address */ + uint32 offset; + uint32 page; +} dos; + + +/* DMA information */ +static struct +{ + volatile int count; + uint16 addrport; + uint16 ackport; + bool autoinit; +} dma; + +/* 8 and 16 bit DMA ports */ +static const uint8 dma8_ports[4] = { 0x87, 0x83, 0x81, 0x82 }; +static const uint8 dma16_ports[4] = { 0xFF, 0x8B, 0x89, 0x8A }; + +/* Sound Blaster context */ +static struct +{ + bool initialized; + + uint16 baseio; + uint16 dsp_version; + + uint16 sample_rate; + uint8 format; + + uint8 irq, dma, dma16; + + uint8 *buffer; + uint32 buf_size; + uint32 buf_chunk; + + sbmix_t callback; + void *user_data; +} sb; + + +/* +** Basic DSP routines +*/ +static void dsp_write(uint8 value) +{ + int timeout = DEFAULT_TIMEOUT; + + /* wait until DSP is ready... */ + while (timeout-- && (inportb(sb.baseio + DSP_WRITE_BUSY) & 0x80)) + ; /* loop */ + + outportb(sb.baseio + DSP_WRITE, value); +} + +static uint8 dsp_read(void) +{ + int timeout = DEFAULT_TIMEOUT; + + while (timeout-- && (0 == (inportb(sb.baseio + DSP_READ_READY) & 0x80))) + ; /* loop */ + + return inportb(sb.baseio + DSP_READ); +} + +/* returns zero if DSP found and successfully reset, nonzero otherwise */ +static int dsp_reset(void) +{ + outportb(sb.baseio + DSP_RESET, 1); /* reset command */ + delay(5); /* 5 usec delay */ + outportb(sb.baseio + DSP_RESET, 0); /* clear */ + delay(5); /* 5 usec delay */ + + if (DSP_RESET_SUCCESS == dsp_read()) + return 0; + + /* BLEH, we failed */ + return -1; +} + +/* return DSP version in 8:8 major:minor format */ +static uint16 dsp_getversion(void) +{ + uint8 major, minor; + + dsp_write(DSP_GET_VERSION); + + major = dsp_read(); + minor = dsp_read(); + + return ((uint16) (major << 8) | minor); +} + +/* +** BLASTER environment variable parsing +*/ +static int get_env_item(char *env, void *ptr, char find, int base, int width) +{ + char *item; + int value; + + item = strrchr(env, find); + if (NULL == item) + return -1; + + item++; + value = strtol(item, NULL, base); + + switch (width) + { + case 32: + *(uint32 *) ptr = value; + break; + + case 16: + *(uint16 *) ptr = value; + break; + + case 8: + *(uint8 *) ptr = value; + break; + + default: + break; + } + + return 0; +} + +/* parse the BLASTER environment variable */ +static int parse_blaster_env(void) +{ + char blaster[255 + 1], *penv; + + penv = getenv("BLASTER"); + + /* bail out if we can't find it... */ + if (NULL == penv) + return -1; + + /* copy it, normalize case */ + strncpy(blaster, penv, 255); + strupr(blaster); + + if (get_env_item(blaster, &sb.baseio, 'A', 16, 16)) + return -1; + if (get_env_item(blaster, &sb.irq, 'I', 10, 8)) + return -1; + if (get_env_item(blaster, &sb.dma, 'D', 10, 8)) + return -1; + if (get_env_item(blaster, &sb.dma16, 'H', 10, 8)) + sb.dma16 = (uint8) INVALID; + + return 0; +} + +/* +** Brute force autodetection code +*/ + +/* detect the base IO by attempting to +** reset the DSP at known addresses +*/ +static uint16 detect_baseio(void) +{ + int i; + static const uint16 port_val[] = + { + 0x210, 0x220, 0x230, 0x240, + 0x250, 0x260, 0x280, (uint16) INVALID + }; + + for (i = 0; (uint16) INVALID != port_val[i]; i++) + { + sb.baseio = port_val[i]; + if (0 == dsp_reset()) + break; + } + + /* will return INVALID if not found */ + return port_val[i]; +} + +/* stop all DSP activity */ +static void dsp_stop(void) +{ + /* pause 8/16 bit DMA mode digitized sound IO */ + dsp_reset(); + dsp_write(DSP_DMA_PAUSE_8BIT); + dsp_write(DSP_DMA_PAUSE_16BIT); +} + +/* return number of set bits in byte x */ +static int bitcount(uint8 x) +{ + int i, set_count = 0; + + for (i = 0; i < 8; i++) + if (x & (1 << i)) + set_count++; + + return set_count; +} + +/* returns position of lowest bit set in byte x (INVALID if none) */ +static int bitpos(uint8 x) +{ + int i; + + for (i = 0; i < 8; i++) + if (x & (1 << i)) + return i; + + return INVALID; +} + +static uint8 detect_dma(bool high_dma) +{ + uint8 dma_maskout, dma_mask; + int i; + + /* stop DSP activity */ + dsp_stop(); + + dma_maskout = ~0x10; /* initially mask only DMA4 */ + + /* poll to find out which dma channels are in use */ + for (i = 0; i < DETECT_POLL_REPS; i++) + dma_maskout &= ~(inportb(0xD0) & 0xF0) | (inportb(0x08) >> 4); + + /* TODO: this causes a pretty nasty sound */ + /* program card, see whch channel becomes active */ + if (false == high_dma) + { + /* 8 bit */ + dsp_write(DSP_DMA_DAC_8BIT); + } + else + { + dsp_write(DSP_DMA_START_16BIT); /* 16-bit, D/A, S/C, FIFO off */ + dsp_write(DSP_DMA_SIGNED | DSP_DMA_MONO); /* 16-bit mono signed PCM */ + } + + dsp_write(0xF0); /* send some default length */ + dsp_write(0xFF); + + /* poll to find out which DMA channels are in use with sound */ + dma_mask = 0; /* dma channels active during audio, minus masked out */ + for (i = 0; i < DETECT_POLL_REPS; i++) + dma_mask |= (((inportb(0xD0) & 0xF0) | (inportb(0x08) >> 4)) & dma_maskout); + + /* stop all DSP activity */ + dsp_stop(); + + if (1 == bitcount(dma_mask)) + return (uint8) bitpos(dma_mask); + else + return (uint8) INVALID; +} + +static void dsp_transfer(uint8 dma) +{ + outportb(DMA_MASKPORT_8BIT, DMA_STOPMASK_BASE | dma); + + /* write DMA mode: single-cycle read transfer */ + outportb(DMA_MODEPORT_8BIT, DMA_ONESHOT_MODE | dma); + outportb(DMA_CLRPTRPORT_8BIT, 0x00); + + /* one transfer */ + outportb(DMA_COUNTBASE_8BIT + (2 * dma), 0x00); /* low */ + outportb(DMA_COUNTBASE_8BIT + (2 * dma), 0x00); /* high */ + + /* address */ + outportb(DMA_ADDRBASE_8BIT + (2 * dma), 0x00); + outportb(DMA_ADDRBASE_8BIT + (2 * dma), 0x00); + outportb(dma8_ports[dma], 0x00); + + /* unmask DMA channel */ + outportb(DMA_MASKPORT_8BIT, DMA_STARTMASK_BASE | dma); + + /* 8-bit single cycle DMA mode */ + dsp_write(DSP_DMA_DAC_8BIT); + dsp_write(0x00); + dsp_write(0x00); +} + +/* +** IRQ autodetection +*/ +#define NUM_IRQ_CHANNELS 5 + +static const uint8 irq_channels[NUM_IRQ_CHANNELS] = { 2, 3, 5, 7, 10 }; +static volatile bool irq_hit[NUM_IRQ_CHANNELS]; + +#define MAKE_IRQ_HANDLER(num) \ +static int chan##num##_handler(void) { irq_hit[num] = true; return 0; } \ +THIN_LOCKED_STATIC_FUNC(chan##num##_handler) + +MAKE_IRQ_HANDLER(0) +MAKE_IRQ_HANDLER(1) +MAKE_IRQ_HANDLER(2) +MAKE_IRQ_HANDLER(3) +MAKE_IRQ_HANDLER(4) + +static void ack_interrupt(uint8 irq) +{ + /* acknowledge the interrupts! */ + inportb(sb.baseio + 0x0E); + if (irq > 7) + outportb(0xA0, 0x20); + outportb(0x20, 0x20); +} + +static uint8 detect_irq(void) +{ + bool irq_mask[NUM_IRQ_CHANNELS]; + uint8 irq = (uint8) INVALID; + int i; + + THIN_LOCK_FUNC(chan0_handler); + THIN_LOCK_FUNC(chan1_handler); + THIN_LOCK_FUNC(chan2_handler); + THIN_LOCK_FUNC(chan3_handler); + THIN_LOCK_FUNC(chan4_handler); + THIN_LOCK_VAR(irq_hit); + + THIN_DISABLE_INTS(); + + /* install temp handlers */ + thin_int_install(SB_IRQVEC(irq_channels[0]), chan0_handler); + thin_int_install(SB_IRQVEC(irq_channels[1]), chan1_handler); + thin_int_install(SB_IRQVEC(irq_channels[2]), chan2_handler); + thin_int_install(SB_IRQVEC(irq_channels[3]), chan3_handler); + thin_int_install(SB_IRQVEC(irq_channels[4]), chan4_handler); + + /* enable IRQs */ + for (i = 0; i < NUM_IRQ_CHANNELS; i++) + { + thin_irq_enable(irq_channels[i]); + irq_hit[i] = false; + } + + THIN_ENABLE_INTS(); + + /* wait to see which interrupts are triggered without sound */ + delay(100); + + /* mask out any interrupts triggered without sound */ + for (i = 0; i < NUM_IRQ_CHANNELS; i++) + { + irq_mask[i] = irq_hit[i]; + irq_hit[i] = false; + } + + /* try to trigger an interrupt using DSP command F2 */ + dsp_write(0xF2); + + delay(100); + + /* detect triggered interrupts */ + for (i = 0; i < NUM_IRQ_CHANNELS; i++) + { + if (true == irq_hit[i] && false == irq_mask[i]) + { + irq = irq_channels[i]; + ack_interrupt(irq); + break; + } + } + + /* if F2 fails to trigger an int, run a short transfer */ + if ((uint8) INVALID == irq) + { + dsp_reset(); + dsp_transfer(sb.dma); + + delay(100); + + /* detect triggered interrupts */ + for (i = 0; i < NUM_IRQ_CHANNELS; i++) + { + if (true == irq_hit[i] && false == irq_mask[i]) + { + irq = irq_channels[i]; + ack_interrupt(irq); + break; + } + } + } + + /* reset DSP just in case */ + dsp_reset(); + + THIN_DISABLE_INTS(); + + /* restore IRQs to previous state, uninstall handlers */ + for (i = 0; i < NUM_IRQ_CHANNELS; i++) + { + thin_irq_restore(irq_channels[i]); + thin_int_remove(SB_IRQVEC(irq_channels[i])); + } + + THIN_ENABLE_INTS(); + + return irq; +} + +/* try and detect an SB without environment variables */ +static int sb_detect(void) +{ + sb.baseio = detect_baseio(); + if ((uint16) INVALID == sb.baseio) + return -1; + + sb.irq = detect_irq(); + if ((uint8) INVALID == sb.irq) + return -1; + + sb.dma = detect_dma(false); + if ((uint8) INVALID == sb.dma) + return -1; + + /* may or may not exist */ + sb.dma16 = detect_dma(true); + + return 0; +} + +/* +** Probe for an SB +*/ +static int sb_probe(void) +{ + int retval; + + retval = parse_blaster_env(); + + /* if environment parse failed, try brute force autodetection */ + if (-1 == retval) + retval = sb_detect(); + + /* no blaster found */ + if (-1 == retval) + { + thin_printf("thinlib.sb: no sound blaster found\n"); + return -1; + } + + if (dsp_reset()) + { + thin_printf("thinlib.sb: could not reset SB DSP: check BLASTER= variable\n"); + return -1; + } + + sb.dsp_version = dsp_getversion(); + return 0; +} + +/* +** Interrupt handler for 8/16-bit audio +*/ + +static int sb_isr(void) +{ + uint32 address, offset; + + dma.count++; + + /* NOTE: this only works with 8-bit, as one-shot mode + ** does not seem to work with 16-bit transfers + */ + if (false == dma.autoinit) + { + dsp_write(DSP_DMA_DAC_8BIT); + dsp_write(LOW_BYTE(sb.buf_size - 1)); + dsp_write(HIGH_BYTE(sb.buf_size - 1)); + } + + /* indicate we got the interrupt */ + inportb(dma.ackport); + + /* determine the current playback position */ + address = inportb(dma.addrport); + address |= (inportb(dma.addrport) << 8); + address -= dos.offset; + + if (address < sb.buf_size) + offset = sb.buf_chunk; + else + offset = 0; + + sb.callback(sb.user_data, sb.buffer + offset, sb.buf_size); + + /* if we haven't enabled near pointers, we've written to a double + ** buffer, so transfer it to low DOS memory area + */ + if (0 == thinlib_nearptr) + dosmemput(sb.buffer + offset, sb.buf_chunk, dos.bufaddr + offset); + + /* acknowledge interrupt was taken */ + if (sb.irq > 7) + outportb(0xA0, 0x20); + outportb(0x20, 0x20); + + return 0; +} +THIN_LOCKED_STATIC_FUNC(sb_isr) + + +/* install the SB ISR */ +static void sb_setisr(void) +{ + THIN_DISABLE_INTS(); + + thin_int_install(SB_IRQVEC(sb.irq), sb_isr); + + /* enable IRQ */ + thin_irq_enable(sb.irq); + + THIN_ENABLE_INTS(); +} + + +static void sb_restoreisr(void) +{ + THIN_DISABLE_INTS(); + + /* restore IRQ to previous state */ + thin_irq_restore(sb.irq); + + thin_int_remove(SB_IRQVEC(sb.irq)); + + THIN_ENABLE_INTS(); +} + +/* allocate sound buffers */ +static int sb_allocate_buffers(int buf_size) +{ + int double_bufsize; + + sb.buf_size = buf_size; + +// if (sb.format & SB_FORMAT_STEREO) +// sb.buf_size *= 2; + + if (sb.format & SB_FORMAT_16BIT) + sb.buf_chunk = sb.buf_size * sizeof(uint16); + else + sb.buf_chunk = sb.buf_size * sizeof(uint8); + + double_bufsize = 2 * sb.buf_chunk; + + dos.buffer.size = (double_bufsize + 15) >> 4; + if (_go32_dpmi_allocate_dos_memory(&dos.buffer)) + return -1; + + /* calc linear address */ + dos.bufaddr = dos.buffer.rm_segment << 4; + if (sb.format & SB_FORMAT_16BIT) + { + dos.page = (dos.bufaddr >> 16) & 0xFF; + dos.offset = (dos.bufaddr >> 1) & 0xFFFF; + } + else + { + dos.page = (dos.bufaddr >> 16) & 0xFF; + dos.offset = dos.bufaddr & 0xFFFF; + } + + if (thinlib_nearptr) + { + sb.buffer = (uint8 *) THIN_PHYSICAL_ADDR(dos.bufaddr); + } + else + { + sb.buffer = malloc(double_bufsize); + if (NULL == sb.buffer) + return -1; + } + + /* clear out the buffers */ + if (sb.format & SB_FORMAT_SIGNED) + memset(sb.buffer, SILENCE_SIGNED, double_bufsize); + else + memset(sb.buffer, SILENCE_UNSIGNED, double_bufsize); + + if (0 == thinlib_nearptr) + dosmemput(sb.buffer, double_bufsize, dos.bufaddr); + + return 0; +} + +/* free buffers */ +static void sb_free_buffers(void) +{ + sb.callback = NULL; + + _go32_dpmi_free_dos_memory(&dos.buffer); + + if (0 == thinlib_nearptr) + { + free(sb.buffer); + sb.buffer = NULL; + } + + sb.buffer = NULL; +} + +/* get rid of all things SB */ +void thin_sb_shutdown(void) +{ + if (true == sb.initialized) + { + sb.initialized = false; + + dsp_reset(); + + sb_restoreisr(); + + sb_free_buffers(); + } +} + +/* initialize sound bastard */ +int thin_sb_init(int *sample_rate, int *buf_size, int *format) +{ +#define CLAMP_RATE(in_rate, min_rate, max_rate) \ + (in_rate < min_rate ? min_rate : \ + (in_rate > max_rate ? max_rate : in_rate)) + + /* don't init twice! */ + if (true == sb.initialized) + return 0; + + /* lock variables, routines */ + THIN_LOCK_VAR(dma); + THIN_LOCK_VAR(dos); + THIN_LOCK_VAR(sb); + THIN_LOCK_FUNC(sb_isr); + + memset(&sb, 0, sizeof(sb)); + + if (sb_probe()) + return -1; + + /* try autoinit DMA first */ + dma.autoinit = true; + sb.format = (uint8) *format; + + /* determine which SB model we have, and act accordingly */ + if (sb.dsp_version < DSP_VERSION_SB_15) + { + /* SB 1.0 */ + sb.sample_rate = CLAMP_RATE(*sample_rate, 4000, 22050); + sb.format &= ~(SB_FORMAT_16BIT | SB_FORMAT_STEREO); + dma.autoinit = false; + } + else if (sb.dsp_version < DSP_VERSION_SB_20) + { + /* SB 1.5 */ + sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 22050); + sb.format &= ~(SB_FORMAT_16BIT | SB_FORMAT_STEREO); + } + else if (sb.dsp_version < DSP_VERSION_SB_PRO) + { + /* SB 2.0 */ + sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 44100); + sb.format &= ~(SB_FORMAT_16BIT | SB_FORMAT_STEREO); + } + else if (sb.dsp_version < DSP_VERSION_SB16) + { + /* SB Pro */ + if (sb.format & SB_FORMAT_STEREO) + sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 22050); + else + sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 44100); + sb.format &= ~SB_FORMAT_16BIT; + } + else + { + /* SB 16 */ + sb.sample_rate = CLAMP_RATE(*sample_rate, 5000, 44100); + } + + /* sanity check for 16-bit */ + if ((sb.format & SB_FORMAT_16BIT) && ((uint8) INVALID == sb.dma16)) + { + sb.format &= ~SB_FORMAT_16BIT; + thin_printf("thinlib.sb: 16-bit DMA channel not available, dropping to 8-bit\n"); + } + + /* clamp buffer size to something sane */ + if ((uint16) *buf_size > sb.sample_rate) + { + *buf_size = sb.sample_rate; + thin_printf("thinlib.sb: buffer size too big, dropping to %d bytes\n", *buf_size); + } + + /* allocate buffer / DOS memory */ + if (sb_allocate_buffers(*buf_size)) + { + thin_printf("thinlib.sb: failed allocating sound buffers\n"); + return -1; + } + + /* set the new IRQ vector! */ + sb_setisr(); + + sb.initialized = true; + + /* return the actual values */ + *sample_rate = sb.sample_rate; + *buf_size = sb.buf_size; + *format = sb.format; + + return 0; +} + +void thin_sb_stop(void) +{ + if (true == sb.initialized) + { + if (sb.format & SB_FORMAT_16BIT) + { + dsp_write(DSP_DMA_PAUSE_16BIT); /* pause 16-bit DMA */ + dsp_write(DSP_DMA_STOP_8BIT); + dsp_write(DSP_DMA_PAUSE_16BIT); + } + else + { + dsp_write(DSP_DMA_PAUSE_8BIT); /* pause 8-bit DMA */ + dsp_write(DSP_SPEAKER_OFF); + } + } +} + +/* return time constant for older sound bastards */ +static uint8 get_time_constant(int rate) +{ + return ((65536 - (256000000L / rate)) / 256); +} + +static void init_samplerate(int rate) +{ + if ((sb.format & SB_FORMAT_16BIT) || sb.dsp_version >= DSP_VERSION_SB16) + { + dsp_write(DSP_DMA_DAC_RATE); + dsp_write(HIGH_BYTE(rate)); + dsp_write(LOW_BYTE(rate)); + } + else + { + dsp_write(DSP_DMA_TIME_CONST); + dsp_write(get_time_constant(rate)); + } +} + +/* set the sample rate */ +void thin_sb_setrate(int rate) +{ + if (sb.format & SB_FORMAT_16BIT) + { + dsp_write(DSP_DMA_PAUSE_16BIT); /* pause 16-bit DMA */ + init_samplerate(rate); + dsp_write(DSP_DMA_CONT_16BIT); /* continue 16-bit DMA */ + } + else + { + dsp_write(DSP_DMA_PAUSE_8BIT); /* pause 8-bit DMA */ + init_samplerate(rate); + dsp_write(DSP_DMA_CONT_8BIT); /* continue 8-bit DMA */ + } + + sb.sample_rate = rate; +} + +/* start SB DMA transfer */ +static void start_transfer(void) +{ + uint8 dma_mode, start_command, mode_command; + int dma_length; + + /* reset DMA count */ + dma.count = 0; + + dma_length = sb.buf_size * 2; + + if (true == dma.autoinit) + { + start_command = DSP_DMA_DAC_MODE; /* autoinit DMA */ + dma_mode = DMA_AUTOINIT_MODE; + } + else + { + start_command = 0; + dma_mode = DMA_ONESHOT_MODE; + } + + /* things get a little bit nasty here, look out */ + if (sb.format & SB_FORMAT_16BIT) + { + uint8 dma_base = sb.dma16 - 4; + + dma_mode |= dma_base; + start_command |= DSP_DMA_START_16BIT; + + outportb(DMA_MASKPORT_16BIT, DMA_STOPMASK_BASE | dma_base); + outportb(DMA_MODEPORT_16BIT, dma_mode); + outportb(DMA_CLRPTRPORT_16BIT, 0x00); + outportb(DMA_ADDRBASE_16BIT + (4 * dma_base), LOW_BYTE(dos.offset)); + outportb(DMA_ADDRBASE_16BIT + (4 * dma_base), HIGH_BYTE(dos.offset)); + outportb(DMA_COUNTBASE_16BIT + (4 * dma_base), LOW_BYTE(dma_length - 1)); + outportb(DMA_COUNTBASE_16BIT + (4 * dma_base), HIGH_BYTE(dma_length - 1)); + outportb(dma16_ports[dma_base], dos.page); + outportb(DMA_MASKPORT_16BIT, DMA_STARTMASK_BASE | dma_base); + + dma.ackport = sb.baseio + DSP_DMA_ACK_16BIT; + dma.addrport = DMA_ADDRBASE_16BIT + (4 * (sb.dma16 - 4)); + } + else + { + dma_mode |= sb.dma; + start_command |= DSP_DMA_START_8BIT; + + outportb(DMA_MASKPORT_8BIT, DMA_STOPMASK_BASE + sb.dma); + outportb(DMA_MODEPORT_8BIT, dma_mode); + outportb(DMA_CLRPTRPORT_8BIT, 0x00); + outportb(DMA_ADDRBASE_8BIT + (2 * sb.dma), LOW_BYTE(dos.offset)); + outportb(DMA_ADDRBASE_8BIT + (2 * sb.dma), HIGH_BYTE(dos.offset)); + outportb(DMA_COUNTBASE_8BIT + (2 * sb.dma), LOW_BYTE(dma_length - 1)); + outportb(DMA_COUNTBASE_8BIT + (2 * sb.dma), HIGH_BYTE(dma_length - 1)); + outportb(dma8_ports[sb.dma], dos.page); + outportb(DMA_MASKPORT_8BIT, DMA_STARTMASK_BASE + sb.dma); + + dma.ackport = sb.baseio + DSP_DMA_ACK_8BIT; + dma.addrport = DMA_ADDRBASE_8BIT + (2 * sb.dma); + } + + /* check signed/unsigned */ + if (sb.format & SB_FORMAT_SIGNED) + mode_command = DSP_DMA_SIGNED; + else + mode_command = DSP_DMA_UNSIGNED; + + /* check stereo */ + if (sb.format & SB_FORMAT_STEREO) + mode_command |= DSP_DMA_STEREO; + else + mode_command |= DSP_DMA_MONO; + + init_samplerate(sb.sample_rate); + + /* start things going */ + if ((sb.format & SB_FORMAT_16BIT) || sb.dsp_version >= DSP_VERSION_SB16) + { + dsp_write(start_command); + dsp_write(mode_command); + dsp_write(LOW_BYTE(sb.buf_size - 1)); + dsp_write(HIGH_BYTE(sb.buf_size - 1)); + } + else + { + /* turn on speaker */ + dsp_write(DSP_SPEAKER_ON); + + if (true == dma.autoinit) + { + dsp_write(DSP_DMA_BLOCK_SIZE); /* set buffer size */ + dsp_write(LOW_BYTE(sb.buf_size - 1)); + dsp_write(HIGH_BYTE(sb.buf_size - 1)); + + if (sb.dsp_version < DSP_VERSION_SB_20) + dsp_write(DSP_DMA_DAC_AI_8BIT); /* low speed autoinit */ + else + dsp_write(DSP_DMA_DAC_HS_8BIT); + } + else + { + dsp_write(DSP_DMA_DAC_8BIT); + dsp_write(LOW_BYTE(sb.buf_size - 1)); + dsp_write(HIGH_BYTE(sb.buf_size - 1)); + } + } +} + +/* TODO: this gets totally wacked when we change the timer rate!!! */ +/* start playing the output buffer */ +int thin_sb_start(sbmix_t fillbuf, void *user_data) +{ + clock_t count; + int projected_dmacount; + + /* make sure we really should be here... */ + if (false == sb.initialized || NULL == fillbuf) + return -1; + + /* stop any current processing */ + thin_sb_stop(); + + /* set the callback routine */ + sb.callback = fillbuf; + sb.user_data = user_data; + + /* calculate how many DMAs we should have in one second + ** and scale it down just a tad + */ + projected_dmacount = (int) ((0.8 * sb.sample_rate) / sb.buf_size); + if (projected_dmacount < 1) + projected_dmacount = 1; + + /* get the transfer going, so we can ensure interrupts are firing */ + start_transfer(); + count = clock(); + while ((clock() - count) < CLOCKS_PER_SEC && dma.count < projected_dmacount) + ; /* spin */ + + if (dma.count < projected_dmacount) + { + if (true == dma.autoinit) + { + thin_printf("thinlib.sb: Autoinit DMA failed, trying one-shot mode.\n"); + dsp_reset(); + dma.autoinit = false; + dma.count = 0; + return (thin_sb_start(fillbuf, user_data)); + } + else + { + thin_printf("thinlib.sb: One-shot DMA mode failed, sound will not be heard.\n"); + thin_printf("thinlib.sb: DSP version: %d.%d baseio: %X IRQ: %d DMA: %d High: %d\n", + sb.dsp_version >> 8, sb.dsp_version & 0xFF, + sb.baseio, sb.irq, sb.dma, sb.dma16); + return -1; + } + } + + return 0; +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_sb.h b/sys/thinlib/lib/tl_sb.h new file mode 100644 index 0000000..74889ad --- /dev/null +++ b/sys/thinlib/lib/tl_sb.h @@ -0,0 +1,35 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_sb.h +** +** DOS Sound Blaster header file +** +** $Id: $ +*/ + +#ifndef _TL_SB_H_ +#define _TL_SB_H_ + +typedef void (*sbmix_t)(void *user_data, void *buffer, int size); + +/* Sample format bitfields */ +#define SB_FORMAT_8BIT 0x00 +#define SB_FORMAT_16BIT 0x01 +#define SB_FORMAT_MONO 0x00 +#define SB_FORMAT_STEREO 0x02 +#define SB_FORMAT_UNSIGNED 0x00 +#define SB_FORMAT_SIGNED 0x04 + +extern int thin_sb_init(int *sample_rate, int *buf_size, int *format); +extern void thin_sb_shutdown(void); +extern int thin_sb_start(sbmix_t fillbuf, void *user_data); +extern void thin_sb_stop(void); +extern void thin_sb_setrate(int rate); + +#endif /* !_TL_SB_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_sound.c b/sys/thinlib/lib/tl_sound.c new file mode 100644 index 0000000..35b7bab --- /dev/null +++ b/sys/thinlib/lib/tl_sound.c @@ -0,0 +1,120 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_sound.c +** +** sound driver +** +** $Id: $ +*/ + +#include "tl_types.h" +#include "tl_sound.h" +#include "tl_sb.h" +#include "tl_log.h" + + +typedef struct snddriver_s +{ + const char *name; + int (*init)(int *sample_rate, int *frag_size, int *format); + void (*shutdown)(void); + int (*start)(audio_callback_t callback, void *user_data); + void (*stop)(void); + void (*setrate)(int sample_rate); + audio_callback_t callback; + void *user_data; +} snddriver_t; + +static snddriver_t sb = +{ + "Sound Blaster", + thin_sb_init, + thin_sb_shutdown, + thin_sb_start, + thin_sb_stop, + thin_sb_setrate, + NULL, + NULL +}; + +static snddriver_t *driver_list[] = +{ + &sb, + NULL +}; + +static snddriver_t snddriver; + +int thin_sound_init(thinsound_t *sound_params) +{ + snddriver_t **iter; + int sample_rate, frag_size, format; + + THIN_ASSERT(sound_params); + + sample_rate = sound_params->sample_rate; + frag_size = sound_params->frag_size; + format = sound_params->format; + + for (iter = driver_list; *iter != NULL; iter++) + { + if (0 == (*iter)->init(&sample_rate, &frag_size, &format)) + { + snddriver = **iter; + + /* copy the parameters back */ + sound_params->sample_rate = sample_rate; + sound_params->frag_size = frag_size; + sound_params->format = format; + + /* and set the callback */ + snddriver.callback = sound_params->callback; + snddriver.user_data = sound_params->user_data; + + return 0; + } + } + + snddriver.name = NULL; + + thin_printf("thin: could not find any sound drivers.\n"); + return -1; +} + +void thin_sound_shutdown(void) +{ + if (NULL == snddriver.name) + return; + + snddriver.shutdown(); + memset(&snddriver, 0, sizeof(snddriver_t)); +} + +void thin_sound_start(void) +{ + if (NULL == snddriver.name) + return; + + THIN_ASSERT(snddriver.callback); + snddriver.start(snddriver.callback, snddriver.user_data); +} + +void thin_sound_stop(void) +{ + if (NULL == snddriver.name) + return; + + snddriver.stop(); +} + +void thin_sound_setrate(int sample_rate) +{ + if (snddriver.setrate) + snddriver.setrate(sample_rate); +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_sound.h b/sys/thinlib/lib/tl_sound.h new file mode 100644 index 0000000..6e7f28e --- /dev/null +++ b/sys/thinlib/lib/tl_sound.h @@ -0,0 +1,48 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_sound.h +** +** thinlib sound routines +** +** $Id: $ +*/ + +#ifndef _TL_SOUND_H_ +#define _TL_SOUND_H_ + +#include "tl_types.h" + +#define THIN_SOUND_8BIT 0x00 +#define THIN_SOUND_16BIT 0x01 +#define THIN_SOUND_MONO 0x00 +#define THIN_SOUND_STEREO 0x02 +#define THIN_SOUND_UNSIGNED 0x00 +#define THIN_SOUND_SIGNED 0x04 + +typedef void (*audio_callback_t)(void *user_data, void *buffer, int samples); + +typedef struct thinsound_s +{ + int sample_rate; + int frag_size; + int format; + audio_callback_t callback; + void *user_data; +} thinsound_t; + +extern int thin_sound_init(thinsound_t *sound_params); +extern void thin_sound_shutdown(void); + +// TODO: roll into one pause() function +extern void thin_sound_start(void); +extern void thin_sound_stop(void); + +extern void thin_sound_setrate(int sample_rate); + +#endif /* !_TL_SOUND_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_timer.c b/sys/thinlib/lib/tl_timer.c new file mode 100644 index 0000000..2c235aa --- /dev/null +++ b/sys/thinlib/lib/tl_timer.c @@ -0,0 +1,138 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_timer.c +** +** DOS timer routines +** +** $Id: $ +*/ + +#include +#include +#include + +#include "tl_types.h" +#include "tl_djgpp.h" +#include "tl_timer.h" + +#define TIMER_INT 0x08 +#define TIMER_TICKS 1193182L + +#define TIMER_CONTROL 0x43 +#define TIMER_ACCESS 0x40 +#define TIMER_DEFAULT_MODE 0x36 + +static _go32_dpmi_seginfo old_handler, new_handler; + +static struct +{ + timerhandler_t handler; + void *param; + int interval, frac, current; + uint8 current_mode; + bool initialized; +} timer; + +/* port 0x43 - write control word +** port 0x40 - read/write timer count +** control word composition: +** D7-D6 - 0=counter0, 1=counter1, 2=counter2, 3=read-back +** D5-D4 - 0=latch, 1=r/w lsb, 2=r/w msb, 3=r/2 lsb then msb +** D3-D1 - 0=m0, 1=m1, 2/6=m2, 3/7=m3, 4=m4, 5=m5 +** D0 - 0=16-bit binary counter, 1=BCD counter +** +** mode 0 - interrupt on terminal count +** mode 1 - hardware retriggerable one-shot +** mode 2 - rate generator +** mode 3 - square wave mode +** mode 4 - software triggered mode +** mode 5 - hardware triggered strobe (retriggerable) +*/ + + +/* Reprogram the PIT timer to fire at a specified value */ +void thin_timer_setrate(int hertz) +{ + int time; + + if (0 == hertz) + time = 0; + else + time = TIMER_TICKS / (long) hertz; + + timer.interval = time; + timer.frac = time & 0xFFFF; + + if (0 == time) + timer.current_mode = TIMER_DEFAULT_MODE; /* reset to standard */ + + outportb(TIMER_CONTROL, timer.current_mode); + outportb(TIMER_ACCESS, timer.frac & 0xFF); + outportb(TIMER_ACCESS, timer.frac >> 8); +} + +static void _timer_int_handler(void) +{ + timer.current += timer.frac; + if (timer.current >= timer.interval) + { + timer.current -= timer.interval; + timer.handler(timer.param); + } + + outportb(0x20, 0x20); +} +THIN_LOCKED_STATIC_FUNC(_timer_int_handler); + +/* Lock code, data, and chain an interrupt handler */ +int thin_timer_init(int hertz, timerhandler_t func_ptr, void *param) +{ + if (false == timer.initialized) + { + THIN_LOCK_FUNC(_timer_int_handler); + THIN_LOCK_VAR(timer); + + timer.handler = func_ptr; + timer.param = param; + + /* chain onto old timer interrupt */ + _go32_dpmi_get_protected_mode_interrupt_vector(TIMER_INT, &old_handler); + new_handler.pm_offset = (int) _timer_int_handler; + new_handler.pm_selector = _go32_my_cs(); + _go32_dpmi_chain_protected_mode_interrupt_vector(TIMER_INT, &new_handler); + + timer.current = 0; + + /* Set PIC to fire at desired refresh rate */ + + /* counter 0, lsb+msb, mode 3, binary counter */ + timer.current_mode = 0x36; + + timer.initialized = true; + } + + thin_timer_setrate(hertz); + + return 0; +} + +/* Remove the timer handler */ +void thin_timer_shutdown(void) +{ + if (false == timer.initialized) + return; + + /* Restore previous timer setting */ + thin_timer_setrate(0); + + /* Remove the interrupt handler */ + _go32_dpmi_set_protected_mode_interrupt_vector(TIMER_INT, &old_handler); + + timer.initialized = false; +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_timer.h b/sys/thinlib/lib/tl_timer.h new file mode 100644 index 0000000..0926eeb --- /dev/null +++ b/sys/thinlib/lib/tl_timer.h @@ -0,0 +1,25 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_timer.h +** +** DOS timer routine defines / prototypes +** +** $Id: $ +*/ + +#ifndef _TL_TIMER_H_ +#define _TL_TIMER_H_ + +typedef void (*timerhandler_t)(void *param); + +extern int thin_timer_init(int hertz, timerhandler_t func_ptr, void *param); +extern void thin_timer_shutdown(void); +extern void thin_timer_setrate(int hertz); + +#endif /* !_TL_TIMER_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_types.h b/sys/thinlib/lib/tl_types.h new file mode 100644 index 0000000..b0862b4 --- /dev/null +++ b/sys/thinlib/lib/tl_types.h @@ -0,0 +1,61 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_types.h +** +** type definitions for thinlib +** +** $Id: $ +*/ + +#ifndef _TL_TYPES_ +#define _TL_TYPES_ + +/* TODO: rethink putting these here. */ +#ifdef THINLIB_DEBUG + +#include "tl_log.h" + +#define THIN_ASSERT(expr) thin_assert((int) (expr), __LINE__, __FILE__, NULL) +#define THIN_ASSERT_MSG(msg) thin_assert(false, __LINE__, __FILE__, (msg)) + +#else /* !THINLIB_DEBUG */ + +#define THIN_ASSERT(expr) +#define THIN_ASSERT_MSG(msg) + +#endif /* !THINLIB_DEBUG */ + +/* quell stupid compiler warnings */ +#define UNUSED(x) ((x) = (x)) + +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +#ifndef __cplusplus +#undef false +#undef true +#undef NULL + +typedef enum +{ + false = 0, + true = 1 +} bool; + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#endif /* !__cplusplus */ + +#endif /* !_TL_TYPES_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_vesa.c b/sys/thinlib/lib/tl_vesa.c new file mode 100644 index 0000000..799f923 --- /dev/null +++ b/sys/thinlib/lib/tl_vesa.c @@ -0,0 +1,401 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_vesa.c +** +** VESA code. +** +** $Id: $ +*/ + +#include +#include +#include +#include +#include +#include + +#include "tl_types.h" +#include "tl_log.h" +#include "tl_bmp.h" + +#include "tl_djgpp.h" + +#include "tl_video.h" +#include "tl_vesa.h" + +#define __PACKED__ __attribute__ ((packed)) + +/* VESA information block structure */ +typedef struct vesainfo_s +{ + char VESASignature[4] __PACKED__; + uint16 VESAVersion __PACKED__; + uint32 OEMStringPtr __PACKED__; + char Capabilities[4] __PACKED__; + uint32 VideoModePtr __PACKED__; + uint16 TotalMemory __PACKED__; + uint16 OemSoftwareRev __PACKED__; + uint32 OemVendorNamePtr __PACKED__; + uint32 OemProductNamePtr __PACKED__; + uint32 OemProductRevPtr __PACKED__; + uint8 Reserved[222] __PACKED__; +} vesainfo_t; + +/* SuperVGA mode information block */ +typedef struct modeinfo_s +{ + uint16 ModeAttributes __PACKED__; + uint8 WinAAttributes __PACKED__; + uint8 WinBAttributes __PACKED__; + uint16 WinGranularity __PACKED__; + uint16 WinSize __PACKED__; + uint16 WinASegment __PACKED__; + uint16 WinBSegment __PACKED__; + uint32 WinFuncPtr __PACKED__; + uint16 BytesPerScanLine __PACKED__; + uint16 XResolution __PACKED__; + uint16 YResolution __PACKED__; + uint8 XCharSize __PACKED__; + uint8 YCharSize __PACKED__; + uint8 NumberOfPlanes __PACKED__; + uint8 BitsPerPixel __PACKED__; + uint8 NumberOfBanks __PACKED__; + uint8 MemoryModel __PACKED__; + uint8 BankSize __PACKED__; + uint8 NumberOfImagePages __PACKED__; + uint8 Reserved_page __PACKED__; + uint8 RedMaskSize __PACKED__; + uint8 RedMaskPos __PACKED__; + uint8 GreenMaskSize __PACKED__; + uint8 GreenMaskPos __PACKED__; + uint8 BlueMaskSize __PACKED__; + uint8 BlueMaskPos __PACKED__; + uint8 ReservedMaskSize __PACKED__; + uint8 ReservedMaskPos __PACKED__; + uint8 DirectColorModeInfo __PACKED__; + + /* VBE 2.0 extensions */ + uint32 PhysBasePtr __PACKED__; + uint32 OffScreenMemOffset __PACKED__; + uint16 OffScreenMemSize __PACKED__; + + /* VBE 3.0 extensions */ + uint16 LinBytesPerScanLine __PACKED__; + uint8 BnkNumberOfPages __PACKED__; + uint8 LinNumberOfPages __PACKED__; + uint8 LinRedMaskSize __PACKED__; + uint8 LinRedFieldPos __PACKED__; + uint8 LinGreenMaskSize __PACKED__; + uint8 LinGreenFieldPos __PACKED__; + uint8 LinBlueMaskSize __PACKED__; + uint8 LinBlueFieldPos __PACKED__; + uint8 LinRsvdMaskSize __PACKED__; + uint8 LinRsvdFieldPos __PACKED__; + uint32 MaxPixelClock __PACKED__; + + uint8 Reserved[190] __PACKED__; +} modeinfo_t; + + +#define MASK_LINEAR(addr) (addr & 0x000FFFFF) +#define RM_TO_LINEAR(addr) (((addr & 0xFFFF0000) >> 12) + (addr & 0xFFFF)) +#define RM_OFFSET(addr) (addr & 0xF) +#define RM_SEGMENT(addr) ((addr >> 4) & 0xFFFF) + +#define VBE_LINEAR_ADDR 0x4000 +#define VBE_LINEAR_AVAIL 0x0080 + +#define VBE_INT 0x10 +#define VBE_SUCCESS 0x004F +#define VBE_FUNC_DETECT 0x4F00 +#define VBE_FUNC_GETMODEINFO 0x4F01 +#define VBE_FUNC_SETMODE 0x4F02 +#define VBE_FUNC_GETMODE 0x4F03 +#define VBE_FUNC_FLIPPAGE 0x4F07 + +#define MAX_NUM_MODES 256 + +short int vid_selector = -1; +static uint16 modelist[MAX_NUM_MODES]; +static bitmap_t *screen = NULL; +static bitmap_t *hardware = NULL; +static int total_memory = 0; +static bool vesa_hardware = false; + +/* look for vesa */ +static int vesa_detect(void) +{ + vesainfo_t vesa_info; + __dpmi_regs regs; + long list_ptr; + int mode_pos; + + /* Use DOS transfer buffer to hold VBE info */ + THIN_ASSERT(sizeof(vesainfo_t) < _go32_info_block.size_of_transfer_buffer); + memset(®s, 0, sizeof(__dpmi_regs)); + + strncpy(vesa_info.VESASignature, "VBE2", 4); + dosmemput(&vesa_info, sizeof(vesainfo_t), MASK_LINEAR(__tb)); + + regs.x.ax = VBE_FUNC_DETECT; + regs.x.es = RM_SEGMENT(__tb); + regs.x.di = RM_OFFSET(__tb); + + __dpmi_int(VBE_INT, ®s); + if (VBE_SUCCESS != regs.x.ax) + return -1; + + dosmemget(MASK_LINEAR(__tb), sizeof(vesainfo_t), &vesa_info); + if (strncmp(vesa_info.VESASignature, "VESA", 4) != 0) + return -1; + + /* check to see if linear framebuffer is available */ + if ((vesa_info.VESAVersion >> 8) < 2) + { + thin_printf("thinlib.vesa: no linear framebuffer available\n"); + return -1; + } + + /* build list of available modes */ + memset(&modelist, 0, MAX_NUM_MODES * sizeof(uint16)); + mode_pos = 0; + + list_ptr = RM_TO_LINEAR(vesa_info.VideoModePtr); + while (1) + { + uint16 mode; + + dosmemget(list_ptr + mode_pos * 2, 2, &mode); + + if (0xFFFF == mode) + { + modelist[mode_pos] = 0; + break; + } + + modelist[mode_pos++] = mode; + } + + total_memory = vesa_info.TotalMemory; + + return 0; +} + +static int vesa_getmodeinfo(uint16 mode, modeinfo_t *modeinfo) +{ + __dpmi_regs regs; + + THIN_ASSERT(sizeof(modeinfo_t) < _go32_info_block.size_of_transfer_buffer); + + memset(®s, 0, sizeof(regs)); + regs.x.ax = VBE_FUNC_GETMODEINFO; + regs.x.cx = mode; + regs.x.es = RM_SEGMENT(__tb); + regs.x.di = RM_OFFSET(__tb); + + __dpmi_int(VBE_INT, ®s); + if (VBE_SUCCESS != regs.x.ax) + return -1; + + dosmemget(MASK_LINEAR(__tb), sizeof(modeinfo_t), modeinfo); + return 0; +} + +static uint16 vesa_findmode(int width, int height, int bpp) +{ + modeinfo_t mode_info; + uint16 mode; + int mode_pos; + + for (mode_pos = 0; ; mode_pos++) + { + mode = modelist[mode_pos]; + + if (0 == mode) + break; + + if (vesa_getmodeinfo(mode, &mode_info)) + break; /* we are definitely screwed */ + + if (mode_info.XResolution == width && mode_info.YResolution == height + && mode_info.BitsPerPixel == bpp) + { + return mode; + } + } + + return 0; +} + +int thin_vesa_setmode(int width, int height, int bpp) +{ + uint16 mode; + __dpmi_regs regs; + __dpmi_meminfo mi; + modeinfo_t mode_info; + unsigned int address; + + mode = vesa_findmode(width, height, bpp); + if (0 == mode) + { + thin_printf("thinlib.vesa: yikes, couldn't find mode\n"); + return -1; + } + + if (vesa_getmodeinfo(mode, &mode_info)) + { + thin_printf("thinlib.vesa: error in vesa_getmodeinfo\n"); + return -1; + } + + mi.size = mode_info.BytesPerScanLine * mode_info.YResolution; + mi.address = mode_info.PhysBasePtr; + if (-1 == __dpmi_physical_address_mapping(&mi)) + { + thin_printf("thinlib.vesa: error in __dpmi_physical_address_mapping\n"); + return -1; + } + + if (false == vesa_hardware) + { + vid_selector = __dpmi_allocate_ldt_descriptors(1); + if (-1 == vid_selector) + { + thin_printf("thinlib.vesa: error in __dpmi_allocate_ldt_descriptors\n"); + return -1; + } + + /* paranoid */ + if (-1 == __dpmi_set_descriptor_access_rights(vid_selector, 0x40f3)) + { + thin_printf("thinlib.vesa: error in __dpmi_set_descriptor_access_rights\n"); + return -1; + } + + if (-1 == __dpmi_set_segment_base_address(vid_selector, mi.address)) + { + thin_printf("thinlib.vesa: error in __dpmi_set_segment_base_address\n"); + return -1; + } + + if (-1 == __dpmi_set_segment_limit(vid_selector, total_memory << 16 | 0xfff)) + { + thin_printf("thinlib.vesa: error in __dpmi_set_segment_limit\n"); + return -1; + } + } + + memset(®s, 0, sizeof(regs)); + regs.x.ax = VBE_FUNC_SETMODE; + regs.x.bx = mode | VBE_LINEAR_ADDR; + + __dpmi_int(VBE_INT, ®s); + if (VBE_SUCCESS != regs.x.ax) + { + thin_printf("thinlib.vesa: vesa dpmi int failed\n"); + return -1; + } + + if (false == vesa_hardware) + address = 0; + else + address = mi.address; + + if (NULL != screen) + thin_bmp_destroy(&screen); + + if (vesa_hardware) + { + screen = thin_bmp_createhw((uint8 *) THIN_PHYSICAL_ADDR(address), + mode_info.XResolution, mode_info.YResolution, + mode_info.BitsPerPixel, mode_info.XResolution); + if (NULL == screen) + { + thin_printf("thinlib.vesa: failed creating hardware surface\n"); + return -1; + } + } + else + { + if (NULL != hardware) + thin_bmp_destroy(&hardware); + + hardware = thin_bmp_createhw((uint8 *) address, + mode_info.XResolution, mode_info.YResolution, + mode_info.BitsPerPixel, mode_info.XResolution); + if (NULL == hardware) + { + thin_printf("thinlib.vesa: failed creating hardware surface\n"); + return -1; + } + + screen = thin_bmp_create(mode_info.XResolution, mode_info.YResolution, + mode_info.BitsPerPixel, 0); + if (NULL == screen) + { + thin_printf("thinlib.vesa: failed creating software surface\n"); + return -1; + } + } + + return 0; +} + +void thin_vesa_shutdown(void) +{ + __dpmi_regs regs; + + /* set text mode */ + memset(®s, 0, sizeof(regs)); + regs.x.ax = 0x0003; + __dpmi_int(VBE_INT, ®s); + + if (NULL != screen) + thin_bmp_destroy(&screen); + + if (NULL != hardware) + thin_bmp_destroy(&hardware); +} + +int thin_vesa_init(int width, int height, int bpp, int param) +{ + screen = NULL; + hardware = NULL; + + /* check to see if VESA card is present */ + if (vesa_detect()) + return -1; + + if (thinlib_nearptr && (param & THIN_VIDEO_HWSURFACE)) + vesa_hardware = true; + else + vesa_hardware = false; + + return thin_vesa_setmode(width, height, bpp); +} + +bitmap_t *thin_vesa_lockwrite(void) +{ + return screen; +} + + +void thin_vesa_freewrite(int num_dirties, rect_t *dirty_rects) +{ + UNUSED(num_dirties); + UNUSED(dirty_rects); + + /* if we don't have a hardware surface, blat it out */ + if (false == vesa_hardware) + { + _movedatal(_my_ds(), (unsigned) screen->line[0], + vid_selector, (unsigned) hardware->line[0], + hardware->pitch * hardware->height / 4); + } +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_vesa.h b/sys/thinlib/lib/tl_vesa.h new file mode 100644 index 0000000..3bcba07 --- /dev/null +++ b/sys/thinlib/lib/tl_vesa.h @@ -0,0 +1,29 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_vesa.h +** +** VESA code header +** +** $Id: $ +*/ + +#ifndef _TL_VESA_H_ +#define _TL_VESA_H_ + +#include "tl_bmp.h" + +extern int thin_vesa_init(int width, int height, int bpp, int param); +extern void thin_vesa_shutdown(void); + +extern int thin_vesa_setmode(int width, int height, int bpp); + +extern bitmap_t *thin_vesa_lockwrite(void); +extern void thin_vesa_freewrite(int num_dirties, rect_t *dirty_rects); + +#endif /* !_TL_VESA_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_vga.c b/sys/thinlib/lib/tl_vga.c new file mode 100644 index 0000000..ba851b3 --- /dev/null +++ b/sys/thinlib/lib/tl_vga.c @@ -0,0 +1,381 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_vga.c +** +** VGA-related functions +** +** $Id: $ +*/ + +#include +#include +#include +#include +#include "tl_types.h" +#include "tl_bmp.h" +#include "tl_video.h" +#include "tl_vga.h" +#include "tl_djgpp.h" +#include "tl_int.h" + +#define DEFAULT_OVERSCAN 0 + +#define MODE_TEXT 0x03 +#define MODE_13H 0x13 + +#define VGA_ADDRESS 0xA0000 /* we love segments! */ + +/* VGA card register addresses */ +#define VGA_ATTR 0x3C0 /* Attribute reg */ +#define VGA_MISC 0x3C2 /* Misc. output register */ +#define VGA_SEQ_ADDR 0x3C4 /* Base port of sequencer */ +#define VGA_SEQ_DATA 0x3C5 /* Data port of sequencer */ +#define VGA_CRTC_ADDR 0x3D4 /* Base port of CRT controller */ +#define VGA_CRTC_DATA 0x3D5 /* Data port of CRT controller */ +#define VGA_STATUS 0x3DA /* Input status #1 register */ + +#define VGA_PAL_READ 0x3C7 /* Palette read address */ +#define VGA_PAL_WRITE 0x3C8 /* Palette write address */ +#define VGA_PAL_DATA 0x3C9 /* Palette data register */ + +/* generic VGA CRTC register indexes */ +#define HZ_DISPLAY_TOTAL 0x00 +#define HZ_DISPLAY_END 0x01 +#define CRTC_OVERFLOW 0x07 +#define VT_DISPLAY_END 0x12 +#define MEM_OFFSET 0x13 + +/* indices into our register array */ +#define CLOCK_INDEX 0 +#define H_TOTAL_INDEX 1 +#define H_DISPLAY_INDEX 2 +#define H_BLANKING_START_INDEX 3 +#define H_BLANKING_END_INDEX 4 +#define H_RETRACE_START_INDEX 5 +#define H_RETRACE_END_INDEX 6 +#define V_TOTAL_INDEX 7 +#define OVERFLOW_INDEX 8 +#define MAXIMUM_SCANLINE_INDEX 10 +#define V_RETRACE_START_INDEX 11 +#define V_RETRACE_END_INDEX 12 +#define V_END_INDEX 13 +#define MEM_OFFSET_INDEX 14 +#define UNDERLINE_LOC_INDEX 15 +#define V_BLANKING_START_INDEX 16 +#define V_BLANKING_END_INDEX 17 +#define MODE_CONTROL_INDEX 18 +#define MEMORY_MODE_INDEX 20 + + +typedef struct vgareg_s +{ + int port; + int index; + uint8 value; +} vgareg_t; + +typedef struct vgamode_s +{ + int width; + int height; + char *name; + vgareg_t *regs; +} vgamode_t; + +/* 60 Hz */ +static vgareg_t mode_256x224[] = +{ + { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x5F }, { 0x3D4, 0x01, 0x3F }, + { 0x3D4, 0x02, 0x40 }, { 0x3D4, 0x03, 0x82 }, { 0x3D4, 0x04, 0x4A }, + { 0x3D4, 0x05, 0x9A }, { 0x3D4, 0x06, 0x0B }, { 0x3D4, 0x07, 0xB2 }, + { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x61 }, { 0x3d4, 0x10, 0x00 }, + { 0x3D4, 0x11, 0xAC }, { 0x3D4, 0x12, 0xBF }, { 0x3D4, 0x13, 0x20 }, + { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0x01 }, { 0x3D4, 0x16, 0x0A }, + { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, + { 0, 0, 0 } +}; + +static vgareg_t mode_256x240[] = +{ + { 0x3c2, 0x00, 0xe3},{ 0x3d4, 0x00, 0x55},{ 0x3d4, 0x01, 0x3f}, + { 0x3d4, 0x02, 0x80},{ 0x3d4, 0x03, 0x90},{ 0x3d4, 0x04, 0x49}, + { 0x3d4, 0x05, 0x80},{ 0x3D4, 0x06, 0x43},{ 0x3d4, 0x07, 0xb2}, + { 0x3d4, 0x08, 0x00},{ 0x3D4, 0x09, 0x61},{ 0x3d4, 0x10, 0x04}, + { 0x3d4, 0x11, 0xac},{ 0x3D4, 0x12, 0xdf},{ 0x3d4, 0x13, 0x20}, + { 0x3d4, 0x14, 0x40},{ 0x3d4, 0x15, 0x07},{ 0x3D4, 0x16, 0x11}, + { 0x3d4, 0x17, 0xa3},{ 0x3c4, 0x01, 0x01},{ 0x3c4, 0x04, 0x0e}, + { 0, 0, 0 } +}; + +static vgareg_t mode_256x256[] = +{ + { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x5F }, { 0x3D4, 0x01, 0x3F }, + { 0x3D4, 0x02, 0x40 }, { 0x3D4, 0x03, 0x82 }, { 0x3D4, 0x04, 0x4A }, + { 0x3D4, 0x05, 0x9A }, { 0x3D4, 0x06, 0x23 }, { 0x3D4, 0x07, 0xB2 }, + { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x61 }, { 0x3D4, 0x10, 0x0A }, + { 0x3D4, 0x11, 0xAC }, { 0x3D4, 0x12, 0xFF }, { 0x3D4, 0x13, 0x20 }, + { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0x07 }, { 0x3D4, 0x16, 0x1A }, + { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, + { 0, 0, 0 } +}; + +/* 60 Hz */ +static vgareg_t mode_256x256wide[] = +{ + { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x52 }, { 0x3D4, 0x01, 0x3F }, + { 0x3D4, 0x02, 0x80 }, { 0x3D4, 0x03, 0x90 }, { 0x3D4, 0x04, 0x49 }, + { 0x3D4, 0x05, 0x80 }, { 0x3D4, 0x06, 0x55 }, { 0x3D4, 0x07, 0xB2 }, + { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x61 }, { 0x3D4, 0x10, 0x20 }, + { 0x3D4, 0x11, 0xAC }, { 0x3D4, 0x12, 0xFF }, { 0x3D4, 0x13, 0x20 }, + { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0x07 }, { 0x3D4, 0x16, 0x1A }, + { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, + { 0, 0, 0 } +}; + +/* 60 Hz */ +static vgareg_t mode_288x224[] = +{ + { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x5F }, { 0x3D4, 0x01, 0x47 }, + { 0x3D4, 0x02, 0x50 }, { 0x3D4, 0x03, 0x82 }, { 0x3D4, 0x04, 0x50 }, + { 0x3D4, 0x05, 0x80 }, { 0x3D4, 0x06, 0x08 }, { 0x3D4, 0x07, 0x3E }, + { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x41 }, { 0x3D4, 0x10, 0xDA }, + { 0x3D4, 0x11, 0x9C }, { 0x3D4, 0x12, 0xBF }, { 0x3D4, 0x13, 0x24 }, + { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0xC7 }, { 0x3D4, 0x16, 0x04 }, + { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, + { 0, 0, 0 } +}; + +static vgareg_t mode_320x200[] = +{ + { 0, 0, 0 } +}; + +static vgamode_t vidmodes[] = +{ + { 288, 224, "288x224", mode_288x224 }, + { 256, 224, "256x224", mode_256x224 }, + { 256, 240, "256x240", mode_256x240 }, + { 256, 256, "256x256 (wide)", mode_256x256wide }, + { 256, 256, "256x256", mode_256x256 }, + { 320, 200, "320x200", mode_320x200 }, + { 0, 0, NULL, 0 } +}; + + +static bitmap_t *screen = NULL; +static bitmap_t *hardware = NULL; + +/* current VGA mode */ +static vgamode_t *vga_mode = NULL; +static bool vga_hardware = false; + +/* Set a VGA mode */ +static void vga_setvgamode(uint8 mode) +{ + __dpmi_regs r; + r.x.ax = mode; + __dpmi_int(0x10, &r); +} + +static void vga_set_overscan(int index) +{ + outportb(VGA_ATTR, 0x31); + outportb(VGA_ATTR, index); +} + +static void vga_outregs(vgareg_t *reg) +{ + uint8 crtc_val; + + /* Disable interrupts, wait for vertical retrace */ +// thin_vga_waitvsync(); + THIN_DISABLE_INTS(); + + /* Sequencer reset */ + outportb(VGA_SEQ_ADDR, 0x00); + outportb(VGA_SEQ_DATA, 0x01); + crtc_val = inportb(VGA_CRTC_DATA) & 0x7F; + + /* Unprotect registers 0-7 */ + outportb(VGA_CRTC_ADDR, 0x11); + outportb(VGA_CRTC_DATA, crtc_val); + + /* Reset read/write flip-flop */ + inportb(VGA_STATUS); + + /* Do the icky register stuff */ + while (reg->port) + { + switch(reg->port) + { + case VGA_ATTR: + /* Reset read/write flip-flop */ + inportb(VGA_STATUS); + /* Ensure VGA output is enabled - bit 5 */ + outportb(VGA_ATTR, reg->index | 0x20); + outportb(VGA_ATTR, reg->value); + break; + + case VGA_MISC: + /* Write directly to port */ + outportb(reg->port, reg->value); + break; + + case VGA_SEQ_ADDR: + case VGA_CRTC_ADDR: + default: + /* Index to port, value to port + 1 */ + outportb(reg->port, reg->index); + outportb(reg->port + 1, reg->value); + break; + } + + reg++; + } + + /* Set overscan color */ + vga_set_overscan(DEFAULT_OVERSCAN); + + /* Clear sequencer reset */ + outportb(VGA_SEQ_ADDR, 0x00); + outportb(VGA_SEQ_DATA, 0x03); + + THIN_ENABLE_INTS(); +} + +/* Set up VGA mode 13h, then tweak it appropriately */ +int thin_vga_setmode(int width, int height, int bpp) +{ + if (8 != bpp) + return -1; + + vga_mode = vidmodes; + + /* Search for the video mode */ + while ((vga_mode->width != width) || (vga_mode->height != height)) + { + if (NULL == vga_mode->regs) + { + vga_mode = NULL; + return -1; + } + vga_mode++; + } + + /* Set up our standard mode 13h */ + vga_setvgamode(MODE_13H); + + vga_outregs(vga_mode->regs); + + return 0; +} + +/* Destroy VGA */ +void thin_vga_shutdown(void) +{ + /* set textmode */ + vga_setvgamode(MODE_TEXT); + + if (screen) + thin_bmp_destroy(&screen); + + if (hardware) + thin_bmp_destroy(&hardware); +} + +/* Initialize VGA */ +int thin_vga_init(int width, int height, int bpp, int param) +{ + if (8 != bpp) + return -1; + + /* ensure we really want a hardware surface */ + if (thinlib_nearptr && (param & THIN_VIDEO_HWSURFACE)) + { + vga_hardware = true; + screen = thin_bmp_createhw((uint8 *) THIN_PHYSICAL_ADDR(VGA_ADDRESS), + width, height, bpp, width); + if (NULL == screen) + return -1; + } + else + { + vga_hardware = false; + hardware = thin_bmp_createhw((uint8 *) VGA_ADDRESS, + width, height, bpp, width); + if (NULL == hardware) + return -1; + + screen = thin_bmp_create(width, height, bpp, 0); + if (NULL == screen) + return -1; + } + + /* Set the initial video mode, no scanlines */ + if (thin_vga_setmode(width, height, bpp)) + { + thin_vga_shutdown(); + return -1; + } + + return 0; +} + +/* cram an 8-bit, 256 entry rgb palette into 6-bit vga */ +void thin_vga_setpalette(rgb_t *palette, int index, int length) +{ + int i; + + /* we also want to find the closest color index to black, + ** and set that as our overscan color + */ + int overscan_index = 0; + int overscan_sum = 255 * 3; + + outportb(VGA_PAL_WRITE, index); + + for (i = 0; i < length; i++) + { + if (palette[i].r + palette[i].g + palette[i].b < overscan_sum) + { + overscan_sum = palette[i].r + palette[i].g + palette[i].b; + overscan_index = index + i; + } + + outportb(VGA_PAL_DATA, palette[i].r >> 2); + outportb(VGA_PAL_DATA, palette[i].g >> 2); + outportb(VGA_PAL_DATA, palette[i].b >> 2); + } + + vga_set_overscan(overscan_index); +} + +void thin_vga_waitvsync(void) +{ + while (0 == (inportb(VGA_STATUS) & 0x08)); + //while (inportb(VGA_STATUS) & 0x08); +} + +bitmap_t *thin_vga_lockwrite(void) +{ + /* always return screen */ + return screen; +} + +void thin_vga_freewrite(int num_dirties, rect_t *dirty_rects) +{ + UNUSED(num_dirties); + UNUSED(dirty_rects); + + if (false == vga_hardware) + { + dosmemput(screen->line[0], hardware->pitch * hardware->height, + (int) hardware->line[0]); + } +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_vga.h b/sys/thinlib/lib/tl_vga.h new file mode 100644 index 0000000..ce53812 --- /dev/null +++ b/sys/thinlib/lib/tl_vga.h @@ -0,0 +1,32 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_vga.h +** +** VGA-specific thinlib routines +** +** $Id: $ +*/ + +#ifndef _TL_VGA_H_ +#define _TL_VGA_H_ + +#include "tl_types.h" +#include "tl_bmp.h" + +extern int thin_vga_init(int width, int height, int bpp, int param); +extern void thin_vga_shutdown(void); + +extern int thin_vga_setmode(int width, int height, int bpp); +extern void thin_vga_setpalette(rgb_t *palette, int index, int length); +extern void thin_vga_waitvsync(void); + +extern bitmap_t *thin_vga_lockwrite(void); +extern void thin_vga_freewrite(int num_dirties, rect_t *dirty_rects); + +#endif /* !_TL_VGA_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_video.c b/sys/thinlib/lib/tl_video.c new file mode 100644 index 0000000..f4290b7 --- /dev/null +++ b/sys/thinlib/lib/tl_video.c @@ -0,0 +1,140 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_video.h +** +** thinlib video routines +** +** $Id: $ +*/ + +#include "tl_types.h" +#include "tl_video.h" +#include "tl_vesa.h" +#include "tl_vga.h" +#include "tl_log.h" + +typedef struct viddriver_s +{ + const char *name; + int (*init)(int width, int height, int bpp, int param); + void (*shutdown)(void); + int (*setmode)(int width, int height, int bpp); + void (*setpalette)(rgb_t *palette, int index, int length); + void (*waitvsync)(void); + bitmap_t *(*lock)(void); + void (*free)(int num_dirties, rect_t *dirty_rects); + void (*blit)(bitmap_t *primary, int num_dirties, rect_t *dirty_rects); + int caps; +} viddriver_t; + +static viddriver_t vesa = +{ + "VESA 3.0 LFB", + thin_vesa_init, + thin_vesa_shutdown, + thin_vesa_setmode, + thin_vga_setpalette, + thin_vga_waitvsync, + thin_vesa_lockwrite, + thin_vesa_freewrite, + NULL, + 0, +}; + +static viddriver_t vga = +{ + "VGA", + thin_vga_init, + thin_vga_shutdown, + thin_vga_setmode, + thin_vga_setpalette, + thin_vga_waitvsync, + thin_vga_lockwrite, + thin_vga_freewrite, + NULL, + 0, /*THIN_VIDEO_SCANLINES,*/ +}; + +static viddriver_t *driver_list[] = +{ + &vesa, + &vga, + NULL +}; + +static viddriver_t driver; + +int thin_vid_init(int width, int height, int bpp, int param) +{ + /* cascade driver checks by iterating through all drivers */ + viddriver_t **iter; + + for (iter = driver_list; *iter != NULL; iter++) + { + if (0 == (*iter)->init(width, height, bpp, param)) + { + driver = **iter; + return 0; + } + } + + driver.name = NULL; + thin_printf("thinlib.video: could not find any matching video modes.\n"); + return -1; +} + +void thin_vid_shutdown(void) +{ + if (NULL != driver.name) + { + driver.shutdown(); + memset(&driver, 0, sizeof(viddriver_t)); + } +} + +int thin_vid_getcaps(void) +{ + return driver.caps; +} + +int thin_vid_setmode(int width, int height, int bpp) +{ + if (driver.setmode(width, height, bpp)) + { + thin_printf("thinlib.video: could not set %s video mode %dx%d %dbpp\n", + driver.name, width, height, bpp); + return -1; + } + + return 0; +} + +void thin_vid_setpalette(rgb_t *palette, int index, int length) +{ + driver.setpalette(palette, index, length); +} + +bitmap_t *thin_vid_lockwrite(void) +{ + return driver.lock(); +} + +void thin_vid_freewrite(int num_dirties, rect_t *dirty_rects) +{ + if (NULL != driver.free) + driver.free(num_dirties, dirty_rects); +} + +void thin_vid_customblit(bitmap_t *primary, int num_dirties, + rect_t *dirty_rects) +{ + THIN_ASSERT(driver.blit); + + driver.blit(primary, num_dirties, dirty_rects); +} + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/lib/tl_video.h b/sys/thinlib/lib/tl_video.h new file mode 100644 index 0000000..731ad78 --- /dev/null +++ b/sys/thinlib/lib/tl_video.h @@ -0,0 +1,41 @@ +/* +** thinlib (c) 2001 Matthew Conte (matt@conte.com) +** +** +** tl_video.h +** +** thinlib video routines +** +** $Id: $ +*/ + +#ifndef _TL_VIDEO_H_ +#define _TL_VIDEO_H_ + +#include "tl_types.h" +#include "tl_bmp.h" + +/* video driver capabilities */ +#define THIN_VIDEO_CUSTOMBLIT 0x0001 +#define THIN_VIDEO_SCANLINES 0x0002 +#define THIN_VIDEO_HWSURFACE 0x0004 + +extern int thin_vid_getcaps(void); + +extern int thin_vid_init(int width, int height, int bpp, int param); +extern void thin_vid_shutdown(void); + +extern int thin_vid_setmode(int width, int height, int bpp); +extern void thin_vid_setpalette(rgb_t *palette, int index, int length); + +extern bitmap_t *thin_vid_lockwrite(void); +extern void thin_vid_freewrite(int num_dirties, rect_t *dirty_rects); + +extern void thin_vid_customblit(bitmap_t *primary, int num_dirties, + rect_t *dirty_rects); + +#endif /* !_TL_VIDEO_H_ */ + +/* +** $Log: $ +*/ diff --git a/sys/thinlib/thinlib.c b/sys/thinlib/thinlib.c new file mode 100644 index 0000000..bd2d943 --- /dev/null +++ b/sys/thinlib/thinlib.c @@ -0,0 +1,375 @@ +#include +#include +#include "fb.h" +#include "input.h" +#include "rc.h" +#include "pcm.h" +#include "thinlib.h" + +struct pcm pcm; + +static volatile int audio_int; + +static int samplerate = 44100; +static int sound = 1; +static int stereo = 0; + +static int joystick = 1; + +static int dpp = 0; +static int dpp_pad = 0; +static int dpp_port = 0x378; + +struct fb fb; + +static bitmap_t *screen = NULL; +static int vmode[3] = { 320, 200, 8 }; + +rcvar_t vid_exports[] = +{ + RCV_VECTOR("vmode", vmode, 3), + RCV_END +}; + +rcvar_t pcm_exports[] = +{ + RCV_BOOL("sound", &sound), + RCV_INT("samplerate", &samplerate), + RCV_INT("stereo", &stereo), + RCV_END +}; + +rcvar_t joy_exports[] = +{ + RCV_BOOL("joystick", &joystick), + RCV_BOOL("dpp", &dpp), + RCV_INT("dpp_pad", &dpp_pad), + RCV_INT("dpp_port", &dpp_port), + RCV_END +}; + +void joy_init() +{ + if (joystick) + { + if (thin_joy_init()) + joystick = 0; + } + + if (dpp) + { + if (thin_dpp_init()) + dpp = 0; + else + thin_dpp_add(dpp_port, dpp_pad); + } +} + +void joy_close() +{ + if (joystick) + thin_joy_shutdown(); + if (dpp) + thin_dpp_shutdown(); +} + +void joy_poll() +{ + /* handled by event polling */ +} + + +/* hardware audio buffer fill */ +static void _audio_callback(void *user_data, void *buf, int len) +{ + /* user_data unused */ + memcpy(buf, pcm.buf, len); + audio_int = 1; +} + +void pcm_init() +{ + thinsound_t params; + int i; + + if (!sound) + { + pcm.hz = 11025; + pcm.len = 4096; + pcm.buf = (byte *) malloc(pcm.len); + pcm.pos = 0; + pcm.stereo = stereo; + return; + } + + params.sample_rate = samplerate; + params.frag_size = samplerate / 60; + for (i = 1; i < params.frag_size; i <<= 1); + params.frag_size = i; + params.format = THIN_SOUND_8BIT | THIN_SOUND_UNSIGNED; + if (stereo) + params.format |= THIN_SOUND_STEREO; + else + params.format |= THIN_SOUND_MONO; + params.callback = _audio_callback; + + if (thin_sound_init(¶ms)) + { + sound = 0; + return; + } + + pcm.hz = params.sample_rate; + pcm.len = params.frag_size; + pcm.stereo = (params.format & THIN_SOUND_STEREO) ? 1 : 0; + pcm.buf = (byte *) malloc(pcm.len); + if (!pcm.buf) + die("failed to allocate sound buffer\n"); + + memset(pcm.buf, 0, pcm.len); + pcm.pos = 0; + + thin_sound_start(); +} + +void pcm_close() +{ + if (sound) + { + thin_sound_stop(); + thin_shutdown(); + } + + if (pcm.buf) + free(pcm.buf); + + memset(&pcm, 0, sizeof pcm); +} + +int pcm_submit() +{ + if (!sound) + { + pcm.pos = 0; + return 0; + } + + if (pcm.pos < pcm.len) + return 1; + + while (!audio_int) + ; /* spin */ + + audio_int = 0; + pcm.pos = 0; + + return 1; +} + + +/* keyboard stuff... */ + +/* keymap - mappings of the form { scancode, localcode } - from keymap.c */ +extern int keymap[][2]; +static int scanmap[256]; + +static int mapscancode(int scan) +{ + int i; + for (i = 0; keymap[i][0]; i++) + if (keymap[i][0] == scan) + return keymap[i][1]; + return 0; +} + +static void buildscanmap() +{ + int key, i; + + memset(scanmap, 0, sizeof(scanmap)); + + for (key = 0; key < 256; key++) + scanmap[key] = mapscancode(key); +} + +void ev_poll() +{ + thin_event_t event; + event_t ev; + + thin_event_gather(); + + while (thin_event_get(&event)) + { + switch (event.type) + { + case THIN_KEY_PRESS: + ev.type = EV_PRESS; + ev.code = scanmap[event.data.keysym]; + ev_postevent(&ev); + break; + + case THIN_KEY_RELEASE: + ev.type = EV_RELEASE; + ev.code = scanmap[event.data.keysym]; + ev_postevent(&ev); + break; + + case THIN_JOY_MOTION: + ev.type = event.data.joy_motion.state ? EV_PRESS : EV_RELEASE; + switch (event.data.joy_motion.dir) + { + case THIN_JOY_LEFT: + ev.code = K_JOYLEFT; + break; + + case THIN_JOY_RIGHT: + ev.code = K_JOYRIGHT; + break; + + case THIN_JOY_UP: + ev.code = K_JOYUP; + break; + + case THIN_JOY_DOWN: + ev.code = K_JOYDOWN; + break; + } + + ev_postevent(&ev); + break; + + case THIN_JOY_BUTTON_PRESS: + ev.type = EV_PRESS; + ev.code = K_JOY0 + event.data.joy_button; + ev_postevent(&ev); + break; + + case THIN_JOY_BUTTON_RELEASE: + ev.type = EV_RELEASE; + ev.code = K_JOY0 + event.data.joy_button; + ev_postevent(&ev); + break; + + default: + break; + } + } +} + +void vid_preinit() +{ + int gotmask = thin_init(THIN_VIDEO | THIN_SOUND | THIN_KEY); + if ((THIN_VIDEO | THIN_KEY) != (gotmask & (THIN_VIDEO | THIN_KEY))) + die("thinlib initialization failed."); + thin_key_set_repeat(false); + buildscanmap(); + + /* don't spam the graphics screen if we don't have soundcard */ + thin_setlogfunc(NULL); + + joy_init(); +} + +void vid_init() +{ + int red_length, green_length, blue_length; + int red_offset, green_offset, blue_offset; + + if (thin_vid_init(vmode[0], vmode[1], vmode[2], THIN_VIDEO_HWSURFACE)) + die("could not set video mode"); + + screen = thin_vid_lockwrite(); + if (NULL == screen) + die("could not get ahold of video surface"); + + fb.w = screen->width; + fb.h = screen->height; + fb.pitch = screen->pitch; + fb.ptr = screen->data; + + fb.pelsize = (screen->bpp + 7) / 8; + fb.indexed = (screen->bpp == 8) ? 1 : 0; + + switch (screen->bpp) + { + case 8: + red_length = 0; + green_length = 0; + blue_length = 0; + red_offset = 0; + green_offset = 0; + blue_offset = 0; + break; + + case 16: + red_length = 5; + green_length = 6; + blue_length = 5; + red_offset = 11; + green_offset = 5; + blue_offset = 0; + break; + + case 32: + red_length = 8; + green_length = 8; + blue_length = 8; + red_offset = 16; + green_offset = 8; + blue_offset = 0; + break; + + case 15: + case 24: + default: + die("i don't know what to do with %dbpp mode", screen->bpp); + break; + } + + fb.cc[0].r = 8 - red_length; + fb.cc[1].r = 8 - green_length; + fb.cc[2].r = 8 - blue_length; + fb.cc[0].l = red_offset; + fb.cc[1].l = green_offset; + fb.cc[2].l = blue_offset; + + fb.enabled = 1; + fb.dirty = 0; +} + +void vid_close() +{ + fb.enabled = 0; + joy_close(); + thin_shutdown(); +} + +void vid_settitle(char *title) +{ +} + +void vid_setpal(int i, int r, int g, int b) +{ + rgb_t color; + + color.r = r; + color.g = g; + color.b = b; + thin_vid_setpalette(&color, i, 1); +} + +void vid_begin() +{ + screen = thin_vid_lockwrite(); + + fb.ptr = screen->data; + fb.pitch = screen->pitch; + fb.w = screen->width; + fb.h = screen->height; +} + +void vid_end() +{ + thin_vid_freewrite(-1, NULL); +} diff --git a/sys/windows/gameboy.ico b/sys/windows/gameboy.ico new file mode 100644 index 0000000000000000000000000000000000000000..22598f69332473f9aba0941cbf4aa7114cf18e05 GIT binary patch literal 2238 zcmb`{KW-C26vy!wfdm~&Lz^fS9mO0V6gfbeTw$(|5|>VOzNZ#Vo&YzKkZ_1C-m`^|gv+u5}vcI^B6F>dc3M?7`*4EuP2ogms~568pwwe#C~ z%$Tlcv+3a5Y0T&In17nb)yKE7=sg-L3i_hQ0u2=f21RdlG*lEQj9%$zs3_1ZdZDAC zqQC^P2pTF1dS7V2&}yM8^1wtsHqoJa}i9B>PR1`4fp^r)E_5ua+SSd7A6lfw39Ss!)8p}gRLq&nf zSLrFCOx?@)j~~M#~sEWwy)G9GX(ZIX>V$Uf~ocIKsi7?ep_EIXQ{b)6PwF|uV4Ee&-Bil&4b_3c$L4Wyv(cryA8wTJq?H4whkEGVYt{l zAS;(SkKTEl{M!TQ)8u;G__qf9vR60$?Sw!2 zuU3LKxvO#g z*YAIIcH<7$p3mAgtft!G`q~SyW=Af)XOQl4xo-1+x}P`L`Fy6@&l~Ny-;EgO-BLTw zC)MW8o6`J+=0Cu;*ZbEeypdjDpM{ygXH F{X4&;*vJ3? literal 0 HcmV?d00001 diff --git a/sys/windows/resource.rc b/sys/windows/resource.rc new file mode 100644 index 0000000..1a33296 --- /dev/null +++ b/sys/windows/resource.rc @@ -0,0 +1,3 @@ +#define IDI_GAMEBOYICO 107 + +IDI_GAMEBOYICO ICON DISCARDABLE "sys/mingw32/gameboy.ico" diff --git a/sys/windows/windows.c b/sys/windows/windows.c new file mode 100644 index 0000000..3df9192 --- /dev/null +++ b/sys/windows/windows.c @@ -0,0 +1,77 @@ +/* + * MinGW32 system file + * based on nix.c and dos.c + * req's SDL + * -Dave Kiddell + */ + +#include +#include +#include +char *strdup(); + +#include + +void *sys_timer() +{ + Uint32 *tv; + + tv = malloc(sizeof *tv); + *tv = SDL_GetTicks() * 1000; + return tv; +} + +int sys_elapsed(Uint32 *cl) +{ + Uint32 now; + Uint32 usecs; + + now = SDL_GetTicks() * 1000; + usecs = now - *cl; + *cl = now; + return usecs; +} + +void sys_sleep(int us) +{ + /* dbk: for some reason 2000 works.. + maybe its just compensation for the time it takes for SDL_Delay to + execute, or maybe sys_timer is too slow */ + SDL_Delay(us/1000); +} + +void sys_sanitize(char *s) +{ + int i; + for (i = 0; s[i]; i++) + if (s[i] == '\\') s[i] = '/'; +} + +void sys_initpath(char *exe) +{ + char *buf, *home, *p; + + home = strdup(exe); + sys_sanitize(home); + p = strrchr(home, '/'); + if (p) *p = 0; + else + { + buf = "."; + rc_setvar("rcpath", 1, &buf); + rc_setvar("savedir", 1, &buf); + return; + } + buf = malloc(strlen(home) + 8); + sprintf(buf, ".;%s/", home); + rc_setvar("rcpath", 1, &buf); + sprintf(buf, ".", home); + rc_setvar("savedir", 1, &buf); + free(buf); +} + +void sys_checkdir(char *path, int wr) +{ +} + + diff --git a/sys/x11/keymap.c b/sys/x11/keymap.c new file mode 100644 index 0000000..93cb4bb --- /dev/null +++ b/sys/x11/keymap.c @@ -0,0 +1,96 @@ +/* + * xkeymap.c + * + * Mappings from X keycode to local key codes. + */ + +#include +#include "input.h" + +int keymap[][2] = +{ + { XK_Shift_L, K_SHIFT }, + { XK_Shift_R, K_SHIFT }, + { XK_Control_L, K_CTRL }, + { XK_Control_R, K_CTRL }, + { XK_Alt_L, K_ALT }, + { XK_Alt_R, K_ALT }, + { XK_Meta_L, K_ALT }, + { XK_Meta_R, K_ALT }, + + { XK_Up, K_UP }, + { XK_Down, K_DOWN }, + { XK_Right, K_RIGHT }, + { XK_Left, K_LEFT }, + { XK_Return, K_ENTER }, + { XK_Tab, K_TAB }, + { XK_BackSpace, K_BS }, + { XK_Delete, K_DEL }, + { XK_Insert, K_INS }, + { XK_Home, K_HOME }, + { XK_End, K_END }, + { XK_Prior, K_PRIOR }, + { XK_Next, K_NEXT }, + { XK_Escape, K_ESC }, + { XK_Pause, K_PAUSE }, + { XK_Caps_Lock, K_CAPS }, + { XK_Num_Lock, K_NUMLOCK }, + { XK_Scroll_Lock, K_SCROLL }, + + { XK_minus, K_MINUS }, + { XK_equal, K_EQUALS }, + { XK_asciitilde, K_TILDE }, + + { XK_F1, K_F1 }, + { XK_F2, K_F2 }, + { XK_F3, K_F3 }, + { XK_F4, K_F4 }, + { XK_F5, K_F5 }, + { XK_F6, K_F6 }, + { XK_F7, K_F7 }, + { XK_F8, K_F8 }, + { XK_F9, K_F9 }, + { XK_F10, K_F10 }, + { XK_F11, K_F11 }, + { XK_F12, K_F12 }, + + { XK_KP_Insert, K_NUM0 }, + { XK_KP_End, K_NUM1 }, + { XK_KP_Down, K_NUM2 }, + { XK_KP_Next, K_NUM3 }, + { XK_KP_Left, K_NUM4 }, + { XK_KP_Begin, K_NUM5 }, + { XK_KP_Space, K_NUM5 }, /* FIXME - ??? */ + { XK_KP_Right, K_NUM6 }, + { XK_KP_Home, K_NUM7 }, + { XK_KP_Up, K_NUM8 }, + { XK_KP_Prior, K_NUM9 }, + { XK_KP_0, K_NUM0 }, + { XK_KP_1, K_NUM1 }, + { XK_KP_2, K_NUM2 }, + { XK_KP_3, K_NUM3 }, + { XK_KP_4, K_NUM4 }, + { XK_KP_5, K_NUM5 }, + { XK_KP_6, K_NUM6 }, + { XK_KP_7, K_NUM7 }, + { XK_KP_8, K_NUM8 }, + { XK_KP_9, K_NUM9 }, + { XK_KP_Add, K_NUMPLUS }, + { XK_KP_Subtract, K_NUMMINUS }, + { XK_KP_Multiply, K_NUMMUL }, + { XK_KP_Divide, K_NUMDIV }, + { XK_KP_Separator, K_NUMDOT }, + { XK_KP_Delete, K_NUMDOT }, + { XK_KP_Enter, K_NUMENTER }, + + { 0, 0 } +}; + + + + + + + + + diff --git a/sys/x11/xlib.c b/sys/x11/xlib.c new file mode 100644 index 0000000..596ac72 --- /dev/null +++ b/sys/x11/xlib.c @@ -0,0 +1,524 @@ +/* + * xlib.c + * + * Xlib interface. + * dist under gnu gpl + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#if defined(HAVE_LIBXEXT) && defined(HAVE_X11_EXTENSIONS_XSHM_H) \ + && defined(HAVE_SYS_IPC_H) && defined(HAVE_SYS_SHM_H) +#define USE_XSHM +#endif +#else +#define USE_XSHM /* assume we have shm if no config.h - is this ok? */ +#endif + +#ifdef USE_XSHM +/* make sure ipc.h and shm.h will work! */ +#define _SVID_SOURCE +#define _XOPEN_SOURCE +#endif + +#include + +#include +#include +#include + +#ifdef USE_XSHM +#include +#include +#include +#endif + +#include "fb.h" +#include "input.h" +#include "rc.h" + + +struct fb fb; + +static int vmode[3] = { 0, 0, 0 }; +static int x_shmsync = 1; + +rcvar_t vid_exports[] = +{ + RCV_VECTOR("vmode", &vmode, 3), + RCV_BOOL("x_shmsync", &x_shmsync), + RCV_END +}; + + +static int initok; + +/* Loads of bogus Xlib crap...bleh */ + +static char *x_displayname; + +static Display *x_display; +static int x_screen; + +static struct +{ + int bits; + int vc; + int bytes; +} x_vissup[] = +{ + { 8, PseudoColor, 1 }, + { 15, TrueColor, 2 }, + { 16, TrueColor, 2 }, + { 32, TrueColor, 4 }, + { 24, TrueColor, 3 }, + { 0, 0, 0 } +}; + +static int x_bits, x_bytes; +static Visual *x_vis; +static XVisualInfo x_visinfo; +static int x_pseudo; +static Colormap x_cmap; +static XColor x_ctable[256]; + +static int x_wattrmask; +static XSetWindowAttributes x_wattr; +static int x_gcvalmask; +static XGCValues x_gcval; + +static Window x_win; +static int x_win_x, x_win_y; +static int x_width, x_height; +static GC x_gc; + +static XSizeHints x_size; +static XWMHints x_wmhints; +/*static XClassHint x_class;*/ + +#ifdef USE_XSHM +static XShmSegmentInfo x_shm; +#endif + +static int x_useshm; +static int x_shmevent; +static int x_shmdone; +static XImage *x_image; +static int x_byteswap; + +static XEvent x_ev; + + + + +static void freescreen() +{ + if (!initok || !x_image) return; + if ((char *)fb.ptr != (char *)x_image->data) + free(fb.ptr); +#ifdef USE_XSHM + if (x_useshm) + { + /* FIXME - is this the right way to free shared mem? */ + XSync(x_display, False); + if (!XShmDetach(x_display, &x_shm)) + die ("XShmDetach failed\n"); + XSync(x_display, False); + shmdt(x_shm.shmaddr); + shmctl(x_shm.shmid, IPC_RMID, 0); + x_image->data = NULL; + } +#endif + free(x_image); + x_image = NULL; + fb.ptr = NULL; +} + +static void allocscreen() +{ + if (initok) freescreen(); +#ifdef USE_XSHM + if (x_useshm) + { + x_image = XShmCreateImage( + x_display, x_vis, x_bits, ZPixmap, 0, + &x_shm, x_width, x_height); + if (x_image) + { + x_shm.shmid = shmget( + IPC_PRIVATE, + x_image->bytes_per_line * x_image->height, + IPC_CREAT | 0777); + if (x_shm.shmid < 0) + die("shmget failed\n"); + x_image->data = x_shm.shmaddr = + shmat(x_shm.shmid, 0, 0); + if (!x_image->data) + die("shmat failed\n"); + if (!XShmAttach(x_display, &x_shm)) + die("XShmAttach failed\n"); + XSync(x_display, False); + x_shmdone = 1; + fb.pitch = x_image->bytes_per_line; + } + else + { + x_useshm = 0; + } + } +#endif + if (!x_useshm) + { + x_image = XCreateImage( + x_display, x_vis, x_bits, ZPixmap, 0, + malloc(x_width*x_height*x_bytes), + x_width, x_height, x_bits, x_width*x_bytes); + if (!x_image) + die("XCreateImage failed\n"); + } + x_byteswap = x_image->byte_order == +#ifdef IS_LITTLE_ENDIAN + MSBFirst +#else + LSBFirst +#endif + ; + if (x_byteswap && x_bytes > 1) + fb.ptr = malloc(x_image->bytes_per_line * x_image->height); + else + fb.ptr = (byte *)x_image->data; +} + + + +void vid_resize() +{ + freescreen(); + x_width = fb.w; + x_height = fb.h; + XResizeWindow(x_display, x_win, x_width, x_height); + x_size.flags = PSize | PMinSize | PMaxSize; + x_size.min_width = x_size.max_width = x_size.base_width = x_width; + x_size.min_height = x_size.max_height = x_size.base_height = x_height; + XSetWMNormalHints(x_display, x_win, &x_size); + XSync(x_display, False); + allocscreen(); +} + + +static void colorshifts() +{ + int i; + int mask[3]; + int l, c; + + mask[0] = x_vis->red_mask; + mask[1] = x_vis->green_mask; + mask[2] = x_vis->blue_mask; + + for (i = 0; i < 3; i++) + { + for (l = 0; l < 32 && !((1< XK_asciitilde) + return 0; + code = sym - XK_space + ' '; + if (code >= 'A' && code <= 'Z') + code = tolower(code);; + return code; +} + + +void vid_end(); + +static int nextevent(int sync) +{ + event_t ev; + + if (!sync && !XPending(x_display)) + return 0; + + XNextEvent(x_display, &x_ev); + switch(x_ev.type) + { + case KeyPress: + ev.type = EV_PRESS; + ev.code = mapxkeycode(x_ev.xkey.keycode); + break; + case KeyRelease: + ev.type = EV_RELEASE; + ev.code = mapxkeycode(x_ev.xkey.keycode); + break; + case Expose: + vid_end(); + return 1; + break; + default: + if (x_ev.type == x_shmevent) x_shmdone = 1; + return 1; + break; + } + return ev_postevent(&ev); /* returns 0 if queue is full */ +} + + + +void ev_poll() +{ + while (nextevent(0)); + joy_poll(); +} + + + +void vid_settitle(char *title) +{ + XStoreName(x_display, x_win, title); + XSetIconName(x_display, x_win, title); +} + +void vid_setpal(int i, int r, int g, int b) +{ + if (!initok) return; + + if (x_pseudo == 1) + { + x_ctable[i].red = r << 8; + x_ctable[i].green = g << 8; + x_ctable[i].blue = b << 8; + XStoreColors(x_display, x_cmap, x_ctable, 256); + } +} + +void vid_begin() +{ + if (!x_useshm) return; + + /* XSync(x_display, False); */ + while (!x_shmdone && x_shmsync) + nextevent(1); +} + +static void endianswap() +{ + int cnt; + un16 t16; + un32 t32; + un16 *src16 = (void *)fb.ptr; + un16 *dst16 = (void *)x_image->data; + un32 *src32 = (void *)fb.ptr; + un32 *dst32 = (void *)x_image->data; + + switch (x_bytes) + { + case 2: + cnt = (x_image->bytes_per_line * x_image->height)>>1; + while (cnt--) + { + t16 = *(src16++); + *(dst16++) = (t16 << 8) | (t16 >> 8); + } + break; + case 4: + cnt = (x_image->bytes_per_line * x_image->height)>>2; + while (cnt--) + { + t32 = *(src32++); + *(dst32++) = (t32 << 24) | ((t32 << 8) & 0x00FF0000) | + ((t32 >> 8) & 0x0000FF00) | (t32 >> 24); + } + break; + } +} + + +void vid_end() +{ + if (!initok) return; + + if (x_byteswap) endianswap(); + if (x_useshm) + { + if (!x_shmdone) return; +#ifdef USE_XSHM + if (!XShmPutImage( + x_display, x_win, x_gc, x_image, + 0, 0, 0, 0, x_width, x_height, True)) + die("XShmPutImage failed\n"); +#endif + x_shmdone = 0; + } + else + { + XPutImage(x_display, x_win, x_gc, x_image, + 0, 0, 0, 0, x_width, x_height); + } +} + + + + +